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