ConnectivityService.java revision 6e6dec284369238f16ac23497292de5a1a39aca8
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.IBinder; 34import android.os.Looper; 35import android.os.Message; 36import android.os.RemoteException; 37import android.os.ServiceManager; 38import android.os.SystemProperties; 39import android.provider.Settings; 40import android.text.TextUtils; 41import android.util.EventLog; 42import android.util.Log; 43 44import com.android.internal.telephony.Phone; 45 46import java.io.FileDescriptor; 47import java.io.PrintWriter; 48import java.util.ArrayList; 49import java.util.List; 50 51/** 52 * @hide 53 */ 54public class ConnectivityService extends IConnectivityManager.Stub { 55 56 private static final boolean DBG = true; 57 private static final String TAG = "ConnectivityService"; 58 59 // Event log tags (must be in sync with event-log-tags) 60 private static final int EVENTLOG_CONNECTIVITY_STATE_CHANGED = 50020; 61 62 // how long to wait before switching back to a radio's default network 63 private static final int RESTORE_DEFAULT_NETWORK_DELAY = 1 * 60 * 1000; 64 // system property that can override the above value 65 private static final String NETWORK_RESTORE_DELAY_PROP_NAME = 66 "android.telephony.apn-restore"; 67 68 /** 69 * Sometimes we want to refer to the individual network state 70 * trackers separately, and sometimes we just want to treat them 71 * abstractly. 72 */ 73 private NetworkStateTracker mNetTrackers[]; 74 75 /** 76 * A per Net list of the PID's that requested access to the net 77 * used both as a refcount and for per-PID DNS selection 78 */ 79 private List mNetRequestersPids[]; 80 81 private WifiWatchdogService mWifiWatchdogService; 82 83 // priority order of the nettrackers 84 // (excluding dynamically set mNetworkPreference) 85 // TODO - move mNetworkTypePreference into this 86 private int[] mPriorityList; 87 88 private Context mContext; 89 private int mNetworkPreference; 90 private int mActiveDefaultNetwork = -1; 91 92 private int mNumDnsEntries; 93 94 private boolean mTestMode; 95 private static ConnectivityService sServiceInstance; 96 97 private Handler mHandler; 98 99 // list of DeathRecipients used to make sure features are turned off when 100 // a process dies 101 private List mFeatureUsers; 102 103 private boolean mSystemReady; 104 private ArrayList<Intent> mDeferredBroadcasts; 105 106 private class NetworkAttributes { 107 /** 108 * Class for holding settings read from resources. 109 */ 110 public String mName; 111 public int mType; 112 public int mRadio; 113 public int mPriority; 114 public NetworkInfo.State mLastState; 115 public NetworkAttributes(String init) { 116 String fragments[] = init.split(","); 117 mName = fragments[0].toLowerCase(); 118 if (fragments[1].toLowerCase().equals("wifi")) { 119 mRadio = ConnectivityManager.TYPE_WIFI; 120 } else { 121 mRadio = ConnectivityManager.TYPE_MOBILE; 122 } 123 if (mName.equals("default")) { 124 mType = mRadio; 125 } else if (mName.equals("mms")) { 126 mType = ConnectivityManager.TYPE_MOBILE_MMS; 127 } else if (mName.equals("supl")) { 128 mType = ConnectivityManager.TYPE_MOBILE_SUPL; 129 } else if (mName.equals("dun")) { 130 mType = ConnectivityManager.TYPE_MOBILE_DUN; 131 } else if (mName.equals("hipri")) { 132 mType = ConnectivityManager.TYPE_MOBILE_HIPRI; 133 } 134 mPriority = Integer.parseInt(fragments[2]); 135 mLastState = NetworkInfo.State.UNKNOWN; 136 } 137 public boolean isDefault() { 138 return (mType == mRadio); 139 } 140 } 141 NetworkAttributes[] mNetAttributes; 142 143 private class RadioAttributes { 144 public String mName; 145 public int mPriority; 146 public int mSimultaneity; 147 public int mType; 148 public RadioAttributes(String init) { 149 String fragments[] = init.split(","); 150 mName = fragments[0].toLowerCase(); 151 mPriority = Integer.parseInt(fragments[1]); 152 mSimultaneity = Integer.parseInt(fragments[2]); 153 if (mName.equals("wifi")) { 154 mType = ConnectivityManager.TYPE_WIFI; 155 } else { 156 mType = ConnectivityManager.TYPE_MOBILE; 157 } 158 } 159 } 160 RadioAttributes[] mRadioAttributes; 161 162 private static class ConnectivityThread extends Thread { 163 private Context mContext; 164 165 private ConnectivityThread(Context context) { 166 super("ConnectivityThread"); 167 mContext = context; 168 } 169 170 @Override 171 public void run() { 172 Looper.prepare(); 173 synchronized (this) { 174 sServiceInstance = new ConnectivityService(mContext); 175 notifyAll(); 176 } 177 Looper.loop(); 178 } 179 180 public static ConnectivityService getServiceInstance(Context context) { 181 ConnectivityThread thread = new ConnectivityThread(context); 182 thread.start(); 183 184 synchronized (thread) { 185 while (sServiceInstance == null) { 186 try { 187 // Wait until sServiceInstance has been initialized. 188 thread.wait(); 189 } catch (InterruptedException ignore) { 190 Log.e(TAG, 191 "Unexpected InterruptedException while waiting"+ 192 " for ConnectivityService thread"); 193 } 194 } 195 } 196 197 return sServiceInstance; 198 } 199 } 200 201 public static ConnectivityService getInstance(Context context) { 202 return ConnectivityThread.getServiceInstance(context); 203 } 204 205 private ConnectivityService(Context context) { 206 if (DBG) Log.v(TAG, "ConnectivityService starting up"); 207 mContext = context; 208 mNetTrackers = new NetworkStateTracker[ 209 ConnectivityManager.MAX_NETWORK_TYPE+1]; 210 mHandler = new MyHandler(); 211 212 mNetworkPreference = getPersistedNetworkPreference(); 213 214 // Load device network attributes from resources 215 mNetAttributes = new NetworkAttributes[ 216 ConnectivityManager.MAX_NETWORK_TYPE+1]; 217 mRadioAttributes = new RadioAttributes[ 218 ConnectivityManager.MAX_RADIO_TYPE+1]; 219 String[] naStrings = context.getResources().getStringArray( 220 com.android.internal.R.array.networkAttributes); 221 // TODO - what if the setting has gaps/unknown types? 222 for (String a : naStrings) { 223 NetworkAttributes n = new NetworkAttributes(a); 224 mNetAttributes[n.mType] = n; 225 } 226 String[] raStrings = context.getResources().getStringArray( 227 com.android.internal.R.array.radioAttributes); 228 for (String a : raStrings) { 229 RadioAttributes r = new RadioAttributes(a); 230 mRadioAttributes[r.mType] = r; 231 } 232 233 // high priority first 234 mPriorityList = new int[naStrings.length]; 235 { 236 int priority = 0; //lowest 237 int nextPos = naStrings.length-1; 238 while (nextPos>-1) { 239 for (int i = 0; i < mNetAttributes.length; i++) { 240 if(mNetAttributes[i].mPriority == priority) { 241 mPriorityList[nextPos--] = i; 242 } 243 } 244 priority++; 245 } 246 } 247 248 mNetRequestersPids = 249 new ArrayList[ConnectivityManager.MAX_NETWORK_TYPE+1]; 250 for (int i=0; i<=ConnectivityManager.MAX_NETWORK_TYPE; i++) { 251 mNetRequestersPids[i] = new ArrayList(); 252 } 253 254 mFeatureUsers = new ArrayList(); 255 256 /* 257 * Create the network state trackers for Wi-Fi and mobile 258 * data. Maybe this could be done with a factory class, 259 * but it's not clear that it's worth it, given that 260 * the number of different network types is not going 261 * to change very often. 262 */ 263 if (DBG) Log.v(TAG, "Starting Wifi Service."); 264 WifiStateTracker wst = new WifiStateTracker(context, mHandler); 265 WifiService wifiService = new WifiService(context, wst); 266 ServiceManager.addService(Context.WIFI_SERVICE, wifiService); 267 mNetTrackers[ConnectivityManager.TYPE_WIFI] = wst; 268 269 mNetTrackers[ConnectivityManager.TYPE_MOBILE] = 270 new MobileDataStateTracker(context, mHandler, 271 ConnectivityManager.TYPE_MOBILE, Phone.APN_TYPE_DEFAULT, 272 "MOBILE"); 273 274 mNetTrackers[ConnectivityManager.TYPE_MOBILE_MMS] = 275 new MobileDataStateTracker(context, mHandler, 276 ConnectivityManager.TYPE_MOBILE_MMS, Phone.APN_TYPE_MMS, 277 "MOBILE_MMS"); 278 279 mNetTrackers[ConnectivityManager.TYPE_MOBILE_SUPL] = 280 new MobileDataStateTracker(context, mHandler, 281 ConnectivityManager.TYPE_MOBILE_SUPL, Phone.APN_TYPE_SUPL, 282 "MOBILE_SUPL"); 283 284 mNetTrackers[ConnectivityManager.TYPE_MOBILE_DUN] = 285 new MobileDataStateTracker(context, mHandler, 286 ConnectivityManager.TYPE_MOBILE_DUN, Phone.APN_TYPE_DUN, 287 "MOBILE_DUN"); 288 289 mNetTrackers[ConnectivityManager.TYPE_MOBILE_HIPRI] = 290 new MobileDataStateTracker(context, mHandler, 291 ConnectivityManager.TYPE_MOBILE_HIPRI, Phone.APN_TYPE_HIPRI, 292 "MOBILE_HIPRI"); 293 294 mNumDnsEntries = 0; 295 296 mTestMode = SystemProperties.get("cm.test.mode").equals("true") 297 && SystemProperties.get("ro.build.type").equals("eng"); 298 299 for (NetworkStateTracker t : mNetTrackers) 300 t.startMonitoring(); 301 302 // Constructing this starts it too 303 mWifiWatchdogService = new WifiWatchdogService(context, wst); 304 } 305 306 /** 307 * Sets the preferred network. 308 * @param preference the new preference 309 */ 310 public synchronized void setNetworkPreference(int preference) { 311 enforceChangePermission(); 312 if (ConnectivityManager.isNetworkTypeValid(preference) && 313 mNetAttributes[preference].isDefault()) { 314 if (mNetworkPreference != preference) { 315 persistNetworkPreference(preference); 316 mNetworkPreference = preference; 317 enforcePreference(); 318 } 319 } 320 } 321 322 public int getNetworkPreference() { 323 enforceAccessPermission(); 324 return mNetworkPreference; 325 } 326 327 private void persistNetworkPreference(int networkPreference) { 328 final ContentResolver cr = mContext.getContentResolver(); 329 Settings.Secure.putInt(cr, Settings.Secure.NETWORK_PREFERENCE, 330 networkPreference); 331 } 332 333 private int getPersistedNetworkPreference() { 334 final ContentResolver cr = mContext.getContentResolver(); 335 336 final int networkPrefSetting = Settings.Secure 337 .getInt(cr, Settings.Secure.NETWORK_PREFERENCE, -1); 338 if (networkPrefSetting != -1) { 339 return networkPrefSetting; 340 } 341 342 return ConnectivityManager.DEFAULT_NETWORK_PREFERENCE; 343 } 344 345 /** 346 * Make the state of network connectivity conform to the preference settings 347 * In this method, we only tear down a non-preferred network. Establishing 348 * a connection to the preferred network is taken care of when we handle 349 * the disconnect event from the non-preferred network 350 * (see {@link #handleDisconnect(NetworkInfo)}). 351 */ 352 private void enforcePreference() { 353 if (mNetTrackers[mNetworkPreference].getNetworkInfo().isConnected()) 354 return; 355 356 if (!mNetTrackers[mNetworkPreference].isAvailable()) 357 return; 358 359 for (int t=0; t <= ConnectivityManager.MAX_RADIO_TYPE; t++) { 360 if (t != mNetworkPreference && 361 mNetTrackers[t].getNetworkInfo().isConnected()) { 362 if (DBG) { 363 Log.d(TAG, "tearing down " + 364 mNetTrackers[t].getNetworkInfo() + 365 " in enforcePreference"); 366 } 367 teardown(mNetTrackers[t]); 368 } 369 } 370 } 371 372 private boolean teardown(NetworkStateTracker netTracker) { 373 if (netTracker.teardown()) { 374 netTracker.setTeardownRequested(true); 375 return true; 376 } else { 377 return false; 378 } 379 } 380 381 /** 382 * Return NetworkInfo for the active (i.e., connected) network interface. 383 * It is assumed that at most one network is active at a time. If more 384 * than one is active, it is indeterminate which will be returned. 385 * @return the info for the active network, or {@code null} if none is 386 * active 387 */ 388 public NetworkInfo getActiveNetworkInfo() { 389 enforceAccessPermission(); 390 for (int type=0; type <= ConnectivityManager.MAX_NETWORK_TYPE; type++) { 391 if (!mNetAttributes[type].isDefault()) { 392 continue; 393 } 394 NetworkStateTracker t = mNetTrackers[type]; 395 NetworkInfo info = t.getNetworkInfo(); 396 if (info.isConnected()) { 397 if (DBG && type != mActiveDefaultNetwork) Log.e(TAG, 398 "connected default network is not " + 399 "mActiveDefaultNetwork!"); 400 return info; 401 } 402 } 403 return null; 404 } 405 406 public NetworkInfo getNetworkInfo(int networkType) { 407 enforceAccessPermission(); 408 if (ConnectivityManager.isNetworkTypeValid(networkType)) { 409 NetworkStateTracker t = mNetTrackers[networkType]; 410 if (t != null) 411 return t.getNetworkInfo(); 412 } 413 return null; 414 } 415 416 public NetworkInfo[] getAllNetworkInfo() { 417 enforceAccessPermission(); 418 NetworkInfo[] result = new NetworkInfo[mNetTrackers.length]; 419 int i = 0; 420 for (NetworkStateTracker t : mNetTrackers) { 421 result[i++] = t.getNetworkInfo(); 422 } 423 return result; 424 } 425 426 public boolean setRadios(boolean turnOn) { 427 boolean result = true; 428 enforceChangePermission(); 429 for (NetworkStateTracker t : mNetTrackers) { 430 result = t.setRadio(turnOn) && result; 431 } 432 return result; 433 } 434 435 public boolean setRadio(int netType, boolean turnOn) { 436 enforceChangePermission(); 437 if (!ConnectivityManager.isNetworkTypeValid(netType)) { 438 return false; 439 } 440 NetworkStateTracker tracker = mNetTrackers[netType]; 441 return tracker != null && tracker.setRadio(turnOn); 442 } 443 444 /** 445 * Used to notice when the calling process dies so we can self-expire 446 * 447 * Also used to know if the process has cleaned up after itself when 448 * our auto-expire timer goes off. The timer has a link to an object. 449 * 450 */ 451 private class FeatureUser implements IBinder.DeathRecipient { 452 int mNetworkType; 453 String mFeature; 454 IBinder mBinder; 455 int mPid; 456 int mUid; 457 long mCreateTime; 458 459 FeatureUser(int type, String feature, IBinder binder) { 460 super(); 461 mNetworkType = type; 462 mFeature = feature; 463 mBinder = binder; 464 mPid = getCallingPid(); 465 mUid = getCallingUid(); 466 mCreateTime = System.currentTimeMillis(); 467 468 try { 469 mBinder.linkToDeath(this, 0); 470 } catch (RemoteException e) { 471 binderDied(); 472 } 473 } 474 475 void unlinkDeathRecipient() { 476 mBinder.unlinkToDeath(this, 0); 477 } 478 479 public void binderDied() { 480 Log.d(TAG, "ConnectivityService FeatureUser binderDied(" + 481 mNetworkType + ", " + mFeature + ", " + mBinder + "), created " + 482 (System.currentTimeMillis() - mCreateTime) + " mSec ago"); 483 stopUsingNetworkFeature(this, false); 484 } 485 486 public void expire() { 487 Log.d(TAG, "ConnectivityService FeatureUser expire(" + 488 mNetworkType + ", " + mFeature + ", " + mBinder +"), created " + 489 (System.currentTimeMillis() - mCreateTime) + " mSec ago"); 490 stopUsingNetworkFeature(this, false); 491 } 492 493 public String toString() { 494 return "FeatureUser("+mNetworkType+","+mFeature+","+mPid+","+mUid+"), created " + 495 (System.currentTimeMillis() - mCreateTime) + " mSec ago"; 496 } 497 } 498 499 // javadoc from interface 500 public int startUsingNetworkFeature(int networkType, String feature, 501 IBinder binder) { 502 if (DBG) { 503 Log.d(TAG, "startUsingNetworkFeature for net " + networkType + 504 ": " + feature); 505 } 506 enforceChangePermission(); 507 if (!ConnectivityManager.isNetworkTypeValid(networkType)) { 508 return Phone.APN_REQUEST_FAILED; 509 } 510 511 FeatureUser f = new FeatureUser(networkType, feature, binder); 512 513 // TODO - move this into the MobileDataStateTracker 514 int usedNetworkType = networkType; 515 if(networkType == ConnectivityManager.TYPE_MOBILE) { 516 if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_MMS)) { 517 usedNetworkType = ConnectivityManager.TYPE_MOBILE_MMS; 518 } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_SUPL)) { 519 usedNetworkType = ConnectivityManager.TYPE_MOBILE_SUPL; 520 } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_DUN)) { 521 usedNetworkType = ConnectivityManager.TYPE_MOBILE_DUN; 522 } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_HIPRI)) { 523 usedNetworkType = ConnectivityManager.TYPE_MOBILE_HIPRI; 524 } 525 } 526 NetworkStateTracker network = mNetTrackers[usedNetworkType]; 527 if (network != null) { 528 if (usedNetworkType != networkType) { 529 Integer currentPid = new Integer(getCallingPid()); 530 531 NetworkStateTracker radio = mNetTrackers[networkType]; 532 NetworkInfo ni = network.getNetworkInfo(); 533 534 if (ni.isAvailable() == false) { 535 if (DBG) Log.d(TAG, "special network not available"); 536 return Phone.APN_TYPE_NOT_AVAILABLE; 537 } 538 539 synchronized(this) { 540 mFeatureUsers.add(f); 541 if (!mNetRequestersPids[usedNetworkType].contains(currentPid)) { 542 // this gets used for per-pid dns when connected 543 mNetRequestersPids[usedNetworkType].add(currentPid); 544 } 545 } 546 mHandler.sendMessageDelayed(mHandler.obtainMessage( 547 NetworkStateTracker.EVENT_RESTORE_DEFAULT_NETWORK, 548 f), getRestoreDefaultNetworkDelay()); 549 550 551 if ((ni.isConnectedOrConnecting() == true) && 552 !network.isTeardownRequested()) { 553 if (ni.isConnected() == true) { 554 // add the pid-specific dns 555 handleDnsConfigurationChange(); 556 if (DBG) Log.d(TAG, "special network already active"); 557 return Phone.APN_ALREADY_ACTIVE; 558 } 559 if (DBG) Log.d(TAG, "special network already connecting"); 560 return Phone.APN_REQUEST_STARTED; 561 } 562 563 // check if the radio in play can make another contact 564 // assume if cannot for now 565 566 if (DBG) Log.d(TAG, "reconnecting to special network"); 567 network.reconnect(); 568 return Phone.APN_REQUEST_STARTED; 569 } else { 570 synchronized(this) { 571 mFeatureUsers.add(f); 572 } 573 mHandler.sendMessageDelayed(mHandler.obtainMessage( 574 NetworkStateTracker.EVENT_RESTORE_DEFAULT_NETWORK, 575 f), getRestoreDefaultNetworkDelay()); 576 577 return network.startUsingNetworkFeature(feature, 578 getCallingPid(), getCallingUid()); 579 } 580 } 581 return Phone.APN_TYPE_NOT_AVAILABLE; 582 } 583 584 // javadoc from interface 585 public int stopUsingNetworkFeature(int networkType, String feature) { 586 int pid = getCallingPid(); 587 int uid = getCallingUid(); 588 589 FeatureUser u = null; 590 boolean found = false; 591 592 synchronized(this) { 593 for (int i = 0; i < mFeatureUsers.size() ; i++) { 594 u = (FeatureUser)mFeatureUsers.get(i); 595 if (uid == u.mUid && pid == u.mPid && 596 networkType == u.mNetworkType && 597 TextUtils.equals(feature, u.mFeature)) { 598 found = true; 599 break; 600 } 601 } 602 } 603 if (found && u != null) { 604 // stop regardless of how many other time this proc had called start 605 return stopUsingNetworkFeature(u, true); 606 } else { 607 // none found! 608 if (DBG) Log.d(TAG, "ignoring stopUsingNetworkFeature - not a live request"); 609 return 1; 610 } 611 } 612 613 private int stopUsingNetworkFeature(FeatureUser u, boolean ignoreDups) { 614 int networkType = u.mNetworkType; 615 String feature = u.mFeature; 616 int pid = u.mPid; 617 int uid = u.mUid; 618 619 NetworkStateTracker tracker = null; 620 boolean callTeardown = false; // used to carry our decision outside of sync block 621 622 if (DBG) { 623 Log.d(TAG, "stopUsingNetworkFeature for net " + networkType + 624 ": " + feature); 625 } 626 enforceChangePermission(); 627 if (!ConnectivityManager.isNetworkTypeValid(networkType)) { 628 return -1; 629 } 630 631 // need to link the mFeatureUsers list with the mNetRequestersPids state in this 632 // sync block 633 synchronized(this) { 634 // check if this process still has an outstanding start request 635 if (!mFeatureUsers.contains(u)) { 636 return 1; 637 } 638 u.unlinkDeathRecipient(); 639 mFeatureUsers.remove(mFeatureUsers.indexOf(u)); 640 // If we care about duplicate requests, check for that here. 641 // 642 // This is done to support the extension of a request - the app 643 // can request we start the network feature again and renew the 644 // auto-shutoff delay. Normal "stop" calls from the app though 645 // do not pay attention to duplicate requests - in effect the 646 // API does not refcount and a single stop will counter multiple starts. 647 if (ignoreDups == false) { 648 for (int i = 0; i < mFeatureUsers.size() ; i++) { 649 FeatureUser x = (FeatureUser)mFeatureUsers.get(i); 650 if (x.mUid == u.mUid && x.mPid == u.mPid && 651 x.mNetworkType == u.mNetworkType && 652 TextUtils.equals(x.mFeature, u.mFeature)) { 653 if (DBG) Log.d(TAG, "ignoring stopUsingNetworkFeature as dup is found"); 654 return 1; 655 } 656 } 657 } 658 659 // TODO - move to MobileDataStateTracker 660 int usedNetworkType = networkType; 661 if (networkType == ConnectivityManager.TYPE_MOBILE) { 662 if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_MMS)) { 663 usedNetworkType = ConnectivityManager.TYPE_MOBILE_MMS; 664 } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_SUPL)) { 665 usedNetworkType = ConnectivityManager.TYPE_MOBILE_SUPL; 666 } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_DUN)) { 667 usedNetworkType = ConnectivityManager.TYPE_MOBILE_DUN; 668 } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_HIPRI)) { 669 usedNetworkType = ConnectivityManager.TYPE_MOBILE_HIPRI; 670 } 671 } 672 tracker = mNetTrackers[usedNetworkType]; 673 if(usedNetworkType != networkType) { 674 Integer currentPid = new Integer(pid); 675 mNetRequestersPids[usedNetworkType].remove(currentPid); 676 reassessPidDns(pid, true); 677 if (mNetRequestersPids[usedNetworkType].size() != 0) { 678 if (DBG) Log.d(TAG, "not tearing down special network - " + 679 "others still using it"); 680 return 1; 681 } 682 callTeardown = true; 683 } 684 } 685 686 if (callTeardown) { 687 tracker.teardown(); 688 return 1; 689 } else { 690 // do it the old fashioned way 691 return tracker.stopUsingNetworkFeature(feature, pid, uid); 692 } 693 } 694 695 /** 696 * Ensure that a network route exists to deliver traffic to the specified 697 * host via the specified network interface. 698 * @param networkType the type of the network over which traffic to the 699 * specified host is to be routed 700 * @param hostAddress the IP address of the host to which the route is 701 * desired 702 * @return {@code true} on success, {@code false} on failure 703 */ 704 public boolean requestRouteToHost(int networkType, int hostAddress) { 705 enforceChangePermission(); 706 if (!ConnectivityManager.isNetworkTypeValid(networkType)) { 707 return false; 708 } 709 NetworkStateTracker tracker = mNetTrackers[networkType]; 710 711 if (!tracker.getNetworkInfo().isConnected() || tracker.isTeardownRequested()) { 712 if (DBG) { 713 Log.d(TAG, "requestRouteToHost on down network (" + networkType + " - dropped"); 714 } 715 return false; 716 } 717 return tracker.requestRouteToHost(hostAddress); 718 } 719 720 /** 721 * @see ConnectivityManager#getBackgroundDataSetting() 722 */ 723 public boolean getBackgroundDataSetting() { 724 return Settings.Secure.getInt(mContext.getContentResolver(), 725 Settings.Secure.BACKGROUND_DATA, 1) == 1; 726 } 727 728 /** 729 * @see ConnectivityManager#setBackgroundDataSetting(boolean) 730 */ 731 public void setBackgroundDataSetting(boolean allowBackgroundDataUsage) { 732 mContext.enforceCallingOrSelfPermission( 733 android.Manifest.permission.CHANGE_BACKGROUND_DATA_SETTING, 734 "ConnectivityService"); 735 736 if (getBackgroundDataSetting() == allowBackgroundDataUsage) return; 737 738 Settings.Secure.putInt(mContext.getContentResolver(), 739 Settings.Secure.BACKGROUND_DATA, 740 allowBackgroundDataUsage ? 1 : 0); 741 742 Intent broadcast = new Intent( 743 ConnectivityManager.ACTION_BACKGROUND_DATA_SETTING_CHANGED); 744 mContext.sendBroadcast(broadcast); 745 } 746 747 private int getNumConnectedNetworks() { 748 int numConnectedNets = 0; 749 750 for (NetworkStateTracker nt : mNetTrackers) { 751 if (nt.getNetworkInfo().isConnected() && 752 !nt.isTeardownRequested()) { 753 ++numConnectedNets; 754 } 755 } 756 return numConnectedNets; 757 } 758 759 private void enforceAccessPermission() { 760 mContext.enforceCallingOrSelfPermission( 761 android.Manifest.permission.ACCESS_NETWORK_STATE, 762 "ConnectivityService"); 763 } 764 765 private void enforceChangePermission() { 766 mContext.enforceCallingOrSelfPermission( 767 android.Manifest.permission.CHANGE_NETWORK_STATE, 768 "ConnectivityService"); 769 } 770 771 /** 772 * Handle a {@code DISCONNECTED} event. If this pertains to the non-active 773 * network, we ignore it. If it is for the active network, we send out a 774 * broadcast. But first, we check whether it might be possible to connect 775 * to a different network. 776 * @param info the {@code NetworkInfo} for the network 777 */ 778 private void handleDisconnect(NetworkInfo info) { 779 780 int prevNetType = info.getType(); 781 782 mNetTrackers[prevNetType].setTeardownRequested(false); 783 /* 784 * If the disconnected network is not the active one, then don't report 785 * this as a loss of connectivity. What probably happened is that we're 786 * getting the disconnect for a network that we explicitly disabled 787 * in accordance with network preference policies. 788 */ 789 if (!mNetAttributes[prevNetType].isDefault()) { 790 List pids = mNetRequestersPids[prevNetType]; 791 for (int i = 0; i<pids.size(); i++) { 792 Integer pid = (Integer)pids.get(i); 793 // will remove them because the net's no longer connected 794 // need to do this now as only now do we know the pids and 795 // can properly null things that are no longer referenced. 796 reassessPidDns(pid.intValue(), false); 797 } 798 } 799 800 Intent intent = new Intent(ConnectivityManager.CONNECTIVITY_ACTION); 801 intent.putExtra(ConnectivityManager.EXTRA_NETWORK_INFO, info); 802 if (info.isFailover()) { 803 intent.putExtra(ConnectivityManager.EXTRA_IS_FAILOVER, true); 804 info.setFailover(false); 805 } 806 if (info.getReason() != null) { 807 intent.putExtra(ConnectivityManager.EXTRA_REASON, info.getReason()); 808 } 809 if (info.getExtraInfo() != null) { 810 intent.putExtra(ConnectivityManager.EXTRA_EXTRA_INFO, 811 info.getExtraInfo()); 812 } 813 814 NetworkStateTracker newNet = tryFailover(prevNetType); 815 if (newNet != null) { 816 NetworkInfo switchTo = newNet.getNetworkInfo(); 817 intent.putExtra(ConnectivityManager.EXTRA_OTHER_NETWORK_INFO, switchTo); 818 } else { 819 intent.putExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, true); 820 } 821 // do this before we broadcast the change 822 handleConnectivityChange(); 823 824 sendStickyBroadcast(intent); 825 /* 826 * If the failover network is already connected, then immediately send 827 * out a followup broadcast indicating successful failover 828 */ 829 if (newNet != null && newNet.getNetworkInfo().isConnected()) { 830 sendConnectedBroadcast(newNet.getNetworkInfo()); 831 } 832 } 833 834 // returns -1 if no failover available 835 private NetworkStateTracker tryFailover(int prevNetType) { 836 /* 837 * If this is a default network, check if other defaults are available 838 * or active 839 */ 840 NetworkStateTracker newNet = null; 841 if (mNetAttributes[prevNetType].isDefault()) { 842 if (mActiveDefaultNetwork == prevNetType) { 843 mActiveDefaultNetwork = -1; 844 } 845 846 int newType = -1; 847 int newPriority = -1; 848 for (int checkType=0; checkType <= ConnectivityManager.MAX_NETWORK_TYPE; checkType++) { 849 if (checkType == prevNetType) { 850 continue; 851 } 852 if (mNetAttributes[checkType].isDefault()) { 853 /* TODO - if we have multiple nets we could use 854 * we may want to put more thought into which we choose 855 */ 856 if (checkType == mNetworkPreference) { 857 newType = checkType; 858 break; 859 } 860 if (mRadioAttributes[mNetAttributes[checkType].mRadio]. 861 mPriority > newPriority) { 862 newType = checkType; 863 newPriority = mRadioAttributes[mNetAttributes[newType].mRadio].mPriority; 864 } 865 } 866 } 867 868 if (newType != -1) { 869 newNet = mNetTrackers[newType]; 870 /** 871 * See if the other network is available to fail over to. 872 * If is not available, we enable it anyway, so that it 873 * will be able to connect when it does become available, 874 * but we report a total loss of connectivity rather than 875 * report that we are attempting to fail over. 876 */ 877 if (newNet.isAvailable()) { 878 NetworkInfo switchTo = newNet.getNetworkInfo(); 879 switchTo.setFailover(true); 880 if (!switchTo.isConnectedOrConnecting() || 881 newNet.isTeardownRequested()) { 882 newNet.reconnect(); 883 } 884 if (DBG) { 885 if (switchTo.isConnected()) { 886 Log.v(TAG, "Switching to already connected " + 887 switchTo.getTypeName()); 888 } else { 889 Log.v(TAG, "Attempting to switch to " + 890 switchTo.getTypeName()); 891 } 892 } 893 } else { 894 newNet.reconnect(); 895 } 896 } 897 } 898 899 return newNet; 900 } 901 902 private void sendConnectedBroadcast(NetworkInfo info) { 903 Intent intent = new Intent(ConnectivityManager.CONNECTIVITY_ACTION); 904 intent.putExtra(ConnectivityManager.EXTRA_NETWORK_INFO, info); 905 if (info.isFailover()) { 906 intent.putExtra(ConnectivityManager.EXTRA_IS_FAILOVER, true); 907 info.setFailover(false); 908 } 909 if (info.getReason() != null) { 910 intent.putExtra(ConnectivityManager.EXTRA_REASON, info.getReason()); 911 } 912 if (info.getExtraInfo() != null) { 913 intent.putExtra(ConnectivityManager.EXTRA_EXTRA_INFO, 914 info.getExtraInfo()); 915 } 916 sendStickyBroadcast(intent); 917 } 918 919 /** 920 * Called when an attempt to fail over to another network has failed. 921 * @param info the {@link NetworkInfo} for the failed network 922 */ 923 private void handleConnectionFailure(NetworkInfo info) { 924 mNetTrackers[info.getType()].setTeardownRequested(false); 925 926 String reason = info.getReason(); 927 String extraInfo = info.getExtraInfo(); 928 929 if (DBG) { 930 String reasonText; 931 if (reason == null) { 932 reasonText = "."; 933 } else { 934 reasonText = " (" + reason + ")."; 935 } 936 Log.v(TAG, "Attempt to connect to " + info.getTypeName() + 937 " failed" + reasonText); 938 } 939 940 Intent intent = new Intent(ConnectivityManager.CONNECTIVITY_ACTION); 941 intent.putExtra(ConnectivityManager.EXTRA_NETWORK_INFO, info); 942 if (getActiveNetworkInfo() == null) { 943 intent.putExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, true); 944 } 945 if (reason != null) { 946 intent.putExtra(ConnectivityManager.EXTRA_REASON, reason); 947 } 948 if (extraInfo != null) { 949 intent.putExtra(ConnectivityManager.EXTRA_EXTRA_INFO, extraInfo); 950 } 951 if (info.isFailover()) { 952 intent.putExtra(ConnectivityManager.EXTRA_IS_FAILOVER, true); 953 info.setFailover(false); 954 } 955 956 NetworkStateTracker newNet = tryFailover(info.getType()); 957 if (newNet != null) { 958 NetworkInfo switchTo = newNet.getNetworkInfo(); 959 intent.putExtra(ConnectivityManager.EXTRA_OTHER_NETWORK_INFO, switchTo); 960 } else { 961 intent.putExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, true); 962 } 963 // do this before we broadcast the change 964 handleConnectivityChange(); 965 966 sendStickyBroadcast(intent); 967 /* 968 * If the failover network is already connected, then immediately send 969 * out a followup broadcast indicating successful failover 970 */ 971 if (newNet != null && newNet.getNetworkInfo().isConnected()) { 972 sendConnectedBroadcast(newNet.getNetworkInfo()); 973 } 974 } 975 976 private void sendStickyBroadcast(Intent intent) { 977 synchronized(this) { 978 if (mSystemReady) { 979 mContext.sendStickyBroadcast(intent); 980 } else { 981 if (mDeferredBroadcasts == null) { 982 mDeferredBroadcasts = new ArrayList<Intent>(); 983 } 984 mDeferredBroadcasts.add(intent); 985 } 986 } 987 } 988 989 void systemReady() { 990 synchronized(this) { 991 mSystemReady = true; 992 if (mDeferredBroadcasts != null) { 993 int count = mDeferredBroadcasts.size(); 994 for (int i = 0; i < count; i++) { 995 mContext.sendStickyBroadcast(mDeferredBroadcasts.get(i)); 996 } 997 mDeferredBroadcasts = null; 998 } 999 } 1000 } 1001 1002 private void handleConnect(NetworkInfo info) { 1003 int type = info.getType(); 1004 1005 // snapshot isFailover, because sendConnectedBroadcast() resets it 1006 boolean isFailover = info.isFailover(); 1007 NetworkStateTracker thisNet = mNetTrackers[type]; 1008 1009 // if this is a default net and other default is running 1010 // kill the one not preferred 1011 if (mNetAttributes[type].isDefault()) { 1012 if (mActiveDefaultNetwork != -1 && mActiveDefaultNetwork != type) { 1013 if ((type != mNetworkPreference && 1014 mNetAttributes[mActiveDefaultNetwork].mPriority > 1015 mNetAttributes[type].mPriority) || 1016 mNetworkPreference == mActiveDefaultNetwork) { 1017 // don't accept this one 1018 if (DBG) Log.v(TAG, "Not broadcasting CONNECT_ACTION " + 1019 "to torn down network " + info.getTypeName()); 1020 teardown(thisNet); 1021 return; 1022 } else { 1023 // tear down the other 1024 NetworkStateTracker otherNet = 1025 mNetTrackers[mActiveDefaultNetwork]; 1026 if (DBG) Log.v(TAG, "Policy requires " + 1027 otherNet.getNetworkInfo().getTypeName() + 1028 " teardown"); 1029 if (!teardown(otherNet)) { 1030 Log.e(TAG, "Network declined teardown request"); 1031 return; 1032 } 1033 if (isFailover) { 1034 otherNet.releaseWakeLock(); 1035 } 1036 } 1037 } 1038 mActiveDefaultNetwork = type; 1039 } 1040 thisNet.setTeardownRequested(false); 1041 thisNet.updateNetworkSettings(); 1042 handleConnectivityChange(); 1043 sendConnectedBroadcast(info); 1044 } 1045 1046 private void handleScanResultsAvailable(NetworkInfo info) { 1047 int networkType = info.getType(); 1048 if (networkType != ConnectivityManager.TYPE_WIFI) { 1049 if (DBG) Log.v(TAG, "Got ScanResultsAvailable for " + 1050 info.getTypeName() + " network. Don't know how to handle."); 1051 } 1052 1053 mNetTrackers[networkType].interpretScanResultsAvailable(); 1054 } 1055 1056 private void handleNotificationChange(boolean visible, int id, 1057 Notification notification) { 1058 NotificationManager notificationManager = (NotificationManager) mContext 1059 .getSystemService(Context.NOTIFICATION_SERVICE); 1060 1061 if (visible) { 1062 notificationManager.notify(id, notification); 1063 } else { 1064 notificationManager.cancel(id); 1065 } 1066 } 1067 1068 /** 1069 * After any kind of change in the connectivity state of any network, 1070 * make sure that anything that depends on the connectivity state of 1071 * more than one network is set up correctly. We're mainly concerned 1072 * with making sure that the list of DNS servers is set up according 1073 * to which networks are connected, and ensuring that the right routing 1074 * table entries exist. 1075 */ 1076 private void handleConnectivityChange() { 1077 /* 1078 * If a non-default network is enabled, add the host routes that 1079 * will allow it's DNS servers to be accessed. Only 1080 * If both mobile and wifi are enabled, add the host routes that 1081 * will allow MMS traffic to pass on the mobile network. But 1082 * remove the default route for the mobile network, so that there 1083 * will be only one default route, to ensure that all traffic 1084 * except MMS will travel via Wi-Fi. 1085 */ 1086 handleDnsConfigurationChange(); 1087 1088 for (int netType : mPriorityList) { 1089 if (mNetTrackers[netType].getNetworkInfo().isConnected()) { 1090 if (mNetAttributes[netType].isDefault()) { 1091 mNetTrackers[netType].addDefaultRoute(); 1092 } else { 1093 mNetTrackers[netType].addPrivateDnsRoutes(); 1094 } 1095 } else { 1096 if (mNetAttributes[netType].isDefault()) { 1097 mNetTrackers[netType].removeDefaultRoute(); 1098 } else { 1099 mNetTrackers[netType].removePrivateDnsRoutes(); 1100 } 1101 } 1102 } 1103 } 1104 1105 /** 1106 * Adjust the per-process dns entries (net.dns<x>.<pid>) based 1107 * on the highest priority active net which this process requested. 1108 * If there aren't any, clear it out 1109 */ 1110 private void reassessPidDns(int myPid, boolean doBump) 1111 { 1112 if (DBG) Log.d(TAG, "reassessPidDns for pid " + myPid); 1113 for(int i : mPriorityList) { 1114 if (mNetAttributes[i].isDefault()) { 1115 continue; 1116 } 1117 NetworkStateTracker nt = mNetTrackers[i]; 1118 if (nt.getNetworkInfo().isConnected() && 1119 !nt.isTeardownRequested()) { 1120 List pids = mNetRequestersPids[i]; 1121 for (int j=0; j<pids.size(); j++) { 1122 Integer pid = (Integer)pids.get(j); 1123 if (pid.intValue() == myPid) { 1124 String[] dnsList = nt.getNameServers(); 1125 writePidDns(dnsList, myPid); 1126 if (doBump) { 1127 bumpDns(); 1128 } 1129 return; 1130 } 1131 } 1132 } 1133 } 1134 // nothing found - delete 1135 for (int i = 1; ; i++) { 1136 String prop = "net.dns" + i + "." + myPid; 1137 if (SystemProperties.get(prop).length() == 0) { 1138 if (doBump) { 1139 bumpDns(); 1140 } 1141 return; 1142 } 1143 SystemProperties.set(prop, ""); 1144 } 1145 } 1146 1147 private void writePidDns(String[] dnsList, int pid) { 1148 int j = 1; 1149 for (String dns : dnsList) { 1150 if (dns != null && !TextUtils.equals(dns, "0.0.0.0")) { 1151 SystemProperties.set("net.dns" + j++ + "." + pid, dns); 1152 } 1153 } 1154 } 1155 1156 private void bumpDns() { 1157 /* 1158 * Bump the property that tells the name resolver library to reread 1159 * the DNS server list from the properties. 1160 */ 1161 String propVal = SystemProperties.get("net.dnschange"); 1162 int n = 0; 1163 if (propVal.length() != 0) { 1164 try { 1165 n = Integer.parseInt(propVal); 1166 } catch (NumberFormatException e) {} 1167 } 1168 SystemProperties.set("net.dnschange", "" + (n+1)); 1169 } 1170 1171 private void handleDnsConfigurationChange() { 1172 // add default net's dns entries 1173 for (int x = mPriorityList.length-1; x>= 0; x--) { 1174 int netType = mPriorityList[x]; 1175 NetworkStateTracker nt = mNetTrackers[netType]; 1176 if (nt != null && nt.getNetworkInfo().isConnected() && 1177 !nt.isTeardownRequested()) { 1178 String[] dnsList = nt.getNameServers(); 1179 if (mNetAttributes[netType].isDefault()) { 1180 int j = 1; 1181 for (String dns : dnsList) { 1182 if (dns != null && !TextUtils.equals(dns, "0.0.0.0")) { 1183 if (DBG) { 1184 Log.d(TAG, "adding dns " + dns + " for " + 1185 nt.getNetworkInfo().getTypeName()); 1186 } 1187 SystemProperties.set("net.dns" + j++, dns); 1188 } 1189 } 1190 for (int k=j ; k<mNumDnsEntries; k++) { 1191 if (DBG) Log.d(TAG, "erasing net.dns" + k); 1192 SystemProperties.set("net.dns" + k, ""); 1193 } 1194 mNumDnsEntries = j; 1195 } else { 1196 // set per-pid dns for attached secondary nets 1197 List pids = mNetRequestersPids[netType]; 1198 for (int y=0; y< pids.size(); y++) { 1199 Integer pid = (Integer)pids.get(y); 1200 writePidDns(dnsList, pid.intValue()); 1201 } 1202 } 1203 } 1204 } 1205 1206 bumpDns(); 1207 } 1208 1209 private int getRestoreDefaultNetworkDelay() { 1210 String restoreDefaultNetworkDelayStr = SystemProperties.get( 1211 NETWORK_RESTORE_DELAY_PROP_NAME); 1212 if(restoreDefaultNetworkDelayStr != null && 1213 restoreDefaultNetworkDelayStr.length() != 0) { 1214 try { 1215 return Integer.valueOf(restoreDefaultNetworkDelayStr); 1216 } catch (NumberFormatException e) { 1217 } 1218 } 1219 return RESTORE_DEFAULT_NETWORK_DELAY; 1220 } 1221 1222 @Override 1223 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 1224 if (mContext.checkCallingOrSelfPermission( 1225 android.Manifest.permission.DUMP) 1226 != PackageManager.PERMISSION_GRANTED) { 1227 pw.println("Permission Denial: can't dump ConnectivityService " + 1228 "from from pid=" + Binder.getCallingPid() + ", uid=" + 1229 Binder.getCallingUid()); 1230 return; 1231 } 1232 pw.println(); 1233 for (NetworkStateTracker nst : mNetTrackers) { 1234 if (nst != null) { 1235 if (nst.getNetworkInfo().isConnected()) { 1236 pw.println("Active network: " + nst.getNetworkInfo(). 1237 getTypeName()); 1238 } 1239 pw.println(nst.getNetworkInfo()); 1240 pw.println(nst); 1241 pw.println(); 1242 } 1243 } 1244 1245 pw.println("Network Requester Pids:"); 1246 for (int net : mPriorityList) { 1247 String pidString = net + ": "; 1248 for (Object pid : mNetRequestersPids[net]) { 1249 pidString = pidString + pid.toString() + ", "; 1250 } 1251 pw.println(pidString); 1252 } 1253 pw.println(); 1254 1255 pw.println("FeatureUsers:"); 1256 for (Object requester : mFeatureUsers) { 1257 pw.println(requester.toString()); 1258 } 1259 pw.println(); 1260 } 1261 1262 // must be stateless - things change under us. 1263 private class MyHandler extends Handler { 1264 @Override 1265 public void handleMessage(Message msg) { 1266 NetworkInfo info; 1267 switch (msg.what) { 1268 case NetworkStateTracker.EVENT_STATE_CHANGED: 1269 info = (NetworkInfo) msg.obj; 1270 int type = info.getType(); 1271 NetworkInfo.State state = info.getState(); 1272 // only do this optimization for wifi. It going into scan mode for location 1273 // services generates alot of noise. Meanwhile the mms apn won't send out 1274 // subsequent notifications when on default cellular because it never 1275 // disconnects.. so only do this to wifi notifications. Fixed better when the 1276 // APN notifications are standardized. 1277 if (mNetAttributes[type].mLastState == state && 1278 mNetAttributes[type].mRadio == ConnectivityManager.TYPE_WIFI) { 1279 if (DBG) { 1280 // TODO - remove this after we validate the dropping doesn't break 1281 // anything 1282 Log.d(TAG, "Dropping ConnectivityChange for " + 1283 info.getTypeName() + ": " + 1284 state + "/" + info.getDetailedState()); 1285 } 1286 return; 1287 } 1288 mNetAttributes[type].mLastState = state; 1289 1290 if (DBG) Log.d(TAG, "ConnectivityChange for " + 1291 info.getTypeName() + ": " + 1292 state + "/" + info.getDetailedState()); 1293 1294 // Connectivity state changed: 1295 // [31-13] Reserved for future use 1296 // [12-9] Network subtype (for mobile network, as defined 1297 // by TelephonyManager) 1298 // [8-3] Detailed state ordinal (as defined by 1299 // NetworkInfo.DetailedState) 1300 // [2-0] Network type (as defined by ConnectivityManager) 1301 int eventLogParam = (info.getType() & 0x7) | 1302 ((info.getDetailedState().ordinal() & 0x3f) << 3) | 1303 (info.getSubtype() << 9); 1304 EventLog.writeEvent(EVENTLOG_CONNECTIVITY_STATE_CHANGED, 1305 eventLogParam); 1306 1307 if (info.getDetailedState() == 1308 NetworkInfo.DetailedState.FAILED) { 1309 handleConnectionFailure(info); 1310 } else if (state == NetworkInfo.State.DISCONNECTED) { 1311 handleDisconnect(info); 1312 } else if (state == NetworkInfo.State.SUSPENDED) { 1313 // TODO: need to think this over. 1314 // the logic here is, handle SUSPENDED the same as 1315 // DISCONNECTED. The only difference being we are 1316 // broadcasting an intent with NetworkInfo that's 1317 // suspended. This allows the applications an 1318 // opportunity to handle DISCONNECTED and SUSPENDED 1319 // differently, or not. 1320 handleDisconnect(info); 1321 } else if (state == NetworkInfo.State.CONNECTED) { 1322 handleConnect(info); 1323 } 1324 break; 1325 1326 case NetworkStateTracker.EVENT_SCAN_RESULTS_AVAILABLE: 1327 info = (NetworkInfo) msg.obj; 1328 handleScanResultsAvailable(info); 1329 break; 1330 1331 case NetworkStateTracker.EVENT_NOTIFICATION_CHANGED: 1332 handleNotificationChange(msg.arg1 == 1, msg.arg2, 1333 (Notification) msg.obj); 1334 1335 case NetworkStateTracker.EVENT_CONFIGURATION_CHANGED: 1336 handleDnsConfigurationChange(); 1337 break; 1338 1339 case NetworkStateTracker.EVENT_ROAMING_CHANGED: 1340 // fill me in 1341 break; 1342 1343 case NetworkStateTracker.EVENT_NETWORK_SUBTYPE_CHANGED: 1344 // fill me in 1345 break; 1346 case NetworkStateTracker.EVENT_RESTORE_DEFAULT_NETWORK: 1347 FeatureUser u = (FeatureUser)msg.obj; 1348 u.expire(); 1349 break; 1350 } 1351 } 1352 } 1353} 1354