ConnectivityService.java revision 9066cfe9886ac131c34d59ed0e2d287b0e3c0087
1/* 2 * Copyright (C) 2008 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 17package com.android.server; 18 19import android.app.Notification; 20import android.app.NotificationManager; 21import android.content.ContentResolver; 22import android.content.Context; 23import android.content.Intent; 24import android.content.pm.PackageManager; 25import android.net.ConnectivityManager; 26import android.net.IConnectivityManager; 27import android.net.MobileDataStateTracker; 28import android.net.NetworkInfo; 29import android.net.NetworkStateTracker; 30import android.net.wifi.WifiStateTracker; 31import android.os.Binder; 32import android.os.Handler; 33import android.os.Looper; 34import android.os.Message; 35import android.os.ServiceManager; 36import android.os.SystemProperties; 37import android.provider.Settings; 38import android.provider.Sync; 39import android.util.EventLog; 40import android.util.Log; 41 42import java.io.FileDescriptor; 43import java.io.PrintWriter; 44 45/** 46 * @hide 47 */ 48public class ConnectivityService extends IConnectivityManager.Stub { 49 50 private static final boolean DBG = false; 51 private static final String TAG = "ConnectivityService"; 52 53 // Event log tags (must be in sync with event-log-tags) 54 private static final int EVENTLOG_CONNECTIVITY_STATE_CHANGED = 50020; 55 56 /** 57 * Sometimes we want to refer to the individual network state 58 * trackers separately, and sometimes we just want to treat them 59 * abstractly. 60 */ 61 private NetworkStateTracker mNetTrackers[]; 62 private WifiStateTracker mWifiStateTracker; 63 private MobileDataStateTracker mMobileDataStateTracker; 64 private WifiWatchdogService mWifiWatchdogService; 65 66 private Context mContext; 67 private int mNetworkPreference; 68 private NetworkStateTracker mActiveNetwork; 69 70 private int mNumDnsEntries; 71 private static int sDnsChangeCounter; 72 73 private boolean mTestMode; 74 private static ConnectivityService sServiceInstance; 75 76 private static class ConnectivityThread extends Thread { 77 private Context mContext; 78 79 private ConnectivityThread(Context context) { 80 super("ConnectivityThread"); 81 mContext = context; 82 } 83 84 @Override 85 public void run() { 86 Looper.prepare(); 87 synchronized (this) { 88 sServiceInstance = new ConnectivityService(mContext); 89 notifyAll(); 90 } 91 Looper.loop(); 92 } 93 94 public static ConnectivityService getServiceInstance(Context context) { 95 ConnectivityThread thread = new ConnectivityThread(context); 96 thread.start(); 97 98 synchronized (thread) { 99 while (sServiceInstance == null) { 100 try { 101 // Wait until sServiceInstance has been initialized. 102 thread.wait(); 103 } catch (InterruptedException ignore) { 104 Log.e(TAG, 105 "Unexpected InterruptedException while waiting for ConnectivityService thread"); 106 } 107 } 108 } 109 110 return sServiceInstance; 111 } 112 } 113 114 public static ConnectivityService getInstance(Context context) { 115 return ConnectivityThread.getServiceInstance(context); 116 } 117 118 private ConnectivityService(Context context) { 119 if (DBG) Log.v(TAG, "ConnectivityService starting up"); 120 mContext = context; 121 mNetTrackers = new NetworkStateTracker[2]; 122 Handler handler = new MyHandler(); 123 124 mNetworkPreference = getPersistedNetworkPreference(); 125 126 /* 127 * Create the network state trackers for Wi-Fi and mobile 128 * data. Maybe this could be done with a factory class, 129 * but it's not clear that it's worth it, given that 130 * the number of different network types is not going 131 * to change very often. 132 */ 133 if (DBG) Log.v(TAG, "Starting Wifi Service."); 134 mWifiStateTracker = new WifiStateTracker(context, handler); 135 WifiService wifiService = new WifiService(context, mWifiStateTracker); 136 ServiceManager.addService(Context.WIFI_SERVICE, wifiService); 137 mNetTrackers[ConnectivityManager.TYPE_WIFI] = mWifiStateTracker; 138 139 mMobileDataStateTracker = new MobileDataStateTracker(context, handler); 140 mNetTrackers[ConnectivityManager.TYPE_MOBILE] = mMobileDataStateTracker; 141 142 mActiveNetwork = null; 143 mNumDnsEntries = 0; 144 145 mTestMode = SystemProperties.get("cm.test.mode").equals("true") 146 && SystemProperties.get("ro.build.type").equals("eng"); 147 148 for (NetworkStateTracker t : mNetTrackers) 149 t.startMonitoring(); 150 151 // Constructing this starts it too 152 mWifiWatchdogService = new WifiWatchdogService(context, mWifiStateTracker); 153 } 154 155 /** 156 * Sets the preferred network. 157 * @param preference the new preference 158 */ 159 public synchronized void setNetworkPreference(int preference) { 160 enforceChangePermission(); 161 if (ConnectivityManager.isNetworkTypeValid(preference)) { 162 if (mNetworkPreference != preference) { 163 persistNetworkPreference(preference); 164 mNetworkPreference = preference; 165 enforcePreference(); 166 } 167 } 168 } 169 170 public int getNetworkPreference() { 171 enforceAccessPermission(); 172 return mNetworkPreference; 173 } 174 175 private void persistNetworkPreference(int networkPreference) { 176 final ContentResolver cr = mContext.getContentResolver(); 177 Settings.Secure.putInt(cr, Settings.Secure.NETWORK_PREFERENCE, networkPreference); 178 } 179 180 private int getPersistedNetworkPreference() { 181 final ContentResolver cr = mContext.getContentResolver(); 182 183 final int networkPrefSetting = Settings.Secure 184 .getInt(cr, Settings.Secure.NETWORK_PREFERENCE, -1); 185 if (networkPrefSetting != -1) { 186 return networkPrefSetting; 187 } 188 189 return ConnectivityManager.DEFAULT_NETWORK_PREFERENCE; 190 } 191 192 /** 193 * Make the state of network connectivity conform to the preference settings. 194 * In this method, we only tear down a non-preferred network. Establishing 195 * a connection to the preferred network is taken care of when we handle 196 * the disconnect event from the non-preferred network 197 * (see {@link #handleDisconnect(NetworkInfo)}). 198 */ 199 private void enforcePreference() { 200 if (mActiveNetwork == null) 201 return; 202 203 for (NetworkStateTracker t : mNetTrackers) { 204 if (t == mActiveNetwork) { 205 int netType = t.getNetworkInfo().getType(); 206 int otherNetType = ((netType == ConnectivityManager.TYPE_WIFI) ? 207 ConnectivityManager.TYPE_MOBILE : 208 ConnectivityManager.TYPE_WIFI); 209 210 if (t.getNetworkInfo().getType() != mNetworkPreference) { 211 NetworkStateTracker otherTracker = mNetTrackers[otherNetType]; 212 if (otherTracker.isAvailable()) { 213 teardown(t); 214 } 215 } 216 } 217 } 218 } 219 220 private boolean teardown(NetworkStateTracker netTracker) { 221 if (netTracker.teardown()) { 222 netTracker.setTeardownRequested(true); 223 return true; 224 } else { 225 return false; 226 } 227 } 228 229 /** 230 * Return NetworkInfo for the active (i.e., connected) network interface. 231 * It is assumed that at most one network is active at a time. If more 232 * than one is active, it is indeterminate which will be returned. 233 * @return the info for the active network, or {@code null} if none is active 234 */ 235 public NetworkInfo getActiveNetworkInfo() { 236 enforceAccessPermission(); 237 for (NetworkStateTracker t : mNetTrackers) { 238 NetworkInfo info = t.getNetworkInfo(); 239 if (info.isConnected()) { 240 return info; 241 } 242 } 243 return null; 244 } 245 246 public NetworkInfo getNetworkInfo(int networkType) { 247 enforceAccessPermission(); 248 if (ConnectivityManager.isNetworkTypeValid(networkType)) { 249 NetworkStateTracker t = mNetTrackers[networkType]; 250 if (t != null) 251 return t.getNetworkInfo(); 252 } 253 return null; 254 } 255 256 public NetworkInfo[] getAllNetworkInfo() { 257 enforceAccessPermission(); 258 NetworkInfo[] result = new NetworkInfo[mNetTrackers.length]; 259 int i = 0; 260 for (NetworkStateTracker t : mNetTrackers) { 261 result[i++] = t.getNetworkInfo(); 262 } 263 return result; 264 } 265 266 public boolean setRadios(boolean turnOn) { 267 boolean result = true; 268 enforceChangePermission(); 269 for (NetworkStateTracker t : mNetTrackers) { 270 result = t.setRadio(turnOn) && result; 271 } 272 return result; 273 } 274 275 public boolean setRadio(int netType, boolean turnOn) { 276 enforceChangePermission(); 277 if (!ConnectivityManager.isNetworkTypeValid(netType)) { 278 return false; 279 } 280 NetworkStateTracker tracker = mNetTrackers[netType]; 281 return tracker != null && tracker.setRadio(turnOn); 282 } 283 284 public int startUsingNetworkFeature(int networkType, String feature) { 285 enforceChangePermission(); 286 if (!ConnectivityManager.isNetworkTypeValid(networkType)) { 287 return -1; 288 } 289 NetworkStateTracker tracker = mNetTrackers[networkType]; 290 if (tracker != null) { 291 return tracker.startUsingNetworkFeature(feature, getCallingPid(), getCallingUid()); 292 } 293 return -1; 294 } 295 296 public int stopUsingNetworkFeature(int networkType, String feature) { 297 enforceChangePermission(); 298 if (!ConnectivityManager.isNetworkTypeValid(networkType)) { 299 return -1; 300 } 301 NetworkStateTracker tracker = mNetTrackers[networkType]; 302 if (tracker != null) { 303 return tracker.stopUsingNetworkFeature(feature, getCallingPid(), getCallingUid()); 304 } 305 return -1; 306 } 307 308 /** 309 * Ensure that a network route exists to deliver traffic to the specified 310 * host via the specified network interface. 311 * @param networkType the type of the network over which traffic to the specified 312 * host is to be routed 313 * @param hostAddress the IP address of the host to which the route is desired 314 * @return {@code true} on success, {@code false} on failure 315 */ 316 public boolean requestRouteToHost(int networkType, int hostAddress) { 317 enforceChangePermission(); 318 if (!ConnectivityManager.isNetworkTypeValid(networkType)) { 319 return false; 320 } 321 NetworkStateTracker tracker = mNetTrackers[networkType]; 322 /* 323 * If there's only one connected network, and it's the one requested, 324 * then we don't have to do anything - the requested route already 325 * exists. If it's not the requested network, then it's not possible 326 * to establish the requested route. Finally, if there is more than 327 * one connected network, then we must insert an entry in the routing 328 * table. 329 */ 330 if (getNumConnectedNetworks() > 1) { 331 return tracker.requestRouteToHost(hostAddress); 332 } else { 333 return tracker.getNetworkInfo().getType() == networkType; 334 } 335 } 336 337 /** 338 * @see ConnectivityManager#getBackgroundDataSetting() 339 */ 340 public boolean getBackgroundDataSetting() { 341 return Settings.Secure.getInt(mContext.getContentResolver(), 342 Settings.Secure.BACKGROUND_DATA, 1) == 1; 343 } 344 345 /** 346 * @see ConnectivityManager#setBackgroundDataSetting(boolean) 347 */ 348 public void setBackgroundDataSetting(boolean allowBackgroundDataUsage) { 349 mContext.enforceCallingOrSelfPermission( 350 android.Manifest.permission.CHANGE_BACKGROUND_DATA_SETTING, 351 "ConnectivityService"); 352 353 if (getBackgroundDataSetting() == allowBackgroundDataUsage) return; 354 355 Settings.Secure.putInt(mContext.getContentResolver(), 356 Settings.Secure.BACKGROUND_DATA, allowBackgroundDataUsage ? 1 : 0); 357 358 Intent broadcast = new Intent( 359 ConnectivityManager.ACTION_BACKGROUND_DATA_SETTING_CHANGED); 360 mContext.sendBroadcast(broadcast); 361 } 362 363 private int getNumConnectedNetworks() { 364 int numConnectedNets = 0; 365 366 for (NetworkStateTracker nt : mNetTrackers) { 367 if (nt.getNetworkInfo().isConnected() && !nt.isTeardownRequested()) { 368 ++numConnectedNets; 369 } 370 } 371 return numConnectedNets; 372 } 373 374 private void enforceAccessPermission() { 375 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.ACCESS_NETWORK_STATE, 376 "ConnectivityService"); 377 } 378 379 private void enforceChangePermission() { 380 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.CHANGE_NETWORK_STATE, 381 "ConnectivityService"); 382 383 } 384 385 /** 386 * Handle a {@code DISCONNECTED} event. If this pertains to the non-active network, 387 * we ignore it. If it is for the active network, we send out a broadcast. 388 * But first, we check whether it might be possible to connect to a different 389 * network. 390 * @param info the {@code NetworkInfo} for the network 391 */ 392 private void handleDisconnect(NetworkInfo info) { 393 394 if (DBG) Log.v(TAG, "Handle DISCONNECT for " + info.getTypeName()); 395 396 mNetTrackers[info.getType()].setTeardownRequested(false); 397 /* 398 * If the disconnected network is not the active one, then don't report 399 * this as a loss of connectivity. What probably happened is that we're 400 * getting the disconnect for a network that we explicitly disabled 401 * in accordance with network preference policies. 402 */ 403 if (mActiveNetwork == null || info.getType() != mActiveNetwork.getNetworkInfo().getType()) 404 return; 405 406 NetworkStateTracker newNet; 407 if (info.getType() == ConnectivityManager.TYPE_MOBILE) { 408 newNet = mWifiStateTracker; 409 } else /* info().getType() == TYPE_WIFI */ { 410 newNet = mMobileDataStateTracker; 411 } 412 413 /** 414 * See if the other network is available to fail over to. 415 * If is not available, we enable it anyway, so that it 416 * will be able to connect when it does become available, 417 * but we report a total loss of connectivity rather than 418 * report that we are attempting to fail over. 419 */ 420 NetworkInfo switchTo = null; 421 if (newNet.isAvailable()) { 422 mActiveNetwork = newNet; 423 switchTo = newNet.getNetworkInfo(); 424 switchTo.setFailover(true); 425 if (!switchTo.isConnectedOrConnecting()) { 426 newNet.reconnect(); 427 } 428 } else { 429 newNet.reconnect(); 430 } 431 432 boolean otherNetworkConnected = false; 433 Intent intent = new Intent(ConnectivityManager.CONNECTIVITY_ACTION); 434 intent.putExtra(ConnectivityManager.EXTRA_NETWORK_INFO, info); 435 if (info.isFailover()) { 436 intent.putExtra(ConnectivityManager.EXTRA_IS_FAILOVER, true); 437 info.setFailover(false); 438 } 439 if (info.getReason() != null) { 440 intent.putExtra(ConnectivityManager.EXTRA_REASON, info.getReason()); 441 } 442 if (info.getExtraInfo() != null) { 443 intent.putExtra(ConnectivityManager.EXTRA_EXTRA_INFO, info.getExtraInfo()); 444 } 445 if (switchTo != null) { 446 otherNetworkConnected = switchTo.isConnected(); 447 if (DBG) { 448 if (otherNetworkConnected) { 449 Log.v(TAG, "Switching to already connected " + switchTo.getTypeName()); 450 } else { 451 Log.v(TAG, "Attempting to switch to " + switchTo.getTypeName()); 452 } 453 } 454 intent.putExtra(ConnectivityManager.EXTRA_OTHER_NETWORK_INFO, switchTo); 455 } else { 456 intent.putExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, true); 457 } 458 if (DBG) Log.v(TAG, "Sending DISCONNECT bcast for " + info.getTypeName() + 459 (switchTo == null ? "" : " other=" + switchTo.getTypeName())); 460 461 mContext.sendStickyBroadcast(intent); 462 /* 463 * If the failover network is already connected, then immediately send out 464 * a followup broadcast indicating successful failover 465 */ 466 if (switchTo != null && otherNetworkConnected) 467 sendConnectedBroadcast(switchTo); 468 } 469 470 private void sendConnectedBroadcast(NetworkInfo info) { 471 Intent intent = new Intent(ConnectivityManager.CONNECTIVITY_ACTION); 472 intent.putExtra(ConnectivityManager.EXTRA_NETWORK_INFO, info); 473 if (info.isFailover()) { 474 intent.putExtra(ConnectivityManager.EXTRA_IS_FAILOVER, true); 475 info.setFailover(false); 476 } 477 if (info.getReason() != null) { 478 intent.putExtra(ConnectivityManager.EXTRA_REASON, info.getReason()); 479 } 480 if (info.getExtraInfo() != null) { 481 intent.putExtra(ConnectivityManager.EXTRA_EXTRA_INFO, info.getExtraInfo()); 482 } 483 mContext.sendStickyBroadcast(intent); 484 } 485 486 /** 487 * Called when an attempt to fail over to another network has failed. 488 * @param info the {@link NetworkInfo} for the failed network 489 */ 490 private void handleConnectionFailure(NetworkInfo info) { 491 mNetTrackers[info.getType()].setTeardownRequested(false); 492 if (getActiveNetworkInfo() == null) { 493 String reason = info.getReason(); 494 String extraInfo = info.getExtraInfo(); 495 496 if (DBG) { 497 String reasonText; 498 if (reason == null) { 499 reasonText = "."; 500 } else { 501 reasonText = " (" + reason + ")."; 502 } 503 Log.v(TAG, "Attempt to connect to " + info.getTypeName() + " failed" + reasonText); 504 } 505 506 Intent intent = new Intent(ConnectivityManager.CONNECTIVITY_ACTION); 507 intent.putExtra(ConnectivityManager.EXTRA_NETWORK_INFO, info); 508 intent.putExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, true); 509 if (reason != null) { 510 intent.putExtra(ConnectivityManager.EXTRA_REASON, reason); 511 } 512 if (extraInfo != null) { 513 intent.putExtra(ConnectivityManager.EXTRA_EXTRA_INFO, extraInfo); 514 } 515 if (info.isFailover()) { 516 intent.putExtra(ConnectivityManager.EXTRA_IS_FAILOVER, true); 517 info.setFailover(false); 518 } 519 mContext.sendStickyBroadcast(intent); 520 } 521 } 522 523 private void handleConnect(NetworkInfo info) { 524 if (DBG) Log.v(TAG, "Handle CONNECT for " + info.getTypeName()); 525 526 // snapshot isFailover, because sendConnectedBroadcast() resets it 527 boolean isFailover = info.isFailover(); 528 NetworkStateTracker thisNet = mNetTrackers[info.getType()]; 529 NetworkStateTracker deadnet = null; 530 NetworkStateTracker otherNet; 531 if (info.getType() == ConnectivityManager.TYPE_MOBILE) { 532 otherNet = mWifiStateTracker; 533 } else /* info().getType() == TYPE_WIFI */ { 534 otherNet = mMobileDataStateTracker; 535 } 536 /* 537 * Check policy to see whether we are connected to a non-preferred 538 * network that now needs to be torn down. 539 */ 540 NetworkInfo wifiInfo = mWifiStateTracker.getNetworkInfo(); 541 NetworkInfo mobileInfo = mMobileDataStateTracker.getNetworkInfo(); 542 if (wifiInfo.isConnected() && mobileInfo.isConnected()) { 543 if (mNetworkPreference == ConnectivityManager.TYPE_WIFI) 544 deadnet = mMobileDataStateTracker; 545 else 546 deadnet = mWifiStateTracker; 547 } 548 549 boolean toredown = false; 550 thisNet.setTeardownRequested(false); 551 if (!mTestMode && deadnet != null) { 552 if (DBG) Log.v(TAG, "Policy requires " + 553 deadnet.getNetworkInfo().getTypeName() + " teardown"); 554 toredown = teardown(deadnet); 555 if (DBG && !toredown) { 556 Log.d(TAG, "Network declined teardown request"); 557 } 558 } 559 560 /* 561 * Note that if toredown is true, deadnet cannot be null, so there is 562 * no danger of a null pointer exception here.. 563 */ 564 if (!toredown || deadnet.getNetworkInfo().getType() != info.getType()) { 565 mActiveNetwork = thisNet; 566 if (DBG) Log.v(TAG, "Sending CONNECT bcast for " + info.getTypeName()); 567 thisNet.updateNetworkSettings(); 568 sendConnectedBroadcast(info); 569 if (isFailover) { 570 otherNet.releaseWakeLock(); 571 } 572 } else { 573 if (DBG) Log.v(TAG, "Not broadcasting CONNECT_ACTION to torn down network " + 574 info.getTypeName()); 575 } 576 } 577 578 private void handleScanResultsAvailable(NetworkInfo info) { 579 int networkType = info.getType(); 580 if (networkType != ConnectivityManager.TYPE_WIFI) { 581 if (DBG) Log.v(TAG, "Got ScanResultsAvailable for " + info.getTypeName() + " network." 582 + " Don't know how to handle."); 583 } 584 585 mNetTrackers[networkType].interpretScanResultsAvailable(); 586 } 587 588 private void handleNotificationChange(boolean visible, int id, Notification notification) { 589 NotificationManager notificationManager = (NotificationManager) mContext 590 .getSystemService(Context.NOTIFICATION_SERVICE); 591 592 if (visible) { 593 notificationManager.notify(id, notification); 594 } else { 595 notificationManager.cancel(id); 596 } 597 } 598 599 /** 600 * After any kind of change in the connectivity state of any network, 601 * make sure that anything that depends on the connectivity state of 602 * more than one network is set up correctly. We're mainly concerned 603 * with making sure that the list of DNS servers is set up according 604 * to which networks are connected, and ensuring that the right routing 605 * table entries exist. 606 */ 607 private void handleConnectivityChange() { 608 /* 609 * If both mobile and wifi are enabled, add the host routes that 610 * will allow MMS traffic to pass on the mobile network. But 611 * remove the default route for the mobile network, so that there 612 * will be only one default route, to ensure that all traffic 613 * except MMS will travel via Wi-Fi. 614 */ 615 int numConnectedNets = handleConfigurationChange(); 616 if (numConnectedNets > 1) { 617 mMobileDataStateTracker.addPrivateRoutes(); 618 mMobileDataStateTracker.removeDefaultRoute(); 619 } else if (mMobileDataStateTracker.getNetworkInfo().isConnected()) { 620 mMobileDataStateTracker.removePrivateRoutes(); 621 mMobileDataStateTracker.restoreDefaultRoute(); 622 } 623 } 624 625 private int handleConfigurationChange() { 626 /* 627 * Set DNS properties. Always put Wi-Fi entries at the front of 628 * the list if it is active. 629 */ 630 int index = 1; 631 String lastDns = ""; 632 int numConnectedNets = 0; 633 int incrValue = ConnectivityManager.TYPE_MOBILE - ConnectivityManager.TYPE_WIFI; 634 int stopValue = ConnectivityManager.TYPE_MOBILE + incrValue; 635 636 for (int netType = ConnectivityManager.TYPE_WIFI; netType != stopValue; netType += incrValue) { 637 NetworkStateTracker nt = mNetTrackers[netType]; 638 if (nt.getNetworkInfo().isConnected() && !nt.isTeardownRequested()) { 639 ++numConnectedNets; 640 String[] dnsList = nt.getNameServers(); 641 for (int i = 0; i < dnsList.length && dnsList[i] != null; i++) { 642 // skip duplicate entries 643 if (!dnsList[i].equals(lastDns)) { 644 SystemProperties.set("net.dns" + index++, dnsList[i]); 645 lastDns = dnsList[i]; 646 } 647 } 648 } 649 } 650 // Null out any DNS properties that are no longer used 651 for (int i = index; i <= mNumDnsEntries; i++) { 652 SystemProperties.set("net.dns" + i, ""); 653 } 654 mNumDnsEntries = index - 1; 655 // Notify the name resolver library of the change 656 SystemProperties.set("net.dnschange", String.valueOf(sDnsChangeCounter++)); 657 return numConnectedNets; 658 } 659 660 @Override 661 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 662 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP) 663 != PackageManager.PERMISSION_GRANTED) { 664 pw.println("Permission Denial: can't dump ConnectivityService from from pid=" 665 + Binder.getCallingPid() 666 + ", uid=" + Binder.getCallingUid()); 667 return; 668 } 669 if (mActiveNetwork == null) { 670 pw.println("No active network"); 671 } else { 672 pw.println("Active network: " + mActiveNetwork.getNetworkInfo().getTypeName()); 673 } 674 pw.println(); 675 for (NetworkStateTracker nst : mNetTrackers) { 676 pw.println(nst.getNetworkInfo()); 677 pw.println(nst); 678 pw.println(); 679 } 680 } 681 682 private class MyHandler extends Handler { 683 @Override 684 public void handleMessage(Message msg) { 685 NetworkInfo info; 686 switch (msg.what) { 687 case NetworkStateTracker.EVENT_STATE_CHANGED: 688 info = (NetworkInfo) msg.obj; 689 if (DBG) Log.v(TAG, "ConnectivityChange for " + info.getTypeName() + ": " + 690 info.getState() + "/" + info.getDetailedState()); 691 692 // Connectivity state changed: 693 // [31-13] Reserved for future use 694 // [12-9] Network subtype (for mobile network, as defined by TelephonyManager) 695 // [8-3] Detailed state ordinal (as defined by NetworkInfo.DetailedState) 696 // [2-0] Network type (as defined by ConnectivityManager) 697 int eventLogParam = (info.getType() & 0x7) | 698 ((info.getDetailedState().ordinal() & 0x3f) << 3) | 699 (info.getSubtype() << 9); 700 EventLog.writeEvent(EVENTLOG_CONNECTIVITY_STATE_CHANGED, eventLogParam); 701 702 if (info.getDetailedState() == NetworkInfo.DetailedState.FAILED) { 703 handleConnectionFailure(info); 704 } else if (info.getState() == NetworkInfo.State.DISCONNECTED) { 705 handleDisconnect(info); 706 } else if (info.getState() == NetworkInfo.State.SUSPENDED) { 707 // TODO: need to think this over. 708 // the logic here is, handle SUSPENDED the same as DISCONNECTED. The 709 // only difference being we are broadcasting an intent with NetworkInfo 710 // that's suspended. This allows the applications an opportunity to 711 // handle DISCONNECTED and SUSPENDED differently, or not. 712 handleDisconnect(info); 713 } else if (info.getState() == NetworkInfo.State.CONNECTED) { 714 handleConnect(info); 715 } 716 handleConnectivityChange(); 717 break; 718 719 case NetworkStateTracker.EVENT_SCAN_RESULTS_AVAILABLE: 720 info = (NetworkInfo) msg.obj; 721 handleScanResultsAvailable(info); 722 break; 723 724 case NetworkStateTracker.EVENT_NOTIFICATION_CHANGED: 725 handleNotificationChange(msg.arg1 == 1, msg.arg2, (Notification) msg.obj); 726 727 case NetworkStateTracker.EVENT_CONFIGURATION_CHANGED: 728 handleConfigurationChange(); 729 break; 730 731 case NetworkStateTracker.EVENT_ROAMING_CHANGED: 732 // fill me in 733 break; 734 735 case NetworkStateTracker.EVENT_NETWORK_SUBTYPE_CHANGED: 736 // fill me in 737 break; 738 } 739 } 740 } 741} 742