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 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 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 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 331 private void queueOrSendMessage(int what, Object obj) { 332 queueOrSendMessage(what, 0, 0, obj); 333 } 334 335 private void queueOrSendMessage(int what, int arg1, int arg2) { 336 queueOrSendMessage(what, arg1, arg2, null); 337 } 338 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 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 467 protected void saveAcceptUnvalidated(boolean accept) { 468 } 469 470 /** 471 * Requests that the network hardware send the specified packet at the specified interval. 472 */ 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 */ 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 */ 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 */ 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 */ 504 protected void preventAutomaticReconnect() { 505 } 506 507 protected void log(String s) { 508 Log.d(LOG_TAG, "NetworkAgent: " + s); 509 } 510 } 511