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