1 /* 2 * Copyright (C) 2014 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.net; 18 19 import android.annotation.IntDef; 20 import android.annotation.IntRange; 21 import android.annotation.NonNull; 22 import android.annotation.Nullable; 23 import android.annotation.SystemApi; 24 import android.compat.annotation.UnsupportedAppUsage; 25 import android.content.Context; 26 import android.os.Build; 27 import android.os.Bundle; 28 import android.os.ConditionVariable; 29 import android.os.Handler; 30 import android.os.Looper; 31 import android.os.Message; 32 import android.os.Messenger; 33 import android.util.Log; 34 35 import com.android.internal.annotations.VisibleForTesting; 36 import com.android.internal.util.AsyncChannel; 37 import com.android.internal.util.Protocol; 38 39 import java.lang.annotation.Retention; 40 import java.lang.annotation.RetentionPolicy; 41 import java.time.Duration; 42 import java.util.ArrayList; 43 import java.util.Objects; 44 import java.util.concurrent.atomic.AtomicBoolean; 45 46 /** 47 * A utility class for handling for communicating between bearer-specific 48 * code and ConnectivityService. 49 * 50 * An agent manages the life cycle of a network. A network starts its 51 * life cycle when {@link register} is called on NetworkAgent. The network 52 * is then connecting. When full L3 connectivity has been established, 53 * the agent shoud call {@link markConnected} to inform the system that 54 * this network is ready to use. When the network disconnects its life 55 * ends and the agent should call {@link unregister}, at which point the 56 * system will clean up and free resources. 57 * Any reconnection becomes a new logical network, so after a network 58 * is disconnected the agent cannot be used any more. Network providers 59 * should create a new NetworkAgent instance to handle new connections. 60 * 61 * A bearer may have more than one NetworkAgent if it can simultaneously 62 * support separate networks (IMS / Internet / MMS Apns on cellular, or 63 * perhaps connections with different SSID or P2P for Wi-Fi). 64 * 65 * This class supports methods to start and stop sending keepalive packets. 66 * Keepalive packets are typically sent at periodic intervals over a network 67 * with NAT when there is no other traffic to avoid the network forcefully 68 * closing the connection. NetworkAgents that manage technologies that 69 * have hardware support for keepalive should implement the related 70 * methods to save battery life. NetworkAgent that cannot get support 71 * without waking up the CPU should not, as this would be prohibitive in 72 * terms of battery - these agents should simply not override the related 73 * methods, which results in the implementation returning 74 * {@link SocketKeepalive.ERROR_UNSUPPORTED} as appropriate. 75 * 76 * Keepalive packets need to be sent at relatively frequent intervals 77 * (a few seconds to a few minutes). As the contents of keepalive packets 78 * depend on the current network status, hardware needs to be configured 79 * to send them and has a limited amount of memory to do so. The HAL 80 * formalizes this as slots that an implementation can configure to send 81 * the correct packets. Devices typically have a small number of slots 82 * per radio technology, and the specific number of slots for each 83 * technology is specified in configuration files. 84 * {@see SocketKeepalive} for details. 85 * 86 * @hide 87 */ 88 @SystemApi 89 public abstract class NetworkAgent { 90 /** 91 * The {@link Network} corresponding to this object. 92 */ 93 @Nullable 94 private volatile Network mNetwork; 95 96 // Whether this NetworkAgent is using the legacy (never unhidden) API. The difference is 97 // that the legacy API uses NetworkInfo to convey the state, while the current API is 98 // exposing methods to manage it and generate it internally instead. 99 // TODO : remove this as soon as all agents have been converted. 100 private final boolean mIsLegacy; 101 102 private final Handler mHandler; 103 private volatile AsyncChannel mAsyncChannel; 104 private final String LOG_TAG; 105 private static final boolean DBG = true; 106 private static final boolean VDBG = false; 107 private final ArrayList<Message> mPreConnectedQueue = new ArrayList<Message>(); 108 private volatile long mLastBwRefreshTime = 0; 109 private static final long BW_REFRESH_MIN_WIN_MS = 500; 110 private boolean mBandwidthUpdateScheduled = false; 111 private AtomicBoolean mBandwidthUpdatePending = new AtomicBoolean(false); 112 // Not used by legacy agents. Non-legacy agents use this to convert the NetworkAgent system API 113 // into the internal API of ConnectivityService. 114 @NonNull 115 private NetworkInfo mNetworkInfo; 116 @NonNull 117 private final Object mRegisterLock = new Object(); 118 119 /** 120 * The ID of the {@link NetworkProvider} that created this object, or 121 * {@link NetworkProvider#ID_NONE} if unknown. 122 * @hide 123 */ 124 public final int providerId; 125 126 private static final int BASE = Protocol.BASE_NETWORK_AGENT; 127 128 /** 129 * Sent by ConnectivityService to the NetworkAgent to inform it of 130 * suspected connectivity problems on its network. The NetworkAgent 131 * should take steps to verify and correct connectivity. 132 * @hide 133 */ 134 public static final int CMD_SUSPECT_BAD = BASE; 135 136 /** 137 * Sent by the NetworkAgent (note the EVENT vs CMD prefix) to 138 * ConnectivityService to pass the current NetworkInfo (connection state). 139 * Sent when the NetworkInfo changes, mainly due to change of state. 140 * obj = NetworkInfo 141 * @hide 142 */ 143 public static final int EVENT_NETWORK_INFO_CHANGED = BASE + 1; 144 145 /** 146 * Sent by the NetworkAgent to ConnectivityService to pass the current 147 * NetworkCapabilties. 148 * obj = NetworkCapabilities 149 * @hide 150 */ 151 public static final int EVENT_NETWORK_CAPABILITIES_CHANGED = BASE + 2; 152 153 /** 154 * Sent by the NetworkAgent to ConnectivityService to pass the current 155 * NetworkProperties. 156 * obj = NetworkProperties 157 * @hide 158 */ 159 public static final int EVENT_NETWORK_PROPERTIES_CHANGED = BASE + 3; 160 161 /** 162 * Centralize the place where base network score, and network score scaling, will be 163 * stored, so as we can consistently compare apple and oranges, or wifi, ethernet and LTE 164 * @hide 165 */ 166 public static final int WIFI_BASE_SCORE = 60; 167 168 /** 169 * Sent by the NetworkAgent to ConnectivityService to pass the current 170 * network score. 171 * arg1 = network score int 172 * @hide 173 */ 174 public static final int EVENT_NETWORK_SCORE_CHANGED = BASE + 4; 175 176 /** 177 * Sent by ConnectivityService to the NetworkAgent to inform the agent of the 178 * networks status - whether we could use the network or could not, due to 179 * either a bad network configuration (no internet link) or captive portal. 180 * 181 * arg1 = either {@code VALID_NETWORK} or {@code INVALID_NETWORK} 182 * obj = Bundle containing map from {@code REDIRECT_URL_KEY} to {@code String} 183 * representing URL that Internet probe was redirect to, if it was redirected, 184 * or mapping to {@code null} otherwise. 185 * @hide 186 */ 187 public static final int CMD_REPORT_NETWORK_STATUS = BASE + 7; 188 189 190 /** 191 * Network validation suceeded. 192 * Corresponds to {@link NetworkCapabilities.NET_CAPABILITY_VALIDATED}. 193 */ 194 public static final int VALIDATION_STATUS_VALID = 1; 195 196 /** 197 * Network validation was attempted and failed. This may be received more than once as 198 * subsequent validation attempts are made. 199 */ 200 public static final int VALIDATION_STATUS_NOT_VALID = 2; 201 202 /** @hide */ 203 @Retention(RetentionPolicy.SOURCE) 204 @IntDef(prefix = { "VALIDATION_STATUS_" }, value = { 205 VALIDATION_STATUS_VALID, 206 VALIDATION_STATUS_NOT_VALID 207 }) 208 public @interface ValidationStatus {} 209 210 // TODO: remove. 211 /** @hide */ 212 public static final int VALID_NETWORK = 1; 213 /** @hide */ 214 public static final int INVALID_NETWORK = 2; 215 216 /** 217 * The key for the redirect URL in the Bundle argument of {@code CMD_REPORT_NETWORK_STATUS}. 218 * @hide 219 */ 220 public static String REDIRECT_URL_KEY = "redirect URL"; 221 222 /** 223 * Sent by the NetworkAgent to ConnectivityService to indicate this network was 224 * explicitly selected. This should be sent before the NetworkInfo is marked 225 * CONNECTED so it can be given special treatment at that time. 226 * 227 * obj = boolean indicating whether to use this network even if unvalidated 228 * @hide 229 */ 230 public static final int EVENT_SET_EXPLICITLY_SELECTED = BASE + 8; 231 232 /** 233 * Sent by ConnectivityService to the NetworkAgent to inform the agent of 234 * whether the network should in the future be used even if not validated. 235 * This decision is made by the user, but it is the network transport's 236 * responsibility to remember it. 237 * 238 * arg1 = 1 if true, 0 if false 239 * @hide 240 */ 241 public static final int CMD_SAVE_ACCEPT_UNVALIDATED = BASE + 9; 242 243 /** 244 * Sent by ConnectivityService to the NetworkAgent to inform the agent to pull 245 * the underlying network connection for updated bandwidth information. 246 * @hide 247 */ 248 public static final int CMD_REQUEST_BANDWIDTH_UPDATE = BASE + 10; 249 250 /** 251 * Sent by ConnectivityService to the NetworkAgent to request that the specified packet be sent 252 * periodically on the given interval. 253 * 254 * arg1 = the hardware slot number of the keepalive to start 255 * arg2 = interval in seconds 256 * obj = KeepalivePacketData object describing the data to be sent 257 * 258 * Also used internally by ConnectivityService / KeepaliveTracker, with different semantics. 259 * @hide 260 */ 261 public static final int CMD_START_SOCKET_KEEPALIVE = BASE + 11; 262 263 /** 264 * Requests that the specified keepalive packet be stopped. 265 * 266 * arg1 = hardware slot number of the keepalive to stop. 267 * 268 * Also used internally by ConnectivityService / KeepaliveTracker, with different semantics. 269 * @hide 270 */ 271 public static final int CMD_STOP_SOCKET_KEEPALIVE = BASE + 12; 272 273 /** 274 * Sent by the NetworkAgent to ConnectivityService to provide status on a socket keepalive 275 * request. This may either be the reply to a CMD_START_SOCKET_KEEPALIVE, or an asynchronous 276 * error notification. 277 * 278 * This is also sent by KeepaliveTracker to the app's {@link SocketKeepalive}, 279 * so that the app's {@link SocketKeepalive.Callback} methods can be called. 280 * 281 * arg1 = hardware slot number of the keepalive 282 * arg2 = error code 283 * @hide 284 */ 285 public static final int EVENT_SOCKET_KEEPALIVE = BASE + 13; 286 287 /** 288 * Sent by ConnectivityService to inform this network transport of signal strength thresholds 289 * that when crossed should trigger a system wakeup and a NetworkCapabilities update. 290 * 291 * obj = int[] describing signal strength thresholds. 292 * @hide 293 */ 294 public static final int CMD_SET_SIGNAL_STRENGTH_THRESHOLDS = BASE + 14; 295 296 /** 297 * Sent by ConnectivityService to the NeworkAgent to inform the agent to avoid 298 * automatically reconnecting to this network (e.g. via autojoin). Happens 299 * when user selects "No" option on the "Stay connected?" dialog box. 300 * @hide 301 */ 302 public static final int CMD_PREVENT_AUTOMATIC_RECONNECT = BASE + 15; 303 304 /** 305 * Sent by the KeepaliveTracker to NetworkAgent to add a packet filter. 306 * 307 * For TCP keepalive offloads, keepalive packets are sent by the firmware. However, because the 308 * remote site will send ACK packets in response to the keepalive packets, the firmware also 309 * needs to be configured to properly filter the ACKs to prevent the system from waking up. 310 * This does not happen with UDP, so this message is TCP-specific. 311 * arg1 = hardware slot number of the keepalive to filter for. 312 * obj = the keepalive packet to send repeatedly. 313 * @hide 314 */ 315 public static final int CMD_ADD_KEEPALIVE_PACKET_FILTER = BASE + 16; 316 317 /** 318 * Sent by the KeepaliveTracker to NetworkAgent to remove a packet filter. See 319 * {@link #CMD_ADD_KEEPALIVE_PACKET_FILTER}. 320 * arg1 = hardware slot number of the keepalive packet filter to remove. 321 * @hide 322 */ 323 public static final int CMD_REMOVE_KEEPALIVE_PACKET_FILTER = BASE + 17; 324 325 /** @hide TODO: remove and replace usage with the public constructor. */ NetworkAgent(Looper looper, Context context, String logTag, NetworkInfo ni, NetworkCapabilities nc, LinkProperties lp, int score)326 public NetworkAgent(Looper looper, Context context, String logTag, NetworkInfo ni, 327 NetworkCapabilities nc, LinkProperties lp, int score) { 328 this(looper, context, logTag, ni, nc, lp, score, null, NetworkProvider.ID_NONE); 329 // Register done by the constructor called in the previous line 330 } 331 332 /** @hide TODO: remove and replace usage with the public constructor. */ NetworkAgent(Looper looper, Context context, String logTag, NetworkInfo ni, NetworkCapabilities nc, LinkProperties lp, int score, NetworkAgentConfig config)333 public NetworkAgent(Looper looper, Context context, String logTag, NetworkInfo ni, 334 NetworkCapabilities nc, LinkProperties lp, int score, NetworkAgentConfig config) { 335 this(looper, context, logTag, ni, nc, lp, score, config, NetworkProvider.ID_NONE); 336 // Register done by the constructor called in the previous line 337 } 338 339 /** @hide TODO: remove and replace usage with the public constructor. */ NetworkAgent(Looper looper, Context context, String logTag, NetworkInfo ni, NetworkCapabilities nc, LinkProperties lp, int score, int providerId)340 public NetworkAgent(Looper looper, Context context, String logTag, NetworkInfo ni, 341 NetworkCapabilities nc, LinkProperties lp, int score, int providerId) { 342 this(looper, context, logTag, ni, nc, lp, score, null, providerId); 343 // Register done by the constructor called in the previous line 344 } 345 346 /** @hide TODO: remove and replace usage with the public constructor. */ NetworkAgent(Looper looper, Context context, String logTag, NetworkInfo ni, NetworkCapabilities nc, LinkProperties lp, int score, NetworkAgentConfig config, int providerId)347 public NetworkAgent(Looper looper, Context context, String logTag, NetworkInfo ni, 348 NetworkCapabilities nc, LinkProperties lp, int score, NetworkAgentConfig config, 349 int providerId) { 350 this(looper, context, logTag, nc, lp, score, config, providerId, ni, true /* legacy */); 351 register(); 352 } 353 getLegacyNetworkInfo(final NetworkAgentConfig config)354 private static NetworkInfo getLegacyNetworkInfo(final NetworkAgentConfig config) { 355 // The subtype can be changed with (TODO) setLegacySubtype, but it starts 356 // with the type and an empty description. 357 final NetworkInfo ni = new NetworkInfo(config.legacyType, 0, config.legacyTypeName, ""); 358 ni.setIsAvailable(true); 359 ni.setExtraInfo(config.getLegacyExtraInfo()); 360 return ni; 361 } 362 363 /** 364 * Create a new network agent. 365 * @param context a {@link Context} to get system services from. 366 * @param looper the {@link Looper} on which to invoke the callbacks. 367 * @param logTag the tag for logs 368 * @param nc the initial {@link NetworkCapabilities} of this network. Update with 369 * sendNetworkCapabilities. 370 * @param lp the initial {@link LinkProperties} of this network. Update with sendLinkProperties. 371 * @param score the initial score of this network. Update with sendNetworkScore. 372 * @param config an immutable {@link NetworkAgentConfig} for this agent. 373 * @param provider the {@link NetworkProvider} managing this agent. 374 */ NetworkAgent(@onNull Context context, @NonNull Looper looper, @NonNull String logTag, @NonNull NetworkCapabilities nc, @NonNull LinkProperties lp, int score, @NonNull NetworkAgentConfig config, @Nullable NetworkProvider provider)375 public NetworkAgent(@NonNull Context context, @NonNull Looper looper, @NonNull String logTag, 376 @NonNull NetworkCapabilities nc, @NonNull LinkProperties lp, int score, 377 @NonNull NetworkAgentConfig config, @Nullable NetworkProvider provider) { 378 this(looper, context, logTag, nc, lp, score, config, 379 provider == null ? NetworkProvider.ID_NONE : provider.getProviderId(), 380 getLegacyNetworkInfo(config), false /* legacy */); 381 } 382 383 private static class InitialConfiguration { 384 public final Context context; 385 public final NetworkCapabilities capabilities; 386 public final LinkProperties properties; 387 public final int score; 388 public final NetworkAgentConfig config; 389 public final NetworkInfo info; InitialConfiguration(@onNull Context context, @NonNull NetworkCapabilities capabilities, @NonNull LinkProperties properties, int score, @NonNull NetworkAgentConfig config, @NonNull NetworkInfo info)390 InitialConfiguration(@NonNull Context context, @NonNull NetworkCapabilities capabilities, 391 @NonNull LinkProperties properties, int score, @NonNull NetworkAgentConfig config, 392 @NonNull NetworkInfo info) { 393 this.context = context; 394 this.capabilities = capabilities; 395 this.properties = properties; 396 this.score = score; 397 this.config = config; 398 this.info = info; 399 } 400 } 401 private volatile InitialConfiguration mInitialConfiguration; 402 NetworkAgent(@onNull Looper looper, @NonNull Context context, @NonNull String logTag, @NonNull NetworkCapabilities nc, @NonNull LinkProperties lp, int score, @NonNull NetworkAgentConfig config, int providerId, @NonNull NetworkInfo ni, boolean legacy)403 private NetworkAgent(@NonNull Looper looper, @NonNull Context context, @NonNull String logTag, 404 @NonNull NetworkCapabilities nc, @NonNull LinkProperties lp, int score, 405 @NonNull NetworkAgentConfig config, int providerId, @NonNull NetworkInfo ni, 406 boolean legacy) { 407 mHandler = new NetworkAgentHandler(looper); 408 LOG_TAG = logTag; 409 mIsLegacy = legacy; 410 mNetworkInfo = new NetworkInfo(ni); 411 this.providerId = providerId; 412 if (ni == null || nc == null || lp == null) { 413 throw new IllegalArgumentException(); 414 } 415 416 mInitialConfiguration = new InitialConfiguration(context, new NetworkCapabilities(nc), 417 new LinkProperties(lp), score, config, ni); 418 } 419 420 private class NetworkAgentHandler extends Handler { NetworkAgentHandler(Looper looper)421 NetworkAgentHandler(Looper looper) { 422 super(looper); 423 } 424 425 @Override handleMessage(Message msg)426 public void handleMessage(Message msg) { 427 switch (msg.what) { 428 case AsyncChannel.CMD_CHANNEL_FULL_CONNECTION: { 429 if (mAsyncChannel != null) { 430 log("Received new connection while already connected!"); 431 } else { 432 if (VDBG) log("NetworkAgent fully connected"); 433 AsyncChannel ac = new AsyncChannel(); 434 ac.connected(null, this, msg.replyTo); 435 ac.replyToMessage(msg, AsyncChannel.CMD_CHANNEL_FULLY_CONNECTED, 436 AsyncChannel.STATUS_SUCCESSFUL); 437 synchronized (mPreConnectedQueue) { 438 mAsyncChannel = ac; 439 for (Message m : mPreConnectedQueue) { 440 ac.sendMessage(m); 441 } 442 mPreConnectedQueue.clear(); 443 } 444 } 445 break; 446 } 447 case AsyncChannel.CMD_CHANNEL_DISCONNECT: { 448 if (VDBG) log("CMD_CHANNEL_DISCONNECT"); 449 if (mAsyncChannel != null) mAsyncChannel.disconnect(); 450 break; 451 } 452 case AsyncChannel.CMD_CHANNEL_DISCONNECTED: { 453 if (DBG) log("NetworkAgent channel lost"); 454 // let the client know CS is done with us. 455 onNetworkUnwanted(); 456 synchronized (mPreConnectedQueue) { 457 mAsyncChannel = null; 458 } 459 break; 460 } 461 case CMD_SUSPECT_BAD: { 462 log("Unhandled Message " + msg); 463 break; 464 } 465 case CMD_REQUEST_BANDWIDTH_UPDATE: { 466 long currentTimeMs = System.currentTimeMillis(); 467 if (VDBG) { 468 log("CMD_REQUEST_BANDWIDTH_UPDATE request received."); 469 } 470 if (currentTimeMs >= (mLastBwRefreshTime + BW_REFRESH_MIN_WIN_MS)) { 471 mBandwidthUpdateScheduled = false; 472 if (!mBandwidthUpdatePending.getAndSet(true)) { 473 onBandwidthUpdateRequested(); 474 } 475 } else { 476 // deliver the request at a later time rather than discard it completely. 477 if (!mBandwidthUpdateScheduled) { 478 long waitTime = mLastBwRefreshTime + BW_REFRESH_MIN_WIN_MS 479 - currentTimeMs + 1; 480 mBandwidthUpdateScheduled = sendEmptyMessageDelayed( 481 CMD_REQUEST_BANDWIDTH_UPDATE, waitTime); 482 } 483 } 484 break; 485 } 486 case CMD_REPORT_NETWORK_STATUS: { 487 String redirectUrl = ((Bundle) msg.obj).getString(REDIRECT_URL_KEY); 488 if (VDBG) { 489 log("CMD_REPORT_NETWORK_STATUS(" 490 + (msg.arg1 == VALID_NETWORK ? "VALID, " : "INVALID, ") 491 + redirectUrl); 492 } 493 Uri uri = null; 494 try { 495 if (null != redirectUrl) { 496 uri = Uri.parse(redirectUrl); 497 } 498 } catch (Exception e) { 499 Log.wtf(LOG_TAG, "Surprising URI : " + redirectUrl, e); 500 } 501 onValidationStatus(msg.arg1 /* status */, uri); 502 break; 503 } 504 case CMD_SAVE_ACCEPT_UNVALIDATED: { 505 onSaveAcceptUnvalidated(msg.arg1 != 0); 506 break; 507 } 508 case CMD_START_SOCKET_KEEPALIVE: { 509 onStartSocketKeepalive(msg.arg1 /* slot */, 510 Duration.ofSeconds(msg.arg2) /* interval */, 511 (KeepalivePacketData) msg.obj /* packet */); 512 break; 513 } 514 case CMD_STOP_SOCKET_KEEPALIVE: { 515 onStopSocketKeepalive(msg.arg1 /* slot */); 516 break; 517 } 518 519 case CMD_SET_SIGNAL_STRENGTH_THRESHOLDS: { 520 ArrayList<Integer> thresholds = 521 ((Bundle) msg.obj).getIntegerArrayList("thresholds"); 522 // TODO: Change signal strength thresholds API to use an ArrayList<Integer> 523 // rather than convert to int[]. 524 int[] intThresholds = new int[(thresholds != null) ? thresholds.size() : 0]; 525 for (int i = 0; i < intThresholds.length; i++) { 526 intThresholds[i] = thresholds.get(i); 527 } 528 onSignalStrengthThresholdsUpdated(intThresholds); 529 break; 530 } 531 case CMD_PREVENT_AUTOMATIC_RECONNECT: { 532 onAutomaticReconnectDisabled(); 533 break; 534 } 535 case CMD_ADD_KEEPALIVE_PACKET_FILTER: { 536 onAddKeepalivePacketFilter(msg.arg1 /* slot */, 537 (KeepalivePacketData) msg.obj /* packet */); 538 break; 539 } 540 case CMD_REMOVE_KEEPALIVE_PACKET_FILTER: { 541 onRemoveKeepalivePacketFilter(msg.arg1 /* slot */); 542 break; 543 } 544 } 545 } 546 } 547 548 /** 549 * Register this network agent with ConnectivityService. 550 * 551 * This method can only be called once per network agent. 552 * 553 * @return the Network associated with this network agent (which can also be obtained later 554 * by calling getNetwork() on this agent). 555 * @throws IllegalStateException thrown by the system server if this network agent is 556 * already registered. 557 */ 558 @NonNull register()559 public Network register() { 560 if (VDBG) log("Registering NetworkAgent"); 561 synchronized (mRegisterLock) { 562 if (mNetwork != null) { 563 throw new IllegalStateException("Agent already registered"); 564 } 565 final ConnectivityManager cm = (ConnectivityManager) mInitialConfiguration.context 566 .getSystemService(Context.CONNECTIVITY_SERVICE); 567 mNetwork = cm.registerNetworkAgent(new Messenger(mHandler), 568 new NetworkInfo(mInitialConfiguration.info), 569 mInitialConfiguration.properties, mInitialConfiguration.capabilities, 570 mInitialConfiguration.score, mInitialConfiguration.config, providerId); 571 mInitialConfiguration = null; // All this memory can now be GC'd 572 } 573 return mNetwork; 574 } 575 576 /** 577 * Register this network agent with a testing harness. 578 * 579 * The returned Messenger sends messages to the Handler. This allows a test to send 580 * this object {@code CMD_*} messages as if they came from ConnectivityService, which 581 * is useful for testing the behavior. 582 * 583 * @hide 584 */ registerForTest(final Network network)585 public Messenger registerForTest(final Network network) { 586 log("Registering NetworkAgent for test"); 587 synchronized (mRegisterLock) { 588 mNetwork = network; 589 mInitialConfiguration = null; 590 } 591 return new Messenger(mHandler); 592 } 593 594 /** 595 * Waits for the handler to be idle. 596 * This is useful for testing, and has smaller scope than an accessor to mHandler. 597 * TODO : move the implementation in common library with the tests 598 * @hide 599 */ 600 @VisibleForTesting waitForIdle(final long timeoutMs)601 public boolean waitForIdle(final long timeoutMs) { 602 final ConditionVariable cv = new ConditionVariable(false); 603 mHandler.post(cv::open); 604 return cv.block(timeoutMs); 605 } 606 607 /** 608 * @return The Network associated with this agent, or null if it's not registered yet. 609 */ 610 @Nullable getNetwork()611 public Network getNetwork() { 612 return mNetwork; 613 } 614 queueOrSendMessage(int what, Object obj)615 private void queueOrSendMessage(int what, Object obj) { 616 queueOrSendMessage(what, 0, 0, obj); 617 } 618 queueOrSendMessage(int what, int arg1, int arg2)619 private void queueOrSendMessage(int what, int arg1, int arg2) { 620 queueOrSendMessage(what, arg1, arg2, null); 621 } 622 queueOrSendMessage(int what, int arg1, int arg2, Object obj)623 private void queueOrSendMessage(int what, int arg1, int arg2, Object obj) { 624 Message msg = Message.obtain(); 625 msg.what = what; 626 msg.arg1 = arg1; 627 msg.arg2 = arg2; 628 msg.obj = obj; 629 queueOrSendMessage(msg); 630 } 631 queueOrSendMessage(Message msg)632 private void queueOrSendMessage(Message msg) { 633 synchronized (mPreConnectedQueue) { 634 if (mAsyncChannel != null) { 635 mAsyncChannel.sendMessage(msg); 636 } else { 637 mPreConnectedQueue.add(msg); 638 } 639 } 640 } 641 642 /** 643 * Must be called by the agent when the network's {@link LinkProperties} change. 644 * @param linkProperties the new LinkProperties. 645 */ sendLinkProperties(@onNull LinkProperties linkProperties)646 public final void sendLinkProperties(@NonNull LinkProperties linkProperties) { 647 Objects.requireNonNull(linkProperties); 648 queueOrSendMessage(EVENT_NETWORK_PROPERTIES_CHANGED, new LinkProperties(linkProperties)); 649 } 650 651 /** 652 * Inform ConnectivityService that this agent has now connected. 653 * Call {@link #unregister} to disconnect. 654 */ markConnected()655 public void markConnected() { 656 if (mIsLegacy) { 657 throw new UnsupportedOperationException( 658 "Legacy agents can't call markConnected."); 659 } 660 // |reason| cannot be used by the non-legacy agents 661 mNetworkInfo.setDetailedState(NetworkInfo.DetailedState.CONNECTED, null /* reason */, 662 mNetworkInfo.getExtraInfo()); 663 queueOrSendMessage(EVENT_NETWORK_INFO_CHANGED, mNetworkInfo); 664 } 665 666 /** 667 * Unregister this network agent. 668 * 669 * This signals the network has disconnected and ends its lifecycle. After this is called, 670 * the network is torn down and this agent can no longer be used. 671 */ unregister()672 public void unregister() { 673 if (mIsLegacy) { 674 throw new UnsupportedOperationException("Legacy agents can't call unregister."); 675 } 676 // When unregistering an agent nobody should use the extrainfo (or reason) any more. 677 mNetworkInfo.setDetailedState(NetworkInfo.DetailedState.DISCONNECTED, null /* reason */, 678 null /* extraInfo */); 679 queueOrSendMessage(EVENT_NETWORK_INFO_CHANGED, mNetworkInfo); 680 } 681 682 /** 683 * Change the legacy subtype of this network agent. 684 * 685 * This is only for backward compatibility and should not be used by non-legacy network agents, 686 * or agents that did not use to set a subtype. As such, only TYPE_MOBILE type agents can use 687 * this and others will be thrown an exception if they try. 688 * 689 * @deprecated this is for backward compatibility only. 690 * @param legacySubtype the legacy subtype. 691 * @hide 692 */ 693 @Deprecated setLegacySubtype(final int legacySubtype, @NonNull final String legacySubtypeName)694 public void setLegacySubtype(final int legacySubtype, @NonNull final String legacySubtypeName) { 695 if (mIsLegacy) { 696 throw new UnsupportedOperationException("Legacy agents can't call setLegacySubtype."); 697 } 698 mNetworkInfo.setSubtype(legacySubtype, legacySubtypeName); 699 queueOrSendMessage(EVENT_NETWORK_INFO_CHANGED, mNetworkInfo); 700 } 701 702 /** 703 * Set the ExtraInfo of this network agent. 704 * 705 * This sets the ExtraInfo field inside the NetworkInfo returned by legacy public API and the 706 * broadcasts about the corresponding Network. 707 * This is only for backward compatibility and should not be used by non-legacy network agents, 708 * who will be thrown an exception if they try. The extra info should only be : 709 * <ul> 710 * <li>For cellular agents, the APN name.</li> 711 * <li>For ethernet agents, the interface name.</li> 712 * </ul> 713 * 714 * @deprecated this is for backward compatibility only. 715 * @param extraInfo the ExtraInfo. 716 * @hide 717 */ 718 @Deprecated setLegacyExtraInfo(@ullable final String extraInfo)719 public void setLegacyExtraInfo(@Nullable final String extraInfo) { 720 if (mIsLegacy) { 721 throw new UnsupportedOperationException("Legacy agents can't call setLegacyExtraInfo."); 722 } 723 mNetworkInfo.setExtraInfo(extraInfo); 724 queueOrSendMessage(EVENT_NETWORK_INFO_CHANGED, mNetworkInfo); 725 } 726 727 /** 728 * Must be called by the agent when it has a new NetworkInfo object. 729 * @hide TODO: expose something better. 730 */ 731 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) sendNetworkInfo(NetworkInfo networkInfo)732 public final void sendNetworkInfo(NetworkInfo networkInfo) { 733 if (!mIsLegacy) { 734 throw new UnsupportedOperationException("Only legacy agents can call sendNetworkInfo."); 735 } 736 queueOrSendMessage(EVENT_NETWORK_INFO_CHANGED, new NetworkInfo(networkInfo)); 737 } 738 739 /** 740 * Must be called by the agent when the network's {@link NetworkCapabilities} change. 741 * @param networkCapabilities the new NetworkCapabilities. 742 */ sendNetworkCapabilities(@onNull NetworkCapabilities networkCapabilities)743 public final void sendNetworkCapabilities(@NonNull NetworkCapabilities networkCapabilities) { 744 Objects.requireNonNull(networkCapabilities); 745 mBandwidthUpdatePending.set(false); 746 mLastBwRefreshTime = System.currentTimeMillis(); 747 queueOrSendMessage(EVENT_NETWORK_CAPABILITIES_CHANGED, 748 new NetworkCapabilities(networkCapabilities)); 749 } 750 751 /** 752 * Must be called by the agent to update the score of this network. 753 * 754 * @param score the new score, between 0 and 99. 755 */ sendNetworkScore(@ntRangefrom = 0, to = 99) int score)756 public final void sendNetworkScore(@IntRange(from = 0, to = 99) int score) { 757 if (score < 0) { 758 throw new IllegalArgumentException("Score must be >= 0"); 759 } 760 queueOrSendMessage(EVENT_NETWORK_SCORE_CHANGED, score, 0); 761 } 762 763 /** 764 * Must be called by the agent to indicate this network was manually selected by the user. 765 * This should be called before the NetworkInfo is marked CONNECTED so that this 766 * Network can be given special treatment at that time. If {@code acceptUnvalidated} is 767 * {@code true}, then the system will switch to this network. If it is {@code false} and the 768 * network cannot be validated, the system will ask the user whether to switch to this network. 769 * If the user confirms and selects "don't ask again", then the system will call 770 * {@link #saveAcceptUnvalidated} to persist the user's choice. Thus, if the transport ever 771 * calls this method with {@code acceptUnvalidated} set to {@code false}, it must also implement 772 * {@link #saveAcceptUnvalidated} to respect the user's choice. 773 * @hide should move to NetworkAgentConfig. 774 */ explicitlySelected(boolean acceptUnvalidated)775 public void explicitlySelected(boolean acceptUnvalidated) { 776 explicitlySelected(true /* explicitlySelected */, acceptUnvalidated); 777 } 778 779 /** 780 * Must be called by the agent to indicate whether the network was manually selected by the 781 * user. This should be called before the network becomes connected, so it can be given 782 * special treatment when it does. 783 * 784 * If {@code explicitlySelected} is {@code true}, and {@code acceptUnvalidated} is {@code true}, 785 * then the system will switch to this network. If {@code explicitlySelected} is {@code true} 786 * and {@code acceptUnvalidated} is {@code false}, and the network cannot be validated, the 787 * system will ask the user whether to switch to this network. If the user confirms and selects 788 * "don't ask again", then the system will call {@link #saveAcceptUnvalidated} to persist the 789 * user's choice. Thus, if the transport ever calls this method with {@code explicitlySelected} 790 * set to {@code true} and {@code acceptUnvalidated} set to {@code false}, it must also 791 * implement {@link #saveAcceptUnvalidated} to respect the user's choice. 792 * 793 * If {@code explicitlySelected} is {@code false} and {@code acceptUnvalidated} is 794 * {@code true}, the system will interpret this as the user having accepted partial connectivity 795 * on this network. Thus, the system will switch to the network and consider it validated even 796 * if it only provides partial connectivity, but the network is not otherwise treated specially. 797 * @hide should move to NetworkAgentConfig. 798 */ explicitlySelected(boolean explicitlySelected, boolean acceptUnvalidated)799 public void explicitlySelected(boolean explicitlySelected, boolean acceptUnvalidated) { 800 queueOrSendMessage(EVENT_SET_EXPLICITLY_SELECTED, 801 explicitlySelected ? 1 : 0, 802 acceptUnvalidated ? 1 : 0); 803 } 804 805 /** 806 * Called when ConnectivityService has indicated they no longer want this network. 807 * The parent factory should (previously) have received indication of the change 808 * as well, either canceling NetworkRequests or altering their score such that this 809 * network won't be immediately requested again. 810 */ onNetworkUnwanted()811 public void onNetworkUnwanted() { 812 unwanted(); 813 } 814 /** @hide TODO delete once subclasses have moved to onNetworkUnwanted. */ unwanted()815 protected void unwanted() { 816 } 817 818 /** 819 * Called when ConnectivityService request a bandwidth update. The parent factory 820 * shall try to overwrite this method and produce a bandwidth update if capable. 821 * @hide 822 */ onBandwidthUpdateRequested()823 public void onBandwidthUpdateRequested() { 824 pollLceData(); 825 } 826 /** @hide TODO delete once subclasses have moved to onBandwidthUpdateRequested. */ pollLceData()827 protected void pollLceData() { 828 } 829 830 /** 831 * Called when the system determines the usefulness of this network. 832 * 833 * The system attempts to validate Internet connectivity on networks that provide the 834 * {@link NetworkCapabilities#NET_CAPABILITY_INTERNET} capability. 835 * 836 * Currently there are two possible values: 837 * {@code VALIDATION_STATUS_VALID} if Internet connectivity was validated, 838 * {@code VALIDATION_STATUS_NOT_VALID} if Internet connectivity was not validated. 839 * 840 * This is guaranteed to be called again when the network status changes, but the system 841 * may also call this multiple times even if the status does not change. 842 * 843 * @param status one of {@code VALIDATION_STATUS_VALID} or {@code VALIDATION_STATUS_NOT_VALID}. 844 * @param redirectUri If Internet connectivity is being redirected (e.g., on a captive portal), 845 * this is the destination the probes are being redirected to, otherwise {@code null}. 846 */ onValidationStatus(@alidationStatus int status, @Nullable Uri redirectUri)847 public void onValidationStatus(@ValidationStatus int status, @Nullable Uri redirectUri) { 848 networkStatus(status, null == redirectUri ? "" : redirectUri.toString()); 849 } 850 /** @hide TODO delete once subclasses have moved to onValidationStatus */ networkStatus(int status, String redirectUrl)851 protected void networkStatus(int status, String redirectUrl) { 852 } 853 854 855 /** 856 * Called when the user asks to remember the choice to use this network even if unvalidated. 857 * The transport is responsible for remembering the choice, and the next time the user connects 858 * to the network, should explicitlySelected with {@code acceptUnvalidated} set to {@code true}. 859 * This method will only be called if {@link #explicitlySelected} was called with 860 * {@code acceptUnvalidated} set to {@code false}. 861 * @param accept whether the user wants to use the network even if unvalidated. 862 */ onSaveAcceptUnvalidated(boolean accept)863 public void onSaveAcceptUnvalidated(boolean accept) { 864 saveAcceptUnvalidated(accept); 865 } 866 /** @hide TODO delete once subclasses have moved to onSaveAcceptUnvalidated */ saveAcceptUnvalidated(boolean accept)867 protected void saveAcceptUnvalidated(boolean accept) { 868 } 869 870 /** 871 * Requests that the network hardware send the specified packet at the specified interval. 872 * 873 * @param slot the hardware slot on which to start the keepalive. 874 * @param interval the interval between packets, between 10 and 3600. Note that this API 875 * does not support sub-second precision and will round off the request. 876 * @param packet the packet to send. 877 */ 878 // seconds is from SocketKeepalive.MIN_INTERVAL_SEC to MAX_INTERVAL_SEC, but these should 879 // not be exposed as constants because they may change in the future (API guideline 4.8) 880 // and should have getters if exposed at all. Getters can't be used in the annotation, 881 // so the values unfortunately need to be copied. onStartSocketKeepalive(int slot, @NonNull Duration interval, @NonNull KeepalivePacketData packet)882 public void onStartSocketKeepalive(int slot, @NonNull Duration interval, 883 @NonNull KeepalivePacketData packet) { 884 final long intervalSeconds = interval.getSeconds(); 885 if (intervalSeconds < SocketKeepalive.MIN_INTERVAL_SEC 886 || intervalSeconds > SocketKeepalive.MAX_INTERVAL_SEC) { 887 throw new IllegalArgumentException("Interval needs to be comprised between " 888 + SocketKeepalive.MIN_INTERVAL_SEC + " and " + SocketKeepalive.MAX_INTERVAL_SEC 889 + " but was " + intervalSeconds); 890 } 891 final Message msg = mHandler.obtainMessage(CMD_START_SOCKET_KEEPALIVE, slot, 892 (int) intervalSeconds, packet); 893 startSocketKeepalive(msg); 894 msg.recycle(); 895 } 896 /** @hide TODO delete once subclasses have moved to onStartSocketKeepalive */ startSocketKeepalive(Message msg)897 protected void startSocketKeepalive(Message msg) { 898 onSocketKeepaliveEvent(msg.arg1, SocketKeepalive.ERROR_UNSUPPORTED); 899 } 900 901 /** 902 * Requests that the network hardware stop a previously-started keepalive. 903 * 904 * @param slot the hardware slot on which to stop the keepalive. 905 */ onStopSocketKeepalive(int slot)906 public void onStopSocketKeepalive(int slot) { 907 Message msg = mHandler.obtainMessage(CMD_STOP_SOCKET_KEEPALIVE, slot, 0, null); 908 stopSocketKeepalive(msg); 909 msg.recycle(); 910 } 911 /** @hide TODO delete once subclasses have moved to onStopSocketKeepalive */ stopSocketKeepalive(Message msg)912 protected void stopSocketKeepalive(Message msg) { 913 onSocketKeepaliveEvent(msg.arg1, SocketKeepalive.ERROR_UNSUPPORTED); 914 } 915 916 /** 917 * Must be called by the agent when a socket keepalive event occurs. 918 * 919 * @param slot the hardware slot on which the event occurred. 920 * @param event the event that occurred, as one of the SocketKeepalive.ERROR_* 921 * or SocketKeepalive.SUCCESS constants. 922 */ sendSocketKeepaliveEvent(int slot, @SocketKeepalive.KeepaliveEvent int event)923 public final void sendSocketKeepaliveEvent(int slot, 924 @SocketKeepalive.KeepaliveEvent int event) { 925 queueOrSendMessage(EVENT_SOCKET_KEEPALIVE, slot, event); 926 } 927 /** @hide TODO delete once callers have moved to sendSocketKeepaliveEvent */ onSocketKeepaliveEvent(int slot, int reason)928 public void onSocketKeepaliveEvent(int slot, int reason) { 929 sendSocketKeepaliveEvent(slot, reason); 930 } 931 932 /** 933 * Called by ConnectivityService to add specific packet filter to network hardware to block 934 * replies (e.g., TCP ACKs) matching the sent keepalive packets. Implementations that support 935 * this feature must override this method. 936 * 937 * @param slot the hardware slot on which the keepalive should be sent. 938 * @param packet the packet that is being sent. 939 */ onAddKeepalivePacketFilter(int slot, @NonNull KeepalivePacketData packet)940 public void onAddKeepalivePacketFilter(int slot, @NonNull KeepalivePacketData packet) { 941 Message msg = mHandler.obtainMessage(CMD_ADD_KEEPALIVE_PACKET_FILTER, slot, 0, packet); 942 addKeepalivePacketFilter(msg); 943 msg.recycle(); 944 } 945 /** @hide TODO delete once subclasses have moved to onAddKeepalivePacketFilter */ addKeepalivePacketFilter(Message msg)946 protected void addKeepalivePacketFilter(Message msg) { 947 } 948 949 /** 950 * Called by ConnectivityService to remove a packet filter installed with 951 * {@link #addKeepalivePacketFilter(Message)}. Implementations that support this feature 952 * must override this method. 953 * 954 * @param slot the hardware slot on which the keepalive is being sent. 955 */ onRemoveKeepalivePacketFilter(int slot)956 public void onRemoveKeepalivePacketFilter(int slot) { 957 Message msg = mHandler.obtainMessage(CMD_REMOVE_KEEPALIVE_PACKET_FILTER, slot, 0, null); 958 removeKeepalivePacketFilter(msg); 959 msg.recycle(); 960 } 961 /** @hide TODO delete once subclasses have moved to onRemoveKeepalivePacketFilter */ removeKeepalivePacketFilter(Message msg)962 protected void removeKeepalivePacketFilter(Message msg) { 963 } 964 965 /** 966 * Called by ConnectivityService to inform this network agent of signal strength thresholds 967 * that when crossed should trigger a system wakeup and a NetworkCapabilities update. 968 * 969 * When the system updates the list of thresholds that should wake up the CPU for a 970 * given agent it will call this method on the agent. The agent that implement this 971 * should implement it in hardware so as to ensure the CPU will be woken up on breach. 972 * Agents are expected to react to a breach by sending an updated NetworkCapabilities 973 * object with the appropriate signal strength to sendNetworkCapabilities. 974 * 975 * The specific units are bearer-dependent. See details on the units and requests in 976 * {@link NetworkCapabilities.Builder#setSignalStrength}. 977 * 978 * @param thresholds the array of thresholds that should trigger wakeups. 979 */ onSignalStrengthThresholdsUpdated(@onNull int[] thresholds)980 public void onSignalStrengthThresholdsUpdated(@NonNull int[] thresholds) { 981 setSignalStrengthThresholds(thresholds); 982 } 983 /** @hide TODO delete once subclasses have moved to onSetSignalStrengthThresholds */ setSignalStrengthThresholds(int[] thresholds)984 protected void setSignalStrengthThresholds(int[] thresholds) { 985 } 986 987 /** 988 * Called when the user asks to not stay connected to this network because it was found to not 989 * provide Internet access. Usually followed by call to {@code unwanted}. The transport is 990 * responsible for making sure the device does not automatically reconnect to the same network 991 * after the {@code unwanted} call. 992 */ onAutomaticReconnectDisabled()993 public void onAutomaticReconnectDisabled() { 994 preventAutomaticReconnect(); 995 } 996 /** @hide TODO delete once subclasses have moved to onAutomaticReconnectDisabled */ preventAutomaticReconnect()997 protected void preventAutomaticReconnect() { 998 } 999 1000 /** @hide */ log(String s)1001 protected void log(String s) { 1002 Log.d(LOG_TAG, "NetworkAgent: " + s); 1003 } 1004 } 1005