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