ConnectivityService.java revision 6244f0fc168291b428ba2595e0a3a0d5d4be2bd4
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 = NetworkUtils.numericToInetAddress(dns); 290 } catch (IllegalArgumentException 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 if (mActiveDefaultNetwork != -1) { 542 return mNetTrackers[mActiveDefaultNetwork].getNetworkInfo(); 543 } 544 return null; 545 } 546 547 public NetworkInfo getNetworkInfo(int networkType) { 548 enforceAccessPermission(); 549 if (ConnectivityManager.isNetworkTypeValid(networkType)) { 550 NetworkStateTracker t = mNetTrackers[networkType]; 551 if (t != null) 552 return t.getNetworkInfo(); 553 } 554 return null; 555 } 556 557 public NetworkInfo[] getAllNetworkInfo() { 558 enforceAccessPermission(); 559 NetworkInfo[] result = new NetworkInfo[mNetworksDefined]; 560 int i = 0; 561 for (NetworkStateTracker t : mNetTrackers) { 562 if(t != null) result[i++] = t.getNetworkInfo(); 563 } 564 return result; 565 } 566 567 /** 568 * Return LinkProperties for the active (i.e., connected) default 569 * network interface. It is assumed that at most one default network 570 * is active at a time. If more than one is active, it is indeterminate 571 * which will be returned. 572 * @return the ip properties for the active network, or {@code null} if 573 * none is active 574 */ 575 public LinkProperties getActiveLinkProperties() { 576 enforceAccessPermission(); 577 for (int type=0; type <= ConnectivityManager.MAX_NETWORK_TYPE; type++) { 578 if (mNetAttributes[type] == null || !mNetAttributes[type].isDefault()) { 579 continue; 580 } 581 NetworkStateTracker t = mNetTrackers[type]; 582 NetworkInfo info = t.getNetworkInfo(); 583 if (info.isConnected()) { 584 return t.getLinkProperties(); 585 } 586 } 587 return null; 588 } 589 590 public LinkProperties getLinkProperties(int networkType) { 591 enforceAccessPermission(); 592 if (ConnectivityManager.isNetworkTypeValid(networkType)) { 593 NetworkStateTracker t = mNetTrackers[networkType]; 594 if (t != null) return t.getLinkProperties(); 595 } 596 return null; 597 } 598 599 public boolean setRadios(boolean turnOn) { 600 boolean result = true; 601 enforceChangePermission(); 602 for (NetworkStateTracker t : mNetTrackers) { 603 if (t != null) result = t.setRadio(turnOn) && result; 604 } 605 return result; 606 } 607 608 public boolean setRadio(int netType, boolean turnOn) { 609 enforceChangePermission(); 610 if (!ConnectivityManager.isNetworkTypeValid(netType)) { 611 return false; 612 } 613 NetworkStateTracker tracker = mNetTrackers[netType]; 614 return tracker != null && tracker.setRadio(turnOn); 615 } 616 617 /** 618 * Used to notice when the calling process dies so we can self-expire 619 * 620 * Also used to know if the process has cleaned up after itself when 621 * our auto-expire timer goes off. The timer has a link to an object. 622 * 623 */ 624 private class FeatureUser implements IBinder.DeathRecipient { 625 int mNetworkType; 626 String mFeature; 627 IBinder mBinder; 628 int mPid; 629 int mUid; 630 long mCreateTime; 631 632 FeatureUser(int type, String feature, IBinder binder) { 633 super(); 634 mNetworkType = type; 635 mFeature = feature; 636 mBinder = binder; 637 mPid = getCallingPid(); 638 mUid = getCallingUid(); 639 mCreateTime = System.currentTimeMillis(); 640 641 try { 642 mBinder.linkToDeath(this, 0); 643 } catch (RemoteException e) { 644 binderDied(); 645 } 646 } 647 648 void unlinkDeathRecipient() { 649 mBinder.unlinkToDeath(this, 0); 650 } 651 652 public void binderDied() { 653 log("ConnectivityService FeatureUser binderDied(" + 654 mNetworkType + ", " + mFeature + ", " + mBinder + "), created " + 655 (System.currentTimeMillis() - mCreateTime) + " mSec ago"); 656 stopUsingNetworkFeature(this, false); 657 } 658 659 public void expire() { 660 log("ConnectivityService FeatureUser expire(" + 661 mNetworkType + ", " + mFeature + ", " + mBinder +"), created " + 662 (System.currentTimeMillis() - mCreateTime) + " mSec ago"); 663 stopUsingNetworkFeature(this, false); 664 } 665 666 public String toString() { 667 return "FeatureUser("+mNetworkType+","+mFeature+","+mPid+","+mUid+"), created " + 668 (System.currentTimeMillis() - mCreateTime) + " mSec ago"; 669 } 670 } 671 672 // javadoc from interface 673 public int startUsingNetworkFeature(int networkType, String feature, 674 IBinder binder) { 675 if (DBG) { 676 log("startUsingNetworkFeature for net " + networkType + ": " + feature); 677 } 678 enforceChangePermission(); 679 if (!ConnectivityManager.isNetworkTypeValid(networkType) || 680 mNetAttributes[networkType] == null) { 681 return Phone.APN_REQUEST_FAILED; 682 } 683 684 FeatureUser f = new FeatureUser(networkType, feature, binder); 685 686 // TODO - move this into the MobileDataStateTracker 687 int usedNetworkType = networkType; 688 if(networkType == ConnectivityManager.TYPE_MOBILE) { 689 usedNetworkType = convertFeatureToNetworkType(feature); 690 if (usedNetworkType < 0) { 691 Slog.e(TAG, "Can't match any netTracker!"); 692 usedNetworkType = networkType; 693 } 694 } 695 NetworkStateTracker network = mNetTrackers[usedNetworkType]; 696 if (network != null) { 697 Integer currentPid = new Integer(getCallingPid()); 698 if (usedNetworkType != networkType) { 699 NetworkStateTracker radio = mNetTrackers[networkType]; 700 NetworkInfo ni = network.getNetworkInfo(); 701 702 if (ni.isAvailable() == false) { 703 if (DBG) log("special network not available"); 704 if (!TextUtils.equals(feature,Phone.FEATURE_ENABLE_DUN_ALWAYS)) { 705 return Phone.APN_TYPE_NOT_AVAILABLE; 706 } else { 707 // else make the attempt anyway - probably giving REQUEST_STARTED below 708 } 709 } 710 711 synchronized(this) { 712 mFeatureUsers.add(f); 713 if (!mNetRequestersPids[usedNetworkType].contains(currentPid)) { 714 // this gets used for per-pid dns when connected 715 mNetRequestersPids[usedNetworkType].add(currentPid); 716 } 717 } 718 mHandler.sendMessageDelayed(mHandler.obtainMessage(EVENT_RESTORE_DEFAULT_NETWORK, 719 f), getRestoreDefaultNetworkDelay()); 720 721 722 if ((ni.isConnectedOrConnecting() == true) && 723 !network.isTeardownRequested()) { 724 if (ni.isConnected() == true) { 725 // add the pid-specific dns 726 handleDnsConfigurationChange(networkType); 727 if (DBG) log("special network already active"); 728 return Phone.APN_ALREADY_ACTIVE; 729 } 730 if (DBG) log("special network already connecting"); 731 return Phone.APN_REQUEST_STARTED; 732 } 733 734 // check if the radio in play can make another contact 735 // assume if cannot for now 736 737 if (DBG) log("reconnecting to special network"); 738 network.reconnect(); 739 return Phone.APN_REQUEST_STARTED; 740 } else { 741 // need to remember this unsupported request so we respond appropriately on stop 742 synchronized(this) { 743 mFeatureUsers.add(f); 744 if (!mNetRequestersPids[usedNetworkType].contains(currentPid)) { 745 // this gets used for per-pid dns when connected 746 mNetRequestersPids[usedNetworkType].add(currentPid); 747 } 748 } 749 return -1; 750 } 751 } 752 return Phone.APN_TYPE_NOT_AVAILABLE; 753 } 754 755 // javadoc from interface 756 public int stopUsingNetworkFeature(int networkType, String feature) { 757 enforceChangePermission(); 758 759 int pid = getCallingPid(); 760 int uid = getCallingUid(); 761 762 FeatureUser u = null; 763 boolean found = false; 764 765 synchronized(this) { 766 for (int i = 0; i < mFeatureUsers.size() ; i++) { 767 u = (FeatureUser)mFeatureUsers.get(i); 768 if (uid == u.mUid && pid == u.mPid && 769 networkType == u.mNetworkType && 770 TextUtils.equals(feature, u.mFeature)) { 771 found = true; 772 break; 773 } 774 } 775 } 776 if (found && u != null) { 777 // stop regardless of how many other time this proc had called start 778 return stopUsingNetworkFeature(u, true); 779 } else { 780 // none found! 781 if (DBG) log("ignoring stopUsingNetworkFeature - not a live request"); 782 return 1; 783 } 784 } 785 786 private int stopUsingNetworkFeature(FeatureUser u, boolean ignoreDups) { 787 int networkType = u.mNetworkType; 788 String feature = u.mFeature; 789 int pid = u.mPid; 790 int uid = u.mUid; 791 792 NetworkStateTracker tracker = null; 793 boolean callTeardown = false; // used to carry our decision outside of sync block 794 795 if (DBG) { 796 log("stopUsingNetworkFeature for net " + networkType + 797 ": " + feature); 798 } 799 800 if (!ConnectivityManager.isNetworkTypeValid(networkType)) { 801 return -1; 802 } 803 804 // need to link the mFeatureUsers list with the mNetRequestersPids state in this 805 // sync block 806 synchronized(this) { 807 // check if this process still has an outstanding start request 808 if (!mFeatureUsers.contains(u)) { 809 if (DBG) log("ignoring - this process has no outstanding requests"); 810 return 1; 811 } 812 u.unlinkDeathRecipient(); 813 mFeatureUsers.remove(mFeatureUsers.indexOf(u)); 814 // If we care about duplicate requests, check for that here. 815 // 816 // This is done to support the extension of a request - the app 817 // can request we start the network feature again and renew the 818 // auto-shutoff delay. Normal "stop" calls from the app though 819 // do not pay attention to duplicate requests - in effect the 820 // API does not refcount and a single stop will counter multiple starts. 821 if (ignoreDups == false) { 822 for (int i = 0; i < mFeatureUsers.size() ; i++) { 823 FeatureUser x = (FeatureUser)mFeatureUsers.get(i); 824 if (x.mUid == u.mUid && x.mPid == u.mPid && 825 x.mNetworkType == u.mNetworkType && 826 TextUtils.equals(x.mFeature, u.mFeature)) { 827 if (DBG) log("ignoring stopUsingNetworkFeature as dup is found"); 828 return 1; 829 } 830 } 831 } 832 833 // TODO - move to MobileDataStateTracker 834 int usedNetworkType = networkType; 835 if (networkType == ConnectivityManager.TYPE_MOBILE) { 836 usedNetworkType = convertFeatureToNetworkType(feature); 837 if (usedNetworkType < 0) { 838 usedNetworkType = networkType; 839 } 840 } 841 tracker = mNetTrackers[usedNetworkType]; 842 if (tracker == null) { 843 if (DBG) log("ignoring - no known tracker for net type " + usedNetworkType); 844 return -1; 845 } 846 if (usedNetworkType != networkType) { 847 Integer currentPid = new Integer(pid); 848 mNetRequestersPids[usedNetworkType].remove(currentPid); 849 reassessPidDns(pid, true); 850 if (mNetRequestersPids[usedNetworkType].size() != 0) { 851 if (DBG) log("not tearing down special network - " + 852 "others still using it"); 853 return 1; 854 } 855 callTeardown = true; 856 } else { 857 if (DBG) log("not a known feature - dropping"); 858 } 859 } 860 if (DBG) log("Doing network teardown"); 861 if (callTeardown) { 862 tracker.teardown(); 863 return 1; 864 } else { 865 return -1; 866 } 867 } 868 869 /** 870 * @deprecated use requestRouteToHostAddress instead 871 * 872 * Ensure that a network route exists to deliver traffic to the specified 873 * host via the specified network interface. 874 * @param networkType the type of the network over which traffic to the 875 * specified host is to be routed 876 * @param hostAddress the IP address of the host to which the route is 877 * desired 878 * @return {@code true} on success, {@code false} on failure 879 */ 880 public boolean requestRouteToHost(int networkType, int hostAddress) { 881 InetAddress inetAddress = NetworkUtils.intToInetAddress(hostAddress); 882 883 if (inetAddress == null) { 884 return false; 885 } 886 887 return requestRouteToHostAddress(networkType, inetAddress.getAddress()); 888 } 889 890 /** 891 * Ensure that a network route exists to deliver traffic to the specified 892 * host via the specified network interface. 893 * @param networkType the type of the network over which traffic to the 894 * specified host is to be routed 895 * @param hostAddress the IP address of the host to which the route is 896 * desired 897 * @return {@code true} on success, {@code false} on failure 898 */ 899 public boolean requestRouteToHostAddress(int networkType, byte[] hostAddress) { 900 enforceChangePermission(); 901 if (!ConnectivityManager.isNetworkTypeValid(networkType)) { 902 return false; 903 } 904 NetworkStateTracker tracker = mNetTrackers[networkType]; 905 906 if (tracker == null || !tracker.getNetworkInfo().isConnected() || 907 tracker.isTeardownRequested()) { 908 if (DBG) { 909 log("requestRouteToHostAddress on down network " + 910 "(" + networkType + ") - dropped"); 911 } 912 return false; 913 } 914 try { 915 InetAddress addr = InetAddress.getByAddress(hostAddress); 916 return addHostRoute(tracker, addr); 917 } catch (UnknownHostException e) {} 918 return false; 919 } 920 921 /** 922 * Ensure that a network route exists to deliver traffic to the specified 923 * host via the mobile data network. 924 * @param hostAddress the IP address of the host to which the route is desired, 925 * in network byte order. 926 * TODO - deprecate 927 * @return {@code true} on success, {@code false} on failure 928 */ 929 private boolean addHostRoute(NetworkStateTracker nt, InetAddress hostAddress) { 930 if (nt.getNetworkInfo().getType() == ConnectivityManager.TYPE_WIFI) { 931 return false; 932 } 933 934 LinkProperties p = nt.getLinkProperties(); 935 if (p == null) return false; 936 String interfaceName = p.getInterfaceName(); 937 938 if (DBG) { 939 log("Requested host route to " + hostAddress + "(" + interfaceName + ")"); 940 } 941 if (interfaceName != null) { 942 return NetworkUtils.addHostRoute(interfaceName, hostAddress, null); 943 } else { 944 if (DBG) loge("addHostRoute failed due to null interface name"); 945 return false; 946 } 947 } 948 949 /** 950 * @see ConnectivityManager#getBackgroundDataSetting() 951 */ 952 public boolean getBackgroundDataSetting() { 953 return mBackgroundDataEnabled.get(); 954 } 955 956 /** 957 * @see ConnectivityManager#setBackgroundDataSetting(boolean) 958 */ 959 public void setBackgroundDataSetting(boolean allowBackgroundDataUsage) { 960 mContext.enforceCallingOrSelfPermission( 961 android.Manifest.permission.CHANGE_BACKGROUND_DATA_SETTING, 962 "ConnectivityService"); 963 964 mBackgroundDataEnabled.set(allowBackgroundDataUsage); 965 966 mHandler.sendMessage(mHandler.obtainMessage(EVENT_SET_BACKGROUND_DATA, 967 (allowBackgroundDataUsage ? ENABLED : DISABLED), 0)); 968 } 969 970 private void handleSetBackgroundData(boolean enabled) { 971 Settings.Secure.putInt(mContext.getContentResolver(), 972 Settings.Secure.BACKGROUND_DATA, enabled ? 1 : 0); 973 Intent broadcast = new Intent( 974 ConnectivityManager.ACTION_BACKGROUND_DATA_SETTING_CHANGED); 975 mContext.sendBroadcast(broadcast); 976 } 977 978 /** 979 * @see ConnectivityManager#getMobileDataEnabled() 980 */ 981 public boolean getMobileDataEnabled() { 982 // TODO: This detail should probably be in DataConnectionTracker's 983 // which is where we store the value and maybe make this 984 // asynchronous. 985 enforceAccessPermission(); 986 boolean retVal = Settings.Secure.getInt(mContext.getContentResolver(), 987 Settings.Secure.MOBILE_DATA, 1) == 1; 988 if (DBG) log("getMobileDataEnabled returning " + retVal); 989 return retVal; 990 } 991 992 /** 993 * @see ConnectivityManager#setMobileDataEnabled(boolean) 994 */ 995 public void setMobileDataEnabled(boolean enabled) { 996 enforceChangePermission(); 997 if (DBG) log("setMobileDataEnabled(" + enabled + ")"); 998 999 mHandler.sendMessage(mHandler.obtainMessage(EVENT_SET_MOBILE_DATA, 1000 (enabled ? ENABLED : DISABLED), 0)); 1001 } 1002 1003 private void handleSetMobileData(boolean enabled) { 1004 if (mNetTrackers[ConnectivityManager.TYPE_MOBILE] != null) { 1005 if (DBG) { 1006 Slog.d(TAG, mNetTrackers[ConnectivityManager.TYPE_MOBILE].toString() + enabled); 1007 } 1008 mNetTrackers[ConnectivityManager.TYPE_MOBILE].setDataEnable(enabled); 1009 } 1010 } 1011 1012 private void enforceAccessPermission() { 1013 mContext.enforceCallingOrSelfPermission( 1014 android.Manifest.permission.ACCESS_NETWORK_STATE, 1015 "ConnectivityService"); 1016 } 1017 1018 private void enforceChangePermission() { 1019 mContext.enforceCallingOrSelfPermission( 1020 android.Manifest.permission.CHANGE_NETWORK_STATE, 1021 "ConnectivityService"); 1022 } 1023 1024 // TODO Make this a special check when it goes public 1025 private void enforceTetherChangePermission() { 1026 mContext.enforceCallingOrSelfPermission( 1027 android.Manifest.permission.CHANGE_NETWORK_STATE, 1028 "ConnectivityService"); 1029 } 1030 1031 private void enforceTetherAccessPermission() { 1032 mContext.enforceCallingOrSelfPermission( 1033 android.Manifest.permission.ACCESS_NETWORK_STATE, 1034 "ConnectivityService"); 1035 } 1036 1037 private void enforceConnectivityInternalPermission() { 1038 mContext.enforceCallingOrSelfPermission( 1039 android.Manifest.permission.CONNECTIVITY_INTERNAL, 1040 "ConnectivityService"); 1041 } 1042 1043 /** 1044 * Handle a {@code DISCONNECTED} event. If this pertains to the non-active 1045 * network, we ignore it. If it is for the active network, we send out a 1046 * broadcast. But first, we check whether it might be possible to connect 1047 * to a different network. 1048 * @param info the {@code NetworkInfo} for the network 1049 */ 1050 private void handleDisconnect(NetworkInfo info) { 1051 1052 int prevNetType = info.getType(); 1053 1054 mNetTrackers[prevNetType].setTeardownRequested(false); 1055 /* 1056 * If the disconnected network is not the active one, then don't report 1057 * this as a loss of connectivity. What probably happened is that we're 1058 * getting the disconnect for a network that we explicitly disabled 1059 * in accordance with network preference policies. 1060 */ 1061 if (!mNetAttributes[prevNetType].isDefault()) { 1062 List pids = mNetRequestersPids[prevNetType]; 1063 for (int i = 0; i<pids.size(); i++) { 1064 Integer pid = (Integer)pids.get(i); 1065 // will remove them because the net's no longer connected 1066 // need to do this now as only now do we know the pids and 1067 // can properly null things that are no longer referenced. 1068 reassessPidDns(pid.intValue(), false); 1069 } 1070 } 1071 1072 Intent intent = new Intent(ConnectivityManager.CONNECTIVITY_ACTION); 1073 intent.putExtra(ConnectivityManager.EXTRA_NETWORK_INFO, info); 1074 if (info.isFailover()) { 1075 intent.putExtra(ConnectivityManager.EXTRA_IS_FAILOVER, true); 1076 info.setFailover(false); 1077 } 1078 if (info.getReason() != null) { 1079 intent.putExtra(ConnectivityManager.EXTRA_REASON, info.getReason()); 1080 } 1081 if (info.getExtraInfo() != null) { 1082 intent.putExtra(ConnectivityManager.EXTRA_EXTRA_INFO, 1083 info.getExtraInfo()); 1084 } 1085 1086 if (mNetAttributes[prevNetType].isDefault()) { 1087 tryFailover(prevNetType); 1088 if (mActiveDefaultNetwork != -1) { 1089 NetworkInfo switchTo = mNetTrackers[mActiveDefaultNetwork].getNetworkInfo(); 1090 intent.putExtra(ConnectivityManager.EXTRA_OTHER_NETWORK_INFO, switchTo); 1091 } else { 1092 mDefaultInetConditionPublished = 0; // we're not connected anymore 1093 intent.putExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, true); 1094 } 1095 } 1096 intent.putExtra(ConnectivityManager.EXTRA_INET_CONDITION, mDefaultInetConditionPublished); 1097 // do this before we broadcast the change 1098 handleConnectivityChange(prevNetType); 1099 1100 sendStickyBroadcast(intent); 1101 /* 1102 * If the failover network is already connected, then immediately send 1103 * out a followup broadcast indicating successful failover 1104 */ 1105 if (mActiveDefaultNetwork != -1) { 1106 sendConnectedBroadcast(mNetTrackers[mActiveDefaultNetwork].getNetworkInfo()); 1107 } 1108 } 1109 1110 private void tryFailover(int prevNetType) { 1111 /* 1112 * If this is a default network, check if other defaults are available. 1113 * Try to reconnect on all available and let them hash it out when 1114 * more than one connects. 1115 */ 1116 if (mNetAttributes[prevNetType].isDefault()) { 1117 if (mActiveDefaultNetwork == prevNetType) { 1118 mActiveDefaultNetwork = -1; 1119 } 1120 1121 // don't signal a reconnect for anything lower or equal priority than our 1122 // current connected default 1123 // TODO - don't filter by priority now - nice optimization but risky 1124// int currentPriority = -1; 1125// if (mActiveDefaultNetwork != -1) { 1126// currentPriority = mNetAttributes[mActiveDefaultNetwork].mPriority; 1127// } 1128 for (int checkType=0; checkType <= ConnectivityManager.MAX_NETWORK_TYPE; checkType++) { 1129 if (checkType == prevNetType) continue; 1130 if (mNetAttributes[checkType] == null) continue; 1131 if (!mNetAttributes[checkType].isDefault()) continue; 1132 1133// Enabling the isAvailable() optimization caused mobile to not get 1134// selected if it was in the middle of error handling. Specifically 1135// a moble connection that took 30 seconds to complete the DEACTIVATE_DATA_CALL 1136// would not be available and we wouldn't get connected to anything. 1137// So removing the isAvailable() optimization below for now. TODO: This 1138// optimization should work and we need to investigate why it doesn't work. 1139// This could be related to how DEACTIVATE_DATA_CALL is reporting its 1140// complete before it is really complete. 1141// if (!mNetTrackers[checkType].isAvailable()) continue; 1142 1143// if (currentPriority >= mNetAttributes[checkType].mPriority) continue; 1144 1145 NetworkStateTracker checkTracker = mNetTrackers[checkType]; 1146 NetworkInfo checkInfo = checkTracker.getNetworkInfo(); 1147 if (!checkInfo.isConnectedOrConnecting() || checkTracker.isTeardownRequested()) { 1148 checkInfo.setFailover(true); 1149 checkTracker.reconnect(); 1150 } 1151 if (DBG) log("Attempting to switch to " + checkInfo.getTypeName()); 1152 } 1153 } 1154 } 1155 1156 private void sendConnectedBroadcast(NetworkInfo info) { 1157 sendGeneralBroadcast(info, ConnectivityManager.CONNECTIVITY_ACTION); 1158 } 1159 1160 private void sendInetConditionBroadcast(NetworkInfo info) { 1161 sendGeneralBroadcast(info, ConnectivityManager.INET_CONDITION_ACTION); 1162 } 1163 1164 private void sendGeneralBroadcast(NetworkInfo info, String bcastType) { 1165 Intent intent = new Intent(bcastType); 1166 intent.putExtra(ConnectivityManager.EXTRA_NETWORK_INFO, info); 1167 if (info.isFailover()) { 1168 intent.putExtra(ConnectivityManager.EXTRA_IS_FAILOVER, true); 1169 info.setFailover(false); 1170 } 1171 if (info.getReason() != null) { 1172 intent.putExtra(ConnectivityManager.EXTRA_REASON, info.getReason()); 1173 } 1174 if (info.getExtraInfo() != null) { 1175 intent.putExtra(ConnectivityManager.EXTRA_EXTRA_INFO, 1176 info.getExtraInfo()); 1177 } 1178 intent.putExtra(ConnectivityManager.EXTRA_INET_CONDITION, mDefaultInetConditionPublished); 1179 sendStickyBroadcast(intent); 1180 } 1181 1182 /** 1183 * Called when an attempt to fail over to another network has failed. 1184 * @param info the {@link NetworkInfo} for the failed network 1185 */ 1186 private void handleConnectionFailure(NetworkInfo info) { 1187 mNetTrackers[info.getType()].setTeardownRequested(false); 1188 1189 String reason = info.getReason(); 1190 String extraInfo = info.getExtraInfo(); 1191 1192 String reasonText; 1193 if (reason == null) { 1194 reasonText = "."; 1195 } else { 1196 reasonText = " (" + reason + ")."; 1197 } 1198 loge("Attempt to connect to " + info.getTypeName() + " failed" + reasonText); 1199 1200 Intent intent = new Intent(ConnectivityManager.CONNECTIVITY_ACTION); 1201 intent.putExtra(ConnectivityManager.EXTRA_NETWORK_INFO, info); 1202 if (getActiveNetworkInfo() == null) { 1203 intent.putExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, true); 1204 } 1205 if (reason != null) { 1206 intent.putExtra(ConnectivityManager.EXTRA_REASON, reason); 1207 } 1208 if (extraInfo != null) { 1209 intent.putExtra(ConnectivityManager.EXTRA_EXTRA_INFO, extraInfo); 1210 } 1211 if (info.isFailover()) { 1212 intent.putExtra(ConnectivityManager.EXTRA_IS_FAILOVER, true); 1213 info.setFailover(false); 1214 } 1215 1216 if (mNetAttributes[info.getType()].isDefault()) { 1217 tryFailover(info.getType()); 1218 if (mActiveDefaultNetwork != -1) { 1219 NetworkInfo switchTo = mNetTrackers[mActiveDefaultNetwork].getNetworkInfo(); 1220 intent.putExtra(ConnectivityManager.EXTRA_OTHER_NETWORK_INFO, switchTo); 1221 } else { 1222 mDefaultInetConditionPublished = 0; 1223 intent.putExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, true); 1224 } 1225 } 1226 1227 intent.putExtra(ConnectivityManager.EXTRA_INET_CONDITION, mDefaultInetConditionPublished); 1228 sendStickyBroadcast(intent); 1229 /* 1230 * If the failover network is already connected, then immediately send 1231 * out a followup broadcast indicating successful failover 1232 */ 1233 if (mActiveDefaultNetwork != -1) { 1234 sendConnectedBroadcast(mNetTrackers[mActiveDefaultNetwork].getNetworkInfo()); 1235 } 1236 } 1237 1238 private void sendStickyBroadcast(Intent intent) { 1239 synchronized(this) { 1240 if (!mSystemReady) { 1241 mInitialBroadcast = new Intent(intent); 1242 } 1243 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 1244 mContext.sendStickyBroadcast(intent); 1245 } 1246 } 1247 1248 void systemReady() { 1249 synchronized(this) { 1250 mSystemReady = true; 1251 if (mInitialBroadcast != null) { 1252 mContext.sendStickyBroadcast(mInitialBroadcast); 1253 mInitialBroadcast = null; 1254 } 1255 } 1256 // load the global proxy at startup 1257 mHandler.sendMessage(mHandler.obtainMessage(EVENT_APPLY_GLOBAL_HTTP_PROXY)); 1258 } 1259 1260 private void handleConnect(NetworkInfo info) { 1261 int type = info.getType(); 1262 1263 // snapshot isFailover, because sendConnectedBroadcast() resets it 1264 boolean isFailover = info.isFailover(); 1265 NetworkStateTracker thisNet = mNetTrackers[type]; 1266 1267 // if this is a default net and other default is running 1268 // kill the one not preferred 1269 if (mNetAttributes[type].isDefault()) { 1270 if (mActiveDefaultNetwork != -1 && mActiveDefaultNetwork != type) { 1271 if ((type != mNetworkPreference && 1272 mNetAttributes[mActiveDefaultNetwork].mPriority > 1273 mNetAttributes[type].mPriority) || 1274 mNetworkPreference == mActiveDefaultNetwork) { 1275 // don't accept this one 1276 if (DBG) { 1277 log("Not broadcasting CONNECT_ACTION " + 1278 "to torn down network " + info.getTypeName()); 1279 } 1280 teardown(thisNet); 1281 return; 1282 } else { 1283 // tear down the other 1284 NetworkStateTracker otherNet = 1285 mNetTrackers[mActiveDefaultNetwork]; 1286 if (DBG) { 1287 log("Policy requires " + otherNet.getNetworkInfo().getTypeName() + 1288 " teardown"); 1289 } 1290 if (!teardown(otherNet)) { 1291 loge("Network declined teardown request"); 1292 return; 1293 } 1294 } 1295 } 1296 synchronized (ConnectivityService.this) { 1297 // have a new default network, release the transition wakelock in a second 1298 // if it's held. The second pause is to allow apps to reconnect over the 1299 // new network 1300 if (mNetTransitionWakeLock.isHeld()) { 1301 mHandler.sendMessageDelayed(mHandler.obtainMessage( 1302 EVENT_CLEAR_NET_TRANSITION_WAKELOCK, 1303 mNetTransitionWakeLockSerialNumber, 0), 1304 1000); 1305 } 1306 } 1307 mActiveDefaultNetwork = type; 1308 // this will cause us to come up initially as unconnected and switching 1309 // to connected after our normal pause unless somebody reports us as reall 1310 // disconnected 1311 mDefaultInetConditionPublished = 0; 1312 mDefaultConnectionSequence++; 1313 mInetConditionChangeInFlight = false; 1314 // Don't do this - if we never sign in stay, grey 1315 //reportNetworkCondition(mActiveDefaultNetwork, 100); 1316 } 1317 thisNet.setTeardownRequested(false); 1318 updateNetworkSettings(thisNet); 1319 handleConnectivityChange(type); 1320 sendConnectedBroadcast(info); 1321 } 1322 1323 /** 1324 * After a change in the connectivity state of a network. We're mainly 1325 * concerned with making sure that the list of DNS servers is set up 1326 * according to which networks are connected, and ensuring that the 1327 * right routing table entries exist. 1328 */ 1329 private void handleConnectivityChange(int netType) { 1330 /* 1331 * If a non-default network is enabled, add the host routes that 1332 * will allow it's DNS servers to be accessed. 1333 */ 1334 handleDnsConfigurationChange(netType); 1335 1336 if (mNetTrackers[netType].getNetworkInfo().isConnected()) { 1337 if (mNetAttributes[netType].isDefault()) { 1338 handleApplyDefaultProxy(netType); 1339 addDefaultRoute(mNetTrackers[netType]); 1340 } else { 1341 // many radios add a default route even when we don't want one. 1342 // remove the default interface unless we need it for our active network 1343 if (mActiveDefaultNetwork != -1) { 1344 LinkProperties linkProperties = 1345 mNetTrackers[mActiveDefaultNetwork].getLinkProperties(); 1346 LinkProperties newLinkProperties = 1347 mNetTrackers[netType].getLinkProperties(); 1348 String defaultIface = linkProperties.getInterfaceName(); 1349 if (defaultIface != null && 1350 !defaultIface.equals(newLinkProperties.getInterfaceName())) { 1351 mNetTrackers[netType].removeDefaultRoute(); 1352 } 1353 } 1354 mNetTrackers[netType].addPrivateDnsRoutes(); 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 if (TextUtils.isEmpty(interfaceName)) return; 1408 for (InetAddress gateway : p.getGateways()) { 1409 1410 if (NetworkUtils.addHostRoute(interfaceName, gateway, null) && 1411 NetworkUtils.addDefaultRoute(interfaceName, gateway)) { 1412 if (DBG) { 1413 NetworkInfo networkInfo = nt.getNetworkInfo(); 1414 log("addDefaultRoute for " + networkInfo.getTypeName() + 1415 " (" + interfaceName + "), GatewayAddr=" + gateway.getHostAddress()); 1416 } 1417 } 1418 } 1419 } 1420 1421 1422 public void removeDefaultRoute(NetworkStateTracker nt) { 1423 LinkProperties p = nt.getLinkProperties(); 1424 if (p == null) return; 1425 String interfaceName = p.getInterfaceName(); 1426 1427 if (interfaceName != null) { 1428 if (NetworkUtils.removeDefaultRoute(interfaceName) >= 0) { 1429 if (DBG) { 1430 NetworkInfo networkInfo = nt.getNetworkInfo(); 1431 log("removeDefaultRoute for " + networkInfo.getTypeName() + " (" + 1432 interfaceName + ")"); 1433 } 1434 } 1435 } 1436 } 1437 1438 /** 1439 * Reads the network specific TCP buffer sizes from SystemProperties 1440 * net.tcp.buffersize.[default|wifi|umts|edge|gprs] and set them for system 1441 * wide use 1442 */ 1443 public void updateNetworkSettings(NetworkStateTracker nt) { 1444 String key = nt.getTcpBufferSizesPropName(); 1445 String bufferSizes = SystemProperties.get(key); 1446 1447 if (bufferSizes.length() == 0) { 1448 loge(key + " not found in system properties. Using defaults"); 1449 1450 // Setting to default values so we won't be stuck to previous values 1451 key = "net.tcp.buffersize.default"; 1452 bufferSizes = SystemProperties.get(key); 1453 } 1454 1455 // Set values in kernel 1456 if (bufferSizes.length() != 0) { 1457 if (DBG) { 1458 log("Setting TCP values: [" + bufferSizes 1459 + "] which comes from [" + key + "]"); 1460 } 1461 setBufferSize(bufferSizes); 1462 } 1463 } 1464 1465 /** 1466 * Writes TCP buffer sizes to /sys/kernel/ipv4/tcp_[r/w]mem_[min/def/max] 1467 * which maps to /proc/sys/net/ipv4/tcp_rmem and tcpwmem 1468 * 1469 * @param bufferSizes in the format of "readMin, readInitial, readMax, 1470 * writeMin, writeInitial, writeMax" 1471 */ 1472 private void setBufferSize(String bufferSizes) { 1473 try { 1474 String[] values = bufferSizes.split(","); 1475 1476 if (values.length == 6) { 1477 final String prefix = "/sys/kernel/ipv4/tcp_"; 1478 stringToFile(prefix + "rmem_min", values[0]); 1479 stringToFile(prefix + "rmem_def", values[1]); 1480 stringToFile(prefix + "rmem_max", values[2]); 1481 stringToFile(prefix + "wmem_min", values[3]); 1482 stringToFile(prefix + "wmem_def", values[4]); 1483 stringToFile(prefix + "wmem_max", values[5]); 1484 } else { 1485 loge("Invalid buffersize string: " + bufferSizes); 1486 } 1487 } catch (IOException e) { 1488 loge("Can't set tcp buffer sizes:" + e); 1489 } 1490 } 1491 1492 /** 1493 * Writes string to file. Basically same as "echo -n $string > $filename" 1494 * 1495 * @param filename 1496 * @param string 1497 * @throws IOException 1498 */ 1499 private void stringToFile(String filename, String string) throws IOException { 1500 FileWriter out = new FileWriter(filename); 1501 try { 1502 out.write(string); 1503 } finally { 1504 out.close(); 1505 } 1506 } 1507 1508 1509 /** 1510 * Adjust the per-process dns entries (net.dns<x>.<pid>) based 1511 * on the highest priority active net which this process requested. 1512 * If there aren't any, clear it out 1513 */ 1514 private void reassessPidDns(int myPid, boolean doBump) 1515 { 1516 if (DBG) log("reassessPidDns for pid " + myPid); 1517 for(int i : mPriorityList) { 1518 if (mNetAttributes[i].isDefault()) { 1519 continue; 1520 } 1521 NetworkStateTracker nt = mNetTrackers[i]; 1522 if (nt.getNetworkInfo().isConnected() && 1523 !nt.isTeardownRequested()) { 1524 LinkProperties p = nt.getLinkProperties(); 1525 if (p == null) continue; 1526 List pids = mNetRequestersPids[i]; 1527 for (int j=0; j<pids.size(); j++) { 1528 Integer pid = (Integer)pids.get(j); 1529 if (pid.intValue() == myPid) { 1530 Collection<InetAddress> dnses = p.getDnses(); 1531 writePidDns(dnses, myPid); 1532 if (doBump) { 1533 bumpDns(); 1534 } 1535 return; 1536 } 1537 } 1538 } 1539 } 1540 // nothing found - delete 1541 for (int i = 1; ; i++) { 1542 String prop = "net.dns" + i + "." + myPid; 1543 if (SystemProperties.get(prop).length() == 0) { 1544 if (doBump) { 1545 bumpDns(); 1546 } 1547 return; 1548 } 1549 SystemProperties.set(prop, ""); 1550 } 1551 } 1552 1553 // return true if results in a change 1554 private boolean writePidDns(Collection <InetAddress> dnses, int pid) { 1555 int j = 1; 1556 boolean changed = false; 1557 for (InetAddress dns : dnses) { 1558 String dnsString = dns.getHostAddress(); 1559 if (changed || !dnsString.equals(SystemProperties.get("net.dns" + j + "." + pid))) { 1560 changed = true; 1561 SystemProperties.set("net.dns" + j++ + "." + pid, dns.getHostAddress()); 1562 } 1563 } 1564 return changed; 1565 } 1566 1567 private void bumpDns() { 1568 /* 1569 * Bump the property that tells the name resolver library to reread 1570 * the DNS server list from the properties. 1571 */ 1572 String propVal = SystemProperties.get("net.dnschange"); 1573 int n = 0; 1574 if (propVal.length() != 0) { 1575 try { 1576 n = Integer.parseInt(propVal); 1577 } catch (NumberFormatException e) {} 1578 } 1579 SystemProperties.set("net.dnschange", "" + (n+1)); 1580 /* 1581 * Tell the VMs to toss their DNS caches 1582 */ 1583 Intent intent = new Intent(Intent.ACTION_CLEAR_DNS_CACHE); 1584 intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING); 1585 /* 1586 * Connectivity events can happen before boot has completed ... 1587 */ 1588 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 1589 mContext.sendBroadcast(intent); 1590 } 1591 1592 private void handleDnsConfigurationChange(int netType) { 1593 // add default net's dns entries 1594 NetworkStateTracker nt = mNetTrackers[netType]; 1595 if (nt != null && nt.getNetworkInfo().isConnected() && !nt.isTeardownRequested()) { 1596 LinkProperties p = nt.getLinkProperties(); 1597 if (p == null) return; 1598 Collection<InetAddress> dnses = p.getDnses(); 1599 boolean changed = false; 1600 if (mNetAttributes[netType].isDefault()) { 1601 int j = 1; 1602 if (dnses.size() == 0 && mDefaultDns != null) { 1603 String dnsString = mDefaultDns.getHostAddress(); 1604 if (!dnsString.equals(SystemProperties.get("net.dns1"))) { 1605 if (DBG) { 1606 log("no dns provided - using " + dnsString); 1607 } 1608 changed = true; 1609 SystemProperties.set("net.dns1", dnsString); 1610 } 1611 j++; 1612 } else { 1613 for (InetAddress dns : dnses) { 1614 String dnsString = dns.getHostAddress(); 1615 if (!changed && dnsString.equals(SystemProperties.get("net.dns" + j))) { 1616 j++; 1617 continue; 1618 } 1619 if (DBG) { 1620 log("adding dns " + dns + " for " + 1621 nt.getNetworkInfo().getTypeName()); 1622 } 1623 changed = true; 1624 SystemProperties.set("net.dns" + j++, dnsString); 1625 } 1626 } 1627 for (int k=j ; k<mNumDnsEntries; k++) { 1628 if (changed || !TextUtils.isEmpty(SystemProperties.get("net.dns" + k))) { 1629 if (DBG) log("erasing net.dns" + k); 1630 changed = true; 1631 SystemProperties.set("net.dns" + k, ""); 1632 } 1633 } 1634 mNumDnsEntries = j; 1635 } else { 1636 // set per-pid dns for attached secondary nets 1637 List pids = mNetRequestersPids[netType]; 1638 for (int y=0; y< pids.size(); y++) { 1639 Integer pid = (Integer)pids.get(y); 1640 changed = writePidDns(dnses, pid.intValue()); 1641 } 1642 } 1643 if (changed) bumpDns(); 1644 } 1645 } 1646 1647 private int getRestoreDefaultNetworkDelay() { 1648 String restoreDefaultNetworkDelayStr = SystemProperties.get( 1649 NETWORK_RESTORE_DELAY_PROP_NAME); 1650 if(restoreDefaultNetworkDelayStr != null && 1651 restoreDefaultNetworkDelayStr.length() != 0) { 1652 try { 1653 return Integer.valueOf(restoreDefaultNetworkDelayStr); 1654 } catch (NumberFormatException e) { 1655 } 1656 } 1657 return RESTORE_DEFAULT_NETWORK_DELAY; 1658 } 1659 1660 @Override 1661 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 1662 if (mContext.checkCallingOrSelfPermission( 1663 android.Manifest.permission.DUMP) 1664 != PackageManager.PERMISSION_GRANTED) { 1665 pw.println("Permission Denial: can't dump ConnectivityService " + 1666 "from from pid=" + Binder.getCallingPid() + ", uid=" + 1667 Binder.getCallingUid()); 1668 return; 1669 } 1670 pw.println(); 1671 for (NetworkStateTracker nst : mNetTrackers) { 1672 if (nst != null) { 1673 if (nst.getNetworkInfo().isConnected()) { 1674 pw.println("Active network: " + nst.getNetworkInfo(). 1675 getTypeName()); 1676 } 1677 pw.println(nst.getNetworkInfo()); 1678 pw.println(nst); 1679 pw.println(); 1680 } 1681 } 1682 1683 pw.println("Network Requester Pids:"); 1684 for (int net : mPriorityList) { 1685 String pidString = net + ": "; 1686 for (Object pid : mNetRequestersPids[net]) { 1687 pidString = pidString + pid.toString() + ", "; 1688 } 1689 pw.println(pidString); 1690 } 1691 pw.println(); 1692 1693 pw.println("FeatureUsers:"); 1694 for (Object requester : mFeatureUsers) { 1695 pw.println(requester.toString()); 1696 } 1697 pw.println(); 1698 1699 synchronized (this) { 1700 pw.println("NetworkTranstionWakeLock is currently " + 1701 (mNetTransitionWakeLock.isHeld() ? "" : "not ") + "held."); 1702 pw.println("It was last requested for "+mNetTransitionWakeLockCausedBy); 1703 } 1704 pw.println(); 1705 1706 mTethering.dump(fd, pw, args); 1707 1708 if (mInetLog != null) { 1709 pw.println(); 1710 pw.println("Inet condition reports:"); 1711 for(int i = 0; i < mInetLog.size(); i++) { 1712 pw.println(mInetLog.get(i)); 1713 } 1714 } 1715 } 1716 1717 // must be stateless - things change under us. 1718 private class MyHandler extends Handler { 1719 public MyHandler(Looper looper) { 1720 super(looper); 1721 } 1722 1723 @Override 1724 public void handleMessage(Message msg) { 1725 NetworkInfo info; 1726 switch (msg.what) { 1727 case NetworkStateTracker.EVENT_STATE_CHANGED: 1728 info = (NetworkInfo) msg.obj; 1729 int type = info.getType(); 1730 NetworkInfo.State state = info.getState(); 1731 // only do this optimization for wifi. It going into scan mode for location 1732 // services generates alot of noise. Meanwhile the mms apn won't send out 1733 // subsequent notifications when on default cellular because it never 1734 // disconnects.. so only do this to wifi notifications. Fixed better when the 1735 // APN notifications are standardized. 1736 if (mNetAttributes[type].mLastState == state && 1737 mNetAttributes[type].mRadio == ConnectivityManager.TYPE_WIFI) { 1738 if (DBG) { 1739 // TODO - remove this after we validate the dropping doesn't break 1740 // anything 1741 log("Dropping ConnectivityChange for " + 1742 info.getTypeName() + ": " + 1743 state + "/" + info.getDetailedState()); 1744 } 1745 return; 1746 } 1747 mNetAttributes[type].mLastState = state; 1748 1749 if (DBG) log("ConnectivityChange for " + 1750 info.getTypeName() + ": " + 1751 state + "/" + info.getDetailedState()); 1752 1753 // Connectivity state changed: 1754 // [31-13] Reserved for future use 1755 // [12-9] Network subtype (for mobile network, as defined 1756 // by TelephonyManager) 1757 // [8-3] Detailed state ordinal (as defined by 1758 // NetworkInfo.DetailedState) 1759 // [2-0] Network type (as defined by ConnectivityManager) 1760 int eventLogParam = (info.getType() & 0x7) | 1761 ((info.getDetailedState().ordinal() & 0x3f) << 3) | 1762 (info.getSubtype() << 9); 1763 EventLog.writeEvent(EventLogTags.CONNECTIVITY_STATE_CHANGED, 1764 eventLogParam); 1765 1766 if (info.getDetailedState() == 1767 NetworkInfo.DetailedState.FAILED) { 1768 handleConnectionFailure(info); 1769 } else if (state == NetworkInfo.State.DISCONNECTED) { 1770 handleDisconnect(info); 1771 } else if (state == NetworkInfo.State.SUSPENDED) { 1772 // TODO: need to think this over. 1773 // the logic here is, handle SUSPENDED the same as 1774 // DISCONNECTED. The only difference being we are 1775 // broadcasting an intent with NetworkInfo that's 1776 // suspended. This allows the applications an 1777 // opportunity to handle DISCONNECTED and SUSPENDED 1778 // differently, or not. 1779 handleDisconnect(info); 1780 } else if (state == NetworkInfo.State.CONNECTED) { 1781 handleConnect(info); 1782 } 1783 break; 1784 case NetworkStateTracker.EVENT_CONFIGURATION_CHANGED: 1785 info = (NetworkInfo) msg.obj; 1786 type = info.getType(); 1787 handleConnectivityChange(type); 1788 break; 1789 case EVENT_CLEAR_NET_TRANSITION_WAKELOCK: 1790 String causedBy = null; 1791 synchronized (ConnectivityService.this) { 1792 if (msg.arg1 == mNetTransitionWakeLockSerialNumber && 1793 mNetTransitionWakeLock.isHeld()) { 1794 mNetTransitionWakeLock.release(); 1795 causedBy = mNetTransitionWakeLockCausedBy; 1796 } 1797 } 1798 if (causedBy != null) { 1799 log("NetTransition Wakelock for " + causedBy + " released by timeout"); 1800 } 1801 break; 1802 case EVENT_RESTORE_DEFAULT_NETWORK: 1803 FeatureUser u = (FeatureUser)msg.obj; 1804 u.expire(); 1805 break; 1806 case EVENT_INET_CONDITION_CHANGE: 1807 { 1808 int netType = msg.arg1; 1809 int condition = msg.arg2; 1810 handleInetConditionChange(netType, condition); 1811 break; 1812 } 1813 case EVENT_INET_CONDITION_HOLD_END: 1814 { 1815 int netType = msg.arg1; 1816 int sequence = msg.arg2; 1817 handleInetConditionHoldEnd(netType, sequence); 1818 break; 1819 } 1820 case EVENT_SET_NETWORK_PREFERENCE: 1821 { 1822 int preference = msg.arg1; 1823 handleSetNetworkPreference(preference); 1824 break; 1825 } 1826 case EVENT_SET_BACKGROUND_DATA: 1827 { 1828 boolean enabled = (msg.arg1 == ENABLED); 1829 handleSetBackgroundData(enabled); 1830 break; 1831 } 1832 case EVENT_SET_MOBILE_DATA: 1833 { 1834 boolean enabled = (msg.arg1 == ENABLED); 1835 handleSetMobileData(enabled); 1836 break; 1837 } 1838 case EVENT_APPLY_GLOBAL_HTTP_PROXY: 1839 { 1840 handleDeprecatedGlobalHttpProxy(); 1841 } 1842 } 1843 } 1844 } 1845 1846 // javadoc from interface 1847 public int tether(String iface) { 1848 enforceTetherChangePermission(); 1849 1850 if (isTetheringSupported()) { 1851 return mTethering.tether(iface); 1852 } else { 1853 return ConnectivityManager.TETHER_ERROR_UNSUPPORTED; 1854 } 1855 } 1856 1857 // javadoc from interface 1858 public int untether(String iface) { 1859 enforceTetherChangePermission(); 1860 1861 if (isTetheringSupported()) { 1862 return mTethering.untether(iface); 1863 } else { 1864 return ConnectivityManager.TETHER_ERROR_UNSUPPORTED; 1865 } 1866 } 1867 1868 // javadoc from interface 1869 public int getLastTetherError(String iface) { 1870 enforceTetherAccessPermission(); 1871 1872 if (isTetheringSupported()) { 1873 return mTethering.getLastTetherError(iface); 1874 } else { 1875 return ConnectivityManager.TETHER_ERROR_UNSUPPORTED; 1876 } 1877 } 1878 1879 // TODO - proper iface API for selection by property, inspection, etc 1880 public String[] getTetherableUsbRegexs() { 1881 enforceTetherAccessPermission(); 1882 if (isTetheringSupported()) { 1883 return mTethering.getTetherableUsbRegexs(); 1884 } else { 1885 return new String[0]; 1886 } 1887 } 1888 1889 public String[] getTetherableWifiRegexs() { 1890 enforceTetherAccessPermission(); 1891 if (isTetheringSupported()) { 1892 return mTethering.getTetherableWifiRegexs(); 1893 } else { 1894 return new String[0]; 1895 } 1896 } 1897 1898 public String[] getTetherableBluetoothRegexs() { 1899 enforceTetherAccessPermission(); 1900 if (isTetheringSupported()) { 1901 return mTethering.getTetherableBluetoothRegexs(); 1902 } else { 1903 return new String[0]; 1904 } 1905 } 1906 1907 // TODO - move iface listing, queries, etc to new module 1908 // javadoc from interface 1909 public String[] getTetherableIfaces() { 1910 enforceTetherAccessPermission(); 1911 return mTethering.getTetherableIfaces(); 1912 } 1913 1914 public String[] getTetheredIfaces() { 1915 enforceTetherAccessPermission(); 1916 return mTethering.getTetheredIfaces(); 1917 } 1918 1919 public String[] getTetheringErroredIfaces() { 1920 enforceTetherAccessPermission(); 1921 return mTethering.getErroredIfaces(); 1922 } 1923 1924 // if ro.tether.denied = true we default to no tethering 1925 // gservices could set the secure setting to 1 though to enable it on a build where it 1926 // had previously been turned off. 1927 public boolean isTetheringSupported() { 1928 enforceTetherAccessPermission(); 1929 int defaultVal = (SystemProperties.get("ro.tether.denied").equals("true") ? 0 : 1); 1930 boolean tetherEnabledInSettings = (Settings.Secure.getInt(mContext.getContentResolver(), 1931 Settings.Secure.TETHER_SUPPORTED, defaultVal) != 0); 1932 return tetherEnabledInSettings && mTetheringConfigValid; 1933 } 1934 1935 // An API NetworkStateTrackers can call when they lose their network. 1936 // This will automatically be cleared after X seconds or a network becomes CONNECTED, 1937 // whichever happens first. The timer is started by the first caller and not 1938 // restarted by subsequent callers. 1939 public void requestNetworkTransitionWakelock(String forWhom) { 1940 enforceConnectivityInternalPermission(); 1941 synchronized (this) { 1942 if (mNetTransitionWakeLock.isHeld()) return; 1943 mNetTransitionWakeLockSerialNumber++; 1944 mNetTransitionWakeLock.acquire(); 1945 mNetTransitionWakeLockCausedBy = forWhom; 1946 } 1947 mHandler.sendMessageDelayed(mHandler.obtainMessage( 1948 EVENT_CLEAR_NET_TRANSITION_WAKELOCK, 1949 mNetTransitionWakeLockSerialNumber, 0), 1950 mNetTransitionWakeLockTimeout); 1951 return; 1952 } 1953 1954 // 100 percent is full good, 0 is full bad. 1955 public void reportInetCondition(int networkType, int percentage) { 1956 if (DBG) log("reportNetworkCondition(" + networkType + ", " + percentage + ")"); 1957 mContext.enforceCallingOrSelfPermission( 1958 android.Manifest.permission.STATUS_BAR, 1959 "ConnectivityService"); 1960 1961 if (DBG) { 1962 int pid = getCallingPid(); 1963 int uid = getCallingUid(); 1964 String s = pid + "(" + uid + ") reports inet is " + 1965 (percentage > 50 ? "connected" : "disconnected") + " (" + percentage + ") on " + 1966 "network Type " + networkType + " at " + GregorianCalendar.getInstance().getTime(); 1967 mInetLog.add(s); 1968 while(mInetLog.size() > INET_CONDITION_LOG_MAX_SIZE) { 1969 mInetLog.remove(0); 1970 } 1971 } 1972 mHandler.sendMessage(mHandler.obtainMessage( 1973 EVENT_INET_CONDITION_CHANGE, networkType, percentage)); 1974 } 1975 1976 private void handleInetConditionChange(int netType, int condition) { 1977 if (DBG) { 1978 log("Inet connectivity change, net=" + 1979 netType + ", condition=" + condition + 1980 ",mActiveDefaultNetwork=" + mActiveDefaultNetwork); 1981 } 1982 if (mActiveDefaultNetwork == -1) { 1983 if (DBG) log("no active default network - aborting"); 1984 return; 1985 } 1986 if (mActiveDefaultNetwork != netType) { 1987 if (DBG) log("given net not default - aborting"); 1988 return; 1989 } 1990 mDefaultInetCondition = condition; 1991 int delay; 1992 if (mInetConditionChangeInFlight == false) { 1993 if (DBG) log("starting a change hold"); 1994 // setup a new hold to debounce this 1995 if (mDefaultInetCondition > 50) { 1996 delay = Settings.Secure.getInt(mContext.getContentResolver(), 1997 Settings.Secure.INET_CONDITION_DEBOUNCE_UP_DELAY, 500); 1998 } else { 1999 delay = Settings.Secure.getInt(mContext.getContentResolver(), 2000 Settings.Secure.INET_CONDITION_DEBOUNCE_DOWN_DELAY, 3000); 2001 } 2002 mInetConditionChangeInFlight = true; 2003 mHandler.sendMessageDelayed(mHandler.obtainMessage(EVENT_INET_CONDITION_HOLD_END, 2004 mActiveDefaultNetwork, mDefaultConnectionSequence), delay); 2005 } else { 2006 // we've set the new condition, when this hold ends that will get 2007 // picked up 2008 if (DBG) log("currently in hold - not setting new end evt"); 2009 } 2010 } 2011 2012 private void handleInetConditionHoldEnd(int netType, int sequence) { 2013 if (DBG) { 2014 log("Inet hold end, net=" + netType + 2015 ", condition =" + mDefaultInetCondition + 2016 ", published condition =" + mDefaultInetConditionPublished); 2017 } 2018 mInetConditionChangeInFlight = false; 2019 2020 if (mActiveDefaultNetwork == -1) { 2021 if (DBG) log("no active default network - aborting"); 2022 return; 2023 } 2024 if (mDefaultConnectionSequence != sequence) { 2025 if (DBG) log("event hold for obsolete network - aborting"); 2026 return; 2027 } 2028 if (mDefaultInetConditionPublished == mDefaultInetCondition) { 2029 if (DBG) log("no change in condition - aborting"); 2030 return; 2031 } 2032 NetworkInfo networkInfo = mNetTrackers[mActiveDefaultNetwork].getNetworkInfo(); 2033 if (networkInfo.isConnected() == false) { 2034 if (DBG) log("default network not connected - aborting"); 2035 return; 2036 } 2037 mDefaultInetConditionPublished = mDefaultInetCondition; 2038 sendInetConditionBroadcast(networkInfo); 2039 return; 2040 } 2041 2042 public synchronized ProxyProperties getProxy() { 2043 if (mGlobalProxy != null) return mGlobalProxy; 2044 if (mDefaultProxy != null) return mDefaultProxy; 2045 return null; 2046 } 2047 2048 public void setGlobalProxy(ProxyProperties proxyProperties) { 2049 enforceChangePermission(); 2050 synchronized (mGlobalProxyLock) { 2051 if (proxyProperties == mGlobalProxy) return; 2052 if (proxyProperties != null && proxyProperties.equals(mGlobalProxy)) return; 2053 if (mGlobalProxy != null && mGlobalProxy.equals(proxyProperties)) return; 2054 2055 String host = ""; 2056 int port = 0; 2057 String exclList = ""; 2058 if (proxyProperties != null && !TextUtils.isEmpty(proxyProperties.getHost())) { 2059 mGlobalProxy = new ProxyProperties(proxyProperties); 2060 host = mGlobalProxy.getHost(); 2061 port = mGlobalProxy.getPort(); 2062 exclList = mGlobalProxy.getExclusionList(); 2063 } else { 2064 mGlobalProxy = null; 2065 } 2066 ContentResolver res = mContext.getContentResolver(); 2067 Settings.Secure.putString(res, Settings.Secure.GLOBAL_HTTP_PROXY_HOST, host); 2068 Settings.Secure.putInt(res, Settings.Secure.GLOBAL_HTTP_PROXY_PORT, port); 2069 Settings.Secure.putString(res, Settings.Secure.GLOBAL_HTTP_PROXY_EXCLUSION_LIST, 2070 exclList); 2071 } 2072 2073 if (mGlobalProxy == null) { 2074 proxyProperties = mDefaultProxy; 2075 } 2076 sendProxyBroadcast(proxyProperties); 2077 } 2078 2079 private void loadGlobalProxy() { 2080 ContentResolver res = mContext.getContentResolver(); 2081 String host = Settings.Secure.getString(res, Settings.Secure.GLOBAL_HTTP_PROXY_HOST); 2082 int port = Settings.Secure.getInt(res, Settings.Secure.GLOBAL_HTTP_PROXY_PORT, 0); 2083 String exclList = Settings.Secure.getString(res, 2084 Settings.Secure.GLOBAL_HTTP_PROXY_EXCLUSION_LIST); 2085 if (!TextUtils.isEmpty(host)) { 2086 ProxyProperties proxyProperties = new ProxyProperties(host, port, exclList); 2087 synchronized (mGlobalProxyLock) { 2088 mGlobalProxy = proxyProperties; 2089 } 2090 } 2091 } 2092 2093 public ProxyProperties getGlobalProxy() { 2094 synchronized (mGlobalProxyLock) { 2095 return mGlobalProxy; 2096 } 2097 } 2098 2099 private void handleApplyDefaultProxy(int type) { 2100 // check if new default - push it out to all VM if so 2101 ProxyProperties proxy = mNetTrackers[type].getLinkProperties().getHttpProxy(); 2102 synchronized (this) { 2103 if (mDefaultProxy != null && mDefaultProxy.equals(proxy)) return; 2104 if (mDefaultProxy == proxy) return; 2105 if (!TextUtils.isEmpty(proxy.getHost())) { 2106 mDefaultProxy = proxy; 2107 } else { 2108 mDefaultProxy = null; 2109 } 2110 } 2111 if (DBG) log("changing default proxy to " + proxy); 2112 if ((proxy == null && mGlobalProxy == null) || proxy.equals(mGlobalProxy)) return; 2113 if (mGlobalProxy != null) return; 2114 sendProxyBroadcast(proxy); 2115 } 2116 2117 private void handleDeprecatedGlobalHttpProxy() { 2118 String proxy = Settings.Secure.getString(mContext.getContentResolver(), 2119 Settings.Secure.HTTP_PROXY); 2120 if (!TextUtils.isEmpty(proxy)) { 2121 String data[] = proxy.split(":"); 2122 String proxyHost = data[0]; 2123 int proxyPort = 8080; 2124 if (data.length > 1) { 2125 try { 2126 proxyPort = Integer.parseInt(data[1]); 2127 } catch (NumberFormatException e) { 2128 return; 2129 } 2130 } 2131 ProxyProperties p = new ProxyProperties(data[0], proxyPort, ""); 2132 setGlobalProxy(p); 2133 } 2134 } 2135 2136 private void sendProxyBroadcast(ProxyProperties proxy) { 2137 if (proxy == null) proxy = new ProxyProperties("", 0, ""); 2138 log("sending Proxy Broadcast for " + proxy); 2139 Intent intent = new Intent(Proxy.PROXY_CHANGE_ACTION); 2140 intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING | 2141 Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 2142 intent.putExtra(Proxy.EXTRA_PROXY_INFO, proxy); 2143 mContext.sendStickyBroadcast(intent); 2144 } 2145 2146 private static class SettingsObserver extends ContentObserver { 2147 private int mWhat; 2148 private Handler mHandler; 2149 SettingsObserver(Handler handler, int what) { 2150 super(handler); 2151 mHandler = handler; 2152 mWhat = what; 2153 } 2154 2155 void observe(Context context) { 2156 ContentResolver resolver = context.getContentResolver(); 2157 resolver.registerContentObserver(Settings.Secure.getUriFor( 2158 Settings.Secure.HTTP_PROXY), false, this); 2159 } 2160 2161 @Override 2162 public void onChange(boolean selfChange) { 2163 mHandler.obtainMessage(mWhat).sendToTarget(); 2164 } 2165 } 2166 2167 private void log(String s) { 2168 Slog.d(TAG, s); 2169 } 2170 2171 private void loge(String s) { 2172 Slog.e(TAG, s); 2173 } 2174 int convertFeatureToNetworkType(String feature){ 2175 int networkType = -1; 2176 if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_MMS)) { 2177 networkType = ConnectivityManager.TYPE_MOBILE_MMS; 2178 } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_SUPL)) { 2179 networkType = ConnectivityManager.TYPE_MOBILE_SUPL; 2180 } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_DUN) || 2181 TextUtils.equals(feature, Phone.FEATURE_ENABLE_DUN_ALWAYS)) { 2182 networkType = ConnectivityManager.TYPE_MOBILE_DUN; 2183 } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_HIPRI)) { 2184 networkType = ConnectivityManager.TYPE_MOBILE_HIPRI; 2185 } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_FOTA)) { 2186 networkType = ConnectivityManager.TYPE_MOBILE_FOTA; 2187 } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_IMS)) { 2188 networkType = ConnectivityManager.TYPE_MOBILE_IMS; 2189 } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_CBS)) { 2190 networkType = ConnectivityManager.TYPE_MOBILE_CBS; 2191 } 2192 return networkType; 2193 } 2194} 2195