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