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