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 17 package com.android.server; 18 19 import static android.Manifest.permission.MANAGE_NETWORK_POLICY; 20 import static android.Manifest.permission.RECEIVE_DATA_ACTIVITY_CHANGE; 21 import static android.net.ConnectivityManager.CONNECTIVITY_ACTION; 22 import static android.net.ConnectivityManager.CONNECTIVITY_ACTION_IMMEDIATE; 23 import static android.net.ConnectivityManager.TYPE_BLUETOOTH; 24 import static android.net.ConnectivityManager.TYPE_DUMMY; 25 import static android.net.ConnectivityManager.TYPE_ETHERNET; 26 import static android.net.ConnectivityManager.TYPE_MOBILE; 27 import static android.net.ConnectivityManager.TYPE_WIFI; 28 import static android.net.ConnectivityManager.TYPE_WIMAX; 29 import static android.net.ConnectivityManager.getNetworkTypeName; 30 import static android.net.ConnectivityManager.isNetworkTypeValid; 31 import static android.net.NetworkPolicyManager.RULE_ALLOW_ALL; 32 import static android.net.NetworkPolicyManager.RULE_REJECT_METERED; 33 34 import android.app.Notification; 35 import android.app.NotificationManager; 36 import android.app.PendingIntent; 37 import android.bluetooth.BluetoothTetheringDataTracker; 38 import android.content.BroadcastReceiver; 39 import android.content.ContentResolver; 40 import android.content.Context; 41 import android.content.ContextWrapper; 42 import android.content.Intent; 43 import android.content.IntentFilter; 44 import android.content.pm.PackageManager; 45 import android.content.res.Configuration; 46 import android.content.res.Resources; 47 import android.database.ContentObserver; 48 import android.net.CaptivePortalTracker; 49 import android.net.ConnectivityManager; 50 import android.net.DummyDataStateTracker; 51 import android.net.EthernetDataTracker; 52 import android.net.IConnectivityManager; 53 import android.net.INetworkManagementEventObserver; 54 import android.net.INetworkPolicyListener; 55 import android.net.INetworkPolicyManager; 56 import android.net.INetworkStatsService; 57 import android.net.LinkAddress; 58 import android.net.LinkProperties; 59 import android.net.Uri; 60 import android.net.LinkProperties.CompareResult; 61 import android.net.MobileDataStateTracker; 62 import android.net.NetworkConfig; 63 import android.net.NetworkInfo; 64 import android.net.NetworkInfo.DetailedState; 65 import android.net.NetworkInfo.State; 66 import android.net.NetworkQuotaInfo; 67 import android.net.NetworkState; 68 import android.net.NetworkStateTracker; 69 import android.net.NetworkUtils; 70 import android.net.Proxy; 71 import android.net.ProxyProperties; 72 import android.net.RouteInfo; 73 import android.net.wifi.WifiStateTracker; 74 import android.net.wimax.WimaxManagerConstants; 75 import android.os.AsyncTask; 76 import android.os.Binder; 77 import android.os.FileUtils; 78 import android.os.Handler; 79 import android.os.HandlerThread; 80 import android.os.IBinder; 81 import android.os.INetworkManagementService; 82 import android.os.Looper; 83 import android.os.Message; 84 import android.os.Messenger; 85 import android.os.ParcelFileDescriptor; 86 import android.os.PowerManager; 87 import android.os.Process; 88 import android.os.RemoteException; 89 import android.os.ResultReceiver; 90 import android.os.ServiceManager; 91 import android.os.SystemClock; 92 import android.os.SystemProperties; 93 import android.os.UserHandle; 94 import android.provider.Settings; 95 import android.security.Credentials; 96 import android.security.KeyStore; 97 import android.telephony.TelephonyManager; 98 import android.text.TextUtils; 99 import android.util.Slog; 100 import android.util.SparseIntArray; 101 import android.util.Xml; 102 103 import com.android.internal.R; 104 import com.android.internal.net.LegacyVpnInfo; 105 import com.android.internal.net.VpnConfig; 106 import com.android.internal.net.VpnProfile; 107 import com.android.internal.telephony.DctConstants; 108 import com.android.internal.telephony.Phone; 109 import com.android.internal.telephony.PhoneConstants; 110 import com.android.internal.util.IndentingPrintWriter; 111 import com.android.internal.util.XmlUtils; 112 import com.android.server.am.BatteryStatsService; 113 import com.android.server.connectivity.Nat464Xlat; 114 import com.android.server.connectivity.Tethering; 115 import com.android.server.connectivity.Vpn; 116 import com.android.server.net.BaseNetworkObserver; 117 import com.android.server.net.LockdownVpnTracker; 118 import com.google.android.collect.Lists; 119 import com.google.android.collect.Sets; 120 121 import dalvik.system.DexClassLoader; 122 123 import org.xmlpull.v1.XmlPullParser; 124 import org.xmlpull.v1.XmlPullParserException; 125 126 import java.io.File; 127 import java.io.FileDescriptor; 128 import java.io.FileNotFoundException; 129 import java.io.FileReader; 130 import java.io.IOException; 131 import java.io.PrintWriter; 132 import java.lang.reflect.Constructor; 133 import java.net.HttpURLConnection; 134 import java.net.Inet4Address; 135 import java.net.Inet6Address; 136 import java.net.InetAddress; 137 import java.net.URL; 138 import java.net.UnknownHostException; 139 import java.util.ArrayList; 140 import java.util.Arrays; 141 import java.util.Collection; 142 import java.util.GregorianCalendar; 143 import java.util.HashSet; 144 import java.util.List; 145 import java.util.Random; 146 import java.util.concurrent.atomic.AtomicInteger; 147 148 /** 149 * @hide 150 */ 151 public class ConnectivityService extends IConnectivityManager.Stub { 152 private static final String TAG = "ConnectivityService"; 153 154 private static final boolean DBG = true; 155 private static final boolean VDBG = false; 156 157 private static final boolean LOGD_RULES = false; 158 159 // TODO: create better separation between radio types and network types 160 161 // how long to wait before switching back to a radio's default network 162 private static final int RESTORE_DEFAULT_NETWORK_DELAY = 1 * 60 * 1000; 163 // system property that can override the above value 164 private static final String NETWORK_RESTORE_DELAY_PROP_NAME = 165 "android.telephony.apn-restore"; 166 167 // Default value if FAIL_FAST_TIME_MS is not set 168 private static final int DEFAULT_FAIL_FAST_TIME_MS = 1 * 60 * 1000; 169 // system property that can override DEFAULT_FAIL_FAST_TIME_MS 170 private static final String FAIL_FAST_TIME_MS = 171 "persist.radio.fail_fast_time_ms"; 172 173 // used in recursive route setting to add gateways for the host for which 174 // a host route was requested. 175 private static final int MAX_HOSTROUTE_CYCLE_COUNT = 10; 176 177 private Tethering mTethering; 178 private boolean mTetheringConfigValid = false; 179 180 private KeyStore mKeyStore; 181 182 private Vpn mVpn; 183 private VpnCallback mVpnCallback = new VpnCallback(); 184 185 private boolean mLockdownEnabled; 186 private LockdownVpnTracker mLockdownTracker; 187 188 private Nat464Xlat mClat; 189 190 /** Lock around {@link #mUidRules} and {@link #mMeteredIfaces}. */ 191 private Object mRulesLock = new Object(); 192 /** Currently active network rules by UID. */ 193 private SparseIntArray mUidRules = new SparseIntArray(); 194 /** Set of ifaces that are costly. */ 195 private HashSet<String> mMeteredIfaces = Sets.newHashSet(); 196 197 /** 198 * Sometimes we want to refer to the individual network state 199 * trackers separately, and sometimes we just want to treat them 200 * abstractly. 201 */ 202 private NetworkStateTracker mNetTrackers[]; 203 204 /* Handles captive portal check on a network */ 205 private CaptivePortalTracker mCaptivePortalTracker; 206 207 /** 208 * The link properties that define the current links 209 */ 210 private LinkProperties mCurrentLinkProperties[]; 211 212 /** 213 * A per Net list of the PID's that requested access to the net 214 * used both as a refcount and for per-PID DNS selection 215 */ 216 private List<Integer> mNetRequestersPids[]; 217 218 // priority order of the nettrackers 219 // (excluding dynamically set mNetworkPreference) 220 // TODO - move mNetworkTypePreference into this 221 private int[] mPriorityList; 222 223 private Context mContext; 224 private int mNetworkPreference; 225 private int mActiveDefaultNetwork = -1; 226 // 0 is full bad, 100 is full good 227 private int mDefaultInetCondition = 0; 228 private int mDefaultInetConditionPublished = 0; 229 private boolean mInetConditionChangeInFlight = false; 230 private int mDefaultConnectionSequence = 0; 231 232 private Object mDnsLock = new Object(); 233 private int mNumDnsEntries; 234 private boolean mDnsOverridden = false; 235 236 private boolean mTestMode; 237 private static ConnectivityService sServiceInstance; 238 239 private INetworkManagementService mNetd; 240 private INetworkPolicyManager mPolicyManager; 241 242 private static final int ENABLED = 1; 243 private static final int DISABLED = 0; 244 245 private static final boolean ADD = true; 246 private static final boolean REMOVE = false; 247 248 private static final boolean TO_DEFAULT_TABLE = true; 249 private static final boolean TO_SECONDARY_TABLE = false; 250 251 /** 252 * used internally as a delayed event to make us switch back to the 253 * default network 254 */ 255 private static final int EVENT_RESTORE_DEFAULT_NETWORK = 1; 256 257 /** 258 * used internally to change our mobile data enabled flag 259 */ 260 private static final int EVENT_CHANGE_MOBILE_DATA_ENABLED = 2; 261 262 /** 263 * used internally to change our network preference setting 264 * arg1 = networkType to prefer 265 */ 266 private static final int EVENT_SET_NETWORK_PREFERENCE = 3; 267 268 /** 269 * used internally to synchronize inet condition reports 270 * arg1 = networkType 271 * arg2 = condition (0 bad, 100 good) 272 */ 273 private static final int EVENT_INET_CONDITION_CHANGE = 4; 274 275 /** 276 * used internally to mark the end of inet condition hold periods 277 * arg1 = networkType 278 */ 279 private static final int EVENT_INET_CONDITION_HOLD_END = 5; 280 281 /** 282 * used internally to set enable/disable cellular data 283 * arg1 = ENBALED or DISABLED 284 */ 285 private static final int EVENT_SET_MOBILE_DATA = 7; 286 287 /** 288 * used internally to clear a wakelock when transitioning 289 * from one net to another 290 */ 291 private static final int EVENT_CLEAR_NET_TRANSITION_WAKELOCK = 8; 292 293 /** 294 * used internally to reload global proxy settings 295 */ 296 private static final int EVENT_APPLY_GLOBAL_HTTP_PROXY = 9; 297 298 /** 299 * used internally to set external dependency met/unmet 300 * arg1 = ENABLED (met) or DISABLED (unmet) 301 * arg2 = NetworkType 302 */ 303 private static final int EVENT_SET_DEPENDENCY_MET = 10; 304 305 /** 306 * used internally to restore DNS properties back to the 307 * default network 308 */ 309 private static final int EVENT_RESTORE_DNS = 11; 310 311 /** 312 * used internally to send a sticky broadcast delayed. 313 */ 314 private static final int EVENT_SEND_STICKY_BROADCAST_INTENT = 12; 315 316 /** 317 * Used internally to 318 * {@link NetworkStateTracker#setPolicyDataEnable(boolean)}. 319 */ 320 private static final int EVENT_SET_POLICY_DATA_ENABLE = 13; 321 322 private static final int EVENT_VPN_STATE_CHANGED = 14; 323 324 /** 325 * Used internally to disable fail fast of mobile data 326 */ 327 private static final int EVENT_ENABLE_FAIL_FAST_MOBILE_DATA = 15; 328 329 /** Handler used for internal events. */ 330 private InternalHandler mHandler; 331 /** Handler used for incoming {@link NetworkStateTracker} events. */ 332 private NetworkStateTrackerHandler mTrackerHandler; 333 334 // list of DeathRecipients used to make sure features are turned off when 335 // a process dies 336 private List<FeatureUser> mFeatureUsers; 337 338 private boolean mSystemReady; 339 private Intent mInitialBroadcast; 340 341 private PowerManager.WakeLock mNetTransitionWakeLock; 342 private String mNetTransitionWakeLockCausedBy = ""; 343 private int mNetTransitionWakeLockSerialNumber; 344 private int mNetTransitionWakeLockTimeout; 345 346 private InetAddress mDefaultDns; 347 348 // this collection is used to refcount the added routes - if there are none left 349 // it's time to remove the route from the route table 350 private Collection<RouteInfo> mAddedRoutes = new ArrayList<RouteInfo>(); 351 352 // used in DBG mode to track inet condition reports 353 private static final int INET_CONDITION_LOG_MAX_SIZE = 15; 354 private ArrayList mInetLog; 355 356 // track the current default http proxy - tell the world if we get a new one (real change) 357 private ProxyProperties mDefaultProxy = null; 358 private Object mProxyLock = new Object(); 359 private boolean mDefaultProxyDisabled = false; 360 361 // track the global proxy. 362 private ProxyProperties mGlobalProxy = null; 363 364 private SettingsObserver mSettingsObserver; 365 366 NetworkConfig[] mNetConfigs; 367 int mNetworksDefined; 368 369 private static class RadioAttributes { 370 public int mSimultaneity; 371 public int mType; 372 public RadioAttributes(String init) { 373 String fragments[] = init.split(","); 374 mType = Integer.parseInt(fragments[0]); 375 mSimultaneity = Integer.parseInt(fragments[1]); 376 } 377 } 378 RadioAttributes[] mRadioAttributes; 379 380 // the set of network types that can only be enabled by system/sig apps 381 List mProtectedNetworks; 382 383 private AtomicInteger mEnableFailFastMobileDataTag = new AtomicInteger(0); 384 385 TelephonyManager mTelephonyManager; 386 387 // We only want one checkMobileProvisioning after booting. 388 volatile boolean mFirstProvisioningCheckStarted = false; 389 390 public ConnectivityService(Context context, INetworkManagementService netd, 391 INetworkStatsService statsService, INetworkPolicyManager policyManager) { 392 // Currently, omitting a NetworkFactory will create one internally 393 // TODO: create here when we have cleaner WiMAX support 394 this(context, netd, statsService, policyManager, null); 395 } 396 397 public ConnectivityService(Context context, INetworkManagementService netManager, 398 INetworkStatsService statsService, INetworkPolicyManager policyManager, 399 NetworkFactory netFactory) { 400 if (DBG) log("ConnectivityService starting up"); 401 402 HandlerThread handlerThread = new HandlerThread("ConnectivityServiceThread"); 403 handlerThread.start(); 404 mHandler = new InternalHandler(handlerThread.getLooper()); 405 mTrackerHandler = new NetworkStateTrackerHandler(handlerThread.getLooper()); 406 407 if (netFactory == null) { 408 netFactory = new DefaultNetworkFactory(context, mTrackerHandler); 409 } 410 411 // setup our unique device name 412 if (TextUtils.isEmpty(SystemProperties.get("net.hostname"))) { 413 String id = Settings.Secure.getString(context.getContentResolver(), 414 Settings.Secure.ANDROID_ID); 415 if (id != null && id.length() > 0) { 416 String name = new String("android-").concat(id); 417 SystemProperties.set("net.hostname", name); 418 } 419 } 420 421 // read our default dns server ip 422 String dns = Settings.Global.getString(context.getContentResolver(), 423 Settings.Global.DEFAULT_DNS_SERVER); 424 if (dns == null || dns.length() == 0) { 425 dns = context.getResources().getString( 426 com.android.internal.R.string.config_default_dns_server); 427 } 428 try { 429 mDefaultDns = NetworkUtils.numericToInetAddress(dns); 430 } catch (IllegalArgumentException e) { 431 loge("Error setting defaultDns using " + dns); 432 } 433 434 mContext = checkNotNull(context, "missing Context"); 435 mNetd = checkNotNull(netManager, "missing INetworkManagementService"); 436 mPolicyManager = checkNotNull(policyManager, "missing INetworkPolicyManager"); 437 mKeyStore = KeyStore.getInstance(); 438 mTelephonyManager = (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE); 439 440 try { 441 mPolicyManager.registerListener(mPolicyListener); 442 } catch (RemoteException e) { 443 // ouch, no rules updates means some processes may never get network 444 loge("unable to register INetworkPolicyListener" + e.toString()); 445 } 446 447 final PowerManager powerManager = (PowerManager) context.getSystemService( 448 Context.POWER_SERVICE); 449 mNetTransitionWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG); 450 mNetTransitionWakeLockTimeout = mContext.getResources().getInteger( 451 com.android.internal.R.integer.config_networkTransitionTimeout); 452 453 mNetTrackers = new NetworkStateTracker[ 454 ConnectivityManager.MAX_NETWORK_TYPE+1]; 455 mCurrentLinkProperties = new LinkProperties[ConnectivityManager.MAX_NETWORK_TYPE+1]; 456 457 mRadioAttributes = new RadioAttributes[ConnectivityManager.MAX_RADIO_TYPE+1]; 458 mNetConfigs = new NetworkConfig[ConnectivityManager.MAX_NETWORK_TYPE+1]; 459 460 // Load device network attributes from resources 461 String[] raStrings = context.getResources().getStringArray( 462 com.android.internal.R.array.radioAttributes); 463 for (String raString : raStrings) { 464 RadioAttributes r = new RadioAttributes(raString); 465 if (r.mType > ConnectivityManager.MAX_RADIO_TYPE) { 466 loge("Error in radioAttributes - ignoring attempt to define type " + r.mType); 467 continue; 468 } 469 if (mRadioAttributes[r.mType] != null) { 470 loge("Error in radioAttributes - ignoring attempt to redefine type " + 471 r.mType); 472 continue; 473 } 474 mRadioAttributes[r.mType] = r; 475 } 476 477 // TODO: What is the "correct" way to do determine if this is a wifi only device? 478 boolean wifiOnly = SystemProperties.getBoolean("ro.radio.noril", false); 479 log("wifiOnly=" + wifiOnly); 480 String[] naStrings = context.getResources().getStringArray( 481 com.android.internal.R.array.networkAttributes); 482 for (String naString : naStrings) { 483 try { 484 NetworkConfig n = new NetworkConfig(naString); 485 if (n.type > ConnectivityManager.MAX_NETWORK_TYPE) { 486 loge("Error in networkAttributes - ignoring attempt to define type " + 487 n.type); 488 continue; 489 } 490 if (wifiOnly && ConnectivityManager.isNetworkTypeMobile(n.type)) { 491 log("networkAttributes - ignoring mobile as this dev is wifiOnly " + 492 n.type); 493 continue; 494 } 495 if (mNetConfigs[n.type] != null) { 496 loge("Error in networkAttributes - ignoring attempt to redefine type " + 497 n.type); 498 continue; 499 } 500 if (mRadioAttributes[n.radio] == null) { 501 loge("Error in networkAttributes - ignoring attempt to use undefined " + 502 "radio " + n.radio + " in network type " + n.type); 503 continue; 504 } 505 mNetConfigs[n.type] = n; 506 mNetworksDefined++; 507 } catch(Exception e) { 508 // ignore it - leave the entry null 509 } 510 } 511 512 mProtectedNetworks = new ArrayList<Integer>(); 513 int[] protectedNetworks = context.getResources().getIntArray( 514 com.android.internal.R.array.config_protectedNetworks); 515 for (int p : protectedNetworks) { 516 if ((mNetConfigs[p] != null) && (mProtectedNetworks.contains(p) == false)) { 517 mProtectedNetworks.add(p); 518 } else { 519 if (DBG) loge("Ignoring protectedNetwork " + p); 520 } 521 } 522 523 // high priority first 524 mPriorityList = new int[mNetworksDefined]; 525 { 526 int insertionPoint = mNetworksDefined-1; 527 int currentLowest = 0; 528 int nextLowest = 0; 529 while (insertionPoint > -1) { 530 for (NetworkConfig na : mNetConfigs) { 531 if (na == null) continue; 532 if (na.priority < currentLowest) continue; 533 if (na.priority > currentLowest) { 534 if (na.priority < nextLowest || nextLowest == 0) { 535 nextLowest = na.priority; 536 } 537 continue; 538 } 539 mPriorityList[insertionPoint--] = na.type; 540 } 541 currentLowest = nextLowest; 542 nextLowest = 0; 543 } 544 } 545 546 // Update mNetworkPreference according to user mannually first then overlay config.xml 547 mNetworkPreference = getPersistedNetworkPreference(); 548 if (mNetworkPreference == -1) { 549 for (int n : mPriorityList) { 550 if (mNetConfigs[n].isDefault() && ConnectivityManager.isNetworkTypeValid(n)) { 551 mNetworkPreference = n; 552 break; 553 } 554 } 555 if (mNetworkPreference == -1) { 556 throw new IllegalStateException( 557 "You should set at least one default Network in config.xml!"); 558 } 559 } 560 561 mNetRequestersPids = 562 (List<Integer> [])new ArrayList[ConnectivityManager.MAX_NETWORK_TYPE+1]; 563 for (int i : mPriorityList) { 564 mNetRequestersPids[i] = new ArrayList<Integer>(); 565 } 566 567 mFeatureUsers = new ArrayList<FeatureUser>(); 568 569 mTestMode = SystemProperties.get("cm.test.mode").equals("true") 570 && SystemProperties.get("ro.build.type").equals("eng"); 571 572 // Create and start trackers for hard-coded networks 573 for (int targetNetworkType : mPriorityList) { 574 final NetworkConfig config = mNetConfigs[targetNetworkType]; 575 final NetworkStateTracker tracker; 576 try { 577 tracker = netFactory.createTracker(targetNetworkType, config); 578 mNetTrackers[targetNetworkType] = tracker; 579 } catch (IllegalArgumentException e) { 580 Slog.e(TAG, "Problem creating " + getNetworkTypeName(targetNetworkType) 581 + " tracker: " + e); 582 continue; 583 } 584 585 tracker.startMonitoring(context, mTrackerHandler); 586 if (config.isDefault()) { 587 tracker.reconnect(); 588 } 589 } 590 591 mTethering = new Tethering(mContext, mNetd, statsService, this, mHandler.getLooper()); 592 mTetheringConfigValid = ((mTethering.getTetherableUsbRegexs().length != 0 || 593 mTethering.getTetherableWifiRegexs().length != 0 || 594 mTethering.getTetherableBluetoothRegexs().length != 0) && 595 mTethering.getUpstreamIfaceTypes().length != 0); 596 597 mVpn = new Vpn(mContext, mVpnCallback, mNetd, this); 598 mVpn.startMonitoring(mContext, mTrackerHandler); 599 600 mClat = new Nat464Xlat(mContext, mNetd, this, mTrackerHandler); 601 602 try { 603 mNetd.registerObserver(mTethering); 604 mNetd.registerObserver(mDataActivityObserver); 605 mNetd.registerObserver(mClat); 606 } catch (RemoteException e) { 607 loge("Error registering observer :" + e); 608 } 609 610 if (DBG) { 611 mInetLog = new ArrayList(); 612 } 613 614 mSettingsObserver = new SettingsObserver(mHandler, EVENT_APPLY_GLOBAL_HTTP_PROXY); 615 mSettingsObserver.observe(mContext); 616 617 mCaptivePortalTracker = CaptivePortalTracker.makeCaptivePortalTracker(mContext, this); 618 loadGlobalProxy(); 619 } 620 621 /** 622 * Factory that creates {@link NetworkStateTracker} instances using given 623 * {@link NetworkConfig}. 624 */ 625 public interface NetworkFactory { 626 public NetworkStateTracker createTracker(int targetNetworkType, NetworkConfig config); 627 } 628 629 private static class DefaultNetworkFactory implements NetworkFactory { 630 private final Context mContext; 631 private final Handler mTrackerHandler; 632 633 public DefaultNetworkFactory(Context context, Handler trackerHandler) { 634 mContext = context; 635 mTrackerHandler = trackerHandler; 636 } 637 638 @Override 639 public NetworkStateTracker createTracker(int targetNetworkType, NetworkConfig config) { 640 switch (config.radio) { 641 case TYPE_WIFI: 642 return new WifiStateTracker(targetNetworkType, config.name); 643 case TYPE_MOBILE: 644 return new MobileDataStateTracker(targetNetworkType, config.name); 645 case TYPE_DUMMY: 646 return new DummyDataStateTracker(targetNetworkType, config.name); 647 case TYPE_BLUETOOTH: 648 return BluetoothTetheringDataTracker.getInstance(); 649 case TYPE_WIMAX: 650 return makeWimaxStateTracker(mContext, mTrackerHandler); 651 case TYPE_ETHERNET: 652 return EthernetDataTracker.getInstance(); 653 default: 654 throw new IllegalArgumentException( 655 "Trying to create a NetworkStateTracker for an unknown radio type: " 656 + config.radio); 657 } 658 } 659 } 660 661 /** 662 * Loads external WiMAX library and registers as system service, returning a 663 * {@link NetworkStateTracker} for WiMAX. Caller is still responsible for 664 * invoking {@link NetworkStateTracker#startMonitoring(Context, Handler)}. 665 */ 666 private static NetworkStateTracker makeWimaxStateTracker( 667 Context context, Handler trackerHandler) { 668 // Initialize Wimax 669 DexClassLoader wimaxClassLoader; 670 Class wimaxStateTrackerClass = null; 671 Class wimaxServiceClass = null; 672 Class wimaxManagerClass; 673 String wimaxJarLocation; 674 String wimaxLibLocation; 675 String wimaxManagerClassName; 676 String wimaxServiceClassName; 677 String wimaxStateTrackerClassName; 678 679 NetworkStateTracker wimaxStateTracker = null; 680 681 boolean isWimaxEnabled = context.getResources().getBoolean( 682 com.android.internal.R.bool.config_wimaxEnabled); 683 684 if (isWimaxEnabled) { 685 try { 686 wimaxJarLocation = context.getResources().getString( 687 com.android.internal.R.string.config_wimaxServiceJarLocation); 688 wimaxLibLocation = context.getResources().getString( 689 com.android.internal.R.string.config_wimaxNativeLibLocation); 690 wimaxManagerClassName = context.getResources().getString( 691 com.android.internal.R.string.config_wimaxManagerClassname); 692 wimaxServiceClassName = context.getResources().getString( 693 com.android.internal.R.string.config_wimaxServiceClassname); 694 wimaxStateTrackerClassName = context.getResources().getString( 695 com.android.internal.R.string.config_wimaxStateTrackerClassname); 696 697 if (DBG) log("wimaxJarLocation: " + wimaxJarLocation); 698 wimaxClassLoader = new DexClassLoader(wimaxJarLocation, 699 new ContextWrapper(context).getCacheDir().getAbsolutePath(), 700 wimaxLibLocation, ClassLoader.getSystemClassLoader()); 701 702 try { 703 wimaxManagerClass = wimaxClassLoader.loadClass(wimaxManagerClassName); 704 wimaxStateTrackerClass = wimaxClassLoader.loadClass(wimaxStateTrackerClassName); 705 wimaxServiceClass = wimaxClassLoader.loadClass(wimaxServiceClassName); 706 } catch (ClassNotFoundException ex) { 707 loge("Exception finding Wimax classes: " + ex.toString()); 708 return null; 709 } 710 } catch(Resources.NotFoundException ex) { 711 loge("Wimax Resources does not exist!!! "); 712 return null; 713 } 714 715 try { 716 if (DBG) log("Starting Wimax Service... "); 717 718 Constructor wmxStTrkrConst = wimaxStateTrackerClass.getConstructor 719 (new Class[] {Context.class, Handler.class}); 720 wimaxStateTracker = (NetworkStateTracker) wmxStTrkrConst.newInstance( 721 context, trackerHandler); 722 723 Constructor wmxSrvConst = wimaxServiceClass.getDeclaredConstructor 724 (new Class[] {Context.class, wimaxStateTrackerClass}); 725 wmxSrvConst.setAccessible(true); 726 IBinder svcInvoker = (IBinder)wmxSrvConst.newInstance(context, wimaxStateTracker); 727 wmxSrvConst.setAccessible(false); 728 729 ServiceManager.addService(WimaxManagerConstants.WIMAX_SERVICE, svcInvoker); 730 731 } catch(Exception ex) { 732 loge("Exception creating Wimax classes: " + ex.toString()); 733 return null; 734 } 735 } else { 736 loge("Wimax is not enabled or not added to the network attributes!!! "); 737 return null; 738 } 739 740 return wimaxStateTracker; 741 } 742 743 /** 744 * Sets the preferred network. 745 * @param preference the new preference 746 */ 747 public void setNetworkPreference(int preference) { 748 enforceChangePermission(); 749 750 mHandler.sendMessage( 751 mHandler.obtainMessage(EVENT_SET_NETWORK_PREFERENCE, preference, 0)); 752 } 753 754 public int getNetworkPreference() { 755 enforceAccessPermission(); 756 int preference; 757 synchronized(this) { 758 preference = mNetworkPreference; 759 } 760 return preference; 761 } 762 763 private void handleSetNetworkPreference(int preference) { 764 if (ConnectivityManager.isNetworkTypeValid(preference) && 765 mNetConfigs[preference] != null && 766 mNetConfigs[preference].isDefault()) { 767 if (mNetworkPreference != preference) { 768 final ContentResolver cr = mContext.getContentResolver(); 769 Settings.Global.putInt(cr, Settings.Global.NETWORK_PREFERENCE, preference); 770 synchronized(this) { 771 mNetworkPreference = preference; 772 } 773 enforcePreference(); 774 } 775 } 776 } 777 778 private int getConnectivityChangeDelay() { 779 final ContentResolver cr = mContext.getContentResolver(); 780 781 /** Check system properties for the default value then use secure settings value, if any. */ 782 int defaultDelay = SystemProperties.getInt( 783 "conn." + Settings.Global.CONNECTIVITY_CHANGE_DELAY, 784 ConnectivityManager.CONNECTIVITY_CHANGE_DELAY_DEFAULT); 785 return Settings.Global.getInt(cr, Settings.Global.CONNECTIVITY_CHANGE_DELAY, 786 defaultDelay); 787 } 788 789 private int getPersistedNetworkPreference() { 790 final ContentResolver cr = mContext.getContentResolver(); 791 792 final int networkPrefSetting = Settings.Global 793 .getInt(cr, Settings.Global.NETWORK_PREFERENCE, -1); 794 795 return networkPrefSetting; 796 } 797 798 /** 799 * Make the state of network connectivity conform to the preference settings 800 * In this method, we only tear down a non-preferred network. Establishing 801 * a connection to the preferred network is taken care of when we handle 802 * the disconnect event from the non-preferred network 803 * (see {@link #handleDisconnect(NetworkInfo)}). 804 */ 805 private void enforcePreference() { 806 if (mNetTrackers[mNetworkPreference].getNetworkInfo().isConnected()) 807 return; 808 809 if (!mNetTrackers[mNetworkPreference].isAvailable()) 810 return; 811 812 for (int t=0; t <= ConnectivityManager.MAX_RADIO_TYPE; t++) { 813 if (t != mNetworkPreference && mNetTrackers[t] != null && 814 mNetTrackers[t].getNetworkInfo().isConnected()) { 815 if (DBG) { 816 log("tearing down " + mNetTrackers[t].getNetworkInfo() + 817 " in enforcePreference"); 818 } 819 teardown(mNetTrackers[t]); 820 } 821 } 822 } 823 824 private boolean teardown(NetworkStateTracker netTracker) { 825 if (netTracker.teardown()) { 826 netTracker.setTeardownRequested(true); 827 return true; 828 } else { 829 return false; 830 } 831 } 832 833 /** 834 * Check if UID should be blocked from using the network represented by the 835 * given {@link NetworkStateTracker}. 836 */ 837 private boolean isNetworkBlocked(NetworkStateTracker tracker, int uid) { 838 final String iface = tracker.getLinkProperties().getInterfaceName(); 839 840 final boolean networkCostly; 841 final int uidRules; 842 synchronized (mRulesLock) { 843 networkCostly = mMeteredIfaces.contains(iface); 844 uidRules = mUidRules.get(uid, RULE_ALLOW_ALL); 845 } 846 847 if (networkCostly && (uidRules & RULE_REJECT_METERED) != 0) { 848 return true; 849 } 850 851 // no restrictive rules; network is visible 852 return false; 853 } 854 855 /** 856 * Return a filtered {@link NetworkInfo}, potentially marked 857 * {@link DetailedState#BLOCKED} based on 858 * {@link #isNetworkBlocked(NetworkStateTracker, int)}. 859 */ 860 private NetworkInfo getFilteredNetworkInfo(NetworkStateTracker tracker, int uid) { 861 NetworkInfo info = tracker.getNetworkInfo(); 862 if (isNetworkBlocked(tracker, uid)) { 863 // network is blocked; clone and override state 864 info = new NetworkInfo(info); 865 info.setDetailedState(DetailedState.BLOCKED, null, null); 866 } 867 if (mLockdownTracker != null) { 868 info = mLockdownTracker.augmentNetworkInfo(info); 869 } 870 return info; 871 } 872 873 /** 874 * Return NetworkInfo for the active (i.e., connected) network interface. 875 * It is assumed that at most one network is active at a time. If more 876 * than one is active, it is indeterminate which will be returned. 877 * @return the info for the active network, or {@code null} if none is 878 * active 879 */ 880 @Override 881 public NetworkInfo getActiveNetworkInfo() { 882 enforceAccessPermission(); 883 final int uid = Binder.getCallingUid(); 884 return getNetworkInfo(mActiveDefaultNetwork, uid); 885 } 886 887 public NetworkInfo getActiveNetworkInfoUnfiltered() { 888 enforceAccessPermission(); 889 if (isNetworkTypeValid(mActiveDefaultNetwork)) { 890 final NetworkStateTracker tracker = mNetTrackers[mActiveDefaultNetwork]; 891 if (tracker != null) { 892 return tracker.getNetworkInfo(); 893 } 894 } 895 return null; 896 } 897 898 @Override 899 public NetworkInfo getActiveNetworkInfoForUid(int uid) { 900 enforceConnectivityInternalPermission(); 901 return getNetworkInfo(mActiveDefaultNetwork, uid); 902 } 903 904 @Override 905 public NetworkInfo getNetworkInfo(int networkType) { 906 enforceAccessPermission(); 907 final int uid = Binder.getCallingUid(); 908 return getNetworkInfo(networkType, uid); 909 } 910 911 private NetworkInfo getNetworkInfo(int networkType, int uid) { 912 NetworkInfo info = null; 913 if (isNetworkTypeValid(networkType)) { 914 final NetworkStateTracker tracker = mNetTrackers[networkType]; 915 if (tracker != null) { 916 info = getFilteredNetworkInfo(tracker, uid); 917 } 918 } 919 return info; 920 } 921 922 @Override 923 public NetworkInfo[] getAllNetworkInfo() { 924 enforceAccessPermission(); 925 final int uid = Binder.getCallingUid(); 926 final ArrayList<NetworkInfo> result = Lists.newArrayList(); 927 synchronized (mRulesLock) { 928 for (NetworkStateTracker tracker : mNetTrackers) { 929 if (tracker != null) { 930 result.add(getFilteredNetworkInfo(tracker, uid)); 931 } 932 } 933 } 934 return result.toArray(new NetworkInfo[result.size()]); 935 } 936 937 @Override 938 public boolean isNetworkSupported(int networkType) { 939 enforceAccessPermission(); 940 return (isNetworkTypeValid(networkType) && (mNetTrackers[networkType] != null)); 941 } 942 943 /** 944 * Return LinkProperties for the active (i.e., connected) default 945 * network interface. It is assumed that at most one default network 946 * is active at a time. If more than one is active, it is indeterminate 947 * which will be returned. 948 * @return the ip properties for the active network, or {@code null} if 949 * none is active 950 */ 951 @Override 952 public LinkProperties getActiveLinkProperties() { 953 return getLinkProperties(mActiveDefaultNetwork); 954 } 955 956 @Override 957 public LinkProperties getLinkProperties(int networkType) { 958 enforceAccessPermission(); 959 if (isNetworkTypeValid(networkType)) { 960 final NetworkStateTracker tracker = mNetTrackers[networkType]; 961 if (tracker != null) { 962 return tracker.getLinkProperties(); 963 } 964 } 965 return null; 966 } 967 968 @Override 969 public NetworkState[] getAllNetworkState() { 970 enforceAccessPermission(); 971 final int uid = Binder.getCallingUid(); 972 final ArrayList<NetworkState> result = Lists.newArrayList(); 973 synchronized (mRulesLock) { 974 for (NetworkStateTracker tracker : mNetTrackers) { 975 if (tracker != null) { 976 final NetworkInfo info = getFilteredNetworkInfo(tracker, uid); 977 result.add(new NetworkState( 978 info, tracker.getLinkProperties(), tracker.getLinkCapabilities())); 979 } 980 } 981 } 982 return result.toArray(new NetworkState[result.size()]); 983 } 984 985 private NetworkState getNetworkStateUnchecked(int networkType) { 986 if (isNetworkTypeValid(networkType)) { 987 final NetworkStateTracker tracker = mNetTrackers[networkType]; 988 if (tracker != null) { 989 return new NetworkState(tracker.getNetworkInfo(), tracker.getLinkProperties(), 990 tracker.getLinkCapabilities()); 991 } 992 } 993 return null; 994 } 995 996 @Override 997 public NetworkQuotaInfo getActiveNetworkQuotaInfo() { 998 enforceAccessPermission(); 999 1000 final long token = Binder.clearCallingIdentity(); 1001 try { 1002 final NetworkState state = getNetworkStateUnchecked(mActiveDefaultNetwork); 1003 if (state != null) { 1004 try { 1005 return mPolicyManager.getNetworkQuotaInfo(state); 1006 } catch (RemoteException e) { 1007 } 1008 } 1009 return null; 1010 } finally { 1011 Binder.restoreCallingIdentity(token); 1012 } 1013 } 1014 1015 @Override 1016 public boolean isActiveNetworkMetered() { 1017 enforceAccessPermission(); 1018 final long token = Binder.clearCallingIdentity(); 1019 try { 1020 return isNetworkMeteredUnchecked(mActiveDefaultNetwork); 1021 } finally { 1022 Binder.restoreCallingIdentity(token); 1023 } 1024 } 1025 1026 private boolean isNetworkMeteredUnchecked(int networkType) { 1027 final NetworkState state = getNetworkStateUnchecked(networkType); 1028 if (state != null) { 1029 try { 1030 return mPolicyManager.isNetworkMetered(state); 1031 } catch (RemoteException e) { 1032 } 1033 } 1034 return false; 1035 } 1036 1037 public boolean setRadios(boolean turnOn) { 1038 boolean result = true; 1039 enforceChangePermission(); 1040 for (NetworkStateTracker t : mNetTrackers) { 1041 if (t != null) result = t.setRadio(turnOn) && result; 1042 } 1043 return result; 1044 } 1045 1046 public boolean setRadio(int netType, boolean turnOn) { 1047 enforceChangePermission(); 1048 if (!ConnectivityManager.isNetworkTypeValid(netType)) { 1049 return false; 1050 } 1051 NetworkStateTracker tracker = mNetTrackers[netType]; 1052 return tracker != null && tracker.setRadio(turnOn); 1053 } 1054 1055 private INetworkManagementEventObserver mDataActivityObserver = new BaseNetworkObserver() { 1056 @Override 1057 public void interfaceClassDataActivityChanged(String label, boolean active) { 1058 int deviceType = Integer.parseInt(label); 1059 sendDataActivityBroadcast(deviceType, active); 1060 } 1061 }; 1062 1063 /** 1064 * Used to notice when the calling process dies so we can self-expire 1065 * 1066 * Also used to know if the process has cleaned up after itself when 1067 * our auto-expire timer goes off. The timer has a link to an object. 1068 * 1069 */ 1070 private class FeatureUser implements IBinder.DeathRecipient { 1071 int mNetworkType; 1072 String mFeature; 1073 IBinder mBinder; 1074 int mPid; 1075 int mUid; 1076 long mCreateTime; 1077 1078 FeatureUser(int type, String feature, IBinder binder) { 1079 super(); 1080 mNetworkType = type; 1081 mFeature = feature; 1082 mBinder = binder; 1083 mPid = getCallingPid(); 1084 mUid = getCallingUid(); 1085 mCreateTime = System.currentTimeMillis(); 1086 1087 try { 1088 mBinder.linkToDeath(this, 0); 1089 } catch (RemoteException e) { 1090 binderDied(); 1091 } 1092 } 1093 1094 void unlinkDeathRecipient() { 1095 mBinder.unlinkToDeath(this, 0); 1096 } 1097 1098 public void binderDied() { 1099 log("ConnectivityService FeatureUser binderDied(" + 1100 mNetworkType + ", " + mFeature + ", " + mBinder + "), created " + 1101 (System.currentTimeMillis() - mCreateTime) + " mSec ago"); 1102 stopUsingNetworkFeature(this, false); 1103 } 1104 1105 public void expire() { 1106 if (VDBG) { 1107 log("ConnectivityService FeatureUser expire(" + 1108 mNetworkType + ", " + mFeature + ", " + mBinder +"), created " + 1109 (System.currentTimeMillis() - mCreateTime) + " mSec ago"); 1110 } 1111 stopUsingNetworkFeature(this, false); 1112 } 1113 1114 public boolean isSameUser(FeatureUser u) { 1115 if (u == null) return false; 1116 1117 return isSameUser(u.mPid, u.mUid, u.mNetworkType, u.mFeature); 1118 } 1119 1120 public boolean isSameUser(int pid, int uid, int networkType, String feature) { 1121 if ((mPid == pid) && (mUid == uid) && (mNetworkType == networkType) && 1122 TextUtils.equals(mFeature, feature)) { 1123 return true; 1124 } 1125 return false; 1126 } 1127 1128 public String toString() { 1129 return "FeatureUser("+mNetworkType+","+mFeature+","+mPid+","+mUid+"), created " + 1130 (System.currentTimeMillis() - mCreateTime) + " mSec ago"; 1131 } 1132 } 1133 1134 // javadoc from interface 1135 public int startUsingNetworkFeature(int networkType, String feature, 1136 IBinder binder) { 1137 long startTime = 0; 1138 if (DBG) { 1139 startTime = SystemClock.elapsedRealtime(); 1140 } 1141 if (VDBG) { 1142 log("startUsingNetworkFeature for net " + networkType + ": " + feature + ", uid=" 1143 + Binder.getCallingUid()); 1144 } 1145 enforceChangePermission(); 1146 try { 1147 if (!ConnectivityManager.isNetworkTypeValid(networkType) || 1148 mNetConfigs[networkType] == null) { 1149 return PhoneConstants.APN_REQUEST_FAILED; 1150 } 1151 1152 FeatureUser f = new FeatureUser(networkType, feature, binder); 1153 1154 // TODO - move this into individual networktrackers 1155 int usedNetworkType = convertFeatureToNetworkType(networkType, feature); 1156 1157 if (mLockdownEnabled) { 1158 // Since carrier APNs usually aren't available from VPN 1159 // endpoint, mark them as unavailable. 1160 return PhoneConstants.APN_TYPE_NOT_AVAILABLE; 1161 } 1162 1163 if (mProtectedNetworks.contains(usedNetworkType)) { 1164 enforceConnectivityInternalPermission(); 1165 } 1166 1167 // if UID is restricted, don't allow them to bring up metered APNs 1168 final boolean networkMetered = isNetworkMeteredUnchecked(usedNetworkType); 1169 final int uidRules; 1170 synchronized (mRulesLock) { 1171 uidRules = mUidRules.get(Binder.getCallingUid(), RULE_ALLOW_ALL); 1172 } 1173 if (networkMetered && (uidRules & RULE_REJECT_METERED) != 0) { 1174 return PhoneConstants.APN_REQUEST_FAILED; 1175 } 1176 1177 NetworkStateTracker network = mNetTrackers[usedNetworkType]; 1178 if (network != null) { 1179 Integer currentPid = new Integer(getCallingPid()); 1180 if (usedNetworkType != networkType) { 1181 NetworkInfo ni = network.getNetworkInfo(); 1182 1183 if (ni.isAvailable() == false) { 1184 if (!TextUtils.equals(feature,Phone.FEATURE_ENABLE_DUN_ALWAYS)) { 1185 if (DBG) log("special network not available ni=" + ni.getTypeName()); 1186 return PhoneConstants.APN_TYPE_NOT_AVAILABLE; 1187 } else { 1188 // else make the attempt anyway - probably giving REQUEST_STARTED below 1189 if (DBG) { 1190 log("special network not available, but try anyway ni=" + 1191 ni.getTypeName()); 1192 } 1193 } 1194 } 1195 1196 int restoreTimer = getRestoreDefaultNetworkDelay(usedNetworkType); 1197 1198 synchronized(this) { 1199 boolean addToList = true; 1200 if (restoreTimer < 0) { 1201 // In case there is no timer is specified for the feature, 1202 // make sure we don't add duplicate entry with the same request. 1203 for (FeatureUser u : mFeatureUsers) { 1204 if (u.isSameUser(f)) { 1205 // Duplicate user is found. Do not add. 1206 addToList = false; 1207 break; 1208 } 1209 } 1210 } 1211 1212 if (addToList) mFeatureUsers.add(f); 1213 if (!mNetRequestersPids[usedNetworkType].contains(currentPid)) { 1214 // this gets used for per-pid dns when connected 1215 mNetRequestersPids[usedNetworkType].add(currentPid); 1216 } 1217 } 1218 1219 if (restoreTimer >= 0) { 1220 mHandler.sendMessageDelayed(mHandler.obtainMessage( 1221 EVENT_RESTORE_DEFAULT_NETWORK, f), restoreTimer); 1222 } 1223 1224 if ((ni.isConnectedOrConnecting() == true) && 1225 !network.isTeardownRequested()) { 1226 if (ni.isConnected() == true) { 1227 final long token = Binder.clearCallingIdentity(); 1228 try { 1229 // add the pid-specific dns 1230 handleDnsConfigurationChange(usedNetworkType); 1231 if (VDBG) log("special network already active"); 1232 } finally { 1233 Binder.restoreCallingIdentity(token); 1234 } 1235 return PhoneConstants.APN_ALREADY_ACTIVE; 1236 } 1237 if (VDBG) log("special network already connecting"); 1238 return PhoneConstants.APN_REQUEST_STARTED; 1239 } 1240 1241 // check if the radio in play can make another contact 1242 // assume if cannot for now 1243 1244 if (DBG) { 1245 log("startUsingNetworkFeature reconnecting to " + networkType + ": " + 1246 feature); 1247 } 1248 if (network.reconnect()) { 1249 return PhoneConstants.APN_REQUEST_STARTED; 1250 } else { 1251 return PhoneConstants.APN_REQUEST_FAILED; 1252 } 1253 } else { 1254 // need to remember this unsupported request so we respond appropriately on stop 1255 synchronized(this) { 1256 mFeatureUsers.add(f); 1257 if (!mNetRequestersPids[usedNetworkType].contains(currentPid)) { 1258 // this gets used for per-pid dns when connected 1259 mNetRequestersPids[usedNetworkType].add(currentPid); 1260 } 1261 } 1262 return -1; 1263 } 1264 } 1265 return PhoneConstants.APN_TYPE_NOT_AVAILABLE; 1266 } finally { 1267 if (DBG) { 1268 final long execTime = SystemClock.elapsedRealtime() - startTime; 1269 if (execTime > 250) { 1270 loge("startUsingNetworkFeature took too long: " + execTime + "ms"); 1271 } else { 1272 if (VDBG) log("startUsingNetworkFeature took " + execTime + "ms"); 1273 } 1274 } 1275 } 1276 } 1277 1278 // javadoc from interface 1279 public int stopUsingNetworkFeature(int networkType, String feature) { 1280 enforceChangePermission(); 1281 1282 int pid = getCallingPid(); 1283 int uid = getCallingUid(); 1284 1285 FeatureUser u = null; 1286 boolean found = false; 1287 1288 synchronized(this) { 1289 for (FeatureUser x : mFeatureUsers) { 1290 if (x.isSameUser(pid, uid, networkType, feature)) { 1291 u = x; 1292 found = true; 1293 break; 1294 } 1295 } 1296 } 1297 if (found && u != null) { 1298 // stop regardless of how many other time this proc had called start 1299 return stopUsingNetworkFeature(u, true); 1300 } else { 1301 // none found! 1302 if (VDBG) log("stopUsingNetworkFeature - not a live request, ignoring"); 1303 return 1; 1304 } 1305 } 1306 1307 private int stopUsingNetworkFeature(FeatureUser u, boolean ignoreDups) { 1308 int networkType = u.mNetworkType; 1309 String feature = u.mFeature; 1310 int pid = u.mPid; 1311 int uid = u.mUid; 1312 1313 NetworkStateTracker tracker = null; 1314 boolean callTeardown = false; // used to carry our decision outside of sync block 1315 1316 if (VDBG) { 1317 log("stopUsingNetworkFeature: net " + networkType + ": " + feature); 1318 } 1319 1320 if (!ConnectivityManager.isNetworkTypeValid(networkType)) { 1321 if (DBG) { 1322 log("stopUsingNetworkFeature: net " + networkType + ": " + feature + 1323 ", net is invalid"); 1324 } 1325 return -1; 1326 } 1327 1328 // need to link the mFeatureUsers list with the mNetRequestersPids state in this 1329 // sync block 1330 synchronized(this) { 1331 // check if this process still has an outstanding start request 1332 if (!mFeatureUsers.contains(u)) { 1333 if (VDBG) { 1334 log("stopUsingNetworkFeature: this process has no outstanding requests" + 1335 ", ignoring"); 1336 } 1337 return 1; 1338 } 1339 u.unlinkDeathRecipient(); 1340 mFeatureUsers.remove(mFeatureUsers.indexOf(u)); 1341 // If we care about duplicate requests, check for that here. 1342 // 1343 // This is done to support the extension of a request - the app 1344 // can request we start the network feature again and renew the 1345 // auto-shutoff delay. Normal "stop" calls from the app though 1346 // do not pay attention to duplicate requests - in effect the 1347 // API does not refcount and a single stop will counter multiple starts. 1348 if (ignoreDups == false) { 1349 for (FeatureUser x : mFeatureUsers) { 1350 if (x.isSameUser(u)) { 1351 if (VDBG) log("stopUsingNetworkFeature: dup is found, ignoring"); 1352 return 1; 1353 } 1354 } 1355 } 1356 1357 // TODO - move to individual network trackers 1358 int usedNetworkType = convertFeatureToNetworkType(networkType, feature); 1359 1360 tracker = mNetTrackers[usedNetworkType]; 1361 if (tracker == null) { 1362 if (DBG) { 1363 log("stopUsingNetworkFeature: net " + networkType + ": " + feature + 1364 " no known tracker for used net type " + usedNetworkType); 1365 } 1366 return -1; 1367 } 1368 if (usedNetworkType != networkType) { 1369 Integer currentPid = new Integer(pid); 1370 mNetRequestersPids[usedNetworkType].remove(currentPid); 1371 1372 final long token = Binder.clearCallingIdentity(); 1373 try { 1374 reassessPidDns(pid, true); 1375 } finally { 1376 Binder.restoreCallingIdentity(token); 1377 } 1378 flushVmDnsCache(); 1379 if (mNetRequestersPids[usedNetworkType].size() != 0) { 1380 if (VDBG) { 1381 log("stopUsingNetworkFeature: net " + networkType + ": " + feature + 1382 " others still using it"); 1383 } 1384 return 1; 1385 } 1386 callTeardown = true; 1387 } else { 1388 if (DBG) { 1389 log("stopUsingNetworkFeature: net " + networkType + ": " + feature + 1390 " not a known feature - dropping"); 1391 } 1392 } 1393 } 1394 1395 if (callTeardown) { 1396 if (DBG) { 1397 log("stopUsingNetworkFeature: teardown net " + networkType + ": " + feature); 1398 } 1399 tracker.teardown(); 1400 return 1; 1401 } else { 1402 return -1; 1403 } 1404 } 1405 1406 /** 1407 * @deprecated use requestRouteToHostAddress instead 1408 * 1409 * Ensure that a network route exists to deliver traffic to the specified 1410 * host via the specified network interface. 1411 * @param networkType the type of the network over which traffic to the 1412 * specified host is to be routed 1413 * @param hostAddress the IP address of the host to which the route is 1414 * desired 1415 * @return {@code true} on success, {@code false} on failure 1416 */ 1417 public boolean requestRouteToHost(int networkType, int hostAddress) { 1418 InetAddress inetAddress = NetworkUtils.intToInetAddress(hostAddress); 1419 1420 if (inetAddress == null) { 1421 return false; 1422 } 1423 1424 return requestRouteToHostAddress(networkType, inetAddress.getAddress()); 1425 } 1426 1427 /** 1428 * Ensure that a network route exists to deliver traffic to the specified 1429 * host via the specified network interface. 1430 * @param networkType the type of the network over which traffic to the 1431 * specified host is to be routed 1432 * @param hostAddress the IP address of the host to which the route is 1433 * desired 1434 * @return {@code true} on success, {@code false} on failure 1435 */ 1436 public boolean requestRouteToHostAddress(int networkType, byte[] hostAddress) { 1437 enforceChangePermission(); 1438 if (mProtectedNetworks.contains(networkType)) { 1439 enforceConnectivityInternalPermission(); 1440 } 1441 1442 if (!ConnectivityManager.isNetworkTypeValid(networkType)) { 1443 if (DBG) log("requestRouteToHostAddress on invalid network: " + networkType); 1444 return false; 1445 } 1446 NetworkStateTracker tracker = mNetTrackers[networkType]; 1447 DetailedState netState = tracker.getNetworkInfo().getDetailedState(); 1448 1449 if (tracker == null || (netState != DetailedState.CONNECTED && 1450 netState != DetailedState.CAPTIVE_PORTAL_CHECK) || 1451 tracker.isTeardownRequested()) { 1452 if (VDBG) { 1453 log("requestRouteToHostAddress on down network " 1454 + "(" + networkType + ") - dropped" 1455 + " tracker=" + tracker 1456 + " netState=" + netState 1457 + " isTeardownRequested=" 1458 + ((tracker != null) ? tracker.isTeardownRequested() : "tracker:null")); 1459 } 1460 return false; 1461 } 1462 final long token = Binder.clearCallingIdentity(); 1463 try { 1464 InetAddress addr = InetAddress.getByAddress(hostAddress); 1465 LinkProperties lp = tracker.getLinkProperties(); 1466 boolean ok = addRouteToAddress(lp, addr); 1467 if (DBG) log("requestRouteToHostAddress ok=" + ok); 1468 return ok; 1469 } catch (UnknownHostException e) { 1470 if (DBG) log("requestRouteToHostAddress got " + e.toString()); 1471 } finally { 1472 Binder.restoreCallingIdentity(token); 1473 } 1474 if (DBG) log("requestRouteToHostAddress X bottom return false"); 1475 return false; 1476 } 1477 1478 private boolean addRoute(LinkProperties p, RouteInfo r, boolean toDefaultTable) { 1479 return modifyRoute(p, r, 0, ADD, toDefaultTable); 1480 } 1481 1482 private boolean removeRoute(LinkProperties p, RouteInfo r, boolean toDefaultTable) { 1483 return modifyRoute(p, r, 0, REMOVE, toDefaultTable); 1484 } 1485 1486 private boolean addRouteToAddress(LinkProperties lp, InetAddress addr) { 1487 return modifyRouteToAddress(lp, addr, ADD, TO_DEFAULT_TABLE); 1488 } 1489 1490 private boolean removeRouteToAddress(LinkProperties lp, InetAddress addr) { 1491 return modifyRouteToAddress(lp, addr, REMOVE, TO_DEFAULT_TABLE); 1492 } 1493 1494 private boolean modifyRouteToAddress(LinkProperties lp, InetAddress addr, boolean doAdd, 1495 boolean toDefaultTable) { 1496 RouteInfo bestRoute = RouteInfo.selectBestRoute(lp.getAllRoutes(), addr); 1497 if (bestRoute == null) { 1498 bestRoute = RouteInfo.makeHostRoute(addr, lp.getInterfaceName()); 1499 } else { 1500 String iface = bestRoute.getInterface(); 1501 if (bestRoute.getGateway().equals(addr)) { 1502 // if there is no better route, add the implied hostroute for our gateway 1503 bestRoute = RouteInfo.makeHostRoute(addr, iface); 1504 } else { 1505 // if we will connect to this through another route, add a direct route 1506 // to it's gateway 1507 bestRoute = RouteInfo.makeHostRoute(addr, bestRoute.getGateway(), iface); 1508 } 1509 } 1510 return modifyRoute(lp, bestRoute, 0, doAdd, toDefaultTable); 1511 } 1512 1513 private boolean modifyRoute(LinkProperties lp, RouteInfo r, int cycleCount, boolean doAdd, 1514 boolean toDefaultTable) { 1515 if ((lp == null) || (r == null)) { 1516 if (DBG) log("modifyRoute got unexpected null: " + lp + ", " + r); 1517 return false; 1518 } 1519 1520 if (cycleCount > MAX_HOSTROUTE_CYCLE_COUNT) { 1521 loge("Error modifying route - too much recursion"); 1522 return false; 1523 } 1524 1525 String ifaceName = r.getInterface(); 1526 if(ifaceName == null) { 1527 loge("Error modifying route - no interface name"); 1528 return false; 1529 } 1530 if (r.hasGateway()) { 1531 RouteInfo bestRoute = RouteInfo.selectBestRoute(lp.getAllRoutes(), r.getGateway()); 1532 if (bestRoute != null) { 1533 if (bestRoute.getGateway().equals(r.getGateway())) { 1534 // if there is no better route, add the implied hostroute for our gateway 1535 bestRoute = RouteInfo.makeHostRoute(r.getGateway(), ifaceName); 1536 } else { 1537 // if we will connect to our gateway through another route, add a direct 1538 // route to it's gateway 1539 bestRoute = RouteInfo.makeHostRoute(r.getGateway(), 1540 bestRoute.getGateway(), 1541 ifaceName); 1542 } 1543 modifyRoute(lp, bestRoute, cycleCount+1, doAdd, toDefaultTable); 1544 } 1545 } 1546 if (doAdd) { 1547 if (VDBG) log("Adding " + r + " for interface " + ifaceName); 1548 try { 1549 if (toDefaultTable) { 1550 mAddedRoutes.add(r); // only track default table - only one apps can effect 1551 mNetd.addRoute(ifaceName, r); 1552 } else { 1553 mNetd.addSecondaryRoute(ifaceName, r); 1554 } 1555 } catch (Exception e) { 1556 // never crash - catch them all 1557 if (DBG) loge("Exception trying to add a route: " + e); 1558 return false; 1559 } 1560 } else { 1561 // if we remove this one and there are no more like it, then refcount==0 and 1562 // we can remove it from the table 1563 if (toDefaultTable) { 1564 mAddedRoutes.remove(r); 1565 if (mAddedRoutes.contains(r) == false) { 1566 if (VDBG) log("Removing " + r + " for interface " + ifaceName); 1567 try { 1568 mNetd.removeRoute(ifaceName, r); 1569 } catch (Exception e) { 1570 // never crash - catch them all 1571 if (VDBG) loge("Exception trying to remove a route: " + e); 1572 return false; 1573 } 1574 } else { 1575 if (VDBG) log("not removing " + r + " as it's still in use"); 1576 } 1577 } else { 1578 if (VDBG) log("Removing " + r + " for interface " + ifaceName); 1579 try { 1580 mNetd.removeSecondaryRoute(ifaceName, r); 1581 } catch (Exception e) { 1582 // never crash - catch them all 1583 if (VDBG) loge("Exception trying to remove a route: " + e); 1584 return false; 1585 } 1586 } 1587 } 1588 return true; 1589 } 1590 1591 /** 1592 * @see ConnectivityManager#getMobileDataEnabled() 1593 */ 1594 public boolean getMobileDataEnabled() { 1595 // TODO: This detail should probably be in DataConnectionTracker's 1596 // which is where we store the value and maybe make this 1597 // asynchronous. 1598 enforceAccessPermission(); 1599 boolean retVal = Settings.Global.getInt(mContext.getContentResolver(), 1600 Settings.Global.MOBILE_DATA, 1) == 1; 1601 if (VDBG) log("getMobileDataEnabled returning " + retVal); 1602 return retVal; 1603 } 1604 1605 public void setDataDependency(int networkType, boolean met) { 1606 enforceConnectivityInternalPermission(); 1607 1608 mHandler.sendMessage(mHandler.obtainMessage(EVENT_SET_DEPENDENCY_MET, 1609 (met ? ENABLED : DISABLED), networkType)); 1610 } 1611 1612 private void handleSetDependencyMet(int networkType, boolean met) { 1613 if (mNetTrackers[networkType] != null) { 1614 if (DBG) { 1615 log("handleSetDependencyMet(" + networkType + ", " + met + ")"); 1616 } 1617 mNetTrackers[networkType].setDependencyMet(met); 1618 } 1619 } 1620 1621 private INetworkPolicyListener mPolicyListener = new INetworkPolicyListener.Stub() { 1622 @Override 1623 public void onUidRulesChanged(int uid, int uidRules) { 1624 // caller is NPMS, since we only register with them 1625 if (LOGD_RULES) { 1626 log("onUidRulesChanged(uid=" + uid + ", uidRules=" + uidRules + ")"); 1627 } 1628 1629 synchronized (mRulesLock) { 1630 // skip update when we've already applied rules 1631 final int oldRules = mUidRules.get(uid, RULE_ALLOW_ALL); 1632 if (oldRules == uidRules) return; 1633 1634 mUidRules.put(uid, uidRules); 1635 } 1636 1637 // TODO: notify UID when it has requested targeted updates 1638 } 1639 1640 @Override 1641 public void onMeteredIfacesChanged(String[] meteredIfaces) { 1642 // caller is NPMS, since we only register with them 1643 if (LOGD_RULES) { 1644 log("onMeteredIfacesChanged(ifaces=" + Arrays.toString(meteredIfaces) + ")"); 1645 } 1646 1647 synchronized (mRulesLock) { 1648 mMeteredIfaces.clear(); 1649 for (String iface : meteredIfaces) { 1650 mMeteredIfaces.add(iface); 1651 } 1652 } 1653 } 1654 1655 @Override 1656 public void onRestrictBackgroundChanged(boolean restrictBackground) { 1657 // caller is NPMS, since we only register with them 1658 if (LOGD_RULES) { 1659 log("onRestrictBackgroundChanged(restrictBackground=" + restrictBackground + ")"); 1660 } 1661 1662 // kick off connectivity change broadcast for active network, since 1663 // global background policy change is radical. 1664 final int networkType = mActiveDefaultNetwork; 1665 if (isNetworkTypeValid(networkType)) { 1666 final NetworkStateTracker tracker = mNetTrackers[networkType]; 1667 if (tracker != null) { 1668 final NetworkInfo info = tracker.getNetworkInfo(); 1669 if (info != null && info.isConnected()) { 1670 sendConnectedBroadcast(info); 1671 } 1672 } 1673 } 1674 } 1675 }; 1676 1677 /** 1678 * @see ConnectivityManager#setMobileDataEnabled(boolean) 1679 */ 1680 public void setMobileDataEnabled(boolean enabled) { 1681 enforceChangePermission(); 1682 if (DBG) log("setMobileDataEnabled(" + enabled + ")"); 1683 1684 mHandler.sendMessage(mHandler.obtainMessage(EVENT_SET_MOBILE_DATA, 1685 (enabled ? ENABLED : DISABLED), 0)); 1686 } 1687 1688 private void handleSetMobileData(boolean enabled) { 1689 if (mNetTrackers[ConnectivityManager.TYPE_MOBILE] != null) { 1690 if (VDBG) { 1691 log(mNetTrackers[ConnectivityManager.TYPE_MOBILE].toString() + enabled); 1692 } 1693 mNetTrackers[ConnectivityManager.TYPE_MOBILE].setUserDataEnable(enabled); 1694 } 1695 if (mNetTrackers[ConnectivityManager.TYPE_WIMAX] != null) { 1696 if (VDBG) { 1697 log(mNetTrackers[ConnectivityManager.TYPE_WIMAX].toString() + enabled); 1698 } 1699 mNetTrackers[ConnectivityManager.TYPE_WIMAX].setUserDataEnable(enabled); 1700 } 1701 } 1702 1703 @Override 1704 public void setPolicyDataEnable(int networkType, boolean enabled) { 1705 // only someone like NPMS should only be calling us 1706 mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG); 1707 1708 mHandler.sendMessage(mHandler.obtainMessage( 1709 EVENT_SET_POLICY_DATA_ENABLE, networkType, (enabled ? ENABLED : DISABLED))); 1710 } 1711 1712 private void handleSetPolicyDataEnable(int networkType, boolean enabled) { 1713 if (isNetworkTypeValid(networkType)) { 1714 final NetworkStateTracker tracker = mNetTrackers[networkType]; 1715 if (tracker != null) { 1716 tracker.setPolicyDataEnable(enabled); 1717 } 1718 } 1719 } 1720 1721 private void enforceAccessPermission() { 1722 mContext.enforceCallingOrSelfPermission( 1723 android.Manifest.permission.ACCESS_NETWORK_STATE, 1724 "ConnectivityService"); 1725 } 1726 1727 private void enforceChangePermission() { 1728 mContext.enforceCallingOrSelfPermission( 1729 android.Manifest.permission.CHANGE_NETWORK_STATE, 1730 "ConnectivityService"); 1731 } 1732 1733 // TODO Make this a special check when it goes public 1734 private void enforceTetherChangePermission() { 1735 mContext.enforceCallingOrSelfPermission( 1736 android.Manifest.permission.CHANGE_NETWORK_STATE, 1737 "ConnectivityService"); 1738 } 1739 1740 private void enforceTetherAccessPermission() { 1741 mContext.enforceCallingOrSelfPermission( 1742 android.Manifest.permission.ACCESS_NETWORK_STATE, 1743 "ConnectivityService"); 1744 } 1745 1746 private void enforceConnectivityInternalPermission() { 1747 mContext.enforceCallingOrSelfPermission( 1748 android.Manifest.permission.CONNECTIVITY_INTERNAL, 1749 "ConnectivityService"); 1750 } 1751 1752 /** 1753 * Handle a {@code DISCONNECTED} event. If this pertains to the non-active 1754 * network, we ignore it. If it is for the active network, we send out a 1755 * broadcast. But first, we check whether it might be possible to connect 1756 * to a different network. 1757 * @param info the {@code NetworkInfo} for the network 1758 */ 1759 private void handleDisconnect(NetworkInfo info) { 1760 1761 int prevNetType = info.getType(); 1762 1763 mNetTrackers[prevNetType].setTeardownRequested(false); 1764 1765 // Remove idletimer previously setup in {@code handleConnect} 1766 removeDataActivityTracking(prevNetType); 1767 1768 /* 1769 * If the disconnected network is not the active one, then don't report 1770 * this as a loss of connectivity. What probably happened is that we're 1771 * getting the disconnect for a network that we explicitly disabled 1772 * in accordance with network preference policies. 1773 */ 1774 if (!mNetConfigs[prevNetType].isDefault()) { 1775 List<Integer> pids = mNetRequestersPids[prevNetType]; 1776 for (Integer pid : pids) { 1777 // will remove them because the net's no longer connected 1778 // need to do this now as only now do we know the pids and 1779 // can properly null things that are no longer referenced. 1780 reassessPidDns(pid.intValue(), false); 1781 } 1782 } 1783 1784 Intent intent = new Intent(ConnectivityManager.CONNECTIVITY_ACTION); 1785 intent.putExtra(ConnectivityManager.EXTRA_NETWORK_INFO, new NetworkInfo(info)); 1786 intent.putExtra(ConnectivityManager.EXTRA_NETWORK_TYPE, info.getType()); 1787 if (info.isFailover()) { 1788 intent.putExtra(ConnectivityManager.EXTRA_IS_FAILOVER, true); 1789 info.setFailover(false); 1790 } 1791 if (info.getReason() != null) { 1792 intent.putExtra(ConnectivityManager.EXTRA_REASON, info.getReason()); 1793 } 1794 if (info.getExtraInfo() != null) { 1795 intent.putExtra(ConnectivityManager.EXTRA_EXTRA_INFO, 1796 info.getExtraInfo()); 1797 } 1798 1799 if (mNetConfigs[prevNetType].isDefault()) { 1800 tryFailover(prevNetType); 1801 if (mActiveDefaultNetwork != -1) { 1802 NetworkInfo switchTo = mNetTrackers[mActiveDefaultNetwork].getNetworkInfo(); 1803 intent.putExtra(ConnectivityManager.EXTRA_OTHER_NETWORK_INFO, switchTo); 1804 } else { 1805 mDefaultInetConditionPublished = 0; // we're not connected anymore 1806 intent.putExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, true); 1807 } 1808 } 1809 intent.putExtra(ConnectivityManager.EXTRA_INET_CONDITION, mDefaultInetConditionPublished); 1810 1811 // Reset interface if no other connections are using the same interface 1812 boolean doReset = true; 1813 LinkProperties linkProperties = mNetTrackers[prevNetType].getLinkProperties(); 1814 if (linkProperties != null) { 1815 String oldIface = linkProperties.getInterfaceName(); 1816 if (TextUtils.isEmpty(oldIface) == false) { 1817 for (NetworkStateTracker networkStateTracker : mNetTrackers) { 1818 if (networkStateTracker == null) continue; 1819 NetworkInfo networkInfo = networkStateTracker.getNetworkInfo(); 1820 if (networkInfo.isConnected() && networkInfo.getType() != prevNetType) { 1821 LinkProperties l = networkStateTracker.getLinkProperties(); 1822 if (l == null) continue; 1823 if (oldIface.equals(l.getInterfaceName())) { 1824 doReset = false; 1825 break; 1826 } 1827 } 1828 } 1829 } 1830 } 1831 1832 // do this before we broadcast the change 1833 handleConnectivityChange(prevNetType, doReset); 1834 1835 final Intent immediateIntent = new Intent(intent); 1836 immediateIntent.setAction(CONNECTIVITY_ACTION_IMMEDIATE); 1837 sendStickyBroadcast(immediateIntent); 1838 sendStickyBroadcastDelayed(intent, getConnectivityChangeDelay()); 1839 /* 1840 * If the failover network is already connected, then immediately send 1841 * out a followup broadcast indicating successful failover 1842 */ 1843 if (mActiveDefaultNetwork != -1) { 1844 sendConnectedBroadcastDelayed(mNetTrackers[mActiveDefaultNetwork].getNetworkInfo(), 1845 getConnectivityChangeDelay()); 1846 } 1847 } 1848 1849 private void tryFailover(int prevNetType) { 1850 /* 1851 * If this is a default network, check if other defaults are available. 1852 * Try to reconnect on all available and let them hash it out when 1853 * more than one connects. 1854 */ 1855 if (mNetConfigs[prevNetType].isDefault()) { 1856 if (mActiveDefaultNetwork == prevNetType) { 1857 mActiveDefaultNetwork = -1; 1858 } 1859 1860 // don't signal a reconnect for anything lower or equal priority than our 1861 // current connected default 1862 // TODO - don't filter by priority now - nice optimization but risky 1863 // int currentPriority = -1; 1864 // if (mActiveDefaultNetwork != -1) { 1865 // currentPriority = mNetConfigs[mActiveDefaultNetwork].mPriority; 1866 // } 1867 for (int checkType=0; checkType <= ConnectivityManager.MAX_NETWORK_TYPE; checkType++) { 1868 if (checkType == prevNetType) continue; 1869 if (mNetConfigs[checkType] == null) continue; 1870 if (!mNetConfigs[checkType].isDefault()) continue; 1871 if (mNetTrackers[checkType] == null) continue; 1872 1873 // Enabling the isAvailable() optimization caused mobile to not get 1874 // selected if it was in the middle of error handling. Specifically 1875 // a moble connection that took 30 seconds to complete the DEACTIVATE_DATA_CALL 1876 // would not be available and we wouldn't get connected to anything. 1877 // So removing the isAvailable() optimization below for now. TODO: This 1878 // optimization should work and we need to investigate why it doesn't work. 1879 // This could be related to how DEACTIVATE_DATA_CALL is reporting its 1880 // complete before it is really complete. 1881 // if (!mNetTrackers[checkType].isAvailable()) continue; 1882 1883 // if (currentPriority >= mNetConfigs[checkType].mPriority) continue; 1884 1885 NetworkStateTracker checkTracker = mNetTrackers[checkType]; 1886 NetworkInfo checkInfo = checkTracker.getNetworkInfo(); 1887 if (!checkInfo.isConnectedOrConnecting() || checkTracker.isTeardownRequested()) { 1888 checkInfo.setFailover(true); 1889 checkTracker.reconnect(); 1890 } 1891 if (DBG) log("Attempting to switch to " + checkInfo.getTypeName()); 1892 } 1893 } 1894 } 1895 1896 public void sendConnectedBroadcast(NetworkInfo info) { 1897 enforceConnectivityInternalPermission(); 1898 sendGeneralBroadcast(info, CONNECTIVITY_ACTION_IMMEDIATE); 1899 sendGeneralBroadcast(info, CONNECTIVITY_ACTION); 1900 } 1901 1902 private void sendConnectedBroadcastDelayed(NetworkInfo info, int delayMs) { 1903 sendGeneralBroadcast(info, CONNECTIVITY_ACTION_IMMEDIATE); 1904 sendGeneralBroadcastDelayed(info, CONNECTIVITY_ACTION, delayMs); 1905 } 1906 1907 private void sendInetConditionBroadcast(NetworkInfo info) { 1908 sendGeneralBroadcast(info, ConnectivityManager.INET_CONDITION_ACTION); 1909 } 1910 1911 private Intent makeGeneralIntent(NetworkInfo info, String bcastType) { 1912 if (mLockdownTracker != null) { 1913 info = mLockdownTracker.augmentNetworkInfo(info); 1914 } 1915 1916 Intent intent = new Intent(bcastType); 1917 intent.putExtra(ConnectivityManager.EXTRA_NETWORK_INFO, new NetworkInfo(info)); 1918 intent.putExtra(ConnectivityManager.EXTRA_NETWORK_TYPE, info.getType()); 1919 if (info.isFailover()) { 1920 intent.putExtra(ConnectivityManager.EXTRA_IS_FAILOVER, true); 1921 info.setFailover(false); 1922 } 1923 if (info.getReason() != null) { 1924 intent.putExtra(ConnectivityManager.EXTRA_REASON, info.getReason()); 1925 } 1926 if (info.getExtraInfo() != null) { 1927 intent.putExtra(ConnectivityManager.EXTRA_EXTRA_INFO, 1928 info.getExtraInfo()); 1929 } 1930 intent.putExtra(ConnectivityManager.EXTRA_INET_CONDITION, mDefaultInetConditionPublished); 1931 return intent; 1932 } 1933 1934 private void sendGeneralBroadcast(NetworkInfo info, String bcastType) { 1935 sendStickyBroadcast(makeGeneralIntent(info, bcastType)); 1936 } 1937 1938 private void sendGeneralBroadcastDelayed(NetworkInfo info, String bcastType, int delayMs) { 1939 sendStickyBroadcastDelayed(makeGeneralIntent(info, bcastType), delayMs); 1940 } 1941 1942 private void sendDataActivityBroadcast(int deviceType, boolean active) { 1943 Intent intent = new Intent(ConnectivityManager.ACTION_DATA_ACTIVITY_CHANGE); 1944 intent.putExtra(ConnectivityManager.EXTRA_DEVICE_TYPE, deviceType); 1945 intent.putExtra(ConnectivityManager.EXTRA_IS_ACTIVE, active); 1946 final long ident = Binder.clearCallingIdentity(); 1947 try { 1948 mContext.sendOrderedBroadcastAsUser(intent, UserHandle.ALL, 1949 RECEIVE_DATA_ACTIVITY_CHANGE, null, null, 0, null, null); 1950 } finally { 1951 Binder.restoreCallingIdentity(ident); 1952 } 1953 } 1954 1955 /** 1956 * Called when an attempt to fail over to another network has failed. 1957 * @param info the {@link NetworkInfo} for the failed network 1958 */ 1959 private void handleConnectionFailure(NetworkInfo info) { 1960 mNetTrackers[info.getType()].setTeardownRequested(false); 1961 1962 String reason = info.getReason(); 1963 String extraInfo = info.getExtraInfo(); 1964 1965 String reasonText; 1966 if (reason == null) { 1967 reasonText = "."; 1968 } else { 1969 reasonText = " (" + reason + ")."; 1970 } 1971 loge("Attempt to connect to " + info.getTypeName() + " failed" + reasonText); 1972 1973 Intent intent = new Intent(ConnectivityManager.CONNECTIVITY_ACTION); 1974 intent.putExtra(ConnectivityManager.EXTRA_NETWORK_INFO, new NetworkInfo(info)); 1975 intent.putExtra(ConnectivityManager.EXTRA_NETWORK_TYPE, info.getType()); 1976 if (getActiveNetworkInfo() == null) { 1977 intent.putExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, true); 1978 } 1979 if (reason != null) { 1980 intent.putExtra(ConnectivityManager.EXTRA_REASON, reason); 1981 } 1982 if (extraInfo != null) { 1983 intent.putExtra(ConnectivityManager.EXTRA_EXTRA_INFO, extraInfo); 1984 } 1985 if (info.isFailover()) { 1986 intent.putExtra(ConnectivityManager.EXTRA_IS_FAILOVER, true); 1987 info.setFailover(false); 1988 } 1989 1990 if (mNetConfigs[info.getType()].isDefault()) { 1991 tryFailover(info.getType()); 1992 if (mActiveDefaultNetwork != -1) { 1993 NetworkInfo switchTo = mNetTrackers[mActiveDefaultNetwork].getNetworkInfo(); 1994 intent.putExtra(ConnectivityManager.EXTRA_OTHER_NETWORK_INFO, switchTo); 1995 } else { 1996 mDefaultInetConditionPublished = 0; 1997 intent.putExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, true); 1998 } 1999 } 2000 2001 intent.putExtra(ConnectivityManager.EXTRA_INET_CONDITION, mDefaultInetConditionPublished); 2002 2003 final Intent immediateIntent = new Intent(intent); 2004 immediateIntent.setAction(CONNECTIVITY_ACTION_IMMEDIATE); 2005 sendStickyBroadcast(immediateIntent); 2006 sendStickyBroadcast(intent); 2007 /* 2008 * If the failover network is already connected, then immediately send 2009 * out a followup broadcast indicating successful failover 2010 */ 2011 if (mActiveDefaultNetwork != -1) { 2012 sendConnectedBroadcast(mNetTrackers[mActiveDefaultNetwork].getNetworkInfo()); 2013 } 2014 } 2015 2016 private void sendStickyBroadcast(Intent intent) { 2017 synchronized(this) { 2018 if (!mSystemReady) { 2019 mInitialBroadcast = new Intent(intent); 2020 } 2021 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 2022 if (VDBG) { 2023 log("sendStickyBroadcast: action=" + intent.getAction()); 2024 } 2025 2026 final long ident = Binder.clearCallingIdentity(); 2027 try { 2028 mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); 2029 } finally { 2030 Binder.restoreCallingIdentity(ident); 2031 } 2032 } 2033 } 2034 2035 private void sendStickyBroadcastDelayed(Intent intent, int delayMs) { 2036 if (delayMs <= 0) { 2037 sendStickyBroadcast(intent); 2038 } else { 2039 if (VDBG) { 2040 log("sendStickyBroadcastDelayed: delayMs=" + delayMs + ", action=" 2041 + intent.getAction()); 2042 } 2043 mHandler.sendMessageDelayed(mHandler.obtainMessage( 2044 EVENT_SEND_STICKY_BROADCAST_INTENT, intent), delayMs); 2045 } 2046 } 2047 2048 void systemReady() { 2049 synchronized(this) { 2050 mSystemReady = true; 2051 if (mInitialBroadcast != null) { 2052 mContext.sendStickyBroadcastAsUser(mInitialBroadcast, UserHandle.ALL); 2053 mInitialBroadcast = null; 2054 } 2055 } 2056 // load the global proxy at startup 2057 mHandler.sendMessage(mHandler.obtainMessage(EVENT_APPLY_GLOBAL_HTTP_PROXY)); 2058 2059 // Try bringing up tracker, but if KeyStore isn't ready yet, wait 2060 // for user to unlock device. 2061 if (!updateLockdownVpn()) { 2062 final IntentFilter filter = new IntentFilter(Intent.ACTION_USER_PRESENT); 2063 mContext.registerReceiver(mUserPresentReceiver, filter); 2064 } 2065 } 2066 2067 private BroadcastReceiver mUserPresentReceiver = new BroadcastReceiver() { 2068 @Override 2069 public void onReceive(Context context, Intent intent) { 2070 // Try creating lockdown tracker, since user present usually means 2071 // unlocked keystore. 2072 if (updateLockdownVpn()) { 2073 mContext.unregisterReceiver(this); 2074 } 2075 } 2076 }; 2077 2078 private boolean isNewNetTypePreferredOverCurrentNetType(int type) { 2079 if ((type != mNetworkPreference && 2080 mNetConfigs[mActiveDefaultNetwork].priority > 2081 mNetConfigs[type].priority) || 2082 mNetworkPreference == mActiveDefaultNetwork) return false; 2083 return true; 2084 } 2085 2086 private void handleConnect(NetworkInfo info) { 2087 final int newNetType = info.getType(); 2088 2089 setupDataActivityTracking(newNetType); 2090 2091 // snapshot isFailover, because sendConnectedBroadcast() resets it 2092 boolean isFailover = info.isFailover(); 2093 final NetworkStateTracker thisNet = mNetTrackers[newNetType]; 2094 final String thisIface = thisNet.getLinkProperties().getInterfaceName(); 2095 2096 // if this is a default net and other default is running 2097 // kill the one not preferred 2098 if (mNetConfigs[newNetType].isDefault()) { 2099 if (mActiveDefaultNetwork != -1 && mActiveDefaultNetwork != newNetType) { 2100 if (isNewNetTypePreferredOverCurrentNetType(newNetType)) { 2101 // tear down the other 2102 NetworkStateTracker otherNet = 2103 mNetTrackers[mActiveDefaultNetwork]; 2104 if (DBG) { 2105 log("Policy requires " + otherNet.getNetworkInfo().getTypeName() + 2106 " teardown"); 2107 } 2108 if (!teardown(otherNet)) { 2109 loge("Network declined teardown request"); 2110 teardown(thisNet); 2111 return; 2112 } 2113 } else { 2114 // don't accept this one 2115 if (VDBG) { 2116 log("Not broadcasting CONNECT_ACTION " + 2117 "to torn down network " + info.getTypeName()); 2118 } 2119 teardown(thisNet); 2120 return; 2121 } 2122 } 2123 synchronized (ConnectivityService.this) { 2124 // have a new default network, release the transition wakelock in a second 2125 // if it's held. The second pause is to allow apps to reconnect over the 2126 // new network 2127 if (mNetTransitionWakeLock.isHeld()) { 2128 mHandler.sendMessageDelayed(mHandler.obtainMessage( 2129 EVENT_CLEAR_NET_TRANSITION_WAKELOCK, 2130 mNetTransitionWakeLockSerialNumber, 0), 2131 1000); 2132 } 2133 } 2134 mActiveDefaultNetwork = newNetType; 2135 // this will cause us to come up initially as unconnected and switching 2136 // to connected after our normal pause unless somebody reports us as reall 2137 // disconnected 2138 mDefaultInetConditionPublished = 0; 2139 mDefaultConnectionSequence++; 2140 mInetConditionChangeInFlight = false; 2141 // Don't do this - if we never sign in stay, grey 2142 //reportNetworkCondition(mActiveDefaultNetwork, 100); 2143 } 2144 thisNet.setTeardownRequested(false); 2145 updateNetworkSettings(thisNet); 2146 handleConnectivityChange(newNetType, false); 2147 sendConnectedBroadcastDelayed(info, getConnectivityChangeDelay()); 2148 2149 // notify battery stats service about this network 2150 if (thisIface != null) { 2151 try { 2152 BatteryStatsService.getService().noteNetworkInterfaceType(thisIface, newNetType); 2153 } catch (RemoteException e) { 2154 // ignored; service lives in system_server 2155 } 2156 } 2157 } 2158 2159 private void handleCaptivePortalTrackerCheck(NetworkInfo info) { 2160 if (DBG) log("Captive portal check " + info); 2161 int type = info.getType(); 2162 final NetworkStateTracker thisNet = mNetTrackers[type]; 2163 if (mNetConfigs[type].isDefault()) { 2164 if (mActiveDefaultNetwork != -1 && mActiveDefaultNetwork != type) { 2165 if (isNewNetTypePreferredOverCurrentNetType(type)) { 2166 if (DBG) log("Captive check on " + info.getTypeName()); 2167 mCaptivePortalTracker.detectCaptivePortal(new NetworkInfo(info)); 2168 return; 2169 } else { 2170 if (DBG) log("Tear down low priority net " + info.getTypeName()); 2171 teardown(thisNet); 2172 return; 2173 } 2174 } 2175 } 2176 2177 thisNet.captivePortalCheckComplete(); 2178 } 2179 2180 /** @hide */ 2181 public void captivePortalCheckComplete(NetworkInfo info) { 2182 enforceConnectivityInternalPermission(); 2183 mNetTrackers[info.getType()].captivePortalCheckComplete(); 2184 } 2185 2186 /** 2187 * Setup data activity tracking for the given network interface. 2188 * 2189 * Every {@code setupDataActivityTracking} should be paired with a 2190 * {@link removeDataActivityTracking} for cleanup. 2191 */ 2192 private void setupDataActivityTracking(int type) { 2193 final NetworkStateTracker thisNet = mNetTrackers[type]; 2194 final String iface = thisNet.getLinkProperties().getInterfaceName(); 2195 2196 final int timeout; 2197 2198 if (ConnectivityManager.isNetworkTypeMobile(type)) { 2199 timeout = Settings.Global.getInt(mContext.getContentResolver(), 2200 Settings.Global.DATA_ACTIVITY_TIMEOUT_MOBILE, 2201 0); 2202 // Canonicalize mobile network type 2203 type = ConnectivityManager.TYPE_MOBILE; 2204 } else if (ConnectivityManager.TYPE_WIFI == type) { 2205 timeout = Settings.Global.getInt(mContext.getContentResolver(), 2206 Settings.Global.DATA_ACTIVITY_TIMEOUT_WIFI, 2207 0); 2208 } else { 2209 // do not track any other networks 2210 timeout = 0; 2211 } 2212 2213 if (timeout > 0 && iface != null) { 2214 try { 2215 mNetd.addIdleTimer(iface, timeout, Integer.toString(type)); 2216 } catch (RemoteException e) { 2217 } 2218 } 2219 } 2220 2221 /** 2222 * Remove data activity tracking when network disconnects. 2223 */ 2224 private void removeDataActivityTracking(int type) { 2225 final NetworkStateTracker net = mNetTrackers[type]; 2226 final String iface = net.getLinkProperties().getInterfaceName(); 2227 2228 if (iface != null && (ConnectivityManager.isNetworkTypeMobile(type) || 2229 ConnectivityManager.TYPE_WIFI == type)) { 2230 try { 2231 // the call fails silently if no idletimer setup for this interface 2232 mNetd.removeIdleTimer(iface); 2233 } catch (RemoteException e) { 2234 } 2235 } 2236 } 2237 2238 /** 2239 * After a change in the connectivity state of a network. We're mainly 2240 * concerned with making sure that the list of DNS servers is set up 2241 * according to which networks are connected, and ensuring that the 2242 * right routing table entries exist. 2243 */ 2244 private void handleConnectivityChange(int netType, boolean doReset) { 2245 int resetMask = doReset ? NetworkUtils.RESET_ALL_ADDRESSES : 0; 2246 2247 /* 2248 * If a non-default network is enabled, add the host routes that 2249 * will allow it's DNS servers to be accessed. 2250 */ 2251 handleDnsConfigurationChange(netType); 2252 2253 LinkProperties curLp = mCurrentLinkProperties[netType]; 2254 LinkProperties newLp = null; 2255 2256 if (mNetTrackers[netType].getNetworkInfo().isConnected()) { 2257 newLp = mNetTrackers[netType].getLinkProperties(); 2258 if (VDBG) { 2259 log("handleConnectivityChange: changed linkProperty[" + netType + "]:" + 2260 " doReset=" + doReset + " resetMask=" + resetMask + 2261 "\n curLp=" + curLp + 2262 "\n newLp=" + newLp); 2263 } 2264 2265 if (curLp != null) { 2266 if (curLp.isIdenticalInterfaceName(newLp)) { 2267 CompareResult<LinkAddress> car = curLp.compareAddresses(newLp); 2268 if ((car.removed.size() != 0) || (car.added.size() != 0)) { 2269 for (LinkAddress linkAddr : car.removed) { 2270 if (linkAddr.getAddress() instanceof Inet4Address) { 2271 resetMask |= NetworkUtils.RESET_IPV4_ADDRESSES; 2272 } 2273 if (linkAddr.getAddress() instanceof Inet6Address) { 2274 resetMask |= NetworkUtils.RESET_IPV6_ADDRESSES; 2275 } 2276 } 2277 if (DBG) { 2278 log("handleConnectivityChange: addresses changed" + 2279 " linkProperty[" + netType + "]:" + " resetMask=" + resetMask + 2280 "\n car=" + car); 2281 } 2282 } else { 2283 if (DBG) { 2284 log("handleConnectivityChange: address are the same reset per doReset" + 2285 " linkProperty[" + netType + "]:" + 2286 " resetMask=" + resetMask); 2287 } 2288 } 2289 } else { 2290 resetMask = NetworkUtils.RESET_ALL_ADDRESSES; 2291 if (DBG) { 2292 log("handleConnectivityChange: interface not not equivalent reset both" + 2293 " linkProperty[" + netType + "]:" + 2294 " resetMask=" + resetMask); 2295 } 2296 } 2297 } 2298 if (mNetConfigs[netType].isDefault()) { 2299 handleApplyDefaultProxy(newLp.getHttpProxy()); 2300 } 2301 } else { 2302 if (VDBG) { 2303 log("handleConnectivityChange: changed linkProperty[" + netType + "]:" + 2304 " doReset=" + doReset + " resetMask=" + resetMask + 2305 "\n curLp=" + curLp + 2306 "\n newLp= null"); 2307 } 2308 } 2309 mCurrentLinkProperties[netType] = newLp; 2310 boolean resetDns = updateRoutes(newLp, curLp, mNetConfigs[netType].isDefault()); 2311 2312 if (resetMask != 0 || resetDns) { 2313 if (curLp != null) { 2314 for (String iface : curLp.getAllInterfaceNames()) { 2315 if (TextUtils.isEmpty(iface) == false) { 2316 if (resetMask != 0) { 2317 if (DBG) log("resetConnections(" + iface + ", " + resetMask + ")"); 2318 NetworkUtils.resetConnections(iface, resetMask); 2319 2320 // Tell VPN the interface is down. It is a temporary 2321 // but effective fix to make VPN aware of the change. 2322 if ((resetMask & NetworkUtils.RESET_IPV4_ADDRESSES) != 0) { 2323 mVpn.interfaceStatusChanged(iface, false); 2324 } 2325 } 2326 if (resetDns) { 2327 flushVmDnsCache(); 2328 if (VDBG) log("resetting DNS cache for " + iface); 2329 try { 2330 mNetd.flushInterfaceDnsCache(iface); 2331 } catch (Exception e) { 2332 // never crash - catch them all 2333 if (DBG) loge("Exception resetting dns cache: " + e); 2334 } 2335 } 2336 } else { 2337 loge("Can't reset connection for type "+netType); 2338 } 2339 } 2340 } 2341 } 2342 2343 // Update 464xlat state. 2344 NetworkStateTracker tracker = mNetTrackers[netType]; 2345 if (mClat.requiresClat(netType, tracker)) { 2346 // If the connection was previously using clat, but is not using it now, stop the clat 2347 // daemon. Normally, this happens automatically when the connection disconnects, but if 2348 // the disconnect is not reported, or if the connection's LinkProperties changed for 2349 // some other reason (e.g., handoff changes the IP addresses on the link), it would 2350 // still be running. If it's not running, then stopping it is a no-op. 2351 if (Nat464Xlat.isRunningClat(curLp) && !Nat464Xlat.isRunningClat(newLp)) { 2352 mClat.stopClat(); 2353 } 2354 // If the link requires clat to be running, then start the daemon now. 2355 if (mNetTrackers[netType].getNetworkInfo().isConnected()) { 2356 mClat.startClat(tracker); 2357 } else { 2358 mClat.stopClat(); 2359 } 2360 } 2361 2362 // TODO: Temporary notifying upstread change to Tethering. 2363 // @see bug/4455071 2364 /** Notify TetheringService if interface name has been changed. */ 2365 if (TextUtils.equals(mNetTrackers[netType].getNetworkInfo().getReason(), 2366 PhoneConstants.REASON_LINK_PROPERTIES_CHANGED)) { 2367 if (isTetheringSupported()) { 2368 mTethering.handleTetherIfaceChange(); 2369 } 2370 } 2371 } 2372 2373 /** 2374 * Add and remove routes using the old properties (null if not previously connected), 2375 * new properties (null if becoming disconnected). May even be double null, which 2376 * is a noop. 2377 * Uses isLinkDefault to determine if default routes should be set or conversely if 2378 * host routes should be set to the dns servers 2379 * returns a boolean indicating the routes changed 2380 */ 2381 private boolean updateRoutes(LinkProperties newLp, LinkProperties curLp, 2382 boolean isLinkDefault) { 2383 Collection<RouteInfo> routesToAdd = null; 2384 CompareResult<InetAddress> dnsDiff = new CompareResult<InetAddress>(); 2385 CompareResult<RouteInfo> routeDiff = new CompareResult<RouteInfo>(); 2386 if (curLp != null) { 2387 // check for the delta between the current set and the new 2388 routeDiff = curLp.compareRoutes(newLp); 2389 dnsDiff = curLp.compareDnses(newLp); 2390 } else if (newLp != null) { 2391 routeDiff.added = newLp.getAllRoutes(); 2392 dnsDiff.added = newLp.getDnses(); 2393 } 2394 2395 boolean routesChanged = (routeDiff.removed.size() != 0 || routeDiff.added.size() != 0); 2396 2397 for (RouteInfo r : routeDiff.removed) { 2398 if (isLinkDefault || ! r.isDefaultRoute()) { 2399 removeRoute(curLp, r, TO_DEFAULT_TABLE); 2400 } 2401 if (isLinkDefault == false) { 2402 // remove from a secondary route table 2403 removeRoute(curLp, r, TO_SECONDARY_TABLE); 2404 } 2405 } 2406 2407 if (!isLinkDefault) { 2408 // handle DNS routes 2409 if (routesChanged) { 2410 // routes changed - remove all old dns entries and add new 2411 if (curLp != null) { 2412 for (InetAddress oldDns : curLp.getDnses()) { 2413 removeRouteToAddress(curLp, oldDns); 2414 } 2415 } 2416 if (newLp != null) { 2417 for (InetAddress newDns : newLp.getDnses()) { 2418 addRouteToAddress(newLp, newDns); 2419 } 2420 } 2421 } else { 2422 // no change in routes, check for change in dns themselves 2423 for (InetAddress oldDns : dnsDiff.removed) { 2424 removeRouteToAddress(curLp, oldDns); 2425 } 2426 for (InetAddress newDns : dnsDiff.added) { 2427 addRouteToAddress(newLp, newDns); 2428 } 2429 } 2430 } 2431 2432 for (RouteInfo r : routeDiff.added) { 2433 if (isLinkDefault || ! r.isDefaultRoute()) { 2434 addRoute(newLp, r, TO_DEFAULT_TABLE); 2435 } else { 2436 // add to a secondary route table 2437 addRoute(newLp, r, TO_SECONDARY_TABLE); 2438 2439 // many radios add a default route even when we don't want one. 2440 // remove the default route unless somebody else has asked for it 2441 String ifaceName = newLp.getInterfaceName(); 2442 if (TextUtils.isEmpty(ifaceName) == false && mAddedRoutes.contains(r) == false) { 2443 if (VDBG) log("Removing " + r + " for interface " + ifaceName); 2444 try { 2445 mNetd.removeRoute(ifaceName, r); 2446 } catch (Exception e) { 2447 // never crash - catch them all 2448 if (DBG) loge("Exception trying to remove a route: " + e); 2449 } 2450 } 2451 } 2452 } 2453 2454 return routesChanged; 2455 } 2456 2457 2458 /** 2459 * Reads the network specific TCP buffer sizes from SystemProperties 2460 * net.tcp.buffersize.[default|wifi|umts|edge|gprs] and set them for system 2461 * wide use 2462 */ 2463 private void updateNetworkSettings(NetworkStateTracker nt) { 2464 String key = nt.getTcpBufferSizesPropName(); 2465 String bufferSizes = key == null ? null : SystemProperties.get(key); 2466 2467 if (TextUtils.isEmpty(bufferSizes)) { 2468 if (VDBG) log(key + " not found in system properties. Using defaults"); 2469 2470 // Setting to default values so we won't be stuck to previous values 2471 key = "net.tcp.buffersize.default"; 2472 bufferSizes = SystemProperties.get(key); 2473 } 2474 2475 // Set values in kernel 2476 if (bufferSizes.length() != 0) { 2477 if (VDBG) { 2478 log("Setting TCP values: [" + bufferSizes 2479 + "] which comes from [" + key + "]"); 2480 } 2481 setBufferSize(bufferSizes); 2482 } 2483 } 2484 2485 /** 2486 * Writes TCP buffer sizes to /sys/kernel/ipv4/tcp_[r/w]mem_[min/def/max] 2487 * which maps to /proc/sys/net/ipv4/tcp_rmem and tcpwmem 2488 * 2489 * @param bufferSizes in the format of "readMin, readInitial, readMax, 2490 * writeMin, writeInitial, writeMax" 2491 */ 2492 private void setBufferSize(String bufferSizes) { 2493 try { 2494 String[] values = bufferSizes.split(","); 2495 2496 if (values.length == 6) { 2497 final String prefix = "/sys/kernel/ipv4/tcp_"; 2498 FileUtils.stringToFile(prefix + "rmem_min", values[0]); 2499 FileUtils.stringToFile(prefix + "rmem_def", values[1]); 2500 FileUtils.stringToFile(prefix + "rmem_max", values[2]); 2501 FileUtils.stringToFile(prefix + "wmem_min", values[3]); 2502 FileUtils.stringToFile(prefix + "wmem_def", values[4]); 2503 FileUtils.stringToFile(prefix + "wmem_max", values[5]); 2504 } else { 2505 loge("Invalid buffersize string: " + bufferSizes); 2506 } 2507 } catch (IOException e) { 2508 loge("Can't set tcp buffer sizes:" + e); 2509 } 2510 } 2511 2512 /** 2513 * Adjust the per-process dns entries (net.dns<x>.<pid>) based 2514 * on the highest priority active net which this process requested. 2515 * If there aren't any, clear it out 2516 */ 2517 private void reassessPidDns(int pid, boolean doBump) 2518 { 2519 if (VDBG) log("reassessPidDns for pid " + pid); 2520 Integer myPid = new Integer(pid); 2521 for(int i : mPriorityList) { 2522 if (mNetConfigs[i].isDefault()) { 2523 continue; 2524 } 2525 NetworkStateTracker nt = mNetTrackers[i]; 2526 if (nt.getNetworkInfo().isConnected() && 2527 !nt.isTeardownRequested()) { 2528 LinkProperties p = nt.getLinkProperties(); 2529 if (p == null) continue; 2530 if (mNetRequestersPids[i].contains(myPid)) { 2531 try { 2532 mNetd.setDnsInterfaceForPid(p.getInterfaceName(), pid); 2533 } catch (Exception e) { 2534 Slog.e(TAG, "exception reasseses pid dns: " + e); 2535 } 2536 return; 2537 } 2538 } 2539 } 2540 // nothing found - delete 2541 try { 2542 mNetd.clearDnsInterfaceForPid(pid); 2543 } catch (Exception e) { 2544 Slog.e(TAG, "exception clear interface from pid: " + e); 2545 } 2546 } 2547 2548 private void flushVmDnsCache() { 2549 /* 2550 * Tell the VMs to toss their DNS caches 2551 */ 2552 Intent intent = new Intent(Intent.ACTION_CLEAR_DNS_CACHE); 2553 intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING); 2554 /* 2555 * Connectivity events can happen before boot has completed ... 2556 */ 2557 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 2558 final long ident = Binder.clearCallingIdentity(); 2559 try { 2560 mContext.sendBroadcastAsUser(intent, UserHandle.ALL); 2561 } finally { 2562 Binder.restoreCallingIdentity(ident); 2563 } 2564 } 2565 2566 // Caller must grab mDnsLock. 2567 private void updateDnsLocked(String network, String iface, 2568 Collection<InetAddress> dnses, String domains) { 2569 int last = 0; 2570 if (dnses.size() == 0 && mDefaultDns != null) { 2571 dnses = new ArrayList(); 2572 dnses.add(mDefaultDns); 2573 if (DBG) { 2574 loge("no dns provided for " + network + " - using " + mDefaultDns.getHostAddress()); 2575 } 2576 } 2577 2578 try { 2579 mNetd.setDnsServersForInterface(iface, NetworkUtils.makeStrings(dnses), domains); 2580 mNetd.setDefaultInterfaceForDns(iface); 2581 for (InetAddress dns : dnses) { 2582 ++last; 2583 String key = "net.dns" + last; 2584 String value = dns.getHostAddress(); 2585 SystemProperties.set(key, value); 2586 } 2587 for (int i = last + 1; i <= mNumDnsEntries; ++i) { 2588 String key = "net.dns" + i; 2589 SystemProperties.set(key, ""); 2590 } 2591 mNumDnsEntries = last; 2592 } catch (Exception e) { 2593 if (DBG) loge("exception setting default dns interface: " + e); 2594 } 2595 } 2596 2597 private void handleDnsConfigurationChange(int netType) { 2598 // add default net's dns entries 2599 NetworkStateTracker nt = mNetTrackers[netType]; 2600 if (nt != null && nt.getNetworkInfo().isConnected() && !nt.isTeardownRequested()) { 2601 LinkProperties p = nt.getLinkProperties(); 2602 if (p == null) return; 2603 Collection<InetAddress> dnses = p.getDnses(); 2604 if (mNetConfigs[netType].isDefault()) { 2605 String network = nt.getNetworkInfo().getTypeName(); 2606 synchronized (mDnsLock) { 2607 if (!mDnsOverridden) { 2608 updateDnsLocked(network, p.getInterfaceName(), dnses, p.getDomains()); 2609 } 2610 } 2611 } else { 2612 try { 2613 mNetd.setDnsServersForInterface(p.getInterfaceName(), 2614 NetworkUtils.makeStrings(dnses), p.getDomains()); 2615 } catch (Exception e) { 2616 if (DBG) loge("exception setting dns servers: " + e); 2617 } 2618 // set per-pid dns for attached secondary nets 2619 List<Integer> pids = mNetRequestersPids[netType]; 2620 for (Integer pid : pids) { 2621 try { 2622 mNetd.setDnsInterfaceForPid(p.getInterfaceName(), pid); 2623 } catch (Exception e) { 2624 Slog.e(TAG, "exception setting interface for pid: " + e); 2625 } 2626 } 2627 } 2628 flushVmDnsCache(); 2629 } 2630 } 2631 2632 private int getRestoreDefaultNetworkDelay(int networkType) { 2633 String restoreDefaultNetworkDelayStr = SystemProperties.get( 2634 NETWORK_RESTORE_DELAY_PROP_NAME); 2635 if(restoreDefaultNetworkDelayStr != null && 2636 restoreDefaultNetworkDelayStr.length() != 0) { 2637 try { 2638 return Integer.valueOf(restoreDefaultNetworkDelayStr); 2639 } catch (NumberFormatException e) { 2640 } 2641 } 2642 // if the system property isn't set, use the value for the apn type 2643 int ret = RESTORE_DEFAULT_NETWORK_DELAY; 2644 2645 if ((networkType <= ConnectivityManager.MAX_NETWORK_TYPE) && 2646 (mNetConfigs[networkType] != null)) { 2647 ret = mNetConfigs[networkType].restoreTime; 2648 } 2649 return ret; 2650 } 2651 2652 @Override 2653 protected void dump(FileDescriptor fd, PrintWriter writer, String[] args) { 2654 final IndentingPrintWriter pw = new IndentingPrintWriter(writer, " "); 2655 if (mContext.checkCallingOrSelfPermission( 2656 android.Manifest.permission.DUMP) 2657 != PackageManager.PERMISSION_GRANTED) { 2658 pw.println("Permission Denial: can't dump ConnectivityService " + 2659 "from from pid=" + Binder.getCallingPid() + ", uid=" + 2660 Binder.getCallingUid()); 2661 return; 2662 } 2663 2664 // TODO: add locking to get atomic snapshot 2665 pw.println(); 2666 for (int i = 0; i < mNetTrackers.length; i++) { 2667 final NetworkStateTracker nst = mNetTrackers[i]; 2668 if (nst != null) { 2669 pw.println("NetworkStateTracker for " + getNetworkTypeName(i) + ":"); 2670 pw.increaseIndent(); 2671 if (nst.getNetworkInfo().isConnected()) { 2672 pw.println("Active network: " + nst.getNetworkInfo(). 2673 getTypeName()); 2674 } 2675 pw.println(nst.getNetworkInfo()); 2676 pw.println(nst.getLinkProperties()); 2677 pw.println(nst); 2678 pw.println(); 2679 pw.decreaseIndent(); 2680 } 2681 } 2682 2683 pw.println("Network Requester Pids:"); 2684 pw.increaseIndent(); 2685 for (int net : mPriorityList) { 2686 String pidString = net + ": "; 2687 for (Integer pid : mNetRequestersPids[net]) { 2688 pidString = pidString + pid.toString() + ", "; 2689 } 2690 pw.println(pidString); 2691 } 2692 pw.println(); 2693 pw.decreaseIndent(); 2694 2695 pw.println("FeatureUsers:"); 2696 pw.increaseIndent(); 2697 for (Object requester : mFeatureUsers) { 2698 pw.println(requester.toString()); 2699 } 2700 pw.println(); 2701 pw.decreaseIndent(); 2702 2703 synchronized (this) { 2704 pw.println("NetworkTranstionWakeLock is currently " + 2705 (mNetTransitionWakeLock.isHeld() ? "" : "not ") + "held."); 2706 pw.println("It was last requested for "+mNetTransitionWakeLockCausedBy); 2707 } 2708 pw.println(); 2709 2710 mTethering.dump(fd, pw, args); 2711 2712 if (mInetLog != null) { 2713 pw.println(); 2714 pw.println("Inet condition reports:"); 2715 pw.increaseIndent(); 2716 for(int i = 0; i < mInetLog.size(); i++) { 2717 pw.println(mInetLog.get(i)); 2718 } 2719 pw.decreaseIndent(); 2720 } 2721 } 2722 2723 // must be stateless - things change under us. 2724 private class NetworkStateTrackerHandler extends Handler { 2725 public NetworkStateTrackerHandler(Looper looper) { 2726 super(looper); 2727 } 2728 2729 @Override 2730 public void handleMessage(Message msg) { 2731 NetworkInfo info; 2732 switch (msg.what) { 2733 case NetworkStateTracker.EVENT_STATE_CHANGED: 2734 info = (NetworkInfo) msg.obj; 2735 int type = info.getType(); 2736 NetworkInfo.State state = info.getState(); 2737 2738 if (VDBG || (state == NetworkInfo.State.CONNECTED) || 2739 (state == NetworkInfo.State.DISCONNECTED)) { 2740 log("ConnectivityChange for " + 2741 info.getTypeName() + ": " + 2742 state + "/" + info.getDetailedState()); 2743 } 2744 2745 // After booting we'll check once for mobile provisioning 2746 // if we've provisioned by and connected. 2747 if (!mFirstProvisioningCheckStarted 2748 && (0 != Settings.Global.getInt(mContext.getContentResolver(), 2749 Settings.Global.DEVICE_PROVISIONED, 0)) 2750 && (state == NetworkInfo.State.CONNECTED)) { 2751 log("check provisioning after booting"); 2752 mFirstProvisioningCheckStarted = true; 2753 checkMobileProvisioning(true, CheckMp.MAX_TIMEOUT_MS, null); 2754 } 2755 2756 EventLogTags.writeConnectivityStateChanged( 2757 info.getType(), info.getSubtype(), info.getDetailedState().ordinal()); 2758 2759 if (info.getDetailedState() == 2760 NetworkInfo.DetailedState.FAILED) { 2761 handleConnectionFailure(info); 2762 } else if (info.getDetailedState() == 2763 DetailedState.CAPTIVE_PORTAL_CHECK) { 2764 handleCaptivePortalTrackerCheck(info); 2765 } else if (state == NetworkInfo.State.DISCONNECTED) { 2766 handleDisconnect(info); 2767 } else if (state == NetworkInfo.State.SUSPENDED) { 2768 // TODO: need to think this over. 2769 // the logic here is, handle SUSPENDED the same as 2770 // DISCONNECTED. The only difference being we are 2771 // broadcasting an intent with NetworkInfo that's 2772 // suspended. This allows the applications an 2773 // opportunity to handle DISCONNECTED and SUSPENDED 2774 // differently, or not. 2775 handleDisconnect(info); 2776 } else if (state == NetworkInfo.State.CONNECTED) { 2777 handleConnect(info); 2778 } 2779 if (mLockdownTracker != null) { 2780 mLockdownTracker.onNetworkInfoChanged(info); 2781 } 2782 break; 2783 case NetworkStateTracker.EVENT_CONFIGURATION_CHANGED: 2784 info = (NetworkInfo) msg.obj; 2785 // TODO: Temporary allowing network configuration 2786 // change not resetting sockets. 2787 // @see bug/4455071 2788 handleConnectivityChange(info.getType(), false); 2789 break; 2790 case NetworkStateTracker.EVENT_NETWORK_SUBTYPE_CHANGED: 2791 info = (NetworkInfo) msg.obj; 2792 type = info.getType(); 2793 updateNetworkSettings(mNetTrackers[type]); 2794 break; 2795 } 2796 } 2797 } 2798 2799 private class InternalHandler extends Handler { 2800 public InternalHandler(Looper looper) { 2801 super(looper); 2802 } 2803 2804 @Override 2805 public void handleMessage(Message msg) { 2806 NetworkInfo info; 2807 switch (msg.what) { 2808 case EVENT_CLEAR_NET_TRANSITION_WAKELOCK: 2809 String causedBy = null; 2810 synchronized (ConnectivityService.this) { 2811 if (msg.arg1 == mNetTransitionWakeLockSerialNumber && 2812 mNetTransitionWakeLock.isHeld()) { 2813 mNetTransitionWakeLock.release(); 2814 causedBy = mNetTransitionWakeLockCausedBy; 2815 } 2816 } 2817 if (causedBy != null) { 2818 log("NetTransition Wakelock for " + causedBy + " released by timeout"); 2819 } 2820 break; 2821 case EVENT_RESTORE_DEFAULT_NETWORK: 2822 FeatureUser u = (FeatureUser)msg.obj; 2823 u.expire(); 2824 break; 2825 case EVENT_INET_CONDITION_CHANGE: 2826 { 2827 int netType = msg.arg1; 2828 int condition = msg.arg2; 2829 handleInetConditionChange(netType, condition); 2830 break; 2831 } 2832 case EVENT_INET_CONDITION_HOLD_END: 2833 { 2834 int netType = msg.arg1; 2835 int sequence = msg.arg2; 2836 handleInetConditionHoldEnd(netType, sequence); 2837 break; 2838 } 2839 case EVENT_SET_NETWORK_PREFERENCE: 2840 { 2841 int preference = msg.arg1; 2842 handleSetNetworkPreference(preference); 2843 break; 2844 } 2845 case EVENT_SET_MOBILE_DATA: 2846 { 2847 boolean enabled = (msg.arg1 == ENABLED); 2848 handleSetMobileData(enabled); 2849 break; 2850 } 2851 case EVENT_APPLY_GLOBAL_HTTP_PROXY: 2852 { 2853 handleDeprecatedGlobalHttpProxy(); 2854 break; 2855 } 2856 case EVENT_SET_DEPENDENCY_MET: 2857 { 2858 boolean met = (msg.arg1 == ENABLED); 2859 handleSetDependencyMet(msg.arg2, met); 2860 break; 2861 } 2862 case EVENT_RESTORE_DNS: 2863 { 2864 if (mActiveDefaultNetwork != -1) { 2865 handleDnsConfigurationChange(mActiveDefaultNetwork); 2866 } 2867 break; 2868 } 2869 case EVENT_SEND_STICKY_BROADCAST_INTENT: 2870 { 2871 Intent intent = (Intent)msg.obj; 2872 sendStickyBroadcast(intent); 2873 break; 2874 } 2875 case EVENT_SET_POLICY_DATA_ENABLE: { 2876 final int networkType = msg.arg1; 2877 final boolean enabled = msg.arg2 == ENABLED; 2878 handleSetPolicyDataEnable(networkType, enabled); 2879 break; 2880 } 2881 case EVENT_VPN_STATE_CHANGED: { 2882 if (mLockdownTracker != null) { 2883 mLockdownTracker.onVpnStateChanged((NetworkInfo) msg.obj); 2884 } 2885 break; 2886 } 2887 case EVENT_ENABLE_FAIL_FAST_MOBILE_DATA: { 2888 int tag = mEnableFailFastMobileDataTag.get(); 2889 if (msg.arg1 == tag) { 2890 MobileDataStateTracker mobileDst = 2891 (MobileDataStateTracker) mNetTrackers[ConnectivityManager.TYPE_MOBILE]; 2892 if (mobileDst != null) { 2893 mobileDst.setEnableFailFastMobileData(msg.arg2); 2894 } 2895 } else { 2896 log("EVENT_ENABLE_FAIL_FAST_MOBILE_DATA: stale arg1:" + msg.arg1 2897 + " != tag:" + tag); 2898 } 2899 } 2900 } 2901 } 2902 } 2903 2904 // javadoc from interface 2905 public int tether(String iface) { 2906 enforceTetherChangePermission(); 2907 2908 if (isTetheringSupported()) { 2909 return mTethering.tether(iface); 2910 } else { 2911 return ConnectivityManager.TETHER_ERROR_UNSUPPORTED; 2912 } 2913 } 2914 2915 // javadoc from interface 2916 public int untether(String iface) { 2917 enforceTetherChangePermission(); 2918 2919 if (isTetheringSupported()) { 2920 return mTethering.untether(iface); 2921 } else { 2922 return ConnectivityManager.TETHER_ERROR_UNSUPPORTED; 2923 } 2924 } 2925 2926 // javadoc from interface 2927 public int getLastTetherError(String iface) { 2928 enforceTetherAccessPermission(); 2929 2930 if (isTetheringSupported()) { 2931 return mTethering.getLastTetherError(iface); 2932 } else { 2933 return ConnectivityManager.TETHER_ERROR_UNSUPPORTED; 2934 } 2935 } 2936 2937 // TODO - proper iface API for selection by property, inspection, etc 2938 public String[] getTetherableUsbRegexs() { 2939 enforceTetherAccessPermission(); 2940 if (isTetheringSupported()) { 2941 return mTethering.getTetherableUsbRegexs(); 2942 } else { 2943 return new String[0]; 2944 } 2945 } 2946 2947 public String[] getTetherableWifiRegexs() { 2948 enforceTetherAccessPermission(); 2949 if (isTetheringSupported()) { 2950 return mTethering.getTetherableWifiRegexs(); 2951 } else { 2952 return new String[0]; 2953 } 2954 } 2955 2956 public String[] getTetherableBluetoothRegexs() { 2957 enforceTetherAccessPermission(); 2958 if (isTetheringSupported()) { 2959 return mTethering.getTetherableBluetoothRegexs(); 2960 } else { 2961 return new String[0]; 2962 } 2963 } 2964 2965 public int setUsbTethering(boolean enable) { 2966 enforceTetherChangePermission(); 2967 if (isTetheringSupported()) { 2968 return mTethering.setUsbTethering(enable); 2969 } else { 2970 return ConnectivityManager.TETHER_ERROR_UNSUPPORTED; 2971 } 2972 } 2973 2974 // TODO - move iface listing, queries, etc to new module 2975 // javadoc from interface 2976 public String[] getTetherableIfaces() { 2977 enforceTetherAccessPermission(); 2978 return mTethering.getTetherableIfaces(); 2979 } 2980 2981 public String[] getTetheredIfaces() { 2982 enforceTetherAccessPermission(); 2983 return mTethering.getTetheredIfaces(); 2984 } 2985 2986 @Override 2987 public String[] getTetheredIfacePairs() { 2988 enforceTetherAccessPermission(); 2989 return mTethering.getTetheredIfacePairs(); 2990 } 2991 2992 public String[] getTetheringErroredIfaces() { 2993 enforceTetherAccessPermission(); 2994 return mTethering.getErroredIfaces(); 2995 } 2996 2997 // if ro.tether.denied = true we default to no tethering 2998 // gservices could set the secure setting to 1 though to enable it on a build where it 2999 // had previously been turned off. 3000 public boolean isTetheringSupported() { 3001 enforceTetherAccessPermission(); 3002 int defaultVal = (SystemProperties.get("ro.tether.denied").equals("true") ? 0 : 1); 3003 boolean tetherEnabledInSettings = (Settings.Global.getInt(mContext.getContentResolver(), 3004 Settings.Global.TETHER_SUPPORTED, defaultVal) != 0); 3005 return tetherEnabledInSettings && mTetheringConfigValid; 3006 } 3007 3008 // An API NetworkStateTrackers can call when they lose their network. 3009 // This will automatically be cleared after X seconds or a network becomes CONNECTED, 3010 // whichever happens first. The timer is started by the first caller and not 3011 // restarted by subsequent callers. 3012 public void requestNetworkTransitionWakelock(String forWhom) { 3013 enforceConnectivityInternalPermission(); 3014 synchronized (this) { 3015 if (mNetTransitionWakeLock.isHeld()) return; 3016 mNetTransitionWakeLockSerialNumber++; 3017 mNetTransitionWakeLock.acquire(); 3018 mNetTransitionWakeLockCausedBy = forWhom; 3019 } 3020 mHandler.sendMessageDelayed(mHandler.obtainMessage( 3021 EVENT_CLEAR_NET_TRANSITION_WAKELOCK, 3022 mNetTransitionWakeLockSerialNumber, 0), 3023 mNetTransitionWakeLockTimeout); 3024 return; 3025 } 3026 3027 // 100 percent is full good, 0 is full bad. 3028 public void reportInetCondition(int networkType, int percentage) { 3029 if (VDBG) log("reportNetworkCondition(" + networkType + ", " + percentage + ")"); 3030 mContext.enforceCallingOrSelfPermission( 3031 android.Manifest.permission.STATUS_BAR, 3032 "ConnectivityService"); 3033 3034 if (DBG) { 3035 int pid = getCallingPid(); 3036 int uid = getCallingUid(); 3037 String s = pid + "(" + uid + ") reports inet is " + 3038 (percentage > 50 ? "connected" : "disconnected") + " (" + percentage + ") on " + 3039 "network Type " + networkType + " at " + GregorianCalendar.getInstance().getTime(); 3040 mInetLog.add(s); 3041 while(mInetLog.size() > INET_CONDITION_LOG_MAX_SIZE) { 3042 mInetLog.remove(0); 3043 } 3044 } 3045 mHandler.sendMessage(mHandler.obtainMessage( 3046 EVENT_INET_CONDITION_CHANGE, networkType, percentage)); 3047 } 3048 3049 private void handleInetConditionChange(int netType, int condition) { 3050 if (mActiveDefaultNetwork == -1) { 3051 if (DBG) log("handleInetConditionChange: no active default network - ignore"); 3052 return; 3053 } 3054 if (mActiveDefaultNetwork != netType) { 3055 if (DBG) log("handleInetConditionChange: net=" + netType + 3056 " != default=" + mActiveDefaultNetwork + " - ignore"); 3057 return; 3058 } 3059 if (VDBG) { 3060 log("handleInetConditionChange: net=" + 3061 netType + ", condition=" + condition + 3062 ",mActiveDefaultNetwork=" + mActiveDefaultNetwork); 3063 } 3064 mDefaultInetCondition = condition; 3065 int delay; 3066 if (mInetConditionChangeInFlight == false) { 3067 if (VDBG) log("handleInetConditionChange: starting a change hold"); 3068 // setup a new hold to debounce this 3069 if (mDefaultInetCondition > 50) { 3070 delay = Settings.Global.getInt(mContext.getContentResolver(), 3071 Settings.Global.INET_CONDITION_DEBOUNCE_UP_DELAY, 500); 3072 } else { 3073 delay = Settings.Global.getInt(mContext.getContentResolver(), 3074 Settings.Global.INET_CONDITION_DEBOUNCE_DOWN_DELAY, 3000); 3075 } 3076 mInetConditionChangeInFlight = true; 3077 mHandler.sendMessageDelayed(mHandler.obtainMessage(EVENT_INET_CONDITION_HOLD_END, 3078 mActiveDefaultNetwork, mDefaultConnectionSequence), delay); 3079 } else { 3080 // we've set the new condition, when this hold ends that will get picked up 3081 if (VDBG) log("handleInetConditionChange: currently in hold - not setting new end evt"); 3082 } 3083 } 3084 3085 private void handleInetConditionHoldEnd(int netType, int sequence) { 3086 if (DBG) { 3087 log("handleInetConditionHoldEnd: net=" + netType + 3088 ", condition=" + mDefaultInetCondition + 3089 ", published condition=" + mDefaultInetConditionPublished); 3090 } 3091 mInetConditionChangeInFlight = false; 3092 3093 if (mActiveDefaultNetwork == -1) { 3094 if (DBG) log("handleInetConditionHoldEnd: no active default network - ignoring"); 3095 return; 3096 } 3097 if (mDefaultConnectionSequence != sequence) { 3098 if (DBG) log("handleInetConditionHoldEnd: event hold for obsolete network - ignoring"); 3099 return; 3100 } 3101 // TODO: Figure out why this optimization sometimes causes a 3102 // change in mDefaultInetCondition to be missed and the 3103 // UI to not be updated. 3104 //if (mDefaultInetConditionPublished == mDefaultInetCondition) { 3105 // if (DBG) log("no change in condition - aborting"); 3106 // return; 3107 //} 3108 NetworkInfo networkInfo = mNetTrackers[mActiveDefaultNetwork].getNetworkInfo(); 3109 if (networkInfo.isConnected() == false) { 3110 if (DBG) log("handleInetConditionHoldEnd: default network not connected - ignoring"); 3111 return; 3112 } 3113 mDefaultInetConditionPublished = mDefaultInetCondition; 3114 sendInetConditionBroadcast(networkInfo); 3115 return; 3116 } 3117 3118 public ProxyProperties getProxy() { 3119 // this information is already available as a world read/writable jvm property 3120 // so this API change wouldn't have a benifit. It also breaks the passing 3121 // of proxy info to all the JVMs. 3122 // enforceAccessPermission(); 3123 synchronized (mProxyLock) { 3124 if (mGlobalProxy != null) return mGlobalProxy; 3125 return (mDefaultProxyDisabled ? null : mDefaultProxy); 3126 } 3127 } 3128 3129 public void setGlobalProxy(ProxyProperties proxyProperties) { 3130 enforceConnectivityInternalPermission(); 3131 synchronized (mProxyLock) { 3132 if (proxyProperties == mGlobalProxy) return; 3133 if (proxyProperties != null && proxyProperties.equals(mGlobalProxy)) return; 3134 if (mGlobalProxy != null && mGlobalProxy.equals(proxyProperties)) return; 3135 3136 String host = ""; 3137 int port = 0; 3138 String exclList = ""; 3139 if (proxyProperties != null && !TextUtils.isEmpty(proxyProperties.getHost())) { 3140 mGlobalProxy = new ProxyProperties(proxyProperties); 3141 host = mGlobalProxy.getHost(); 3142 port = mGlobalProxy.getPort(); 3143 exclList = mGlobalProxy.getExclusionList(); 3144 } else { 3145 mGlobalProxy = null; 3146 } 3147 ContentResolver res = mContext.getContentResolver(); 3148 final long token = Binder.clearCallingIdentity(); 3149 try { 3150 Settings.Global.putString(res, Settings.Global.GLOBAL_HTTP_PROXY_HOST, host); 3151 Settings.Global.putInt(res, Settings.Global.GLOBAL_HTTP_PROXY_PORT, port); 3152 Settings.Global.putString(res, Settings.Global.GLOBAL_HTTP_PROXY_EXCLUSION_LIST, 3153 exclList); 3154 } finally { 3155 Binder.restoreCallingIdentity(token); 3156 } 3157 } 3158 3159 if (mGlobalProxy == null) { 3160 proxyProperties = mDefaultProxy; 3161 } 3162 sendProxyBroadcast(proxyProperties); 3163 } 3164 3165 private void loadGlobalProxy() { 3166 ContentResolver res = mContext.getContentResolver(); 3167 String host = Settings.Global.getString(res, Settings.Global.GLOBAL_HTTP_PROXY_HOST); 3168 int port = Settings.Global.getInt(res, Settings.Global.GLOBAL_HTTP_PROXY_PORT, 0); 3169 String exclList = Settings.Global.getString(res, 3170 Settings.Global.GLOBAL_HTTP_PROXY_EXCLUSION_LIST); 3171 if (!TextUtils.isEmpty(host)) { 3172 ProxyProperties proxyProperties = new ProxyProperties(host, port, exclList); 3173 synchronized (mProxyLock) { 3174 mGlobalProxy = proxyProperties; 3175 } 3176 } 3177 } 3178 3179 public ProxyProperties getGlobalProxy() { 3180 // this information is already available as a world read/writable jvm property 3181 // so this API change wouldn't have a benifit. It also breaks the passing 3182 // of proxy info to all the JVMs. 3183 // enforceAccessPermission(); 3184 synchronized (mProxyLock) { 3185 return mGlobalProxy; 3186 } 3187 } 3188 3189 private void handleApplyDefaultProxy(ProxyProperties proxy) { 3190 if (proxy != null && TextUtils.isEmpty(proxy.getHost())) { 3191 proxy = null; 3192 } 3193 synchronized (mProxyLock) { 3194 if (mDefaultProxy != null && mDefaultProxy.equals(proxy)) return; 3195 if (mDefaultProxy == proxy) return; // catches repeated nulls 3196 mDefaultProxy = proxy; 3197 3198 if (mGlobalProxy != null) return; 3199 if (!mDefaultProxyDisabled) { 3200 sendProxyBroadcast(proxy); 3201 } 3202 } 3203 } 3204 3205 private void handleDeprecatedGlobalHttpProxy() { 3206 String proxy = Settings.Global.getString(mContext.getContentResolver(), 3207 Settings.Global.HTTP_PROXY); 3208 if (!TextUtils.isEmpty(proxy)) { 3209 String data[] = proxy.split(":"); 3210 String proxyHost = data[0]; 3211 int proxyPort = 8080; 3212 if (data.length > 1) { 3213 try { 3214 proxyPort = Integer.parseInt(data[1]); 3215 } catch (NumberFormatException e) { 3216 return; 3217 } 3218 } 3219 ProxyProperties p = new ProxyProperties(data[0], proxyPort, ""); 3220 setGlobalProxy(p); 3221 } 3222 } 3223 3224 private void sendProxyBroadcast(ProxyProperties proxy) { 3225 if (proxy == null) proxy = new ProxyProperties("", 0, ""); 3226 if (DBG) log("sending Proxy Broadcast for " + proxy); 3227 Intent intent = new Intent(Proxy.PROXY_CHANGE_ACTION); 3228 intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING | 3229 Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 3230 intent.putExtra(Proxy.EXTRA_PROXY_INFO, proxy); 3231 final long ident = Binder.clearCallingIdentity(); 3232 try { 3233 mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); 3234 } finally { 3235 Binder.restoreCallingIdentity(ident); 3236 } 3237 } 3238 3239 private static class SettingsObserver extends ContentObserver { 3240 private int mWhat; 3241 private Handler mHandler; 3242 SettingsObserver(Handler handler, int what) { 3243 super(handler); 3244 mHandler = handler; 3245 mWhat = what; 3246 } 3247 3248 void observe(Context context) { 3249 ContentResolver resolver = context.getContentResolver(); 3250 resolver.registerContentObserver(Settings.Global.getUriFor( 3251 Settings.Global.HTTP_PROXY), false, this); 3252 } 3253 3254 @Override 3255 public void onChange(boolean selfChange) { 3256 mHandler.obtainMessage(mWhat).sendToTarget(); 3257 } 3258 } 3259 3260 private static void log(String s) { 3261 Slog.d(TAG, s); 3262 } 3263 3264 private static void loge(String s) { 3265 Slog.e(TAG, s); 3266 } 3267 3268 int convertFeatureToNetworkType(int networkType, String feature) { 3269 int usedNetworkType = networkType; 3270 3271 if(networkType == ConnectivityManager.TYPE_MOBILE) { 3272 if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_MMS)) { 3273 usedNetworkType = ConnectivityManager.TYPE_MOBILE_MMS; 3274 } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_SUPL)) { 3275 usedNetworkType = ConnectivityManager.TYPE_MOBILE_SUPL; 3276 } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_DUN) || 3277 TextUtils.equals(feature, Phone.FEATURE_ENABLE_DUN_ALWAYS)) { 3278 usedNetworkType = ConnectivityManager.TYPE_MOBILE_DUN; 3279 } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_HIPRI)) { 3280 usedNetworkType = ConnectivityManager.TYPE_MOBILE_HIPRI; 3281 } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_FOTA)) { 3282 usedNetworkType = ConnectivityManager.TYPE_MOBILE_FOTA; 3283 } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_IMS)) { 3284 usedNetworkType = ConnectivityManager.TYPE_MOBILE_IMS; 3285 } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_CBS)) { 3286 usedNetworkType = ConnectivityManager.TYPE_MOBILE_CBS; 3287 } else { 3288 Slog.e(TAG, "Can't match any mobile netTracker!"); 3289 } 3290 } else if (networkType == ConnectivityManager.TYPE_WIFI) { 3291 if (TextUtils.equals(feature, "p2p")) { 3292 usedNetworkType = ConnectivityManager.TYPE_WIFI_P2P; 3293 } else { 3294 Slog.e(TAG, "Can't match any wifi netTracker!"); 3295 } 3296 } else { 3297 Slog.e(TAG, "Unexpected network type"); 3298 } 3299 return usedNetworkType; 3300 } 3301 3302 private static <T> T checkNotNull(T value, String message) { 3303 if (value == null) { 3304 throw new NullPointerException(message); 3305 } 3306 return value; 3307 } 3308 3309 /** 3310 * Protect a socket from VPN routing rules. This method is used by 3311 * VpnBuilder and not available in ConnectivityManager. Permissions 3312 * are checked in Vpn class. 3313 * @hide 3314 */ 3315 @Override 3316 public boolean protectVpn(ParcelFileDescriptor socket) { 3317 throwIfLockdownEnabled(); 3318 try { 3319 int type = mActiveDefaultNetwork; 3320 if (ConnectivityManager.isNetworkTypeValid(type) && mNetTrackers[type] != null) { 3321 mVpn.protect(socket, mNetTrackers[type].getLinkProperties().getInterfaceName()); 3322 return true; 3323 } 3324 } catch (Exception e) { 3325 // ignore 3326 } finally { 3327 try { 3328 socket.close(); 3329 } catch (Exception e) { 3330 // ignore 3331 } 3332 } 3333 return false; 3334 } 3335 3336 /** 3337 * Prepare for a VPN application. This method is used by VpnDialogs 3338 * and not available in ConnectivityManager. Permissions are checked 3339 * in Vpn class. 3340 * @hide 3341 */ 3342 @Override 3343 public boolean prepareVpn(String oldPackage, String newPackage) { 3344 throwIfLockdownEnabled(); 3345 return mVpn.prepare(oldPackage, newPackage); 3346 } 3347 3348 /** 3349 * Configure a TUN interface and return its file descriptor. Parameters 3350 * are encoded and opaque to this class. This method is used by VpnBuilder 3351 * and not available in ConnectivityManager. Permissions are checked in 3352 * Vpn class. 3353 * @hide 3354 */ 3355 @Override 3356 public ParcelFileDescriptor establishVpn(VpnConfig config) { 3357 throwIfLockdownEnabled(); 3358 return mVpn.establish(config); 3359 } 3360 3361 /** 3362 * Start legacy VPN, controlling native daemons as needed. Creates a 3363 * secondary thread to perform connection work, returning quickly. 3364 */ 3365 @Override 3366 public void startLegacyVpn(VpnProfile profile) { 3367 throwIfLockdownEnabled(); 3368 final LinkProperties egress = getActiveLinkProperties(); 3369 if (egress == null) { 3370 throw new IllegalStateException("Missing active network connection"); 3371 } 3372 mVpn.startLegacyVpn(profile, mKeyStore, egress); 3373 } 3374 3375 /** 3376 * Return the information of the ongoing legacy VPN. This method is used 3377 * by VpnSettings and not available in ConnectivityManager. Permissions 3378 * are checked in Vpn class. 3379 * @hide 3380 */ 3381 @Override 3382 public LegacyVpnInfo getLegacyVpnInfo() { 3383 throwIfLockdownEnabled(); 3384 return mVpn.getLegacyVpnInfo(); 3385 } 3386 3387 /** 3388 * Callback for VPN subsystem. Currently VPN is not adapted to the service 3389 * through NetworkStateTracker since it works differently. For example, it 3390 * needs to override DNS servers but never takes the default routes. It 3391 * relies on another data network, and it could keep existing connections 3392 * alive after reconnecting, switching between networks, or even resuming 3393 * from deep sleep. Calls from applications should be done synchronously 3394 * to avoid race conditions. As these are all hidden APIs, refactoring can 3395 * be done whenever a better abstraction is developed. 3396 */ 3397 public class VpnCallback { 3398 private VpnCallback() { 3399 } 3400 3401 public void onStateChanged(NetworkInfo info) { 3402 mHandler.obtainMessage(EVENT_VPN_STATE_CHANGED, info).sendToTarget(); 3403 } 3404 3405 public void override(List<String> dnsServers, List<String> searchDomains) { 3406 if (dnsServers == null) { 3407 restore(); 3408 return; 3409 } 3410 3411 // Convert DNS servers into addresses. 3412 List<InetAddress> addresses = new ArrayList<InetAddress>(); 3413 for (String address : dnsServers) { 3414 // Double check the addresses and remove invalid ones. 3415 try { 3416 addresses.add(InetAddress.parseNumericAddress(address)); 3417 } catch (Exception e) { 3418 // ignore 3419 } 3420 } 3421 if (addresses.isEmpty()) { 3422 restore(); 3423 return; 3424 } 3425 3426 // Concatenate search domains into a string. 3427 StringBuilder buffer = new StringBuilder(); 3428 if (searchDomains != null) { 3429 for (String domain : searchDomains) { 3430 buffer.append(domain).append(' '); 3431 } 3432 } 3433 String domains = buffer.toString().trim(); 3434 3435 // Apply DNS changes. 3436 synchronized (mDnsLock) { 3437 updateDnsLocked("VPN", "VPN", addresses, domains); 3438 mDnsOverridden = true; 3439 } 3440 3441 // Temporarily disable the default proxy (not global). 3442 synchronized (mProxyLock) { 3443 mDefaultProxyDisabled = true; 3444 if (mGlobalProxy == null && mDefaultProxy != null) { 3445 sendProxyBroadcast(null); 3446 } 3447 } 3448 3449 // TODO: support proxy per network. 3450 } 3451 3452 public void restore() { 3453 synchronized (mDnsLock) { 3454 if (mDnsOverridden) { 3455 mDnsOverridden = false; 3456 mHandler.sendEmptyMessage(EVENT_RESTORE_DNS); 3457 } 3458 } 3459 synchronized (mProxyLock) { 3460 mDefaultProxyDisabled = false; 3461 if (mGlobalProxy == null && mDefaultProxy != null) { 3462 sendProxyBroadcast(mDefaultProxy); 3463 } 3464 } 3465 } 3466 } 3467 3468 @Override 3469 public boolean updateLockdownVpn() { 3470 if (Binder.getCallingUid() != Process.SYSTEM_UID) { 3471 Slog.w(TAG, "Lockdown VPN only available to AID_SYSTEM"); 3472 return false; 3473 } 3474 3475 // Tear down existing lockdown if profile was removed 3476 mLockdownEnabled = LockdownVpnTracker.isEnabled(); 3477 if (mLockdownEnabled) { 3478 if (!mKeyStore.isUnlocked()) { 3479 Slog.w(TAG, "KeyStore locked; unable to create LockdownTracker"); 3480 return false; 3481 } 3482 3483 final String profileName = new String(mKeyStore.get(Credentials.LOCKDOWN_VPN)); 3484 final VpnProfile profile = VpnProfile.decode( 3485 profileName, mKeyStore.get(Credentials.VPN + profileName)); 3486 setLockdownTracker(new LockdownVpnTracker(mContext, mNetd, this, mVpn, profile)); 3487 } else { 3488 setLockdownTracker(null); 3489 } 3490 3491 return true; 3492 } 3493 3494 /** 3495 * Internally set new {@link LockdownVpnTracker}, shutting down any existing 3496 * {@link LockdownVpnTracker}. Can be {@code null} to disable lockdown. 3497 */ 3498 private void setLockdownTracker(LockdownVpnTracker tracker) { 3499 // Shutdown any existing tracker 3500 final LockdownVpnTracker existing = mLockdownTracker; 3501 mLockdownTracker = null; 3502 if (existing != null) { 3503 existing.shutdown(); 3504 } 3505 3506 try { 3507 if (tracker != null) { 3508 mNetd.setFirewallEnabled(true); 3509 mNetd.setFirewallInterfaceRule("lo", true); 3510 mLockdownTracker = tracker; 3511 mLockdownTracker.init(); 3512 } else { 3513 mNetd.setFirewallEnabled(false); 3514 } 3515 } catch (RemoteException e) { 3516 // ignored; NMS lives inside system_server 3517 } 3518 } 3519 3520 private void throwIfLockdownEnabled() { 3521 if (mLockdownEnabled) { 3522 throw new IllegalStateException("Unavailable in lockdown mode"); 3523 } 3524 } 3525 3526 public void supplyMessenger(int networkType, Messenger messenger) { 3527 enforceConnectivityInternalPermission(); 3528 3529 if (isNetworkTypeValid(networkType) && mNetTrackers[networkType] != null) { 3530 mNetTrackers[networkType].supplyMessenger(messenger); 3531 } 3532 } 3533 3534 public int findConnectionTypeForIface(String iface) { 3535 enforceConnectivityInternalPermission(); 3536 3537 if (TextUtils.isEmpty(iface)) return ConnectivityManager.TYPE_NONE; 3538 for (NetworkStateTracker tracker : mNetTrackers) { 3539 if (tracker != null) { 3540 LinkProperties lp = tracker.getLinkProperties(); 3541 if (lp != null && iface.equals(lp.getInterfaceName())) { 3542 return tracker.getNetworkInfo().getType(); 3543 } 3544 } 3545 } 3546 return ConnectivityManager.TYPE_NONE; 3547 } 3548 3549 /** 3550 * Have mobile data fail fast if enabled. 3551 * 3552 * @param enabled DctConstants.ENABLED/DISABLED 3553 */ 3554 private void setEnableFailFastMobileData(int enabled) { 3555 int tag; 3556 3557 if (enabled == DctConstants.ENABLED) { 3558 tag = mEnableFailFastMobileDataTag.incrementAndGet(); 3559 } else { 3560 tag = mEnableFailFastMobileDataTag.get(); 3561 } 3562 mHandler.sendMessage(mHandler.obtainMessage(EVENT_ENABLE_FAIL_FAST_MOBILE_DATA, tag, 3563 enabled)); 3564 } 3565 3566 @Override 3567 public int checkMobileProvisioning(boolean sendNotification, int suggestedTimeOutMs, 3568 final ResultReceiver resultReceiver) { 3569 log("checkMobileProvisioning: E sendNotification=" + sendNotification 3570 + " suggestedTimeOutMs=" + suggestedTimeOutMs 3571 + " resultReceiver=" + resultReceiver); 3572 enforceChangePermission(); 3573 3574 mFirstProvisioningCheckStarted = true; 3575 3576 int timeOutMs = suggestedTimeOutMs; 3577 if (suggestedTimeOutMs > CheckMp.MAX_TIMEOUT_MS) { 3578 timeOutMs = CheckMp.MAX_TIMEOUT_MS; 3579 } 3580 3581 // Check that mobile networks are supported 3582 if (!isNetworkSupported(ConnectivityManager.TYPE_MOBILE) 3583 || !isNetworkSupported(ConnectivityManager.TYPE_MOBILE_HIPRI)) { 3584 log("checkMobileProvisioning: X no mobile network"); 3585 if (resultReceiver != null) { 3586 resultReceiver.send(ConnectivityManager.CMP_RESULT_CODE_NO_CONNECTION, null); 3587 } 3588 return timeOutMs; 3589 } 3590 3591 final long token = Binder.clearCallingIdentity(); 3592 try { 3593 CheckMp checkMp = new CheckMp(mContext, this); 3594 CheckMp.CallBack cb = new CheckMp.CallBack() { 3595 @Override 3596 void onComplete(Integer result) { 3597 log("CheckMp.onComplete: result=" + result); 3598 if (resultReceiver != null) { 3599 log("CheckMp.onComplete: send result"); 3600 resultReceiver.send(result, null); 3601 } 3602 NetworkInfo ni = 3603 mNetTrackers[ConnectivityManager.TYPE_MOBILE_HIPRI].getNetworkInfo(); 3604 switch(result) { 3605 case ConnectivityManager.CMP_RESULT_CODE_CONNECTABLE: 3606 case ConnectivityManager.CMP_RESULT_CODE_NO_CONNECTION: { 3607 log("CheckMp.onComplete: ignore, connected or no connection"); 3608 break; 3609 } 3610 case ConnectivityManager.CMP_RESULT_CODE_REDIRECTED: { 3611 log("CheckMp.onComplete: warm sim"); 3612 String url = getMobileProvisioningUrl(); 3613 if (TextUtils.isEmpty(url)) { 3614 url = getMobileRedirectedProvisioningUrl(); 3615 } 3616 if (TextUtils.isEmpty(url) == false) { 3617 log("CheckMp.onComplete: warm sim (redirected), url=" + url); 3618 setNotificationVisible(true, ni, url); 3619 } else { 3620 log("CheckMp.onComplete: warm sim (redirected), no url"); 3621 } 3622 break; 3623 } 3624 case ConnectivityManager.CMP_RESULT_CODE_NO_DNS: 3625 case ConnectivityManager.CMP_RESULT_CODE_NO_TCP_CONNECTION: { 3626 String url = getMobileProvisioningUrl(); 3627 if (TextUtils.isEmpty(url) == false) { 3628 log("CheckMp.onComplete: warm sim (no dns/tcp), url=" + url); 3629 setNotificationVisible(true, ni, url); 3630 } else { 3631 log("CheckMp.onComplete: warm sim (no dns/tcp), no url"); 3632 } 3633 break; 3634 } 3635 default: { 3636 loge("CheckMp.onComplete: ignore unexpected result=" + result); 3637 break; 3638 } 3639 } 3640 } 3641 }; 3642 CheckMp.Params params = 3643 new CheckMp.Params(checkMp.getDefaultUrl(), timeOutMs, cb); 3644 log("checkMobileProvisioning: params=" + params); 3645 setNotificationVisible(false, null, null); 3646 checkMp.execute(params); 3647 } finally { 3648 Binder.restoreCallingIdentity(token); 3649 log("checkMobileProvisioning: X"); 3650 } 3651 return timeOutMs; 3652 } 3653 3654 static class CheckMp extends 3655 AsyncTask<CheckMp.Params, Void, Integer> { 3656 private static final String CHECKMP_TAG = "CheckMp"; 3657 public static final int MAX_TIMEOUT_MS = 60000; 3658 private static final int SOCKET_TIMEOUT_MS = 5000; 3659 private Context mContext; 3660 private ConnectivityService mCs; 3661 private TelephonyManager mTm; 3662 private Params mParams; 3663 3664 /** 3665 * Parameters for AsyncTask.execute 3666 */ 3667 static class Params { 3668 private String mUrl; 3669 private long mTimeOutMs; 3670 private CallBack mCb; 3671 3672 Params(String url, long timeOutMs, CallBack cb) { 3673 mUrl = url; 3674 mTimeOutMs = timeOutMs; 3675 mCb = cb; 3676 } 3677 3678 @Override 3679 public String toString() { 3680 return "{" + " url=" + mUrl + " mTimeOutMs=" + mTimeOutMs + " mCb=" + mCb + "}"; 3681 } 3682 } 3683 3684 /** 3685 * The call back object passed in Params. onComplete will be called 3686 * on the main thread. 3687 */ 3688 abstract static class CallBack { 3689 // Called on the main thread. 3690 abstract void onComplete(Integer result); 3691 } 3692 3693 public CheckMp(Context context, ConnectivityService cs) { 3694 mContext = context; 3695 mCs = cs; 3696 3697 // Setup access to TelephonyService we'll be using. 3698 mTm = (TelephonyManager) mContext.getSystemService( 3699 Context.TELEPHONY_SERVICE); 3700 } 3701 3702 /** 3703 * Get the default url to use for the test. 3704 */ 3705 public String getDefaultUrl() { 3706 // See http://go/clientsdns for usage approval 3707 String server = Settings.Global.getString(mContext.getContentResolver(), 3708 Settings.Global.CAPTIVE_PORTAL_SERVER); 3709 if (server == null) { 3710 server = "clients3.google.com"; 3711 } 3712 return "http://" + server + "/generate_204"; 3713 } 3714 3715 /** 3716 * Detect if its possible to connect to the http url. DNS based detection techniques 3717 * do not work at all hotspots. The best way to check is to perform a request to 3718 * a known address that fetches the data we expect. 3719 */ 3720 private synchronized Integer isMobileOk(Params params) { 3721 Integer result = ConnectivityManager.CMP_RESULT_CODE_NO_CONNECTION; 3722 Uri orgUri = Uri.parse(params.mUrl); 3723 Random rand = new Random(); 3724 mParams = params; 3725 3726 try { 3727 if (mCs.isNetworkSupported(ConnectivityManager.TYPE_MOBILE) == false) { 3728 log("isMobileOk: not mobile capable"); 3729 result = ConnectivityManager.CMP_RESULT_CODE_NO_CONNECTION; 3730 return result; 3731 } 3732 3733 // Enable fail fast as we'll do retries here and use a 3734 // hipri connection so the default connection stays active. 3735 log("isMobileOk: start hipri url=" + params.mUrl); 3736 mCs.setEnableFailFastMobileData(DctConstants.ENABLED); 3737 mCs.startUsingNetworkFeature(ConnectivityManager.TYPE_MOBILE, 3738 Phone.FEATURE_ENABLE_HIPRI, new Binder()); 3739 3740 // Continue trying to connect until time has run out 3741 long endTime = SystemClock.elapsedRealtime() + params.mTimeOutMs; 3742 while(SystemClock.elapsedRealtime() < endTime) { 3743 try { 3744 // Wait for hipri to connect. 3745 // TODO: Don't poll and handle situation where hipri fails 3746 // because default is retrying. See b/9569540 3747 NetworkInfo.State state = mCs 3748 .getNetworkInfo(ConnectivityManager.TYPE_MOBILE_HIPRI).getState(); 3749 if (state != NetworkInfo.State.CONNECTED) { 3750 log("isMobileOk: not connected ni=" + 3751 mCs.getNetworkInfo(ConnectivityManager.TYPE_MOBILE_HIPRI)); 3752 sleep(1); 3753 result = ConnectivityManager.CMP_RESULT_CODE_NO_CONNECTION; 3754 continue; 3755 } 3756 3757 // Get of the addresses associated with the url host. We need to use the 3758 // address otherwise HttpURLConnection object will use the name to get 3759 // the addresses and is will try every address but that will bypass the 3760 // route to host we setup and the connection could succeed as the default 3761 // interface might be connected to the internet via wifi or other interface. 3762 InetAddress[] addresses; 3763 try { 3764 addresses = InetAddress.getAllByName(orgUri.getHost()); 3765 } catch (UnknownHostException e) { 3766 log("isMobileOk: UnknownHostException"); 3767 result = ConnectivityManager.CMP_RESULT_CODE_NO_DNS; 3768 return result; 3769 } 3770 log("isMobileOk: addresses=" + inetAddressesToString(addresses)); 3771 3772 // Get the type of addresses supported by this link 3773 LinkProperties lp = mCs.getLinkProperties( 3774 ConnectivityManager.TYPE_MOBILE_HIPRI); 3775 boolean linkHasIpv4 = hasIPv4Address(lp); 3776 boolean linkHasIpv6 = hasIPv6Address(lp); 3777 log("isMobileOk: linkHasIpv4=" + linkHasIpv4 3778 + " linkHasIpv6=" + linkHasIpv6); 3779 3780 // Loop through at most 3 valid addresses or all of the address or until 3781 // we run out of time 3782 int loops = Math.min(3, addresses.length); 3783 for(int validAddr=0, addrTried=0; 3784 (validAddr < loops) && (addrTried < addresses.length) 3785 && (SystemClock.elapsedRealtime() < endTime); 3786 addrTried ++) { 3787 3788 // Choose the address at random but make sure its type is supported 3789 InetAddress hostAddr = addresses[rand.nextInt(addresses.length)]; 3790 if (((hostAddr instanceof Inet4Address) && linkHasIpv4) 3791 || ((hostAddr instanceof Inet6Address) && linkHasIpv6)) { 3792 // Valid address, so use it 3793 validAddr += 1; 3794 } else { 3795 // Invalid address so try next address 3796 continue; 3797 } 3798 3799 // Make a route to host so we check the specific interface. 3800 if (mCs.requestRouteToHostAddress(ConnectivityManager.TYPE_MOBILE_HIPRI, 3801 hostAddr.getAddress())) { 3802 // Wait a short time to be sure the route is established ?? 3803 log("isMobileOk:" 3804 + " wait to establish route to hostAddr=" + hostAddr); 3805 sleep(3); 3806 } else { 3807 log("isMobileOk:" 3808 + " could not establish route to hostAddr=" + hostAddr); 3809 continue; 3810 } 3811 3812 // Rewrite the url to have numeric address to use the specific route. 3813 // I also set the "Connection" to "Close" as by default "Keep-Alive" 3814 // is used which is useless in this case. 3815 URL newUrl = new URL(orgUri.getScheme() + "://" 3816 + hostAddr.getHostAddress() + orgUri.getPath()); 3817 log("isMobileOk: newUrl=" + newUrl); 3818 3819 HttpURLConnection urlConn = null; 3820 try { 3821 // Open the connection set the request header and get the response 3822 urlConn = (HttpURLConnection) newUrl.openConnection( 3823 java.net.Proxy.NO_PROXY); 3824 urlConn.setInstanceFollowRedirects(false); 3825 urlConn.setConnectTimeout(SOCKET_TIMEOUT_MS); 3826 urlConn.setReadTimeout(SOCKET_TIMEOUT_MS); 3827 urlConn.setUseCaches(false); 3828 urlConn.setAllowUserInteraction(false); 3829 urlConn.setRequestProperty("Connection", "close"); 3830 int responseCode = urlConn.getResponseCode(); 3831 if (responseCode == 204) { 3832 result = ConnectivityManager.CMP_RESULT_CODE_CONNECTABLE; 3833 } else { 3834 result = ConnectivityManager.CMP_RESULT_CODE_REDIRECTED; 3835 } 3836 log("isMobileOk: connected responseCode=" + responseCode); 3837 urlConn.disconnect(); 3838 urlConn = null; 3839 return result; 3840 } catch (Exception e) { 3841 log("isMobileOk: HttpURLConnection Exception e=" + e); 3842 if (urlConn != null) { 3843 urlConn.disconnect(); 3844 urlConn = null; 3845 } 3846 } 3847 } 3848 result = ConnectivityManager.CMP_RESULT_CODE_NO_TCP_CONNECTION; 3849 log("isMobileOk: loops|timed out"); 3850 return result; 3851 } catch (Exception e) { 3852 log("isMobileOk: Exception e=" + e); 3853 continue; 3854 } 3855 } 3856 log("isMobileOk: timed out"); 3857 } finally { 3858 log("isMobileOk: F stop hipri"); 3859 mCs.setEnableFailFastMobileData(DctConstants.DISABLED); 3860 mCs.stopUsingNetworkFeature(ConnectivityManager.TYPE_MOBILE, 3861 Phone.FEATURE_ENABLE_HIPRI); 3862 log("isMobileOk: X result=" + result); 3863 } 3864 return result; 3865 } 3866 3867 @Override 3868 protected Integer doInBackground(Params... params) { 3869 return isMobileOk(params[0]); 3870 } 3871 3872 @Override 3873 protected void onPostExecute(Integer result) { 3874 log("onPostExecute: result=" + result); 3875 if ((mParams != null) && (mParams.mCb != null)) { 3876 mParams.mCb.onComplete(result); 3877 } 3878 } 3879 3880 private String inetAddressesToString(InetAddress[] addresses) { 3881 StringBuffer sb = new StringBuffer(); 3882 boolean firstTime = true; 3883 for(InetAddress addr : addresses) { 3884 if (firstTime) { 3885 firstTime = false; 3886 } else { 3887 sb.append(","); 3888 } 3889 sb.append(addr); 3890 } 3891 return sb.toString(); 3892 } 3893 3894 private void printNetworkInfo() { 3895 boolean hasIccCard = mTm.hasIccCard(); 3896 int simState = mTm.getSimState(); 3897 log("hasIccCard=" + hasIccCard 3898 + " simState=" + simState); 3899 NetworkInfo[] ni = mCs.getAllNetworkInfo(); 3900 if (ni != null) { 3901 log("ni.length=" + ni.length); 3902 for (NetworkInfo netInfo: ni) { 3903 log("netInfo=" + netInfo.toString()); 3904 } 3905 } else { 3906 log("no network info ni=null"); 3907 } 3908 } 3909 3910 /** 3911 * Sleep for a few seconds then return. 3912 * @param seconds 3913 */ 3914 private static void sleep(int seconds) { 3915 try { 3916 Thread.sleep(seconds * 1000); 3917 } catch (InterruptedException e) { 3918 e.printStackTrace(); 3919 } 3920 } 3921 3922 public boolean hasIPv4Address(LinkProperties lp) { 3923 return lp.hasIPv4Address(); 3924 } 3925 3926 // Not implemented in LinkProperties, do it here. 3927 public boolean hasIPv6Address(LinkProperties lp) { 3928 for (LinkAddress address : lp.getLinkAddresses()) { 3929 if (address.getAddress() instanceof Inet6Address) { 3930 return true; 3931 } 3932 } 3933 return false; 3934 } 3935 3936 private void log(String s) { 3937 Slog.d(ConnectivityService.TAG, "[" + CHECKMP_TAG + "] " + s); 3938 } 3939 } 3940 3941 private static final String NOTIFICATION_ID = "CaptivePortal.Notification"; 3942 3943 private void setNotificationVisible(boolean visible, NetworkInfo networkInfo, String url) { 3944 log("setNotificationVisible: E visible=" + visible + " ni=" + networkInfo + " url=" + url); 3945 3946 Resources r = Resources.getSystem(); 3947 NotificationManager notificationManager = (NotificationManager) mContext 3948 .getSystemService(Context.NOTIFICATION_SERVICE); 3949 3950 if (visible) { 3951 CharSequence title; 3952 CharSequence details; 3953 int icon; 3954 switch (networkInfo.getType()) { 3955 case ConnectivityManager.TYPE_WIFI: 3956 log("setNotificationVisible: TYPE_WIFI"); 3957 title = r.getString(R.string.wifi_available_sign_in, 0); 3958 details = r.getString(R.string.network_available_sign_in_detailed, 3959 networkInfo.getExtraInfo()); 3960 icon = R.drawable.stat_notify_wifi_in_range; 3961 break; 3962 case ConnectivityManager.TYPE_MOBILE: 3963 case ConnectivityManager.TYPE_MOBILE_HIPRI: 3964 log("setNotificationVisible: TYPE_MOBILE|HIPRI"); 3965 title = r.getString(R.string.network_available_sign_in, 0); 3966 // TODO: Change this to pull from NetworkInfo once a printable 3967 // name has been added to it 3968 details = mTelephonyManager.getNetworkOperatorName(); 3969 icon = R.drawable.stat_notify_rssi_in_range; 3970 break; 3971 default: 3972 log("setNotificationVisible: other type=" + networkInfo.getType()); 3973 title = r.getString(R.string.network_available_sign_in, 0); 3974 details = r.getString(R.string.network_available_sign_in_detailed, 3975 networkInfo.getExtraInfo()); 3976 icon = R.drawable.stat_notify_rssi_in_range; 3977 break; 3978 } 3979 3980 Notification notification = new Notification(); 3981 notification.when = 0; 3982 notification.icon = icon; 3983 notification.flags = Notification.FLAG_AUTO_CANCEL; 3984 Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url)); 3985 intent.setFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT | 3986 Intent.FLAG_ACTIVITY_NEW_TASK); 3987 notification.contentIntent = PendingIntent.getActivity(mContext, 0, intent, 0); 3988 notification.tickerText = title; 3989 notification.setLatestEventInfo(mContext, title, details, notification.contentIntent); 3990 3991 log("setNotificaitionVisible: notify notificaiton=" + notification); 3992 notificationManager.notify(NOTIFICATION_ID, 1, notification); 3993 } else { 3994 log("setNotificaitionVisible: cancel"); 3995 notificationManager.cancel(NOTIFICATION_ID, 1); 3996 } 3997 log("setNotificationVisible: X visible=" + visible + " ni=" + networkInfo + " url=" + url); 3998 } 3999 4000 /** Location to an updatable file listing carrier provisioning urls. 4001 * An example: 4002 * 4003 * <?xml version="1.0" encoding="utf-8"?> 4004 * <provisioningUrls> 4005 * <provisioningUrl mcc="310" mnc="4">http://myserver.com/foo?mdn=%3$s&iccid=%1$s&imei=%2$s</provisioningUrl> 4006 * <redirectedUrl mcc="310" mnc="4">http://www.google.com</redirectedUrl> 4007 * </provisioningUrls> 4008 */ 4009 private static final String PROVISIONING_URL_PATH = 4010 "/data/misc/radio/provisioning_urls.xml"; 4011 private final File mProvisioningUrlFile = new File(PROVISIONING_URL_PATH); 4012 4013 /** XML tag for root element. */ 4014 private static final String TAG_PROVISIONING_URLS = "provisioningUrls"; 4015 /** XML tag for individual url */ 4016 private static final String TAG_PROVISIONING_URL = "provisioningUrl"; 4017 /** XML tag for redirected url */ 4018 private static final String TAG_REDIRECTED_URL = "redirectedUrl"; 4019 /** XML attribute for mcc */ 4020 private static final String ATTR_MCC = "mcc"; 4021 /** XML attribute for mnc */ 4022 private static final String ATTR_MNC = "mnc"; 4023 4024 private static final int REDIRECTED_PROVISIONING = 1; 4025 private static final int PROVISIONING = 2; 4026 4027 private String getProvisioningUrlBaseFromFile(int type) { 4028 FileReader fileReader = null; 4029 XmlPullParser parser = null; 4030 Configuration config = mContext.getResources().getConfiguration(); 4031 String tagType; 4032 4033 switch (type) { 4034 case PROVISIONING: 4035 tagType = TAG_PROVISIONING_URL; 4036 break; 4037 case REDIRECTED_PROVISIONING: 4038 tagType = TAG_REDIRECTED_URL; 4039 break; 4040 default: 4041 throw new RuntimeException("getProvisioningUrlBaseFromFile: Unexpected parameter " + 4042 type); 4043 } 4044 4045 try { 4046 fileReader = new FileReader(mProvisioningUrlFile); 4047 parser = Xml.newPullParser(); 4048 parser.setInput(fileReader); 4049 XmlUtils.beginDocument(parser, TAG_PROVISIONING_URLS); 4050 4051 while (true) { 4052 XmlUtils.nextElement(parser); 4053 4054 String element = parser.getName(); 4055 if (element == null) break; 4056 4057 if (element.equals(tagType)) { 4058 String mcc = parser.getAttributeValue(null, ATTR_MCC); 4059 try { 4060 if (mcc != null && Integer.parseInt(mcc) == config.mcc) { 4061 String mnc = parser.getAttributeValue(null, ATTR_MNC); 4062 if (mnc != null && Integer.parseInt(mnc) == config.mnc) { 4063 parser.next(); 4064 if (parser.getEventType() == XmlPullParser.TEXT) { 4065 return parser.getText(); 4066 } 4067 } 4068 } 4069 } catch (NumberFormatException e) { 4070 loge("NumberFormatException in getProvisioningUrlBaseFromFile: " + e); 4071 } 4072 } 4073 } 4074 return null; 4075 } catch (FileNotFoundException e) { 4076 loge("Carrier Provisioning Urls file not found"); 4077 } catch (XmlPullParserException e) { 4078 loge("Xml parser exception reading Carrier Provisioning Urls file: " + e); 4079 } catch (IOException e) { 4080 loge("I/O exception reading Carrier Provisioning Urls file: " + e); 4081 } finally { 4082 if (fileReader != null) { 4083 try { 4084 fileReader.close(); 4085 } catch (IOException e) {} 4086 } 4087 } 4088 return null; 4089 } 4090 4091 private String getMobileRedirectedProvisioningUrl() { 4092 String url = getProvisioningUrlBaseFromFile(REDIRECTED_PROVISIONING); 4093 if (TextUtils.isEmpty(url)) { 4094 url = mContext.getResources().getString(R.string.mobile_redirected_provisioning_url); 4095 } 4096 return url; 4097 } 4098 4099 public String getMobileProvisioningUrl() { 4100 enforceConnectivityInternalPermission(); 4101 String url = getProvisioningUrlBaseFromFile(PROVISIONING); 4102 if (TextUtils.isEmpty(url)) { 4103 url = mContext.getResources().getString(R.string.mobile_provisioning_url); 4104 log("getProvisioningUrl: mobile_provisioining_url from resource =" + url); 4105 } else { 4106 log("getProvisioningUrl: mobile_provisioning_url from File =" + url); 4107 } 4108 // populate the iccid, imei and phone number in the provisioning url. 4109 if (!TextUtils.isEmpty(url)) { 4110 String phoneNumber = mTelephonyManager.getLine1Number(); 4111 if (TextUtils.isEmpty(phoneNumber)) { 4112 phoneNumber = "0000000000"; 4113 } 4114 url = String.format(url, 4115 mTelephonyManager.getSimSerialNumber() /* ICCID */, 4116 mTelephonyManager.getDeviceId() /* IMEI */, 4117 phoneNumber /* Phone numer */); 4118 } 4119 4120 return url; 4121 } 4122 } 4123