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