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