ConnectivityService.java revision 8dcc28be065bb5997ed97d58c9592324b891023a
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.Slog; 43 44import com.android.internal.telephony.Phone; 45 46import com.android.server.connectivity.Tethering; 47 48import java.io.FileDescriptor; 49import java.io.PrintWriter; 50import java.util.ArrayList; 51import java.util.GregorianCalendar; 52import java.util.List; 53 54/** 55 * @hide 56 */ 57public class ConnectivityService extends IConnectivityManager.Stub { 58 59 private static final boolean DBG = true; 60 private static final String TAG = "ConnectivityService"; 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 private Tethering mTethering; 70 private boolean mTetheringConfigValid = false; 71 72 /** 73 * Sometimes we want to refer to the individual network state 74 * trackers separately, and sometimes we just want to treat them 75 * abstractly. 76 */ 77 private NetworkStateTracker mNetTrackers[]; 78 79 /** 80 * A per Net list of the PID's that requested access to the net 81 * used both as a refcount and for per-PID DNS selection 82 */ 83 private List mNetRequestersPids[]; 84 85 // priority order of the nettrackers 86 // (excluding dynamically set mNetworkPreference) 87 // TODO - move mNetworkTypePreference into this 88 private int[] mPriorityList; 89 90 private Context mContext; 91 private int mNetworkPreference; 92 private int mActiveDefaultNetwork = -1; 93 // 0 is full bad, 100 is full good 94 private int mDefaultInetCondition = 0; 95 private int mDefaultInetConditionPublished = 0; 96 private boolean mInetConditionChangeInFlight = false; 97 private int mDefaultConnectionSequence = 0; 98 99 private int mNumDnsEntries; 100 101 private boolean mTestMode; 102 private static ConnectivityService sServiceInstance; 103 104 private static final int ENABLED = 1; 105 private static final int DISABLED = 0; 106 107 // Share the event space with NetworkStateTracker (which can't see this 108 // internal class but sends us events). If you change these, change 109 // NetworkStateTracker.java too. 110 private static final int MIN_NETWORK_STATE_TRACKER_EVENT = 1; 111 private static final int MAX_NETWORK_STATE_TRACKER_EVENT = 100; 112 113 /** 114 * used internally as a delayed event to make us switch back to the 115 * default network 116 */ 117 private static final int EVENT_RESTORE_DEFAULT_NETWORK = 118 MAX_NETWORK_STATE_TRACKER_EVENT + 1; 119 120 /** 121 * used internally to change our mobile data enabled flag 122 */ 123 private static final int EVENT_CHANGE_MOBILE_DATA_ENABLED = 124 MAX_NETWORK_STATE_TRACKER_EVENT + 2; 125 126 /** 127 * used internally to change our network preference setting 128 * arg1 = networkType to prefer 129 */ 130 private static final int EVENT_SET_NETWORK_PREFERENCE = 131 MAX_NETWORK_STATE_TRACKER_EVENT + 3; 132 133 /** 134 * used internally to synchronize inet condition reports 135 * arg1 = networkType 136 * arg2 = condition (0 bad, 100 good) 137 */ 138 private static final int EVENT_INET_CONDITION_CHANGE = 139 MAX_NETWORK_STATE_TRACKER_EVENT + 4; 140 141 /** 142 * used internally to mark the end of inet condition hold periods 143 * arg1 = networkType 144 */ 145 private static final int EVENT_INET_CONDITION_HOLD_END = 146 MAX_NETWORK_STATE_TRACKER_EVENT + 5; 147 148 /** 149 * used internally to set the background data preference 150 * arg1 = TRUE for enabled, FALSE for disabled 151 */ 152 private static final int EVENT_SET_BACKGROUND_DATA = 153 MAX_NETWORK_STATE_TRACKER_EVENT + 6; 154 155 /** 156 * used internally to set enable/disable cellular data 157 * arg1 = ENBALED or DISABLED 158 */ 159 private static final int EVENT_SET_MOBILE_DATA = 160 MAX_NETWORK_STATE_TRACKER_EVENT + 7; 161 162 private Handler mHandler; 163 164 // list of DeathRecipients used to make sure features are turned off when 165 // a process dies 166 private List mFeatureUsers; 167 168 private boolean mSystemReady; 169 private Intent mInitialBroadcast; 170 171 // used in DBG mode to track inet condition reports 172 private static final int INET_CONDITION_LOG_MAX_SIZE = 15; 173 private ArrayList mInetLog; 174 175 private static class NetworkAttributes { 176 /** 177 * Class for holding settings read from resources. 178 */ 179 public String mName; 180 public int mType; 181 public int mRadio; 182 public int mPriority; 183 public NetworkInfo.State mLastState; 184 public NetworkAttributes(String init) { 185 String fragments[] = init.split(","); 186 mName = fragments[0].toLowerCase(); 187 mType = Integer.parseInt(fragments[1]); 188 mRadio = Integer.parseInt(fragments[2]); 189 mPriority = Integer.parseInt(fragments[3]); 190 mLastState = NetworkInfo.State.UNKNOWN; 191 } 192 public boolean isDefault() { 193 return (mType == mRadio); 194 } 195 } 196 NetworkAttributes[] mNetAttributes; 197 int mNetworksDefined; 198 199 private static class RadioAttributes { 200 public int mSimultaneity; 201 public int mType; 202 public RadioAttributes(String init) { 203 String fragments[] = init.split(","); 204 mType = Integer.parseInt(fragments[0]); 205 mSimultaneity = Integer.parseInt(fragments[1]); 206 } 207 } 208 RadioAttributes[] mRadioAttributes; 209 210 private static class ConnectivityThread extends Thread { 211 private Context mContext; 212 213 private ConnectivityThread(Context context) { 214 super("ConnectivityThread"); 215 mContext = context; 216 } 217 218 @Override 219 public void run() { 220 Looper.prepare(); 221 synchronized (this) { 222 sServiceInstance = new ConnectivityService(mContext); 223 notifyAll(); 224 } 225 Looper.loop(); 226 } 227 228 public static ConnectivityService getServiceInstance(Context context) { 229 ConnectivityThread thread = new ConnectivityThread(context); 230 thread.start(); 231 232 synchronized (thread) { 233 while (sServiceInstance == null) { 234 try { 235 // Wait until sServiceInstance has been initialized. 236 thread.wait(); 237 } catch (InterruptedException ignore) { 238 Slog.e(TAG, 239 "Unexpected InterruptedException while waiting"+ 240 " for ConnectivityService thread"); 241 } 242 } 243 } 244 245 return sServiceInstance; 246 } 247 } 248 249 public static ConnectivityService getInstance(Context context) { 250 return ConnectivityThread.getServiceInstance(context); 251 } 252 253 private ConnectivityService(Context context) { 254 if (DBG) Slog.v(TAG, "ConnectivityService starting up"); 255 256 // setup our unique device name 257 String id = Settings.Secure.getString(context.getContentResolver(), 258 Settings.Secure.ANDROID_ID); 259 if (id != null && id.length() > 0) { 260 String name = new String("android_").concat(id); 261 SystemProperties.set("net.hostname", name); 262 } 263 264 mContext = context; 265 mNetTrackers = new NetworkStateTracker[ 266 ConnectivityManager.MAX_NETWORK_TYPE+1]; 267 mHandler = new MyHandler(); 268 269 mNetworkPreference = getPersistedNetworkPreference(); 270 271 mRadioAttributes = new RadioAttributes[ConnectivityManager.MAX_RADIO_TYPE+1]; 272 mNetAttributes = new NetworkAttributes[ConnectivityManager.MAX_NETWORK_TYPE+1]; 273 274 // Load device network attributes from resources 275 String[] raStrings = context.getResources().getStringArray( 276 com.android.internal.R.array.radioAttributes); 277 for (String raString : raStrings) { 278 RadioAttributes r = new RadioAttributes(raString); 279 if (r.mType > ConnectivityManager.MAX_RADIO_TYPE) { 280 Slog.e(TAG, "Error in radioAttributes - ignoring attempt to define type " + r.mType); 281 continue; 282 } 283 if (mRadioAttributes[r.mType] != null) { 284 Slog.e(TAG, "Error in radioAttributes - ignoring attempt to redefine type " + 285 r.mType); 286 continue; 287 } 288 mRadioAttributes[r.mType] = r; 289 } 290 291 String[] naStrings = context.getResources().getStringArray( 292 com.android.internal.R.array.networkAttributes); 293 for (String naString : naStrings) { 294 try { 295 NetworkAttributes n = new NetworkAttributes(naString); 296 if (n.mType > ConnectivityManager.MAX_NETWORK_TYPE) { 297 Slog.e(TAG, "Error in networkAttributes - ignoring attempt to define type " + 298 n.mType); 299 continue; 300 } 301 if (mNetAttributes[n.mType] != null) { 302 Slog.e(TAG, "Error in networkAttributes - ignoring attempt to redefine type " + 303 n.mType); 304 continue; 305 } 306 if (mRadioAttributes[n.mRadio] == null) { 307 Slog.e(TAG, "Error in networkAttributes - ignoring attempt to use undefined " + 308 "radio " + n.mRadio + " in network type " + n.mType); 309 continue; 310 } 311 mNetAttributes[n.mType] = n; 312 mNetworksDefined++; 313 } catch(Exception e) { 314 // ignore it - leave the entry null 315 } 316 } 317 318 // high priority first 319 mPriorityList = new int[mNetworksDefined]; 320 { 321 int insertionPoint = mNetworksDefined-1; 322 int currentLowest = 0; 323 int nextLowest = 0; 324 while (insertionPoint > -1) { 325 for (NetworkAttributes na : mNetAttributes) { 326 if (na == null) continue; 327 if (na.mPriority < currentLowest) continue; 328 if (na.mPriority > currentLowest) { 329 if (na.mPriority < nextLowest || nextLowest == 0) { 330 nextLowest = na.mPriority; 331 } 332 continue; 333 } 334 mPriorityList[insertionPoint--] = na.mType; 335 } 336 currentLowest = nextLowest; 337 nextLowest = 0; 338 } 339 } 340 341 mNetRequestersPids = new ArrayList[ConnectivityManager.MAX_NETWORK_TYPE+1]; 342 for (int i : mPriorityList) { 343 mNetRequestersPids[i] = new ArrayList(); 344 } 345 346 mFeatureUsers = new ArrayList(); 347 348 mNumDnsEntries = 0; 349 350 mTestMode = SystemProperties.get("cm.test.mode").equals("true") 351 && SystemProperties.get("ro.build.type").equals("eng"); 352 /* 353 * Create the network state trackers for Wi-Fi and mobile 354 * data. Maybe this could be done with a factory class, 355 * but it's not clear that it's worth it, given that 356 * the number of different network types is not going 357 * to change very often. 358 */ 359 boolean noMobileData = !getMobileDataEnabled(); 360 for (int netType : mPriorityList) { 361 switch (mNetAttributes[netType].mRadio) { 362 case ConnectivityManager.TYPE_WIFI: 363 if (DBG) Slog.v(TAG, "Starting Wifi Service."); 364 WifiStateTracker wst = new WifiStateTracker(context, mHandler); 365 WifiService wifiService = new WifiService(context, wst); 366 ServiceManager.addService(Context.WIFI_SERVICE, wifiService); 367 wifiService.startWifi(); 368 mNetTrackers[ConnectivityManager.TYPE_WIFI] = wst; 369 wst.startMonitoring(); 370 371 break; 372 case ConnectivityManager.TYPE_MOBILE: 373 mNetTrackers[netType] = new MobileDataStateTracker(context, mHandler, 374 netType, mNetAttributes[netType].mName); 375 mNetTrackers[netType].startMonitoring(); 376 if (noMobileData) { 377 if (DBG) Slog.d(TAG, "tearing down Mobile networks due to setting"); 378 mNetTrackers[netType].teardown(); 379 } 380 break; 381 default: 382 Slog.e(TAG, "Trying to create a DataStateTracker for an unknown radio type " + 383 mNetAttributes[netType].mRadio); 384 continue; 385 } 386 } 387 388 mTethering = new Tethering(mContext, mHandler.getLooper()); 389 mTetheringConfigValid = (((mNetTrackers[ConnectivityManager.TYPE_MOBILE_DUN] != null) || 390 !mTethering.isDunRequired()) && 391 (mTethering.getTetherableUsbRegexs().length != 0 || 392 mTethering.getTetherableWifiRegexs().length != 0) && 393 mTethering.getUpstreamIfaceRegexs().length != 0); 394 395 if (DBG) { 396 mInetLog = new ArrayList(); 397 } 398 } 399 400 401 /** 402 * Sets the preferred network. 403 * @param preference the new preference 404 */ 405 public void setNetworkPreference(int preference) { 406 enforceChangePermission(); 407 408 mHandler.sendMessage(mHandler.obtainMessage(EVENT_SET_NETWORK_PREFERENCE, preference, 0)); 409 } 410 411 public int getNetworkPreference() { 412 enforceAccessPermission(); 413 int preference; 414 synchronized(this) { 415 preference = mNetworkPreference; 416 } 417 return preference; 418 } 419 420 private void handleSetNetworkPreference(int preference) { 421 if (ConnectivityManager.isNetworkTypeValid(preference) && 422 mNetAttributes[preference] != null && 423 mNetAttributes[preference].isDefault()) { 424 if (mNetworkPreference != preference) { 425 final ContentResolver cr = mContext.getContentResolver(); 426 Settings.Secure.putInt(cr, Settings.Secure.NETWORK_PREFERENCE, preference); 427 synchronized(this) { 428 mNetworkPreference = preference; 429 } 430 enforcePreference(); 431 } 432 } 433 } 434 435 private int getPersistedNetworkPreference() { 436 final ContentResolver cr = mContext.getContentResolver(); 437 438 final int networkPrefSetting = Settings.Secure 439 .getInt(cr, Settings.Secure.NETWORK_PREFERENCE, -1); 440 if (networkPrefSetting != -1) { 441 return networkPrefSetting; 442 } 443 444 return ConnectivityManager.DEFAULT_NETWORK_PREFERENCE; 445 } 446 447 /** 448 * Make the state of network connectivity conform to the preference settings 449 * In this method, we only tear down a non-preferred network. Establishing 450 * a connection to the preferred network is taken care of when we handle 451 * the disconnect event from the non-preferred network 452 * (see {@link #handleDisconnect(NetworkInfo)}). 453 */ 454 private void enforcePreference() { 455 if (mNetTrackers[mNetworkPreference].getNetworkInfo().isConnected()) 456 return; 457 458 if (!mNetTrackers[mNetworkPreference].isAvailable()) 459 return; 460 461 for (int t=0; t <= ConnectivityManager.MAX_RADIO_TYPE; t++) { 462 if (t != mNetworkPreference && mNetTrackers[t] != null && 463 mNetTrackers[t].getNetworkInfo().isConnected()) { 464 if (DBG) { 465 Slog.d(TAG, "tearing down " + 466 mNetTrackers[t].getNetworkInfo() + 467 " in enforcePreference"); 468 } 469 teardown(mNetTrackers[t]); 470 } 471 } 472 } 473 474 private boolean teardown(NetworkStateTracker netTracker) { 475 if (netTracker.teardown()) { 476 netTracker.setTeardownRequested(true); 477 return true; 478 } else { 479 return false; 480 } 481 } 482 483 /** 484 * Return NetworkInfo for the active (i.e., connected) network interface. 485 * It is assumed that at most one network is active at a time. If more 486 * than one is active, it is indeterminate which will be returned. 487 * @return the info for the active network, or {@code null} if none is 488 * active 489 */ 490 public NetworkInfo getActiveNetworkInfo() { 491 enforceAccessPermission(); 492 for (int type=0; type <= ConnectivityManager.MAX_NETWORK_TYPE; type++) { 493 if (mNetAttributes[type] == null || !mNetAttributes[type].isDefault()) { 494 continue; 495 } 496 NetworkStateTracker t = mNetTrackers[type]; 497 NetworkInfo info = t.getNetworkInfo(); 498 if (info.isConnected()) { 499 if (DBG && type != mActiveDefaultNetwork) Slog.e(TAG, 500 "connected default network is not " + 501 "mActiveDefaultNetwork!"); 502 return info; 503 } 504 } 505 return null; 506 } 507 508 public NetworkInfo getNetworkInfo(int networkType) { 509 enforceAccessPermission(); 510 if (ConnectivityManager.isNetworkTypeValid(networkType)) { 511 NetworkStateTracker t = mNetTrackers[networkType]; 512 if (t != null) 513 return t.getNetworkInfo(); 514 } 515 return null; 516 } 517 518 public NetworkInfo[] getAllNetworkInfo() { 519 enforceAccessPermission(); 520 NetworkInfo[] result = new NetworkInfo[mNetworksDefined]; 521 int i = 0; 522 for (NetworkStateTracker t : mNetTrackers) { 523 if(t != null) result[i++] = t.getNetworkInfo(); 524 } 525 return result; 526 } 527 528 public boolean setRadios(boolean turnOn) { 529 boolean result = true; 530 enforceChangePermission(); 531 for (NetworkStateTracker t : mNetTrackers) { 532 if (t != null) result = t.setRadio(turnOn) && result; 533 } 534 return result; 535 } 536 537 public boolean setRadio(int netType, boolean turnOn) { 538 enforceChangePermission(); 539 if (!ConnectivityManager.isNetworkTypeValid(netType)) { 540 return false; 541 } 542 NetworkStateTracker tracker = mNetTrackers[netType]; 543 return tracker != null && tracker.setRadio(turnOn); 544 } 545 546 /** 547 * Used to notice when the calling process dies so we can self-expire 548 * 549 * Also used to know if the process has cleaned up after itself when 550 * our auto-expire timer goes off. The timer has a link to an object. 551 * 552 */ 553 private class FeatureUser implements IBinder.DeathRecipient { 554 int mNetworkType; 555 String mFeature; 556 IBinder mBinder; 557 int mPid; 558 int mUid; 559 long mCreateTime; 560 561 FeatureUser(int type, String feature, IBinder binder) { 562 super(); 563 mNetworkType = type; 564 mFeature = feature; 565 mBinder = binder; 566 mPid = getCallingPid(); 567 mUid = getCallingUid(); 568 mCreateTime = System.currentTimeMillis(); 569 570 try { 571 mBinder.linkToDeath(this, 0); 572 } catch (RemoteException e) { 573 binderDied(); 574 } 575 } 576 577 void unlinkDeathRecipient() { 578 mBinder.unlinkToDeath(this, 0); 579 } 580 581 public void binderDied() { 582 Slog.d(TAG, "ConnectivityService FeatureUser binderDied(" + 583 mNetworkType + ", " + mFeature + ", " + mBinder + "), created " + 584 (System.currentTimeMillis() - mCreateTime) + " mSec ago"); 585 stopUsingNetworkFeature(this, false); 586 } 587 588 public void expire() { 589 Slog.d(TAG, "ConnectivityService FeatureUser expire(" + 590 mNetworkType + ", " + mFeature + ", " + mBinder +"), created " + 591 (System.currentTimeMillis() - mCreateTime) + " mSec ago"); 592 stopUsingNetworkFeature(this, false); 593 } 594 595 public String toString() { 596 return "FeatureUser("+mNetworkType+","+mFeature+","+mPid+","+mUid+"), created " + 597 (System.currentTimeMillis() - mCreateTime) + " mSec ago"; 598 } 599 } 600 601 // javadoc from interface 602 public int startUsingNetworkFeature(int networkType, String feature, 603 IBinder binder) { 604 if (DBG) { 605 Slog.d(TAG, "startUsingNetworkFeature for net " + networkType + 606 ": " + feature); 607 } 608 enforceChangePermission(); 609 if (!ConnectivityManager.isNetworkTypeValid(networkType) || 610 mNetAttributes[networkType] == null) { 611 return Phone.APN_REQUEST_FAILED; 612 } 613 614 FeatureUser f = new FeatureUser(networkType, feature, binder); 615 616 // TODO - move this into the MobileDataStateTracker 617 int usedNetworkType = networkType; 618 if(networkType == ConnectivityManager.TYPE_MOBILE) { 619 if (!getMobileDataEnabled()) { 620 if (DBG) Slog.d(TAG, "requested special network with data disabled - rejected"); 621 return Phone.APN_TYPE_NOT_AVAILABLE; 622 } 623 if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_MMS)) { 624 usedNetworkType = ConnectivityManager.TYPE_MOBILE_MMS; 625 } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_SUPL)) { 626 usedNetworkType = ConnectivityManager.TYPE_MOBILE_SUPL; 627 } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_DUN)) { 628 usedNetworkType = ConnectivityManager.TYPE_MOBILE_DUN; 629 } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_HIPRI)) { 630 usedNetworkType = ConnectivityManager.TYPE_MOBILE_HIPRI; 631 } 632 } 633 NetworkStateTracker network = mNetTrackers[usedNetworkType]; 634 if (network != null) { 635 if (usedNetworkType != networkType) { 636 Integer currentPid = new Integer(getCallingPid()); 637 638 NetworkStateTracker radio = mNetTrackers[networkType]; 639 NetworkInfo ni = network.getNetworkInfo(); 640 641 if (ni.isAvailable() == false) { 642 if (DBG) Slog.d(TAG, "special network not available"); 643 return Phone.APN_TYPE_NOT_AVAILABLE; 644 } 645 646 synchronized(this) { 647 mFeatureUsers.add(f); 648 if (!mNetRequestersPids[usedNetworkType].contains(currentPid)) { 649 // this gets used for per-pid dns when connected 650 mNetRequestersPids[usedNetworkType].add(currentPid); 651 } 652 } 653 mHandler.sendMessageDelayed(mHandler.obtainMessage(EVENT_RESTORE_DEFAULT_NETWORK, 654 f), getRestoreDefaultNetworkDelay()); 655 656 657 if ((ni.isConnectedOrConnecting() == true) && 658 !network.isTeardownRequested()) { 659 if (ni.isConnected() == true) { 660 // add the pid-specific dns 661 handleDnsConfigurationChange(networkType); 662 if (DBG) Slog.d(TAG, "special network already active"); 663 return Phone.APN_ALREADY_ACTIVE; 664 } 665 if (DBG) Slog.d(TAG, "special network already connecting"); 666 return Phone.APN_REQUEST_STARTED; 667 } 668 669 // check if the radio in play can make another contact 670 // assume if cannot for now 671 672 if (DBG) Slog.d(TAG, "reconnecting to special network"); 673 network.reconnect(); 674 return Phone.APN_REQUEST_STARTED; 675 } else { 676 synchronized(this) { 677 mFeatureUsers.add(f); 678 } 679 mHandler.sendMessageDelayed(mHandler.obtainMessage(EVENT_RESTORE_DEFAULT_NETWORK, 680 f), getRestoreDefaultNetworkDelay()); 681 682 return network.startUsingNetworkFeature(feature, 683 getCallingPid(), getCallingUid()); 684 } 685 } 686 return Phone.APN_TYPE_NOT_AVAILABLE; 687 } 688 689 // javadoc from interface 690 public int stopUsingNetworkFeature(int networkType, String feature) { 691 enforceChangePermission(); 692 693 int pid = getCallingPid(); 694 int uid = getCallingUid(); 695 696 FeatureUser u = null; 697 boolean found = false; 698 699 synchronized(this) { 700 for (int i = 0; i < mFeatureUsers.size() ; i++) { 701 u = (FeatureUser)mFeatureUsers.get(i); 702 if (uid == u.mUid && pid == u.mPid && 703 networkType == u.mNetworkType && 704 TextUtils.equals(feature, u.mFeature)) { 705 found = true; 706 break; 707 } 708 } 709 } 710 if (found && u != null) { 711 // stop regardless of how many other time this proc had called start 712 return stopUsingNetworkFeature(u, true); 713 } else { 714 // none found! 715 if (DBG) Slog.d(TAG, "ignoring stopUsingNetworkFeature - not a live request"); 716 return 1; 717 } 718 } 719 720 private int stopUsingNetworkFeature(FeatureUser u, boolean ignoreDups) { 721 int networkType = u.mNetworkType; 722 String feature = u.mFeature; 723 int pid = u.mPid; 724 int uid = u.mUid; 725 726 NetworkStateTracker tracker = null; 727 boolean callTeardown = false; // used to carry our decision outside of sync block 728 729 if (DBG) { 730 Slog.d(TAG, "stopUsingNetworkFeature for net " + networkType + 731 ": " + feature); 732 } 733 734 if (!ConnectivityManager.isNetworkTypeValid(networkType)) { 735 return -1; 736 } 737 738 // need to link the mFeatureUsers list with the mNetRequestersPids state in this 739 // sync block 740 synchronized(this) { 741 // check if this process still has an outstanding start request 742 if (!mFeatureUsers.contains(u)) { 743 if (DBG) Slog.d(TAG, "ignoring - this process has no outstanding requests"); 744 return 1; 745 } 746 u.unlinkDeathRecipient(); 747 mFeatureUsers.remove(mFeatureUsers.indexOf(u)); 748 // If we care about duplicate requests, check for that here. 749 // 750 // This is done to support the extension of a request - the app 751 // can request we start the network feature again and renew the 752 // auto-shutoff delay. Normal "stop" calls from the app though 753 // do not pay attention to duplicate requests - in effect the 754 // API does not refcount and a single stop will counter multiple starts. 755 if (ignoreDups == false) { 756 for (int i = 0; i < mFeatureUsers.size() ; i++) { 757 FeatureUser x = (FeatureUser)mFeatureUsers.get(i); 758 if (x.mUid == u.mUid && x.mPid == u.mPid && 759 x.mNetworkType == u.mNetworkType && 760 TextUtils.equals(x.mFeature, u.mFeature)) { 761 if (DBG) Slog.d(TAG, "ignoring stopUsingNetworkFeature as dup is found"); 762 return 1; 763 } 764 } 765 } 766 767 // TODO - move to MobileDataStateTracker 768 int usedNetworkType = networkType; 769 if (networkType == ConnectivityManager.TYPE_MOBILE) { 770 if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_MMS)) { 771 usedNetworkType = ConnectivityManager.TYPE_MOBILE_MMS; 772 } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_SUPL)) { 773 usedNetworkType = ConnectivityManager.TYPE_MOBILE_SUPL; 774 } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_DUN)) { 775 usedNetworkType = ConnectivityManager.TYPE_MOBILE_DUN; 776 } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_HIPRI)) { 777 usedNetworkType = ConnectivityManager.TYPE_MOBILE_HIPRI; 778 } 779 } 780 tracker = mNetTrackers[usedNetworkType]; 781 if (tracker == null) { 782 if (DBG) Slog.d(TAG, "ignoring - no known tracker for net type " + usedNetworkType); 783 return -1; 784 } 785 if (usedNetworkType != networkType) { 786 Integer currentPid = new Integer(pid); 787 mNetRequestersPids[usedNetworkType].remove(currentPid); 788 reassessPidDns(pid, true); 789 if (mNetRequestersPids[usedNetworkType].size() != 0) { 790 if (DBG) Slog.d(TAG, "not tearing down special network - " + 791 "others still using it"); 792 return 1; 793 } 794 callTeardown = true; 795 } 796 } 797 if (DBG) Slog.d(TAG, "Doing network teardown"); 798 if (callTeardown) { 799 tracker.teardown(); 800 return 1; 801 } else { 802 // do it the old fashioned way 803 return tracker.stopUsingNetworkFeature(feature, pid, uid); 804 } 805 } 806 807 /** 808 * Ensure that a network route exists to deliver traffic to the specified 809 * host via the specified network interface. 810 * @param networkType the type of the network over which traffic to the 811 * specified host is to be routed 812 * @param hostAddress the IP address of the host to which the route is 813 * desired 814 * @return {@code true} on success, {@code false} on failure 815 */ 816 public boolean requestRouteToHost(int networkType, int hostAddress) { 817 enforceChangePermission(); 818 if (!ConnectivityManager.isNetworkTypeValid(networkType)) { 819 return false; 820 } 821 NetworkStateTracker tracker = mNetTrackers[networkType]; 822 823 if (tracker == null || !tracker.getNetworkInfo().isConnected() || 824 tracker.isTeardownRequested()) { 825 if (DBG) { 826 Slog.d(TAG, "requestRouteToHost on down network (" + networkType + ") - dropped"); 827 } 828 return false; 829 } 830 return tracker.requestRouteToHost(hostAddress); 831 } 832 833 /** 834 * @see ConnectivityManager#getBackgroundDataSetting() 835 */ 836 public boolean getBackgroundDataSetting() { 837 return Settings.Secure.getInt(mContext.getContentResolver(), 838 Settings.Secure.BACKGROUND_DATA, 1) == 1; 839 } 840 841 /** 842 * @see ConnectivityManager#setBackgroundDataSetting(boolean) 843 */ 844 public void setBackgroundDataSetting(boolean allowBackgroundDataUsage) { 845 mContext.enforceCallingOrSelfPermission( 846 android.Manifest.permission.CHANGE_BACKGROUND_DATA_SETTING, 847 "ConnectivityService"); 848 849 mHandler.sendMessage(mHandler.obtainMessage(EVENT_SET_BACKGROUND_DATA, 850 (allowBackgroundDataUsage ? ENABLED : DISABLED), 0)); 851 } 852 853 private void handleSetBackgroundData(boolean enabled) { 854 if (enabled != getBackgroundDataSetting()) { 855 Settings.Secure.putInt(mContext.getContentResolver(), 856 Settings.Secure.BACKGROUND_DATA, enabled ? 1 : 0); 857 Intent broadcast = new Intent( 858 ConnectivityManager.ACTION_BACKGROUND_DATA_SETTING_CHANGED); 859 mContext.sendBroadcast(broadcast); 860 } 861 } 862 863 /** 864 * @see ConnectivityManager#getMobileDataEnabled() 865 */ 866 public boolean getMobileDataEnabled() { 867 enforceAccessPermission(); 868 boolean retVal = Settings.Secure.getInt(mContext.getContentResolver(), 869 Settings.Secure.MOBILE_DATA, 1) == 1; 870 if (DBG) Slog.d(TAG, "getMobileDataEnabled returning " + retVal); 871 return retVal; 872 } 873 874 /** 875 * @see ConnectivityManager#setMobileDataEnabled(boolean) 876 */ 877 public void setMobileDataEnabled(boolean enabled) { 878 enforceChangePermission(); 879 if (DBG) Slog.d(TAG, "setMobileDataEnabled(" + enabled + ")"); 880 881 mHandler.sendMessage(mHandler.obtainMessage(EVENT_SET_MOBILE_DATA, 882 (enabled ? ENABLED : DISABLED), 0)); 883 } 884 885 private void handleSetMobileData(boolean enabled) { 886 if (getMobileDataEnabled() == enabled) return; 887 888 Settings.Secure.putInt(mContext.getContentResolver(), 889 Settings.Secure.MOBILE_DATA, enabled ? 1 : 0); 890 891 if (enabled) { 892 if (mNetTrackers[ConnectivityManager.TYPE_MOBILE] != null) { 893 if (DBG) { 894 Slog.d(TAG, "starting up " + mNetTrackers[ConnectivityManager.TYPE_MOBILE]); 895 } 896 mNetTrackers[ConnectivityManager.TYPE_MOBILE].reconnect(); 897 } 898 } else { 899 for (NetworkStateTracker nt : mNetTrackers) { 900 if (nt == null) continue; 901 int netType = nt.getNetworkInfo().getType(); 902 if (mNetAttributes[netType].mRadio == ConnectivityManager.TYPE_MOBILE) { 903 if (DBG) Slog.d(TAG, "tearing down " + nt); 904 nt.teardown(); 905 } 906 } 907 } 908 } 909 910 private int getNumConnectedNetworks() { 911 int numConnectedNets = 0; 912 913 for (NetworkStateTracker nt : mNetTrackers) { 914 if (nt != null && nt.getNetworkInfo().isConnected() && 915 !nt.isTeardownRequested()) { 916 ++numConnectedNets; 917 } 918 } 919 return numConnectedNets; 920 } 921 922 private void enforceAccessPermission() { 923 mContext.enforceCallingOrSelfPermission( 924 android.Manifest.permission.ACCESS_NETWORK_STATE, 925 "ConnectivityService"); 926 } 927 928 private void enforceChangePermission() { 929 mContext.enforceCallingOrSelfPermission( 930 android.Manifest.permission.CHANGE_NETWORK_STATE, 931 "ConnectivityService"); 932 } 933 934 // TODO Make this a special check when it goes public 935 private void enforceTetherChangePermission() { 936 mContext.enforceCallingOrSelfPermission( 937 android.Manifest.permission.CHANGE_NETWORK_STATE, 938 "ConnectivityService"); 939 } 940 941 private void enforceTetherAccessPermission() { 942 mContext.enforceCallingOrSelfPermission( 943 android.Manifest.permission.ACCESS_NETWORK_STATE, 944 "ConnectivityService"); 945 } 946 947 /** 948 * Handle a {@code DISCONNECTED} event. If this pertains to the non-active 949 * network, we ignore it. If it is for the active network, we send out a 950 * broadcast. But first, we check whether it might be possible to connect 951 * to a different network. 952 * @param info the {@code NetworkInfo} for the network 953 */ 954 private void handleDisconnect(NetworkInfo info) { 955 956 int prevNetType = info.getType(); 957 958 mNetTrackers[prevNetType].setTeardownRequested(false); 959 /* 960 * If the disconnected network is not the active one, then don't report 961 * this as a loss of connectivity. What probably happened is that we're 962 * getting the disconnect for a network that we explicitly disabled 963 * in accordance with network preference policies. 964 */ 965 if (!mNetAttributes[prevNetType].isDefault()) { 966 List pids = mNetRequestersPids[prevNetType]; 967 for (int i = 0; i<pids.size(); i++) { 968 Integer pid = (Integer)pids.get(i); 969 // will remove them because the net's no longer connected 970 // need to do this now as only now do we know the pids and 971 // can properly null things that are no longer referenced. 972 reassessPidDns(pid.intValue(), false); 973 } 974 } 975 976 Intent intent = new Intent(ConnectivityManager.CONNECTIVITY_ACTION); 977 intent.putExtra(ConnectivityManager.EXTRA_NETWORK_INFO, info); 978 if (info.isFailover()) { 979 intent.putExtra(ConnectivityManager.EXTRA_IS_FAILOVER, true); 980 info.setFailover(false); 981 } 982 if (info.getReason() != null) { 983 intent.putExtra(ConnectivityManager.EXTRA_REASON, info.getReason()); 984 } 985 if (info.getExtraInfo() != null) { 986 intent.putExtra(ConnectivityManager.EXTRA_EXTRA_INFO, 987 info.getExtraInfo()); 988 } 989 990 NetworkStateTracker newNet = null; 991 if (mNetAttributes[prevNetType].isDefault()) { 992 newNet = tryFailover(prevNetType); 993 if (newNet != null) { 994 NetworkInfo switchTo = newNet.getNetworkInfo(); 995 if (!switchTo.isConnected()) { 996 // if the other net is connected they've already reset this and perhaps even gotten 997 // a positive report we don't want to overwrite, but if not we need to clear this now 998 // to turn our cellular sig strength white 999 mDefaultInetConditionPublished = 0; 1000 } 1001 intent.putExtra(ConnectivityManager.EXTRA_OTHER_NETWORK_INFO, switchTo); 1002 } else { 1003 mDefaultInetConditionPublished = 0; // we're not connected anymore 1004 intent.putExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, true); 1005 } 1006 } 1007 intent.putExtra(ConnectivityManager.EXTRA_INET_CONDITION, mDefaultInetConditionPublished); 1008 // do this before we broadcast the change 1009 handleConnectivityChange(prevNetType); 1010 1011 sendStickyBroadcast(intent); 1012 /* 1013 * If the failover network is already connected, then immediately send 1014 * out a followup broadcast indicating successful failover 1015 */ 1016 if (newNet != null && newNet.getNetworkInfo().isConnected()) { 1017 sendConnectedBroadcast(newNet.getNetworkInfo()); 1018 } 1019 } 1020 1021 // returns null if no failover available 1022 private NetworkStateTracker tryFailover(int prevNetType) { 1023 /* 1024 * If this is a default network, check if other defaults are available 1025 * or active 1026 */ 1027 NetworkStateTracker newNet = null; 1028 if (mNetAttributes[prevNetType].isDefault()) { 1029 if (mActiveDefaultNetwork == prevNetType) { 1030 mActiveDefaultNetwork = -1; 1031 } 1032 1033 int newType = -1; 1034 int newPriority = -1; 1035 boolean noMobileData = !getMobileDataEnabled(); 1036 for (int checkType=0; checkType <= ConnectivityManager.MAX_NETWORK_TYPE; checkType++) { 1037 if (checkType == prevNetType) continue; 1038 if (mNetAttributes[checkType] == null) continue; 1039 if (mNetAttributes[checkType].mRadio == ConnectivityManager.TYPE_MOBILE && 1040 noMobileData) { 1041 if (DBG) { 1042 Slog.d(TAG, "not failing over to mobile type " + checkType + 1043 " because Mobile Data Disabled"); 1044 } 1045 continue; 1046 } 1047 if (mNetAttributes[checkType].isDefault()) { 1048 /* TODO - if we have multiple nets we could use 1049 * we may want to put more thought into which we choose 1050 */ 1051 if (checkType == mNetworkPreference) { 1052 newType = checkType; 1053 break; 1054 } 1055 if (mNetAttributes[checkType].mPriority > newPriority) { 1056 newType = checkType; 1057 newPriority = mNetAttributes[newType].mPriority; 1058 } 1059 } 1060 } 1061 1062 if (newType != -1) { 1063 newNet = mNetTrackers[newType]; 1064 /** 1065 * See if the other network is available to fail over to. 1066 * If is not available, we enable it anyway, so that it 1067 * will be able to connect when it does become available, 1068 * but we report a total loss of connectivity rather than 1069 * report that we are attempting to fail over. 1070 */ 1071 if (newNet.isAvailable()) { 1072 NetworkInfo switchTo = newNet.getNetworkInfo(); 1073 switchTo.setFailover(true); 1074 if (!switchTo.isConnectedOrConnecting() || 1075 newNet.isTeardownRequested()) { 1076 newNet.reconnect(); 1077 } 1078 if (DBG) { 1079 if (switchTo.isConnected()) { 1080 Slog.v(TAG, "Switching to already connected " + 1081 switchTo.getTypeName()); 1082 } else { 1083 Slog.v(TAG, "Attempting to switch to " + 1084 switchTo.getTypeName()); 1085 } 1086 } 1087 } else { 1088 newNet.reconnect(); 1089 newNet = null; // not officially avail.. try anyway, but 1090 // report no failover 1091 } 1092 } 1093 } 1094 1095 return newNet; 1096 } 1097 1098 private void sendConnectedBroadcast(NetworkInfo info) { 1099 sendGeneralBroadcast(info, ConnectivityManager.CONNECTIVITY_ACTION); 1100 } 1101 1102 private void sendInetConditionBroadcast(NetworkInfo info) { 1103 sendGeneralBroadcast(info, ConnectivityManager.INET_CONDITION_ACTION); 1104 } 1105 1106 private void sendGeneralBroadcast(NetworkInfo info, String bcastType) { 1107 Intent intent = new Intent(bcastType); 1108 intent.putExtra(ConnectivityManager.EXTRA_NETWORK_INFO, info); 1109 if (info.isFailover()) { 1110 intent.putExtra(ConnectivityManager.EXTRA_IS_FAILOVER, true); 1111 info.setFailover(false); 1112 } 1113 if (info.getReason() != null) { 1114 intent.putExtra(ConnectivityManager.EXTRA_REASON, info.getReason()); 1115 } 1116 if (info.getExtraInfo() != null) { 1117 intent.putExtra(ConnectivityManager.EXTRA_EXTRA_INFO, 1118 info.getExtraInfo()); 1119 } 1120 intent.putExtra(ConnectivityManager.EXTRA_INET_CONDITION, mDefaultInetConditionPublished); 1121 sendStickyBroadcast(intent); 1122 } 1123 1124 /** 1125 * Called when an attempt to fail over to another network has failed. 1126 * @param info the {@link NetworkInfo} for the failed network 1127 */ 1128 private void handleConnectionFailure(NetworkInfo info) { 1129 mNetTrackers[info.getType()].setTeardownRequested(false); 1130 1131 String reason = info.getReason(); 1132 String extraInfo = info.getExtraInfo(); 1133 1134 if (DBG) { 1135 String reasonText; 1136 if (reason == null) { 1137 reasonText = "."; 1138 } else { 1139 reasonText = " (" + reason + ")."; 1140 } 1141 Slog.v(TAG, "Attempt to connect to " + info.getTypeName() + 1142 " failed" + reasonText); 1143 } 1144 1145 Intent intent = new Intent(ConnectivityManager.CONNECTIVITY_ACTION); 1146 intent.putExtra(ConnectivityManager.EXTRA_NETWORK_INFO, info); 1147 if (getActiveNetworkInfo() == null) { 1148 intent.putExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, true); 1149 } 1150 if (reason != null) { 1151 intent.putExtra(ConnectivityManager.EXTRA_REASON, reason); 1152 } 1153 if (extraInfo != null) { 1154 intent.putExtra(ConnectivityManager.EXTRA_EXTRA_INFO, extraInfo); 1155 } 1156 if (info.isFailover()) { 1157 intent.putExtra(ConnectivityManager.EXTRA_IS_FAILOVER, true); 1158 info.setFailover(false); 1159 } 1160 1161 NetworkStateTracker newNet = null; 1162 if (mNetAttributes[info.getType()].isDefault()) { 1163 newNet = tryFailover(info.getType()); 1164 if (newNet != null) { 1165 NetworkInfo switchTo = newNet.getNetworkInfo(); 1166 if (!switchTo.isConnected()) { 1167 // if the other net is connected they've already reset this and perhaps even gotten 1168 // a positive report we don't want to overwrite, but if not we need to clear this now 1169 // to turn our cellular sig strength white 1170 mDefaultInetConditionPublished = 0; 1171 } 1172 intent.putExtra(ConnectivityManager.EXTRA_OTHER_NETWORK_INFO, switchTo); 1173 } else { 1174 mDefaultInetConditionPublished = 0; 1175 intent.putExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, true); 1176 } 1177 } 1178 1179 intent.putExtra(ConnectivityManager.EXTRA_INET_CONDITION, mDefaultInetConditionPublished); 1180 sendStickyBroadcast(intent); 1181 /* 1182 * If the failover network is already connected, then immediately send 1183 * out a followup broadcast indicating successful failover 1184 */ 1185 if (newNet != null && newNet.getNetworkInfo().isConnected()) { 1186 sendConnectedBroadcast(newNet.getNetworkInfo()); 1187 } 1188 } 1189 1190 private void sendStickyBroadcast(Intent intent) { 1191 synchronized(this) { 1192 if (!mSystemReady) { 1193 mInitialBroadcast = new Intent(intent); 1194 } 1195 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 1196 mContext.sendStickyBroadcast(intent); 1197 } 1198 } 1199 1200 void systemReady() { 1201 synchronized(this) { 1202 mSystemReady = true; 1203 if (mInitialBroadcast != null) { 1204 mContext.sendStickyBroadcast(mInitialBroadcast); 1205 mInitialBroadcast = null; 1206 } 1207 } 1208 } 1209 1210 private void handleConnect(NetworkInfo info) { 1211 int type = info.getType(); 1212 1213 // snapshot isFailover, because sendConnectedBroadcast() resets it 1214 boolean isFailover = info.isFailover(); 1215 NetworkStateTracker thisNet = mNetTrackers[type]; 1216 1217 // if this is a default net and other default is running 1218 // kill the one not preferred 1219 if (mNetAttributes[type].isDefault()) { 1220 if (mActiveDefaultNetwork != -1 && mActiveDefaultNetwork != type) { 1221 if ((type != mNetworkPreference && 1222 mNetAttributes[mActiveDefaultNetwork].mPriority > 1223 mNetAttributes[type].mPriority) || 1224 mNetworkPreference == mActiveDefaultNetwork) { 1225 // don't accept this one 1226 if (DBG) Slog.v(TAG, "Not broadcasting CONNECT_ACTION " + 1227 "to torn down network " + info.getTypeName()); 1228 teardown(thisNet); 1229 return; 1230 } else { 1231 // tear down the other 1232 NetworkStateTracker otherNet = 1233 mNetTrackers[mActiveDefaultNetwork]; 1234 if (DBG) Slog.v(TAG, "Policy requires " + 1235 otherNet.getNetworkInfo().getTypeName() + 1236 " teardown"); 1237 if (!teardown(otherNet)) { 1238 Slog.e(TAG, "Network declined teardown request"); 1239 return; 1240 } 1241 if (isFailover) { 1242 otherNet.releaseWakeLock(); 1243 } 1244 } 1245 } 1246 mActiveDefaultNetwork = type; 1247 // this will cause us to come up initially as unconnected and switching 1248 // to connected after our normal pause unless somebody reports us as reall 1249 // disconnected 1250 mDefaultInetConditionPublished = 0; 1251 mDefaultConnectionSequence++; 1252 mInetConditionChangeInFlight = false; 1253 // Don't do this - if we never sign in stay, grey 1254 //reportNetworkCondition(mActiveDefaultNetwork, 100); 1255 } 1256 thisNet.setTeardownRequested(false); 1257 thisNet.updateNetworkSettings(); 1258 handleConnectivityChange(type); 1259 sendConnectedBroadcast(info); 1260 } 1261 1262 private void handleScanResultsAvailable(NetworkInfo info) { 1263 int networkType = info.getType(); 1264 if (networkType != ConnectivityManager.TYPE_WIFI) { 1265 if (DBG) Slog.v(TAG, "Got ScanResultsAvailable for " + 1266 info.getTypeName() + " network. Don't know how to handle."); 1267 } 1268 1269 mNetTrackers[networkType].interpretScanResultsAvailable(); 1270 } 1271 1272 private void handleNotificationChange(boolean visible, int id, 1273 Notification notification) { 1274 NotificationManager notificationManager = (NotificationManager) mContext 1275 .getSystemService(Context.NOTIFICATION_SERVICE); 1276 1277 if (visible) { 1278 notificationManager.notify(id, notification); 1279 } else { 1280 notificationManager.cancel(id); 1281 } 1282 } 1283 1284 /** 1285 * After a change in the connectivity state of any network, We're mainly 1286 * concerned with making sure that the list of DNS servers is setupup 1287 * according to which networks are connected, and ensuring that the 1288 * right routing table entries exist. 1289 */ 1290 private void handleConnectivityChange(int netType) { 1291 /* 1292 * If a non-default network is enabled, add the host routes that 1293 * will allow it's DNS servers to be accessed. 1294 */ 1295 handleDnsConfigurationChange(netType); 1296 1297 if (mNetTrackers[netType].getNetworkInfo().isConnected()) { 1298 if (mNetAttributes[netType].isDefault()) { 1299 mNetTrackers[netType].addDefaultRoute(); 1300 } else { 1301 mNetTrackers[netType].addPrivateDnsRoutes(); 1302 } 1303 } else { 1304 if (mNetAttributes[netType].isDefault()) { 1305 mNetTrackers[netType].removeDefaultRoute(); 1306 } else { 1307 mNetTrackers[netType].removePrivateDnsRoutes(); 1308 } 1309 } 1310 } 1311 1312 /** 1313 * Adjust the per-process dns entries (net.dns<x>.<pid>) based 1314 * on the highest priority active net which this process requested. 1315 * If there aren't any, clear it out 1316 */ 1317 private void reassessPidDns(int myPid, boolean doBump) 1318 { 1319 if (DBG) Slog.d(TAG, "reassessPidDns for pid " + myPid); 1320 for(int i : mPriorityList) { 1321 if (mNetAttributes[i].isDefault()) { 1322 continue; 1323 } 1324 NetworkStateTracker nt = mNetTrackers[i]; 1325 if (nt.getNetworkInfo().isConnected() && 1326 !nt.isTeardownRequested()) { 1327 List pids = mNetRequestersPids[i]; 1328 for (int j=0; j<pids.size(); j++) { 1329 Integer pid = (Integer)pids.get(j); 1330 if (pid.intValue() == myPid) { 1331 String[] dnsList = nt.getNameServers(); 1332 writePidDns(dnsList, myPid); 1333 if (doBump) { 1334 bumpDns(); 1335 } 1336 return; 1337 } 1338 } 1339 } 1340 } 1341 // nothing found - delete 1342 for (int i = 1; ; i++) { 1343 String prop = "net.dns" + i + "." + myPid; 1344 if (SystemProperties.get(prop).length() == 0) { 1345 if (doBump) { 1346 bumpDns(); 1347 } 1348 return; 1349 } 1350 SystemProperties.set(prop, ""); 1351 } 1352 } 1353 1354 private void writePidDns(String[] dnsList, int pid) { 1355 int j = 1; 1356 for (String dns : dnsList) { 1357 if (dns != null && !TextUtils.equals(dns, "0.0.0.0")) { 1358 SystemProperties.set("net.dns" + j++ + "." + pid, dns); 1359 } 1360 } 1361 } 1362 1363 private void bumpDns() { 1364 /* 1365 * Bump the property that tells the name resolver library to reread 1366 * the DNS server list from the properties. 1367 */ 1368 String propVal = SystemProperties.get("net.dnschange"); 1369 int n = 0; 1370 if (propVal.length() != 0) { 1371 try { 1372 n = Integer.parseInt(propVal); 1373 } catch (NumberFormatException e) {} 1374 } 1375 SystemProperties.set("net.dnschange", "" + (n+1)); 1376 } 1377 1378 private void handleDnsConfigurationChange(int netType) { 1379 // add default net's dns entries 1380 NetworkStateTracker nt = mNetTrackers[netType]; 1381 if (nt != null && nt.getNetworkInfo().isConnected() && !nt.isTeardownRequested()) { 1382 String[] dnsList = nt.getNameServers(); 1383 if (mNetAttributes[netType].isDefault()) { 1384 int j = 1; 1385 for (String dns : dnsList) { 1386 if (dns != null && !TextUtils.equals(dns, "0.0.0.0")) { 1387 if (DBG) { 1388 Slog.d(TAG, "adding dns " + dns + " for " + 1389 nt.getNetworkInfo().getTypeName()); 1390 } 1391 SystemProperties.set("net.dns" + j++, dns); 1392 } 1393 } 1394 for (int k=j ; k<mNumDnsEntries; k++) { 1395 if (DBG) Slog.d(TAG, "erasing net.dns" + k); 1396 SystemProperties.set("net.dns" + k, ""); 1397 } 1398 mNumDnsEntries = j; 1399 } else { 1400 // set per-pid dns for attached secondary nets 1401 List pids = mNetRequestersPids[netType]; 1402 for (int y=0; y< pids.size(); y++) { 1403 Integer pid = (Integer)pids.get(y); 1404 writePidDns(dnsList, pid.intValue()); 1405 } 1406 } 1407 } 1408 bumpDns(); 1409 } 1410 1411 private int getRestoreDefaultNetworkDelay() { 1412 String restoreDefaultNetworkDelayStr = SystemProperties.get( 1413 NETWORK_RESTORE_DELAY_PROP_NAME); 1414 if(restoreDefaultNetworkDelayStr != null && 1415 restoreDefaultNetworkDelayStr.length() != 0) { 1416 try { 1417 return Integer.valueOf(restoreDefaultNetworkDelayStr); 1418 } catch (NumberFormatException e) { 1419 } 1420 } 1421 return RESTORE_DEFAULT_NETWORK_DELAY; 1422 } 1423 1424 @Override 1425 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 1426 if (mContext.checkCallingOrSelfPermission( 1427 android.Manifest.permission.DUMP) 1428 != PackageManager.PERMISSION_GRANTED) { 1429 pw.println("Permission Denial: can't dump ConnectivityService " + 1430 "from from pid=" + Binder.getCallingPid() + ", uid=" + 1431 Binder.getCallingUid()); 1432 return; 1433 } 1434 pw.println(); 1435 for (NetworkStateTracker nst : mNetTrackers) { 1436 if (nst != null) { 1437 if (nst.getNetworkInfo().isConnected()) { 1438 pw.println("Active network: " + nst.getNetworkInfo(). 1439 getTypeName()); 1440 } 1441 pw.println(nst.getNetworkInfo()); 1442 pw.println(nst); 1443 pw.println(); 1444 } 1445 } 1446 1447 pw.println("Network Requester Pids:"); 1448 for (int net : mPriorityList) { 1449 String pidString = net + ": "; 1450 for (Object pid : mNetRequestersPids[net]) { 1451 pidString = pidString + pid.toString() + ", "; 1452 } 1453 pw.println(pidString); 1454 } 1455 pw.println(); 1456 1457 pw.println("FeatureUsers:"); 1458 for (Object requester : mFeatureUsers) { 1459 pw.println(requester.toString()); 1460 } 1461 pw.println(); 1462 1463 mTethering.dump(fd, pw, args); 1464 1465 if (mInetLog != null) { 1466 pw.println(); 1467 pw.println("Inet condition reports:"); 1468 for(int i = 0; i < mInetLog.size(); i++) { 1469 pw.println(mInetLog.get(i)); 1470 } 1471 } 1472 } 1473 1474 // must be stateless - things change under us. 1475 private class MyHandler extends Handler { 1476 @Override 1477 public void handleMessage(Message msg) { 1478 NetworkInfo info; 1479 switch (msg.what) { 1480 case NetworkStateTracker.EVENT_STATE_CHANGED: 1481 info = (NetworkInfo) msg.obj; 1482 int type = info.getType(); 1483 NetworkInfo.State state = info.getState(); 1484 // only do this optimization for wifi. It going into scan mode for location 1485 // services generates alot of noise. Meanwhile the mms apn won't send out 1486 // subsequent notifications when on default cellular because it never 1487 // disconnects.. so only do this to wifi notifications. Fixed better when the 1488 // APN notifications are standardized. 1489 if (mNetAttributes[type].mLastState == state && 1490 mNetAttributes[type].mRadio == ConnectivityManager.TYPE_WIFI) { 1491 if (DBG) { 1492 // TODO - remove this after we validate the dropping doesn't break 1493 // anything 1494 Slog.d(TAG, "Dropping ConnectivityChange for " + 1495 info.getTypeName() + ": " + 1496 state + "/" + info.getDetailedState()); 1497 } 1498 return; 1499 } 1500 mNetAttributes[type].mLastState = state; 1501 1502 if (DBG) Slog.d(TAG, "ConnectivityChange for " + 1503 info.getTypeName() + ": " + 1504 state + "/" + info.getDetailedState()); 1505 1506 // Connectivity state changed: 1507 // [31-13] Reserved for future use 1508 // [12-9] Network subtype (for mobile network, as defined 1509 // by TelephonyManager) 1510 // [8-3] Detailed state ordinal (as defined by 1511 // NetworkInfo.DetailedState) 1512 // [2-0] Network type (as defined by ConnectivityManager) 1513 int eventLogParam = (info.getType() & 0x7) | 1514 ((info.getDetailedState().ordinal() & 0x3f) << 3) | 1515 (info.getSubtype() << 9); 1516 EventLog.writeEvent(EventLogTags.CONNECTIVITY_STATE_CHANGED, 1517 eventLogParam); 1518 1519 if (info.getDetailedState() == 1520 NetworkInfo.DetailedState.FAILED) { 1521 handleConnectionFailure(info); 1522 } else if (state == NetworkInfo.State.DISCONNECTED) { 1523 handleDisconnect(info); 1524 } else if (state == NetworkInfo.State.SUSPENDED) { 1525 // TODO: need to think this over. 1526 // the logic here is, handle SUSPENDED the same as 1527 // DISCONNECTED. The only difference being we are 1528 // broadcasting an intent with NetworkInfo that's 1529 // suspended. This allows the applications an 1530 // opportunity to handle DISCONNECTED and SUSPENDED 1531 // differently, or not. 1532 handleDisconnect(info); 1533 } else if (state == NetworkInfo.State.CONNECTED) { 1534 handleConnect(info); 1535 } 1536 break; 1537 1538 case NetworkStateTracker.EVENT_SCAN_RESULTS_AVAILABLE: 1539 info = (NetworkInfo) msg.obj; 1540 handleScanResultsAvailable(info); 1541 break; 1542 1543 case NetworkStateTracker.EVENT_NOTIFICATION_CHANGED: 1544 handleNotificationChange(msg.arg1 == 1, msg.arg2, 1545 (Notification) msg.obj); 1546 break; 1547 1548 case NetworkStateTracker.EVENT_CONFIGURATION_CHANGED: 1549 info = (NetworkInfo) msg.obj; 1550 type = info.getType(); 1551 handleDnsConfigurationChange(type); 1552 break; 1553 1554 case NetworkStateTracker.EVENT_ROAMING_CHANGED: 1555 // fill me in 1556 break; 1557 1558 case NetworkStateTracker.EVENT_NETWORK_SUBTYPE_CHANGED: 1559 // fill me in 1560 break; 1561 case EVENT_RESTORE_DEFAULT_NETWORK: 1562 FeatureUser u = (FeatureUser)msg.obj; 1563 u.expire(); 1564 break; 1565 case EVENT_INET_CONDITION_CHANGE: 1566 { 1567 int netType = msg.arg1; 1568 int condition = msg.arg2; 1569 handleInetConditionChange(netType, condition); 1570 break; 1571 } 1572 case EVENT_INET_CONDITION_HOLD_END: 1573 { 1574 int netType = msg.arg1; 1575 int sequence = msg.arg2; 1576 handleInetConditionHoldEnd(netType, sequence); 1577 break; 1578 } 1579 case EVENT_SET_NETWORK_PREFERENCE: 1580 { 1581 int preference = msg.arg1; 1582 handleSetNetworkPreference(preference); 1583 break; 1584 } 1585 case EVENT_SET_BACKGROUND_DATA: 1586 { 1587 boolean enabled = (msg.arg1 == ENABLED); 1588 handleSetBackgroundData(enabled); 1589 break; 1590 } 1591 case EVENT_SET_MOBILE_DATA: 1592 { 1593 boolean enabled = (msg.arg1 == ENABLED); 1594 handleSetMobileData(enabled); 1595 break; 1596 } 1597 } 1598 } 1599 } 1600 1601 // javadoc from interface 1602 public int tether(String iface) { 1603 enforceTetherChangePermission(); 1604 1605 if (isTetheringSupported()) { 1606 return mTethering.tether(iface); 1607 } else { 1608 return ConnectivityManager.TETHER_ERROR_UNSUPPORTED; 1609 } 1610 } 1611 1612 // javadoc from interface 1613 public int untether(String iface) { 1614 enforceTetherChangePermission(); 1615 1616 if (isTetheringSupported()) { 1617 return mTethering.untether(iface); 1618 } else { 1619 return ConnectivityManager.TETHER_ERROR_UNSUPPORTED; 1620 } 1621 } 1622 1623 // javadoc from interface 1624 public int getLastTetherError(String iface) { 1625 enforceTetherAccessPermission(); 1626 1627 if (isTetheringSupported()) { 1628 return mTethering.getLastTetherError(iface); 1629 } else { 1630 return ConnectivityManager.TETHER_ERROR_UNSUPPORTED; 1631 } 1632 } 1633 1634 // TODO - proper iface API for selection by property, inspection, etc 1635 public String[] getTetherableUsbRegexs() { 1636 enforceTetherAccessPermission(); 1637 if (isTetheringSupported()) { 1638 return mTethering.getTetherableUsbRegexs(); 1639 } else { 1640 return new String[0]; 1641 } 1642 } 1643 1644 public String[] getTetherableWifiRegexs() { 1645 enforceTetherAccessPermission(); 1646 if (isTetheringSupported()) { 1647 return mTethering.getTetherableWifiRegexs(); 1648 } else { 1649 return new String[0]; 1650 } 1651 } 1652 1653 // TODO - move iface listing, queries, etc to new module 1654 // javadoc from interface 1655 public String[] getTetherableIfaces() { 1656 enforceTetherAccessPermission(); 1657 return mTethering.getTetherableIfaces(); 1658 } 1659 1660 public String[] getTetheredIfaces() { 1661 enforceTetherAccessPermission(); 1662 return mTethering.getTetheredIfaces(); 1663 } 1664 1665 public String[] getTetheringErroredIfaces() { 1666 enforceTetherAccessPermission(); 1667 return mTethering.getErroredIfaces(); 1668 } 1669 1670 // if ro.tether.denied = true we default to no tethering 1671 // gservices could set the secure setting to 1 though to enable it on a build where it 1672 // had previously been turned off. 1673 public boolean isTetheringSupported() { 1674 enforceTetherAccessPermission(); 1675 int defaultVal = (SystemProperties.get("ro.tether.denied").equals("true") ? 0 : 1); 1676 boolean tetherEnabledInSettings = (Settings.Secure.getInt(mContext.getContentResolver(), 1677 Settings.Secure.TETHER_SUPPORTED, defaultVal) != 0); 1678 return tetherEnabledInSettings && mTetheringConfigValid; 1679 } 1680 1681 // 100 percent is full good, 0 is full bad. 1682 public void reportInetCondition(int networkType, int percentage) { 1683 if (DBG) Slog.d(TAG, "reportNetworkCondition(" + networkType + ", " + percentage + ")"); 1684 mContext.enforceCallingOrSelfPermission( 1685 android.Manifest.permission.STATUS_BAR, 1686 "ConnectivityService"); 1687 1688 if (DBG) { 1689 int pid = getCallingPid(); 1690 int uid = getCallingUid(); 1691 String s = pid + "(" + uid + ") reports inet is " + 1692 (percentage > 50 ? "connected" : "disconnected") + " (" + percentage + ") on " + 1693 "network Type " + networkType + " at " + GregorianCalendar.getInstance().getTime(); 1694 mInetLog.add(s); 1695 while(mInetLog.size() > INET_CONDITION_LOG_MAX_SIZE) { 1696 mInetLog.remove(0); 1697 } 1698 } 1699 mHandler.sendMessage(mHandler.obtainMessage( 1700 EVENT_INET_CONDITION_CHANGE, networkType, percentage)); 1701 } 1702 1703 private void handleInetConditionChange(int netType, int condition) { 1704 if (DBG) { 1705 Slog.d(TAG, "Inet connectivity change, net=" + 1706 netType + ", condition=" + condition + 1707 ",mActiveDefaultNetwork=" + mActiveDefaultNetwork); 1708 } 1709 if (mActiveDefaultNetwork == -1) { 1710 if (DBG) Slog.d(TAG, "no active default network - aborting"); 1711 return; 1712 } 1713 if (mActiveDefaultNetwork != netType) { 1714 if (DBG) Slog.d(TAG, "given net not default - aborting"); 1715 return; 1716 } 1717 mDefaultInetCondition = condition; 1718 int delay; 1719 if (mInetConditionChangeInFlight == false) { 1720 if (DBG) Slog.d(TAG, "starting a change hold"); 1721 // setup a new hold to debounce this 1722 if (mDefaultInetCondition > 50) { 1723 delay = Settings.Secure.getInt(mContext.getContentResolver(), 1724 Settings.Secure.INET_CONDITION_DEBOUNCE_UP_DELAY, 500); 1725 } else { 1726 delay = Settings.Secure.getInt(mContext.getContentResolver(), 1727 Settings.Secure.INET_CONDITION_DEBOUNCE_DOWN_DELAY, 3000); 1728 } 1729 mInetConditionChangeInFlight = true; 1730 mHandler.sendMessageDelayed(mHandler.obtainMessage(EVENT_INET_CONDITION_HOLD_END, 1731 mActiveDefaultNetwork, mDefaultConnectionSequence), delay); 1732 } else { 1733 // we've set the new condition, when this hold ends that will get 1734 // picked up 1735 if (DBG) Slog.d(TAG, "currently in hold - not setting new end evt"); 1736 } 1737 } 1738 1739 private void handleInetConditionHoldEnd(int netType, int sequence) { 1740 if (DBG) { 1741 Slog.d(TAG, "Inet hold end, net=" + netType + 1742 ", condition =" + mDefaultInetCondition + 1743 ", published condition =" + mDefaultInetConditionPublished); 1744 } 1745 mInetConditionChangeInFlight = false; 1746 1747 if (mActiveDefaultNetwork == -1) { 1748 if (DBG) Slog.d(TAG, "no active default network - aborting"); 1749 return; 1750 } 1751 if (mDefaultConnectionSequence != sequence) { 1752 if (DBG) Slog.d(TAG, "event hold for obsolete network - aborting"); 1753 return; 1754 } 1755 if (mDefaultInetConditionPublished == mDefaultInetCondition) { 1756 if (DBG) Slog.d(TAG, "no change in condition - aborting"); 1757 return; 1758 } 1759 NetworkInfo networkInfo = mNetTrackers[mActiveDefaultNetwork].getNetworkInfo(); 1760 if (networkInfo.isConnected() == false) { 1761 if (DBG) Slog.d(TAG, "default network not connected - aborting"); 1762 return; 1763 } 1764 mDefaultInetConditionPublished = mDefaultInetCondition; 1765 sendInetConditionBroadcast(networkInfo); 1766 return; 1767 } 1768} 1769