ConnectivityService.java revision 6b818de29a5c273aad99eb3f5456f88169c911f4
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.bluetooth.BluetoothTetheringDataTracker; 20import android.content.ContentResolver; 21import android.content.Context; 22import android.content.Intent; 23import android.content.pm.PackageManager; 24import android.database.ContentObserver; 25import android.net.ConnectivityManager; 26import android.net.DummyDataStateTracker; 27import android.net.IConnectivityManager; 28import android.net.LinkProperties; 29import android.net.MobileDataStateTracker; 30import android.net.NetworkInfo; 31import android.net.NetworkStateTracker; 32import android.net.NetworkUtils; 33import android.net.Proxy; 34import android.net.ProxyProperties; 35import android.net.vpn.VpnManager; 36import android.net.wifi.WifiStateTracker; 37import android.os.Binder; 38import android.os.Handler; 39import android.os.HandlerThread; 40import android.os.IBinder; 41import android.os.Looper; 42import android.os.Message; 43import android.os.PowerManager; 44import android.os.RemoteException; 45import android.os.ServiceManager; 46import android.os.SystemProperties; 47import android.provider.Settings; 48import android.text.TextUtils; 49import android.util.EventLog; 50import android.util.Slog; 51 52import com.android.internal.telephony.Phone; 53import com.android.server.connectivity.Tethering; 54 55import java.io.FileDescriptor; 56import java.io.FileWriter; 57import java.io.IOException; 58import java.io.PrintWriter; 59import java.net.InetAddress; 60import java.net.UnknownHostException; 61import java.util.ArrayList; 62import java.util.Collection; 63import java.util.concurrent.atomic.AtomicBoolean; 64import java.util.GregorianCalendar; 65import java.util.List; 66 67/** 68 * @hide 69 */ 70public class ConnectivityService extends IConnectivityManager.Stub { 71 72 private static final boolean DBG = true; 73 private static final String TAG = "ConnectivityService"; 74 75 // how long to wait before switching back to a radio's default network 76 private static final int RESTORE_DEFAULT_NETWORK_DELAY = 1 * 60 * 1000; 77 // system property that can override the above value 78 private static final String NETWORK_RESTORE_DELAY_PROP_NAME = 79 "android.telephony.apn-restore"; 80 81 private Tethering mTethering; 82 private boolean mTetheringConfigValid = false; 83 84 /** 85 * Sometimes we want to refer to the individual network state 86 * trackers separately, and sometimes we just want to treat them 87 * abstractly. 88 */ 89 private NetworkStateTracker mNetTrackers[]; 90 91 /** 92 * A per Net list of the PID's that requested access to the net 93 * used both as a refcount and for per-PID DNS selection 94 */ 95 private List mNetRequestersPids[]; 96 97 private WifiWatchdogService mWifiWatchdogService; 98 99 // priority order of the nettrackers 100 // (excluding dynamically set mNetworkPreference) 101 // TODO - move mNetworkTypePreference into this 102 private int[] mPriorityList; 103 104 private Context mContext; 105 private int mNetworkPreference; 106 private int mActiveDefaultNetwork = -1; 107 // 0 is full bad, 100 is full good 108 private int mDefaultInetCondition = 0; 109 private int mDefaultInetConditionPublished = 0; 110 private boolean mInetConditionChangeInFlight = false; 111 private int mDefaultConnectionSequence = 0; 112 113 private int mNumDnsEntries; 114 115 private boolean mTestMode; 116 private static ConnectivityService sServiceInstance; 117 118 private AtomicBoolean mBackgroundDataEnabled = new AtomicBoolean(true); 119 120 private static final int ENABLED = 1; 121 private static final int DISABLED = 0; 122 123 // Share the event space with NetworkStateTracker (which can't see this 124 // internal class but sends us events). If you change these, change 125 // NetworkStateTracker.java too. 126 private static final int MIN_NETWORK_STATE_TRACKER_EVENT = 1; 127 private static final int MAX_NETWORK_STATE_TRACKER_EVENT = 100; 128 129 /** 130 * used internally as a delayed event to make us switch back to the 131 * default network 132 */ 133 private static final int EVENT_RESTORE_DEFAULT_NETWORK = 134 MAX_NETWORK_STATE_TRACKER_EVENT + 1; 135 136 /** 137 * used internally to change our mobile data enabled flag 138 */ 139 private static final int EVENT_CHANGE_MOBILE_DATA_ENABLED = 140 MAX_NETWORK_STATE_TRACKER_EVENT + 2; 141 142 /** 143 * used internally to change our network preference setting 144 * arg1 = networkType to prefer 145 */ 146 private static final int EVENT_SET_NETWORK_PREFERENCE = 147 MAX_NETWORK_STATE_TRACKER_EVENT + 3; 148 149 /** 150 * used internally to synchronize inet condition reports 151 * arg1 = networkType 152 * arg2 = condition (0 bad, 100 good) 153 */ 154 private static final int EVENT_INET_CONDITION_CHANGE = 155 MAX_NETWORK_STATE_TRACKER_EVENT + 4; 156 157 /** 158 * used internally to mark the end of inet condition hold periods 159 * arg1 = networkType 160 */ 161 private static final int EVENT_INET_CONDITION_HOLD_END = 162 MAX_NETWORK_STATE_TRACKER_EVENT + 5; 163 164 /** 165 * used internally to set the background data preference 166 * arg1 = TRUE for enabled, FALSE for disabled 167 */ 168 private static final int EVENT_SET_BACKGROUND_DATA = 169 MAX_NETWORK_STATE_TRACKER_EVENT + 6; 170 171 /** 172 * used internally to set enable/disable cellular data 173 * arg1 = ENBALED or DISABLED 174 */ 175 private static final int EVENT_SET_MOBILE_DATA = 176 MAX_NETWORK_STATE_TRACKER_EVENT + 7; 177 178 /** 179 * used internally to clear a wakelock when transitioning 180 * from one net to another 181 */ 182 private static final int EVENT_CLEAR_NET_TRANSITION_WAKELOCK = 183 MAX_NETWORK_STATE_TRACKER_EVENT + 8; 184 185 /** 186 * used internally to reload global proxy settings 187 */ 188 private static final int EVENT_APPLY_GLOBAL_HTTP_PROXY = 189 MAX_NETWORK_STATE_TRACKER_EVENT + 9; 190 191 private Handler mHandler; 192 193 // list of DeathRecipients used to make sure features are turned off when 194 // a process dies 195 private List mFeatureUsers; 196 197 private boolean mSystemReady; 198 private Intent mInitialBroadcast; 199 200 private PowerManager.WakeLock mNetTransitionWakeLock; 201 private String mNetTransitionWakeLockCausedBy = ""; 202 private int mNetTransitionWakeLockSerialNumber; 203 private int mNetTransitionWakeLockTimeout; 204 205 private InetAddress mDefaultDns; 206 207 // used in DBG mode to track inet condition reports 208 private static final int INET_CONDITION_LOG_MAX_SIZE = 15; 209 private ArrayList mInetLog; 210 211 // track the current default http proxy - tell the world if we get a new one (real change) 212 private ProxyProperties mDefaultProxy = null; 213 // track the global proxy. 214 private ProxyProperties mGlobalProxy = null; 215 private final Object mGlobalProxyLock = new Object(); 216 217 private SettingsObserver mSettingsObserver; 218 219 private static class NetworkAttributes { 220 /** 221 * Class for holding settings read from resources. 222 */ 223 public String mName; 224 public int mType; 225 public int mRadio; 226 public int mPriority; 227 public NetworkInfo.State mLastState; 228 public NetworkAttributes(String init) { 229 String fragments[] = init.split(","); 230 mName = fragments[0].toLowerCase(); 231 mType = Integer.parseInt(fragments[1]); 232 mRadio = Integer.parseInt(fragments[2]); 233 mPriority = Integer.parseInt(fragments[3]); 234 mLastState = NetworkInfo.State.UNKNOWN; 235 } 236 public boolean isDefault() { 237 return (mType == mRadio); 238 } 239 } 240 NetworkAttributes[] mNetAttributes; 241 int mNetworksDefined; 242 243 private static class RadioAttributes { 244 public int mSimultaneity; 245 public int mType; 246 public RadioAttributes(String init) { 247 String fragments[] = init.split(","); 248 mType = Integer.parseInt(fragments[0]); 249 mSimultaneity = Integer.parseInt(fragments[1]); 250 } 251 } 252 RadioAttributes[] mRadioAttributes; 253 254 public static synchronized ConnectivityService getInstance(Context context) { 255 if (sServiceInstance == null) { 256 sServiceInstance = new ConnectivityService(context); 257 } 258 return sServiceInstance; 259 } 260 261 private ConnectivityService(Context context) { 262 if (DBG) log("ConnectivityService starting up"); 263 264 HandlerThread handlerThread = new HandlerThread("ConnectivityServiceThread"); 265 handlerThread.start(); 266 mHandler = new MyHandler(handlerThread.getLooper()); 267 268 mBackgroundDataEnabled.set(Settings.Secure.getInt(context.getContentResolver(), 269 Settings.Secure.BACKGROUND_DATA, 1) == 1); 270 271 // setup our unique device name 272 if (TextUtils.isEmpty(SystemProperties.get("net.hostname"))) { 273 String id = Settings.Secure.getString(context.getContentResolver(), 274 Settings.Secure.ANDROID_ID); 275 if (id != null && id.length() > 0) { 276 String name = new String("android_").concat(id); 277 SystemProperties.set("net.hostname", name); 278 } 279 } 280 281 // read our default dns server ip 282 String dns = Settings.Secure.getString(context.getContentResolver(), 283 Settings.Secure.DEFAULT_DNS_SERVER); 284 if (dns == null || dns.length() == 0) { 285 dns = context.getResources().getString( 286 com.android.internal.R.string.config_default_dns_server); 287 } 288 try { 289 mDefaultDns = InetAddress.getByName(dns); 290 } catch (UnknownHostException e) { 291 loge("Error setting defaultDns using " + dns); 292 } 293 294 mContext = context; 295 296 PowerManager powerManager = (PowerManager)mContext.getSystemService(Context.POWER_SERVICE); 297 mNetTransitionWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG); 298 mNetTransitionWakeLockTimeout = mContext.getResources().getInteger( 299 com.android.internal.R.integer.config_networkTransitionTimeout); 300 301 mNetTrackers = new NetworkStateTracker[ 302 ConnectivityManager.MAX_NETWORK_TYPE+1]; 303 304 mNetworkPreference = getPersistedNetworkPreference(); 305 306 mRadioAttributes = new RadioAttributes[ConnectivityManager.MAX_RADIO_TYPE+1]; 307 mNetAttributes = new NetworkAttributes[ConnectivityManager.MAX_NETWORK_TYPE+1]; 308 309 // Load device network attributes from resources 310 String[] raStrings = context.getResources().getStringArray( 311 com.android.internal.R.array.radioAttributes); 312 for (String raString : raStrings) { 313 RadioAttributes r = new RadioAttributes(raString); 314 if (r.mType > ConnectivityManager.MAX_RADIO_TYPE) { 315 loge("Error in radioAttributes - ignoring attempt to define type " + r.mType); 316 continue; 317 } 318 if (mRadioAttributes[r.mType] != null) { 319 loge("Error in radioAttributes - ignoring attempt to redefine type " + 320 r.mType); 321 continue; 322 } 323 mRadioAttributes[r.mType] = r; 324 } 325 326 String[] naStrings = context.getResources().getStringArray( 327 com.android.internal.R.array.networkAttributes); 328 for (String naString : naStrings) { 329 try { 330 NetworkAttributes n = new NetworkAttributes(naString); 331 if (n.mType > ConnectivityManager.MAX_NETWORK_TYPE) { 332 loge("Error in networkAttributes - ignoring attempt to define type " + 333 n.mType); 334 continue; 335 } 336 if (mNetAttributes[n.mType] != null) { 337 loge("Error in networkAttributes - ignoring attempt to redefine type " + 338 n.mType); 339 continue; 340 } 341 if (mRadioAttributes[n.mRadio] == null) { 342 loge("Error in networkAttributes - ignoring attempt to use undefined " + 343 "radio " + n.mRadio + " in network type " + n.mType); 344 continue; 345 } 346 mNetAttributes[n.mType] = n; 347 mNetworksDefined++; 348 } catch(Exception e) { 349 // ignore it - leave the entry null 350 } 351 } 352 353 // high priority first 354 mPriorityList = new int[mNetworksDefined]; 355 { 356 int insertionPoint = mNetworksDefined-1; 357 int currentLowest = 0; 358 int nextLowest = 0; 359 while (insertionPoint > -1) { 360 for (NetworkAttributes na : mNetAttributes) { 361 if (na == null) continue; 362 if (na.mPriority < currentLowest) continue; 363 if (na.mPriority > currentLowest) { 364 if (na.mPriority < nextLowest || nextLowest == 0) { 365 nextLowest = na.mPriority; 366 } 367 continue; 368 } 369 mPriorityList[insertionPoint--] = na.mType; 370 } 371 currentLowest = nextLowest; 372 nextLowest = 0; 373 } 374 } 375 376 mNetRequestersPids = new ArrayList[ConnectivityManager.MAX_NETWORK_TYPE+1]; 377 for (int i : mPriorityList) { 378 mNetRequestersPids[i] = new ArrayList(); 379 } 380 381 mFeatureUsers = new ArrayList(); 382 383 mNumDnsEntries = 0; 384 385 mTestMode = SystemProperties.get("cm.test.mode").equals("true") 386 && SystemProperties.get("ro.build.type").equals("eng"); 387 /* 388 * Create the network state trackers for Wi-Fi and mobile 389 * data. Maybe this could be done with a factory class, 390 * but it's not clear that it's worth it, given that 391 * the number of different network types is not going 392 * to change very often. 393 */ 394 for (int netType : mPriorityList) { 395 switch (mNetAttributes[netType].mRadio) { 396 case ConnectivityManager.TYPE_WIFI: 397 if (DBG) log("Starting Wifi Service."); 398 WifiStateTracker wst = new WifiStateTracker(); 399 WifiService wifiService = new WifiService(context); 400 ServiceManager.addService(Context.WIFI_SERVICE, wifiService); 401 wifiService.checkAndStartWifi(); 402 mNetTrackers[ConnectivityManager.TYPE_WIFI] = wst; 403 wst.startMonitoring(context, mHandler); 404 405 //TODO: as part of WWS refactor, create only when needed 406 mWifiWatchdogService = new WifiWatchdogService(context); 407 408 break; 409 case ConnectivityManager.TYPE_MOBILE: 410 mNetTrackers[netType] = new MobileDataStateTracker(netType, 411 mNetAttributes[netType].mName); 412 mNetTrackers[netType].startMonitoring(context, mHandler); 413 break; 414 case ConnectivityManager.TYPE_DUMMY: 415 mNetTrackers[netType] = new DummyDataStateTracker(netType, 416 mNetAttributes[netType].mName); 417 mNetTrackers[netType].startMonitoring(context, mHandler); 418 break; 419 case ConnectivityManager.TYPE_BLUETOOTH: 420 mNetTrackers[netType] = BluetoothTetheringDataTracker.getInstance(); 421 mNetTrackers[netType].startMonitoring(context, mHandler); 422 break; 423 default: 424 loge("Trying to create a DataStateTracker for an unknown radio type " + 425 mNetAttributes[netType].mRadio); 426 continue; 427 } 428 } 429 430 mTethering = new Tethering(mContext, mHandler.getLooper()); 431 mTetheringConfigValid = (((mNetTrackers[ConnectivityManager.TYPE_MOBILE_DUN] != null) || 432 !mTethering.isDunRequired()) && 433 (mTethering.getTetherableUsbRegexs().length != 0 || 434 mTethering.getTetherableWifiRegexs().length != 0 || 435 mTethering.getTetherableBluetoothRegexs().length != 0) && 436 mTethering.getUpstreamIfaceRegexs().length != 0); 437 438 if (DBG) { 439 mInetLog = new ArrayList(); 440 } 441 442 mSettingsObserver = new SettingsObserver(mHandler, EVENT_APPLY_GLOBAL_HTTP_PROXY); 443 mSettingsObserver.observe(mContext); 444 445 loadGlobalProxy(); 446 447 VpnManager.startVpnService(context); 448 } 449 450 451 /** 452 * Sets the preferred network. 453 * @param preference the new preference 454 */ 455 public void setNetworkPreference(int preference) { 456 enforceChangePermission(); 457 458 mHandler.sendMessage(mHandler.obtainMessage(EVENT_SET_NETWORK_PREFERENCE, preference, 0)); 459 } 460 461 public int getNetworkPreference() { 462 enforceAccessPermission(); 463 int preference; 464 synchronized(this) { 465 preference = mNetworkPreference; 466 } 467 return preference; 468 } 469 470 private void handleSetNetworkPreference(int preference) { 471 if (ConnectivityManager.isNetworkTypeValid(preference) && 472 mNetAttributes[preference] != null && 473 mNetAttributes[preference].isDefault()) { 474 if (mNetworkPreference != preference) { 475 final ContentResolver cr = mContext.getContentResolver(); 476 Settings.Secure.putInt(cr, Settings.Secure.NETWORK_PREFERENCE, preference); 477 synchronized(this) { 478 mNetworkPreference = preference; 479 } 480 enforcePreference(); 481 } 482 } 483 } 484 485 private int getPersistedNetworkPreference() { 486 final ContentResolver cr = mContext.getContentResolver(); 487 488 final int networkPrefSetting = Settings.Secure 489 .getInt(cr, Settings.Secure.NETWORK_PREFERENCE, -1); 490 if (networkPrefSetting != -1) { 491 return networkPrefSetting; 492 } 493 494 return ConnectivityManager.DEFAULT_NETWORK_PREFERENCE; 495 } 496 497 /** 498 * Make the state of network connectivity conform to the preference settings 499 * In this method, we only tear down a non-preferred network. Establishing 500 * a connection to the preferred network is taken care of when we handle 501 * the disconnect event from the non-preferred network 502 * (see {@link #handleDisconnect(NetworkInfo)}). 503 */ 504 private void enforcePreference() { 505 if (mNetTrackers[mNetworkPreference].getNetworkInfo().isConnected()) 506 return; 507 508 if (!mNetTrackers[mNetworkPreference].isAvailable()) 509 return; 510 511 for (int t=0; t <= ConnectivityManager.MAX_RADIO_TYPE; t++) { 512 if (t != mNetworkPreference && mNetTrackers[t] != null && 513 mNetTrackers[t].getNetworkInfo().isConnected()) { 514 if (DBG) { 515 log("tearing down " + mNetTrackers[t].getNetworkInfo() + 516 " in enforcePreference"); 517 } 518 teardown(mNetTrackers[t]); 519 } 520 } 521 } 522 523 private boolean teardown(NetworkStateTracker netTracker) { 524 if (netTracker.teardown()) { 525 netTracker.setTeardownRequested(true); 526 return true; 527 } else { 528 return false; 529 } 530 } 531 532 /** 533 * Return NetworkInfo for the active (i.e., connected) network interface. 534 * It is assumed that at most one network is active at a time. If more 535 * than one is active, it is indeterminate which will be returned. 536 * @return the info for the active network, or {@code null} if none is 537 * active 538 */ 539 public NetworkInfo getActiveNetworkInfo() { 540 enforceAccessPermission(); 541 for (int type=0; type <= ConnectivityManager.MAX_NETWORK_TYPE; type++) { 542 if (mNetAttributes[type] == null || !mNetAttributes[type].isDefault()) { 543 continue; 544 } 545 NetworkStateTracker t = mNetTrackers[type]; 546 NetworkInfo info = t.getNetworkInfo(); 547 if (info.isConnected()) { 548 if (DBG && type != mActiveDefaultNetwork) { 549 loge("connected default network is not mActiveDefaultNetwork!"); 550 } 551 return info; 552 } 553 } 554 return null; 555 } 556 557 public NetworkInfo getNetworkInfo(int networkType) { 558 enforceAccessPermission(); 559 if (ConnectivityManager.isNetworkTypeValid(networkType)) { 560 NetworkStateTracker t = mNetTrackers[networkType]; 561 if (t != null) 562 return t.getNetworkInfo(); 563 } 564 return null; 565 } 566 567 public NetworkInfo[] getAllNetworkInfo() { 568 enforceAccessPermission(); 569 NetworkInfo[] result = new NetworkInfo[mNetworksDefined]; 570 int i = 0; 571 for (NetworkStateTracker t : mNetTrackers) { 572 if(t != null) result[i++] = t.getNetworkInfo(); 573 } 574 return result; 575 } 576 577 /** 578 * Return LinkProperties for the active (i.e., connected) default 579 * network interface. It is assumed that at most one default network 580 * is active at a time. If more than one is active, it is indeterminate 581 * which will be returned. 582 * @return the ip properties for the active network, or {@code null} if 583 * none is active 584 */ 585 public LinkProperties getActiveLinkProperties() { 586 enforceAccessPermission(); 587 for (int type=0; type <= ConnectivityManager.MAX_NETWORK_TYPE; type++) { 588 if (mNetAttributes[type] == null || !mNetAttributes[type].isDefault()) { 589 continue; 590 } 591 NetworkStateTracker t = mNetTrackers[type]; 592 NetworkInfo info = t.getNetworkInfo(); 593 if (info.isConnected()) { 594 return t.getLinkProperties(); 595 } 596 } 597 return null; 598 } 599 600 public LinkProperties getLinkProperties(int networkType) { 601 enforceAccessPermission(); 602 if (ConnectivityManager.isNetworkTypeValid(networkType)) { 603 NetworkStateTracker t = mNetTrackers[networkType]; 604 if (t != null) return t.getLinkProperties(); 605 } 606 return null; 607 } 608 609 public boolean setRadios(boolean turnOn) { 610 boolean result = true; 611 enforceChangePermission(); 612 for (NetworkStateTracker t : mNetTrackers) { 613 if (t != null) result = t.setRadio(turnOn) && result; 614 } 615 return result; 616 } 617 618 public boolean setRadio(int netType, boolean turnOn) { 619 enforceChangePermission(); 620 if (!ConnectivityManager.isNetworkTypeValid(netType)) { 621 return false; 622 } 623 NetworkStateTracker tracker = mNetTrackers[netType]; 624 return tracker != null && tracker.setRadio(turnOn); 625 } 626 627 /** 628 * Used to notice when the calling process dies so we can self-expire 629 * 630 * Also used to know if the process has cleaned up after itself when 631 * our auto-expire timer goes off. The timer has a link to an object. 632 * 633 */ 634 private class FeatureUser implements IBinder.DeathRecipient { 635 int mNetworkType; 636 String mFeature; 637 IBinder mBinder; 638 int mPid; 639 int mUid; 640 long mCreateTime; 641 642 FeatureUser(int type, String feature, IBinder binder) { 643 super(); 644 mNetworkType = type; 645 mFeature = feature; 646 mBinder = binder; 647 mPid = getCallingPid(); 648 mUid = getCallingUid(); 649 mCreateTime = System.currentTimeMillis(); 650 651 try { 652 mBinder.linkToDeath(this, 0); 653 } catch (RemoteException e) { 654 binderDied(); 655 } 656 } 657 658 void unlinkDeathRecipient() { 659 mBinder.unlinkToDeath(this, 0); 660 } 661 662 public void binderDied() { 663 log("ConnectivityService FeatureUser binderDied(" + 664 mNetworkType + ", " + mFeature + ", " + mBinder + "), created " + 665 (System.currentTimeMillis() - mCreateTime) + " mSec ago"); 666 stopUsingNetworkFeature(this, false); 667 } 668 669 public void expire() { 670 log("ConnectivityService FeatureUser expire(" + 671 mNetworkType + ", " + mFeature + ", " + mBinder +"), created " + 672 (System.currentTimeMillis() - mCreateTime) + " mSec ago"); 673 stopUsingNetworkFeature(this, false); 674 } 675 676 public String toString() { 677 return "FeatureUser("+mNetworkType+","+mFeature+","+mPid+","+mUid+"), created " + 678 (System.currentTimeMillis() - mCreateTime) + " mSec ago"; 679 } 680 } 681 682 // javadoc from interface 683 public int startUsingNetworkFeature(int networkType, String feature, 684 IBinder binder) { 685 if (DBG) { 686 log("startUsingNetworkFeature for net " + networkType + ": " + feature); 687 } 688 enforceChangePermission(); 689 if (!ConnectivityManager.isNetworkTypeValid(networkType) || 690 mNetAttributes[networkType] == null) { 691 return Phone.APN_REQUEST_FAILED; 692 } 693 694 FeatureUser f = new FeatureUser(networkType, feature, binder); 695 696 // TODO - move this into the MobileDataStateTracker 697 int usedNetworkType = networkType; 698 if(networkType == ConnectivityManager.TYPE_MOBILE) { 699 if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_MMS)) { 700 usedNetworkType = ConnectivityManager.TYPE_MOBILE_MMS; 701 } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_SUPL)) { 702 usedNetworkType = ConnectivityManager.TYPE_MOBILE_SUPL; 703 } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_DUN) || 704 TextUtils.equals(feature, Phone.FEATURE_ENABLE_DUN_ALWAYS)) { 705 usedNetworkType = ConnectivityManager.TYPE_MOBILE_DUN; 706 } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_HIPRI)) { 707 usedNetworkType = ConnectivityManager.TYPE_MOBILE_HIPRI; 708 } 709 } 710 NetworkStateTracker network = mNetTrackers[usedNetworkType]; 711 if (network != null) { 712 Integer currentPid = new Integer(getCallingPid()); 713 if (usedNetworkType != networkType) { 714 NetworkStateTracker radio = mNetTrackers[networkType]; 715 NetworkInfo ni = network.getNetworkInfo(); 716 717 if (ni.isAvailable() == false) { 718 if (DBG) log("special network not available"); 719 if (!TextUtils.equals(feature,Phone.FEATURE_ENABLE_DUN_ALWAYS)) { 720 return Phone.APN_TYPE_NOT_AVAILABLE; 721 } else { 722 // else make the attempt anyway - probably giving REQUEST_STARTED below 723 } 724 } 725 726 synchronized(this) { 727 mFeatureUsers.add(f); 728 if (!mNetRequestersPids[usedNetworkType].contains(currentPid)) { 729 // this gets used for per-pid dns when connected 730 mNetRequestersPids[usedNetworkType].add(currentPid); 731 } 732 } 733 mHandler.sendMessageDelayed(mHandler.obtainMessage(EVENT_RESTORE_DEFAULT_NETWORK, 734 f), getRestoreDefaultNetworkDelay()); 735 736 737 if ((ni.isConnectedOrConnecting() == true) && 738 !network.isTeardownRequested()) { 739 if (ni.isConnected() == true) { 740 // add the pid-specific dns 741 handleDnsConfigurationChange(networkType); 742 if (DBG) log("special network already active"); 743 return Phone.APN_ALREADY_ACTIVE; 744 } 745 if (DBG) log("special network already connecting"); 746 return Phone.APN_REQUEST_STARTED; 747 } 748 749 // check if the radio in play can make another contact 750 // assume if cannot for now 751 752 if (DBG) log("reconnecting to special network"); 753 network.reconnect(); 754 return Phone.APN_REQUEST_STARTED; 755 } else { 756 // need to remember this unsupported request so we respond appropriately on stop 757 synchronized(this) { 758 mFeatureUsers.add(f); 759 if (!mNetRequestersPids[usedNetworkType].contains(currentPid)) { 760 // this gets used for per-pid dns when connected 761 mNetRequestersPids[usedNetworkType].add(currentPid); 762 } 763 } 764 return -1; 765 } 766 } 767 return Phone.APN_TYPE_NOT_AVAILABLE; 768 } 769 770 // javadoc from interface 771 public int stopUsingNetworkFeature(int networkType, String feature) { 772 enforceChangePermission(); 773 774 int pid = getCallingPid(); 775 int uid = getCallingUid(); 776 777 FeatureUser u = null; 778 boolean found = false; 779 780 synchronized(this) { 781 for (int i = 0; i < mFeatureUsers.size() ; i++) { 782 u = (FeatureUser)mFeatureUsers.get(i); 783 if (uid == u.mUid && pid == u.mPid && 784 networkType == u.mNetworkType && 785 TextUtils.equals(feature, u.mFeature)) { 786 found = true; 787 break; 788 } 789 } 790 } 791 if (found && u != null) { 792 // stop regardless of how many other time this proc had called start 793 return stopUsingNetworkFeature(u, true); 794 } else { 795 // none found! 796 if (DBG) log("ignoring stopUsingNetworkFeature - not a live request"); 797 return 1; 798 } 799 } 800 801 private int stopUsingNetworkFeature(FeatureUser u, boolean ignoreDups) { 802 int networkType = u.mNetworkType; 803 String feature = u.mFeature; 804 int pid = u.mPid; 805 int uid = u.mUid; 806 807 NetworkStateTracker tracker = null; 808 boolean callTeardown = false; // used to carry our decision outside of sync block 809 810 if (DBG) { 811 log("stopUsingNetworkFeature for net " + networkType + 812 ": " + feature); 813 } 814 815 if (!ConnectivityManager.isNetworkTypeValid(networkType)) { 816 return -1; 817 } 818 819 // need to link the mFeatureUsers list with the mNetRequestersPids state in this 820 // sync block 821 synchronized(this) { 822 // check if this process still has an outstanding start request 823 if (!mFeatureUsers.contains(u)) { 824 if (DBG) log("ignoring - this process has no outstanding requests"); 825 return 1; 826 } 827 u.unlinkDeathRecipient(); 828 mFeatureUsers.remove(mFeatureUsers.indexOf(u)); 829 // If we care about duplicate requests, check for that here. 830 // 831 // This is done to support the extension of a request - the app 832 // can request we start the network feature again and renew the 833 // auto-shutoff delay. Normal "stop" calls from the app though 834 // do not pay attention to duplicate requests - in effect the 835 // API does not refcount and a single stop will counter multiple starts. 836 if (ignoreDups == false) { 837 for (int i = 0; i < mFeatureUsers.size() ; i++) { 838 FeatureUser x = (FeatureUser)mFeatureUsers.get(i); 839 if (x.mUid == u.mUid && x.mPid == u.mPid && 840 x.mNetworkType == u.mNetworkType && 841 TextUtils.equals(x.mFeature, u.mFeature)) { 842 if (DBG) log("ignoring stopUsingNetworkFeature as dup is found"); 843 return 1; 844 } 845 } 846 } 847 848 // TODO - move to MobileDataStateTracker 849 int usedNetworkType = networkType; 850 if (networkType == ConnectivityManager.TYPE_MOBILE) { 851 if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_MMS)) { 852 usedNetworkType = ConnectivityManager.TYPE_MOBILE_MMS; 853 } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_SUPL)) { 854 usedNetworkType = ConnectivityManager.TYPE_MOBILE_SUPL; 855 } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_DUN) || 856 TextUtils.equals(feature, Phone.FEATURE_ENABLE_DUN_ALWAYS)) { 857 usedNetworkType = ConnectivityManager.TYPE_MOBILE_DUN; 858 } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_HIPRI)) { 859 usedNetworkType = ConnectivityManager.TYPE_MOBILE_HIPRI; 860 } 861 } 862 tracker = mNetTrackers[usedNetworkType]; 863 if (tracker == null) { 864 if (DBG) log("ignoring - no known tracker for net type " + usedNetworkType); 865 return -1; 866 } 867 if (usedNetworkType != networkType) { 868 Integer currentPid = new Integer(pid); 869 mNetRequestersPids[usedNetworkType].remove(currentPid); 870 reassessPidDns(pid, true); 871 if (mNetRequestersPids[usedNetworkType].size() != 0) { 872 if (DBG) log("not tearing down special network - " + 873 "others still using it"); 874 return 1; 875 } 876 callTeardown = true; 877 } else { 878 if (DBG) log("not a known feature - dropping"); 879 } 880 } 881 if (DBG) log("Doing network teardown"); 882 if (callTeardown) { 883 tracker.teardown(); 884 return 1; 885 } else { 886 return -1; 887 } 888 } 889 890 /** 891 * @deprecated use requestRouteToHostAddress instead 892 * 893 * Ensure that a network route exists to deliver traffic to the specified 894 * host via the specified network interface. 895 * @param networkType the type of the network over which traffic to the 896 * specified host is to be routed 897 * @param hostAddress the IP address of the host to which the route is 898 * desired 899 * @return {@code true} on success, {@code false} on failure 900 */ 901 public boolean requestRouteToHost(int networkType, int hostAddress) { 902 InetAddress inetAddress = NetworkUtils.intToInetAddress(hostAddress); 903 904 if (inetAddress == null) { 905 return false; 906 } 907 908 return requestRouteToHostAddress(networkType, inetAddress.getAddress()); 909 } 910 911 /** 912 * Ensure that a network route exists to deliver traffic to the specified 913 * host via the specified network interface. 914 * @param networkType the type of the network over which traffic to the 915 * specified host is to be routed 916 * @param hostAddress the IP address of the host to which the route is 917 * desired 918 * @return {@code true} on success, {@code false} on failure 919 */ 920 public boolean requestRouteToHostAddress(int networkType, byte[] hostAddress) { 921 enforceChangePermission(); 922 if (!ConnectivityManager.isNetworkTypeValid(networkType)) { 923 return false; 924 } 925 NetworkStateTracker tracker = mNetTrackers[networkType]; 926 927 if (tracker == null || !tracker.getNetworkInfo().isConnected() || 928 tracker.isTeardownRequested()) { 929 if (DBG) { 930 log("requestRouteToHostAddress on down network " + 931 "(" + networkType + ") - dropped"); 932 } 933 return false; 934 } 935 try { 936 InetAddress addr = InetAddress.getByAddress(hostAddress); 937 return addHostRoute(tracker, addr); 938 } catch (UnknownHostException e) {} 939 return false; 940 } 941 942 /** 943 * Ensure that a network route exists to deliver traffic to the specified 944 * host via the mobile data network. 945 * @param hostAddress the IP address of the host to which the route is desired, 946 * in network byte order. 947 * TODO - deprecate 948 * @return {@code true} on success, {@code false} on failure 949 */ 950 private boolean addHostRoute(NetworkStateTracker nt, InetAddress hostAddress) { 951 if (nt.getNetworkInfo().getType() == ConnectivityManager.TYPE_WIFI) { 952 return false; 953 } 954 955 LinkProperties p = nt.getLinkProperties(); 956 if (p == null) return false; 957 String interfaceName = p.getInterfaceName(); 958 959 if (DBG) { 960 log("Requested host route to " + hostAddress + "(" + interfaceName + ")"); 961 } 962 if (interfaceName != null) { 963 return NetworkUtils.addHostRoute(interfaceName, hostAddress, null); 964 } else { 965 if (DBG) loge("addHostRoute failed due to null interface name"); 966 return false; 967 } 968 } 969 970 /** 971 * @see ConnectivityManager#getBackgroundDataSetting() 972 */ 973 public boolean getBackgroundDataSetting() { 974 return mBackgroundDataEnabled.get(); 975 } 976 977 /** 978 * @see ConnectivityManager#setBackgroundDataSetting(boolean) 979 */ 980 public void setBackgroundDataSetting(boolean allowBackgroundDataUsage) { 981 mContext.enforceCallingOrSelfPermission( 982 android.Manifest.permission.CHANGE_BACKGROUND_DATA_SETTING, 983 "ConnectivityService"); 984 985 mBackgroundDataEnabled.set(allowBackgroundDataUsage); 986 987 mHandler.sendMessage(mHandler.obtainMessage(EVENT_SET_BACKGROUND_DATA, 988 (allowBackgroundDataUsage ? ENABLED : DISABLED), 0)); 989 } 990 991 private void handleSetBackgroundData(boolean enabled) { 992 if (enabled != getBackgroundDataSetting()) { 993 Settings.Secure.putInt(mContext.getContentResolver(), 994 Settings.Secure.BACKGROUND_DATA, enabled ? 1 : 0); 995 Intent broadcast = new Intent( 996 ConnectivityManager.ACTION_BACKGROUND_DATA_SETTING_CHANGED); 997 mContext.sendBroadcast(broadcast); 998 } 999 } 1000 1001 /** 1002 * @see ConnectivityManager#getMobileDataEnabled() 1003 */ 1004 public boolean getMobileDataEnabled() { 1005 // TODO: This detail should probably be in DataConnectionTracker's 1006 // which is where we store the value and maybe make this 1007 // asynchronous. 1008 enforceAccessPermission(); 1009 boolean retVal = Settings.Secure.getInt(mContext.getContentResolver(), 1010 Settings.Secure.MOBILE_DATA, 1) == 1; 1011 if (DBG) log("getMobileDataEnabled returning " + retVal); 1012 return retVal; 1013 } 1014 1015 /** 1016 * @see ConnectivityManager#setMobileDataEnabled(boolean) 1017 */ 1018 public void setMobileDataEnabled(boolean enabled) { 1019 enforceChangePermission(); 1020 if (DBG) log("setMobileDataEnabled(" + enabled + ")"); 1021 1022 mHandler.sendMessage(mHandler.obtainMessage(EVENT_SET_MOBILE_DATA, 1023 (enabled ? ENABLED : DISABLED), 0)); 1024 } 1025 1026 private void handleSetMobileData(boolean enabled) { 1027 if (mNetTrackers[ConnectivityManager.TYPE_MOBILE] != null) { 1028 if (DBG) { 1029 Slog.d(TAG, mNetTrackers[ConnectivityManager.TYPE_MOBILE].toString() + enabled); 1030 } 1031 mNetTrackers[ConnectivityManager.TYPE_MOBILE].setDataEnable(enabled); 1032 } 1033 } 1034 1035 private void enforceAccessPermission() { 1036 mContext.enforceCallingOrSelfPermission( 1037 android.Manifest.permission.ACCESS_NETWORK_STATE, 1038 "ConnectivityService"); 1039 } 1040 1041 private void enforceChangePermission() { 1042 mContext.enforceCallingOrSelfPermission( 1043 android.Manifest.permission.CHANGE_NETWORK_STATE, 1044 "ConnectivityService"); 1045 } 1046 1047 // TODO Make this a special check when it goes public 1048 private void enforceTetherChangePermission() { 1049 mContext.enforceCallingOrSelfPermission( 1050 android.Manifest.permission.CHANGE_NETWORK_STATE, 1051 "ConnectivityService"); 1052 } 1053 1054 private void enforceTetherAccessPermission() { 1055 mContext.enforceCallingOrSelfPermission( 1056 android.Manifest.permission.ACCESS_NETWORK_STATE, 1057 "ConnectivityService"); 1058 } 1059 1060 private void enforceConnectivityInternalPermission() { 1061 mContext.enforceCallingOrSelfPermission( 1062 android.Manifest.permission.CONNECTIVITY_INTERNAL, 1063 "ConnectivityService"); 1064 } 1065 1066 /** 1067 * Handle a {@code DISCONNECTED} event. If this pertains to the non-active 1068 * network, we ignore it. If it is for the active network, we send out a 1069 * broadcast. But first, we check whether it might be possible to connect 1070 * to a different network. 1071 * @param info the {@code NetworkInfo} for the network 1072 */ 1073 private void handleDisconnect(NetworkInfo info) { 1074 1075 int prevNetType = info.getType(); 1076 1077 mNetTrackers[prevNetType].setTeardownRequested(false); 1078 /* 1079 * If the disconnected network is not the active one, then don't report 1080 * this as a loss of connectivity. What probably happened is that we're 1081 * getting the disconnect for a network that we explicitly disabled 1082 * in accordance with network preference policies. 1083 */ 1084 if (!mNetAttributes[prevNetType].isDefault()) { 1085 List pids = mNetRequestersPids[prevNetType]; 1086 for (int i = 0; i<pids.size(); i++) { 1087 Integer pid = (Integer)pids.get(i); 1088 // will remove them because the net's no longer connected 1089 // need to do this now as only now do we know the pids and 1090 // can properly null things that are no longer referenced. 1091 reassessPidDns(pid.intValue(), false); 1092 } 1093 } 1094 1095 Intent intent = new Intent(ConnectivityManager.CONNECTIVITY_ACTION); 1096 intent.putExtra(ConnectivityManager.EXTRA_NETWORK_INFO, info); 1097 if (info.isFailover()) { 1098 intent.putExtra(ConnectivityManager.EXTRA_IS_FAILOVER, true); 1099 info.setFailover(false); 1100 } 1101 if (info.getReason() != null) { 1102 intent.putExtra(ConnectivityManager.EXTRA_REASON, info.getReason()); 1103 } 1104 if (info.getExtraInfo() != null) { 1105 intent.putExtra(ConnectivityManager.EXTRA_EXTRA_INFO, 1106 info.getExtraInfo()); 1107 } 1108 1109 if (mNetAttributes[prevNetType].isDefault()) { 1110 tryFailover(prevNetType); 1111 if (mActiveDefaultNetwork != -1) { 1112 NetworkInfo switchTo = mNetTrackers[mActiveDefaultNetwork].getNetworkInfo(); 1113 intent.putExtra(ConnectivityManager.EXTRA_OTHER_NETWORK_INFO, switchTo); 1114 } else { 1115 mDefaultInetConditionPublished = 0; // we're not connected anymore 1116 intent.putExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, true); 1117 } 1118 } 1119 intent.putExtra(ConnectivityManager.EXTRA_INET_CONDITION, mDefaultInetConditionPublished); 1120 // do this before we broadcast the change 1121 handleConnectivityChange(prevNetType); 1122 1123 sendStickyBroadcast(intent); 1124 /* 1125 * If the failover network is already connected, then immediately send 1126 * out a followup broadcast indicating successful failover 1127 */ 1128 if (mActiveDefaultNetwork != -1) { 1129 sendConnectedBroadcast(mNetTrackers[mActiveDefaultNetwork].getNetworkInfo()); 1130 } 1131 } 1132 1133 private void tryFailover(int prevNetType) { 1134 /* 1135 * If this is a default network, check if other defaults are available. 1136 * Try to reconnect on all available and let them hash it out when 1137 * more than one connects. 1138 */ 1139 if (mNetAttributes[prevNetType].isDefault()) { 1140 if (mActiveDefaultNetwork == prevNetType) { 1141 mActiveDefaultNetwork = -1; 1142 } 1143 1144 // don't signal a reconnect for anything lower or equal priority than our 1145 // current connected default 1146 // TODO - don't filter by priority now - nice optimization but risky 1147// int currentPriority = -1; 1148// if (mActiveDefaultNetwork != -1) { 1149// currentPriority = mNetAttributes[mActiveDefaultNetwork].mPriority; 1150// } 1151 for (int checkType=0; checkType <= ConnectivityManager.MAX_NETWORK_TYPE; checkType++) { 1152 if (checkType == prevNetType) continue; 1153 if (mNetAttributes[checkType] == null) continue; 1154 if (!mNetAttributes[checkType].isDefault()) continue; 1155 if (!mNetTrackers[checkType].isAvailable()) continue; 1156// if (currentPriority >= mNetAttributes[checkType].mPriority) continue; 1157 1158 NetworkStateTracker checkTracker = mNetTrackers[checkType]; 1159 NetworkInfo checkInfo = checkTracker.getNetworkInfo(); 1160 if (!checkInfo.isConnectedOrConnecting() || checkTracker.isTeardownRequested()) { 1161 checkInfo.setFailover(true); 1162 checkTracker.reconnect(); 1163 } 1164 if (DBG) log("Attempting to switch to " + checkInfo.getTypeName()); 1165 } 1166 } 1167 } 1168 1169 private void sendConnectedBroadcast(NetworkInfo info) { 1170 sendGeneralBroadcast(info, ConnectivityManager.CONNECTIVITY_ACTION); 1171 } 1172 1173 private void sendInetConditionBroadcast(NetworkInfo info) { 1174 sendGeneralBroadcast(info, ConnectivityManager.INET_CONDITION_ACTION); 1175 } 1176 1177 private void sendGeneralBroadcast(NetworkInfo info, String bcastType) { 1178 Intent intent = new Intent(bcastType); 1179 intent.putExtra(ConnectivityManager.EXTRA_NETWORK_INFO, info); 1180 if (info.isFailover()) { 1181 intent.putExtra(ConnectivityManager.EXTRA_IS_FAILOVER, true); 1182 info.setFailover(false); 1183 } 1184 if (info.getReason() != null) { 1185 intent.putExtra(ConnectivityManager.EXTRA_REASON, info.getReason()); 1186 } 1187 if (info.getExtraInfo() != null) { 1188 intent.putExtra(ConnectivityManager.EXTRA_EXTRA_INFO, 1189 info.getExtraInfo()); 1190 } 1191 intent.putExtra(ConnectivityManager.EXTRA_INET_CONDITION, mDefaultInetConditionPublished); 1192 sendStickyBroadcast(intent); 1193 } 1194 1195 /** 1196 * Called when an attempt to fail over to another network has failed. 1197 * @param info the {@link NetworkInfo} for the failed network 1198 */ 1199 private void handleConnectionFailure(NetworkInfo info) { 1200 mNetTrackers[info.getType()].setTeardownRequested(false); 1201 1202 String reason = info.getReason(); 1203 String extraInfo = info.getExtraInfo(); 1204 1205 String reasonText; 1206 if (reason == null) { 1207 reasonText = "."; 1208 } else { 1209 reasonText = " (" + reason + ")."; 1210 } 1211 loge("Attempt to connect to " + info.getTypeName() + " failed" + reasonText); 1212 1213 Intent intent = new Intent(ConnectivityManager.CONNECTIVITY_ACTION); 1214 intent.putExtra(ConnectivityManager.EXTRA_NETWORK_INFO, info); 1215 if (getActiveNetworkInfo() == null) { 1216 intent.putExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, true); 1217 } 1218 if (reason != null) { 1219 intent.putExtra(ConnectivityManager.EXTRA_REASON, reason); 1220 } 1221 if (extraInfo != null) { 1222 intent.putExtra(ConnectivityManager.EXTRA_EXTRA_INFO, extraInfo); 1223 } 1224 if (info.isFailover()) { 1225 intent.putExtra(ConnectivityManager.EXTRA_IS_FAILOVER, true); 1226 info.setFailover(false); 1227 } 1228 1229 if (mNetAttributes[info.getType()].isDefault()) { 1230 tryFailover(info.getType()); 1231 if (mActiveDefaultNetwork != -1) { 1232 NetworkInfo switchTo = mNetTrackers[mActiveDefaultNetwork].getNetworkInfo(); 1233 intent.putExtra(ConnectivityManager.EXTRA_OTHER_NETWORK_INFO, switchTo); 1234 } else { 1235 mDefaultInetConditionPublished = 0; 1236 intent.putExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, true); 1237 } 1238 } 1239 1240 intent.putExtra(ConnectivityManager.EXTRA_INET_CONDITION, mDefaultInetConditionPublished); 1241 sendStickyBroadcast(intent); 1242 /* 1243 * If the failover network is already connected, then immediately send 1244 * out a followup broadcast indicating successful failover 1245 */ 1246 if (mActiveDefaultNetwork != -1) { 1247 sendConnectedBroadcast(mNetTrackers[mActiveDefaultNetwork].getNetworkInfo()); 1248 } 1249 } 1250 1251 private void sendStickyBroadcast(Intent intent) { 1252 synchronized(this) { 1253 if (!mSystemReady) { 1254 mInitialBroadcast = new Intent(intent); 1255 } 1256 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 1257 mContext.sendStickyBroadcast(intent); 1258 } 1259 } 1260 1261 void systemReady() { 1262 synchronized(this) { 1263 mSystemReady = true; 1264 if (mInitialBroadcast != null) { 1265 mContext.sendStickyBroadcast(mInitialBroadcast); 1266 mInitialBroadcast = null; 1267 } 1268 } 1269 // load the global proxy at startup 1270 mHandler.sendMessage(mHandler.obtainMessage(EVENT_APPLY_GLOBAL_HTTP_PROXY)); 1271 } 1272 1273 private void handleConnect(NetworkInfo info) { 1274 int type = info.getType(); 1275 1276 // snapshot isFailover, because sendConnectedBroadcast() resets it 1277 boolean isFailover = info.isFailover(); 1278 NetworkStateTracker thisNet = mNetTrackers[type]; 1279 1280 // if this is a default net and other default is running 1281 // kill the one not preferred 1282 if (mNetAttributes[type].isDefault()) { 1283 if (mActiveDefaultNetwork != -1 && mActiveDefaultNetwork != type) { 1284 if ((type != mNetworkPreference && 1285 mNetAttributes[mActiveDefaultNetwork].mPriority > 1286 mNetAttributes[type].mPriority) || 1287 mNetworkPreference == mActiveDefaultNetwork) { 1288 // don't accept this one 1289 if (DBG) { 1290 log("Not broadcasting CONNECT_ACTION " + 1291 "to torn down network " + info.getTypeName()); 1292 } 1293 teardown(thisNet); 1294 return; 1295 } else { 1296 // tear down the other 1297 NetworkStateTracker otherNet = 1298 mNetTrackers[mActiveDefaultNetwork]; 1299 if (DBG) { 1300 log("Policy requires " + otherNet.getNetworkInfo().getTypeName() + 1301 " teardown"); 1302 } 1303 if (!teardown(otherNet)) { 1304 loge("Network declined teardown request"); 1305 return; 1306 } 1307 } 1308 } 1309 synchronized (ConnectivityService.this) { 1310 // have a new default network, release the transition wakelock in a second 1311 // if it's held. The second pause is to allow apps to reconnect over the 1312 // new network 1313 if (mNetTransitionWakeLock.isHeld()) { 1314 mHandler.sendMessageDelayed(mHandler.obtainMessage( 1315 EVENT_CLEAR_NET_TRANSITION_WAKELOCK, 1316 mNetTransitionWakeLockSerialNumber, 0), 1317 1000); 1318 } 1319 } 1320 mActiveDefaultNetwork = type; 1321 // this will cause us to come up initially as unconnected and switching 1322 // to connected after our normal pause unless somebody reports us as reall 1323 // disconnected 1324 mDefaultInetConditionPublished = 0; 1325 mDefaultConnectionSequence++; 1326 mInetConditionChangeInFlight = false; 1327 // Don't do this - if we never sign in stay, grey 1328 //reportNetworkCondition(mActiveDefaultNetwork, 100); 1329 } 1330 thisNet.setTeardownRequested(false); 1331 updateNetworkSettings(thisNet); 1332 handleConnectivityChange(type); 1333 sendConnectedBroadcast(info); 1334 } 1335 1336 /** 1337 * After a change in the connectivity state of a network. We're mainly 1338 * concerned with making sure that the list of DNS servers is set up 1339 * according to which networks are connected, and ensuring that the 1340 * right routing table entries exist. 1341 */ 1342 private void handleConnectivityChange(int netType) { 1343 /* 1344 * If a non-default network is enabled, add the host routes that 1345 * will allow it's DNS servers to be accessed. 1346 */ 1347 handleDnsConfigurationChange(netType); 1348 1349 if (mNetTrackers[netType].getNetworkInfo().isConnected()) { 1350 if (mNetAttributes[netType].isDefault()) { 1351 handleApplyDefaultProxy(netType); 1352 addDefaultRoute(mNetTrackers[netType]); 1353 } else { 1354 addPrivateDnsRoutes(mNetTrackers[netType]); 1355 } 1356 } else { 1357 if (mNetAttributes[netType].isDefault()) { 1358 removeDefaultRoute(mNetTrackers[netType]); 1359 } else { 1360 removePrivateDnsRoutes(mNetTrackers[netType]); 1361 } 1362 } 1363 } 1364 1365 private void addPrivateDnsRoutes(NetworkStateTracker nt) { 1366 boolean privateDnsRouteSet = nt.isPrivateDnsRouteSet(); 1367 LinkProperties p = nt.getLinkProperties(); 1368 if (p == null) return; 1369 String interfaceName = p.getInterfaceName(); 1370 1371 if (DBG) { 1372 log("addPrivateDnsRoutes for " + nt + 1373 "(" + interfaceName + ") - mPrivateDnsRouteSet = " + privateDnsRouteSet); 1374 } 1375 if (interfaceName != null && !privateDnsRouteSet) { 1376 Collection<InetAddress> dnsList = p.getDnses(); 1377 for (InetAddress dns : dnsList) { 1378 if (DBG) log(" adding " + dns); 1379 NetworkUtils.addHostRoute(interfaceName, dns, null); 1380 } 1381 nt.privateDnsRouteSet(true); 1382 } 1383 } 1384 1385 private void removePrivateDnsRoutes(NetworkStateTracker nt) { 1386 // TODO - we should do this explicitly but the NetUtils api doesnt 1387 // support this yet - must remove all. No worse than before 1388 LinkProperties p = nt.getLinkProperties(); 1389 if (p == null) return; 1390 String interfaceName = p.getInterfaceName(); 1391 boolean privateDnsRouteSet = nt.isPrivateDnsRouteSet(); 1392 if (interfaceName != null && privateDnsRouteSet) { 1393 if (DBG) { 1394 log("removePrivateDnsRoutes for " + nt.getNetworkInfo().getTypeName() + 1395 " (" + interfaceName + ")"); 1396 } 1397 NetworkUtils.removeHostRoutes(interfaceName); 1398 nt.privateDnsRouteSet(false); 1399 } 1400 } 1401 1402 1403 private void addDefaultRoute(NetworkStateTracker nt) { 1404 LinkProperties p = nt.getLinkProperties(); 1405 if (p == null) return; 1406 String interfaceName = p.getInterfaceName(); 1407 InetAddress defaultGatewayAddr = p.getGateway(); 1408 1409 if ((interfaceName != null) && (defaultGatewayAddr != null )) { 1410 if (!NetworkUtils.addDefaultRoute(interfaceName, defaultGatewayAddr) && DBG) { 1411 NetworkInfo networkInfo = nt.getNetworkInfo(); 1412 log("addDefaultRoute for " + networkInfo.getTypeName() + 1413 " (" + interfaceName + "), GatewayAddr=" + defaultGatewayAddr); 1414 } 1415 } 1416 } 1417 1418 1419 public void removeDefaultRoute(NetworkStateTracker nt) { 1420 LinkProperties p = nt.getLinkProperties(); 1421 if (p == null) return; 1422 String interfaceName = p.getInterfaceName(); 1423 1424 if (interfaceName != null) { 1425 if ((NetworkUtils.removeDefaultRoute(interfaceName) >= 0) && DBG) { 1426 NetworkInfo networkInfo = nt.getNetworkInfo(); 1427 log("removeDefaultRoute for " + networkInfo.getTypeName() + " (" + 1428 interfaceName + ")"); 1429 } 1430 } 1431 } 1432 1433 /** 1434 * Reads the network specific TCP buffer sizes from SystemProperties 1435 * net.tcp.buffersize.[default|wifi|umts|edge|gprs] and set them for system 1436 * wide use 1437 */ 1438 public void updateNetworkSettings(NetworkStateTracker nt) { 1439 String key = nt.getTcpBufferSizesPropName(); 1440 String bufferSizes = SystemProperties.get(key); 1441 1442 if (bufferSizes.length() == 0) { 1443 loge(key + " not found in system properties. Using defaults"); 1444 1445 // Setting to default values so we won't be stuck to previous values 1446 key = "net.tcp.buffersize.default"; 1447 bufferSizes = SystemProperties.get(key); 1448 } 1449 1450 // Set values in kernel 1451 if (bufferSizes.length() != 0) { 1452 if (DBG) { 1453 log("Setting TCP values: [" + bufferSizes 1454 + "] which comes from [" + key + "]"); 1455 } 1456 setBufferSize(bufferSizes); 1457 } 1458 } 1459 1460 /** 1461 * Writes TCP buffer sizes to /sys/kernel/ipv4/tcp_[r/w]mem_[min/def/max] 1462 * which maps to /proc/sys/net/ipv4/tcp_rmem and tcpwmem 1463 * 1464 * @param bufferSizes in the format of "readMin, readInitial, readMax, 1465 * writeMin, writeInitial, writeMax" 1466 */ 1467 private void setBufferSize(String bufferSizes) { 1468 try { 1469 String[] values = bufferSizes.split(","); 1470 1471 if (values.length == 6) { 1472 final String prefix = "/sys/kernel/ipv4/tcp_"; 1473 stringToFile(prefix + "rmem_min", values[0]); 1474 stringToFile(prefix + "rmem_def", values[1]); 1475 stringToFile(prefix + "rmem_max", values[2]); 1476 stringToFile(prefix + "wmem_min", values[3]); 1477 stringToFile(prefix + "wmem_def", values[4]); 1478 stringToFile(prefix + "wmem_max", values[5]); 1479 } else { 1480 loge("Invalid buffersize string: " + bufferSizes); 1481 } 1482 } catch (IOException e) { 1483 loge("Can't set tcp buffer sizes:" + e); 1484 } 1485 } 1486 1487 /** 1488 * Writes string to file. Basically same as "echo -n $string > $filename" 1489 * 1490 * @param filename 1491 * @param string 1492 * @throws IOException 1493 */ 1494 private void stringToFile(String filename, String string) throws IOException { 1495 FileWriter out = new FileWriter(filename); 1496 try { 1497 out.write(string); 1498 } finally { 1499 out.close(); 1500 } 1501 } 1502 1503 1504 /** 1505 * Adjust the per-process dns entries (net.dns<x>.<pid>) based 1506 * on the highest priority active net which this process requested. 1507 * If there aren't any, clear it out 1508 */ 1509 private void reassessPidDns(int myPid, boolean doBump) 1510 { 1511 if (DBG) log("reassessPidDns for pid " + myPid); 1512 for(int i : mPriorityList) { 1513 if (mNetAttributes[i].isDefault()) { 1514 continue; 1515 } 1516 NetworkStateTracker nt = mNetTrackers[i]; 1517 if (nt.getNetworkInfo().isConnected() && 1518 !nt.isTeardownRequested()) { 1519 LinkProperties p = nt.getLinkProperties(); 1520 if (p == null) continue; 1521 List pids = mNetRequestersPids[i]; 1522 for (int j=0; j<pids.size(); j++) { 1523 Integer pid = (Integer)pids.get(j); 1524 if (pid.intValue() == myPid) { 1525 Collection<InetAddress> dnses = p.getDnses(); 1526 writePidDns(dnses, myPid); 1527 if (doBump) { 1528 bumpDns(); 1529 } 1530 return; 1531 } 1532 } 1533 } 1534 } 1535 // nothing found - delete 1536 for (int i = 1; ; i++) { 1537 String prop = "net.dns" + i + "." + myPid; 1538 if (SystemProperties.get(prop).length() == 0) { 1539 if (doBump) { 1540 bumpDns(); 1541 } 1542 return; 1543 } 1544 SystemProperties.set(prop, ""); 1545 } 1546 } 1547 1548 // return true if results in a change 1549 private boolean writePidDns(Collection <InetAddress> dnses, int pid) { 1550 int j = 1; 1551 boolean changed = false; 1552 for (InetAddress dns : dnses) { 1553 String dnsString = dns.getHostAddress(); 1554 if (changed || !dnsString.equals(SystemProperties.get("net.dns" + j + "." + pid))) { 1555 changed = true; 1556 SystemProperties.set("net.dns" + j++ + "." + pid, dns.getHostAddress()); 1557 } 1558 } 1559 return changed; 1560 } 1561 1562 private void bumpDns() { 1563 /* 1564 * Bump the property that tells the name resolver library to reread 1565 * the DNS server list from the properties. 1566 */ 1567 String propVal = SystemProperties.get("net.dnschange"); 1568 int n = 0; 1569 if (propVal.length() != 0) { 1570 try { 1571 n = Integer.parseInt(propVal); 1572 } catch (NumberFormatException e) {} 1573 } 1574 SystemProperties.set("net.dnschange", "" + (n+1)); 1575 /* 1576 * Tell the VMs to toss their DNS caches 1577 */ 1578 Intent intent = new Intent(Intent.ACTION_CLEAR_DNS_CACHE); 1579 intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING); 1580 /* 1581 * Connectivity events can happen before boot has completed ... 1582 */ 1583 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 1584 mContext.sendBroadcast(intent); 1585 } 1586 1587 private void handleDnsConfigurationChange(int netType) { 1588 // add default net's dns entries 1589 NetworkStateTracker nt = mNetTrackers[netType]; 1590 if (nt != null && nt.getNetworkInfo().isConnected() && !nt.isTeardownRequested()) { 1591 LinkProperties p = nt.getLinkProperties(); 1592 if (p == null) return; 1593 Collection<InetAddress> dnses = p.getDnses(); 1594 boolean changed = false; 1595 if (mNetAttributes[netType].isDefault()) { 1596 int j = 1; 1597 if (dnses.size() == 0 && mDefaultDns != null) { 1598 String dnsString = mDefaultDns.getHostAddress(); 1599 if (!dnsString.equals(SystemProperties.get("net.dns1"))) { 1600 if (DBG) { 1601 log("no dns provided - using " + dnsString); 1602 } 1603 changed = true; 1604 SystemProperties.set("net.dns1", dnsString); 1605 } 1606 j++; 1607 } else { 1608 for (InetAddress dns : dnses) { 1609 String dnsString = dns.getHostAddress(); 1610 if (!changed && dnsString.equals(SystemProperties.get("net.dns" + j))) { 1611 j++; 1612 continue; 1613 } 1614 if (DBG) { 1615 log("adding dns " + dns + " for " + 1616 nt.getNetworkInfo().getTypeName()); 1617 } 1618 changed = true; 1619 SystemProperties.set("net.dns" + j++, dnsString); 1620 } 1621 } 1622 for (int k=j ; k<mNumDnsEntries; k++) { 1623 if (changed || !TextUtils.isEmpty(SystemProperties.get("net.dns" + k))) { 1624 if (DBG) log("erasing net.dns" + k); 1625 changed = true; 1626 SystemProperties.set("net.dns" + k, ""); 1627 } 1628 } 1629 mNumDnsEntries = j; 1630 } else { 1631 // set per-pid dns for attached secondary nets 1632 List pids = mNetRequestersPids[netType]; 1633 for (int y=0; y< pids.size(); y++) { 1634 Integer pid = (Integer)pids.get(y); 1635 changed = writePidDns(dnses, pid.intValue()); 1636 } 1637 } 1638 if (changed) bumpDns(); 1639 } 1640 } 1641 1642 private int getRestoreDefaultNetworkDelay() { 1643 String restoreDefaultNetworkDelayStr = SystemProperties.get( 1644 NETWORK_RESTORE_DELAY_PROP_NAME); 1645 if(restoreDefaultNetworkDelayStr != null && 1646 restoreDefaultNetworkDelayStr.length() != 0) { 1647 try { 1648 return Integer.valueOf(restoreDefaultNetworkDelayStr); 1649 } catch (NumberFormatException e) { 1650 } 1651 } 1652 return RESTORE_DEFAULT_NETWORK_DELAY; 1653 } 1654 1655 @Override 1656 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 1657 if (mContext.checkCallingOrSelfPermission( 1658 android.Manifest.permission.DUMP) 1659 != PackageManager.PERMISSION_GRANTED) { 1660 pw.println("Permission Denial: can't dump ConnectivityService " + 1661 "from from pid=" + Binder.getCallingPid() + ", uid=" + 1662 Binder.getCallingUid()); 1663 return; 1664 } 1665 pw.println(); 1666 for (NetworkStateTracker nst : mNetTrackers) { 1667 if (nst != null) { 1668 if (nst.getNetworkInfo().isConnected()) { 1669 pw.println("Active network: " + nst.getNetworkInfo(). 1670 getTypeName()); 1671 } 1672 pw.println(nst.getNetworkInfo()); 1673 pw.println(nst); 1674 pw.println(); 1675 } 1676 } 1677 1678 pw.println("Network Requester Pids:"); 1679 for (int net : mPriorityList) { 1680 String pidString = net + ": "; 1681 for (Object pid : mNetRequestersPids[net]) { 1682 pidString = pidString + pid.toString() + ", "; 1683 } 1684 pw.println(pidString); 1685 } 1686 pw.println(); 1687 1688 pw.println("FeatureUsers:"); 1689 for (Object requester : mFeatureUsers) { 1690 pw.println(requester.toString()); 1691 } 1692 pw.println(); 1693 1694 synchronized (this) { 1695 pw.println("NetworkTranstionWakeLock is currently " + 1696 (mNetTransitionWakeLock.isHeld() ? "" : "not ") + "held."); 1697 pw.println("It was last requested for "+mNetTransitionWakeLockCausedBy); 1698 } 1699 pw.println(); 1700 1701 mTethering.dump(fd, pw, args); 1702 1703 if (mInetLog != null) { 1704 pw.println(); 1705 pw.println("Inet condition reports:"); 1706 for(int i = 0; i < mInetLog.size(); i++) { 1707 pw.println(mInetLog.get(i)); 1708 } 1709 } 1710 } 1711 1712 // must be stateless - things change under us. 1713 private class MyHandler extends Handler { 1714 public MyHandler(Looper looper) { 1715 super(looper); 1716 } 1717 1718 @Override 1719 public void handleMessage(Message msg) { 1720 NetworkInfo info; 1721 switch (msg.what) { 1722 case NetworkStateTracker.EVENT_STATE_CHANGED: 1723 info = (NetworkInfo) msg.obj; 1724 int type = info.getType(); 1725 NetworkInfo.State state = info.getState(); 1726 // only do this optimization for wifi. It going into scan mode for location 1727 // services generates alot of noise. Meanwhile the mms apn won't send out 1728 // subsequent notifications when on default cellular because it never 1729 // disconnects.. so only do this to wifi notifications. Fixed better when the 1730 // APN notifications are standardized. 1731 if (mNetAttributes[type].mLastState == state && 1732 mNetAttributes[type].mRadio == ConnectivityManager.TYPE_WIFI) { 1733 if (DBG) { 1734 // TODO - remove this after we validate the dropping doesn't break 1735 // anything 1736 log("Dropping ConnectivityChange for " + 1737 info.getTypeName() + ": " + 1738 state + "/" + info.getDetailedState()); 1739 } 1740 return; 1741 } 1742 mNetAttributes[type].mLastState = state; 1743 1744 if (DBG) log("ConnectivityChange for " + 1745 info.getTypeName() + ": " + 1746 state + "/" + info.getDetailedState()); 1747 1748 // Connectivity state changed: 1749 // [31-13] Reserved for future use 1750 // [12-9] Network subtype (for mobile network, as defined 1751 // by TelephonyManager) 1752 // [8-3] Detailed state ordinal (as defined by 1753 // NetworkInfo.DetailedState) 1754 // [2-0] Network type (as defined by ConnectivityManager) 1755 int eventLogParam = (info.getType() & 0x7) | 1756 ((info.getDetailedState().ordinal() & 0x3f) << 3) | 1757 (info.getSubtype() << 9); 1758 EventLog.writeEvent(EventLogTags.CONNECTIVITY_STATE_CHANGED, 1759 eventLogParam); 1760 1761 if (info.getDetailedState() == 1762 NetworkInfo.DetailedState.FAILED) { 1763 handleConnectionFailure(info); 1764 } else if (state == NetworkInfo.State.DISCONNECTED) { 1765 handleDisconnect(info); 1766 } else if (state == NetworkInfo.State.SUSPENDED) { 1767 // TODO: need to think this over. 1768 // the logic here is, handle SUSPENDED the same as 1769 // DISCONNECTED. The only difference being we are 1770 // broadcasting an intent with NetworkInfo that's 1771 // suspended. This allows the applications an 1772 // opportunity to handle DISCONNECTED and SUSPENDED 1773 // differently, or not. 1774 handleDisconnect(info); 1775 } else if (state == NetworkInfo.State.CONNECTED) { 1776 handleConnect(info); 1777 } 1778 break; 1779 case NetworkStateTracker.EVENT_CONFIGURATION_CHANGED: 1780 info = (NetworkInfo) msg.obj; 1781 type = info.getType(); 1782 handleConnectivityChange(type); 1783 break; 1784 case EVENT_CLEAR_NET_TRANSITION_WAKELOCK: 1785 String causedBy = null; 1786 synchronized (ConnectivityService.this) { 1787 if (msg.arg1 == mNetTransitionWakeLockSerialNumber && 1788 mNetTransitionWakeLock.isHeld()) { 1789 mNetTransitionWakeLock.release(); 1790 causedBy = mNetTransitionWakeLockCausedBy; 1791 } 1792 } 1793 if (causedBy != null) { 1794 log("NetTransition Wakelock for " + causedBy + " released by timeout"); 1795 } 1796 break; 1797 case EVENT_RESTORE_DEFAULT_NETWORK: 1798 FeatureUser u = (FeatureUser)msg.obj; 1799 u.expire(); 1800 break; 1801 case EVENT_INET_CONDITION_CHANGE: 1802 { 1803 int netType = msg.arg1; 1804 int condition = msg.arg2; 1805 handleInetConditionChange(netType, condition); 1806 break; 1807 } 1808 case EVENT_INET_CONDITION_HOLD_END: 1809 { 1810 int netType = msg.arg1; 1811 int sequence = msg.arg2; 1812 handleInetConditionHoldEnd(netType, sequence); 1813 break; 1814 } 1815 case EVENT_SET_NETWORK_PREFERENCE: 1816 { 1817 int preference = msg.arg1; 1818 handleSetNetworkPreference(preference); 1819 break; 1820 } 1821 case EVENT_SET_BACKGROUND_DATA: 1822 { 1823 boolean enabled = (msg.arg1 == ENABLED); 1824 handleSetBackgroundData(enabled); 1825 break; 1826 } 1827 case EVENT_SET_MOBILE_DATA: 1828 { 1829 boolean enabled = (msg.arg1 == ENABLED); 1830 handleSetMobileData(enabled); 1831 break; 1832 } 1833 case EVENT_APPLY_GLOBAL_HTTP_PROXY: 1834 { 1835 handleDeprecatedGlobalHttpProxy(); 1836 } 1837 } 1838 } 1839 } 1840 1841 // javadoc from interface 1842 public int tether(String iface) { 1843 enforceTetherChangePermission(); 1844 1845 if (isTetheringSupported()) { 1846 return mTethering.tether(iface); 1847 } else { 1848 return ConnectivityManager.TETHER_ERROR_UNSUPPORTED; 1849 } 1850 } 1851 1852 // javadoc from interface 1853 public int untether(String iface) { 1854 enforceTetherChangePermission(); 1855 1856 if (isTetheringSupported()) { 1857 return mTethering.untether(iface); 1858 } else { 1859 return ConnectivityManager.TETHER_ERROR_UNSUPPORTED; 1860 } 1861 } 1862 1863 // javadoc from interface 1864 public int getLastTetherError(String iface) { 1865 enforceTetherAccessPermission(); 1866 1867 if (isTetheringSupported()) { 1868 return mTethering.getLastTetherError(iface); 1869 } else { 1870 return ConnectivityManager.TETHER_ERROR_UNSUPPORTED; 1871 } 1872 } 1873 1874 // TODO - proper iface API for selection by property, inspection, etc 1875 public String[] getTetherableUsbRegexs() { 1876 enforceTetherAccessPermission(); 1877 if (isTetheringSupported()) { 1878 return mTethering.getTetherableUsbRegexs(); 1879 } else { 1880 return new String[0]; 1881 } 1882 } 1883 1884 public String[] getTetherableWifiRegexs() { 1885 enforceTetherAccessPermission(); 1886 if (isTetheringSupported()) { 1887 return mTethering.getTetherableWifiRegexs(); 1888 } else { 1889 return new String[0]; 1890 } 1891 } 1892 1893 public String[] getTetherableBluetoothRegexs() { 1894 enforceTetherAccessPermission(); 1895 if (isTetheringSupported()) { 1896 return mTethering.getTetherableBluetoothRegexs(); 1897 } else { 1898 return new String[0]; 1899 } 1900 } 1901 1902 // TODO - move iface listing, queries, etc to new module 1903 // javadoc from interface 1904 public String[] getTetherableIfaces() { 1905 enforceTetherAccessPermission(); 1906 return mTethering.getTetherableIfaces(); 1907 } 1908 1909 public String[] getTetheredIfaces() { 1910 enforceTetherAccessPermission(); 1911 return mTethering.getTetheredIfaces(); 1912 } 1913 1914 public String[] getTetheringErroredIfaces() { 1915 enforceTetherAccessPermission(); 1916 return mTethering.getErroredIfaces(); 1917 } 1918 1919 // if ro.tether.denied = true we default to no tethering 1920 // gservices could set the secure setting to 1 though to enable it on a build where it 1921 // had previously been turned off. 1922 public boolean isTetheringSupported() { 1923 enforceTetherAccessPermission(); 1924 int defaultVal = (SystemProperties.get("ro.tether.denied").equals("true") ? 0 : 1); 1925 boolean tetherEnabledInSettings = (Settings.Secure.getInt(mContext.getContentResolver(), 1926 Settings.Secure.TETHER_SUPPORTED, defaultVal) != 0); 1927 return tetherEnabledInSettings && mTetheringConfigValid; 1928 } 1929 1930 // An API NetworkStateTrackers can call when they lose their network. 1931 // This will automatically be cleared after X seconds or a network becomes CONNECTED, 1932 // whichever happens first. The timer is started by the first caller and not 1933 // restarted by subsequent callers. 1934 public void requestNetworkTransitionWakelock(String forWhom) { 1935 enforceConnectivityInternalPermission(); 1936 synchronized (this) { 1937 if (mNetTransitionWakeLock.isHeld()) return; 1938 mNetTransitionWakeLockSerialNumber++; 1939 mNetTransitionWakeLock.acquire(); 1940 mNetTransitionWakeLockCausedBy = forWhom; 1941 } 1942 mHandler.sendMessageDelayed(mHandler.obtainMessage( 1943 EVENT_CLEAR_NET_TRANSITION_WAKELOCK, 1944 mNetTransitionWakeLockSerialNumber, 0), 1945 mNetTransitionWakeLockTimeout); 1946 return; 1947 } 1948 1949 // 100 percent is full good, 0 is full bad. 1950 public void reportInetCondition(int networkType, int percentage) { 1951 if (DBG) log("reportNetworkCondition(" + networkType + ", " + percentage + ")"); 1952 mContext.enforceCallingOrSelfPermission( 1953 android.Manifest.permission.STATUS_BAR, 1954 "ConnectivityService"); 1955 1956 if (DBG) { 1957 int pid = getCallingPid(); 1958 int uid = getCallingUid(); 1959 String s = pid + "(" + uid + ") reports inet is " + 1960 (percentage > 50 ? "connected" : "disconnected") + " (" + percentage + ") on " + 1961 "network Type " + networkType + " at " + GregorianCalendar.getInstance().getTime(); 1962 mInetLog.add(s); 1963 while(mInetLog.size() > INET_CONDITION_LOG_MAX_SIZE) { 1964 mInetLog.remove(0); 1965 } 1966 } 1967 mHandler.sendMessage(mHandler.obtainMessage( 1968 EVENT_INET_CONDITION_CHANGE, networkType, percentage)); 1969 } 1970 1971 private void handleInetConditionChange(int netType, int condition) { 1972 if (DBG) { 1973 log("Inet connectivity change, net=" + 1974 netType + ", condition=" + condition + 1975 ",mActiveDefaultNetwork=" + mActiveDefaultNetwork); 1976 } 1977 if (mActiveDefaultNetwork == -1) { 1978 if (DBG) log("no active default network - aborting"); 1979 return; 1980 } 1981 if (mActiveDefaultNetwork != netType) { 1982 if (DBG) log("given net not default - aborting"); 1983 return; 1984 } 1985 mDefaultInetCondition = condition; 1986 int delay; 1987 if (mInetConditionChangeInFlight == false) { 1988 if (DBG) log("starting a change hold"); 1989 // setup a new hold to debounce this 1990 if (mDefaultInetCondition > 50) { 1991 delay = Settings.Secure.getInt(mContext.getContentResolver(), 1992 Settings.Secure.INET_CONDITION_DEBOUNCE_UP_DELAY, 500); 1993 } else { 1994 delay = Settings.Secure.getInt(mContext.getContentResolver(), 1995 Settings.Secure.INET_CONDITION_DEBOUNCE_DOWN_DELAY, 3000); 1996 } 1997 mInetConditionChangeInFlight = true; 1998 mHandler.sendMessageDelayed(mHandler.obtainMessage(EVENT_INET_CONDITION_HOLD_END, 1999 mActiveDefaultNetwork, mDefaultConnectionSequence), delay); 2000 } else { 2001 // we've set the new condition, when this hold ends that will get 2002 // picked up 2003 if (DBG) log("currently in hold - not setting new end evt"); 2004 } 2005 } 2006 2007 private void handleInetConditionHoldEnd(int netType, int sequence) { 2008 if (DBG) { 2009 log("Inet hold end, net=" + netType + 2010 ", condition =" + mDefaultInetCondition + 2011 ", published condition =" + mDefaultInetConditionPublished); 2012 } 2013 mInetConditionChangeInFlight = false; 2014 2015 if (mActiveDefaultNetwork == -1) { 2016 if (DBG) log("no active default network - aborting"); 2017 return; 2018 } 2019 if (mDefaultConnectionSequence != sequence) { 2020 if (DBG) log("event hold for obsolete network - aborting"); 2021 return; 2022 } 2023 if (mDefaultInetConditionPublished == mDefaultInetCondition) { 2024 if (DBG) log("no change in condition - aborting"); 2025 return; 2026 } 2027 NetworkInfo networkInfo = mNetTrackers[mActiveDefaultNetwork].getNetworkInfo(); 2028 if (networkInfo.isConnected() == false) { 2029 if (DBG) log("default network not connected - aborting"); 2030 return; 2031 } 2032 mDefaultInetConditionPublished = mDefaultInetCondition; 2033 sendInetConditionBroadcast(networkInfo); 2034 return; 2035 } 2036 2037 public synchronized ProxyProperties getProxy() { 2038 if (mGlobalProxy != null) return mGlobalProxy; 2039 if (mDefaultProxy != null) return mDefaultProxy; 2040 return null; 2041 } 2042 2043 public void setGlobalProxy(ProxyProperties proxyProperties) { 2044 enforceChangePermission(); 2045 synchronized (mGlobalProxyLock) { 2046 if (proxyProperties == mGlobalProxy) return; 2047 if (proxyProperties != null && proxyProperties.equals(mGlobalProxy)) return; 2048 if (mGlobalProxy != null && mGlobalProxy.equals(proxyProperties)) return; 2049 2050 String host = ""; 2051 int port = 0; 2052 String exclList = ""; 2053 if (proxyProperties != null && !TextUtils.isEmpty(proxyProperties.getHost())) { 2054 mGlobalProxy = new ProxyProperties(proxyProperties); 2055 host = mGlobalProxy.getHost(); 2056 port = mGlobalProxy.getPort(); 2057 exclList = mGlobalProxy.getExclusionList(); 2058 } else { 2059 mGlobalProxy = null; 2060 } 2061 ContentResolver res = mContext.getContentResolver(); 2062 Settings.Secure.putString(res, Settings.Secure.GLOBAL_HTTP_PROXY_HOST, host); 2063 Settings.Secure.putInt(res, Settings.Secure.GLOBAL_HTTP_PROXY_PORT, port); 2064 Settings.Secure.putString(res, Settings.Secure.GLOBAL_HTTP_PROXY_EXCLUSION_LIST, 2065 exclList); 2066 } 2067 2068 if (mGlobalProxy == null) { 2069 proxyProperties = mDefaultProxy; 2070 } 2071 sendProxyBroadcast(proxyProperties); 2072 } 2073 2074 private void loadGlobalProxy() { 2075 ContentResolver res = mContext.getContentResolver(); 2076 String host = Settings.Secure.getString(res, Settings.Secure.GLOBAL_HTTP_PROXY_HOST); 2077 int port = Settings.Secure.getInt(res, Settings.Secure.GLOBAL_HTTP_PROXY_PORT, 0); 2078 String exclList = Settings.Secure.getString(res, 2079 Settings.Secure.GLOBAL_HTTP_PROXY_EXCLUSION_LIST); 2080 if (!TextUtils.isEmpty(host)) { 2081 ProxyProperties proxyProperties = new ProxyProperties(host, port, exclList); 2082 synchronized (mGlobalProxyLock) { 2083 mGlobalProxy = proxyProperties; 2084 } 2085 } 2086 } 2087 2088 public ProxyProperties getGlobalProxy() { 2089 synchronized (mGlobalProxyLock) { 2090 return mGlobalProxy; 2091 } 2092 } 2093 2094 private void handleApplyDefaultProxy(int type) { 2095 // check if new default - push it out to all VM if so 2096 ProxyProperties proxy = mNetTrackers[type].getLinkProperties().getHttpProxy(); 2097 synchronized (this) { 2098 if (mDefaultProxy != null && mDefaultProxy.equals(proxy)) return; 2099 if (mDefaultProxy == proxy) return; 2100 if (!TextUtils.isEmpty(proxy.getHost())) { 2101 mDefaultProxy = proxy; 2102 } else { 2103 mDefaultProxy = null; 2104 } 2105 } 2106 if (DBG) log("changing default proxy to " + proxy); 2107 if ((proxy == null && mGlobalProxy == null) || proxy.equals(mGlobalProxy)) return; 2108 if (mGlobalProxy != null) return; 2109 sendProxyBroadcast(proxy); 2110 } 2111 2112 private void handleDeprecatedGlobalHttpProxy() { 2113 String proxy = Settings.Secure.getString(mContext.getContentResolver(), 2114 Settings.Secure.HTTP_PROXY); 2115 if (!TextUtils.isEmpty(proxy)) { 2116 String data[] = proxy.split(":"); 2117 String proxyHost = data[0]; 2118 int proxyPort = 8080; 2119 if (data.length > 1) { 2120 try { 2121 proxyPort = Integer.parseInt(data[1]); 2122 } catch (NumberFormatException e) { 2123 return; 2124 } 2125 } 2126 ProxyProperties p = new ProxyProperties(data[0], proxyPort, ""); 2127 setGlobalProxy(p); 2128 } 2129 } 2130 2131 private void sendProxyBroadcast(ProxyProperties proxy) { 2132 if (proxy == null) proxy = new ProxyProperties("", 0, ""); 2133 log("sending Proxy Broadcast for " + proxy); 2134 Intent intent = new Intent(Proxy.PROXY_CHANGE_ACTION); 2135 intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING); 2136 intent.putExtra(Proxy.EXTRA_PROXY_INFO, proxy); 2137 mContext.sendStickyBroadcast(intent); 2138 } 2139 2140 private static class SettingsObserver extends ContentObserver { 2141 private int mWhat; 2142 private Handler mHandler; 2143 SettingsObserver(Handler handler, int what) { 2144 super(handler); 2145 mHandler = handler; 2146 mWhat = what; 2147 } 2148 2149 void observe(Context context) { 2150 ContentResolver resolver = context.getContentResolver(); 2151 resolver.registerContentObserver(Settings.Secure.getUriFor( 2152 Settings.Secure.HTTP_PROXY), false, this); 2153 } 2154 2155 @Override 2156 public void onChange(boolean selfChange) { 2157 mHandler.obtainMessage(mWhat).sendToTarget(); 2158 } 2159 } 2160 2161 private void log(String s) { 2162 Slog.d(TAG, s); 2163 } 2164 2165 private void loge(String s) { 2166 Slog.e(TAG, s); 2167 } 2168} 2169