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, config.legacyType, 358 config.legacyTypeName, ""); 359 ni.setIsAvailable(true); 360 ni.setExtraInfo(config.getLegacyExtraInfo()); 361 return ni; 362 } 363 364 /** 365 * Create a new network agent. 366 * @param context a {@link Context} to get system services from. 367 * @param looper the {@link Looper} on which to invoke the callbacks. 368 * @param logTag the tag for logs 369 * @param nc the initial {@link NetworkCapabilities} of this network. Update with 370 * sendNetworkCapabilities. 371 * @param lp the initial {@link LinkProperties} of this network. Update with sendLinkProperties. 372 * @param score the initial score of this network. Update with sendNetworkScore. 373 * @param config an immutable {@link NetworkAgentConfig} for this agent. 374 * @param provider the {@link NetworkProvider} managing this agent. 375 */ NetworkAgent(@onNull Context context, @NonNull Looper looper, @NonNull String logTag, @NonNull NetworkCapabilities nc, @NonNull LinkProperties lp, int score, @NonNull NetworkAgentConfig config, @Nullable NetworkProvider provider)376 public NetworkAgent(@NonNull Context context, @NonNull Looper looper, @NonNull String logTag, 377 @NonNull NetworkCapabilities nc, @NonNull LinkProperties lp, int score, 378 @NonNull NetworkAgentConfig config, @Nullable NetworkProvider provider) { 379 this(looper, context, logTag, nc, lp, score, config, 380 provider == null ? NetworkProvider.ID_NONE : provider.getProviderId(), 381 getLegacyNetworkInfo(config), false /* legacy */); 382 } 383 384 private static class InitialConfiguration { 385 public final Context context; 386 public final NetworkCapabilities capabilities; 387 public final LinkProperties properties; 388 public final int score; 389 public final NetworkAgentConfig config; 390 public final NetworkInfo info; InitialConfiguration(@onNull Context context, @NonNull NetworkCapabilities capabilities, @NonNull LinkProperties properties, int score, @NonNull NetworkAgentConfig config, @NonNull NetworkInfo info)391 InitialConfiguration(@NonNull Context context, @NonNull NetworkCapabilities capabilities, 392 @NonNull LinkProperties properties, int score, @NonNull NetworkAgentConfig config, 393 @NonNull NetworkInfo info) { 394 this.context = context; 395 this.capabilities = capabilities; 396 this.properties = properties; 397 this.score = score; 398 this.config = config; 399 this.info = info; 400 } 401 } 402 private volatile InitialConfiguration mInitialConfiguration; 403 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)404 private NetworkAgent(@NonNull Looper looper, @NonNull Context context, @NonNull String logTag, 405 @NonNull NetworkCapabilities nc, @NonNull LinkProperties lp, int score, 406 @NonNull NetworkAgentConfig config, int providerId, @NonNull NetworkInfo ni, 407 boolean legacy) { 408 mHandler = new NetworkAgentHandler(looper); 409 LOG_TAG = logTag; 410 mIsLegacy = legacy; 411 mNetworkInfo = new NetworkInfo(ni); 412 this.providerId = providerId; 413 if (ni == null || nc == null || lp == null) { 414 throw new IllegalArgumentException(); 415 } 416 417 mInitialConfiguration = new InitialConfiguration(context, new NetworkCapabilities(nc), 418 new LinkProperties(lp), score, config, ni); 419 } 420 421 private class NetworkAgentHandler extends Handler { NetworkAgentHandler(Looper looper)422 NetworkAgentHandler(Looper looper) { 423 super(looper); 424 } 425 426 @Override handleMessage(Message msg)427 public void handleMessage(Message msg) { 428 switch (msg.what) { 429 case AsyncChannel.CMD_CHANNEL_FULL_CONNECTION: { 430 if (mAsyncChannel != null) { 431 log("Received new connection while already connected!"); 432 } else { 433 if (VDBG) log("NetworkAgent fully connected"); 434 AsyncChannel ac = new AsyncChannel(); 435 ac.connected(null, this, msg.replyTo); 436 ac.replyToMessage(msg, AsyncChannel.CMD_CHANNEL_FULLY_CONNECTED, 437 AsyncChannel.STATUS_SUCCESSFUL); 438 synchronized (mPreConnectedQueue) { 439 mAsyncChannel = ac; 440 for (Message m : mPreConnectedQueue) { 441 ac.sendMessage(m); 442 } 443 mPreConnectedQueue.clear(); 444 } 445 } 446 break; 447 } 448 case AsyncChannel.CMD_CHANNEL_DISCONNECT: { 449 if (VDBG) log("CMD_CHANNEL_DISCONNECT"); 450 if (mAsyncChannel != null) mAsyncChannel.disconnect(); 451 break; 452 } 453 case AsyncChannel.CMD_CHANNEL_DISCONNECTED: { 454 if (DBG) log("NetworkAgent channel lost"); 455 // let the client know CS is done with us. 456 onNetworkUnwanted(); 457 synchronized (mPreConnectedQueue) { 458 mAsyncChannel = null; 459 } 460 break; 461 } 462 case CMD_SUSPECT_BAD: { 463 log("Unhandled Message " + msg); 464 break; 465 } 466 case CMD_REQUEST_BANDWIDTH_UPDATE: { 467 long currentTimeMs = System.currentTimeMillis(); 468 if (VDBG) { 469 log("CMD_REQUEST_BANDWIDTH_UPDATE request received."); 470 } 471 if (currentTimeMs >= (mLastBwRefreshTime + BW_REFRESH_MIN_WIN_MS)) { 472 mBandwidthUpdateScheduled = false; 473 if (!mBandwidthUpdatePending.getAndSet(true)) { 474 onBandwidthUpdateRequested(); 475 } 476 } else { 477 // deliver the request at a later time rather than discard it completely. 478 if (!mBandwidthUpdateScheduled) { 479 long waitTime = mLastBwRefreshTime + BW_REFRESH_MIN_WIN_MS 480 - currentTimeMs + 1; 481 mBandwidthUpdateScheduled = sendEmptyMessageDelayed( 482 CMD_REQUEST_BANDWIDTH_UPDATE, waitTime); 483 } 484 } 485 break; 486 } 487 case CMD_REPORT_NETWORK_STATUS: { 488 String redirectUrl = ((Bundle) msg.obj).getString(REDIRECT_URL_KEY); 489 if (VDBG) { 490 log("CMD_REPORT_NETWORK_STATUS(" 491 + (msg.arg1 == VALID_NETWORK ? "VALID, " : "INVALID, ") 492 + redirectUrl); 493 } 494 Uri uri = null; 495 try { 496 if (null != redirectUrl) { 497 uri = Uri.parse(redirectUrl); 498 } 499 } catch (Exception e) { 500 Log.wtf(LOG_TAG, "Surprising URI : " + redirectUrl, e); 501 } 502 onValidationStatus(msg.arg1 /* status */, uri); 503 break; 504 } 505 case CMD_SAVE_ACCEPT_UNVALIDATED: { 506 onSaveAcceptUnvalidated(msg.arg1 != 0); 507 break; 508 } 509 case CMD_START_SOCKET_KEEPALIVE: { 510 onStartSocketKeepalive(msg.arg1 /* slot */, 511 Duration.ofSeconds(msg.arg2) /* interval */, 512 (KeepalivePacketData) msg.obj /* packet */); 513 break; 514 } 515 case CMD_STOP_SOCKET_KEEPALIVE: { 516 onStopSocketKeepalive(msg.arg1 /* slot */); 517 break; 518 } 519 520 case CMD_SET_SIGNAL_STRENGTH_THRESHOLDS: { 521 ArrayList<Integer> thresholds = 522 ((Bundle) msg.obj).getIntegerArrayList("thresholds"); 523 // TODO: Change signal strength thresholds API to use an ArrayList<Integer> 524 // rather than convert to int[]. 525 int[] intThresholds = new int[(thresholds != null) ? thresholds.size() : 0]; 526 for (int i = 0; i < intThresholds.length; i++) { 527 intThresholds[i] = thresholds.get(i); 528 } 529 onSignalStrengthThresholdsUpdated(intThresholds); 530 break; 531 } 532 case CMD_PREVENT_AUTOMATIC_RECONNECT: { 533 onAutomaticReconnectDisabled(); 534 break; 535 } 536 case CMD_ADD_KEEPALIVE_PACKET_FILTER: { 537 onAddKeepalivePacketFilter(msg.arg1 /* slot */, 538 (KeepalivePacketData) msg.obj /* packet */); 539 break; 540 } 541 case CMD_REMOVE_KEEPALIVE_PACKET_FILTER: { 542 onRemoveKeepalivePacketFilter(msg.arg1 /* slot */); 543 break; 544 } 545 } 546 } 547 } 548 549 /** 550 * Register this network agent with ConnectivityService. 551 * 552 * This method can only be called once per network agent. 553 * 554 * @return the Network associated with this network agent (which can also be obtained later 555 * by calling getNetwork() on this agent). 556 * @throws IllegalStateException thrown by the system server if this network agent is 557 * already registered. 558 */ 559 @NonNull register()560 public Network register() { 561 if (VDBG) log("Registering NetworkAgent"); 562 synchronized (mRegisterLock) { 563 if (mNetwork != null) { 564 throw new IllegalStateException("Agent already registered"); 565 } 566 final ConnectivityManager cm = (ConnectivityManager) mInitialConfiguration.context 567 .getSystemService(Context.CONNECTIVITY_SERVICE); 568 mNetwork = cm.registerNetworkAgent(new Messenger(mHandler), 569 new NetworkInfo(mInitialConfiguration.info), 570 mInitialConfiguration.properties, mInitialConfiguration.capabilities, 571 mInitialConfiguration.score, mInitialConfiguration.config, providerId); 572 mInitialConfiguration = null; // All this memory can now be GC'd 573 } 574 return mNetwork; 575 } 576 577 /** 578 * Register this network agent with a testing harness. 579 * 580 * The returned Messenger sends messages to the Handler. This allows a test to send 581 * this object {@code CMD_*} messages as if they came from ConnectivityService, which 582 * is useful for testing the behavior. 583 * 584 * @hide 585 */ registerForTest(final Network network)586 public Messenger registerForTest(final Network network) { 587 log("Registering NetworkAgent for test"); 588 synchronized (mRegisterLock) { 589 mNetwork = network; 590 mInitialConfiguration = null; 591 } 592 return new Messenger(mHandler); 593 } 594 595 /** 596 * Waits for the handler to be idle. 597 * This is useful for testing, and has smaller scope than an accessor to mHandler. 598 * TODO : move the implementation in common library with the tests 599 * @hide 600 */ 601 @VisibleForTesting waitForIdle(final long timeoutMs)602 public boolean waitForIdle(final long timeoutMs) { 603 final ConditionVariable cv = new ConditionVariable(false); 604 mHandler.post(cv::open); 605 return cv.block(timeoutMs); 606 } 607 608 /** 609 * @return The Network associated with this agent, or null if it's not registered yet. 610 */ 611 @Nullable getNetwork()612 public Network getNetwork() { 613 return mNetwork; 614 } 615 queueOrSendMessage(int what, Object obj)616 private void queueOrSendMessage(int what, Object obj) { 617 queueOrSendMessage(what, 0, 0, obj); 618 } 619 queueOrSendMessage(int what, int arg1, int arg2)620 private void queueOrSendMessage(int what, int arg1, int arg2) { 621 queueOrSendMessage(what, arg1, arg2, null); 622 } 623 queueOrSendMessage(int what, int arg1, int arg2, Object obj)624 private void queueOrSendMessage(int what, int arg1, int arg2, Object obj) { 625 Message msg = Message.obtain(); 626 msg.what = what; 627 msg.arg1 = arg1; 628 msg.arg2 = arg2; 629 msg.obj = obj; 630 queueOrSendMessage(msg); 631 } 632 queueOrSendMessage(Message msg)633 private void queueOrSendMessage(Message msg) { 634 synchronized (mPreConnectedQueue) { 635 if (mAsyncChannel != null) { 636 mAsyncChannel.sendMessage(msg); 637 } else { 638 mPreConnectedQueue.add(msg); 639 } 640 } 641 } 642 643 /** 644 * Must be called by the agent when the network's {@link LinkProperties} change. 645 * @param linkProperties the new LinkProperties. 646 */ sendLinkProperties(@onNull LinkProperties linkProperties)647 public final void sendLinkProperties(@NonNull LinkProperties linkProperties) { 648 Objects.requireNonNull(linkProperties); 649 queueOrSendMessage(EVENT_NETWORK_PROPERTIES_CHANGED, new LinkProperties(linkProperties)); 650 } 651 652 /** 653 * Inform ConnectivityService that this agent has now connected. 654 * Call {@link #unregister} to disconnect. 655 */ markConnected()656 public void markConnected() { 657 if (mIsLegacy) { 658 throw new UnsupportedOperationException( 659 "Legacy agents can't call markConnected."); 660 } 661 // |reason| cannot be used by the non-legacy agents 662 mNetworkInfo.setDetailedState(NetworkInfo.DetailedState.CONNECTED, null /* reason */, 663 mNetworkInfo.getExtraInfo()); 664 queueOrSendMessage(EVENT_NETWORK_INFO_CHANGED, mNetworkInfo); 665 } 666 667 /** 668 * Unregister this network agent. 669 * 670 * This signals the network has disconnected and ends its lifecycle. After this is called, 671 * the network is torn down and this agent can no longer be used. 672 */ unregister()673 public void unregister() { 674 if (mIsLegacy) { 675 throw new UnsupportedOperationException("Legacy agents can't call unregister."); 676 } 677 // When unregistering an agent nobody should use the extrainfo (or reason) any more. 678 mNetworkInfo.setDetailedState(NetworkInfo.DetailedState.DISCONNECTED, null /* reason */, 679 null /* extraInfo */); 680 queueOrSendMessage(EVENT_NETWORK_INFO_CHANGED, mNetworkInfo); 681 } 682 683 /** 684 * Change the legacy subtype of this network agent. 685 * 686 * This is only for backward compatibility and should not be used by non-legacy network agents, 687 * or agents that did not use to set a subtype. As such, only TYPE_MOBILE type agents can use 688 * this and others will be thrown an exception if they try. 689 * 690 * @deprecated this is for backward compatibility only. 691 * @param legacySubtype the legacy subtype. 692 * @hide 693 */ 694 @Deprecated setLegacySubtype(final int legacySubtype, @NonNull final String legacySubtypeName)695 public void setLegacySubtype(final int legacySubtype, @NonNull final String legacySubtypeName) { 696 if (mIsLegacy) { 697 throw new UnsupportedOperationException("Legacy agents can't call setLegacySubtype."); 698 } 699 mNetworkInfo.setSubtype(legacySubtype, legacySubtypeName); 700 queueOrSendMessage(EVENT_NETWORK_INFO_CHANGED, mNetworkInfo); 701 } 702 703 /** 704 * Set the ExtraInfo of this network agent. 705 * 706 * This sets the ExtraInfo field inside the NetworkInfo returned by legacy public API and the 707 * broadcasts about the corresponding Network. 708 * This is only for backward compatibility and should not be used by non-legacy network agents, 709 * who will be thrown an exception if they try. The extra info should only be : 710 * <ul> 711 * <li>For cellular agents, the APN name.</li> 712 * <li>For ethernet agents, the interface name.</li> 713 * </ul> 714 * 715 * @deprecated this is for backward compatibility only. 716 * @param extraInfo the ExtraInfo. 717 * @hide 718 */ 719 @Deprecated setLegacyExtraInfo(@ullable final String extraInfo)720 public void setLegacyExtraInfo(@Nullable final String extraInfo) { 721 if (mIsLegacy) { 722 throw new UnsupportedOperationException("Legacy agents can't call setLegacyExtraInfo."); 723 } 724 mNetworkInfo.setExtraInfo(extraInfo); 725 queueOrSendMessage(EVENT_NETWORK_INFO_CHANGED, mNetworkInfo); 726 } 727 728 /** 729 * Must be called by the agent when it has a new NetworkInfo object. 730 * @hide TODO: expose something better. 731 */ 732 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) sendNetworkInfo(NetworkInfo networkInfo)733 public final void sendNetworkInfo(NetworkInfo networkInfo) { 734 if (!mIsLegacy) { 735 throw new UnsupportedOperationException("Only legacy agents can call sendNetworkInfo."); 736 } 737 queueOrSendMessage(EVENT_NETWORK_INFO_CHANGED, new NetworkInfo(networkInfo)); 738 } 739 740 /** 741 * Must be called by the agent when the network's {@link NetworkCapabilities} change. 742 * @param networkCapabilities the new NetworkCapabilities. 743 */ sendNetworkCapabilities(@onNull NetworkCapabilities networkCapabilities)744 public final void sendNetworkCapabilities(@NonNull NetworkCapabilities networkCapabilities) { 745 Objects.requireNonNull(networkCapabilities); 746 mBandwidthUpdatePending.set(false); 747 mLastBwRefreshTime = System.currentTimeMillis(); 748 queueOrSendMessage(EVENT_NETWORK_CAPABILITIES_CHANGED, 749 new NetworkCapabilities(networkCapabilities)); 750 } 751 752 /** 753 * Must be called by the agent to update the score of this network. 754 * 755 * @param score the new score, between 0 and 99. 756 */ sendNetworkScore(@ntRangefrom = 0, to = 99) int score)757 public final void sendNetworkScore(@IntRange(from = 0, to = 99) int score) { 758 if (score < 0) { 759 throw new IllegalArgumentException("Score must be >= 0"); 760 } 761 queueOrSendMessage(EVENT_NETWORK_SCORE_CHANGED, score, 0); 762 } 763 764 /** 765 * Must be called by the agent to indicate this network was manually selected by the user. 766 * This should be called before the NetworkInfo is marked CONNECTED so that this 767 * Network can be given special treatment at that time. If {@code acceptUnvalidated} is 768 * {@code true}, then the system will switch to this network. If it is {@code false} and the 769 * network cannot be validated, the system will ask the user whether to switch to this network. 770 * If the user confirms and selects "don't ask again", then the system will call 771 * {@link #saveAcceptUnvalidated} to persist the user's choice. Thus, if the transport ever 772 * calls this method with {@code acceptUnvalidated} set to {@code false}, it must also implement 773 * {@link #saveAcceptUnvalidated} to respect the user's choice. 774 * @hide should move to NetworkAgentConfig. 775 */ explicitlySelected(boolean acceptUnvalidated)776 public void explicitlySelected(boolean acceptUnvalidated) { 777 explicitlySelected(true /* explicitlySelected */, acceptUnvalidated); 778 } 779 780 /** 781 * Must be called by the agent to indicate whether the network was manually selected by the 782 * user. This should be called before the network becomes connected, so it can be given 783 * special treatment when it does. 784 * 785 * If {@code explicitlySelected} is {@code true}, and {@code acceptUnvalidated} is {@code true}, 786 * then the system will switch to this network. If {@code explicitlySelected} is {@code true} 787 * and {@code acceptUnvalidated} is {@code false}, and the network cannot be validated, the 788 * system will ask the user whether to switch to this network. If the user confirms and selects 789 * "don't ask again", then the system will call {@link #saveAcceptUnvalidated} to persist the 790 * user's choice. Thus, if the transport ever calls this method with {@code explicitlySelected} 791 * set to {@code true} and {@code acceptUnvalidated} set to {@code false}, it must also 792 * implement {@link #saveAcceptUnvalidated} to respect the user's choice. 793 * 794 * If {@code explicitlySelected} is {@code false} and {@code acceptUnvalidated} is 795 * {@code true}, the system will interpret this as the user having accepted partial connectivity 796 * on this network. Thus, the system will switch to the network and consider it validated even 797 * if it only provides partial connectivity, but the network is not otherwise treated specially. 798 * @hide should move to NetworkAgentConfig. 799 */ explicitlySelected(boolean explicitlySelected, boolean acceptUnvalidated)800 public void explicitlySelected(boolean explicitlySelected, boolean acceptUnvalidated) { 801 queueOrSendMessage(EVENT_SET_EXPLICITLY_SELECTED, 802 explicitlySelected ? 1 : 0, 803 acceptUnvalidated ? 1 : 0); 804 } 805 806 /** 807 * Called when ConnectivityService has indicated they no longer want this network. 808 * The parent factory should (previously) have received indication of the change 809 * as well, either canceling NetworkRequests or altering their score such that this 810 * network won't be immediately requested again. 811 */ onNetworkUnwanted()812 public void onNetworkUnwanted() { 813 unwanted(); 814 } 815 /** @hide TODO delete once subclasses have moved to onNetworkUnwanted. */ unwanted()816 protected void unwanted() { 817 } 818 819 /** 820 * Called when ConnectivityService request a bandwidth update. The parent factory 821 * shall try to overwrite this method and produce a bandwidth update if capable. 822 * @hide 823 */ onBandwidthUpdateRequested()824 public void onBandwidthUpdateRequested() { 825 pollLceData(); 826 } 827 /** @hide TODO delete once subclasses have moved to onBandwidthUpdateRequested. */ pollLceData()828 protected void pollLceData() { 829 } 830 831 /** 832 * Called when the system determines the usefulness of this network. 833 * 834 * The system attempts to validate Internet connectivity on networks that provide the 835 * {@link NetworkCapabilities#NET_CAPABILITY_INTERNET} capability. 836 * 837 * Currently there are two possible values: 838 * {@code VALIDATION_STATUS_VALID} if Internet connectivity was validated, 839 * {@code VALIDATION_STATUS_NOT_VALID} if Internet connectivity was not validated. 840 * 841 * This is guaranteed to be called again when the network status changes, but the system 842 * may also call this multiple times even if the status does not change. 843 * 844 * @param status one of {@code VALIDATION_STATUS_VALID} or {@code VALIDATION_STATUS_NOT_VALID}. 845 * @param redirectUri If Internet connectivity is being redirected (e.g., on a captive portal), 846 * this is the destination the probes are being redirected to, otherwise {@code null}. 847 */ onValidationStatus(@alidationStatus int status, @Nullable Uri redirectUri)848 public void onValidationStatus(@ValidationStatus int status, @Nullable Uri redirectUri) { 849 networkStatus(status, null == redirectUri ? "" : redirectUri.toString()); 850 } 851 /** @hide TODO delete once subclasses have moved to onValidationStatus */ networkStatus(int status, String redirectUrl)852 protected void networkStatus(int status, String redirectUrl) { 853 } 854 855 856 /** 857 * Called when the user asks to remember the choice to use this network even if unvalidated. 858 * The transport is responsible for remembering the choice, and the next time the user connects 859 * to the network, should explicitlySelected with {@code acceptUnvalidated} set to {@code true}. 860 * This method will only be called if {@link #explicitlySelected} was called with 861 * {@code acceptUnvalidated} set to {@code false}. 862 * @param accept whether the user wants to use the network even if unvalidated. 863 */ onSaveAcceptUnvalidated(boolean accept)864 public void onSaveAcceptUnvalidated(boolean accept) { 865 saveAcceptUnvalidated(accept); 866 } 867 /** @hide TODO delete once subclasses have moved to onSaveAcceptUnvalidated */ saveAcceptUnvalidated(boolean accept)868 protected void saveAcceptUnvalidated(boolean accept) { 869 } 870 871 /** 872 * Requests that the network hardware send the specified packet at the specified interval. 873 * 874 * @param slot the hardware slot on which to start the keepalive. 875 * @param interval the interval between packets, between 10 and 3600. Note that this API 876 * does not support sub-second precision and will round off the request. 877 * @param packet the packet to send. 878 */ 879 // seconds is from SocketKeepalive.MIN_INTERVAL_SEC to MAX_INTERVAL_SEC, but these should 880 // not be exposed as constants because they may change in the future (API guideline 4.8) 881 // and should have getters if exposed at all. Getters can't be used in the annotation, 882 // so the values unfortunately need to be copied. onStartSocketKeepalive(int slot, @NonNull Duration interval, @NonNull KeepalivePacketData packet)883 public void onStartSocketKeepalive(int slot, @NonNull Duration interval, 884 @NonNull KeepalivePacketData packet) { 885 final long intervalSeconds = interval.getSeconds(); 886 if (intervalSeconds < SocketKeepalive.MIN_INTERVAL_SEC 887 || intervalSeconds > SocketKeepalive.MAX_INTERVAL_SEC) { 888 throw new IllegalArgumentException("Interval needs to be comprised between " 889 + SocketKeepalive.MIN_INTERVAL_SEC + " and " + SocketKeepalive.MAX_INTERVAL_SEC 890 + " but was " + intervalSeconds); 891 } 892 final Message msg = mHandler.obtainMessage(CMD_START_SOCKET_KEEPALIVE, slot, 893 (int) intervalSeconds, packet); 894 startSocketKeepalive(msg); 895 msg.recycle(); 896 } 897 /** @hide TODO delete once subclasses have moved to onStartSocketKeepalive */ startSocketKeepalive(Message msg)898 protected void startSocketKeepalive(Message msg) { 899 onSocketKeepaliveEvent(msg.arg1, SocketKeepalive.ERROR_UNSUPPORTED); 900 } 901 902 /** 903 * Requests that the network hardware stop a previously-started keepalive. 904 * 905 * @param slot the hardware slot on which to stop the keepalive. 906 */ onStopSocketKeepalive(int slot)907 public void onStopSocketKeepalive(int slot) { 908 Message msg = mHandler.obtainMessage(CMD_STOP_SOCKET_KEEPALIVE, slot, 0, null); 909 stopSocketKeepalive(msg); 910 msg.recycle(); 911 } 912 /** @hide TODO delete once subclasses have moved to onStopSocketKeepalive */ stopSocketKeepalive(Message msg)913 protected void stopSocketKeepalive(Message msg) { 914 onSocketKeepaliveEvent(msg.arg1, SocketKeepalive.ERROR_UNSUPPORTED); 915 } 916 917 /** 918 * Must be called by the agent when a socket keepalive event occurs. 919 * 920 * @param slot the hardware slot on which the event occurred. 921 * @param event the event that occurred, as one of the SocketKeepalive.ERROR_* 922 * or SocketKeepalive.SUCCESS constants. 923 */ sendSocketKeepaliveEvent(int slot, @SocketKeepalive.KeepaliveEvent int event)924 public final void sendSocketKeepaliveEvent(int slot, 925 @SocketKeepalive.KeepaliveEvent int event) { 926 queueOrSendMessage(EVENT_SOCKET_KEEPALIVE, slot, event); 927 } 928 /** @hide TODO delete once callers have moved to sendSocketKeepaliveEvent */ onSocketKeepaliveEvent(int slot, int reason)929 public void onSocketKeepaliveEvent(int slot, int reason) { 930 sendSocketKeepaliveEvent(slot, reason); 931 } 932 933 /** 934 * Called by ConnectivityService to add specific packet filter to network hardware to block 935 * replies (e.g., TCP ACKs) matching the sent keepalive packets. Implementations that support 936 * this feature must override this method. 937 * 938 * @param slot the hardware slot on which the keepalive should be sent. 939 * @param packet the packet that is being sent. 940 */ onAddKeepalivePacketFilter(int slot, @NonNull KeepalivePacketData packet)941 public void onAddKeepalivePacketFilter(int slot, @NonNull KeepalivePacketData packet) { 942 Message msg = mHandler.obtainMessage(CMD_ADD_KEEPALIVE_PACKET_FILTER, slot, 0, packet); 943 addKeepalivePacketFilter(msg); 944 msg.recycle(); 945 } 946 /** @hide TODO delete once subclasses have moved to onAddKeepalivePacketFilter */ addKeepalivePacketFilter(Message msg)947 protected void addKeepalivePacketFilter(Message msg) { 948 } 949 950 /** 951 * Called by ConnectivityService to remove a packet filter installed with 952 * {@link #addKeepalivePacketFilter(Message)}. Implementations that support this feature 953 * must override this method. 954 * 955 * @param slot the hardware slot on which the keepalive is being sent. 956 */ onRemoveKeepalivePacketFilter(int slot)957 public void onRemoveKeepalivePacketFilter(int slot) { 958 Message msg = mHandler.obtainMessage(CMD_REMOVE_KEEPALIVE_PACKET_FILTER, slot, 0, null); 959 removeKeepalivePacketFilter(msg); 960 msg.recycle(); 961 } 962 /** @hide TODO delete once subclasses have moved to onRemoveKeepalivePacketFilter */ removeKeepalivePacketFilter(Message msg)963 protected void removeKeepalivePacketFilter(Message msg) { 964 } 965 966 /** 967 * Called by ConnectivityService to inform this network agent of signal strength thresholds 968 * that when crossed should trigger a system wakeup and a NetworkCapabilities update. 969 * 970 * When the system updates the list of thresholds that should wake up the CPU for a 971 * given agent it will call this method on the agent. The agent that implement this 972 * should implement it in hardware so as to ensure the CPU will be woken up on breach. 973 * Agents are expected to react to a breach by sending an updated NetworkCapabilities 974 * object with the appropriate signal strength to sendNetworkCapabilities. 975 * 976 * The specific units are bearer-dependent. See details on the units and requests in 977 * {@link NetworkCapabilities.Builder#setSignalStrength}. 978 * 979 * @param thresholds the array of thresholds that should trigger wakeups. 980 */ onSignalStrengthThresholdsUpdated(@onNull int[] thresholds)981 public void onSignalStrengthThresholdsUpdated(@NonNull int[] thresholds) { 982 setSignalStrengthThresholds(thresholds); 983 } 984 /** @hide TODO delete once subclasses have moved to onSetSignalStrengthThresholds */ setSignalStrengthThresholds(int[] thresholds)985 protected void setSignalStrengthThresholds(int[] thresholds) { 986 } 987 988 /** 989 * Called when the user asks to not stay connected to this network because it was found to not 990 * provide Internet access. Usually followed by call to {@code unwanted}. The transport is 991 * responsible for making sure the device does not automatically reconnect to the same network 992 * after the {@code unwanted} call. 993 */ onAutomaticReconnectDisabled()994 public void onAutomaticReconnectDisabled() { 995 preventAutomaticReconnect(); 996 } 997 /** @hide TODO delete once subclasses have moved to onAutomaticReconnectDisabled */ preventAutomaticReconnect()998 protected void preventAutomaticReconnect() { 999 } 1000 1001 /** @hide */ log(String s)1002 protected void log(String s) { 1003 Log.d(LOG_TAG, "NetworkAgent: " + s); 1004 } 1005 } 1006