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