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