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