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