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