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