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 android.app.Notification;
     20 import android.app.NotificationManager;
     21 import android.content.ContentResolver;
     22 import android.content.Context;
     23 import android.content.Intent;
     24 import android.content.pm.PackageManager;
     25 import android.net.ConnectivityManager;
     26 import android.net.IConnectivityManager;
     27 import android.net.MobileDataStateTracker;
     28 import android.net.NetworkInfo;
     29 import android.net.NetworkStateTracker;
     30 import android.net.wifi.WifiStateTracker;
     31 import android.os.Binder;
     32 import android.os.Handler;
     33 import android.os.IBinder;
     34 import android.os.Looper;
     35 import android.os.Message;
     36 import android.os.RemoteException;
     37 import android.os.ServiceManager;
     38 import android.os.SystemProperties;
     39 import android.provider.Settings;
     40 import android.text.TextUtils;
     41 import android.util.EventLog;
     42 import android.util.Slog;
     43 
     44 import com.android.internal.telephony.Phone;
     45 
     46 import com.android.server.connectivity.Tethering;
     47 
     48 import java.io.FileDescriptor;
     49 import java.io.PrintWriter;
     50 import java.util.ArrayList;
     51 import java.util.List;
     52 
     53 /**
     54  * @hide
     55  */
     56 public class ConnectivityService extends IConnectivityManager.Stub {
     57 
     58     private static final boolean DBG = true;
     59     private static final String TAG = "ConnectivityService";
     60 
     61     // how long to wait before switching back to a radio's default network
     62     private static final int RESTORE_DEFAULT_NETWORK_DELAY = 1 * 60 * 1000;
     63     // system property that can override the above value
     64     private static final String NETWORK_RESTORE_DELAY_PROP_NAME =
     65             "android.telephony.apn-restore";
     66 
     67 
     68     private Tethering mTethering;
     69     private boolean mTetheringConfigValid = false;
     70 
     71     /**
     72      * Sometimes we want to refer to the individual network state
     73      * trackers separately, and sometimes we just want to treat them
     74      * abstractly.
     75      */
     76     private NetworkStateTracker mNetTrackers[];
     77 
     78     /**
     79      * A per Net list of the PID's that requested access to the net
     80      * used both as a refcount and for per-PID DNS selection
     81      */
     82     private List mNetRequestersPids[];
     83 
     84     // priority order of the nettrackers
     85     // (excluding dynamically set mNetworkPreference)
     86     // TODO - move mNetworkTypePreference into this
     87     private int[] mPriorityList;
     88 
     89     private Context mContext;
     90     private int mNetworkPreference;
     91     private int mActiveDefaultNetwork = -1;
     92 
     93     private int mNumDnsEntries;
     94 
     95     private boolean mTestMode;
     96     private static ConnectivityService sServiceInstance;
     97 
     98     private Handler mHandler;
     99 
    100     // list of DeathRecipients used to make sure features are turned off when
    101     // a process dies
    102     private List mFeatureUsers;
    103 
    104     private boolean mSystemReady;
    105     private Intent mInitialBroadcast;
    106 
    107     private static class NetworkAttributes {
    108         /**
    109          * Class for holding settings read from resources.
    110          */
    111         public String mName;
    112         public int mType;
    113         public int mRadio;
    114         public int mPriority;
    115         public NetworkInfo.State mLastState;
    116         public NetworkAttributes(String init) {
    117             String fragments[] = init.split(",");
    118             mName = fragments[0].toLowerCase();
    119             mType = Integer.parseInt(fragments[1]);
    120             mRadio = Integer.parseInt(fragments[2]);
    121             mPriority = Integer.parseInt(fragments[3]);
    122             mLastState = NetworkInfo.State.UNKNOWN;
    123         }
    124         public boolean isDefault() {
    125             return (mType == mRadio);
    126         }
    127     }
    128     NetworkAttributes[] mNetAttributes;
    129     int mNetworksDefined;
    130 
    131     private static class RadioAttributes {
    132         public int mSimultaneity;
    133         public int mType;
    134         public RadioAttributes(String init) {
    135             String fragments[] = init.split(",");
    136             mType = Integer.parseInt(fragments[0]);
    137             mSimultaneity = Integer.parseInt(fragments[1]);
    138         }
    139     }
    140     RadioAttributes[] mRadioAttributes;
    141 
    142     private static class ConnectivityThread extends Thread {
    143         private Context mContext;
    144 
    145         private ConnectivityThread(Context context) {
    146             super("ConnectivityThread");
    147             mContext = context;
    148         }
    149 
    150         @Override
    151         public void run() {
    152             Looper.prepare();
    153             synchronized (this) {
    154                 sServiceInstance = new ConnectivityService(mContext);
    155                 notifyAll();
    156             }
    157             Looper.loop();
    158         }
    159 
    160         public static ConnectivityService getServiceInstance(Context context) {
    161             ConnectivityThread thread = new ConnectivityThread(context);
    162             thread.start();
    163 
    164             synchronized (thread) {
    165                 while (sServiceInstance == null) {
    166                     try {
    167                         // Wait until sServiceInstance has been initialized.
    168                         thread.wait();
    169                     } catch (InterruptedException ignore) {
    170                         Slog.e(TAG,
    171                             "Unexpected InterruptedException while waiting"+
    172                             " for ConnectivityService thread");
    173                     }
    174                 }
    175             }
    176 
    177             return sServiceInstance;
    178         }
    179     }
    180 
    181     public static ConnectivityService getInstance(Context context) {
    182         return ConnectivityThread.getServiceInstance(context);
    183     }
    184 
    185     private ConnectivityService(Context context) {
    186         if (DBG) Slog.v(TAG, "ConnectivityService starting up");
    187 
    188         // setup our unique device name
    189         String id = Settings.Secure.getString(context.getContentResolver(),
    190                 Settings.Secure.ANDROID_ID);
    191         if (id != null && id.length() > 0) {
    192             String name = new String("android_").concat(id);
    193             SystemProperties.set("net.hostname", name);
    194         }
    195 
    196         mContext = context;
    197         mNetTrackers = new NetworkStateTracker[
    198                 ConnectivityManager.MAX_NETWORK_TYPE+1];
    199         mHandler = new MyHandler();
    200 
    201         mNetworkPreference = getPersistedNetworkPreference();
    202 
    203         mRadioAttributes = new RadioAttributes[ConnectivityManager.MAX_RADIO_TYPE+1];
    204         mNetAttributes = new NetworkAttributes[ConnectivityManager.MAX_NETWORK_TYPE+1];
    205 
    206         // Load device network attributes from resources
    207         String[] raStrings = context.getResources().getStringArray(
    208                 com.android.internal.R.array.radioAttributes);
    209         for (String raString : raStrings) {
    210             RadioAttributes r = new RadioAttributes(raString);
    211             if (r.mType > ConnectivityManager.MAX_RADIO_TYPE) {
    212                 Slog.e(TAG, "Error in radioAttributes - ignoring attempt to define type " + r.mType);
    213                 continue;
    214             }
    215             if (mRadioAttributes[r.mType] != null) {
    216                 Slog.e(TAG, "Error in radioAttributes - ignoring attempt to redefine type " +
    217                         r.mType);
    218                 continue;
    219             }
    220             mRadioAttributes[r.mType] = r;
    221         }
    222 
    223         String[] naStrings = context.getResources().getStringArray(
    224                 com.android.internal.R.array.networkAttributes);
    225         for (String naString : naStrings) {
    226             try {
    227                 NetworkAttributes n = new NetworkAttributes(naString);
    228                 if (n.mType > ConnectivityManager.MAX_NETWORK_TYPE) {
    229                     Slog.e(TAG, "Error in networkAttributes - ignoring attempt to define type " +
    230                             n.mType);
    231                     continue;
    232                 }
    233                 if (mNetAttributes[n.mType] != null) {
    234                     Slog.e(TAG, "Error in networkAttributes - ignoring attempt to redefine type " +
    235                             n.mType);
    236                     continue;
    237                 }
    238                 if (mRadioAttributes[n.mRadio] == null) {
    239                     Slog.e(TAG, "Error in networkAttributes - ignoring attempt to use undefined " +
    240                             "radio " + n.mRadio + " in network type " + n.mType);
    241                     continue;
    242                 }
    243                 mNetAttributes[n.mType] = n;
    244                 mNetworksDefined++;
    245             } catch(Exception e) {
    246                 // ignore it - leave the entry null
    247             }
    248         }
    249 
    250         // high priority first
    251         mPriorityList = new int[mNetworksDefined];
    252         {
    253             int insertionPoint = mNetworksDefined-1;
    254             int currentLowest = 0;
    255             int nextLowest = 0;
    256             while (insertionPoint > -1) {
    257                 for (NetworkAttributes na : mNetAttributes) {
    258                     if (na == null) continue;
    259                     if (na.mPriority < currentLowest) continue;
    260                     if (na.mPriority > currentLowest) {
    261                         if (na.mPriority < nextLowest || nextLowest == 0) {
    262                             nextLowest = na.mPriority;
    263                         }
    264                         continue;
    265                     }
    266                     mPriorityList[insertionPoint--] = na.mType;
    267                 }
    268                 currentLowest = nextLowest;
    269                 nextLowest = 0;
    270             }
    271         }
    272 
    273         mNetRequestersPids = new ArrayList[ConnectivityManager.MAX_NETWORK_TYPE+1];
    274         for (int i : mPriorityList) {
    275             mNetRequestersPids[i] = new ArrayList();
    276         }
    277 
    278         mFeatureUsers = new ArrayList();
    279 
    280         mNumDnsEntries = 0;
    281 
    282         mTestMode = SystemProperties.get("cm.test.mode").equals("true")
    283                 && SystemProperties.get("ro.build.type").equals("eng");
    284         /*
    285          * Create the network state trackers for Wi-Fi and mobile
    286          * data. Maybe this could be done with a factory class,
    287          * but it's not clear that it's worth it, given that
    288          * the number of different network types is not going
    289          * to change very often.
    290          */
    291         boolean noMobileData = !getMobileDataEnabled();
    292         for (int netType : mPriorityList) {
    293             switch (mNetAttributes[netType].mRadio) {
    294             case ConnectivityManager.TYPE_WIFI:
    295                 if (DBG) Slog.v(TAG, "Starting Wifi Service.");
    296                 WifiStateTracker wst = new WifiStateTracker(context, mHandler);
    297                 WifiService wifiService = new WifiService(context, wst);
    298                 ServiceManager.addService(Context.WIFI_SERVICE, wifiService);
    299                 wifiService.startWifi();
    300                 mNetTrackers[ConnectivityManager.TYPE_WIFI] = wst;
    301                 wst.startMonitoring();
    302 
    303                 break;
    304             case ConnectivityManager.TYPE_MOBILE:
    305                 mNetTrackers[netType] = new MobileDataStateTracker(context, mHandler,
    306                     netType, mNetAttributes[netType].mName);
    307                 mNetTrackers[netType].startMonitoring();
    308                 if (noMobileData) {
    309                     if (DBG) Slog.d(TAG, "tearing down Mobile networks due to setting");
    310                     mNetTrackers[netType].teardown();
    311                 }
    312                 break;
    313             default:
    314                 Slog.e(TAG, "Trying to create a DataStateTracker for an unknown radio type " +
    315                         mNetAttributes[netType].mRadio);
    316                 continue;
    317             }
    318         }
    319 
    320         mTethering = new Tethering(mContext, mHandler.getLooper());
    321         mTetheringConfigValid = (((mNetTrackers[ConnectivityManager.TYPE_MOBILE_DUN] != null) ||
    322                                   !mTethering.isDunRequired()) &&
    323                                  (mTethering.getTetherableUsbRegexs().length != 0 ||
    324                                   mTethering.getTetherableWifiRegexs().length != 0) &&
    325                                  mTethering.getUpstreamIfaceRegexs().length != 0);
    326 
    327     }
    328 
    329 
    330     /**
    331      * Sets the preferred network.
    332      * @param preference the new preference
    333      */
    334     public synchronized void setNetworkPreference(int preference) {
    335         enforceChangePermission();
    336         if (ConnectivityManager.isNetworkTypeValid(preference) &&
    337                 mNetAttributes[preference] != null &&
    338                 mNetAttributes[preference].isDefault()) {
    339             if (mNetworkPreference != preference) {
    340                 persistNetworkPreference(preference);
    341                 mNetworkPreference = preference;
    342                 enforcePreference();
    343             }
    344         }
    345     }
    346 
    347     public int getNetworkPreference() {
    348         enforceAccessPermission();
    349         return mNetworkPreference;
    350     }
    351 
    352     private void persistNetworkPreference(int networkPreference) {
    353         final ContentResolver cr = mContext.getContentResolver();
    354         Settings.Secure.putInt(cr, Settings.Secure.NETWORK_PREFERENCE,
    355                 networkPreference);
    356     }
    357 
    358     private int getPersistedNetworkPreference() {
    359         final ContentResolver cr = mContext.getContentResolver();
    360 
    361         final int networkPrefSetting = Settings.Secure
    362                 .getInt(cr, Settings.Secure.NETWORK_PREFERENCE, -1);
    363         if (networkPrefSetting != -1) {
    364             return networkPrefSetting;
    365         }
    366 
    367         return ConnectivityManager.DEFAULT_NETWORK_PREFERENCE;
    368     }
    369 
    370     /**
    371      * Make the state of network connectivity conform to the preference settings
    372      * In this method, we only tear down a non-preferred network. Establishing
    373      * a connection to the preferred network is taken care of when we handle
    374      * the disconnect event from the non-preferred network
    375      * (see {@link #handleDisconnect(NetworkInfo)}).
    376      */
    377     private void enforcePreference() {
    378         if (mNetTrackers[mNetworkPreference].getNetworkInfo().isConnected())
    379             return;
    380 
    381         if (!mNetTrackers[mNetworkPreference].isAvailable())
    382             return;
    383 
    384         for (int t=0; t <= ConnectivityManager.MAX_RADIO_TYPE; t++) {
    385             if (t != mNetworkPreference && mNetTrackers[t] != null &&
    386                     mNetTrackers[t].getNetworkInfo().isConnected()) {
    387                 if (DBG) {
    388                     Slog.d(TAG, "tearing down " +
    389                             mNetTrackers[t].getNetworkInfo() +
    390                             " in enforcePreference");
    391                 }
    392                 teardown(mNetTrackers[t]);
    393             }
    394         }
    395     }
    396 
    397     private boolean teardown(NetworkStateTracker netTracker) {
    398         if (netTracker.teardown()) {
    399             netTracker.setTeardownRequested(true);
    400             return true;
    401         } else {
    402             return false;
    403         }
    404     }
    405 
    406     /**
    407      * Return NetworkInfo for the active (i.e., connected) network interface.
    408      * It is assumed that at most one network is active at a time. If more
    409      * than one is active, it is indeterminate which will be returned.
    410      * @return the info for the active network, or {@code null} if none is
    411      * active
    412      */
    413     public NetworkInfo getActiveNetworkInfo() {
    414         enforceAccessPermission();
    415         for (int type=0; type <= ConnectivityManager.MAX_NETWORK_TYPE; type++) {
    416             if (mNetAttributes[type] == null || !mNetAttributes[type].isDefault()) {
    417                 continue;
    418             }
    419             NetworkStateTracker t = mNetTrackers[type];
    420             NetworkInfo info = t.getNetworkInfo();
    421             if (info.isConnected()) {
    422                 if (DBG && type != mActiveDefaultNetwork) Slog.e(TAG,
    423                         "connected default network is not " +
    424                         "mActiveDefaultNetwork!");
    425                 return info;
    426             }
    427         }
    428         return null;
    429     }
    430 
    431     public NetworkInfo getNetworkInfo(int networkType) {
    432         enforceAccessPermission();
    433         if (ConnectivityManager.isNetworkTypeValid(networkType)) {
    434             NetworkStateTracker t = mNetTrackers[networkType];
    435             if (t != null)
    436                 return t.getNetworkInfo();
    437         }
    438         return null;
    439     }
    440 
    441     public NetworkInfo[] getAllNetworkInfo() {
    442         enforceAccessPermission();
    443         NetworkInfo[] result = new NetworkInfo[mNetworksDefined];
    444         int i = 0;
    445         for (NetworkStateTracker t : mNetTrackers) {
    446             if(t != null) result[i++] = t.getNetworkInfo();
    447         }
    448         return result;
    449     }
    450 
    451     public boolean setRadios(boolean turnOn) {
    452         boolean result = true;
    453         enforceChangePermission();
    454         for (NetworkStateTracker t : mNetTrackers) {
    455             if (t != null) result = t.setRadio(turnOn) && result;
    456         }
    457         return result;
    458     }
    459 
    460     public boolean setRadio(int netType, boolean turnOn) {
    461         enforceChangePermission();
    462         if (!ConnectivityManager.isNetworkTypeValid(netType)) {
    463             return false;
    464         }
    465         NetworkStateTracker tracker = mNetTrackers[netType];
    466         return tracker != null && tracker.setRadio(turnOn);
    467     }
    468 
    469     /**
    470      * Used to notice when the calling process dies so we can self-expire
    471      *
    472      * Also used to know if the process has cleaned up after itself when
    473      * our auto-expire timer goes off.  The timer has a link to an object.
    474      *
    475      */
    476     private class FeatureUser implements IBinder.DeathRecipient {
    477         int mNetworkType;
    478         String mFeature;
    479         IBinder mBinder;
    480         int mPid;
    481         int mUid;
    482         long mCreateTime;
    483 
    484         FeatureUser(int type, String feature, IBinder binder) {
    485             super();
    486             mNetworkType = type;
    487             mFeature = feature;
    488             mBinder = binder;
    489             mPid = getCallingPid();
    490             mUid = getCallingUid();
    491             mCreateTime = System.currentTimeMillis();
    492 
    493             try {
    494                 mBinder.linkToDeath(this, 0);
    495             } catch (RemoteException e) {
    496                 binderDied();
    497             }
    498         }
    499 
    500         void unlinkDeathRecipient() {
    501             mBinder.unlinkToDeath(this, 0);
    502         }
    503 
    504         public void binderDied() {
    505             Slog.d(TAG, "ConnectivityService FeatureUser binderDied(" +
    506                     mNetworkType + ", " + mFeature + ", " + mBinder + "), created " +
    507                     (System.currentTimeMillis() - mCreateTime) + " mSec ago");
    508             stopUsingNetworkFeature(this, false);
    509         }
    510 
    511         public void expire() {
    512             Slog.d(TAG, "ConnectivityService FeatureUser expire(" +
    513                     mNetworkType + ", " + mFeature + ", " + mBinder +"), created " +
    514                     (System.currentTimeMillis() - mCreateTime) + " mSec ago");
    515             stopUsingNetworkFeature(this, false);
    516         }
    517 
    518         public String toString() {
    519             return "FeatureUser("+mNetworkType+","+mFeature+","+mPid+","+mUid+"), created " +
    520                     (System.currentTimeMillis() - mCreateTime) + " mSec ago";
    521         }
    522     }
    523 
    524     // javadoc from interface
    525     public int startUsingNetworkFeature(int networkType, String feature,
    526             IBinder binder) {
    527         if (DBG) {
    528             Slog.d(TAG, "startUsingNetworkFeature for net " + networkType +
    529                     ": " + feature);
    530         }
    531         enforceChangePermission();
    532         if (!ConnectivityManager.isNetworkTypeValid(networkType) ||
    533                 mNetAttributes[networkType] == null) {
    534             return Phone.APN_REQUEST_FAILED;
    535         }
    536 
    537         FeatureUser f = new FeatureUser(networkType, feature, binder);
    538 
    539         // TODO - move this into the MobileDataStateTracker
    540         int usedNetworkType = networkType;
    541         if(networkType == ConnectivityManager.TYPE_MOBILE) {
    542             if (!getMobileDataEnabled()) {
    543                 if (DBG) Slog.d(TAG, "requested special network with data disabled - rejected");
    544                 return Phone.APN_TYPE_NOT_AVAILABLE;
    545             }
    546             if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_MMS)) {
    547                 usedNetworkType = ConnectivityManager.TYPE_MOBILE_MMS;
    548             } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_SUPL)) {
    549                 usedNetworkType = ConnectivityManager.TYPE_MOBILE_SUPL;
    550             } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_DUN)) {
    551                 usedNetworkType = ConnectivityManager.TYPE_MOBILE_DUN;
    552             } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_HIPRI)) {
    553                 usedNetworkType = ConnectivityManager.TYPE_MOBILE_HIPRI;
    554             }
    555         }
    556         NetworkStateTracker network = mNetTrackers[usedNetworkType];
    557         if (network != null) {
    558             if (usedNetworkType != networkType) {
    559                 Integer currentPid = new Integer(getCallingPid());
    560 
    561                 NetworkStateTracker radio = mNetTrackers[networkType];
    562                 NetworkInfo ni = network.getNetworkInfo();
    563 
    564                 if (ni.isAvailable() == false) {
    565                     if (DBG) Slog.d(TAG, "special network not available");
    566                     return Phone.APN_TYPE_NOT_AVAILABLE;
    567                 }
    568 
    569                 synchronized(this) {
    570                     mFeatureUsers.add(f);
    571                     if (!mNetRequestersPids[usedNetworkType].contains(currentPid)) {
    572                         // this gets used for per-pid dns when connected
    573                         mNetRequestersPids[usedNetworkType].add(currentPid);
    574                     }
    575                 }
    576                 mHandler.sendMessageDelayed(mHandler.obtainMessage(
    577                         NetworkStateTracker.EVENT_RESTORE_DEFAULT_NETWORK,
    578                         f), getRestoreDefaultNetworkDelay());
    579 
    580 
    581                 if ((ni.isConnectedOrConnecting() == true) &&
    582                         !network.isTeardownRequested()) {
    583                     if (ni.isConnected() == true) {
    584                         // add the pid-specific dns
    585                         handleDnsConfigurationChange();
    586                         if (DBG) Slog.d(TAG, "special network already active");
    587                         return Phone.APN_ALREADY_ACTIVE;
    588                     }
    589                     if (DBG) Slog.d(TAG, "special network already connecting");
    590                     return Phone.APN_REQUEST_STARTED;
    591                 }
    592 
    593                 // check if the radio in play can make another contact
    594                 // assume if cannot for now
    595 
    596                 if (DBG) Slog.d(TAG, "reconnecting to special network");
    597                 network.reconnect();
    598                 return Phone.APN_REQUEST_STARTED;
    599             } else {
    600                 synchronized(this) {
    601                     mFeatureUsers.add(f);
    602                 }
    603                 mHandler.sendMessageDelayed(mHandler.obtainMessage(
    604                         NetworkStateTracker.EVENT_RESTORE_DEFAULT_NETWORK,
    605                         f), getRestoreDefaultNetworkDelay());
    606 
    607                 return network.startUsingNetworkFeature(feature,
    608                         getCallingPid(), getCallingUid());
    609             }
    610         }
    611         return Phone.APN_TYPE_NOT_AVAILABLE;
    612     }
    613 
    614     // javadoc from interface
    615     public int stopUsingNetworkFeature(int networkType, String feature) {
    616         enforceChangePermission();
    617 
    618         int pid = getCallingPid();
    619         int uid = getCallingUid();
    620 
    621         FeatureUser u = null;
    622         boolean found = false;
    623 
    624         synchronized(this) {
    625             for (int i = 0; i < mFeatureUsers.size() ; i++) {
    626                 u = (FeatureUser)mFeatureUsers.get(i);
    627                 if (uid == u.mUid && pid == u.mPid &&
    628                         networkType == u.mNetworkType &&
    629                         TextUtils.equals(feature, u.mFeature)) {
    630                     found = true;
    631                     break;
    632                 }
    633             }
    634         }
    635         if (found && u != null) {
    636             // stop regardless of how many other time this proc had called start
    637             return stopUsingNetworkFeature(u, true);
    638         } else {
    639             // none found!
    640             if (DBG) Slog.d(TAG, "ignoring stopUsingNetworkFeature - not a live request");
    641             return 1;
    642         }
    643     }
    644 
    645     private int stopUsingNetworkFeature(FeatureUser u, boolean ignoreDups) {
    646         int networkType = u.mNetworkType;
    647         String feature = u.mFeature;
    648         int pid = u.mPid;
    649         int uid = u.mUid;
    650 
    651         NetworkStateTracker tracker = null;
    652         boolean callTeardown = false;  // used to carry our decision outside of sync block
    653 
    654         if (DBG) {
    655             Slog.d(TAG, "stopUsingNetworkFeature for net " + networkType +
    656                     ": " + feature);
    657         }
    658 
    659         if (!ConnectivityManager.isNetworkTypeValid(networkType)) {
    660             return -1;
    661         }
    662 
    663         // need to link the mFeatureUsers list with the mNetRequestersPids state in this
    664         // sync block
    665         synchronized(this) {
    666             // check if this process still has an outstanding start request
    667             if (!mFeatureUsers.contains(u)) {
    668                 if (DBG) Slog.d(TAG, "ignoring - this process has no outstanding requests");
    669                 return 1;
    670             }
    671             u.unlinkDeathRecipient();
    672             mFeatureUsers.remove(mFeatureUsers.indexOf(u));
    673             // If we care about duplicate requests, check for that here.
    674             //
    675             // This is done to support the extension of a request - the app
    676             // can request we start the network feature again and renew the
    677             // auto-shutoff delay.  Normal "stop" calls from the app though
    678             // do not pay attention to duplicate requests - in effect the
    679             // API does not refcount and a single stop will counter multiple starts.
    680             if (ignoreDups == false) {
    681                 for (int i = 0; i < mFeatureUsers.size() ; i++) {
    682                     FeatureUser x = (FeatureUser)mFeatureUsers.get(i);
    683                     if (x.mUid == u.mUid && x.mPid == u.mPid &&
    684                             x.mNetworkType == u.mNetworkType &&
    685                             TextUtils.equals(x.mFeature, u.mFeature)) {
    686                         if (DBG) Slog.d(TAG, "ignoring stopUsingNetworkFeature as dup is found");
    687                         return 1;
    688                     }
    689                 }
    690             }
    691 
    692             // TODO - move to MobileDataStateTracker
    693             int usedNetworkType = networkType;
    694             if (networkType == ConnectivityManager.TYPE_MOBILE) {
    695                 if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_MMS)) {
    696                     usedNetworkType = ConnectivityManager.TYPE_MOBILE_MMS;
    697                 } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_SUPL)) {
    698                     usedNetworkType = ConnectivityManager.TYPE_MOBILE_SUPL;
    699                 } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_DUN)) {
    700                     usedNetworkType = ConnectivityManager.TYPE_MOBILE_DUN;
    701                 } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_HIPRI)) {
    702                     usedNetworkType = ConnectivityManager.TYPE_MOBILE_HIPRI;
    703                 }
    704             }
    705             tracker =  mNetTrackers[usedNetworkType];
    706             if (tracker == null) {
    707                 if (DBG) Slog.d(TAG, "ignoring - no known tracker for net type " + usedNetworkType);
    708                 return -1;
    709             }
    710             if (usedNetworkType != networkType) {
    711                 Integer currentPid = new Integer(pid);
    712                 mNetRequestersPids[usedNetworkType].remove(currentPid);
    713                 reassessPidDns(pid, true);
    714                 if (mNetRequestersPids[usedNetworkType].size() != 0) {
    715                     if (DBG) Slog.d(TAG, "not tearing down special network - " +
    716                            "others still using it");
    717                     return 1;
    718                 }
    719                 callTeardown = true;
    720             }
    721         }
    722         if (DBG) Slog.d(TAG, "Doing network teardown");
    723         if (callTeardown) {
    724             tracker.teardown();
    725             return 1;
    726         } else {
    727             // do it the old fashioned way
    728             return tracker.stopUsingNetworkFeature(feature, pid, uid);
    729         }
    730     }
    731 
    732     /**
    733      * Ensure that a network route exists to deliver traffic to the specified
    734      * host via the specified network interface.
    735      * @param networkType the type of the network over which traffic to the
    736      * specified host is to be routed
    737      * @param hostAddress the IP address of the host to which the route is
    738      * desired
    739      * @return {@code true} on success, {@code false} on failure
    740      */
    741     public boolean requestRouteToHost(int networkType, int hostAddress) {
    742         enforceChangePermission();
    743         if (!ConnectivityManager.isNetworkTypeValid(networkType)) {
    744             return false;
    745         }
    746         NetworkStateTracker tracker = mNetTrackers[networkType];
    747 
    748         if (tracker == null || !tracker.getNetworkInfo().isConnected() ||
    749                 tracker.isTeardownRequested()) {
    750             if (DBG) {
    751                 Slog.d(TAG, "requestRouteToHost on down network (" + networkType + ") - dropped");
    752             }
    753             return false;
    754         }
    755         return tracker.requestRouteToHost(hostAddress);
    756     }
    757 
    758     /**
    759      * @see ConnectivityManager#getBackgroundDataSetting()
    760      */
    761     public boolean getBackgroundDataSetting() {
    762         return Settings.Secure.getInt(mContext.getContentResolver(),
    763                 Settings.Secure.BACKGROUND_DATA, 1) == 1;
    764     }
    765 
    766     /**
    767      * @see ConnectivityManager#setBackgroundDataSetting(boolean)
    768      */
    769     public void setBackgroundDataSetting(boolean allowBackgroundDataUsage) {
    770         mContext.enforceCallingOrSelfPermission(
    771                 android.Manifest.permission.CHANGE_BACKGROUND_DATA_SETTING,
    772                 "ConnectivityService");
    773 
    774         if (getBackgroundDataSetting() == allowBackgroundDataUsage) return;
    775 
    776         Settings.Secure.putInt(mContext.getContentResolver(),
    777                 Settings.Secure.BACKGROUND_DATA,
    778                 allowBackgroundDataUsage ? 1 : 0);
    779 
    780         Intent broadcast = new Intent(
    781                 ConnectivityManager.ACTION_BACKGROUND_DATA_SETTING_CHANGED);
    782         mContext.sendBroadcast(broadcast);
    783     }
    784 
    785     /**
    786      * @see ConnectivityManager#getMobileDataEnabled()
    787      */
    788     public boolean getMobileDataEnabled() {
    789         enforceAccessPermission();
    790         boolean retVal = Settings.Secure.getInt(mContext.getContentResolver(),
    791                 Settings.Secure.MOBILE_DATA, 1) == 1;
    792         if (DBG) Slog.d(TAG, "getMobileDataEnabled returning " + retVal);
    793         return retVal;
    794     }
    795 
    796     /**
    797      * @see ConnectivityManager#setMobileDataEnabled(boolean)
    798      */
    799     public synchronized void setMobileDataEnabled(boolean enabled) {
    800         enforceChangePermission();
    801         if (DBG) Slog.d(TAG, "setMobileDataEnabled(" + enabled + ")");
    802 
    803         if (getMobileDataEnabled() == enabled) return;
    804 
    805         Settings.Secure.putInt(mContext.getContentResolver(),
    806                 Settings.Secure.MOBILE_DATA, enabled ? 1 : 0);
    807 
    808         if (enabled) {
    809             if (mNetTrackers[ConnectivityManager.TYPE_MOBILE] != null) {
    810                 if (DBG) Slog.d(TAG, "starting up " + mNetTrackers[ConnectivityManager.TYPE_MOBILE]);
    811                 mNetTrackers[ConnectivityManager.TYPE_MOBILE].reconnect();
    812             }
    813         } else {
    814             for (NetworkStateTracker nt : mNetTrackers) {
    815                 if (nt == null) continue;
    816                 int netType = nt.getNetworkInfo().getType();
    817                 if (mNetAttributes[netType].mRadio == ConnectivityManager.TYPE_MOBILE) {
    818                     if (DBG) Slog.d(TAG, "tearing down " + nt);
    819                     nt.teardown();
    820                 }
    821             }
    822         }
    823     }
    824 
    825     private int getNumConnectedNetworks() {
    826         int numConnectedNets = 0;
    827 
    828         for (NetworkStateTracker nt : mNetTrackers) {
    829             if (nt != null && nt.getNetworkInfo().isConnected() &&
    830                     !nt.isTeardownRequested()) {
    831                 ++numConnectedNets;
    832             }
    833         }
    834         return numConnectedNets;
    835     }
    836 
    837     private void enforceAccessPermission() {
    838         mContext.enforceCallingOrSelfPermission(
    839                 android.Manifest.permission.ACCESS_NETWORK_STATE,
    840                 "ConnectivityService");
    841     }
    842 
    843     private void enforceChangePermission() {
    844         mContext.enforceCallingOrSelfPermission(
    845                 android.Manifest.permission.CHANGE_NETWORK_STATE,
    846                 "ConnectivityService");
    847     }
    848 
    849     // TODO Make this a special check when it goes public
    850     private void enforceTetherChangePermission() {
    851         mContext.enforceCallingOrSelfPermission(
    852                 android.Manifest.permission.CHANGE_NETWORK_STATE,
    853                 "ConnectivityService");
    854     }
    855 
    856     private void enforceTetherAccessPermission() {
    857         mContext.enforceCallingOrSelfPermission(
    858                 android.Manifest.permission.ACCESS_NETWORK_STATE,
    859                 "ConnectivityService");
    860     }
    861 
    862     /**
    863      * Handle a {@code DISCONNECTED} event. If this pertains to the non-active
    864      * network, we ignore it. If it is for the active network, we send out a
    865      * broadcast. But first, we check whether it might be possible to connect
    866      * to a different network.
    867      * @param info the {@code NetworkInfo} for the network
    868      */
    869     private void handleDisconnect(NetworkInfo info) {
    870 
    871         int prevNetType = info.getType();
    872 
    873         mNetTrackers[prevNetType].setTeardownRequested(false);
    874         /*
    875          * If the disconnected network is not the active one, then don't report
    876          * this as a loss of connectivity. What probably happened is that we're
    877          * getting the disconnect for a network that we explicitly disabled
    878          * in accordance with network preference policies.
    879          */
    880         if (!mNetAttributes[prevNetType].isDefault()) {
    881             List pids = mNetRequestersPids[prevNetType];
    882             for (int i = 0; i<pids.size(); i++) {
    883                 Integer pid = (Integer)pids.get(i);
    884                 // will remove them because the net's no longer connected
    885                 // need to do this now as only now do we know the pids and
    886                 // can properly null things that are no longer referenced.
    887                 reassessPidDns(pid.intValue(), false);
    888             }
    889         }
    890 
    891         Intent intent = new Intent(ConnectivityManager.CONNECTIVITY_ACTION);
    892         intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
    893         intent.putExtra(ConnectivityManager.EXTRA_NETWORK_INFO, info);
    894         if (info.isFailover()) {
    895             intent.putExtra(ConnectivityManager.EXTRA_IS_FAILOVER, true);
    896             info.setFailover(false);
    897         }
    898         if (info.getReason() != null) {
    899             intent.putExtra(ConnectivityManager.EXTRA_REASON, info.getReason());
    900         }
    901         if (info.getExtraInfo() != null) {
    902             intent.putExtra(ConnectivityManager.EXTRA_EXTRA_INFO,
    903                     info.getExtraInfo());
    904         }
    905 
    906         NetworkStateTracker newNet = null;
    907         if (mNetAttributes[prevNetType].isDefault()) {
    908             newNet = tryFailover(prevNetType);
    909             if (newNet != null) {
    910                 NetworkInfo switchTo = newNet.getNetworkInfo();
    911                 intent.putExtra(ConnectivityManager.EXTRA_OTHER_NETWORK_INFO, switchTo);
    912             } else {
    913                 intent.putExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, true);
    914             }
    915         }
    916         // do this before we broadcast the change
    917         handleConnectivityChange();
    918 
    919         sendStickyBroadcast(intent);
    920         /*
    921          * If the failover network is already connected, then immediately send
    922          * out a followup broadcast indicating successful failover
    923          */
    924         if (newNet != null && newNet.getNetworkInfo().isConnected()) {
    925             sendConnectedBroadcast(newNet.getNetworkInfo());
    926         }
    927     }
    928 
    929     // returns null if no failover available
    930     private NetworkStateTracker tryFailover(int prevNetType) {
    931         /*
    932          * If this is a default network, check if other defaults are available
    933          * or active
    934          */
    935         NetworkStateTracker newNet = null;
    936         if (mNetAttributes[prevNetType].isDefault()) {
    937             if (mActiveDefaultNetwork == prevNetType) {
    938                 mActiveDefaultNetwork = -1;
    939             }
    940 
    941             int newType = -1;
    942             int newPriority = -1;
    943             boolean noMobileData = !getMobileDataEnabled();
    944             for (int checkType=0; checkType <= ConnectivityManager.MAX_NETWORK_TYPE; checkType++) {
    945                 if (checkType == prevNetType) continue;
    946                 if (mNetAttributes[checkType] == null) continue;
    947                 if (mNetAttributes[checkType].mRadio == ConnectivityManager.TYPE_MOBILE &&
    948                         noMobileData) {
    949                     if (DBG) {
    950                         Slog.d(TAG, "not failing over to mobile type " + checkType +
    951                                 " because Mobile Data Disabled");
    952                     }
    953                     continue;
    954                 }
    955                 if (mNetAttributes[checkType].isDefault()) {
    956                     /* TODO - if we have multiple nets we could use
    957                      * we may want to put more thought into which we choose
    958                      */
    959                     if (checkType == mNetworkPreference) {
    960                         newType = checkType;
    961                         break;
    962                     }
    963                     if (mNetAttributes[checkType].mPriority > newPriority) {
    964                         newType = checkType;
    965                         newPriority = mNetAttributes[newType].mPriority;
    966                     }
    967                 }
    968             }
    969 
    970             if (newType != -1) {
    971                 newNet = mNetTrackers[newType];
    972                 /**
    973                  * See if the other network is available to fail over to.
    974                  * If is not available, we enable it anyway, so that it
    975                  * will be able to connect when it does become available,
    976                  * but we report a total loss of connectivity rather than
    977                  * report that we are attempting to fail over.
    978                  */
    979                 if (newNet.isAvailable()) {
    980                     NetworkInfo switchTo = newNet.getNetworkInfo();
    981                     switchTo.setFailover(true);
    982                     if (!switchTo.isConnectedOrConnecting() ||
    983                             newNet.isTeardownRequested()) {
    984                         newNet.reconnect();
    985                     }
    986                     if (DBG) {
    987                         if (switchTo.isConnected()) {
    988                             Slog.v(TAG, "Switching to already connected " +
    989                                     switchTo.getTypeName());
    990                         } else {
    991                             Slog.v(TAG, "Attempting to switch to " +
    992                                     switchTo.getTypeName());
    993                         }
    994                     }
    995                 } else {
    996                     newNet.reconnect();
    997                     newNet = null; // not officially avail..  try anyway, but
    998                                    // report no failover
    999                 }
   1000             }
   1001         }
   1002 
   1003         return newNet;
   1004     }
   1005 
   1006     private void sendConnectedBroadcast(NetworkInfo info) {
   1007         Intent intent = new Intent(ConnectivityManager.CONNECTIVITY_ACTION);
   1008         intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
   1009         intent.putExtra(ConnectivityManager.EXTRA_NETWORK_INFO, info);
   1010         if (info.isFailover()) {
   1011             intent.putExtra(ConnectivityManager.EXTRA_IS_FAILOVER, true);
   1012             info.setFailover(false);
   1013         }
   1014         if (info.getReason() != null) {
   1015             intent.putExtra(ConnectivityManager.EXTRA_REASON, info.getReason());
   1016         }
   1017         if (info.getExtraInfo() != null) {
   1018             intent.putExtra(ConnectivityManager.EXTRA_EXTRA_INFO,
   1019                     info.getExtraInfo());
   1020         }
   1021         sendStickyBroadcast(intent);
   1022     }
   1023 
   1024     /**
   1025      * Called when an attempt to fail over to another network has failed.
   1026      * @param info the {@link NetworkInfo} for the failed network
   1027      */
   1028     private void handleConnectionFailure(NetworkInfo info) {
   1029         mNetTrackers[info.getType()].setTeardownRequested(false);
   1030 
   1031         String reason = info.getReason();
   1032         String extraInfo = info.getExtraInfo();
   1033 
   1034         if (DBG) {
   1035             String reasonText;
   1036             if (reason == null) {
   1037                 reasonText = ".";
   1038             } else {
   1039                 reasonText = " (" + reason + ").";
   1040             }
   1041             Slog.v(TAG, "Attempt to connect to " + info.getTypeName() +
   1042                     " failed" + reasonText);
   1043         }
   1044 
   1045         Intent intent = new Intent(ConnectivityManager.CONNECTIVITY_ACTION);
   1046         intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
   1047         intent.putExtra(ConnectivityManager.EXTRA_NETWORK_INFO, info);
   1048         if (getActiveNetworkInfo() == null) {
   1049             intent.putExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, true);
   1050         }
   1051         if (reason != null) {
   1052             intent.putExtra(ConnectivityManager.EXTRA_REASON, reason);
   1053         }
   1054         if (extraInfo != null) {
   1055             intent.putExtra(ConnectivityManager.EXTRA_EXTRA_INFO, extraInfo);
   1056         }
   1057         if (info.isFailover()) {
   1058             intent.putExtra(ConnectivityManager.EXTRA_IS_FAILOVER, true);
   1059             info.setFailover(false);
   1060         }
   1061 
   1062         NetworkStateTracker newNet = null;
   1063         if (mNetAttributes[info.getType()].isDefault()) {
   1064             newNet = tryFailover(info.getType());
   1065             if (newNet != null) {
   1066                 NetworkInfo switchTo = newNet.getNetworkInfo();
   1067                 intent.putExtra(ConnectivityManager.EXTRA_OTHER_NETWORK_INFO, switchTo);
   1068             } else {
   1069                 intent.putExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, true);
   1070             }
   1071         }
   1072 
   1073         // do this before we broadcast the change
   1074         handleConnectivityChange();
   1075 
   1076         sendStickyBroadcast(intent);
   1077         /*
   1078          * If the failover network is already connected, then immediately send
   1079          * out a followup broadcast indicating successful failover
   1080          */
   1081         if (newNet != null && newNet.getNetworkInfo().isConnected()) {
   1082             sendConnectedBroadcast(newNet.getNetworkInfo());
   1083         }
   1084     }
   1085 
   1086     private void sendStickyBroadcast(Intent intent) {
   1087         synchronized(this) {
   1088             if (!mSystemReady) {
   1089                 mInitialBroadcast = new Intent(intent);
   1090             }
   1091             intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
   1092             mContext.sendStickyBroadcast(intent);
   1093         }
   1094     }
   1095 
   1096     void systemReady() {
   1097         synchronized(this) {
   1098             mSystemReady = true;
   1099             if (mInitialBroadcast != null) {
   1100                 mContext.sendStickyBroadcast(mInitialBroadcast);
   1101                 mInitialBroadcast = null;
   1102             }
   1103         }
   1104     }
   1105 
   1106     private void handleConnect(NetworkInfo info) {
   1107         int type = info.getType();
   1108 
   1109         // snapshot isFailover, because sendConnectedBroadcast() resets it
   1110         boolean isFailover = info.isFailover();
   1111         NetworkStateTracker thisNet = mNetTrackers[type];
   1112 
   1113         // if this is a default net and other default is running
   1114         // kill the one not preferred
   1115         if (mNetAttributes[type].isDefault()) {
   1116             if (mActiveDefaultNetwork != -1 && mActiveDefaultNetwork != type) {
   1117                 if ((type != mNetworkPreference &&
   1118                         mNetAttributes[mActiveDefaultNetwork].mPriority >
   1119                         mNetAttributes[type].mPriority) ||
   1120                         mNetworkPreference == mActiveDefaultNetwork) {
   1121                         // don't accept this one
   1122                         if (DBG) Slog.v(TAG, "Not broadcasting CONNECT_ACTION " +
   1123                                 "to torn down network " + info.getTypeName());
   1124                         teardown(thisNet);
   1125                         return;
   1126                 } else {
   1127                     // tear down the other
   1128                     NetworkStateTracker otherNet =
   1129                             mNetTrackers[mActiveDefaultNetwork];
   1130                     if (DBG) Slog.v(TAG, "Policy requires " +
   1131                             otherNet.getNetworkInfo().getTypeName() +
   1132                             " teardown");
   1133                     if (!teardown(otherNet)) {
   1134                         Slog.e(TAG, "Network declined teardown request");
   1135                         return;
   1136                     }
   1137                     if (isFailover) {
   1138                         otherNet.releaseWakeLock();
   1139                     }
   1140                 }
   1141             }
   1142             mActiveDefaultNetwork = type;
   1143         }
   1144         thisNet.setTeardownRequested(false);
   1145         thisNet.updateNetworkSettings();
   1146         handleConnectivityChange();
   1147         sendConnectedBroadcast(info);
   1148     }
   1149 
   1150     private void handleScanResultsAvailable(NetworkInfo info) {
   1151         int networkType = info.getType();
   1152         if (networkType != ConnectivityManager.TYPE_WIFI) {
   1153             if (DBG) Slog.v(TAG, "Got ScanResultsAvailable for " +
   1154                     info.getTypeName() + " network. Don't know how to handle.");
   1155         }
   1156 
   1157         mNetTrackers[networkType].interpretScanResultsAvailable();
   1158     }
   1159 
   1160     private void handleNotificationChange(boolean visible, int id,
   1161             Notification notification) {
   1162         NotificationManager notificationManager = (NotificationManager) mContext
   1163                 .getSystemService(Context.NOTIFICATION_SERVICE);
   1164 
   1165         if (visible) {
   1166             notificationManager.notify(id, notification);
   1167         } else {
   1168             notificationManager.cancel(id);
   1169         }
   1170     }
   1171 
   1172     /**
   1173      * After any kind of change in the connectivity state of any network,
   1174      * make sure that anything that depends on the connectivity state of
   1175      * more than one network is set up correctly. We're mainly concerned
   1176      * with making sure that the list of DNS servers is set up  according
   1177      * to which networks are connected, and ensuring that the right routing
   1178      * table entries exist.
   1179      */
   1180     private void handleConnectivityChange() {
   1181         /*
   1182          * If a non-default network is enabled, add the host routes that
   1183          * will allow it's DNS servers to be accessed.  Only
   1184          * If both mobile and wifi are enabled, add the host routes that
   1185          * will allow MMS traffic to pass on the mobile network. But
   1186          * remove the default route for the mobile network, so that there
   1187          * will be only one default route, to ensure that all traffic
   1188          * except MMS will travel via Wi-Fi.
   1189          */
   1190         handleDnsConfigurationChange();
   1191 
   1192         for (int netType : mPriorityList) {
   1193             if (mNetTrackers[netType].getNetworkInfo().isConnected()) {
   1194                 if (mNetAttributes[netType].isDefault()) {
   1195                     mNetTrackers[netType].addDefaultRoute();
   1196                 } else {
   1197                     mNetTrackers[netType].addPrivateDnsRoutes();
   1198                 }
   1199             } else {
   1200                 if (mNetAttributes[netType].isDefault()) {
   1201                     mNetTrackers[netType].removeDefaultRoute();
   1202                 } else {
   1203                     mNetTrackers[netType].removePrivateDnsRoutes();
   1204                 }
   1205             }
   1206         }
   1207     }
   1208 
   1209     /**
   1210      * Adjust the per-process dns entries (net.dns<x>.<pid>) based
   1211      * on the highest priority active net which this process requested.
   1212      * If there aren't any, clear it out
   1213      */
   1214     private void reassessPidDns(int myPid, boolean doBump)
   1215     {
   1216         if (DBG) Slog.d(TAG, "reassessPidDns for pid " + myPid);
   1217         for(int i : mPriorityList) {
   1218             if (mNetAttributes[i].isDefault()) {
   1219                 continue;
   1220             }
   1221             NetworkStateTracker nt = mNetTrackers[i];
   1222             if (nt.getNetworkInfo().isConnected() &&
   1223                     !nt.isTeardownRequested()) {
   1224                 List pids = mNetRequestersPids[i];
   1225                 for (int j=0; j<pids.size(); j++) {
   1226                     Integer pid = (Integer)pids.get(j);
   1227                     if (pid.intValue() == myPid) {
   1228                         String[] dnsList = nt.getNameServers();
   1229                         writePidDns(dnsList, myPid);
   1230                         if (doBump) {
   1231                             bumpDns();
   1232                         }
   1233                         return;
   1234                     }
   1235                 }
   1236            }
   1237         }
   1238         // nothing found - delete
   1239         for (int i = 1; ; i++) {
   1240             String prop = "net.dns" + i + "." + myPid;
   1241             if (SystemProperties.get(prop).length() == 0) {
   1242                 if (doBump) {
   1243                     bumpDns();
   1244                 }
   1245                 return;
   1246             }
   1247             SystemProperties.set(prop, "");
   1248         }
   1249     }
   1250 
   1251     private void writePidDns(String[] dnsList, int pid) {
   1252         int j = 1;
   1253         for (String dns : dnsList) {
   1254             if (dns != null && !TextUtils.equals(dns, "0.0.0.0")) {
   1255                 SystemProperties.set("net.dns" + j++ + "." + pid, dns);
   1256             }
   1257         }
   1258     }
   1259 
   1260     private void bumpDns() {
   1261         /*
   1262          * Bump the property that tells the name resolver library to reread
   1263          * the DNS server list from the properties.
   1264          */
   1265         String propVal = SystemProperties.get("net.dnschange");
   1266         int n = 0;
   1267         if (propVal.length() != 0) {
   1268             try {
   1269                 n = Integer.parseInt(propVal);
   1270             } catch (NumberFormatException e) {}
   1271         }
   1272         SystemProperties.set("net.dnschange", "" + (n+1));
   1273     }
   1274 
   1275     private void handleDnsConfigurationChange() {
   1276         // add default net's dns entries
   1277         for (int x = mPriorityList.length-1; x>= 0; x--) {
   1278             int netType = mPriorityList[x];
   1279             NetworkStateTracker nt = mNetTrackers[netType];
   1280             if (nt != null && nt.getNetworkInfo().isConnected() &&
   1281                     !nt.isTeardownRequested()) {
   1282                 String[] dnsList = nt.getNameServers();
   1283                 if (mNetAttributes[netType].isDefault()) {
   1284                     int j = 1;
   1285                     for (String dns : dnsList) {
   1286                         if (dns != null && !TextUtils.equals(dns, "0.0.0.0")) {
   1287                             if (DBG) {
   1288                                 Slog.d(TAG, "adding dns " + dns + " for " +
   1289                                         nt.getNetworkInfo().getTypeName());
   1290                             }
   1291                             SystemProperties.set("net.dns" + j++, dns);
   1292                         }
   1293                     }
   1294                     for (int k=j ; k<mNumDnsEntries; k++) {
   1295                         if (DBG) Slog.d(TAG, "erasing net.dns" + k);
   1296                         SystemProperties.set("net.dns" + k, "");
   1297                     }
   1298                     mNumDnsEntries = j;
   1299                 } else {
   1300                     // set per-pid dns for attached secondary nets
   1301                     List pids = mNetRequestersPids[netType];
   1302                     for (int y=0; y< pids.size(); y++) {
   1303                         Integer pid = (Integer)pids.get(y);
   1304                         writePidDns(dnsList, pid.intValue());
   1305                     }
   1306                 }
   1307             }
   1308         }
   1309 
   1310         bumpDns();
   1311     }
   1312 
   1313     private int getRestoreDefaultNetworkDelay() {
   1314         String restoreDefaultNetworkDelayStr = SystemProperties.get(
   1315                 NETWORK_RESTORE_DELAY_PROP_NAME);
   1316         if(restoreDefaultNetworkDelayStr != null &&
   1317                 restoreDefaultNetworkDelayStr.length() != 0) {
   1318             try {
   1319                 return Integer.valueOf(restoreDefaultNetworkDelayStr);
   1320             } catch (NumberFormatException e) {
   1321             }
   1322         }
   1323         return RESTORE_DEFAULT_NETWORK_DELAY;
   1324     }
   1325 
   1326     @Override
   1327     protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
   1328         if (mContext.checkCallingOrSelfPermission(
   1329                 android.Manifest.permission.DUMP)
   1330                 != PackageManager.PERMISSION_GRANTED) {
   1331             pw.println("Permission Denial: can't dump ConnectivityService " +
   1332                     "from from pid=" + Binder.getCallingPid() + ", uid=" +
   1333                     Binder.getCallingUid());
   1334             return;
   1335         }
   1336         pw.println();
   1337         for (NetworkStateTracker nst : mNetTrackers) {
   1338             if (nst != null) {
   1339                 if (nst.getNetworkInfo().isConnected()) {
   1340                     pw.println("Active network: " + nst.getNetworkInfo().
   1341                             getTypeName());
   1342                 }
   1343                 pw.println(nst.getNetworkInfo());
   1344                 pw.println(nst);
   1345                 pw.println();
   1346             }
   1347         }
   1348 
   1349         pw.println("Network Requester Pids:");
   1350         for (int net : mPriorityList) {
   1351             String pidString = net + ": ";
   1352             for (Object pid : mNetRequestersPids[net]) {
   1353                 pidString = pidString + pid.toString() + ", ";
   1354             }
   1355             pw.println(pidString);
   1356         }
   1357         pw.println();
   1358 
   1359         pw.println("FeatureUsers:");
   1360         for (Object requester : mFeatureUsers) {
   1361             pw.println(requester.toString());
   1362         }
   1363         pw.println();
   1364 
   1365         mTethering.dump(fd, pw, args);
   1366     }
   1367 
   1368     // must be stateless - things change under us.
   1369     private class MyHandler extends Handler {
   1370         @Override
   1371         public void handleMessage(Message msg) {
   1372             NetworkInfo info;
   1373             switch (msg.what) {
   1374                 case NetworkStateTracker.EVENT_STATE_CHANGED:
   1375                     info = (NetworkInfo) msg.obj;
   1376                     int type = info.getType();
   1377                     NetworkInfo.State state = info.getState();
   1378                     // only do this optimization for wifi.  It going into scan mode for location
   1379                     // services generates alot of noise.  Meanwhile the mms apn won't send out
   1380                     // subsequent notifications when on default cellular because it never
   1381                     // disconnects..  so only do this to wifi notifications.  Fixed better when the
   1382                     // APN notifications are standardized.
   1383                     if (mNetAttributes[type].mLastState == state &&
   1384                             mNetAttributes[type].mRadio == ConnectivityManager.TYPE_WIFI) {
   1385                         if (DBG) {
   1386                             // TODO - remove this after we validate the dropping doesn't break
   1387                             // anything
   1388                             Slog.d(TAG, "Dropping ConnectivityChange for " +
   1389                                     info.getTypeName() + ": " +
   1390                                     state + "/" + info.getDetailedState());
   1391                         }
   1392                         return;
   1393                     }
   1394                     mNetAttributes[type].mLastState = state;
   1395 
   1396                     if (DBG) Slog.d(TAG, "ConnectivityChange for " +
   1397                             info.getTypeName() + ": " +
   1398                             state + "/" + info.getDetailedState());
   1399 
   1400                     // Connectivity state changed:
   1401                     // [31-13] Reserved for future use
   1402                     // [12-9] Network subtype (for mobile network, as defined
   1403                     //         by TelephonyManager)
   1404                     // [8-3] Detailed state ordinal (as defined by
   1405                     //         NetworkInfo.DetailedState)
   1406                     // [2-0] Network type (as defined by ConnectivityManager)
   1407                     int eventLogParam = (info.getType() & 0x7) |
   1408                             ((info.getDetailedState().ordinal() & 0x3f) << 3) |
   1409                             (info.getSubtype() << 9);
   1410                     EventLog.writeEvent(EventLogTags.CONNECTIVITY_STATE_CHANGED,
   1411                             eventLogParam);
   1412 
   1413                     if (info.getDetailedState() ==
   1414                             NetworkInfo.DetailedState.FAILED) {
   1415                         handleConnectionFailure(info);
   1416                     } else if (state == NetworkInfo.State.DISCONNECTED) {
   1417                         handleDisconnect(info);
   1418                     } else if (state == NetworkInfo.State.SUSPENDED) {
   1419                         // TODO: need to think this over.
   1420                         // the logic here is, handle SUSPENDED the same as
   1421                         // DISCONNECTED. The only difference being we are
   1422                         // broadcasting an intent with NetworkInfo that's
   1423                         // suspended. This allows the applications an
   1424                         // opportunity to handle DISCONNECTED and SUSPENDED
   1425                         // differently, or not.
   1426                         handleDisconnect(info);
   1427                     } else if (state == NetworkInfo.State.CONNECTED) {
   1428                         handleConnect(info);
   1429                     }
   1430                     break;
   1431 
   1432                 case NetworkStateTracker.EVENT_SCAN_RESULTS_AVAILABLE:
   1433                     info = (NetworkInfo) msg.obj;
   1434                     handleScanResultsAvailable(info);
   1435                     break;
   1436 
   1437                 case NetworkStateTracker.EVENT_NOTIFICATION_CHANGED:
   1438                     handleNotificationChange(msg.arg1 == 1, msg.arg2,
   1439                             (Notification) msg.obj);
   1440 
   1441                 case NetworkStateTracker.EVENT_CONFIGURATION_CHANGED:
   1442                     handleDnsConfigurationChange();
   1443                     break;
   1444 
   1445                 case NetworkStateTracker.EVENT_ROAMING_CHANGED:
   1446                     // fill me in
   1447                     break;
   1448 
   1449                 case NetworkStateTracker.EVENT_NETWORK_SUBTYPE_CHANGED:
   1450                     // fill me in
   1451                     break;
   1452                 case NetworkStateTracker.EVENT_RESTORE_DEFAULT_NETWORK:
   1453                     FeatureUser u = (FeatureUser)msg.obj;
   1454                     u.expire();
   1455                     break;
   1456             }
   1457         }
   1458     }
   1459 
   1460     // javadoc from interface
   1461     public int tether(String iface) {
   1462         enforceTetherChangePermission();
   1463 
   1464         if (isTetheringSupported()) {
   1465             return mTethering.tether(iface);
   1466         } else {
   1467             return ConnectivityManager.TETHER_ERROR_UNSUPPORTED;
   1468         }
   1469     }
   1470 
   1471     // javadoc from interface
   1472     public int untether(String iface) {
   1473         enforceTetherChangePermission();
   1474 
   1475         if (isTetheringSupported()) {
   1476             return mTethering.untether(iface);
   1477         } else {
   1478             return ConnectivityManager.TETHER_ERROR_UNSUPPORTED;
   1479         }
   1480     }
   1481 
   1482     // javadoc from interface
   1483     public int getLastTetherError(String iface) {
   1484         enforceTetherAccessPermission();
   1485 
   1486         if (isTetheringSupported()) {
   1487             return mTethering.getLastTetherError(iface);
   1488         } else {
   1489             return ConnectivityManager.TETHER_ERROR_UNSUPPORTED;
   1490         }
   1491     }
   1492 
   1493     // TODO - proper iface API for selection by property, inspection, etc
   1494     public String[] getTetherableUsbRegexs() {
   1495         enforceTetherAccessPermission();
   1496         if (isTetheringSupported()) {
   1497             return mTethering.getTetherableUsbRegexs();
   1498         } else {
   1499             return new String[0];
   1500         }
   1501     }
   1502 
   1503     public String[] getTetherableWifiRegexs() {
   1504         enforceTetherAccessPermission();
   1505         if (isTetheringSupported()) {
   1506             return mTethering.getTetherableWifiRegexs();
   1507         } else {
   1508             return new String[0];
   1509         }
   1510     }
   1511 
   1512     // TODO - move iface listing, queries, etc to new module
   1513     // javadoc from interface
   1514     public String[] getTetherableIfaces() {
   1515         enforceTetherAccessPermission();
   1516         return mTethering.getTetherableIfaces();
   1517     }
   1518 
   1519     public String[] getTetheredIfaces() {
   1520         enforceTetherAccessPermission();
   1521         return mTethering.getTetheredIfaces();
   1522     }
   1523 
   1524     public String[] getTetheringErroredIfaces() {
   1525         enforceTetherAccessPermission();
   1526         return mTethering.getErroredIfaces();
   1527     }
   1528 
   1529     // if ro.tether.denied = true we default to no tethering
   1530     // gservices could set the secure setting to 1 though to enable it on a build where it
   1531     // had previously been turned off.
   1532     public boolean isTetheringSupported() {
   1533         enforceTetherAccessPermission();
   1534         int defaultVal = (SystemProperties.get("ro.tether.denied").equals("true") ? 0 : 1);
   1535         boolean tetherEnabledInSettings = (Settings.Secure.getInt(mContext.getContentResolver(),
   1536                 Settings.Secure.TETHER_SUPPORTED, defaultVal) != 0);
   1537         return tetherEnabledInSettings && mTetheringConfigValid;
   1538     }
   1539 }
   1540