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