ConnectivityService.java revision 54b6cfa9a9e5b861a9930af873580d6dc20f773c
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.telephony.TelephonyManager; 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 boolean mTeardownRequested[]; 63 private WifiStateTracker mWifiStateTracker; 64 private MobileDataStateTracker mMobileDataStateTracker; 65 private WifiWatchdogService mWifiWatchdogService; 66 67 private Context mContext; 68 private int mNetworkPreference; 69 private NetworkStateTracker mActiveNetwork; 70 71 private int mNumDnsEntries; 72 private static int mDnsChangeCounter; 73 74 private boolean mTestMode; 75 private static ConnectivityService sServiceInstance; 76 77 private static class ConnectivityThread extends Thread { 78 private Context mContext; 79 80 private ConnectivityThread(Context context) { 81 super("ConnectivityThread"); 82 mContext = context; 83 } 84 85 @Override 86 public void run() { 87 Looper.prepare(); 88 synchronized (this) { 89 sServiceInstance = new ConnectivityService(mContext); 90 notifyAll(); 91 } 92 Looper.loop(); 93 } 94 95 public static ConnectivityService getServiceInstance(Context context) { 96 ConnectivityThread thread = new ConnectivityThread(context); 97 thread.start(); 98 99 synchronized (thread) { 100 while (sServiceInstance == null) { 101 try { 102 // Wait until sServiceInstance has been initialized. 103 thread.wait(); 104 } catch (InterruptedException e) { 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 mTeardownRequested = new boolean[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 // The WifiStateTracker should appear first in the list 138 mNetTrackers[ConnectivityManager.TYPE_WIFI] = mWifiStateTracker; 139 140 mMobileDataStateTracker = new MobileDataStateTracker(context, handler); 141 mNetTrackers[ConnectivityManager.TYPE_MOBILE] = mMobileDataStateTracker; 142 143 mActiveNetwork = null; 144 mNumDnsEntries = 0; 145 146 mTestMode = SystemProperties.get("cm.test.mode").equals("true") 147 && SystemProperties.get("ro.build.type").equals("eng"); 148 149 for (NetworkStateTracker t : mNetTrackers) 150 t.startMonitoring(); 151 152 // Constructing this starts it too 153 mWifiWatchdogService = new WifiWatchdogService(context, mWifiStateTracker); 154 } 155 156 /** 157 * Sets the preferred network. 158 * @param preference the new preference 159 */ 160 public synchronized void setNetworkPreference(int preference) { 161 enforceChangePermission(); 162 if (ConnectivityManager.isNetworkTypeValid(preference)) { 163 int oldPreference = mNetworkPreference; 164 persistNetworkPreference(preference); 165 if (mNetworkPreference != oldPreference) 166 enforcePreference(); 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.System.putInt(cr, Settings.System.NETWORK_PREFERENCE, networkPreference); 178 } 179 180 private int getPersistedNetworkPreference() { 181 final ContentResolver cr = mContext.getContentResolver(); 182 183 final int networkPrefSetting = Settings.System 184 .getInt(cr, Settings.System.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 mTeardownRequested[netTracker.getNetworkInfo().getType()] = true; 223 return true; 224 } else { 225 return false; 226 } 227 } 228 229 /** 230 * Return NetworkInfo for the active network interface. It is assumed that at most 231 * one network is active at a time. If more than one is active, it is indeterminate 232 * 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 297 public int stopUsingNetworkFeature(int networkType, String feature) { 298 enforceChangePermission(); 299 if (!ConnectivityManager.isNetworkTypeValid(networkType)) { 300 return -1; 301 } 302 NetworkStateTracker tracker = mNetTrackers[networkType]; 303 if (tracker != null) { 304 return tracker.stopUsingNetworkFeature(feature, getCallingPid(), getCallingUid()); 305 } 306 return -1; 307 } 308 309 /** 310 * Ensure that a network route exists to deliver traffic to the specified 311 * host via the specified network interface. 312 * @param networkType the type of the network over which traffic to the specified 313 * host is to be routed 314 * @param hostAddress the IP address of the host to which the route is desired 315 * @return {@code true} on success, {@code false} on failure 316 */ 317 public boolean requestRouteToHost(int networkType, int hostAddress) { 318 enforceChangePermission(); 319 if (!ConnectivityManager.isNetworkTypeValid(networkType)) { 320 return false; 321 } 322 NetworkStateTracker tracker = mNetTrackers[networkType]; 323 /* 324 * If there's only one connected network, and it's the one requested, 325 * then we don't have to do anything - the requested route already 326 * exists. If it's not the requested network, then it's not possible 327 * to establish the requested route. Finally, if there is more than 328 * one connected network, then we must insert an entry in the routing 329 * table. 330 */ 331 if (getNumConnectedNetworks() > 1) { 332 return tracker.requestRouteToHost(hostAddress); 333 } else { 334 return tracker.getNetworkInfo().getType() == networkType; 335 } 336 } 337 338 private int getNumConnectedNetworks() { 339 int numConnectedNets = 0; 340 341 for (NetworkStateTracker nt : mNetTrackers) { 342 if (nt.getNetworkInfo().isConnected() 343 && !mTeardownRequested[nt.getNetworkInfo().getType()]) { 344 ++numConnectedNets; 345 } 346 } 347 return numConnectedNets; 348 } 349 350 private void enforceAccessPermission() { 351 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.ACCESS_NETWORK_STATE, 352 "ConnectivityService"); 353 } 354 355 private void enforceChangePermission() { 356 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.CHANGE_NETWORK_STATE, 357 "ConnectivityService"); 358 359 } 360 361 /** 362 * Handle a {@code DISCONNECTED} event. If this pertains to the non-active network, 363 * we ignore it. If it is for the active network, we send out a broadcast. 364 * But first, we check whether it might be possible to connect to a different 365 * network. 366 * @param info the {@code NetworkInfo} for the network 367 */ 368 private void handleDisconnect(NetworkInfo info) { 369 370 if (DBG) Log.v(TAG, "Handle DISCONNECT for " + info.getTypeName()); 371 372 /* 373 * If the disconnected network is not the active one, then don't report 374 * this as a loss of connectivity. What probably happened is that we're 375 * getting the disconnect for a network that we explicitly disabled 376 * in accordance with network preference policies. 377 */ 378 mTeardownRequested[info.getType()] = false; 379 if (mActiveNetwork == null || info.getType() != mActiveNetwork.getNetworkInfo().getType()) 380 return; 381 382 NetworkStateTracker newNet; 383 if (info.getType() == ConnectivityManager.TYPE_MOBILE) { 384 newNet = mWifiStateTracker; 385 } else /* info().getType() == TYPE_WIFI */ { 386 newNet = mMobileDataStateTracker; 387 } 388 389 NetworkInfo switchTo = null; 390 if (newNet.isAvailable()) { 391 mActiveNetwork = newNet; 392 switchTo = newNet.getNetworkInfo(); 393 switchTo.setFailover(true); 394 if (!switchTo.isConnectedOrConnecting()) 395 newNet.reconnect(); 396 } 397 398 boolean otherNetworkConnected = false; 399 Intent intent = new Intent(ConnectivityManager.CONNECTIVITY_ACTION); 400 intent.putExtra(ConnectivityManager.EXTRA_NETWORK_INFO, info); 401 if (info.isFailover()) { 402 intent.putExtra(ConnectivityManager.EXTRA_IS_FAILOVER, true); 403 info.setFailover(false); 404 } 405 if (info.getReason() != null) { 406 intent.putExtra(ConnectivityManager.EXTRA_REASON, info.getReason()); 407 } 408 if (info.getExtraInfo() != null) { 409 intent.putExtra(ConnectivityManager.EXTRA_EXTRA_INFO, info.getExtraInfo()); 410 } 411 if (switchTo != null) { 412 otherNetworkConnected = switchTo.isConnected(); 413 if (DBG) { 414 if (otherNetworkConnected) { 415 Log.v(TAG, "Switching to already connected " + switchTo.getTypeName()); 416 } else { 417 Log.v(TAG, "Attempting to switch to " + switchTo.getTypeName()); 418 } 419 } 420 intent.putExtra(ConnectivityManager.EXTRA_OTHER_NETWORK_INFO, switchTo); 421 } else { 422 intent.putExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, true); 423 } 424 if (DBG) Log.v(TAG, "Sending DISCONNECT bcast for " + info.getTypeName() + 425 (switchTo == null ? "" : " other=" + switchTo.getTypeName())); 426 427 mContext.sendStickyBroadcast(intent); 428 /* 429 * If the failover network is already connected, then immediately send out 430 * a followup broadcast indicating successful failover 431 */ 432 if (switchTo != null && otherNetworkConnected) 433 sendConnectedBroadcast(switchTo); 434 } 435 436 private void sendConnectedBroadcast(NetworkInfo info) { 437 Intent intent = new Intent(ConnectivityManager.CONNECTIVITY_ACTION); 438 intent.putExtra(ConnectivityManager.EXTRA_NETWORK_INFO, info); 439 if (info.isFailover()) { 440 intent.putExtra(ConnectivityManager.EXTRA_IS_FAILOVER, true); 441 info.setFailover(false); 442 } 443 if (info.getReason() != null) { 444 intent.putExtra(ConnectivityManager.EXTRA_REASON, info.getReason()); 445 } 446 if (info.getExtraInfo() != null) { 447 intent.putExtra(ConnectivityManager.EXTRA_EXTRA_INFO, info.getExtraInfo()); 448 } 449 mContext.sendStickyBroadcast(intent); 450 } 451 452 private void handleConnectionFailure(NetworkInfo info) { 453 mTeardownRequested[info.getType()] = false; 454 if (getActiveNetworkInfo() == null) { 455 String reason = info.getReason(); 456 String extraInfo = info.getExtraInfo(); 457 458 if (DBG) { 459 String reasonText; 460 if (reason == null) { 461 reasonText = "."; 462 } else { 463 reasonText = " (" + reason + ")."; 464 } 465 Log.v(TAG, "Attempt to connect to " + info.getTypeName() + " failed" + reasonText); 466 } 467 468 Intent intent = new Intent(ConnectivityManager.CONNECTIVITY_ACTION); 469 intent.putExtra(ConnectivityManager.EXTRA_NETWORK_INFO, info); 470 intent.putExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, true); 471 if (reason != null) { 472 intent.putExtra(ConnectivityManager.EXTRA_REASON, reason); 473 } 474 if (extraInfo != null) { 475 intent.putExtra(ConnectivityManager.EXTRA_EXTRA_INFO, extraInfo); 476 } 477 if (info.isFailover()) { 478 intent.putExtra(ConnectivityManager.EXTRA_IS_FAILOVER, true); 479 info.setFailover(false); 480 } 481 mContext.sendStickyBroadcast(intent); 482 } 483 } 484 485 private void handleConnect(NetworkInfo info) { 486 if (DBG) Log.v(TAG, "Handle CONNECT for " + info.getTypeName()); 487 488 // snapshot isFailover, because sendConnectedBroadcast() resets it 489 boolean isFailover = info.isFailover(); 490 NetworkStateTracker thisNet = mNetTrackers[info.getType()]; 491 NetworkStateTracker deadnet = null; 492 NetworkStateTracker otherNet; 493 if (info.getType() == ConnectivityManager.TYPE_MOBILE) { 494 otherNet = mWifiStateTracker; 495 } else /* info().getType() == TYPE_WIFI */ { 496 otherNet = mMobileDataStateTracker; 497 } 498 /* 499 * Check policy to see whether we are now connected to a network that 500 * takes precedence over the other one. If so, we need to tear down 501 * the other one. 502 */ 503 NetworkInfo wifiInfo = mWifiStateTracker.getNetworkInfo(); 504 NetworkInfo mobileInfo = mMobileDataStateTracker.getNetworkInfo(); 505 if (wifiInfo.isConnected() && mobileInfo.isConnected()) { 506 if (mNetworkPreference == ConnectivityManager.TYPE_WIFI) 507 deadnet = mMobileDataStateTracker; 508 else 509 deadnet = mWifiStateTracker; 510 } 511 512 boolean toredown = false; 513 mTeardownRequested[info.getType()] = false; 514 if (!mTestMode && deadnet != null) { 515 if (DBG) Log.v(TAG, "Policy requires " + 516 deadnet.getNetworkInfo().getTypeName() + " teardown"); 517 toredown = teardown(deadnet); 518 if (DBG && !toredown) { 519 Log.d(TAG, "Network declined teardown request"); 520 } 521 } 522 523 if (!toredown || deadnet.getNetworkInfo().getType() != info.getType()) { 524 mActiveNetwork = thisNet; 525 if (DBG) Log.v(TAG, "Sending CONNECT bcast for " + info.getTypeName()); 526 thisNet.updateNetworkSettings(); 527 sendConnectedBroadcast(info); 528 if (isFailover) { 529 otherNet.releaseWakeLock(); 530 } 531 } else { 532 if (DBG) Log.v(TAG, "Not broadcasting CONNECT_ACTION to torn down network " + 533 info.getTypeName()); 534 } 535 } 536 537 private void handleScanResultsAvailable(NetworkInfo info) { 538 int networkType = info.getType(); 539 if (networkType != ConnectivityManager.TYPE_WIFI) { 540 if (DBG) Log.v(TAG, "Got ScanResultsAvailable for " + info.getTypeName() + " network." 541 + " Don't know how to handle."); 542 } 543 544 mNetTrackers[networkType].interpretScanResultsAvailable(); 545 } 546 547 private void handleNotificationChange(boolean visible, int id, Notification notification) { 548 NotificationManager notificationManager = (NotificationManager) mContext 549 .getSystemService(Context.NOTIFICATION_SERVICE); 550 551 if (visible) { 552 notificationManager.notify(id, notification); 553 } else { 554 notificationManager.cancel(id); 555 } 556 } 557 558 /** 559 * After any kind of change in the connectivity state of any network, 560 * make sure that anything that depends on the connectivity state of 561 * more than one network is set up correctly. We're mainly concerned 562 * with making sure that the list of DNS servers is set up according 563 * to which networks are connected, and ensuring that the right routing 564 * table entries exist. 565 */ 566 private void handleConnectivityChange() { 567 /* 568 * If both mobile and wifi are enabled, add the host routes that 569 * will allow MMS traffic to pass on the mobile network. But 570 * remove the default route for the mobile network, so that there 571 * will be only one default route, to ensure that all traffic 572 * except MMS will travel via Wi-Fi. 573 */ 574 int numConnectedNets = handleConfigurationChange(); 575 if (numConnectedNets > 1) { 576 mMobileDataStateTracker.addPrivateRoutes(); 577 mMobileDataStateTracker.removeDefaultRoute(); 578 } else if (mMobileDataStateTracker.getNetworkInfo().isConnected()) { 579 mMobileDataStateTracker.removePrivateRoutes(); 580 mMobileDataStateTracker.restoreDefaultRoute(); 581 } 582 } 583 584 private int handleConfigurationChange() { 585 /* 586 * Set DNS properties. Always put Wi-Fi entries at the front of 587 * the list if it is active. 588 */ 589 int index = 1; 590 String lastDns = ""; 591 int numConnectedNets = 0; 592 int incrValue = ConnectivityManager.TYPE_MOBILE - ConnectivityManager.TYPE_WIFI; 593 int stopValue = ConnectivityManager.TYPE_MOBILE + incrValue; 594 595 for (int net = ConnectivityManager.TYPE_WIFI; net != stopValue; net += incrValue) { 596 NetworkStateTracker nt = mNetTrackers[net]; 597 if (nt.getNetworkInfo().isConnected() 598 && !mTeardownRequested[nt.getNetworkInfo().getType()]) { 599 ++numConnectedNets; 600 String[] dnsList = nt.getNameServers(); 601 for (int i = 0; i < dnsList.length && dnsList[i] != null; i++) { 602 // skip duplicate entries 603 if (!dnsList[i].equals(lastDns)) { 604 SystemProperties.set("net.dns" + index++, dnsList[i]); 605 lastDns = dnsList[i]; 606 } 607 } 608 } 609 } 610 // Null out any DNS properties that are no longer used 611 for (int i = index; i <= mNumDnsEntries; i++) { 612 SystemProperties.set("net.dns" + i, ""); 613 } 614 mNumDnsEntries = index - 1; 615 // Notify the name resolver library of the change 616 SystemProperties.set("net.dnschange", String.valueOf(mDnsChangeCounter++)); 617 return numConnectedNets; 618 } 619 620 @Override 621 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 622 if (mContext.checkCallingPermission(android.Manifest.permission.DUMP) 623 != PackageManager.PERMISSION_GRANTED) { 624 pw.println("Permission Denial: can't dump ConnectivityService from from pid=" 625 + Binder.getCallingPid() 626 + ", uid=" + Binder.getCallingUid()); 627 return; 628 } 629 if (mActiveNetwork == null) { 630 pw.println("No active network"); 631 } else { 632 pw.println("Active network: " + mActiveNetwork.getNetworkInfo().getTypeName()); 633 } 634 pw.println(); 635 for (NetworkStateTracker nst : mNetTrackers) { 636 pw.println(nst.getNetworkInfo()); 637 pw.println(nst); 638 pw.println(); 639 } 640 } 641 642 private class MyHandler extends Handler { 643 @Override 644 public void handleMessage(Message msg) { 645 NetworkInfo info; 646 switch (msg.what) { 647 case NetworkStateTracker.EVENT_STATE_CHANGED: 648 info = (NetworkInfo) msg.obj; 649 if (DBG) Log.v(TAG, "ConnectivityChange for " + info.getTypeName() + ": " + 650 info.getState() + "/" + info.getDetailedState()); 651 652 // Connectivity state changed: 653 // [31-11] Reserved for future use 654 // [10-9] Mobile network connection type (as defined by the TelephonyManager) 655 // [8-3] Detailed state ordinal (as defined by NetworkInfo.DetailedState) 656 // [2-0] Network type (as defined by ConnectivityManager) 657 int eventLogParam = (info.getType() & 0x7) | 658 ((info.getDetailedState().ordinal() & 0x3f) << 3) | 659 (TelephonyManager.getDefault().getNetworkType() << 9); 660 EventLog.writeEvent(EVENTLOG_CONNECTIVITY_STATE_CHANGED, eventLogParam); 661 662 if (info.getDetailedState() == NetworkInfo.DetailedState.FAILED) { 663 handleConnectionFailure(info); 664 } else if (info.getState() == NetworkInfo.State.DISCONNECTED) { 665 handleDisconnect(info); 666 } else if (info.getState() == NetworkInfo.State.SUSPENDED) { 667 // TODO: need to think this over. 668 // the logic here is, handle SUSPENDED the same as DISCONNECTED. The 669 // only difference being we are broadcasting an intent with NetworkInfo 670 // that's suspended. This allows the applications an opportunity to 671 // handle DISCONNECTED and SUSPENDED differently, or not. 672 handleDisconnect(info); 673 } else if (info.getState() == NetworkInfo.State.CONNECTED) { 674 handleConnect(info); 675 } 676 handleConnectivityChange(); 677 break; 678 679 case NetworkStateTracker.EVENT_SCAN_RESULTS_AVAILABLE: 680 info = (NetworkInfo) msg.obj; 681 handleScanResultsAvailable(info); 682 break; 683 684 case NetworkStateTracker.EVENT_NOTIFICATION_CHANGED: 685 handleNotificationChange(msg.arg1 == 1, msg.arg2, (Notification) msg.obj); 686 687 case NetworkStateTracker.EVENT_CONFIGURATION_CHANGED: 688 handleConfigurationChange(); 689 break; 690 } 691 } 692 } 693} 694