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