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.content.Context; 20 import android.os.Bundle; 21 import android.os.Handler; 22 import android.os.Looper; 23 import android.os.Message; 24 import android.os.Messenger; 25 import android.util.Log; 26 27 import com.android.internal.util.AsyncChannel; 28 import com.android.internal.util.Protocol; 29 import android.net.ConnectivityManager.PacketKeepalive; 30 31 import java.util.ArrayList; 32 import java.util.concurrent.atomic.AtomicBoolean; 33 34 /** 35 * A Utility class for handling for communicating between bearer-specific 36 * code and ConnectivityService. 37 * 38 * A bearer may have more than one NetworkAgent if it can simultaneously 39 * support separate networks (IMS / Internet / MMS Apns on cellular, or 40 * perhaps connections with different SSID or P2P for Wi-Fi). 41 * 42 * @hide 43 */ 44 public abstract class NetworkAgent extends Handler { 45 // Guaranteed to be valid (not NETID_UNSET), otherwise registerNetworkAgent() would have thrown 46 // an exception. 47 public final int netId; 48 49 private volatile AsyncChannel mAsyncChannel; 50 private final String LOG_TAG; 51 private static final boolean DBG = true; 52 private static final boolean VDBG = false; 53 private final Context mContext; 54 private final ArrayList<Message>mPreConnectedQueue = new ArrayList<Message>(); 55 private volatile long mLastBwRefreshTime = 0; 56 private static final long BW_REFRESH_MIN_WIN_MS = 500; 57 private boolean mPollLceScheduled = false; 58 private AtomicBoolean mPollLcePending = new AtomicBoolean(false); 59 60 private static final int BASE = Protocol.BASE_NETWORK_AGENT; 61 62 /** 63 * Sent by ConnectivityService to the NetworkAgent to inform it of 64 * suspected connectivity problems on its network. The NetworkAgent 65 * should take steps to verify and correct connectivity. 66 */ 67 public static final int CMD_SUSPECT_BAD = BASE; 68 69 /** 70 * Sent by the NetworkAgent (note the EVENT vs CMD prefix) to 71 * ConnectivityService to pass the current NetworkInfo (connection state). 72 * Sent when the NetworkInfo changes, mainly due to change of state. 73 * obj = NetworkInfo 74 */ 75 public static final int EVENT_NETWORK_INFO_CHANGED = BASE + 1; 76 77 /** 78 * Sent by the NetworkAgent to ConnectivityService to pass the current 79 * NetworkCapabilties. 80 * obj = NetworkCapabilities 81 */ 82 public static final int EVENT_NETWORK_CAPABILITIES_CHANGED = BASE + 2; 83 84 /** 85 * Sent by the NetworkAgent to ConnectivityService to pass the current 86 * NetworkProperties. 87 * obj = NetworkProperties 88 */ 89 public static final int EVENT_NETWORK_PROPERTIES_CHANGED = BASE + 3; 90 91 /* centralize place where base network score, and network score scaling, will be 92 * stored, so as we can consistently compare apple and oranges, or wifi, ethernet and LTE 93 */ 94 public static final int WIFI_BASE_SCORE = 60; 95 96 /** 97 * Sent by the NetworkAgent to ConnectivityService to pass the current 98 * network score. 99 * obj = network score Integer 100 */ 101 public static final int EVENT_NETWORK_SCORE_CHANGED = BASE + 4; 102 103 /** 104 * Sent by the NetworkAgent to ConnectivityService to add new UID ranges 105 * to be forced into this Network. For VPNs only. 106 * obj = UidRange[] to forward 107 */ 108 public static final int EVENT_UID_RANGES_ADDED = BASE + 5; 109 110 /** 111 * Sent by the NetworkAgent to ConnectivityService to remove UID ranges 112 * from being forced into this Network. For VPNs only. 113 * obj = UidRange[] to stop forwarding 114 */ 115 public static final int EVENT_UID_RANGES_REMOVED = BASE + 6; 116 117 /** 118 * Sent by ConnectivityService to the NetworkAgent to inform the agent of the 119 * networks status - whether we could use the network or could not, due to 120 * either a bad network configuration (no internet link) or captive portal. 121 * 122 * arg1 = either {@code VALID_NETWORK} or {@code INVALID_NETWORK} 123 * obj = Bundle containing map from {@code REDIRECT_URL_KEY} to {@code String} 124 * representing URL that Internet probe was redirect to, if it was redirected, 125 * or mapping to {@code null} otherwise. 126 */ 127 public static final int CMD_REPORT_NETWORK_STATUS = BASE + 7; 128 129 public static final int VALID_NETWORK = 1; 130 public static final int INVALID_NETWORK = 2; 131 132 public static String REDIRECT_URL_KEY = "redirect URL"; 133 134 /** 135 * Sent by the NetworkAgent to ConnectivityService to indicate this network was 136 * explicitly selected. This should be sent before the NetworkInfo is marked 137 * CONNECTED so it can be given special treatment at that time. 138 * 139 * obj = boolean indicating whether to use this network even if unvalidated 140 */ 141 public static final int EVENT_SET_EXPLICITLY_SELECTED = BASE + 8; 142 143 /** 144 * Sent by ConnectivityService to the NetworkAgent to inform the agent of 145 * whether the network should in the future be used even if not validated. 146 * This decision is made by the user, but it is the network transport's 147 * responsibility to remember it. 148 * 149 * arg1 = 1 if true, 0 if false 150 */ 151 public static final int CMD_SAVE_ACCEPT_UNVALIDATED = BASE + 9; 152 153 /** 154 * Sent by ConnectivityService to the NetworkAgent to inform the agent to pull 155 * the underlying network connection for updated bandwidth information. 156 */ 157 public static final int CMD_REQUEST_BANDWIDTH_UPDATE = BASE + 10; 158 159 /** 160 * Sent by ConnectivityService to the NetworkAgent to request that the specified packet be sent 161 * periodically on the given interval. 162 * 163 * arg1 = the slot number of the keepalive to start 164 * arg2 = interval in seconds 165 * obj = KeepalivePacketData object describing the data to be sent 166 * 167 * Also used internally by ConnectivityService / KeepaliveTracker, with different semantics. 168 */ 169 public static final int CMD_START_PACKET_KEEPALIVE = BASE + 11; 170 171 /** 172 * Requests that the specified keepalive packet be stopped. 173 * 174 * arg1 = slot number of the keepalive to stop. 175 * 176 * Also used internally by ConnectivityService / KeepaliveTracker, with different semantics. 177 */ 178 public static final int CMD_STOP_PACKET_KEEPALIVE = BASE + 12; 179 180 /** 181 * Sent by the NetworkAgent to ConnectivityService to provide status on a packet keepalive 182 * request. This may either be the reply to a CMD_START_PACKET_KEEPALIVE, or an asynchronous 183 * error notification. 184 * 185 * This is also sent by KeepaliveTracker to the app's ConnectivityManager.PacketKeepalive to 186 * so that the app's PacketKeepaliveCallback methods can be called. 187 * 188 * arg1 = slot number of the keepalive 189 * arg2 = error code 190 */ 191 public static final int EVENT_PACKET_KEEPALIVE = BASE + 13; 192 193 /** 194 * Sent by ConnectivityService to inform this network transport of signal strength thresholds 195 * that when crossed should trigger a system wakeup and a NetworkCapabilities update. 196 * 197 * obj = int[] describing signal strength thresholds. 198 */ 199 public static final int CMD_SET_SIGNAL_STRENGTH_THRESHOLDS = BASE + 14; 200 201 /** 202 * Sent by ConnectivityService to the NeworkAgent to inform the agent to avoid 203 * automatically reconnecting to this network (e.g. via autojoin). Happens 204 * when user selects "No" option on the "Stay connected?" dialog box. 205 */ 206 public static final int CMD_PREVENT_AUTOMATIC_RECONNECT = BASE + 15; 207 NetworkAgent(Looper looper, Context context, String logTag, NetworkInfo ni, NetworkCapabilities nc, LinkProperties lp, int score)208 public NetworkAgent(Looper looper, Context context, String logTag, NetworkInfo ni, 209 NetworkCapabilities nc, LinkProperties lp, int score) { 210 this(looper, context, logTag, ni, nc, lp, score, null); 211 } 212 NetworkAgent(Looper looper, Context context, String logTag, NetworkInfo ni, NetworkCapabilities nc, LinkProperties lp, int score, NetworkMisc misc)213 public NetworkAgent(Looper looper, Context context, String logTag, NetworkInfo ni, 214 NetworkCapabilities nc, LinkProperties lp, int score, NetworkMisc misc) { 215 super(looper); 216 LOG_TAG = logTag; 217 mContext = context; 218 if (ni == null || nc == null || lp == null) { 219 throw new IllegalArgumentException(); 220 } 221 222 if (VDBG) log("Registering NetworkAgent"); 223 ConnectivityManager cm = (ConnectivityManager)mContext.getSystemService( 224 Context.CONNECTIVITY_SERVICE); 225 netId = cm.registerNetworkAgent(new Messenger(this), new NetworkInfo(ni), 226 new LinkProperties(lp), new NetworkCapabilities(nc), score, misc); 227 } 228 229 @Override handleMessage(Message msg)230 public void handleMessage(Message msg) { 231 switch (msg.what) { 232 case AsyncChannel.CMD_CHANNEL_FULL_CONNECTION: { 233 if (mAsyncChannel != null) { 234 log("Received new connection while already connected!"); 235 } else { 236 if (VDBG) log("NetworkAgent fully connected"); 237 AsyncChannel ac = new AsyncChannel(); 238 ac.connected(null, this, msg.replyTo); 239 ac.replyToMessage(msg, AsyncChannel.CMD_CHANNEL_FULLY_CONNECTED, 240 AsyncChannel.STATUS_SUCCESSFUL); 241 synchronized (mPreConnectedQueue) { 242 mAsyncChannel = ac; 243 for (Message m : mPreConnectedQueue) { 244 ac.sendMessage(m); 245 } 246 mPreConnectedQueue.clear(); 247 } 248 } 249 break; 250 } 251 case AsyncChannel.CMD_CHANNEL_DISCONNECT: { 252 if (VDBG) log("CMD_CHANNEL_DISCONNECT"); 253 if (mAsyncChannel != null) mAsyncChannel.disconnect(); 254 break; 255 } 256 case AsyncChannel.CMD_CHANNEL_DISCONNECTED: { 257 if (DBG) log("NetworkAgent channel lost"); 258 // let the client know CS is done with us. 259 unwanted(); 260 synchronized (mPreConnectedQueue) { 261 mAsyncChannel = null; 262 } 263 break; 264 } 265 case CMD_SUSPECT_BAD: { 266 log("Unhandled Message " + msg); 267 break; 268 } 269 case CMD_REQUEST_BANDWIDTH_UPDATE: { 270 long currentTimeMs = System.currentTimeMillis(); 271 if (VDBG) { 272 log("CMD_REQUEST_BANDWIDTH_UPDATE request received."); 273 } 274 if (currentTimeMs >= (mLastBwRefreshTime + BW_REFRESH_MIN_WIN_MS)) { 275 mPollLceScheduled = false; 276 if (mPollLcePending.getAndSet(true) == false) { 277 pollLceData(); 278 } 279 } else { 280 // deliver the request at a later time rather than discard it completely. 281 if (!mPollLceScheduled) { 282 long waitTime = mLastBwRefreshTime + BW_REFRESH_MIN_WIN_MS - 283 currentTimeMs + 1; 284 mPollLceScheduled = sendEmptyMessageDelayed( 285 CMD_REQUEST_BANDWIDTH_UPDATE, waitTime); 286 } 287 } 288 break; 289 } 290 case CMD_REPORT_NETWORK_STATUS: { 291 String redirectUrl = ((Bundle)msg.obj).getString(REDIRECT_URL_KEY); 292 if (VDBG) { 293 log("CMD_REPORT_NETWORK_STATUS(" + 294 (msg.arg1 == VALID_NETWORK ? "VALID, " : "INVALID, ") + redirectUrl); 295 } 296 networkStatus(msg.arg1, redirectUrl); 297 break; 298 } 299 case CMD_SAVE_ACCEPT_UNVALIDATED: { 300 saveAcceptUnvalidated(msg.arg1 != 0); 301 break; 302 } 303 case CMD_START_PACKET_KEEPALIVE: { 304 startPacketKeepalive(msg); 305 break; 306 } 307 case CMD_STOP_PACKET_KEEPALIVE: { 308 stopPacketKeepalive(msg); 309 break; 310 } 311 312 case CMD_SET_SIGNAL_STRENGTH_THRESHOLDS: { 313 ArrayList<Integer> thresholds = 314 ((Bundle) msg.obj).getIntegerArrayList("thresholds"); 315 // TODO: Change signal strength thresholds API to use an ArrayList<Integer> 316 // rather than convert to int[]. 317 int[] intThresholds = new int[(thresholds != null) ? thresholds.size() : 0]; 318 for (int i = 0; i < intThresholds.length; i++) { 319 intThresholds[i] = thresholds.get(i); 320 } 321 setSignalStrengthThresholds(intThresholds); 322 break; 323 } 324 case CMD_PREVENT_AUTOMATIC_RECONNECT: { 325 preventAutomaticReconnect(); 326 break; 327 } 328 } 329 } 330 queueOrSendMessage(int what, Object obj)331 private void queueOrSendMessage(int what, Object obj) { 332 queueOrSendMessage(what, 0, 0, obj); 333 } 334 queueOrSendMessage(int what, int arg1, int arg2)335 private void queueOrSendMessage(int what, int arg1, int arg2) { 336 queueOrSendMessage(what, arg1, arg2, null); 337 } 338 queueOrSendMessage(int what, int arg1, int arg2, Object obj)339 private void queueOrSendMessage(int what, int arg1, int arg2, Object obj) { 340 Message msg = Message.obtain(); 341 msg.what = what; 342 msg.arg1 = arg1; 343 msg.arg2 = arg2; 344 msg.obj = obj; 345 queueOrSendMessage(msg); 346 } 347 queueOrSendMessage(Message msg)348 private void queueOrSendMessage(Message msg) { 349 synchronized (mPreConnectedQueue) { 350 if (mAsyncChannel != null) { 351 mAsyncChannel.sendMessage(msg); 352 } else { 353 mPreConnectedQueue.add(msg); 354 } 355 } 356 } 357 358 /** 359 * Called by the bearer code when it has new LinkProperties data. 360 */ sendLinkProperties(LinkProperties linkProperties)361 public void sendLinkProperties(LinkProperties linkProperties) { 362 queueOrSendMessage(EVENT_NETWORK_PROPERTIES_CHANGED, new LinkProperties(linkProperties)); 363 } 364 365 /** 366 * Called by the bearer code when it has new NetworkInfo data. 367 */ sendNetworkInfo(NetworkInfo networkInfo)368 public void sendNetworkInfo(NetworkInfo networkInfo) { 369 queueOrSendMessage(EVENT_NETWORK_INFO_CHANGED, new NetworkInfo(networkInfo)); 370 } 371 372 /** 373 * Called by the bearer code when it has new NetworkCapabilities data. 374 */ sendNetworkCapabilities(NetworkCapabilities networkCapabilities)375 public void sendNetworkCapabilities(NetworkCapabilities networkCapabilities) { 376 mPollLcePending.set(false); 377 mLastBwRefreshTime = System.currentTimeMillis(); 378 queueOrSendMessage(EVENT_NETWORK_CAPABILITIES_CHANGED, 379 new NetworkCapabilities(networkCapabilities)); 380 } 381 382 /** 383 * Called by the bearer code when it has a new score for this network. 384 */ sendNetworkScore(int score)385 public void sendNetworkScore(int score) { 386 if (score < 0) { 387 throw new IllegalArgumentException("Score must be >= 0"); 388 } 389 queueOrSendMessage(EVENT_NETWORK_SCORE_CHANGED, new Integer(score)); 390 } 391 392 /** 393 * Called by the VPN code when it wants to add ranges of UIDs to be routed 394 * through the VPN network. 395 */ addUidRanges(UidRange[] ranges)396 public void addUidRanges(UidRange[] ranges) { 397 queueOrSendMessage(EVENT_UID_RANGES_ADDED, ranges); 398 } 399 400 /** 401 * Called by the VPN code when it wants to remove ranges of UIDs from being routed 402 * through the VPN network. 403 */ removeUidRanges(UidRange[] ranges)404 public void removeUidRanges(UidRange[] ranges) { 405 queueOrSendMessage(EVENT_UID_RANGES_REMOVED, ranges); 406 } 407 408 /** 409 * Called by the bearer to indicate this network was manually selected by the user. 410 * This should be called before the NetworkInfo is marked CONNECTED so that this 411 * Network can be given special treatment at that time. If {@code acceptUnvalidated} is 412 * {@code true}, then the system will switch to this network. If it is {@code false} and the 413 * network cannot be validated, the system will ask the user whether to switch to this network. 414 * If the user confirms and selects "don't ask again", then the system will call 415 * {@link #saveAcceptUnvalidated} to persist the user's choice. Thus, if the transport ever 416 * calls this method with {@code acceptUnvalidated} set to {@code false}, it must also implement 417 * {@link #saveAcceptUnvalidated} to respect the user's choice. 418 */ explicitlySelected(boolean acceptUnvalidated)419 public void explicitlySelected(boolean acceptUnvalidated) { 420 queueOrSendMessage(EVENT_SET_EXPLICITLY_SELECTED, acceptUnvalidated); 421 } 422 423 /** 424 * Called when ConnectivityService has indicated they no longer want this network. 425 * The parent factory should (previously) have received indication of the change 426 * as well, either canceling NetworkRequests or altering their score such that this 427 * network won't be immediately requested again. 428 */ unwanted()429 abstract protected void unwanted(); 430 431 /** 432 * Called when ConnectivityService request a bandwidth update. The parent factory 433 * shall try to overwrite this method and produce a bandwidth update if capable. 434 */ pollLceData()435 protected void pollLceData() { 436 } 437 438 /** 439 * Called when the system determines the usefulness of this network. 440 * 441 * Networks claiming internet connectivity will have their internet 442 * connectivity verified. 443 * 444 * Currently there are two possible values: 445 * {@code VALID_NETWORK} if the system is happy with the connection, 446 * {@code INVALID_NETWORK} if the system is not happy. 447 * TODO - add indications of captive portal-ness and related success/failure, 448 * ie, CAPTIVE_SUCCESS_NETWORK, CAPTIVE_NETWORK for successful login and detection 449 * 450 * This may be called multiple times as the network status changes and may 451 * generate false negatives if we lose ip connectivity before the link is torn down. 452 * 453 * @param status one of {@code VALID_NETWORK} or {@code INVALID_NETWORK}. 454 * @param redirectUrl If the Internet probe was redirected, this is the destination it was 455 * redirected to, otherwise {@code null}. 456 */ networkStatus(int status, String redirectUrl)457 protected void networkStatus(int status, String redirectUrl) { 458 } 459 460 /** 461 * Called when the user asks to remember the choice to use this network even if unvalidated. 462 * The transport is responsible for remembering the choice, and the next time the user connects 463 * to the network, should explicitlySelected with {@code acceptUnvalidated} set to {@code true}. 464 * This method will only be called if {@link #explicitlySelected} was called with 465 * {@code acceptUnvalidated} set to {@code false}. 466 */ saveAcceptUnvalidated(boolean accept)467 protected void saveAcceptUnvalidated(boolean accept) { 468 } 469 470 /** 471 * Requests that the network hardware send the specified packet at the specified interval. 472 */ startPacketKeepalive(Message msg)473 protected void startPacketKeepalive(Message msg) { 474 onPacketKeepaliveEvent(msg.arg1, PacketKeepalive.ERROR_HARDWARE_UNSUPPORTED); 475 } 476 477 /** 478 * Requests that the network hardware send the specified packet at the specified interval. 479 */ stopPacketKeepalive(Message msg)480 protected void stopPacketKeepalive(Message msg) { 481 onPacketKeepaliveEvent(msg.arg1, PacketKeepalive.ERROR_HARDWARE_UNSUPPORTED); 482 } 483 484 /** 485 * Called by the network when a packet keepalive event occurs. 486 */ onPacketKeepaliveEvent(int slot, int reason)487 public void onPacketKeepaliveEvent(int slot, int reason) { 488 queueOrSendMessage(EVENT_PACKET_KEEPALIVE, slot, reason); 489 } 490 491 /** 492 * Called by ConnectivityService to inform this network transport of signal strength thresholds 493 * that when crossed should trigger a system wakeup and a NetworkCapabilities update. 494 */ setSignalStrengthThresholds(int[] thresholds)495 protected void setSignalStrengthThresholds(int[] thresholds) { 496 } 497 498 /** 499 * Called when the user asks to not stay connected to this network because it was found to not 500 * provide Internet access. Usually followed by call to {@code unwanted}. The transport is 501 * responsible for making sure the device does not automatically reconnect to the same network 502 * after the {@code unwanted} call. 503 */ preventAutomaticReconnect()504 protected void preventAutomaticReconnect() { 505 } 506 log(String s)507 protected void log(String s) { 508 Log.d(LOG_TAG, "NetworkAgent: " + s); 509 } 510 } 511