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.net.ConnectivityManager.CONNECTIVITY_ACTION;
     21 import static android.net.ConnectivityManager.CONNECTIVITY_ACTION_IMMEDIATE;
     22 import static android.net.ConnectivityManager.isNetworkTypeValid;
     23 import static android.net.NetworkPolicyManager.RULE_ALLOW_ALL;
     24 import static android.net.NetworkPolicyManager.RULE_REJECT_METERED;
     25 
     26 import android.bluetooth.BluetoothTetheringDataTracker;
     27 import android.content.ContentResolver;
     28 import android.content.Context;
     29 import android.content.ContextWrapper;
     30 import android.content.Intent;
     31 import android.content.pm.PackageManager;
     32 import android.content.res.Resources;
     33 import android.database.ContentObserver;
     34 import android.net.ConnectivityManager;
     35 import android.net.DummyDataStateTracker;
     36 import android.net.EthernetDataTracker;
     37 import android.net.IConnectivityManager;
     38 import android.net.INetworkPolicyListener;
     39 import android.net.INetworkPolicyManager;
     40 import android.net.INetworkStatsService;
     41 import android.net.LinkAddress;
     42 import android.net.LinkProperties;
     43 import android.net.LinkProperties.CompareResult;
     44 import android.net.MobileDataStateTracker;
     45 import android.net.NetworkConfig;
     46 import android.net.NetworkInfo;
     47 import android.net.NetworkInfo.DetailedState;
     48 import android.net.NetworkQuotaInfo;
     49 import android.net.NetworkState;
     50 import android.net.NetworkStateTracker;
     51 import android.net.NetworkUtils;
     52 import android.net.Proxy;
     53 import android.net.ProxyProperties;
     54 import android.net.RouteInfo;
     55 import android.net.wifi.WifiStateTracker;
     56 import android.net.wimax.WimaxManagerConstants;
     57 import android.os.Binder;
     58 import android.os.FileUtils;
     59 import android.os.Handler;
     60 import android.os.HandlerThread;
     61 import android.os.IBinder;
     62 import android.os.INetworkManagementService;
     63 import android.os.Looper;
     64 import android.os.Message;
     65 import android.os.ParcelFileDescriptor;
     66 import android.os.PowerManager;
     67 import android.os.RemoteException;
     68 import android.os.ServiceManager;
     69 import android.os.SystemProperties;
     70 import android.provider.Settings;
     71 import android.text.TextUtils;
     72 import android.util.EventLog;
     73 import android.util.Slog;
     74 import android.util.SparseIntArray;
     75 
     76 import com.android.internal.net.LegacyVpnInfo;
     77 import com.android.internal.net.VpnConfig;
     78 import com.android.internal.telephony.Phone;
     79 import com.android.server.am.BatteryStatsService;
     80 import com.android.server.connectivity.Tethering;
     81 import com.android.server.connectivity.Vpn;
     82 import com.google.android.collect.Lists;
     83 import com.google.android.collect.Sets;
     84 import dalvik.system.DexClassLoader;
     85 import java.io.FileDescriptor;
     86 import java.io.IOException;
     87 import java.io.PrintWriter;
     88 import java.lang.reflect.Constructor;
     89 import java.lang.reflect.Method;
     90 import java.lang.reflect.Modifier;
     91 import java.lang.reflect.InvocationTargetException;
     92 import java.net.Inet4Address;
     93 import java.net.Inet6Address;
     94 import java.net.InetAddress;
     95 import java.net.UnknownHostException;
     96 import java.util.ArrayList;
     97 import java.util.Arrays;
     98 import java.util.Collection;
     99 import java.util.GregorianCalendar;
    100 import java.util.HashSet;
    101 import java.util.List;
    102 
    103 /**
    104  * @hide
    105  */
    106 public class ConnectivityService extends IConnectivityManager.Stub {
    107 
    108     private static final boolean DBG = true;
    109     private static final boolean VDBG = false;
    110     private static final String TAG = "ConnectivityService";
    111 
    112     private static final boolean LOGD_RULES = false;
    113 
    114     // how long to wait before switching back to a radio's default network
    115     private static final int RESTORE_DEFAULT_NETWORK_DELAY = 1 * 60 * 1000;
    116     // system property that can override the above value
    117     private static final String NETWORK_RESTORE_DELAY_PROP_NAME =
    118             "android.telephony.apn-restore";
    119 
    120     // used in recursive route setting to add gateways for the host for which
    121     // a host route was requested.
    122     private static final int MAX_HOSTROUTE_CYCLE_COUNT = 10;
    123 
    124     private Tethering mTethering;
    125     private boolean mTetheringConfigValid = false;
    126 
    127     private Vpn mVpn;
    128 
    129     /** Lock around {@link #mUidRules} and {@link #mMeteredIfaces}. */
    130     private Object mRulesLock = new Object();
    131     /** Currently active network rules by UID. */
    132     private SparseIntArray mUidRules = new SparseIntArray();
    133     /** Set of ifaces that are costly. */
    134     private HashSet<String> mMeteredIfaces = Sets.newHashSet();
    135 
    136     /**
    137      * Sometimes we want to refer to the individual network state
    138      * trackers separately, and sometimes we just want to treat them
    139      * abstractly.
    140      */
    141     private NetworkStateTracker mNetTrackers[];
    142 
    143     /**
    144      * The link properties that define the current links
    145      */
    146     private LinkProperties mCurrentLinkProperties[];
    147 
    148     /**
    149      * A per Net list of the PID's that requested access to the net
    150      * used both as a refcount and for per-PID DNS selection
    151      */
    152     private List mNetRequestersPids[];
    153 
    154     // priority order of the nettrackers
    155     // (excluding dynamically set mNetworkPreference)
    156     // TODO - move mNetworkTypePreference into this
    157     private int[] mPriorityList;
    158 
    159     private Context mContext;
    160     private int mNetworkPreference;
    161     private int mActiveDefaultNetwork = -1;
    162     // 0 is full bad, 100 is full good
    163     private int mDefaultInetCondition = 0;
    164     private int mDefaultInetConditionPublished = 0;
    165     private boolean mInetConditionChangeInFlight = false;
    166     private int mDefaultConnectionSequence = 0;
    167 
    168     private Object mDnsLock = new Object();
    169     private int mNumDnsEntries;
    170     private boolean mDnsOverridden = false;
    171 
    172     private boolean mTestMode;
    173     private static ConnectivityService sServiceInstance;
    174 
    175     private INetworkManagementService mNetd;
    176     private INetworkPolicyManager mPolicyManager;
    177 
    178     private static final int ENABLED  = 1;
    179     private static final int DISABLED = 0;
    180 
    181     private static final boolean ADD = true;
    182     private static final boolean REMOVE = false;
    183 
    184     private static final boolean TO_DEFAULT_TABLE = true;
    185     private static final boolean TO_SECONDARY_TABLE = false;
    186 
    187     // Share the event space with NetworkStateTracker (which can't see this
    188     // internal class but sends us events).  If you change these, change
    189     // NetworkStateTracker.java too.
    190     private static final int MIN_NETWORK_STATE_TRACKER_EVENT = 1;
    191     private static final int MAX_NETWORK_STATE_TRACKER_EVENT = 100;
    192 
    193     /**
    194      * used internally as a delayed event to make us switch back to the
    195      * default network
    196      */
    197     private static final int EVENT_RESTORE_DEFAULT_NETWORK =
    198             MAX_NETWORK_STATE_TRACKER_EVENT + 1;
    199 
    200     /**
    201      * used internally to change our mobile data enabled flag
    202      */
    203     private static final int EVENT_CHANGE_MOBILE_DATA_ENABLED =
    204             MAX_NETWORK_STATE_TRACKER_EVENT + 2;
    205 
    206     /**
    207      * used internally to change our network preference setting
    208      * arg1 = networkType to prefer
    209      */
    210     private static final int EVENT_SET_NETWORK_PREFERENCE =
    211             MAX_NETWORK_STATE_TRACKER_EVENT + 3;
    212 
    213     /**
    214      * used internally to synchronize inet condition reports
    215      * arg1 = networkType
    216      * arg2 = condition (0 bad, 100 good)
    217      */
    218     private static final int EVENT_INET_CONDITION_CHANGE =
    219             MAX_NETWORK_STATE_TRACKER_EVENT + 4;
    220 
    221     /**
    222      * used internally to mark the end of inet condition hold periods
    223      * arg1 = networkType
    224      */
    225     private static final int EVENT_INET_CONDITION_HOLD_END =
    226             MAX_NETWORK_STATE_TRACKER_EVENT + 5;
    227 
    228     /**
    229      * used internally to set enable/disable cellular data
    230      * arg1 = ENBALED or DISABLED
    231      */
    232     private static final int EVENT_SET_MOBILE_DATA =
    233             MAX_NETWORK_STATE_TRACKER_EVENT + 7;
    234 
    235     /**
    236      * used internally to clear a wakelock when transitioning
    237      * from one net to another
    238      */
    239     private static final int EVENT_CLEAR_NET_TRANSITION_WAKELOCK =
    240             MAX_NETWORK_STATE_TRACKER_EVENT + 8;
    241 
    242     /**
    243      * used internally to reload global proxy settings
    244      */
    245     private static final int EVENT_APPLY_GLOBAL_HTTP_PROXY =
    246             MAX_NETWORK_STATE_TRACKER_EVENT + 9;
    247 
    248     /**
    249      * used internally to set external dependency met/unmet
    250      * arg1 = ENABLED (met) or DISABLED (unmet)
    251      * arg2 = NetworkType
    252      */
    253     private static final int EVENT_SET_DEPENDENCY_MET =
    254             MAX_NETWORK_STATE_TRACKER_EVENT + 10;
    255 
    256     /**
    257      * used internally to restore DNS properties back to the
    258      * default network
    259      */
    260     private static final int EVENT_RESTORE_DNS =
    261             MAX_NETWORK_STATE_TRACKER_EVENT + 11;
    262 
    263     /**
    264      * used internally to send a sticky broadcast delayed.
    265      */
    266     private static final int EVENT_SEND_STICKY_BROADCAST_INTENT =
    267             MAX_NETWORK_STATE_TRACKER_EVENT + 12;
    268 
    269     /**
    270      * Used internally to
    271      * {@link NetworkStateTracker#setPolicyDataEnable(boolean)}.
    272      */
    273     private static final int EVENT_SET_POLICY_DATA_ENABLE = MAX_NETWORK_STATE_TRACKER_EVENT + 13;
    274 
    275     private Handler mHandler;
    276 
    277     // list of DeathRecipients used to make sure features are turned off when
    278     // a process dies
    279     private List<FeatureUser> mFeatureUsers;
    280 
    281     private boolean mSystemReady;
    282     private Intent mInitialBroadcast;
    283 
    284     private PowerManager.WakeLock mNetTransitionWakeLock;
    285     private String mNetTransitionWakeLockCausedBy = "";
    286     private int mNetTransitionWakeLockSerialNumber;
    287     private int mNetTransitionWakeLockTimeout;
    288 
    289     private InetAddress mDefaultDns;
    290 
    291     // this collection is used to refcount the added routes - if there are none left
    292     // it's time to remove the route from the route table
    293     private Collection<RouteInfo> mAddedRoutes = new ArrayList<RouteInfo>();
    294 
    295     // used in DBG mode to track inet condition reports
    296     private static final int INET_CONDITION_LOG_MAX_SIZE = 15;
    297     private ArrayList mInetLog;
    298 
    299     // track the current default http proxy - tell the world if we get a new one (real change)
    300     private ProxyProperties mDefaultProxy = null;
    301     private Object mDefaultProxyLock = new Object();
    302     private boolean mDefaultProxyDisabled = false;
    303 
    304     // track the global proxy.
    305     private ProxyProperties mGlobalProxy = null;
    306     private final Object mGlobalProxyLock = new Object();
    307 
    308     private SettingsObserver mSettingsObserver;
    309 
    310     NetworkConfig[] mNetConfigs;
    311     int mNetworksDefined;
    312 
    313     private static class RadioAttributes {
    314         public int mSimultaneity;
    315         public int mType;
    316         public RadioAttributes(String init) {
    317             String fragments[] = init.split(",");
    318             mType = Integer.parseInt(fragments[0]);
    319             mSimultaneity = Integer.parseInt(fragments[1]);
    320         }
    321     }
    322     RadioAttributes[] mRadioAttributes;
    323 
    324     // the set of network types that can only be enabled by system/sig apps
    325     List mProtectedNetworks;
    326 
    327     public ConnectivityService(Context context, INetworkManagementService netd,
    328             INetworkStatsService statsService, INetworkPolicyManager policyManager) {
    329         if (DBG) log("ConnectivityService starting up");
    330 
    331         HandlerThread handlerThread = new HandlerThread("ConnectivityServiceThread");
    332         handlerThread.start();
    333         mHandler = new MyHandler(handlerThread.getLooper());
    334 
    335         // setup our unique device name
    336         if (TextUtils.isEmpty(SystemProperties.get("net.hostname"))) {
    337             String id = Settings.Secure.getString(context.getContentResolver(),
    338                     Settings.Secure.ANDROID_ID);
    339             if (id != null && id.length() > 0) {
    340                 String name = new String("android-").concat(id);
    341                 SystemProperties.set("net.hostname", name);
    342             }
    343         }
    344 
    345         // read our default dns server ip
    346         String dns = Settings.Secure.getString(context.getContentResolver(),
    347                 Settings.Secure.DEFAULT_DNS_SERVER);
    348         if (dns == null || dns.length() == 0) {
    349             dns = context.getResources().getString(
    350                     com.android.internal.R.string.config_default_dns_server);
    351         }
    352         try {
    353             mDefaultDns = NetworkUtils.numericToInetAddress(dns);
    354         } catch (IllegalArgumentException e) {
    355             loge("Error setting defaultDns using " + dns);
    356         }
    357 
    358         mContext = checkNotNull(context, "missing Context");
    359         mNetd = checkNotNull(netd, "missing INetworkManagementService");
    360         mPolicyManager = checkNotNull(policyManager, "missing INetworkPolicyManager");
    361 
    362         try {
    363             mPolicyManager.registerListener(mPolicyListener);
    364         } catch (RemoteException e) {
    365             // ouch, no rules updates means some processes may never get network
    366             loge("unable to register INetworkPolicyListener" + e.toString());
    367         }
    368 
    369         final PowerManager powerManager = (PowerManager) context.getSystemService(
    370                 Context.POWER_SERVICE);
    371         mNetTransitionWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
    372         mNetTransitionWakeLockTimeout = mContext.getResources().getInteger(
    373                 com.android.internal.R.integer.config_networkTransitionTimeout);
    374 
    375         mNetTrackers = new NetworkStateTracker[
    376                 ConnectivityManager.MAX_NETWORK_TYPE+1];
    377         mCurrentLinkProperties = new LinkProperties[ConnectivityManager.MAX_NETWORK_TYPE+1];
    378 
    379         mNetworkPreference = getPersistedNetworkPreference();
    380 
    381         mRadioAttributes = new RadioAttributes[ConnectivityManager.MAX_RADIO_TYPE+1];
    382         mNetConfigs = new NetworkConfig[ConnectivityManager.MAX_NETWORK_TYPE+1];
    383 
    384         // Load device network attributes from resources
    385         String[] raStrings = context.getResources().getStringArray(
    386                 com.android.internal.R.array.radioAttributes);
    387         for (String raString : raStrings) {
    388             RadioAttributes r = new RadioAttributes(raString);
    389             if (r.mType > ConnectivityManager.MAX_RADIO_TYPE) {
    390                 loge("Error in radioAttributes - ignoring attempt to define type " + r.mType);
    391                 continue;
    392             }
    393             if (mRadioAttributes[r.mType] != null) {
    394                 loge("Error in radioAttributes - ignoring attempt to redefine type " +
    395                         r.mType);
    396                 continue;
    397             }
    398             mRadioAttributes[r.mType] = r;
    399         }
    400 
    401         String[] naStrings = context.getResources().getStringArray(
    402                 com.android.internal.R.array.networkAttributes);
    403         for (String naString : naStrings) {
    404             try {
    405                 NetworkConfig n = new NetworkConfig(naString);
    406                 if (n.type > ConnectivityManager.MAX_NETWORK_TYPE) {
    407                     loge("Error in networkAttributes - ignoring attempt to define type " +
    408                             n.type);
    409                     continue;
    410                 }
    411                 if (mNetConfigs[n.type] != null) {
    412                     loge("Error in networkAttributes - ignoring attempt to redefine type " +
    413                             n.type);
    414                     continue;
    415                 }
    416                 if (mRadioAttributes[n.radio] == null) {
    417                     loge("Error in networkAttributes - ignoring attempt to use undefined " +
    418                             "radio " + n.radio + " in network type " + n.type);
    419                     continue;
    420                 }
    421                 mNetConfigs[n.type] = n;
    422                 mNetworksDefined++;
    423             } catch(Exception e) {
    424                 // ignore it - leave the entry null
    425             }
    426         }
    427 
    428         mProtectedNetworks = new ArrayList<Integer>();
    429         int[] protectedNetworks = context.getResources().getIntArray(
    430                 com.android.internal.R.array.config_protectedNetworks);
    431         for (int p : protectedNetworks) {
    432             if ((mNetConfigs[p] != null) && (mProtectedNetworks.contains(p) == false)) {
    433                 mProtectedNetworks.add(p);
    434             } else {
    435                 if (DBG) loge("Ignoring protectedNetwork " + p);
    436             }
    437         }
    438 
    439         // high priority first
    440         mPriorityList = new int[mNetworksDefined];
    441         {
    442             int insertionPoint = mNetworksDefined-1;
    443             int currentLowest = 0;
    444             int nextLowest = 0;
    445             while (insertionPoint > -1) {
    446                 for (NetworkConfig na : mNetConfigs) {
    447                     if (na == null) continue;
    448                     if (na.priority < currentLowest) continue;
    449                     if (na.priority > currentLowest) {
    450                         if (na.priority < nextLowest || nextLowest == 0) {
    451                             nextLowest = na.priority;
    452                         }
    453                         continue;
    454                     }
    455                     mPriorityList[insertionPoint--] = na.type;
    456                 }
    457                 currentLowest = nextLowest;
    458                 nextLowest = 0;
    459             }
    460         }
    461 
    462         mNetRequestersPids = new ArrayList[ConnectivityManager.MAX_NETWORK_TYPE+1];
    463         for (int i : mPriorityList) {
    464             mNetRequestersPids[i] = new ArrayList();
    465         }
    466 
    467         mFeatureUsers = new ArrayList<FeatureUser>();
    468 
    469         mNumDnsEntries = 0;
    470 
    471         mTestMode = SystemProperties.get("cm.test.mode").equals("true")
    472                 && SystemProperties.get("ro.build.type").equals("eng");
    473         /*
    474          * Create the network state trackers for Wi-Fi and mobile
    475          * data. Maybe this could be done with a factory class,
    476          * but it's not clear that it's worth it, given that
    477          * the number of different network types is not going
    478          * to change very often.
    479          */
    480         for (int netType : mPriorityList) {
    481             switch (mNetConfigs[netType].radio) {
    482             case ConnectivityManager.TYPE_WIFI:
    483                 mNetTrackers[netType] = new WifiStateTracker(netType,
    484                         mNetConfigs[netType].name);
    485                 mNetTrackers[netType].startMonitoring(context, mHandler);
    486                break;
    487             case ConnectivityManager.TYPE_MOBILE:
    488                 mNetTrackers[netType] = new MobileDataStateTracker(netType,
    489                         mNetConfigs[netType].name);
    490                 mNetTrackers[netType].startMonitoring(context, mHandler);
    491                 break;
    492             case ConnectivityManager.TYPE_DUMMY:
    493                 mNetTrackers[netType] = new DummyDataStateTracker(netType,
    494                         mNetConfigs[netType].name);
    495                 mNetTrackers[netType].startMonitoring(context, mHandler);
    496                 break;
    497             case ConnectivityManager.TYPE_BLUETOOTH:
    498                 mNetTrackers[netType] = BluetoothTetheringDataTracker.getInstance();
    499                 mNetTrackers[netType].startMonitoring(context, mHandler);
    500                 break;
    501             case ConnectivityManager.TYPE_WIMAX:
    502                 mNetTrackers[netType] = makeWimaxStateTracker();
    503                 if (mNetTrackers[netType]!= null) {
    504                     mNetTrackers[netType].startMonitoring(context, mHandler);
    505                 }
    506                 break;
    507             case ConnectivityManager.TYPE_ETHERNET:
    508                 mNetTrackers[netType] = EthernetDataTracker.getInstance();
    509                 mNetTrackers[netType].startMonitoring(context, mHandler);
    510                 break;
    511             default:
    512                 loge("Trying to create a DataStateTracker for an unknown radio type " +
    513                         mNetConfigs[netType].radio);
    514                 continue;
    515             }
    516             mCurrentLinkProperties[netType] = null;
    517             if (mNetTrackers[netType] != null && mNetConfigs[netType].isDefault()) {
    518                 mNetTrackers[netType].reconnect();
    519             }
    520         }
    521 
    522         IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
    523         INetworkManagementService nmService = INetworkManagementService.Stub.asInterface(b);
    524 
    525         mTethering = new Tethering(mContext, nmService, statsService, this, mHandler.getLooper());
    526         mTetheringConfigValid = ((mTethering.getTetherableUsbRegexs().length != 0 ||
    527                                   mTethering.getTetherableWifiRegexs().length != 0 ||
    528                                   mTethering.getTetherableBluetoothRegexs().length != 0) &&
    529                                  mTethering.getUpstreamIfaceTypes().length != 0);
    530 
    531         mVpn = new Vpn(mContext, new VpnCallback());
    532 
    533         try {
    534             nmService.registerObserver(mTethering);
    535             nmService.registerObserver(mVpn);
    536         } catch (RemoteException e) {
    537             loge("Error registering observer :" + e);
    538         }
    539 
    540         if (DBG) {
    541             mInetLog = new ArrayList();
    542         }
    543 
    544         mSettingsObserver = new SettingsObserver(mHandler, EVENT_APPLY_GLOBAL_HTTP_PROXY);
    545         mSettingsObserver.observe(mContext);
    546 
    547         loadGlobalProxy();
    548     }
    549 private NetworkStateTracker makeWimaxStateTracker() {
    550         //Initialize Wimax
    551         DexClassLoader wimaxClassLoader;
    552         Class wimaxStateTrackerClass = null;
    553         Class wimaxServiceClass = null;
    554         Class wimaxManagerClass;
    555         String wimaxJarLocation;
    556         String wimaxLibLocation;
    557         String wimaxManagerClassName;
    558         String wimaxServiceClassName;
    559         String wimaxStateTrackerClassName;
    560 
    561         NetworkStateTracker wimaxStateTracker = null;
    562 
    563         boolean isWimaxEnabled = mContext.getResources().getBoolean(
    564                 com.android.internal.R.bool.config_wimaxEnabled);
    565 
    566         if (isWimaxEnabled) {
    567             try {
    568                 wimaxJarLocation = mContext.getResources().getString(
    569                         com.android.internal.R.string.config_wimaxServiceJarLocation);
    570                 wimaxLibLocation = mContext.getResources().getString(
    571                         com.android.internal.R.string.config_wimaxNativeLibLocation);
    572                 wimaxManagerClassName = mContext.getResources().getString(
    573                         com.android.internal.R.string.config_wimaxManagerClassname);
    574                 wimaxServiceClassName = mContext.getResources().getString(
    575                         com.android.internal.R.string.config_wimaxServiceClassname);
    576                 wimaxStateTrackerClassName = mContext.getResources().getString(
    577                         com.android.internal.R.string.config_wimaxStateTrackerClassname);
    578 
    579                 log("wimaxJarLocation: " + wimaxJarLocation);
    580                 wimaxClassLoader =  new DexClassLoader(wimaxJarLocation,
    581                         new ContextWrapper(mContext).getCacheDir().getAbsolutePath(),
    582                         wimaxLibLocation, ClassLoader.getSystemClassLoader());
    583 
    584                 try {
    585                     wimaxManagerClass = wimaxClassLoader.loadClass(wimaxManagerClassName);
    586                     wimaxStateTrackerClass = wimaxClassLoader.loadClass(wimaxStateTrackerClassName);
    587                     wimaxServiceClass = wimaxClassLoader.loadClass(wimaxServiceClassName);
    588                 } catch (ClassNotFoundException ex) {
    589                     loge("Exception finding Wimax classes: " + ex.toString());
    590                     return null;
    591                 }
    592             } catch(Resources.NotFoundException ex) {
    593                 loge("Wimax Resources does not exist!!! ");
    594                 return null;
    595             }
    596 
    597             try {
    598                 log("Starting Wimax Service... ");
    599 
    600                 Constructor wmxStTrkrConst = wimaxStateTrackerClass.getConstructor
    601                         (new Class[] {Context.class, Handler.class});
    602                 wimaxStateTracker = (NetworkStateTracker)wmxStTrkrConst.newInstance(mContext,
    603                         mHandler);
    604 
    605                 Constructor wmxSrvConst = wimaxServiceClass.getDeclaredConstructor
    606                         (new Class[] {Context.class, wimaxStateTrackerClass});
    607                 wmxSrvConst.setAccessible(true);
    608                 IBinder svcInvoker = (IBinder)wmxSrvConst.newInstance(mContext, wimaxStateTracker);
    609                 wmxSrvConst.setAccessible(false);
    610 
    611                 ServiceManager.addService(WimaxManagerConstants.WIMAX_SERVICE, svcInvoker);
    612 
    613             } catch(Exception ex) {
    614                 loge("Exception creating Wimax classes: " + ex.toString());
    615                 return null;
    616             }
    617         } else {
    618             loge("Wimax is not enabled or not added to the network attributes!!! ");
    619             return null;
    620         }
    621 
    622         return wimaxStateTracker;
    623     }
    624     /**
    625      * Sets the preferred network.
    626      * @param preference the new preference
    627      */
    628     public void setNetworkPreference(int preference) {
    629         enforceChangePermission();
    630 
    631         mHandler.sendMessage(mHandler.obtainMessage(EVENT_SET_NETWORK_PREFERENCE, preference, 0));
    632     }
    633 
    634     public int getNetworkPreference() {
    635         enforceAccessPermission();
    636         int preference;
    637         synchronized(this) {
    638             preference = mNetworkPreference;
    639         }
    640         return preference;
    641     }
    642 
    643     private void handleSetNetworkPreference(int preference) {
    644         if (ConnectivityManager.isNetworkTypeValid(preference) &&
    645                 mNetConfigs[preference] != null &&
    646                 mNetConfigs[preference].isDefault()) {
    647             if (mNetworkPreference != preference) {
    648                 final ContentResolver cr = mContext.getContentResolver();
    649                 Settings.Secure.putInt(cr, Settings.Secure.NETWORK_PREFERENCE, preference);
    650                 synchronized(this) {
    651                     mNetworkPreference = preference;
    652                 }
    653                 enforcePreference();
    654             }
    655         }
    656     }
    657 
    658     private int getConnectivityChangeDelay() {
    659         final ContentResolver cr = mContext.getContentResolver();
    660 
    661         /** Check system properties for the default value then use secure settings value, if any. */
    662         int defaultDelay = SystemProperties.getInt(
    663                 "conn." + Settings.Secure.CONNECTIVITY_CHANGE_DELAY,
    664                 Settings.Secure.CONNECTIVITY_CHANGE_DELAY_DEFAULT);
    665         return Settings.Secure.getInt(cr, Settings.Secure.CONNECTIVITY_CHANGE_DELAY,
    666                 defaultDelay);
    667     }
    668 
    669     private int getPersistedNetworkPreference() {
    670         final ContentResolver cr = mContext.getContentResolver();
    671 
    672         final int networkPrefSetting = Settings.Secure
    673                 .getInt(cr, Settings.Secure.NETWORK_PREFERENCE, -1);
    674         if (networkPrefSetting != -1) {
    675             return networkPrefSetting;
    676         }
    677 
    678         return ConnectivityManager.DEFAULT_NETWORK_PREFERENCE;
    679     }
    680 
    681     /**
    682      * Make the state of network connectivity conform to the preference settings
    683      * In this method, we only tear down a non-preferred network. Establishing
    684      * a connection to the preferred network is taken care of when we handle
    685      * the disconnect event from the non-preferred network
    686      * (see {@link #handleDisconnect(NetworkInfo)}).
    687      */
    688     private void enforcePreference() {
    689         if (mNetTrackers[mNetworkPreference].getNetworkInfo().isConnected())
    690             return;
    691 
    692         if (!mNetTrackers[mNetworkPreference].isAvailable())
    693             return;
    694 
    695         for (int t=0; t <= ConnectivityManager.MAX_RADIO_TYPE; t++) {
    696             if (t != mNetworkPreference && mNetTrackers[t] != null &&
    697                     mNetTrackers[t].getNetworkInfo().isConnected()) {
    698                 if (DBG) {
    699                     log("tearing down " + mNetTrackers[t].getNetworkInfo() +
    700                             " in enforcePreference");
    701                 }
    702                 teardown(mNetTrackers[t]);
    703             }
    704         }
    705     }
    706 
    707     private boolean teardown(NetworkStateTracker netTracker) {
    708         if (netTracker.teardown()) {
    709             netTracker.setTeardownRequested(true);
    710             return true;
    711         } else {
    712             return false;
    713         }
    714     }
    715 
    716     /**
    717      * Check if UID should be blocked from using the network represented by the
    718      * given {@link NetworkStateTracker}.
    719      */
    720     private boolean isNetworkBlocked(NetworkStateTracker tracker, int uid) {
    721         final String iface = tracker.getLinkProperties().getInterfaceName();
    722 
    723         final boolean networkCostly;
    724         final int uidRules;
    725         synchronized (mRulesLock) {
    726             networkCostly = mMeteredIfaces.contains(iface);
    727             uidRules = mUidRules.get(uid, RULE_ALLOW_ALL);
    728         }
    729 
    730         if (networkCostly && (uidRules & RULE_REJECT_METERED) != 0) {
    731             return true;
    732         }
    733 
    734         // no restrictive rules; network is visible
    735         return false;
    736     }
    737 
    738     /**
    739      * Return a filtered {@link NetworkInfo}, potentially marked
    740      * {@link DetailedState#BLOCKED} based on
    741      * {@link #isNetworkBlocked(NetworkStateTracker, int)}.
    742      */
    743     private NetworkInfo getFilteredNetworkInfo(NetworkStateTracker tracker, int uid) {
    744         NetworkInfo info = tracker.getNetworkInfo();
    745         if (isNetworkBlocked(tracker, uid)) {
    746             // network is blocked; clone and override state
    747             info = new NetworkInfo(info);
    748             info.setDetailedState(DetailedState.BLOCKED, null, null);
    749         }
    750         return info;
    751     }
    752 
    753     /**
    754      * Return NetworkInfo for the active (i.e., connected) network interface.
    755      * It is assumed that at most one network is active at a time. If more
    756      * than one is active, it is indeterminate which will be returned.
    757      * @return the info for the active network, or {@code null} if none is
    758      * active
    759      */
    760     @Override
    761     public NetworkInfo getActiveNetworkInfo() {
    762         enforceAccessPermission();
    763         final int uid = Binder.getCallingUid();
    764         return getNetworkInfo(mActiveDefaultNetwork, uid);
    765     }
    766 
    767     @Override
    768     public NetworkInfo getActiveNetworkInfoForUid(int uid) {
    769         enforceConnectivityInternalPermission();
    770         return getNetworkInfo(mActiveDefaultNetwork, uid);
    771     }
    772 
    773     @Override
    774     public NetworkInfo getNetworkInfo(int networkType) {
    775         enforceAccessPermission();
    776         final int uid = Binder.getCallingUid();
    777         return getNetworkInfo(networkType, uid);
    778     }
    779 
    780     private NetworkInfo getNetworkInfo(int networkType, int uid) {
    781         NetworkInfo info = null;
    782         if (isNetworkTypeValid(networkType)) {
    783             final NetworkStateTracker tracker = mNetTrackers[networkType];
    784             if (tracker != null) {
    785                 info = getFilteredNetworkInfo(tracker, uid);
    786             }
    787         }
    788         return info;
    789     }
    790 
    791     @Override
    792     public NetworkInfo[] getAllNetworkInfo() {
    793         enforceAccessPermission();
    794         final int uid = Binder.getCallingUid();
    795         final ArrayList<NetworkInfo> result = Lists.newArrayList();
    796         synchronized (mRulesLock) {
    797             for (NetworkStateTracker tracker : mNetTrackers) {
    798                 if (tracker != null) {
    799                     result.add(getFilteredNetworkInfo(tracker, uid));
    800                 }
    801             }
    802         }
    803         return result.toArray(new NetworkInfo[result.size()]);
    804     }
    805 
    806     @Override
    807     public boolean isNetworkSupported(int networkType) {
    808         enforceAccessPermission();
    809         return (isNetworkTypeValid(networkType) && (mNetTrackers[networkType] != null));
    810     }
    811 
    812     /**
    813      * Return LinkProperties for the active (i.e., connected) default
    814      * network interface.  It is assumed that at most one default network
    815      * is active at a time. If more than one is active, it is indeterminate
    816      * which will be returned.
    817      * @return the ip properties for the active network, or {@code null} if
    818      * none is active
    819      */
    820     @Override
    821     public LinkProperties getActiveLinkProperties() {
    822         return getLinkProperties(mActiveDefaultNetwork);
    823     }
    824 
    825     @Override
    826     public LinkProperties getLinkProperties(int networkType) {
    827         enforceAccessPermission();
    828         if (isNetworkTypeValid(networkType)) {
    829             final NetworkStateTracker tracker = mNetTrackers[networkType];
    830             if (tracker != null) {
    831                 return tracker.getLinkProperties();
    832             }
    833         }
    834         return null;
    835     }
    836 
    837     @Override
    838     public NetworkState[] getAllNetworkState() {
    839         enforceAccessPermission();
    840         final int uid = Binder.getCallingUid();
    841         final ArrayList<NetworkState> result = Lists.newArrayList();
    842         synchronized (mRulesLock) {
    843             for (NetworkStateTracker tracker : mNetTrackers) {
    844                 if (tracker != null) {
    845                     final NetworkInfo info = getFilteredNetworkInfo(tracker, uid);
    846                     result.add(new NetworkState(
    847                             info, tracker.getLinkProperties(), tracker.getLinkCapabilities()));
    848                 }
    849             }
    850         }
    851         return result.toArray(new NetworkState[result.size()]);
    852     }
    853 
    854     private NetworkState getNetworkStateUnchecked(int networkType) {
    855         if (isNetworkTypeValid(networkType)) {
    856             final NetworkStateTracker tracker = mNetTrackers[networkType];
    857             if (tracker != null) {
    858                 return new NetworkState(tracker.getNetworkInfo(), tracker.getLinkProperties(),
    859                         tracker.getLinkCapabilities());
    860             }
    861         }
    862         return null;
    863     }
    864 
    865     @Override
    866     public NetworkQuotaInfo getActiveNetworkQuotaInfo() {
    867         enforceAccessPermission();
    868         final NetworkState state = getNetworkStateUnchecked(mActiveDefaultNetwork);
    869         if (state != null) {
    870             try {
    871                 return mPolicyManager.getNetworkQuotaInfo(state);
    872             } catch (RemoteException e) {
    873             }
    874         }
    875         return null;
    876     }
    877 
    878     public boolean setRadios(boolean turnOn) {
    879         boolean result = true;
    880         enforceChangePermission();
    881         for (NetworkStateTracker t : mNetTrackers) {
    882             if (t != null) result = t.setRadio(turnOn) && result;
    883         }
    884         return result;
    885     }
    886 
    887     public boolean setRadio(int netType, boolean turnOn) {
    888         enforceChangePermission();
    889         if (!ConnectivityManager.isNetworkTypeValid(netType)) {
    890             return false;
    891         }
    892         NetworkStateTracker tracker = mNetTrackers[netType];
    893         return tracker != null && tracker.setRadio(turnOn);
    894     }
    895 
    896     /**
    897      * Used to notice when the calling process dies so we can self-expire
    898      *
    899      * Also used to know if the process has cleaned up after itself when
    900      * our auto-expire timer goes off.  The timer has a link to an object.
    901      *
    902      */
    903     private class FeatureUser implements IBinder.DeathRecipient {
    904         int mNetworkType;
    905         String mFeature;
    906         IBinder mBinder;
    907         int mPid;
    908         int mUid;
    909         long mCreateTime;
    910 
    911         FeatureUser(int type, String feature, IBinder binder) {
    912             super();
    913             mNetworkType = type;
    914             mFeature = feature;
    915             mBinder = binder;
    916             mPid = getCallingPid();
    917             mUid = getCallingUid();
    918             mCreateTime = System.currentTimeMillis();
    919 
    920             try {
    921                 mBinder.linkToDeath(this, 0);
    922             } catch (RemoteException e) {
    923                 binderDied();
    924             }
    925         }
    926 
    927         void unlinkDeathRecipient() {
    928             mBinder.unlinkToDeath(this, 0);
    929         }
    930 
    931         public void binderDied() {
    932             log("ConnectivityService FeatureUser binderDied(" +
    933                     mNetworkType + ", " + mFeature + ", " + mBinder + "), created " +
    934                     (System.currentTimeMillis() - mCreateTime) + " mSec ago");
    935             stopUsingNetworkFeature(this, false);
    936         }
    937 
    938         public void expire() {
    939             if (VDBG) {
    940                 log("ConnectivityService FeatureUser expire(" +
    941                         mNetworkType + ", " + mFeature + ", " + mBinder +"), created " +
    942                         (System.currentTimeMillis() - mCreateTime) + " mSec ago");
    943             }
    944             stopUsingNetworkFeature(this, false);
    945         }
    946 
    947         public boolean isSameUser(FeatureUser u) {
    948             if (u == null) return false;
    949 
    950             return isSameUser(u.mPid, u.mUid, u.mNetworkType, u.mFeature);
    951         }
    952 
    953         public boolean isSameUser(int pid, int uid, int networkType, String feature) {
    954             if ((mPid == pid) && (mUid == uid) && (mNetworkType == networkType) &&
    955                 TextUtils.equals(mFeature, feature)) {
    956                 return true;
    957             }
    958             return false;
    959         }
    960 
    961         public String toString() {
    962             return "FeatureUser("+mNetworkType+","+mFeature+","+mPid+","+mUid+"), created " +
    963                     (System.currentTimeMillis() - mCreateTime) + " mSec ago";
    964         }
    965     }
    966 
    967     // javadoc from interface
    968     public int startUsingNetworkFeature(int networkType, String feature,
    969             IBinder binder) {
    970         if (VDBG) {
    971             log("startUsingNetworkFeature for net " + networkType + ": " + feature);
    972         }
    973         enforceChangePermission();
    974         if (!ConnectivityManager.isNetworkTypeValid(networkType) ||
    975                 mNetConfigs[networkType] == null) {
    976             return Phone.APN_REQUEST_FAILED;
    977         }
    978 
    979         FeatureUser f = new FeatureUser(networkType, feature, binder);
    980 
    981         // TODO - move this into individual networktrackers
    982         int usedNetworkType = convertFeatureToNetworkType(networkType, feature);
    983 
    984         if (mProtectedNetworks.contains(usedNetworkType)) {
    985             enforceConnectivityInternalPermission();
    986         }
    987 
    988         NetworkStateTracker network = mNetTrackers[usedNetworkType];
    989         if (network != null) {
    990             Integer currentPid = new Integer(getCallingPid());
    991             if (usedNetworkType != networkType) {
    992                 NetworkInfo ni = network.getNetworkInfo();
    993 
    994                 if (ni.isAvailable() == false) {
    995                     if (DBG) log("special network not available");
    996                     if (!TextUtils.equals(feature,Phone.FEATURE_ENABLE_DUN_ALWAYS)) {
    997                         return Phone.APN_TYPE_NOT_AVAILABLE;
    998                     } else {
    999                         // else make the attempt anyway - probably giving REQUEST_STARTED below
   1000                     }
   1001                 }
   1002 
   1003                 int restoreTimer = getRestoreDefaultNetworkDelay(usedNetworkType);
   1004 
   1005                 synchronized(this) {
   1006                     boolean addToList = true;
   1007                     if (restoreTimer < 0) {
   1008                         // In case there is no timer is specified for the feature,
   1009                         // make sure we don't add duplicate entry with the same request.
   1010                         for (FeatureUser u : mFeatureUsers) {
   1011                             if (u.isSameUser(f)) {
   1012                                 // Duplicate user is found. Do not add.
   1013                                 addToList = false;
   1014                                 break;
   1015                             }
   1016                         }
   1017                     }
   1018 
   1019                     if (addToList) mFeatureUsers.add(f);
   1020                     if (!mNetRequestersPids[usedNetworkType].contains(currentPid)) {
   1021                         // this gets used for per-pid dns when connected
   1022                         mNetRequestersPids[usedNetworkType].add(currentPid);
   1023                     }
   1024                 }
   1025 
   1026                 if (restoreTimer >= 0) {
   1027                     mHandler.sendMessageDelayed(
   1028                             mHandler.obtainMessage(EVENT_RESTORE_DEFAULT_NETWORK, f), restoreTimer);
   1029                 }
   1030 
   1031                 if ((ni.isConnectedOrConnecting() == true) &&
   1032                         !network.isTeardownRequested()) {
   1033                     if (ni.isConnected() == true) {
   1034                         final long token = Binder.clearCallingIdentity();
   1035                         try {
   1036                             // add the pid-specific dns
   1037                             handleDnsConfigurationChange(usedNetworkType);
   1038                             if (VDBG) log("special network already active");
   1039                         } finally {
   1040                             Binder.restoreCallingIdentity(token);
   1041                         }
   1042                         return Phone.APN_ALREADY_ACTIVE;
   1043                     }
   1044                     if (VDBG) log("special network already connecting");
   1045                     return Phone.APN_REQUEST_STARTED;
   1046                 }
   1047 
   1048                 // check if the radio in play can make another contact
   1049                 // assume if cannot for now
   1050 
   1051                 if (DBG) {
   1052                     log("startUsingNetworkFeature reconnecting to " + networkType + ": " + feature);
   1053                 }
   1054                 network.reconnect();
   1055                 return Phone.APN_REQUEST_STARTED;
   1056             } else {
   1057                 // need to remember this unsupported request so we respond appropriately on stop
   1058                 synchronized(this) {
   1059                     mFeatureUsers.add(f);
   1060                     if (!mNetRequestersPids[usedNetworkType].contains(currentPid)) {
   1061                         // this gets used for per-pid dns when connected
   1062                         mNetRequestersPids[usedNetworkType].add(currentPid);
   1063                     }
   1064                 }
   1065                 return -1;
   1066             }
   1067         }
   1068         return Phone.APN_TYPE_NOT_AVAILABLE;
   1069     }
   1070 
   1071     // javadoc from interface
   1072     public int stopUsingNetworkFeature(int networkType, String feature) {
   1073         enforceChangePermission();
   1074 
   1075         int pid = getCallingPid();
   1076         int uid = getCallingUid();
   1077 
   1078         FeatureUser u = null;
   1079         boolean found = false;
   1080 
   1081         synchronized(this) {
   1082             for (FeatureUser x : mFeatureUsers) {
   1083                 if (x.isSameUser(pid, uid, networkType, feature)) {
   1084                     u = x;
   1085                     found = true;
   1086                     break;
   1087                 }
   1088             }
   1089         }
   1090         if (found && u != null) {
   1091             // stop regardless of how many other time this proc had called start
   1092             return stopUsingNetworkFeature(u, true);
   1093         } else {
   1094             // none found!
   1095             if (VDBG) log("stopUsingNetworkFeature - not a live request, ignoring");
   1096             return 1;
   1097         }
   1098     }
   1099 
   1100     private int stopUsingNetworkFeature(FeatureUser u, boolean ignoreDups) {
   1101         int networkType = u.mNetworkType;
   1102         String feature = u.mFeature;
   1103         int pid = u.mPid;
   1104         int uid = u.mUid;
   1105 
   1106         NetworkStateTracker tracker = null;
   1107         boolean callTeardown = false;  // used to carry our decision outside of sync block
   1108 
   1109         if (VDBG) {
   1110             log("stopUsingNetworkFeature: net " + networkType + ": " + feature);
   1111         }
   1112 
   1113         if (!ConnectivityManager.isNetworkTypeValid(networkType)) {
   1114             if (DBG) {
   1115                 log("stopUsingNetworkFeature: net " + networkType + ": " + feature +
   1116                         ", net is invalid");
   1117             }
   1118             return -1;
   1119         }
   1120 
   1121         // need to link the mFeatureUsers list with the mNetRequestersPids state in this
   1122         // sync block
   1123         synchronized(this) {
   1124             // check if this process still has an outstanding start request
   1125             if (!mFeatureUsers.contains(u)) {
   1126                 if (VDBG) {
   1127                     log("stopUsingNetworkFeature: this process has no outstanding requests" +
   1128                         ", ignoring");
   1129                 }
   1130                 return 1;
   1131             }
   1132             u.unlinkDeathRecipient();
   1133             mFeatureUsers.remove(mFeatureUsers.indexOf(u));
   1134             // If we care about duplicate requests, check for that here.
   1135             //
   1136             // This is done to support the extension of a request - the app
   1137             // can request we start the network feature again and renew the
   1138             // auto-shutoff delay.  Normal "stop" calls from the app though
   1139             // do not pay attention to duplicate requests - in effect the
   1140             // API does not refcount and a single stop will counter multiple starts.
   1141             if (ignoreDups == false) {
   1142                 for (FeatureUser x : mFeatureUsers) {
   1143                     if (x.isSameUser(u)) {
   1144                         if (VDBG) log("stopUsingNetworkFeature: dup is found, ignoring");
   1145                         return 1;
   1146                     }
   1147                 }
   1148             }
   1149 
   1150             // TODO - move to individual network trackers
   1151             int usedNetworkType = convertFeatureToNetworkType(networkType, feature);
   1152 
   1153             tracker =  mNetTrackers[usedNetworkType];
   1154             if (tracker == null) {
   1155                 if (DBG) {
   1156                     log("stopUsingNetworkFeature: net " + networkType + ": " + feature +
   1157                             " no known tracker for used net type " + usedNetworkType);
   1158                 }
   1159                 return -1;
   1160             }
   1161             if (usedNetworkType != networkType) {
   1162                 Integer currentPid = new Integer(pid);
   1163                 mNetRequestersPids[usedNetworkType].remove(currentPid);
   1164                 reassessPidDns(pid, true);
   1165                 if (mNetRequestersPids[usedNetworkType].size() != 0) {
   1166                     if (VDBG) {
   1167                         log("stopUsingNetworkFeature: net " + networkType + ": " + feature +
   1168                                 " others still using it");
   1169                     }
   1170                     return 1;
   1171                 }
   1172                 callTeardown = true;
   1173             } else {
   1174                 if (DBG) {
   1175                     log("stopUsingNetworkFeature: net " + networkType + ": " + feature +
   1176                             " not a known feature - dropping");
   1177                 }
   1178             }
   1179         }
   1180 
   1181         if (callTeardown) {
   1182             if (DBG) {
   1183                 log("stopUsingNetworkFeature: teardown net " + networkType + ": " + feature);
   1184             }
   1185             tracker.teardown();
   1186             return 1;
   1187         } else {
   1188             return -1;
   1189         }
   1190     }
   1191 
   1192     /**
   1193      * @deprecated use requestRouteToHostAddress instead
   1194      *
   1195      * Ensure that a network route exists to deliver traffic to the specified
   1196      * host via the specified network interface.
   1197      * @param networkType the type of the network over which traffic to the
   1198      * specified host is to be routed
   1199      * @param hostAddress the IP address of the host to which the route is
   1200      * desired
   1201      * @return {@code true} on success, {@code false} on failure
   1202      */
   1203     public boolean requestRouteToHost(int networkType, int hostAddress) {
   1204         InetAddress inetAddress = NetworkUtils.intToInetAddress(hostAddress);
   1205 
   1206         if (inetAddress == null) {
   1207             return false;
   1208         }
   1209 
   1210         return requestRouteToHostAddress(networkType, inetAddress.getAddress());
   1211     }
   1212 
   1213     /**
   1214      * Ensure that a network route exists to deliver traffic to the specified
   1215      * host via the specified network interface.
   1216      * @param networkType the type of the network over which traffic to the
   1217      * specified host is to be routed
   1218      * @param hostAddress the IP address of the host to which the route is
   1219      * desired
   1220      * @return {@code true} on success, {@code false} on failure
   1221      */
   1222     public boolean requestRouteToHostAddress(int networkType, byte[] hostAddress) {
   1223         enforceChangePermission();
   1224         if (mProtectedNetworks.contains(networkType)) {
   1225             enforceConnectivityInternalPermission();
   1226         }
   1227 
   1228         if (!ConnectivityManager.isNetworkTypeValid(networkType)) {
   1229             if (DBG) log("requestRouteToHostAddress on invalid network: " + networkType);
   1230             return false;
   1231         }
   1232         NetworkStateTracker tracker = mNetTrackers[networkType];
   1233 
   1234         if (tracker == null || !tracker.getNetworkInfo().isConnected() ||
   1235                 tracker.isTeardownRequested()) {
   1236             if (VDBG) {
   1237                 log("requestRouteToHostAddress on down network " +
   1238                            "(" + networkType + ") - dropped");
   1239             }
   1240             return false;
   1241         }
   1242         final long token = Binder.clearCallingIdentity();
   1243         try {
   1244             InetAddress addr = InetAddress.getByAddress(hostAddress);
   1245             LinkProperties lp = tracker.getLinkProperties();
   1246             return addRouteToAddress(lp, addr);
   1247         } catch (UnknownHostException e) {
   1248             if (DBG) log("requestRouteToHostAddress got " + e.toString());
   1249         } finally {
   1250             Binder.restoreCallingIdentity(token);
   1251         }
   1252         return false;
   1253     }
   1254 
   1255     private boolean addRoute(LinkProperties p, RouteInfo r, boolean toDefaultTable) {
   1256         return modifyRoute(p.getInterfaceName(), p, r, 0, ADD, toDefaultTable);
   1257     }
   1258 
   1259     private boolean removeRoute(LinkProperties p, RouteInfo r, boolean toDefaultTable) {
   1260         return modifyRoute(p.getInterfaceName(), p, r, 0, REMOVE, toDefaultTable);
   1261     }
   1262 
   1263     private boolean addRouteToAddress(LinkProperties lp, InetAddress addr) {
   1264         return modifyRouteToAddress(lp, addr, ADD, TO_DEFAULT_TABLE);
   1265     }
   1266 
   1267     private boolean removeRouteToAddress(LinkProperties lp, InetAddress addr) {
   1268         return modifyRouteToAddress(lp, addr, REMOVE, TO_DEFAULT_TABLE);
   1269     }
   1270 
   1271     private boolean modifyRouteToAddress(LinkProperties lp, InetAddress addr, boolean doAdd,
   1272             boolean toDefaultTable) {
   1273         RouteInfo bestRoute = RouteInfo.selectBestRoute(lp.getRoutes(), addr);
   1274         if (bestRoute == null) {
   1275             bestRoute = RouteInfo.makeHostRoute(addr);
   1276         } else {
   1277             if (bestRoute.getGateway().equals(addr)) {
   1278                 // if there is no better route, add the implied hostroute for our gateway
   1279                 bestRoute = RouteInfo.makeHostRoute(addr);
   1280             } else {
   1281                 // if we will connect to this through another route, add a direct route
   1282                 // to it's gateway
   1283                 bestRoute = RouteInfo.makeHostRoute(addr, bestRoute.getGateway());
   1284             }
   1285         }
   1286         return modifyRoute(lp.getInterfaceName(), lp, bestRoute, 0, doAdd, toDefaultTable);
   1287     }
   1288 
   1289     private boolean modifyRoute(String ifaceName, LinkProperties lp, RouteInfo r, int cycleCount,
   1290             boolean doAdd, boolean toDefaultTable) {
   1291         if ((ifaceName == null) || (lp == null) || (r == null)) {
   1292             if (DBG) log("modifyRoute got unexpected null: " + ifaceName + ", " + lp + ", " + r);
   1293             return false;
   1294         }
   1295 
   1296         if (cycleCount > MAX_HOSTROUTE_CYCLE_COUNT) {
   1297             loge("Error modifying route - too much recursion");
   1298             return false;
   1299         }
   1300 
   1301         if (r.isHostRoute() == false) {
   1302             RouteInfo bestRoute = RouteInfo.selectBestRoute(lp.getRoutes(), r.getGateway());
   1303             if (bestRoute != null) {
   1304                 if (bestRoute.getGateway().equals(r.getGateway())) {
   1305                     // if there is no better route, add the implied hostroute for our gateway
   1306                     bestRoute = RouteInfo.makeHostRoute(r.getGateway());
   1307                 } else {
   1308                     // if we will connect to our gateway through another route, add a direct
   1309                     // route to it's gateway
   1310                     bestRoute = RouteInfo.makeHostRoute(r.getGateway(), bestRoute.getGateway());
   1311                 }
   1312                 modifyRoute(ifaceName, lp, bestRoute, cycleCount+1, doAdd, toDefaultTable);
   1313             }
   1314         }
   1315         if (doAdd) {
   1316             if (VDBG) log("Adding " + r + " for interface " + ifaceName);
   1317             try {
   1318                 if (toDefaultTable) {
   1319                     mAddedRoutes.add(r);  // only track default table - only one apps can effect
   1320                     mNetd.addRoute(ifaceName, r);
   1321                 } else {
   1322                     mNetd.addSecondaryRoute(ifaceName, r);
   1323                 }
   1324             } catch (Exception e) {
   1325                 // never crash - catch them all
   1326                 if (DBG) loge("Exception trying to add a route: " + e);
   1327                 return false;
   1328             }
   1329         } else {
   1330             // if we remove this one and there are no more like it, then refcount==0 and
   1331             // we can remove it from the table
   1332             if (toDefaultTable) {
   1333                 mAddedRoutes.remove(r);
   1334                 if (mAddedRoutes.contains(r) == false) {
   1335                     if (VDBG) log("Removing " + r + " for interface " + ifaceName);
   1336                     try {
   1337                         mNetd.removeRoute(ifaceName, r);
   1338                     } catch (Exception e) {
   1339                         // never crash - catch them all
   1340                         if (DBG) loge("Exception trying to remove a route: " + e);
   1341                         return false;
   1342                     }
   1343                 } else {
   1344                     if (VDBG) log("not removing " + r + " as it's still in use");
   1345                 }
   1346             } else {
   1347                 if (VDBG) log("Removing " + r + " for interface " + ifaceName);
   1348                 try {
   1349                     mNetd.removeSecondaryRoute(ifaceName, r);
   1350                 } catch (Exception e) {
   1351                     // never crash - catch them all
   1352                     if (DBG) loge("Exception trying to remove a route: " + e);
   1353                     return false;
   1354                 }
   1355             }
   1356         }
   1357         return true;
   1358     }
   1359 
   1360     /**
   1361      * @see ConnectivityManager#getMobileDataEnabled()
   1362      */
   1363     public boolean getMobileDataEnabled() {
   1364         // TODO: This detail should probably be in DataConnectionTracker's
   1365         //       which is where we store the value and maybe make this
   1366         //       asynchronous.
   1367         enforceAccessPermission();
   1368         boolean retVal = Settings.Secure.getInt(mContext.getContentResolver(),
   1369                 Settings.Secure.MOBILE_DATA, 1) == 1;
   1370         if (VDBG) log("getMobileDataEnabled returning " + retVal);
   1371         return retVal;
   1372     }
   1373 
   1374     public void setDataDependency(int networkType, boolean met) {
   1375         enforceConnectivityInternalPermission();
   1376 
   1377         mHandler.sendMessage(mHandler.obtainMessage(EVENT_SET_DEPENDENCY_MET,
   1378                 (met ? ENABLED : DISABLED), networkType));
   1379     }
   1380 
   1381     private void handleSetDependencyMet(int networkType, boolean met) {
   1382         if (mNetTrackers[networkType] != null) {
   1383             if (DBG) {
   1384                 log("handleSetDependencyMet(" + networkType + ", " + met + ")");
   1385             }
   1386             mNetTrackers[networkType].setDependencyMet(met);
   1387         }
   1388     }
   1389 
   1390     private INetworkPolicyListener mPolicyListener = new INetworkPolicyListener.Stub() {
   1391         @Override
   1392         public void onUidRulesChanged(int uid, int uidRules) {
   1393             // only someone like NPMS should only be calling us
   1394             mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
   1395 
   1396             if (LOGD_RULES) {
   1397                 log("onUidRulesChanged(uid=" + uid + ", uidRules=" + uidRules + ")");
   1398             }
   1399 
   1400             synchronized (mRulesLock) {
   1401                 // skip update when we've already applied rules
   1402                 final int oldRules = mUidRules.get(uid, RULE_ALLOW_ALL);
   1403                 if (oldRules == uidRules) return;
   1404 
   1405                 mUidRules.put(uid, uidRules);
   1406             }
   1407 
   1408             // TODO: dispatch into NMS to push rules towards kernel module
   1409             // TODO: notify UID when it has requested targeted updates
   1410         }
   1411 
   1412         @Override
   1413         public void onMeteredIfacesChanged(String[] meteredIfaces) {
   1414             // only someone like NPMS should only be calling us
   1415             mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
   1416 
   1417             if (LOGD_RULES) {
   1418                 log("onMeteredIfacesChanged(ifaces=" + Arrays.toString(meteredIfaces) + ")");
   1419             }
   1420 
   1421             synchronized (mRulesLock) {
   1422                 mMeteredIfaces.clear();
   1423                 for (String iface : meteredIfaces) {
   1424                     mMeteredIfaces.add(iface);
   1425                 }
   1426             }
   1427         }
   1428     };
   1429 
   1430     /**
   1431      * @see ConnectivityManager#setMobileDataEnabled(boolean)
   1432      */
   1433     public void setMobileDataEnabled(boolean enabled) {
   1434         enforceChangePermission();
   1435         if (DBG) log("setMobileDataEnabled(" + enabled + ")");
   1436 
   1437         mHandler.sendMessage(mHandler.obtainMessage(EVENT_SET_MOBILE_DATA,
   1438                 (enabled ? ENABLED : DISABLED), 0));
   1439     }
   1440 
   1441     private void handleSetMobileData(boolean enabled) {
   1442         if (mNetTrackers[ConnectivityManager.TYPE_MOBILE] != null) {
   1443             if (VDBG) {
   1444                 log(mNetTrackers[ConnectivityManager.TYPE_MOBILE].toString() + enabled);
   1445             }
   1446             mNetTrackers[ConnectivityManager.TYPE_MOBILE].setUserDataEnable(enabled);
   1447         }
   1448         if (mNetTrackers[ConnectivityManager.TYPE_WIMAX] != null) {
   1449             if (VDBG) {
   1450                 log(mNetTrackers[ConnectivityManager.TYPE_WIMAX].toString() + enabled);
   1451             }
   1452             mNetTrackers[ConnectivityManager.TYPE_WIMAX].setUserDataEnable(enabled);
   1453         }
   1454     }
   1455 
   1456     @Override
   1457     public void setPolicyDataEnable(int networkType, boolean enabled) {
   1458         // only someone like NPMS should only be calling us
   1459         mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
   1460 
   1461         mHandler.sendMessage(mHandler.obtainMessage(
   1462                 EVENT_SET_POLICY_DATA_ENABLE, networkType, (enabled ? ENABLED : DISABLED)));
   1463     }
   1464 
   1465     private void handleSetPolicyDataEnable(int networkType, boolean enabled) {
   1466         if (isNetworkTypeValid(networkType)) {
   1467             final NetworkStateTracker tracker = mNetTrackers[networkType];
   1468             if (tracker != null) {
   1469                 tracker.setPolicyDataEnable(enabled);
   1470             }
   1471         }
   1472     }
   1473 
   1474     private void enforceAccessPermission() {
   1475         mContext.enforceCallingOrSelfPermission(
   1476                 android.Manifest.permission.ACCESS_NETWORK_STATE,
   1477                 "ConnectivityService");
   1478     }
   1479 
   1480     private void enforceChangePermission() {
   1481         mContext.enforceCallingOrSelfPermission(
   1482                 android.Manifest.permission.CHANGE_NETWORK_STATE,
   1483                 "ConnectivityService");
   1484     }
   1485 
   1486     // TODO Make this a special check when it goes public
   1487     private void enforceTetherChangePermission() {
   1488         mContext.enforceCallingOrSelfPermission(
   1489                 android.Manifest.permission.CHANGE_NETWORK_STATE,
   1490                 "ConnectivityService");
   1491     }
   1492 
   1493     private void enforceTetherAccessPermission() {
   1494         mContext.enforceCallingOrSelfPermission(
   1495                 android.Manifest.permission.ACCESS_NETWORK_STATE,
   1496                 "ConnectivityService");
   1497     }
   1498 
   1499     private void enforceConnectivityInternalPermission() {
   1500         mContext.enforceCallingOrSelfPermission(
   1501                 android.Manifest.permission.CONNECTIVITY_INTERNAL,
   1502                 "ConnectivityService");
   1503     }
   1504 
   1505     /**
   1506      * Handle a {@code DISCONNECTED} event. If this pertains to the non-active
   1507      * network, we ignore it. If it is for the active network, we send out a
   1508      * broadcast. But first, we check whether it might be possible to connect
   1509      * to a different network.
   1510      * @param info the {@code NetworkInfo} for the network
   1511      */
   1512     private void handleDisconnect(NetworkInfo info) {
   1513 
   1514         int prevNetType = info.getType();
   1515 
   1516         mNetTrackers[prevNetType].setTeardownRequested(false);
   1517         /*
   1518          * If the disconnected network is not the active one, then don't report
   1519          * this as a loss of connectivity. What probably happened is that we're
   1520          * getting the disconnect for a network that we explicitly disabled
   1521          * in accordance with network preference policies.
   1522          */
   1523         if (!mNetConfigs[prevNetType].isDefault()) {
   1524             List pids = mNetRequestersPids[prevNetType];
   1525             for (int i = 0; i<pids.size(); i++) {
   1526                 Integer pid = (Integer)pids.get(i);
   1527                 // will remove them because the net's no longer connected
   1528                 // need to do this now as only now do we know the pids and
   1529                 // can properly null things that are no longer referenced.
   1530                 reassessPidDns(pid.intValue(), false);
   1531             }
   1532         }
   1533 
   1534         Intent intent = new Intent(ConnectivityManager.CONNECTIVITY_ACTION);
   1535         intent.putExtra(ConnectivityManager.EXTRA_NETWORK_INFO, info);
   1536         if (info.isFailover()) {
   1537             intent.putExtra(ConnectivityManager.EXTRA_IS_FAILOVER, true);
   1538             info.setFailover(false);
   1539         }
   1540         if (info.getReason() != null) {
   1541             intent.putExtra(ConnectivityManager.EXTRA_REASON, info.getReason());
   1542         }
   1543         if (info.getExtraInfo() != null) {
   1544             intent.putExtra(ConnectivityManager.EXTRA_EXTRA_INFO,
   1545                     info.getExtraInfo());
   1546         }
   1547 
   1548         if (mNetConfigs[prevNetType].isDefault()) {
   1549             tryFailover(prevNetType);
   1550             if (mActiveDefaultNetwork != -1) {
   1551                 NetworkInfo switchTo = mNetTrackers[mActiveDefaultNetwork].getNetworkInfo();
   1552                 intent.putExtra(ConnectivityManager.EXTRA_OTHER_NETWORK_INFO, switchTo);
   1553             } else {
   1554                 mDefaultInetConditionPublished = 0; // we're not connected anymore
   1555                 intent.putExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, true);
   1556             }
   1557         }
   1558         intent.putExtra(ConnectivityManager.EXTRA_INET_CONDITION, mDefaultInetConditionPublished);
   1559 
   1560         // Reset interface if no other connections are using the same interface
   1561         boolean doReset = true;
   1562         LinkProperties linkProperties = mNetTrackers[prevNetType].getLinkProperties();
   1563         if (linkProperties != null) {
   1564             String oldIface = linkProperties.getInterfaceName();
   1565             if (TextUtils.isEmpty(oldIface) == false) {
   1566                 for (NetworkStateTracker networkStateTracker : mNetTrackers) {
   1567                     if (networkStateTracker == null) continue;
   1568                     NetworkInfo networkInfo = networkStateTracker.getNetworkInfo();
   1569                     if (networkInfo.isConnected() && networkInfo.getType() != prevNetType) {
   1570                         LinkProperties l = networkStateTracker.getLinkProperties();
   1571                         if (l == null) continue;
   1572                         if (oldIface.equals(l.getInterfaceName())) {
   1573                             doReset = false;
   1574                             break;
   1575                         }
   1576                     }
   1577                 }
   1578             }
   1579         }
   1580 
   1581         // do this before we broadcast the change
   1582         handleConnectivityChange(prevNetType, doReset);
   1583 
   1584         final Intent immediateIntent = new Intent(intent);
   1585         immediateIntent.setAction(CONNECTIVITY_ACTION_IMMEDIATE);
   1586         sendStickyBroadcast(immediateIntent);
   1587         sendStickyBroadcastDelayed(intent, getConnectivityChangeDelay());
   1588         /*
   1589          * If the failover network is already connected, then immediately send
   1590          * out a followup broadcast indicating successful failover
   1591          */
   1592         if (mActiveDefaultNetwork != -1) {
   1593             sendConnectedBroadcastDelayed(mNetTrackers[mActiveDefaultNetwork].getNetworkInfo(),
   1594                     getConnectivityChangeDelay());
   1595         }
   1596     }
   1597 
   1598     private void tryFailover(int prevNetType) {
   1599         /*
   1600          * If this is a default network, check if other defaults are available.
   1601          * Try to reconnect on all available and let them hash it out when
   1602          * more than one connects.
   1603          */
   1604         if (mNetConfigs[prevNetType].isDefault()) {
   1605             if (mActiveDefaultNetwork == prevNetType) {
   1606                 mActiveDefaultNetwork = -1;
   1607             }
   1608 
   1609             // don't signal a reconnect for anything lower or equal priority than our
   1610             // current connected default
   1611             // TODO - don't filter by priority now - nice optimization but risky
   1612 //            int currentPriority = -1;
   1613 //            if (mActiveDefaultNetwork != -1) {
   1614 //                currentPriority = mNetConfigs[mActiveDefaultNetwork].mPriority;
   1615 //            }
   1616             for (int checkType=0; checkType <= ConnectivityManager.MAX_NETWORK_TYPE; checkType++) {
   1617                 if (checkType == prevNetType) continue;
   1618                 if (mNetConfigs[checkType] == null) continue;
   1619                 if (!mNetConfigs[checkType].isDefault()) continue;
   1620                 if (mNetTrackers[checkType] == null) continue;
   1621 
   1622 // Enabling the isAvailable() optimization caused mobile to not get
   1623 // selected if it was in the middle of error handling. Specifically
   1624 // a moble connection that took 30 seconds to complete the DEACTIVATE_DATA_CALL
   1625 // would not be available and we wouldn't get connected to anything.
   1626 // So removing the isAvailable() optimization below for now. TODO: This
   1627 // optimization should work and we need to investigate why it doesn't work.
   1628 // This could be related to how DEACTIVATE_DATA_CALL is reporting its
   1629 // complete before it is really complete.
   1630 //                if (!mNetTrackers[checkType].isAvailable()) continue;
   1631 
   1632 //                if (currentPriority >= mNetConfigs[checkType].mPriority) continue;
   1633 
   1634                 NetworkStateTracker checkTracker = mNetTrackers[checkType];
   1635                 NetworkInfo checkInfo = checkTracker.getNetworkInfo();
   1636                 if (!checkInfo.isConnectedOrConnecting() || checkTracker.isTeardownRequested()) {
   1637                     checkInfo.setFailover(true);
   1638                     checkTracker.reconnect();
   1639                 }
   1640                 if (DBG) log("Attempting to switch to " + checkInfo.getTypeName());
   1641             }
   1642         }
   1643     }
   1644 
   1645     private void sendConnectedBroadcast(NetworkInfo info) {
   1646         sendGeneralBroadcast(info, CONNECTIVITY_ACTION_IMMEDIATE);
   1647         sendGeneralBroadcast(info, CONNECTIVITY_ACTION);
   1648     }
   1649 
   1650     private void sendConnectedBroadcastDelayed(NetworkInfo info, int delayMs) {
   1651         sendGeneralBroadcast(info, CONNECTIVITY_ACTION_IMMEDIATE);
   1652         sendGeneralBroadcastDelayed(info, CONNECTIVITY_ACTION, delayMs);
   1653     }
   1654 
   1655     private void sendInetConditionBroadcast(NetworkInfo info) {
   1656         sendGeneralBroadcast(info, ConnectivityManager.INET_CONDITION_ACTION);
   1657     }
   1658 
   1659     private Intent makeGeneralIntent(NetworkInfo info, String bcastType) {
   1660         Intent intent = new Intent(bcastType);
   1661         intent.putExtra(ConnectivityManager.EXTRA_NETWORK_INFO, info);
   1662         if (info.isFailover()) {
   1663             intent.putExtra(ConnectivityManager.EXTRA_IS_FAILOVER, true);
   1664             info.setFailover(false);
   1665         }
   1666         if (info.getReason() != null) {
   1667             intent.putExtra(ConnectivityManager.EXTRA_REASON, info.getReason());
   1668         }
   1669         if (info.getExtraInfo() != null) {
   1670             intent.putExtra(ConnectivityManager.EXTRA_EXTRA_INFO,
   1671                     info.getExtraInfo());
   1672         }
   1673         intent.putExtra(ConnectivityManager.EXTRA_INET_CONDITION, mDefaultInetConditionPublished);
   1674         return intent;
   1675     }
   1676 
   1677     private void sendGeneralBroadcast(NetworkInfo info, String bcastType) {
   1678         sendStickyBroadcast(makeGeneralIntent(info, bcastType));
   1679     }
   1680 
   1681     private void sendGeneralBroadcastDelayed(NetworkInfo info, String bcastType, int delayMs) {
   1682         sendStickyBroadcastDelayed(makeGeneralIntent(info, bcastType), delayMs);
   1683     }
   1684 
   1685     /**
   1686      * Called when an attempt to fail over to another network has failed.
   1687      * @param info the {@link NetworkInfo} for the failed network
   1688      */
   1689     private void handleConnectionFailure(NetworkInfo info) {
   1690         mNetTrackers[info.getType()].setTeardownRequested(false);
   1691 
   1692         String reason = info.getReason();
   1693         String extraInfo = info.getExtraInfo();
   1694 
   1695         String reasonText;
   1696         if (reason == null) {
   1697             reasonText = ".";
   1698         } else {
   1699             reasonText = " (" + reason + ").";
   1700         }
   1701         loge("Attempt to connect to " + info.getTypeName() + " failed" + reasonText);
   1702 
   1703         Intent intent = new Intent(ConnectivityManager.CONNECTIVITY_ACTION);
   1704         intent.putExtra(ConnectivityManager.EXTRA_NETWORK_INFO, info);
   1705         if (getActiveNetworkInfo() == null) {
   1706             intent.putExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, true);
   1707         }
   1708         if (reason != null) {
   1709             intent.putExtra(ConnectivityManager.EXTRA_REASON, reason);
   1710         }
   1711         if (extraInfo != null) {
   1712             intent.putExtra(ConnectivityManager.EXTRA_EXTRA_INFO, extraInfo);
   1713         }
   1714         if (info.isFailover()) {
   1715             intent.putExtra(ConnectivityManager.EXTRA_IS_FAILOVER, true);
   1716             info.setFailover(false);
   1717         }
   1718 
   1719         if (mNetConfigs[info.getType()].isDefault()) {
   1720             tryFailover(info.getType());
   1721             if (mActiveDefaultNetwork != -1) {
   1722                 NetworkInfo switchTo = mNetTrackers[mActiveDefaultNetwork].getNetworkInfo();
   1723                 intent.putExtra(ConnectivityManager.EXTRA_OTHER_NETWORK_INFO, switchTo);
   1724             } else {
   1725                 mDefaultInetConditionPublished = 0;
   1726                 intent.putExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, true);
   1727             }
   1728         }
   1729 
   1730         intent.putExtra(ConnectivityManager.EXTRA_INET_CONDITION, mDefaultInetConditionPublished);
   1731 
   1732         final Intent immediateIntent = new Intent(intent);
   1733         immediateIntent.setAction(CONNECTIVITY_ACTION_IMMEDIATE);
   1734         sendStickyBroadcast(immediateIntent);
   1735         sendStickyBroadcast(intent);
   1736         /*
   1737          * If the failover network is already connected, then immediately send
   1738          * out a followup broadcast indicating successful failover
   1739          */
   1740         if (mActiveDefaultNetwork != -1) {
   1741             sendConnectedBroadcast(mNetTrackers[mActiveDefaultNetwork].getNetworkInfo());
   1742         }
   1743     }
   1744 
   1745     private void sendStickyBroadcast(Intent intent) {
   1746         synchronized(this) {
   1747             if (!mSystemReady) {
   1748                 mInitialBroadcast = new Intent(intent);
   1749             }
   1750             intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
   1751             if (VDBG) {
   1752                 log("sendStickyBroadcast: action=" + intent.getAction());
   1753             }
   1754 
   1755             mContext.sendStickyBroadcast(intent);
   1756         }
   1757     }
   1758 
   1759     private void sendStickyBroadcastDelayed(Intent intent, int delayMs) {
   1760         if (delayMs <= 0) {
   1761             sendStickyBroadcast(intent);
   1762         } else {
   1763             if (VDBG) {
   1764                 log("sendStickyBroadcastDelayed: delayMs=" + delayMs + ", action="
   1765                         + intent.getAction());
   1766             }
   1767             mHandler.sendMessageDelayed(mHandler.obtainMessage(
   1768                     EVENT_SEND_STICKY_BROADCAST_INTENT, intent), delayMs);
   1769         }
   1770     }
   1771 
   1772     void systemReady() {
   1773         synchronized(this) {
   1774             mSystemReady = true;
   1775             if (mInitialBroadcast != null) {
   1776                 mContext.sendStickyBroadcast(mInitialBroadcast);
   1777                 mInitialBroadcast = null;
   1778             }
   1779         }
   1780         // load the global proxy at startup
   1781         mHandler.sendMessage(mHandler.obtainMessage(EVENT_APPLY_GLOBAL_HTTP_PROXY));
   1782     }
   1783 
   1784     private void handleConnect(NetworkInfo info) {
   1785         final int type = info.getType();
   1786 
   1787         // snapshot isFailover, because sendConnectedBroadcast() resets it
   1788         boolean isFailover = info.isFailover();
   1789         final NetworkStateTracker thisNet = mNetTrackers[type];
   1790 
   1791         // if this is a default net and other default is running
   1792         // kill the one not preferred
   1793         if (mNetConfigs[type].isDefault()) {
   1794             if (mActiveDefaultNetwork != -1 && mActiveDefaultNetwork != type) {
   1795                 if ((type != mNetworkPreference &&
   1796                         mNetConfigs[mActiveDefaultNetwork].priority >
   1797                         mNetConfigs[type].priority) ||
   1798                         mNetworkPreference == mActiveDefaultNetwork) {
   1799                         // don't accept this one
   1800                         if (VDBG) {
   1801                             log("Not broadcasting CONNECT_ACTION " +
   1802                                 "to torn down network " + info.getTypeName());
   1803                         }
   1804                         teardown(thisNet);
   1805                         return;
   1806                 } else {
   1807                     // tear down the other
   1808                     NetworkStateTracker otherNet =
   1809                             mNetTrackers[mActiveDefaultNetwork];
   1810                     if (DBG) {
   1811                         log("Policy requires " + otherNet.getNetworkInfo().getTypeName() +
   1812                             " teardown");
   1813                     }
   1814                     if (!teardown(otherNet)) {
   1815                         loge("Network declined teardown request");
   1816                         teardown(thisNet);
   1817                         return;
   1818                     }
   1819                 }
   1820             }
   1821             synchronized (ConnectivityService.this) {
   1822                 // have a new default network, release the transition wakelock in a second
   1823                 // if it's held.  The second pause is to allow apps to reconnect over the
   1824                 // new network
   1825                 if (mNetTransitionWakeLock.isHeld()) {
   1826                     mHandler.sendMessageDelayed(mHandler.obtainMessage(
   1827                             EVENT_CLEAR_NET_TRANSITION_WAKELOCK,
   1828                             mNetTransitionWakeLockSerialNumber, 0),
   1829                             1000);
   1830                 }
   1831             }
   1832             mActiveDefaultNetwork = type;
   1833             // this will cause us to come up initially as unconnected and switching
   1834             // to connected after our normal pause unless somebody reports us as reall
   1835             // disconnected
   1836             mDefaultInetConditionPublished = 0;
   1837             mDefaultConnectionSequence++;
   1838             mInetConditionChangeInFlight = false;
   1839             // Don't do this - if we never sign in stay, grey
   1840             //reportNetworkCondition(mActiveDefaultNetwork, 100);
   1841         }
   1842         thisNet.setTeardownRequested(false);
   1843         updateNetworkSettings(thisNet);
   1844         handleConnectivityChange(type, false);
   1845         sendConnectedBroadcastDelayed(info, getConnectivityChangeDelay());
   1846 
   1847         // notify battery stats service about this network
   1848         final String iface = thisNet.getLinkProperties().getInterfaceName();
   1849         if (iface != null) {
   1850             try {
   1851                 BatteryStatsService.getService().noteNetworkInterfaceType(iface, type);
   1852             } catch (RemoteException e) {
   1853                 // ignored; service lives in system_server
   1854             }
   1855         }
   1856     }
   1857 
   1858     /**
   1859      * After a change in the connectivity state of a network. We're mainly
   1860      * concerned with making sure that the list of DNS servers is set up
   1861      * according to which networks are connected, and ensuring that the
   1862      * right routing table entries exist.
   1863      */
   1864     private void handleConnectivityChange(int netType, boolean doReset) {
   1865         int resetMask = doReset ? NetworkUtils.RESET_ALL_ADDRESSES : 0;
   1866 
   1867         /*
   1868          * If a non-default network is enabled, add the host routes that
   1869          * will allow it's DNS servers to be accessed.
   1870          */
   1871         handleDnsConfigurationChange(netType);
   1872 
   1873         LinkProperties curLp = mCurrentLinkProperties[netType];
   1874         LinkProperties newLp = null;
   1875 
   1876         if (mNetTrackers[netType].getNetworkInfo().isConnected()) {
   1877             newLp = mNetTrackers[netType].getLinkProperties();
   1878             if (VDBG) {
   1879                 log("handleConnectivityChange: changed linkProperty[" + netType + "]:" +
   1880                         " doReset=" + doReset + " resetMask=" + resetMask +
   1881                         "\n   curLp=" + curLp +
   1882                         "\n   newLp=" + newLp);
   1883             }
   1884 
   1885             if (curLp != null) {
   1886                 if (curLp.isIdenticalInterfaceName(newLp)) {
   1887                     CompareResult<LinkAddress> car = curLp.compareAddresses(newLp);
   1888                     if ((car.removed.size() != 0) || (car.added.size() != 0)) {
   1889                         for (LinkAddress linkAddr : car.removed) {
   1890                             if (linkAddr.getAddress() instanceof Inet4Address) {
   1891                                 resetMask |= NetworkUtils.RESET_IPV4_ADDRESSES;
   1892                             }
   1893                             if (linkAddr.getAddress() instanceof Inet6Address) {
   1894                                 resetMask |= NetworkUtils.RESET_IPV6_ADDRESSES;
   1895                             }
   1896                         }
   1897                         if (DBG) {
   1898                             log("handleConnectivityChange: addresses changed" +
   1899                                     " linkProperty[" + netType + "]:" + " resetMask=" + resetMask +
   1900                                     "\n   car=" + car);
   1901                         }
   1902                     } else {
   1903                         if (DBG) {
   1904                             log("handleConnectivityChange: address are the same reset per doReset" +
   1905                                    " linkProperty[" + netType + "]:" +
   1906                                    " resetMask=" + resetMask);
   1907                         }
   1908                     }
   1909                 } else {
   1910                     resetMask = NetworkUtils.RESET_ALL_ADDRESSES;
   1911                     if (DBG) {
   1912                         log("handleConnectivityChange: interface not not equivalent reset both" +
   1913                                 " linkProperty[" + netType + "]:" +
   1914                                 " resetMask=" + resetMask);
   1915                     }
   1916                 }
   1917             }
   1918             if (mNetConfigs[netType].isDefault()) {
   1919                 handleApplyDefaultProxy(newLp.getHttpProxy());
   1920             }
   1921         } else {
   1922             if (VDBG) {
   1923                 log("handleConnectivityChange: changed linkProperty[" + netType + "]:" +
   1924                         " doReset=" + doReset + " resetMask=" + resetMask +
   1925                         "\n  curLp=" + curLp +
   1926                         "\n  newLp= null");
   1927             }
   1928         }
   1929         mCurrentLinkProperties[netType] = newLp;
   1930         boolean resetDns = updateRoutes(newLp, curLp, mNetConfigs[netType].isDefault());
   1931 
   1932         if (resetMask != 0 || resetDns) {
   1933             LinkProperties linkProperties = mNetTrackers[netType].getLinkProperties();
   1934             if (linkProperties != null) {
   1935                 String iface = linkProperties.getInterfaceName();
   1936                 if (TextUtils.isEmpty(iface) == false) {
   1937                     if (resetMask != 0) {
   1938                         if (DBG) log("resetConnections(" + iface + ", " + resetMask + ")");
   1939                         NetworkUtils.resetConnections(iface, resetMask);
   1940 
   1941                         // Tell VPN the interface is down. It is a temporary
   1942                         // but effective fix to make VPN aware of the change.
   1943                         if ((resetMask & NetworkUtils.RESET_IPV4_ADDRESSES) != 0) {
   1944                             mVpn.interfaceStatusChanged(iface, false);
   1945                         }
   1946                     }
   1947                     if (resetDns) {
   1948                         if (VDBG) log("resetting DNS cache for " + iface);
   1949                         try {
   1950                             mNetd.flushInterfaceDnsCache(iface);
   1951                         } catch (Exception e) {
   1952                             // never crash - catch them all
   1953                             if (DBG) loge("Exception resetting dns cache: " + e);
   1954                         }
   1955                     }
   1956                 }
   1957             }
   1958         }
   1959 
   1960         // TODO: Temporary notifying upstread change to Tethering.
   1961         //       @see bug/4455071
   1962         /** Notify TetheringService if interface name has been changed. */
   1963         if (TextUtils.equals(mNetTrackers[netType].getNetworkInfo().getReason(),
   1964                              Phone.REASON_LINK_PROPERTIES_CHANGED)) {
   1965             if (isTetheringSupported()) {
   1966                 mTethering.handleTetherIfaceChange();
   1967             }
   1968         }
   1969     }
   1970 
   1971     /**
   1972      * Add and remove routes using the old properties (null if not previously connected),
   1973      * new properties (null if becoming disconnected).  May even be double null, which
   1974      * is a noop.
   1975      * Uses isLinkDefault to determine if default routes should be set or conversely if
   1976      * host routes should be set to the dns servers
   1977      * returns a boolean indicating the routes changed
   1978      */
   1979     private boolean updateRoutes(LinkProperties newLp, LinkProperties curLp,
   1980             boolean isLinkDefault) {
   1981         Collection<RouteInfo> routesToAdd = null;
   1982         CompareResult<InetAddress> dnsDiff = new CompareResult<InetAddress>();
   1983         CompareResult<RouteInfo> routeDiff = new CompareResult<RouteInfo>();
   1984         if (curLp != null) {
   1985             // check for the delta between the current set and the new
   1986             routeDiff = curLp.compareRoutes(newLp);
   1987             dnsDiff = curLp.compareDnses(newLp);
   1988         } else if (newLp != null) {
   1989             routeDiff.added = newLp.getRoutes();
   1990             dnsDiff.added = newLp.getDnses();
   1991         }
   1992 
   1993         boolean routesChanged = (routeDiff.removed.size() != 0 || routeDiff.added.size() != 0);
   1994 
   1995         for (RouteInfo r : routeDiff.removed) {
   1996             if (isLinkDefault || ! r.isDefaultRoute()) {
   1997                 removeRoute(curLp, r, TO_DEFAULT_TABLE);
   1998             }
   1999             if (isLinkDefault == false) {
   2000                 // remove from a secondary route table
   2001                 removeRoute(curLp, r, TO_SECONDARY_TABLE);
   2002             }
   2003         }
   2004 
   2005         for (RouteInfo r :  routeDiff.added) {
   2006             if (isLinkDefault || ! r.isDefaultRoute()) {
   2007                 addRoute(newLp, r, TO_DEFAULT_TABLE);
   2008             } else {
   2009                 // add to a secondary route table
   2010                 addRoute(newLp, r, TO_SECONDARY_TABLE);
   2011 
   2012                 // many radios add a default route even when we don't want one.
   2013                 // remove the default route unless somebody else has asked for it
   2014                 String ifaceName = newLp.getInterfaceName();
   2015                 if (TextUtils.isEmpty(ifaceName) == false && mAddedRoutes.contains(r) == false) {
   2016                     if (VDBG) log("Removing " + r + " for interface " + ifaceName);
   2017                     try {
   2018                         mNetd.removeRoute(ifaceName, r);
   2019                     } catch (Exception e) {
   2020                         // never crash - catch them all
   2021                         if (DBG) loge("Exception trying to remove a route: " + e);
   2022                     }
   2023                 }
   2024             }
   2025         }
   2026 
   2027         if (!isLinkDefault) {
   2028             // handle DNS routes
   2029             if (routesChanged) {
   2030                 // routes changed - remove all old dns entries and add new
   2031                 if (curLp != null) {
   2032                     for (InetAddress oldDns : curLp.getDnses()) {
   2033                         removeRouteToAddress(curLp, oldDns);
   2034                     }
   2035                 }
   2036                 if (newLp != null) {
   2037                     for (InetAddress newDns : newLp.getDnses()) {
   2038                         addRouteToAddress(newLp, newDns);
   2039                     }
   2040                 }
   2041             } else {
   2042                 // no change in routes, check for change in dns themselves
   2043                 for (InetAddress oldDns : dnsDiff.removed) {
   2044                     removeRouteToAddress(curLp, oldDns);
   2045                 }
   2046                 for (InetAddress newDns : dnsDiff.added) {
   2047                     addRouteToAddress(newLp, newDns);
   2048                 }
   2049             }
   2050         }
   2051         return routesChanged;
   2052     }
   2053 
   2054 
   2055    /**
   2056      * Reads the network specific TCP buffer sizes from SystemProperties
   2057      * net.tcp.buffersize.[default|wifi|umts|edge|gprs] and set them for system
   2058      * wide use
   2059      */
   2060    public void updateNetworkSettings(NetworkStateTracker nt) {
   2061         String key = nt.getTcpBufferSizesPropName();
   2062         String bufferSizes = SystemProperties.get(key);
   2063 
   2064         if (bufferSizes.length() == 0) {
   2065             if (VDBG) log(key + " not found in system properties. Using defaults");
   2066 
   2067             // Setting to default values so we won't be stuck to previous values
   2068             key = "net.tcp.buffersize.default";
   2069             bufferSizes = SystemProperties.get(key);
   2070         }
   2071 
   2072         // Set values in kernel
   2073         if (bufferSizes.length() != 0) {
   2074             if (VDBG) {
   2075                 log("Setting TCP values: [" + bufferSizes
   2076                         + "] which comes from [" + key + "]");
   2077             }
   2078             setBufferSize(bufferSizes);
   2079         }
   2080     }
   2081 
   2082    /**
   2083      * Writes TCP buffer sizes to /sys/kernel/ipv4/tcp_[r/w]mem_[min/def/max]
   2084      * which maps to /proc/sys/net/ipv4/tcp_rmem and tcpwmem
   2085      *
   2086      * @param bufferSizes in the format of "readMin, readInitial, readMax,
   2087      *        writeMin, writeInitial, writeMax"
   2088      */
   2089     private void setBufferSize(String bufferSizes) {
   2090         try {
   2091             String[] values = bufferSizes.split(",");
   2092 
   2093             if (values.length == 6) {
   2094               final String prefix = "/sys/kernel/ipv4/tcp_";
   2095                 FileUtils.stringToFile(prefix + "rmem_min", values[0]);
   2096                 FileUtils.stringToFile(prefix + "rmem_def", values[1]);
   2097                 FileUtils.stringToFile(prefix + "rmem_max", values[2]);
   2098                 FileUtils.stringToFile(prefix + "wmem_min", values[3]);
   2099                 FileUtils.stringToFile(prefix + "wmem_def", values[4]);
   2100                 FileUtils.stringToFile(prefix + "wmem_max", values[5]);
   2101             } else {
   2102                 loge("Invalid buffersize string: " + bufferSizes);
   2103             }
   2104         } catch (IOException e) {
   2105             loge("Can't set tcp buffer sizes:" + e);
   2106         }
   2107     }
   2108 
   2109     /**
   2110      * Adjust the per-process dns entries (net.dns<x>.<pid>) based
   2111      * on the highest priority active net which this process requested.
   2112      * If there aren't any, clear it out
   2113      */
   2114     private void reassessPidDns(int myPid, boolean doBump)
   2115     {
   2116         if (VDBG) log("reassessPidDns for pid " + myPid);
   2117         for(int i : mPriorityList) {
   2118             if (mNetConfigs[i].isDefault()) {
   2119                 continue;
   2120             }
   2121             NetworkStateTracker nt = mNetTrackers[i];
   2122             if (nt.getNetworkInfo().isConnected() &&
   2123                     !nt.isTeardownRequested()) {
   2124                 LinkProperties p = nt.getLinkProperties();
   2125                 if (p == null) continue;
   2126                 List pids = mNetRequestersPids[i];
   2127                 for (int j=0; j<pids.size(); j++) {
   2128                     Integer pid = (Integer)pids.get(j);
   2129                     if (pid.intValue() == myPid) {
   2130                         Collection<InetAddress> dnses = p.getDnses();
   2131                         writePidDns(dnses, myPid);
   2132                         if (doBump) {
   2133                             bumpDns();
   2134                         }
   2135                         return;
   2136                     }
   2137                 }
   2138            }
   2139         }
   2140         // nothing found - delete
   2141         for (int i = 1; ; i++) {
   2142             String prop = "net.dns" + i + "." + myPid;
   2143             if (SystemProperties.get(prop).length() == 0) {
   2144                 if (doBump) {
   2145                     bumpDns();
   2146                 }
   2147                 return;
   2148             }
   2149             SystemProperties.set(prop, "");
   2150         }
   2151     }
   2152 
   2153     // return true if results in a change
   2154     private boolean writePidDns(Collection <InetAddress> dnses, int pid) {
   2155         int j = 1;
   2156         boolean changed = false;
   2157         for (InetAddress dns : dnses) {
   2158             String dnsString = dns.getHostAddress();
   2159             if (changed || !dnsString.equals(SystemProperties.get("net.dns" + j + "." + pid))) {
   2160                 changed = true;
   2161                 SystemProperties.set("net.dns" + j++ + "." + pid, dns.getHostAddress());
   2162             }
   2163         }
   2164         return changed;
   2165     }
   2166 
   2167     private void bumpDns() {
   2168         /*
   2169          * Bump the property that tells the name resolver library to reread
   2170          * the DNS server list from the properties.
   2171          */
   2172         String propVal = SystemProperties.get("net.dnschange");
   2173         int n = 0;
   2174         if (propVal.length() != 0) {
   2175             try {
   2176                 n = Integer.parseInt(propVal);
   2177             } catch (NumberFormatException e) {}
   2178         }
   2179         SystemProperties.set("net.dnschange", "" + (n+1));
   2180         /*
   2181          * Tell the VMs to toss their DNS caches
   2182          */
   2183         Intent intent = new Intent(Intent.ACTION_CLEAR_DNS_CACHE);
   2184         intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
   2185         /*
   2186          * Connectivity events can happen before boot has completed ...
   2187          */
   2188         intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
   2189         mContext.sendBroadcast(intent);
   2190     }
   2191 
   2192     // Caller must grab mDnsLock.
   2193     private boolean updateDns(String network, String iface,
   2194             Collection<InetAddress> dnses, String domains) {
   2195         boolean changed = false;
   2196         int last = 0;
   2197         if (dnses.size() == 0 && mDefaultDns != null) {
   2198             ++last;
   2199             String value = mDefaultDns.getHostAddress();
   2200             if (!value.equals(SystemProperties.get("net.dns1"))) {
   2201                 if (DBG) {
   2202                     loge("no dns provided for " + network + " - using " + value);
   2203                 }
   2204                 changed = true;
   2205                 SystemProperties.set("net.dns1", value);
   2206             }
   2207         } else {
   2208             for (InetAddress dns : dnses) {
   2209                 ++last;
   2210                 String key = "net.dns" + last;
   2211                 String value = dns.getHostAddress();
   2212                 if (!changed && value.equals(SystemProperties.get(key))) {
   2213                     continue;
   2214                 }
   2215                 if (VDBG) {
   2216                     log("adding dns " + value + " for " + network);
   2217                 }
   2218                 changed = true;
   2219                 SystemProperties.set(key, value);
   2220             }
   2221         }
   2222         for (int i = last + 1; i <= mNumDnsEntries; ++i) {
   2223             String key = "net.dns" + i;
   2224             if (VDBG) log("erasing " + key);
   2225             changed = true;
   2226             SystemProperties.set(key, "");
   2227         }
   2228         mNumDnsEntries = last;
   2229 
   2230         if (changed) {
   2231             try {
   2232                 mNetd.setDnsServersForInterface(iface, NetworkUtils.makeStrings(dnses));
   2233                 mNetd.setDefaultInterfaceForDns(iface);
   2234             } catch (Exception e) {
   2235                 if (DBG) loge("exception setting default dns interface: " + e);
   2236             }
   2237         }
   2238         if (!domains.equals(SystemProperties.get("net.dns.search"))) {
   2239             SystemProperties.set("net.dns.search", domains);
   2240             changed = true;
   2241         }
   2242         return changed;
   2243     }
   2244 
   2245     private void handleDnsConfigurationChange(int netType) {
   2246         // add default net's dns entries
   2247         NetworkStateTracker nt = mNetTrackers[netType];
   2248         if (nt != null && nt.getNetworkInfo().isConnected() && !nt.isTeardownRequested()) {
   2249             LinkProperties p = nt.getLinkProperties();
   2250             if (p == null) return;
   2251             Collection<InetAddress> dnses = p.getDnses();
   2252             boolean changed = false;
   2253             if (mNetConfigs[netType].isDefault()) {
   2254                 String network = nt.getNetworkInfo().getTypeName();
   2255                 synchronized (mDnsLock) {
   2256                     if (!mDnsOverridden) {
   2257                         changed = updateDns(network, p.getInterfaceName(), dnses, "");
   2258                     }
   2259                 }
   2260             } else {
   2261                 try {
   2262                     mNetd.setDnsServersForInterface(p.getInterfaceName(),
   2263                             NetworkUtils.makeStrings(dnses));
   2264                 } catch (Exception e) {
   2265                     if (DBG) loge("exception setting dns servers: " + e);
   2266                 }
   2267                 // set per-pid dns for attached secondary nets
   2268                 List pids = mNetRequestersPids[netType];
   2269                 for (int y=0; y< pids.size(); y++) {
   2270                     Integer pid = (Integer)pids.get(y);
   2271                     changed = writePidDns(dnses, pid.intValue());
   2272                 }
   2273             }
   2274             if (changed) bumpDns();
   2275         }
   2276     }
   2277 
   2278     private int getRestoreDefaultNetworkDelay(int networkType) {
   2279         String restoreDefaultNetworkDelayStr = SystemProperties.get(
   2280                 NETWORK_RESTORE_DELAY_PROP_NAME);
   2281         if(restoreDefaultNetworkDelayStr != null &&
   2282                 restoreDefaultNetworkDelayStr.length() != 0) {
   2283             try {
   2284                 return Integer.valueOf(restoreDefaultNetworkDelayStr);
   2285             } catch (NumberFormatException e) {
   2286             }
   2287         }
   2288         // if the system property isn't set, use the value for the apn type
   2289         int ret = RESTORE_DEFAULT_NETWORK_DELAY;
   2290 
   2291         if ((networkType <= ConnectivityManager.MAX_NETWORK_TYPE) &&
   2292                 (mNetConfigs[networkType] != null)) {
   2293             ret = mNetConfigs[networkType].restoreTime;
   2294         }
   2295         return ret;
   2296     }
   2297 
   2298     @Override
   2299     protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
   2300         if (mContext.checkCallingOrSelfPermission(
   2301                 android.Manifest.permission.DUMP)
   2302                 != PackageManager.PERMISSION_GRANTED) {
   2303             pw.println("Permission Denial: can't dump ConnectivityService " +
   2304                     "from from pid=" + Binder.getCallingPid() + ", uid=" +
   2305                     Binder.getCallingUid());
   2306             return;
   2307         }
   2308         pw.println();
   2309         for (NetworkStateTracker nst : mNetTrackers) {
   2310             if (nst != null) {
   2311                 if (nst.getNetworkInfo().isConnected()) {
   2312                     pw.println("Active network: " + nst.getNetworkInfo().
   2313                             getTypeName());
   2314                 }
   2315                 pw.println(nst.getNetworkInfo());
   2316                 pw.println(nst);
   2317                 pw.println();
   2318             }
   2319         }
   2320 
   2321         pw.println("Network Requester Pids:");
   2322         for (int net : mPriorityList) {
   2323             String pidString = net + ": ";
   2324             for (Object pid : mNetRequestersPids[net]) {
   2325                 pidString = pidString + pid.toString() + ", ";
   2326             }
   2327             pw.println(pidString);
   2328         }
   2329         pw.println();
   2330 
   2331         pw.println("FeatureUsers:");
   2332         for (Object requester : mFeatureUsers) {
   2333             pw.println(requester.toString());
   2334         }
   2335         pw.println();
   2336 
   2337         synchronized (this) {
   2338             pw.println("NetworkTranstionWakeLock is currently " +
   2339                     (mNetTransitionWakeLock.isHeld() ? "" : "not ") + "held.");
   2340             pw.println("It was last requested for "+mNetTransitionWakeLockCausedBy);
   2341         }
   2342         pw.println();
   2343 
   2344         mTethering.dump(fd, pw, args);
   2345 
   2346         if (mInetLog != null) {
   2347             pw.println();
   2348             pw.println("Inet condition reports:");
   2349             for(int i = 0; i < mInetLog.size(); i++) {
   2350                 pw.println(mInetLog.get(i));
   2351             }
   2352         }
   2353     }
   2354 
   2355     // must be stateless - things change under us.
   2356     private class MyHandler extends Handler {
   2357         public MyHandler(Looper looper) {
   2358             super(looper);
   2359         }
   2360 
   2361         @Override
   2362         public void handleMessage(Message msg) {
   2363             NetworkInfo info;
   2364             switch (msg.what) {
   2365                 case NetworkStateTracker.EVENT_STATE_CHANGED:
   2366                     info = (NetworkInfo) msg.obj;
   2367                     int type = info.getType();
   2368                     NetworkInfo.State state = info.getState();
   2369 
   2370                     if (VDBG || (state == NetworkInfo.State.CONNECTED) ||
   2371                             (state == NetworkInfo.State.DISCONNECTED)) {
   2372                         log("ConnectivityChange for " +
   2373                             info.getTypeName() + ": " +
   2374                             state + "/" + info.getDetailedState());
   2375                     }
   2376 
   2377                     // Connectivity state changed:
   2378                     // [31-13] Reserved for future use
   2379                     // [12-9] Network subtype (for mobile network, as defined
   2380                     //         by TelephonyManager)
   2381                     // [8-3] Detailed state ordinal (as defined by
   2382                     //         NetworkInfo.DetailedState)
   2383                     // [2-0] Network type (as defined by ConnectivityManager)
   2384                     int eventLogParam = (info.getType() & 0x7) |
   2385                             ((info.getDetailedState().ordinal() & 0x3f) << 3) |
   2386                             (info.getSubtype() << 9);
   2387                     EventLog.writeEvent(EventLogTags.CONNECTIVITY_STATE_CHANGED,
   2388                             eventLogParam);
   2389 
   2390                     if (info.getDetailedState() ==
   2391                             NetworkInfo.DetailedState.FAILED) {
   2392                         handleConnectionFailure(info);
   2393                     } else if (state == NetworkInfo.State.DISCONNECTED) {
   2394                         handleDisconnect(info);
   2395                     } else if (state == NetworkInfo.State.SUSPENDED) {
   2396                         // TODO: need to think this over.
   2397                         // the logic here is, handle SUSPENDED the same as
   2398                         // DISCONNECTED. The only difference being we are
   2399                         // broadcasting an intent with NetworkInfo that's
   2400                         // suspended. This allows the applications an
   2401                         // opportunity to handle DISCONNECTED and SUSPENDED
   2402                         // differently, or not.
   2403                         handleDisconnect(info);
   2404                     } else if (state == NetworkInfo.State.CONNECTED) {
   2405                         handleConnect(info);
   2406                     }
   2407                     break;
   2408                 case NetworkStateTracker.EVENT_CONFIGURATION_CHANGED:
   2409                     info = (NetworkInfo) msg.obj;
   2410                     // TODO: Temporary allowing network configuration
   2411                     //       change not resetting sockets.
   2412                     //       @see bug/4455071
   2413                     handleConnectivityChange(info.getType(), false);
   2414                     break;
   2415                 case EVENT_CLEAR_NET_TRANSITION_WAKELOCK:
   2416                     String causedBy = null;
   2417                     synchronized (ConnectivityService.this) {
   2418                         if (msg.arg1 == mNetTransitionWakeLockSerialNumber &&
   2419                                 mNetTransitionWakeLock.isHeld()) {
   2420                             mNetTransitionWakeLock.release();
   2421                             causedBy = mNetTransitionWakeLockCausedBy;
   2422                         }
   2423                     }
   2424                     if (causedBy != null) {
   2425                         log("NetTransition Wakelock for " + causedBy + " released by timeout");
   2426                     }
   2427                     break;
   2428                 case EVENT_RESTORE_DEFAULT_NETWORK:
   2429                     FeatureUser u = (FeatureUser)msg.obj;
   2430                     u.expire();
   2431                     break;
   2432                 case EVENT_INET_CONDITION_CHANGE:
   2433                 {
   2434                     int netType = msg.arg1;
   2435                     int condition = msg.arg2;
   2436                     handleInetConditionChange(netType, condition);
   2437                     break;
   2438                 }
   2439                 case EVENT_INET_CONDITION_HOLD_END:
   2440                 {
   2441                     int netType = msg.arg1;
   2442                     int sequence = msg.arg2;
   2443                     handleInetConditionHoldEnd(netType, sequence);
   2444                     break;
   2445                 }
   2446                 case EVENT_SET_NETWORK_PREFERENCE:
   2447                 {
   2448                     int preference = msg.arg1;
   2449                     handleSetNetworkPreference(preference);
   2450                     break;
   2451                 }
   2452                 case EVENT_SET_MOBILE_DATA:
   2453                 {
   2454                     boolean enabled = (msg.arg1 == ENABLED);
   2455                     handleSetMobileData(enabled);
   2456                     break;
   2457                 }
   2458                 case EVENT_APPLY_GLOBAL_HTTP_PROXY:
   2459                 {
   2460                     handleDeprecatedGlobalHttpProxy();
   2461                     break;
   2462                 }
   2463                 case EVENT_SET_DEPENDENCY_MET:
   2464                 {
   2465                     boolean met = (msg.arg1 == ENABLED);
   2466                     handleSetDependencyMet(msg.arg2, met);
   2467                     break;
   2468                 }
   2469                 case EVENT_RESTORE_DNS:
   2470                 {
   2471                     if (mActiveDefaultNetwork != -1) {
   2472                         handleDnsConfigurationChange(mActiveDefaultNetwork);
   2473                     }
   2474                     break;
   2475                 }
   2476                 case EVENT_SEND_STICKY_BROADCAST_INTENT:
   2477                 {
   2478                     Intent intent = (Intent)msg.obj;
   2479                     sendStickyBroadcast(intent);
   2480                     break;
   2481                 }
   2482                 case EVENT_SET_POLICY_DATA_ENABLE: {
   2483                     final int networkType = msg.arg1;
   2484                     final boolean enabled = msg.arg2 == ENABLED;
   2485                     handleSetPolicyDataEnable(networkType, enabled);
   2486                 }
   2487             }
   2488         }
   2489     }
   2490 
   2491     // javadoc from interface
   2492     public int tether(String iface) {
   2493         enforceTetherChangePermission();
   2494 
   2495         if (isTetheringSupported()) {
   2496             return mTethering.tether(iface);
   2497         } else {
   2498             return ConnectivityManager.TETHER_ERROR_UNSUPPORTED;
   2499         }
   2500     }
   2501 
   2502     // javadoc from interface
   2503     public int untether(String iface) {
   2504         enforceTetherChangePermission();
   2505 
   2506         if (isTetheringSupported()) {
   2507             return mTethering.untether(iface);
   2508         } else {
   2509             return ConnectivityManager.TETHER_ERROR_UNSUPPORTED;
   2510         }
   2511     }
   2512 
   2513     // javadoc from interface
   2514     public int getLastTetherError(String iface) {
   2515         enforceTetherAccessPermission();
   2516 
   2517         if (isTetheringSupported()) {
   2518             return mTethering.getLastTetherError(iface);
   2519         } else {
   2520             return ConnectivityManager.TETHER_ERROR_UNSUPPORTED;
   2521         }
   2522     }
   2523 
   2524     // TODO - proper iface API for selection by property, inspection, etc
   2525     public String[] getTetherableUsbRegexs() {
   2526         enforceTetherAccessPermission();
   2527         if (isTetheringSupported()) {
   2528             return mTethering.getTetherableUsbRegexs();
   2529         } else {
   2530             return new String[0];
   2531         }
   2532     }
   2533 
   2534     public String[] getTetherableWifiRegexs() {
   2535         enforceTetherAccessPermission();
   2536         if (isTetheringSupported()) {
   2537             return mTethering.getTetherableWifiRegexs();
   2538         } else {
   2539             return new String[0];
   2540         }
   2541     }
   2542 
   2543     public String[] getTetherableBluetoothRegexs() {
   2544         enforceTetherAccessPermission();
   2545         if (isTetheringSupported()) {
   2546             return mTethering.getTetherableBluetoothRegexs();
   2547         } else {
   2548             return new String[0];
   2549         }
   2550     }
   2551 
   2552     public int setUsbTethering(boolean enable) {
   2553         enforceTetherAccessPermission();
   2554         if (isTetheringSupported()) {
   2555             return mTethering.setUsbTethering(enable);
   2556         } else {
   2557             return ConnectivityManager.TETHER_ERROR_UNSUPPORTED;
   2558         }
   2559     }
   2560 
   2561     // TODO - move iface listing, queries, etc to new module
   2562     // javadoc from interface
   2563     public String[] getTetherableIfaces() {
   2564         enforceTetherAccessPermission();
   2565         return mTethering.getTetherableIfaces();
   2566     }
   2567 
   2568     public String[] getTetheredIfaces() {
   2569         enforceTetherAccessPermission();
   2570         return mTethering.getTetheredIfaces();
   2571     }
   2572 
   2573     @Override
   2574     public String[] getTetheredIfacePairs() {
   2575         enforceTetherAccessPermission();
   2576         return mTethering.getTetheredIfacePairs();
   2577     }
   2578 
   2579     public String[] getTetheringErroredIfaces() {
   2580         enforceTetherAccessPermission();
   2581         return mTethering.getErroredIfaces();
   2582     }
   2583 
   2584     // if ro.tether.denied = true we default to no tethering
   2585     // gservices could set the secure setting to 1 though to enable it on a build where it
   2586     // had previously been turned off.
   2587     public boolean isTetheringSupported() {
   2588         enforceTetherAccessPermission();
   2589         int defaultVal = (SystemProperties.get("ro.tether.denied").equals("true") ? 0 : 1);
   2590         boolean tetherEnabledInSettings = (Settings.Secure.getInt(mContext.getContentResolver(),
   2591                 Settings.Secure.TETHER_SUPPORTED, defaultVal) != 0);
   2592         return tetherEnabledInSettings && mTetheringConfigValid;
   2593     }
   2594 
   2595     // An API NetworkStateTrackers can call when they lose their network.
   2596     // This will automatically be cleared after X seconds or a network becomes CONNECTED,
   2597     // whichever happens first.  The timer is started by the first caller and not
   2598     // restarted by subsequent callers.
   2599     public void requestNetworkTransitionWakelock(String forWhom) {
   2600         enforceConnectivityInternalPermission();
   2601         synchronized (this) {
   2602             if (mNetTransitionWakeLock.isHeld()) return;
   2603             mNetTransitionWakeLockSerialNumber++;
   2604             mNetTransitionWakeLock.acquire();
   2605             mNetTransitionWakeLockCausedBy = forWhom;
   2606         }
   2607         mHandler.sendMessageDelayed(mHandler.obtainMessage(
   2608                 EVENT_CLEAR_NET_TRANSITION_WAKELOCK,
   2609                 mNetTransitionWakeLockSerialNumber, 0),
   2610                 mNetTransitionWakeLockTimeout);
   2611         return;
   2612     }
   2613 
   2614     // 100 percent is full good, 0 is full bad.
   2615     public void reportInetCondition(int networkType, int percentage) {
   2616         if (VDBG) log("reportNetworkCondition(" + networkType + ", " + percentage + ")");
   2617         mContext.enforceCallingOrSelfPermission(
   2618                 android.Manifest.permission.STATUS_BAR,
   2619                 "ConnectivityService");
   2620 
   2621         if (DBG) {
   2622             int pid = getCallingPid();
   2623             int uid = getCallingUid();
   2624             String s = pid + "(" + uid + ") reports inet is " +
   2625                 (percentage > 50 ? "connected" : "disconnected") + " (" + percentage + ") on " +
   2626                 "network Type " + networkType + " at " + GregorianCalendar.getInstance().getTime();
   2627             mInetLog.add(s);
   2628             while(mInetLog.size() > INET_CONDITION_LOG_MAX_SIZE) {
   2629                 mInetLog.remove(0);
   2630             }
   2631         }
   2632         mHandler.sendMessage(mHandler.obtainMessage(
   2633             EVENT_INET_CONDITION_CHANGE, networkType, percentage));
   2634     }
   2635 
   2636     private void handleInetConditionChange(int netType, int condition) {
   2637         if (mActiveDefaultNetwork == -1) {
   2638             if (DBG) log("handleInetConditionChange: no active default network - ignore");
   2639             return;
   2640         }
   2641         if (mActiveDefaultNetwork != netType) {
   2642             if (DBG) log("handleInetConditionChange: net=" + netType +
   2643                             " != default=" + mActiveDefaultNetwork + " - ignore");
   2644             return;
   2645         }
   2646         if (VDBG) {
   2647             log("handleInetConditionChange: net=" +
   2648                     netType + ", condition=" + condition +
   2649                     ",mActiveDefaultNetwork=" + mActiveDefaultNetwork);
   2650         }
   2651         mDefaultInetCondition = condition;
   2652         int delay;
   2653         if (mInetConditionChangeInFlight == false) {
   2654             if (VDBG) log("handleInetConditionChange: starting a change hold");
   2655             // setup a new hold to debounce this
   2656             if (mDefaultInetCondition > 50) {
   2657                 delay = Settings.Secure.getInt(mContext.getContentResolver(),
   2658                         Settings.Secure.INET_CONDITION_DEBOUNCE_UP_DELAY, 500);
   2659             } else {
   2660                 delay = Settings.Secure.getInt(mContext.getContentResolver(),
   2661                 Settings.Secure.INET_CONDITION_DEBOUNCE_DOWN_DELAY, 3000);
   2662             }
   2663             mInetConditionChangeInFlight = true;
   2664             mHandler.sendMessageDelayed(mHandler.obtainMessage(EVENT_INET_CONDITION_HOLD_END,
   2665                     mActiveDefaultNetwork, mDefaultConnectionSequence), delay);
   2666         } else {
   2667             // we've set the new condition, when this hold ends that will get picked up
   2668             if (VDBG) log("handleInetConditionChange: currently in hold - not setting new end evt");
   2669         }
   2670     }
   2671 
   2672     private void handleInetConditionHoldEnd(int netType, int sequence) {
   2673         if (DBG) {
   2674             log("handleInetConditionHoldEnd: net=" + netType +
   2675                     ", condition=" + mDefaultInetCondition +
   2676                     ", published condition=" + mDefaultInetConditionPublished);
   2677         }
   2678         mInetConditionChangeInFlight = false;
   2679 
   2680         if (mActiveDefaultNetwork == -1) {
   2681             if (DBG) log("handleInetConditionHoldEnd: no active default network - ignoring");
   2682             return;
   2683         }
   2684         if (mDefaultConnectionSequence != sequence) {
   2685             if (DBG) log("handleInetConditionHoldEnd: event hold for obsolete network - ignoring");
   2686             return;
   2687         }
   2688         // TODO: Figure out why this optimization sometimes causes a
   2689         //       change in mDefaultInetCondition to be missed and the
   2690         //       UI to not be updated.
   2691         //if (mDefaultInetConditionPublished == mDefaultInetCondition) {
   2692         //    if (DBG) log("no change in condition - aborting");
   2693         //    return;
   2694         //}
   2695         NetworkInfo networkInfo = mNetTrackers[mActiveDefaultNetwork].getNetworkInfo();
   2696         if (networkInfo.isConnected() == false) {
   2697             if (DBG) log("handleInetConditionHoldEnd: default network not connected - ignoring");
   2698             return;
   2699         }
   2700         mDefaultInetConditionPublished = mDefaultInetCondition;
   2701         sendInetConditionBroadcast(networkInfo);
   2702         return;
   2703     }
   2704 
   2705     public ProxyProperties getProxy() {
   2706         synchronized (mDefaultProxyLock) {
   2707             return mDefaultProxyDisabled ? null : mDefaultProxy;
   2708         }
   2709     }
   2710 
   2711     public void setGlobalProxy(ProxyProperties proxyProperties) {
   2712         enforceChangePermission();
   2713         synchronized (mGlobalProxyLock) {
   2714             if (proxyProperties == mGlobalProxy) return;
   2715             if (proxyProperties != null && proxyProperties.equals(mGlobalProxy)) return;
   2716             if (mGlobalProxy != null && mGlobalProxy.equals(proxyProperties)) return;
   2717 
   2718             String host = "";
   2719             int port = 0;
   2720             String exclList = "";
   2721             if (proxyProperties != null && !TextUtils.isEmpty(proxyProperties.getHost())) {
   2722                 mGlobalProxy = new ProxyProperties(proxyProperties);
   2723                 host = mGlobalProxy.getHost();
   2724                 port = mGlobalProxy.getPort();
   2725                 exclList = mGlobalProxy.getExclusionList();
   2726             } else {
   2727                 mGlobalProxy = null;
   2728             }
   2729             ContentResolver res = mContext.getContentResolver();
   2730             Settings.Secure.putString(res, Settings.Secure.GLOBAL_HTTP_PROXY_HOST, host);
   2731             Settings.Secure.putInt(res, Settings.Secure.GLOBAL_HTTP_PROXY_PORT, port);
   2732             Settings.Secure.putString(res, Settings.Secure.GLOBAL_HTTP_PROXY_EXCLUSION_LIST,
   2733                     exclList);
   2734         }
   2735 
   2736         if (mGlobalProxy == null) {
   2737             proxyProperties = mDefaultProxy;
   2738         }
   2739         //sendProxyBroadcast(proxyProperties);
   2740     }
   2741 
   2742     private void loadGlobalProxy() {
   2743         ContentResolver res = mContext.getContentResolver();
   2744         String host = Settings.Secure.getString(res, Settings.Secure.GLOBAL_HTTP_PROXY_HOST);
   2745         int port = Settings.Secure.getInt(res, Settings.Secure.GLOBAL_HTTP_PROXY_PORT, 0);
   2746         String exclList = Settings.Secure.getString(res,
   2747                 Settings.Secure.GLOBAL_HTTP_PROXY_EXCLUSION_LIST);
   2748         if (!TextUtils.isEmpty(host)) {
   2749             ProxyProperties proxyProperties = new ProxyProperties(host, port, exclList);
   2750             synchronized (mGlobalProxyLock) {
   2751                 mGlobalProxy = proxyProperties;
   2752             }
   2753         }
   2754     }
   2755 
   2756     public ProxyProperties getGlobalProxy() {
   2757         synchronized (mGlobalProxyLock) {
   2758             return mGlobalProxy;
   2759         }
   2760     }
   2761 
   2762     private void handleApplyDefaultProxy(ProxyProperties proxy) {
   2763         if (proxy != null && TextUtils.isEmpty(proxy.getHost())) {
   2764             proxy = null;
   2765         }
   2766         synchronized (mDefaultProxyLock) {
   2767             if (mDefaultProxy != null && mDefaultProxy.equals(proxy)) return;
   2768             if (mDefaultProxy == proxy) return;
   2769             mDefaultProxy = proxy;
   2770 
   2771             if (!mDefaultProxyDisabled) {
   2772                 sendProxyBroadcast(proxy);
   2773             }
   2774         }
   2775     }
   2776 
   2777     private void handleDeprecatedGlobalHttpProxy() {
   2778         String proxy = Settings.Secure.getString(mContext.getContentResolver(),
   2779                 Settings.Secure.HTTP_PROXY);
   2780         if (!TextUtils.isEmpty(proxy)) {
   2781             String data[] = proxy.split(":");
   2782             String proxyHost =  data[0];
   2783             int proxyPort = 8080;
   2784             if (data.length > 1) {
   2785                 try {
   2786                     proxyPort = Integer.parseInt(data[1]);
   2787                 } catch (NumberFormatException e) {
   2788                     return;
   2789                 }
   2790             }
   2791             ProxyProperties p = new ProxyProperties(data[0], proxyPort, "");
   2792             setGlobalProxy(p);
   2793         }
   2794     }
   2795 
   2796     private void sendProxyBroadcast(ProxyProperties proxy) {
   2797         if (proxy == null) proxy = new ProxyProperties("", 0, "");
   2798         if (DBG) log("sending Proxy Broadcast for " + proxy);
   2799         Intent intent = new Intent(Proxy.PROXY_CHANGE_ACTION);
   2800         intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING |
   2801             Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
   2802         intent.putExtra(Proxy.EXTRA_PROXY_INFO, proxy);
   2803         mContext.sendStickyBroadcast(intent);
   2804     }
   2805 
   2806     private static class SettingsObserver extends ContentObserver {
   2807         private int mWhat;
   2808         private Handler mHandler;
   2809         SettingsObserver(Handler handler, int what) {
   2810             super(handler);
   2811             mHandler = handler;
   2812             mWhat = what;
   2813         }
   2814 
   2815         void observe(Context context) {
   2816             ContentResolver resolver = context.getContentResolver();
   2817             resolver.registerContentObserver(Settings.Secure.getUriFor(
   2818                     Settings.Secure.HTTP_PROXY), false, this);
   2819         }
   2820 
   2821         @Override
   2822         public void onChange(boolean selfChange) {
   2823             mHandler.obtainMessage(mWhat).sendToTarget();
   2824         }
   2825     }
   2826 
   2827     private void log(String s) {
   2828         Slog.d(TAG, s);
   2829     }
   2830 
   2831     private void loge(String s) {
   2832         Slog.e(TAG, s);
   2833     }
   2834 
   2835     int convertFeatureToNetworkType(int networkType, String feature) {
   2836         int usedNetworkType = networkType;
   2837 
   2838         if(networkType == ConnectivityManager.TYPE_MOBILE) {
   2839             if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_MMS)) {
   2840                 usedNetworkType = ConnectivityManager.TYPE_MOBILE_MMS;
   2841             } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_SUPL)) {
   2842                 usedNetworkType = ConnectivityManager.TYPE_MOBILE_SUPL;
   2843             } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_DUN) ||
   2844                     TextUtils.equals(feature, Phone.FEATURE_ENABLE_DUN_ALWAYS)) {
   2845                 usedNetworkType = ConnectivityManager.TYPE_MOBILE_DUN;
   2846             } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_HIPRI)) {
   2847                 usedNetworkType = ConnectivityManager.TYPE_MOBILE_HIPRI;
   2848             } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_FOTA)) {
   2849                 usedNetworkType = ConnectivityManager.TYPE_MOBILE_FOTA;
   2850             } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_IMS)) {
   2851                 usedNetworkType = ConnectivityManager.TYPE_MOBILE_IMS;
   2852             } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_CBS)) {
   2853                 usedNetworkType = ConnectivityManager.TYPE_MOBILE_CBS;
   2854             } else {
   2855                 Slog.e(TAG, "Can't match any mobile netTracker!");
   2856             }
   2857         } else if (networkType == ConnectivityManager.TYPE_WIFI) {
   2858             if (TextUtils.equals(feature, "p2p")) {
   2859                 usedNetworkType = ConnectivityManager.TYPE_WIFI_P2P;
   2860             } else {
   2861                 Slog.e(TAG, "Can't match any wifi netTracker!");
   2862             }
   2863         } else {
   2864             Slog.e(TAG, "Unexpected network type");
   2865         }
   2866         return usedNetworkType;
   2867     }
   2868 
   2869     private static <T> T checkNotNull(T value, String message) {
   2870         if (value == null) {
   2871             throw new NullPointerException(message);
   2872         }
   2873         return value;
   2874     }
   2875 
   2876     /**
   2877      * Protect a socket from VPN routing rules. This method is used by
   2878      * VpnBuilder and not available in ConnectivityManager. Permissions
   2879      * are checked in Vpn class.
   2880      * @hide
   2881      */
   2882     @Override
   2883     public boolean protectVpn(ParcelFileDescriptor socket) {
   2884         try {
   2885             int type = mActiveDefaultNetwork;
   2886             if (ConnectivityManager.isNetworkTypeValid(type)) {
   2887                 mVpn.protect(socket, mNetTrackers[type].getLinkProperties().getInterfaceName());
   2888                 return true;
   2889             }
   2890         } catch (Exception e) {
   2891             // ignore
   2892         } finally {
   2893             try {
   2894                 socket.close();
   2895             } catch (Exception e) {
   2896                 // ignore
   2897             }
   2898         }
   2899         return false;
   2900     }
   2901 
   2902     /**
   2903      * Prepare for a VPN application. This method is used by VpnDialogs
   2904      * and not available in ConnectivityManager. Permissions are checked
   2905      * in Vpn class.
   2906      * @hide
   2907      */
   2908     @Override
   2909     public boolean prepareVpn(String oldPackage, String newPackage) {
   2910         return mVpn.prepare(oldPackage, newPackage);
   2911     }
   2912 
   2913     /**
   2914      * Configure a TUN interface and return its file descriptor. Parameters
   2915      * are encoded and opaque to this class. This method is used by VpnBuilder
   2916      * and not available in ConnectivityManager. Permissions are checked in
   2917      * Vpn class.
   2918      * @hide
   2919      */
   2920     @Override
   2921     public ParcelFileDescriptor establishVpn(VpnConfig config) {
   2922         return mVpn.establish(config);
   2923     }
   2924 
   2925     /**
   2926      * Start legacy VPN and return an intent to VpnDialogs. This method is
   2927      * used by VpnSettings and not available in ConnectivityManager.
   2928      * Permissions are checked in Vpn class.
   2929      * @hide
   2930      */
   2931     @Override
   2932     public void startLegacyVpn(VpnConfig config, String[] racoon, String[] mtpd) {
   2933         mVpn.startLegacyVpn(config, racoon, mtpd);
   2934     }
   2935 
   2936     /**
   2937      * Return the information of the ongoing legacy VPN. This method is used
   2938      * by VpnSettings and not available in ConnectivityManager. Permissions
   2939      * are checked in Vpn class.
   2940      * @hide
   2941      */
   2942     @Override
   2943     public LegacyVpnInfo getLegacyVpnInfo() {
   2944         return mVpn.getLegacyVpnInfo();
   2945     }
   2946 
   2947     /**
   2948      * Callback for VPN subsystem. Currently VPN is not adapted to the service
   2949      * through NetworkStateTracker since it works differently. For example, it
   2950      * needs to override DNS servers but never takes the default routes. It
   2951      * relies on another data network, and it could keep existing connections
   2952      * alive after reconnecting, switching between networks, or even resuming
   2953      * from deep sleep. Calls from applications should be done synchronously
   2954      * to avoid race conditions. As these are all hidden APIs, refactoring can
   2955      * be done whenever a better abstraction is developed.
   2956      */
   2957     public class VpnCallback {
   2958 
   2959         private VpnCallback() {
   2960         }
   2961 
   2962         public void override(List<String> dnsServers, List<String> searchDomains) {
   2963             if (dnsServers == null) {
   2964                 restore();
   2965                 return;
   2966             }
   2967 
   2968             // Convert DNS servers into addresses.
   2969             List<InetAddress> addresses = new ArrayList<InetAddress>();
   2970             for (String address : dnsServers) {
   2971                 // Double check the addresses and remove invalid ones.
   2972                 try {
   2973                     addresses.add(InetAddress.parseNumericAddress(address));
   2974                 } catch (Exception e) {
   2975                     // ignore
   2976                 }
   2977             }
   2978             if (addresses.isEmpty()) {
   2979                 restore();
   2980                 return;
   2981             }
   2982 
   2983             // Concatenate search domains into a string.
   2984             StringBuilder buffer = new StringBuilder();
   2985             if (searchDomains != null) {
   2986                 for (String domain : searchDomains) {
   2987                     buffer.append(domain).append(' ');
   2988                 }
   2989             }
   2990             String domains = buffer.toString().trim();
   2991 
   2992             // Apply DNS changes.
   2993             boolean changed = false;
   2994             synchronized (mDnsLock) {
   2995                 changed = updateDns("VPN", "VPN", addresses, domains);
   2996                 mDnsOverridden = true;
   2997             }
   2998             if (changed) {
   2999                 bumpDns();
   3000             }
   3001 
   3002             // Temporarily disable the default proxy.
   3003             synchronized (mDefaultProxyLock) {
   3004                 mDefaultProxyDisabled = true;
   3005                 if (mDefaultProxy != null) {
   3006                     sendProxyBroadcast(null);
   3007                 }
   3008             }
   3009 
   3010             // TODO: support proxy per network.
   3011         }
   3012 
   3013         public void restore() {
   3014             synchronized (mDnsLock) {
   3015                 if (mDnsOverridden) {
   3016                     mDnsOverridden = false;
   3017                     mHandler.sendEmptyMessage(EVENT_RESTORE_DNS);
   3018                 }
   3019             }
   3020             synchronized (mDefaultProxyLock) {
   3021                 mDefaultProxyDisabled = false;
   3022                 if (mDefaultProxy != null) {
   3023                     sendProxyBroadcast(mDefaultProxy);
   3024                 }
   3025             }
   3026         }
   3027     }
   3028 }
   3029