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