OSDN Git Service

Remove STOPSHIP but allow seamless Handoff when possible.
[android-x86/frameworks-base.git] / services / java / com / android / server / ConnectivityService.java
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.bluetooth.BluetoothTetheringDataTracker;
20 import android.content.ContentResolver;
21 import android.content.Context;
22 import android.content.Intent;
23 import android.content.pm.PackageManager;
24 import android.database.ContentObserver;
25 import android.net.ConnectivityManager;
26 import android.net.DummyDataStateTracker;
27 import android.net.EthernetDataTracker;
28 import android.net.IConnectivityManager;
29 import android.net.LinkAddress;
30 import android.net.LinkProperties;
31 import android.net.LinkProperties.CompareAddressesResult;
32 import android.net.MobileDataStateTracker;
33 import android.net.NetworkConfig;
34 import android.net.NetworkInfo;
35 import android.net.NetworkStateTracker;
36 import android.net.NetworkUtils;
37 import android.net.Proxy;
38 import android.net.ProxyProperties;
39 import android.net.RouteInfo;
40 import android.net.vpn.VpnManager;
41 import android.net.wifi.WifiStateTracker;
42 import android.os.Binder;
43 import android.os.Handler;
44 import android.os.HandlerThread;
45 import android.os.IBinder;
46 import android.os.INetworkManagementService;
47 import android.os.Looper;
48 import android.os.Message;
49 import android.os.PowerManager;
50 import android.os.RemoteException;
51 import android.os.ServiceManager;
52 import android.os.SystemProperties;
53 import android.provider.Settings;
54 import android.text.TextUtils;
55 import android.util.EventLog;
56 import android.util.Slog;
57
58 import com.android.internal.telephony.Phone;
59 import com.android.server.connectivity.Tethering;
60
61 import java.io.FileDescriptor;
62 import java.io.FileWriter;
63 import java.io.IOException;
64 import java.io.PrintWriter;
65 import java.net.Inet6Address;
66 import java.net.InetAddress;
67 import java.net.Inet4Address;
68 import java.net.UnknownHostException;
69 import java.util.ArrayList;
70 import java.util.Collection;
71 import java.util.concurrent.atomic.AtomicBoolean;
72 import java.util.GregorianCalendar;
73 import java.util.List;
74
75 /**
76  * @hide
77  */
78 public class ConnectivityService extends IConnectivityManager.Stub {
79
80     private static final boolean DBG = true;
81     private static final boolean VDBG = true;
82     private static final String TAG = "ConnectivityService";
83
84     // how long to wait before switching back to a radio's default network
85     private static final int RESTORE_DEFAULT_NETWORK_DELAY = 1 * 60 * 1000;
86     // system property that can override the above value
87     private static final String NETWORK_RESTORE_DELAY_PROP_NAME =
88             "android.telephony.apn-restore";
89
90     // used in recursive route setting to add gateways for the host for which
91     // a host route was requested.
92     private static final int MAX_HOSTROUTE_CYCLE_COUNT = 10;
93
94     private Tethering mTethering;
95     private boolean mTetheringConfigValid = false;
96
97     /**
98      * Sometimes we want to refer to the individual network state
99      * trackers separately, and sometimes we just want to treat them
100      * abstractly.
101      */
102     private NetworkStateTracker mNetTrackers[];
103
104     /**
105      * The link properties that define the current links
106      */
107     private LinkProperties mCurrentLinkProperties[];
108
109     /**
110      * A per Net list of the PID's that requested access to the net
111      * used both as a refcount and for per-PID DNS selection
112      */
113     private List mNetRequestersPids[];
114
115     private WifiWatchdogService mWifiWatchdogService;
116
117     // priority order of the nettrackers
118     // (excluding dynamically set mNetworkPreference)
119     // TODO - move mNetworkTypePreference into this
120     private int[] mPriorityList;
121
122     private Context mContext;
123     private int mNetworkPreference;
124     private int mActiveDefaultNetwork = -1;
125     // 0 is full bad, 100 is full good
126     private int mDefaultInetCondition = 0;
127     private int mDefaultInetConditionPublished = 0;
128     private boolean mInetConditionChangeInFlight = false;
129     private int mDefaultConnectionSequence = 0;
130
131     private int mNumDnsEntries;
132
133     private boolean mTestMode;
134     private static ConnectivityService sServiceInstance;
135
136     private AtomicBoolean mBackgroundDataEnabled = new AtomicBoolean(true);
137
138     private INetworkManagementService mNetd;
139
140     private static final int ENABLED  = 1;
141     private static final int DISABLED = 0;
142
143     // Share the event space with NetworkStateTracker (which can't see this
144     // internal class but sends us events).  If you change these, change
145     // NetworkStateTracker.java too.
146     private static final int MIN_NETWORK_STATE_TRACKER_EVENT = 1;
147     private static final int MAX_NETWORK_STATE_TRACKER_EVENT = 100;
148
149     /**
150      * used internally as a delayed event to make us switch back to the
151      * default network
152      */
153     private static final int EVENT_RESTORE_DEFAULT_NETWORK =
154             MAX_NETWORK_STATE_TRACKER_EVENT + 1;
155
156     /**
157      * used internally to change our mobile data enabled flag
158      */
159     private static final int EVENT_CHANGE_MOBILE_DATA_ENABLED =
160             MAX_NETWORK_STATE_TRACKER_EVENT + 2;
161
162     /**
163      * used internally to change our network preference setting
164      * arg1 = networkType to prefer
165      */
166     private static final int EVENT_SET_NETWORK_PREFERENCE =
167             MAX_NETWORK_STATE_TRACKER_EVENT + 3;
168
169     /**
170      * used internally to synchronize inet condition reports
171      * arg1 = networkType
172      * arg2 = condition (0 bad, 100 good)
173      */
174     private static final int EVENT_INET_CONDITION_CHANGE =
175             MAX_NETWORK_STATE_TRACKER_EVENT + 4;
176
177     /**
178      * used internally to mark the end of inet condition hold periods
179      * arg1 = networkType
180      */
181     private static final int EVENT_INET_CONDITION_HOLD_END =
182             MAX_NETWORK_STATE_TRACKER_EVENT + 5;
183
184     /**
185      * used internally to set the background data preference
186      * arg1 = TRUE for enabled, FALSE for disabled
187      */
188     private static final int EVENT_SET_BACKGROUND_DATA =
189             MAX_NETWORK_STATE_TRACKER_EVENT + 6;
190
191     /**
192      * used internally to set enable/disable cellular data
193      * arg1 = ENBALED or DISABLED
194      */
195     private static final int EVENT_SET_MOBILE_DATA =
196             MAX_NETWORK_STATE_TRACKER_EVENT + 7;
197
198     /**
199      * used internally to clear a wakelock when transitioning
200      * from one net to another
201      */
202     private static final int EVENT_CLEAR_NET_TRANSITION_WAKELOCK =
203             MAX_NETWORK_STATE_TRACKER_EVENT + 8;
204
205     /**
206      * used internally to reload global proxy settings
207      */
208     private static final int EVENT_APPLY_GLOBAL_HTTP_PROXY =
209             MAX_NETWORK_STATE_TRACKER_EVENT + 9;
210
211     /**
212      * used internally to set external dependency met/unmet
213      * arg1 = ENABLED (met) or DISABLED (unmet)
214      * arg2 = NetworkType
215      */
216     private static final int EVENT_SET_DEPENDENCY_MET =
217             MAX_NETWORK_STATE_TRACKER_EVENT + 10;
218
219     private Handler mHandler;
220
221     // list of DeathRecipients used to make sure features are turned off when
222     // a process dies
223     private List mFeatureUsers;
224
225     private boolean mSystemReady;
226     private Intent mInitialBroadcast;
227
228     private PowerManager.WakeLock mNetTransitionWakeLock;
229     private String mNetTransitionWakeLockCausedBy = "";
230     private int mNetTransitionWakeLockSerialNumber;
231     private int mNetTransitionWakeLockTimeout;
232
233     private InetAddress mDefaultDns;
234
235     // used in DBG mode to track inet condition reports
236     private static final int INET_CONDITION_LOG_MAX_SIZE = 15;
237     private ArrayList mInetLog;
238
239     // track the current default http proxy - tell the world if we get a new one (real change)
240     private ProxyProperties mDefaultProxy = null;
241     // track the global proxy.
242     private ProxyProperties mGlobalProxy = null;
243     private final Object mGlobalProxyLock = new Object();
244
245     private SettingsObserver mSettingsObserver;
246
247     NetworkConfig[] mNetConfigs;
248     int mNetworksDefined;
249
250     private static class RadioAttributes {
251         public int mSimultaneity;
252         public int mType;
253         public RadioAttributes(String init) {
254             String fragments[] = init.split(",");
255             mType = Integer.parseInt(fragments[0]);
256             mSimultaneity = Integer.parseInt(fragments[1]);
257         }
258     }
259     RadioAttributes[] mRadioAttributes;
260
261     // the set of network types that can only be enabled by system/sig apps
262     List mProtectedNetworks;
263
264     public static synchronized ConnectivityService getInstance(Context context) {
265         if (sServiceInstance == null) {
266             sServiceInstance = new ConnectivityService(context);
267         }
268         return sServiceInstance;
269     }
270
271     private ConnectivityService(Context context) {
272         if (DBG) log("ConnectivityService starting up");
273
274         HandlerThread handlerThread = new HandlerThread("ConnectivityServiceThread");
275         handlerThread.start();
276         mHandler = new MyHandler(handlerThread.getLooper());
277
278         mBackgroundDataEnabled.set(Settings.Secure.getInt(context.getContentResolver(),
279                 Settings.Secure.BACKGROUND_DATA, 1) == 1);
280
281         // setup our unique device name
282         if (TextUtils.isEmpty(SystemProperties.get("net.hostname"))) {
283             String id = Settings.Secure.getString(context.getContentResolver(),
284                     Settings.Secure.ANDROID_ID);
285             if (id != null && id.length() > 0) {
286                 String name = new String("android_").concat(id);
287                 SystemProperties.set("net.hostname", name);
288             }
289         }
290
291         // read our default dns server ip
292         String dns = Settings.Secure.getString(context.getContentResolver(),
293                 Settings.Secure.DEFAULT_DNS_SERVER);
294         if (dns == null || dns.length() == 0) {
295             dns = context.getResources().getString(
296                     com.android.internal.R.string.config_default_dns_server);
297         }
298         try {
299             mDefaultDns = NetworkUtils.numericToInetAddress(dns);
300         } catch (IllegalArgumentException e) {
301             loge("Error setting defaultDns using " + dns);
302         }
303
304         mContext = context;
305
306         PowerManager powerManager = (PowerManager)mContext.getSystemService(Context.POWER_SERVICE);
307         mNetTransitionWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
308         mNetTransitionWakeLockTimeout = mContext.getResources().getInteger(
309                 com.android.internal.R.integer.config_networkTransitionTimeout);
310
311         mNetTrackers = new NetworkStateTracker[
312                 ConnectivityManager.MAX_NETWORK_TYPE+1];
313         mCurrentLinkProperties = new LinkProperties[ConnectivityManager.MAX_NETWORK_TYPE+1];
314
315         mNetworkPreference = getPersistedNetworkPreference();
316
317         mRadioAttributes = new RadioAttributes[ConnectivityManager.MAX_RADIO_TYPE+1];
318         mNetConfigs = new NetworkConfig[ConnectivityManager.MAX_NETWORK_TYPE+1];
319
320         // Load device network attributes from resources
321         String[] raStrings = context.getResources().getStringArray(
322                 com.android.internal.R.array.radioAttributes);
323         for (String raString : raStrings) {
324             RadioAttributes r = new RadioAttributes(raString);
325             if (r.mType > ConnectivityManager.MAX_RADIO_TYPE) {
326                 loge("Error in radioAttributes - ignoring attempt to define type " + r.mType);
327                 continue;
328             }
329             if (mRadioAttributes[r.mType] != null) {
330                 loge("Error in radioAttributes - ignoring attempt to redefine type " +
331                         r.mType);
332                 continue;
333             }
334             mRadioAttributes[r.mType] = r;
335         }
336
337         String[] naStrings = context.getResources().getStringArray(
338                 com.android.internal.R.array.networkAttributes);
339         for (String naString : naStrings) {
340             try {
341                 NetworkConfig n = new NetworkConfig(naString);
342                 if (n.type > ConnectivityManager.MAX_NETWORK_TYPE) {
343                     loge("Error in networkAttributes - ignoring attempt to define type " +
344                             n.type);
345                     continue;
346                 }
347                 if (mNetConfigs[n.type] != null) {
348                     loge("Error in networkAttributes - ignoring attempt to redefine type " +
349                             n.type);
350                     continue;
351                 }
352                 if (mRadioAttributes[n.radio] == null) {
353                     loge("Error in networkAttributes - ignoring attempt to use undefined " +
354                             "radio " + n.radio + " in network type " + n.type);
355                     continue;
356                 }
357                 mNetConfigs[n.type] = n;
358                 mNetworksDefined++;
359             } catch(Exception e) {
360                 // ignore it - leave the entry null
361             }
362         }
363
364         mProtectedNetworks = new ArrayList<Integer>();
365         int[] protectedNetworks = context.getResources().getIntArray(
366                 com.android.internal.R.array.config_protectedNetworks);
367         for (int p : protectedNetworks) {
368             if ((mNetConfigs[p] != null) && (mProtectedNetworks.contains(p) == false)) {
369                 mProtectedNetworks.add(p);
370             } else {
371                 if (DBG) loge("Ignoring protectedNetwork " + p);
372             }
373         }
374
375         // high priority first
376         mPriorityList = new int[mNetworksDefined];
377         {
378             int insertionPoint = mNetworksDefined-1;
379             int currentLowest = 0;
380             int nextLowest = 0;
381             while (insertionPoint > -1) {
382                 for (NetworkConfig na : mNetConfigs) {
383                     if (na == null) continue;
384                     if (na.priority < currentLowest) continue;
385                     if (na.priority > currentLowest) {
386                         if (na.priority < nextLowest || nextLowest == 0) {
387                             nextLowest = na.priority;
388                         }
389                         continue;
390                     }
391                     mPriorityList[insertionPoint--] = na.type;
392                 }
393                 currentLowest = nextLowest;
394                 nextLowest = 0;
395             }
396         }
397
398         mNetRequestersPids = new ArrayList[ConnectivityManager.MAX_NETWORK_TYPE+1];
399         for (int i : mPriorityList) {
400             mNetRequestersPids[i] = new ArrayList();
401         }
402
403         mFeatureUsers = new ArrayList();
404
405         mNumDnsEntries = 0;
406
407         mTestMode = SystemProperties.get("cm.test.mode").equals("true")
408                 && SystemProperties.get("ro.build.type").equals("eng");
409         /*
410          * Create the network state trackers for Wi-Fi and mobile
411          * data. Maybe this could be done with a factory class,
412          * but it's not clear that it's worth it, given that
413          * the number of different network types is not going
414          * to change very often.
415          */
416         for (int netType : mPriorityList) {
417             switch (mNetConfigs[netType].radio) {
418             case ConnectivityManager.TYPE_WIFI:
419                 if (DBG) log("Starting Wifi Service.");
420                 WifiStateTracker wst = new WifiStateTracker();
421                 WifiService wifiService = new WifiService(context);
422                 ServiceManager.addService(Context.WIFI_SERVICE, wifiService);
423                 wifiService.checkAndStartWifi();
424                 mNetTrackers[ConnectivityManager.TYPE_WIFI] = wst;
425                 wst.startMonitoring(context, mHandler);
426
427                 //TODO: as part of WWS refactor, create only when needed
428                 mWifiWatchdogService = new WifiWatchdogService(context);
429
430                 break;
431             case ConnectivityManager.TYPE_MOBILE:
432                 mNetTrackers[netType] = new MobileDataStateTracker(netType,
433                         mNetConfigs[netType].name);
434                 mNetTrackers[netType].startMonitoring(context, mHandler);
435                 break;
436             case ConnectivityManager.TYPE_DUMMY:
437                 mNetTrackers[netType] = new DummyDataStateTracker(netType,
438                         mNetConfigs[netType].name);
439                 mNetTrackers[netType].startMonitoring(context, mHandler);
440                 break;
441             case ConnectivityManager.TYPE_BLUETOOTH:
442                 mNetTrackers[netType] = BluetoothTetheringDataTracker.getInstance();
443                 mNetTrackers[netType].startMonitoring(context, mHandler);
444                 break;
445             case ConnectivityManager.TYPE_ETHERNET:
446                 mNetTrackers[netType] = EthernetDataTracker.getInstance();
447                 mNetTrackers[netType].startMonitoring(context, mHandler);
448                 break;
449             default:
450                 loge("Trying to create a DataStateTracker for an unknown radio type " +
451                         mNetConfigs[netType].radio);
452                 continue;
453             }
454             mCurrentLinkProperties[netType] = mNetTrackers[netType].getLinkProperties();
455         }
456
457         mTethering = new Tethering(mContext, mHandler.getLooper());
458         mTetheringConfigValid = ((mTethering.getTetherableUsbRegexs().length != 0 ||
459                                   mTethering.getTetherableWifiRegexs().length != 0 ||
460                                   mTethering.getTetherableBluetoothRegexs().length != 0) &&
461                                  mTethering.getUpstreamIfaceTypes().length != 0);
462
463         if (DBG) {
464             mInetLog = new ArrayList();
465         }
466
467         mSettingsObserver = new SettingsObserver(mHandler, EVENT_APPLY_GLOBAL_HTTP_PROXY);
468         mSettingsObserver.observe(mContext);
469
470         loadGlobalProxy();
471
472         VpnManager.startVpnService(context);
473     }
474
475
476     /**
477      * Sets the preferred network.
478      * @param preference the new preference
479      */
480     public void setNetworkPreference(int preference) {
481         enforceChangePermission();
482
483         mHandler.sendMessage(mHandler.obtainMessage(EVENT_SET_NETWORK_PREFERENCE, preference, 0));
484     }
485
486     public int getNetworkPreference() {
487         enforceAccessPermission();
488         int preference;
489         synchronized(this) {
490             preference = mNetworkPreference;
491         }
492         return preference;
493     }
494
495     private void handleSetNetworkPreference(int preference) {
496         if (ConnectivityManager.isNetworkTypeValid(preference) &&
497                 mNetConfigs[preference] != null &&
498                 mNetConfigs[preference].isDefault()) {
499             if (mNetworkPreference != preference) {
500                 final ContentResolver cr = mContext.getContentResolver();
501                 Settings.Secure.putInt(cr, Settings.Secure.NETWORK_PREFERENCE, preference);
502                 synchronized(this) {
503                     mNetworkPreference = preference;
504                 }
505                 enforcePreference();
506             }
507         }
508     }
509
510     private int getPersistedNetworkPreference() {
511         final ContentResolver cr = mContext.getContentResolver();
512
513         final int networkPrefSetting = Settings.Secure
514                 .getInt(cr, Settings.Secure.NETWORK_PREFERENCE, -1);
515         if (networkPrefSetting != -1) {
516             return networkPrefSetting;
517         }
518
519         return ConnectivityManager.DEFAULT_NETWORK_PREFERENCE;
520     }
521
522     /**
523      * Make the state of network connectivity conform to the preference settings
524      * In this method, we only tear down a non-preferred network. Establishing
525      * a connection to the preferred network is taken care of when we handle
526      * the disconnect event from the non-preferred network
527      * (see {@link #handleDisconnect(NetworkInfo)}).
528      */
529     private void enforcePreference() {
530         if (mNetTrackers[mNetworkPreference].getNetworkInfo().isConnected())
531             return;
532
533         if (!mNetTrackers[mNetworkPreference].isAvailable())
534             return;
535
536         for (int t=0; t <= ConnectivityManager.MAX_RADIO_TYPE; t++) {
537             if (t != mNetworkPreference && mNetTrackers[t] != null &&
538                     mNetTrackers[t].getNetworkInfo().isConnected()) {
539                 if (DBG) {
540                     log("tearing down " + mNetTrackers[t].getNetworkInfo() +
541                             " in enforcePreference");
542                 }
543                 teardown(mNetTrackers[t]);
544             }
545         }
546     }
547
548     private boolean teardown(NetworkStateTracker netTracker) {
549         if (netTracker.teardown()) {
550             netTracker.setTeardownRequested(true);
551             return true;
552         } else {
553             return false;
554         }
555     }
556
557     /**
558      * Return NetworkInfo for the active (i.e., connected) network interface.
559      * It is assumed that at most one network is active at a time. If more
560      * than one is active, it is indeterminate which will be returned.
561      * @return the info for the active network, or {@code null} if none is
562      * active
563      */
564     public NetworkInfo getActiveNetworkInfo() {
565         return getNetworkInfo(mActiveDefaultNetwork);
566     }
567
568     public NetworkInfo getNetworkInfo(int networkType) {
569         enforceAccessPermission();
570         if (ConnectivityManager.isNetworkTypeValid(networkType)) {
571             NetworkStateTracker t = mNetTrackers[networkType];
572             if (t != null)
573                 return t.getNetworkInfo();
574         }
575         return null;
576     }
577
578     public NetworkInfo[] getAllNetworkInfo() {
579         enforceAccessPermission();
580         NetworkInfo[] result = new NetworkInfo[mNetworksDefined];
581         int i = 0;
582         for (NetworkStateTracker t : mNetTrackers) {
583             if(t != null) result[i++] = t.getNetworkInfo();
584         }
585         return result;
586     }
587
588     /**
589      * Return LinkProperties for the active (i.e., connected) default
590      * network interface.  It is assumed that at most one default network
591      * is active at a time. If more than one is active, it is indeterminate
592      * which will be returned.
593      * @return the ip properties for the active network, or {@code null} if
594      * none is active
595      */
596     public LinkProperties getActiveLinkProperties() {
597         return getLinkProperties(mActiveDefaultNetwork);
598     }
599
600     public LinkProperties getLinkProperties(int networkType) {
601         enforceAccessPermission();
602         if (ConnectivityManager.isNetworkTypeValid(networkType)) {
603             NetworkStateTracker t = mNetTrackers[networkType];
604             if (t != null) return t.getLinkProperties();
605         }
606         return null;
607     }
608
609     public boolean setRadios(boolean turnOn) {
610         boolean result = true;
611         enforceChangePermission();
612         for (NetworkStateTracker t : mNetTrackers) {
613             if (t != null) result = t.setRadio(turnOn) && result;
614         }
615         return result;
616     }
617
618     public boolean setRadio(int netType, boolean turnOn) {
619         enforceChangePermission();
620         if (!ConnectivityManager.isNetworkTypeValid(netType)) {
621             return false;
622         }
623         NetworkStateTracker tracker = mNetTrackers[netType];
624         return tracker != null && tracker.setRadio(turnOn);
625     }
626
627     /**
628      * Used to notice when the calling process dies so we can self-expire
629      *
630      * Also used to know if the process has cleaned up after itself when
631      * our auto-expire timer goes off.  The timer has a link to an object.
632      *
633      */
634     private class FeatureUser implements IBinder.DeathRecipient {
635         int mNetworkType;
636         String mFeature;
637         IBinder mBinder;
638         int mPid;
639         int mUid;
640         long mCreateTime;
641
642         FeatureUser(int type, String feature, IBinder binder) {
643             super();
644             mNetworkType = type;
645             mFeature = feature;
646             mBinder = binder;
647             mPid = getCallingPid();
648             mUid = getCallingUid();
649             mCreateTime = System.currentTimeMillis();
650
651             try {
652                 mBinder.linkToDeath(this, 0);
653             } catch (RemoteException e) {
654                 binderDied();
655             }
656         }
657
658         void unlinkDeathRecipient() {
659             mBinder.unlinkToDeath(this, 0);
660         }
661
662         public void binderDied() {
663             log("ConnectivityService FeatureUser binderDied(" +
664                     mNetworkType + ", " + mFeature + ", " + mBinder + "), created " +
665                     (System.currentTimeMillis() - mCreateTime) + " mSec ago");
666             stopUsingNetworkFeature(this, false);
667         }
668
669         public void expire() {
670             log("ConnectivityService FeatureUser expire(" +
671                     mNetworkType + ", " + mFeature + ", " + mBinder +"), created " +
672                     (System.currentTimeMillis() - mCreateTime) + " mSec ago");
673             stopUsingNetworkFeature(this, false);
674         }
675
676         public String toString() {
677             return "FeatureUser("+mNetworkType+","+mFeature+","+mPid+","+mUid+"), created " +
678                     (System.currentTimeMillis() - mCreateTime) + " mSec ago";
679         }
680     }
681
682     // javadoc from interface
683     public int startUsingNetworkFeature(int networkType, String feature,
684             IBinder binder) {
685         if (DBG) {
686             log("startUsingNetworkFeature for net " + networkType + ": " + feature);
687         }
688         enforceChangePermission();
689         if (!ConnectivityManager.isNetworkTypeValid(networkType) ||
690                 mNetConfigs[networkType] == null) {
691             return Phone.APN_REQUEST_FAILED;
692         }
693
694         FeatureUser f = new FeatureUser(networkType, feature, binder);
695
696         // TODO - move this into the MobileDataStateTracker
697         int usedNetworkType = networkType;
698         if(networkType == ConnectivityManager.TYPE_MOBILE) {
699             usedNetworkType = convertFeatureToNetworkType(feature);
700             if (usedNetworkType < 0) {
701                 Slog.e(TAG, "Can't match any netTracker!");
702                 usedNetworkType = networkType;
703             }
704         }
705
706         if (mProtectedNetworks.contains(usedNetworkType)) {
707             enforceConnectivityInternalPermission();
708         }
709
710         NetworkStateTracker network = mNetTrackers[usedNetworkType];
711         if (network != null) {
712             Integer currentPid = new Integer(getCallingPid());
713             if (usedNetworkType != networkType) {
714                 NetworkStateTracker radio = mNetTrackers[networkType];
715                 NetworkInfo ni = network.getNetworkInfo();
716
717                 if (ni.isAvailable() == false) {
718                     if (DBG) log("special network not available");
719                     if (!TextUtils.equals(feature,Phone.FEATURE_ENABLE_DUN_ALWAYS)) {
720                         return Phone.APN_TYPE_NOT_AVAILABLE;
721                     } else {
722                         // else make the attempt anyway - probably giving REQUEST_STARTED below
723                     }
724                 }
725
726                 synchronized(this) {
727                     mFeatureUsers.add(f);
728                     if (!mNetRequestersPids[usedNetworkType].contains(currentPid)) {
729                         // this gets used for per-pid dns when connected
730                         mNetRequestersPids[usedNetworkType].add(currentPid);
731                     }
732                 }
733
734                 int restoreTimer = getRestoreDefaultNetworkDelay(usedNetworkType);
735
736                 if (restoreTimer >= 0) {
737                     mHandler.sendMessageDelayed(
738                             mHandler.obtainMessage(EVENT_RESTORE_DEFAULT_NETWORK, f), restoreTimer);
739                 }
740
741                 if ((ni.isConnectedOrConnecting() == true) &&
742                         !network.isTeardownRequested()) {
743                     if (ni.isConnected() == true) {
744                         // add the pid-specific dns
745                         handleDnsConfigurationChange(networkType);
746                         if (DBG) log("special network already active");
747                         return Phone.APN_ALREADY_ACTIVE;
748                     }
749                     if (DBG) log("special network already connecting");
750                     return Phone.APN_REQUEST_STARTED;
751                 }
752
753                 // check if the radio in play can make another contact
754                 // assume if cannot for now
755
756                 if (DBG) log("reconnecting to special network");
757                 network.reconnect();
758                 return Phone.APN_REQUEST_STARTED;
759             } else {
760                 // need to remember this unsupported request so we respond appropriately on stop
761                 synchronized(this) {
762                     mFeatureUsers.add(f);
763                     if (!mNetRequestersPids[usedNetworkType].contains(currentPid)) {
764                         // this gets used for per-pid dns when connected
765                         mNetRequestersPids[usedNetworkType].add(currentPid);
766                     }
767                 }
768                 return -1;
769             }
770         }
771         return Phone.APN_TYPE_NOT_AVAILABLE;
772     }
773
774     // javadoc from interface
775     public int stopUsingNetworkFeature(int networkType, String feature) {
776         enforceChangePermission();
777
778         int pid = getCallingPid();
779         int uid = getCallingUid();
780
781         FeatureUser u = null;
782         boolean found = false;
783
784         synchronized(this) {
785             for (int i = 0; i < mFeatureUsers.size() ; i++) {
786                 u = (FeatureUser)mFeatureUsers.get(i);
787                 if (uid == u.mUid && pid == u.mPid &&
788                         networkType == u.mNetworkType &&
789                         TextUtils.equals(feature, u.mFeature)) {
790                     found = true;
791                     break;
792                 }
793             }
794         }
795         if (found && u != null) {
796             // stop regardless of how many other time this proc had called start
797             return stopUsingNetworkFeature(u, true);
798         } else {
799             // none found!
800             if (DBG) log("ignoring stopUsingNetworkFeature - not a live request");
801             return 1;
802         }
803     }
804
805     private int stopUsingNetworkFeature(FeatureUser u, boolean ignoreDups) {
806         int networkType = u.mNetworkType;
807         String feature = u.mFeature;
808         int pid = u.mPid;
809         int uid = u.mUid;
810
811         NetworkStateTracker tracker = null;
812         boolean callTeardown = false;  // used to carry our decision outside of sync block
813
814         if (DBG) {
815             log("stopUsingNetworkFeature for net " + networkType +
816                     ": " + feature);
817         }
818
819         if (!ConnectivityManager.isNetworkTypeValid(networkType)) {
820             return -1;
821         }
822
823         // need to link the mFeatureUsers list with the mNetRequestersPids state in this
824         // sync block
825         synchronized(this) {
826             // check if this process still has an outstanding start request
827             if (!mFeatureUsers.contains(u)) {
828                 if (DBG) log("ignoring - this process has no outstanding requests");
829                 return 1;
830             }
831             u.unlinkDeathRecipient();
832             mFeatureUsers.remove(mFeatureUsers.indexOf(u));
833             // If we care about duplicate requests, check for that here.
834             //
835             // This is done to support the extension of a request - the app
836             // can request we start the network feature again and renew the
837             // auto-shutoff delay.  Normal "stop" calls from the app though
838             // do not pay attention to duplicate requests - in effect the
839             // API does not refcount and a single stop will counter multiple starts.
840             if (ignoreDups == false) {
841                 for (int i = 0; i < mFeatureUsers.size() ; i++) {
842                     FeatureUser x = (FeatureUser)mFeatureUsers.get(i);
843                     if (x.mUid == u.mUid && x.mPid == u.mPid &&
844                             x.mNetworkType == u.mNetworkType &&
845                             TextUtils.equals(x.mFeature, u.mFeature)) {
846                         if (DBG) log("ignoring stopUsingNetworkFeature as dup is found");
847                         return 1;
848                     }
849                 }
850             }
851
852             // TODO - move to MobileDataStateTracker
853             int usedNetworkType = networkType;
854             if (networkType == ConnectivityManager.TYPE_MOBILE) {
855                 usedNetworkType = convertFeatureToNetworkType(feature);
856                 if (usedNetworkType < 0) {
857                     usedNetworkType = networkType;
858                 }
859             }
860             tracker =  mNetTrackers[usedNetworkType];
861             if (tracker == null) {
862                 if (DBG) log("ignoring - no known tracker for net type " + usedNetworkType);
863                 return -1;
864             }
865             if (usedNetworkType != networkType) {
866                 Integer currentPid = new Integer(pid);
867                 mNetRequestersPids[usedNetworkType].remove(currentPid);
868                 reassessPidDns(pid, true);
869                 if (mNetRequestersPids[usedNetworkType].size() != 0) {
870                     if (DBG) log("not tearing down special network - " +
871                            "others still using it");
872                     return 1;
873                 }
874                 callTeardown = true;
875             } else {
876                 if (DBG) log("not a known feature - dropping");
877             }
878         }
879         if (DBG) log("Doing network teardown");
880         if (callTeardown) {
881             tracker.teardown();
882             return 1;
883         } else {
884             return -1;
885         }
886     }
887
888     /**
889      * @deprecated use requestRouteToHostAddress instead
890      *
891      * Ensure that a network route exists to deliver traffic to the specified
892      * host via the specified network interface.
893      * @param networkType the type of the network over which traffic to the
894      * specified host is to be routed
895      * @param hostAddress the IP address of the host to which the route is
896      * desired
897      * @return {@code true} on success, {@code false} on failure
898      */
899     public boolean requestRouteToHost(int networkType, int hostAddress) {
900         InetAddress inetAddress = NetworkUtils.intToInetAddress(hostAddress);
901
902         if (inetAddress == null) {
903             return false;
904         }
905
906         return requestRouteToHostAddress(networkType, inetAddress.getAddress());
907     }
908
909     /**
910      * Ensure that a network route exists to deliver traffic to the specified
911      * host via the specified network interface.
912      * @param networkType the type of the network over which traffic to the
913      * specified host is to be routed
914      * @param hostAddress the IP address of the host to which the route is
915      * desired
916      * @return {@code true} on success, {@code false} on failure
917      */
918     public boolean requestRouteToHostAddress(int networkType, byte[] hostAddress) {
919         enforceChangePermission();
920         if (mProtectedNetworks.contains(networkType)) {
921             enforceConnectivityInternalPermission();
922         }
923
924         if (!ConnectivityManager.isNetworkTypeValid(networkType)) {
925             return false;
926         }
927         NetworkStateTracker tracker = mNetTrackers[networkType];
928
929         if (tracker == null || !tracker.getNetworkInfo().isConnected() ||
930                 tracker.isTeardownRequested()) {
931             if (DBG) {
932                 log("requestRouteToHostAddress on down network " +
933                            "(" + networkType + ") - dropped");
934             }
935             return false;
936         }
937         try {
938             InetAddress addr = InetAddress.getByAddress(hostAddress);
939             return addHostRoute(tracker, addr, 0);
940         } catch (UnknownHostException e) {}
941         return false;
942     }
943
944     /**
945      * Ensure that a network route exists to deliver traffic to the specified
946      * host via the mobile data network.
947      * @param hostAddress the IP address of the host to which the route is desired,
948      * in network byte order.
949      * TODO - deprecate
950      * @return {@code true} on success, {@code false} on failure
951      */
952     private boolean addHostRoute(NetworkStateTracker nt, InetAddress hostAddress, int cycleCount) {
953         LinkProperties lp = nt.getLinkProperties();
954         if ((lp == null) || (hostAddress == null)) return false;
955
956         String interfaceName = lp.getInterfaceName();
957         if (DBG) {
958             log("Requested host route to " + hostAddress + "(" + interfaceName + "), cycleCount=" +
959                     cycleCount);
960         }
961         if (interfaceName == null) {
962             if (DBG) loge("addHostRoute failed due to null interface name");
963             return false;
964         }
965
966         RouteInfo bestRoute = RouteInfo.selectBestRoute(lp.getRoutes(), hostAddress);
967         InetAddress gatewayAddress = null;
968         if (bestRoute != null) {
969             gatewayAddress = bestRoute.getGateway();
970             // if the best route is ourself, don't relf-reference, just add the host route
971             if (hostAddress.equals(gatewayAddress)) gatewayAddress = null;
972         }
973         if (gatewayAddress != null) {
974             if (cycleCount > MAX_HOSTROUTE_CYCLE_COUNT) {
975                 loge("Error adding hostroute - too much recursion");
976                 return false;
977             }
978             if (!addHostRoute(nt, gatewayAddress, cycleCount+1)) return false;
979         }
980
981         RouteInfo route = RouteInfo.makeHostRoute(hostAddress, gatewayAddress);
982
983         try {
984             mNetd.addRoute(interfaceName, route);
985             return true;
986         } catch (Exception ex) {
987             return false;
988         }
989     }
990
991     // TODO support the removal of single host routes.  Keep a ref count of them so we
992     // aren't over-zealous
993     private boolean removeHostRoute(NetworkStateTracker nt, InetAddress hostAddress) {
994         return false;
995     }
996
997     /**
998      * @see ConnectivityManager#getBackgroundDataSetting()
999      */
1000     public boolean getBackgroundDataSetting() {
1001         return mBackgroundDataEnabled.get();
1002     }
1003
1004     /**
1005      * @see ConnectivityManager#setBackgroundDataSetting(boolean)
1006      */
1007     public void setBackgroundDataSetting(boolean allowBackgroundDataUsage) {
1008         mContext.enforceCallingOrSelfPermission(
1009                 android.Manifest.permission.CHANGE_BACKGROUND_DATA_SETTING,
1010                 "ConnectivityService");
1011
1012         mBackgroundDataEnabled.set(allowBackgroundDataUsage);
1013
1014         mHandler.sendMessage(mHandler.obtainMessage(EVENT_SET_BACKGROUND_DATA,
1015                 (allowBackgroundDataUsage ? ENABLED : DISABLED), 0));
1016     }
1017
1018     private void handleSetBackgroundData(boolean enabled) {
1019         Settings.Secure.putInt(mContext.getContentResolver(),
1020                 Settings.Secure.BACKGROUND_DATA, enabled ? 1 : 0);
1021         Intent broadcast = new Intent(
1022                 ConnectivityManager.ACTION_BACKGROUND_DATA_SETTING_CHANGED);
1023         mContext.sendBroadcast(broadcast);
1024     }
1025
1026     /**
1027      * @see ConnectivityManager#getMobileDataEnabled()
1028      */
1029     public boolean getMobileDataEnabled() {
1030         // TODO: This detail should probably be in DataConnectionTracker's
1031         //       which is where we store the value and maybe make this
1032         //       asynchronous.
1033         enforceAccessPermission();
1034         boolean retVal = Settings.Secure.getInt(mContext.getContentResolver(),
1035                 Settings.Secure.MOBILE_DATA, 1) == 1;
1036         if (DBG) log("getMobileDataEnabled returning " + retVal);
1037         return retVal;
1038     }
1039
1040     public void setDataDependency(int networkType, boolean met) {
1041         enforceConnectivityInternalPermission();
1042
1043         if (DBG) {
1044             log("setDataDependency(" + networkType + ", " + met + ")");
1045         }
1046         mHandler.sendMessage(mHandler.obtainMessage(EVENT_SET_DEPENDENCY_MET,
1047                 (met ? ENABLED : DISABLED), networkType));
1048     }
1049
1050     private void handleSetDependencyMet(int networkType, boolean met) {
1051         if (mNetTrackers[networkType] != null) {
1052             if (DBG) {
1053                 log("handleSetDependencyMet(" + networkType + ", " + met + ")");
1054             }
1055             mNetTrackers[networkType].setDependencyMet(met);
1056         }
1057     }
1058
1059     /**
1060      * @see ConnectivityManager#setMobileDataEnabled(boolean)
1061      */
1062     public void setMobileDataEnabled(boolean enabled) {
1063         enforceChangePermission();
1064         if (DBG) log("setMobileDataEnabled(" + enabled + ")");
1065
1066         mHandler.sendMessage(mHandler.obtainMessage(EVENT_SET_MOBILE_DATA,
1067                 (enabled ? ENABLED : DISABLED), 0));
1068     }
1069
1070     private void handleSetMobileData(boolean enabled) {
1071         if (mNetTrackers[ConnectivityManager.TYPE_MOBILE] != null) {
1072             if (DBG) {
1073                 Slog.d(TAG, mNetTrackers[ConnectivityManager.TYPE_MOBILE].toString() + enabled);
1074             }
1075             mNetTrackers[ConnectivityManager.TYPE_MOBILE].setDataEnable(enabled);
1076         }
1077     }
1078
1079     private void enforceAccessPermission() {
1080         mContext.enforceCallingOrSelfPermission(
1081                 android.Manifest.permission.ACCESS_NETWORK_STATE,
1082                 "ConnectivityService");
1083     }
1084
1085     private void enforceChangePermission() {
1086         mContext.enforceCallingOrSelfPermission(
1087                 android.Manifest.permission.CHANGE_NETWORK_STATE,
1088                 "ConnectivityService");
1089     }
1090
1091     // TODO Make this a special check when it goes public
1092     private void enforceTetherChangePermission() {
1093         mContext.enforceCallingOrSelfPermission(
1094                 android.Manifest.permission.CHANGE_NETWORK_STATE,
1095                 "ConnectivityService");
1096     }
1097
1098     private void enforceTetherAccessPermission() {
1099         mContext.enforceCallingOrSelfPermission(
1100                 android.Manifest.permission.ACCESS_NETWORK_STATE,
1101                 "ConnectivityService");
1102     }
1103
1104     private void enforceConnectivityInternalPermission() {
1105         mContext.enforceCallingOrSelfPermission(
1106                 android.Manifest.permission.CONNECTIVITY_INTERNAL,
1107                 "ConnectivityService");
1108     }
1109
1110     /**
1111      * Handle a {@code DISCONNECTED} event. If this pertains to the non-active
1112      * network, we ignore it. If it is for the active network, we send out a
1113      * broadcast. But first, we check whether it might be possible to connect
1114      * to a different network.
1115      * @param info the {@code NetworkInfo} for the network
1116      */
1117     private void handleDisconnect(NetworkInfo info) {
1118
1119         int prevNetType = info.getType();
1120
1121         mNetTrackers[prevNetType].setTeardownRequested(false);
1122         /*
1123          * If the disconnected network is not the active one, then don't report
1124          * this as a loss of connectivity. What probably happened is that we're
1125          * getting the disconnect for a network that we explicitly disabled
1126          * in accordance with network preference policies.
1127          */
1128         if (!mNetConfigs[prevNetType].isDefault()) {
1129             List pids = mNetRequestersPids[prevNetType];
1130             for (int i = 0; i<pids.size(); i++) {
1131                 Integer pid = (Integer)pids.get(i);
1132                 // will remove them because the net's no longer connected
1133                 // need to do this now as only now do we know the pids and
1134                 // can properly null things that are no longer referenced.
1135                 reassessPidDns(pid.intValue(), false);
1136             }
1137         }
1138
1139         Intent intent = new Intent(ConnectivityManager.CONNECTIVITY_ACTION);
1140         intent.putExtra(ConnectivityManager.EXTRA_NETWORK_INFO, info);
1141         if (info.isFailover()) {
1142             intent.putExtra(ConnectivityManager.EXTRA_IS_FAILOVER, true);
1143             info.setFailover(false);
1144         }
1145         if (info.getReason() != null) {
1146             intent.putExtra(ConnectivityManager.EXTRA_REASON, info.getReason());
1147         }
1148         if (info.getExtraInfo() != null) {
1149             intent.putExtra(ConnectivityManager.EXTRA_EXTRA_INFO,
1150                     info.getExtraInfo());
1151         }
1152
1153         if (mNetConfigs[prevNetType].isDefault()) {
1154             tryFailover(prevNetType);
1155             if (mActiveDefaultNetwork != -1) {
1156                 NetworkInfo switchTo = mNetTrackers[mActiveDefaultNetwork].getNetworkInfo();
1157                 intent.putExtra(ConnectivityManager.EXTRA_OTHER_NETWORK_INFO, switchTo);
1158             } else {
1159                 mDefaultInetConditionPublished = 0; // we're not connected anymore
1160                 intent.putExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, true);
1161             }
1162         }
1163         intent.putExtra(ConnectivityManager.EXTRA_INET_CONDITION, mDefaultInetConditionPublished);
1164
1165         // Reset interface if no other connections are using the same interface
1166         boolean doReset = true;
1167         LinkProperties linkProperties = mNetTrackers[prevNetType].getLinkProperties();
1168         if (linkProperties != null) {
1169             String oldIface = linkProperties.getInterfaceName();
1170             if (TextUtils.isEmpty(oldIface) == false) {
1171                 for (NetworkStateTracker networkStateTracker : mNetTrackers) {
1172                     if (networkStateTracker == null) continue;
1173                     NetworkInfo networkInfo = networkStateTracker.getNetworkInfo();
1174                     if (networkInfo.isConnected() && networkInfo.getType() != prevNetType) {
1175                         LinkProperties l = networkStateTracker.getLinkProperties();
1176                         if (l == null) continue;
1177                         if (oldIface.equals(l.getInterfaceName())) {
1178                             doReset = false;
1179                             break;
1180                         }
1181                     }
1182                 }
1183             }
1184         }
1185
1186         // do this before we broadcast the change
1187         handleConnectivityChange(prevNetType, doReset);
1188
1189         sendStickyBroadcast(intent);
1190         /*
1191          * If the failover network is already connected, then immediately send
1192          * out a followup broadcast indicating successful failover
1193          */
1194         if (mActiveDefaultNetwork != -1) {
1195             sendConnectedBroadcast(mNetTrackers[mActiveDefaultNetwork].getNetworkInfo());
1196         }
1197     }
1198
1199     private void tryFailover(int prevNetType) {
1200         /*
1201          * If this is a default network, check if other defaults are available.
1202          * Try to reconnect on all available and let them hash it out when
1203          * more than one connects.
1204          */
1205         if (mNetConfigs[prevNetType].isDefault()) {
1206             if (mActiveDefaultNetwork == prevNetType) {
1207                 mActiveDefaultNetwork = -1;
1208             }
1209
1210             // don't signal a reconnect for anything lower or equal priority than our
1211             // current connected default
1212             // TODO - don't filter by priority now - nice optimization but risky
1213 //            int currentPriority = -1;
1214 //            if (mActiveDefaultNetwork != -1) {
1215 //                currentPriority = mNetConfigs[mActiveDefaultNetwork].mPriority;
1216 //            }
1217             for (int checkType=0; checkType <= ConnectivityManager.MAX_NETWORK_TYPE; checkType++) {
1218                 if (checkType == prevNetType) continue;
1219                 if (mNetConfigs[checkType] == null) continue;
1220                 if (!mNetConfigs[checkType].isDefault()) continue;
1221
1222 // Enabling the isAvailable() optimization caused mobile to not get
1223 // selected if it was in the middle of error handling. Specifically
1224 // a moble connection that took 30 seconds to complete the DEACTIVATE_DATA_CALL
1225 // would not be available and we wouldn't get connected to anything.
1226 // So removing the isAvailable() optimization below for now. TODO: This
1227 // optimization should work and we need to investigate why it doesn't work.
1228 // This could be related to how DEACTIVATE_DATA_CALL is reporting its
1229 // complete before it is really complete.
1230 //                if (!mNetTrackers[checkType].isAvailable()) continue;
1231
1232 //                if (currentPriority >= mNetConfigs[checkType].mPriority) continue;
1233
1234                 NetworkStateTracker checkTracker = mNetTrackers[checkType];
1235                 NetworkInfo checkInfo = checkTracker.getNetworkInfo();
1236                 if (!checkInfo.isConnectedOrConnecting() || checkTracker.isTeardownRequested()) {
1237                     checkInfo.setFailover(true);
1238                     checkTracker.reconnect();
1239                 }
1240                 if (DBG) log("Attempting to switch to " + checkInfo.getTypeName());
1241             }
1242         }
1243     }
1244
1245     private void sendConnectedBroadcast(NetworkInfo info) {
1246         sendGeneralBroadcast(info, ConnectivityManager.CONNECTIVITY_ACTION);
1247     }
1248
1249     private void sendInetConditionBroadcast(NetworkInfo info) {
1250         sendGeneralBroadcast(info, ConnectivityManager.INET_CONDITION_ACTION);
1251     }
1252
1253     private void sendGeneralBroadcast(NetworkInfo info, String bcastType) {
1254         Intent intent = new Intent(bcastType);
1255         intent.putExtra(ConnectivityManager.EXTRA_NETWORK_INFO, info);
1256         if (info.isFailover()) {
1257             intent.putExtra(ConnectivityManager.EXTRA_IS_FAILOVER, true);
1258             info.setFailover(false);
1259         }
1260         if (info.getReason() != null) {
1261             intent.putExtra(ConnectivityManager.EXTRA_REASON, info.getReason());
1262         }
1263         if (info.getExtraInfo() != null) {
1264             intent.putExtra(ConnectivityManager.EXTRA_EXTRA_INFO,
1265                     info.getExtraInfo());
1266         }
1267         intent.putExtra(ConnectivityManager.EXTRA_INET_CONDITION, mDefaultInetConditionPublished);
1268         sendStickyBroadcast(intent);
1269     }
1270
1271     /**
1272      * Called when an attempt to fail over to another network has failed.
1273      * @param info the {@link NetworkInfo} for the failed network
1274      */
1275     private void handleConnectionFailure(NetworkInfo info) {
1276         mNetTrackers[info.getType()].setTeardownRequested(false);
1277
1278         String reason = info.getReason();
1279         String extraInfo = info.getExtraInfo();
1280
1281         String reasonText;
1282         if (reason == null) {
1283             reasonText = ".";
1284         } else {
1285             reasonText = " (" + reason + ").";
1286         }
1287         loge("Attempt to connect to " + info.getTypeName() + " failed" + reasonText);
1288
1289         Intent intent = new Intent(ConnectivityManager.CONNECTIVITY_ACTION);
1290         intent.putExtra(ConnectivityManager.EXTRA_NETWORK_INFO, info);
1291         if (getActiveNetworkInfo() == null) {
1292             intent.putExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, true);
1293         }
1294         if (reason != null) {
1295             intent.putExtra(ConnectivityManager.EXTRA_REASON, reason);
1296         }
1297         if (extraInfo != null) {
1298             intent.putExtra(ConnectivityManager.EXTRA_EXTRA_INFO, extraInfo);
1299         }
1300         if (info.isFailover()) {
1301             intent.putExtra(ConnectivityManager.EXTRA_IS_FAILOVER, true);
1302             info.setFailover(false);
1303         }
1304
1305         if (mNetConfigs[info.getType()].isDefault()) {
1306             tryFailover(info.getType());
1307             if (mActiveDefaultNetwork != -1) {
1308                 NetworkInfo switchTo = mNetTrackers[mActiveDefaultNetwork].getNetworkInfo();
1309                 intent.putExtra(ConnectivityManager.EXTRA_OTHER_NETWORK_INFO, switchTo);
1310             } else {
1311                 mDefaultInetConditionPublished = 0;
1312                 intent.putExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, true);
1313             }
1314         }
1315
1316         intent.putExtra(ConnectivityManager.EXTRA_INET_CONDITION, mDefaultInetConditionPublished);
1317         sendStickyBroadcast(intent);
1318         /*
1319          * If the failover network is already connected, then immediately send
1320          * out a followup broadcast indicating successful failover
1321          */
1322         if (mActiveDefaultNetwork != -1) {
1323             sendConnectedBroadcast(mNetTrackers[mActiveDefaultNetwork].getNetworkInfo());
1324         }
1325     }
1326
1327     private void sendStickyBroadcast(Intent intent) {
1328         synchronized(this) {
1329             if (!mSystemReady) {
1330                 mInitialBroadcast = new Intent(intent);
1331             }
1332             intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
1333             mContext.sendStickyBroadcast(intent);
1334         }
1335     }
1336
1337     void systemReady() {
1338         IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
1339         mNetd = INetworkManagementService.Stub.asInterface(b);
1340
1341         synchronized(this) {
1342             mSystemReady = true;
1343             if (mInitialBroadcast != null) {
1344                 mContext.sendStickyBroadcast(mInitialBroadcast);
1345                 mInitialBroadcast = null;
1346             }
1347         }
1348         // load the global proxy at startup
1349         mHandler.sendMessage(mHandler.obtainMessage(EVENT_APPLY_GLOBAL_HTTP_PROXY));
1350     }
1351
1352     private void handleConnect(NetworkInfo info) {
1353         int type = info.getType();
1354
1355         // snapshot isFailover, because sendConnectedBroadcast() resets it
1356         boolean isFailover = info.isFailover();
1357         NetworkStateTracker thisNet = mNetTrackers[type];
1358
1359         // if this is a default net and other default is running
1360         // kill the one not preferred
1361         if (mNetConfigs[type].isDefault()) {
1362             if (mActiveDefaultNetwork != -1 && mActiveDefaultNetwork != type) {
1363                 if ((type != mNetworkPreference &&
1364                         mNetConfigs[mActiveDefaultNetwork].priority >
1365                         mNetConfigs[type].priority) ||
1366                         mNetworkPreference == mActiveDefaultNetwork) {
1367                         // don't accept this one
1368                         if (DBG) {
1369                             log("Not broadcasting CONNECT_ACTION " +
1370                                 "to torn down network " + info.getTypeName());
1371                         }
1372                         teardown(thisNet);
1373                         return;
1374                 } else {
1375                     // tear down the other
1376                     NetworkStateTracker otherNet =
1377                             mNetTrackers[mActiveDefaultNetwork];
1378                     if (DBG) {
1379                         log("Policy requires " + otherNet.getNetworkInfo().getTypeName() +
1380                             " teardown");
1381                     }
1382                     if (!teardown(otherNet)) {
1383                         loge("Network declined teardown request");
1384                         return;
1385                     }
1386                 }
1387             }
1388             synchronized (ConnectivityService.this) {
1389                 // have a new default network, release the transition wakelock in a second
1390                 // if it's held.  The second pause is to allow apps to reconnect over the
1391                 // new network
1392                 if (mNetTransitionWakeLock.isHeld()) {
1393                     mHandler.sendMessageDelayed(mHandler.obtainMessage(
1394                             EVENT_CLEAR_NET_TRANSITION_WAKELOCK,
1395                             mNetTransitionWakeLockSerialNumber, 0),
1396                             1000);
1397                 }
1398             }
1399             mActiveDefaultNetwork = type;
1400             // this will cause us to come up initially as unconnected and switching
1401             // to connected after our normal pause unless somebody reports us as reall
1402             // disconnected
1403             mDefaultInetConditionPublished = 0;
1404             mDefaultConnectionSequence++;
1405             mInetConditionChangeInFlight = false;
1406             // Don't do this - if we never sign in stay, grey
1407             //reportNetworkCondition(mActiveDefaultNetwork, 100);
1408         }
1409         thisNet.setTeardownRequested(false);
1410         updateNetworkSettings(thisNet);
1411         handleConnectivityChange(type, false);
1412         sendConnectedBroadcast(info);
1413     }
1414
1415     /**
1416      * After a change in the connectivity state of a network. We're mainly
1417      * concerned with making sure that the list of DNS servers is set up
1418      * according to which networks are connected, and ensuring that the
1419      * right routing table entries exist.
1420      */
1421     private void handleConnectivityChange(int netType, boolean doReset) {
1422         int resetMask = doReset ? NetworkUtils.RESET_ALL_ADDRESSES : 0;
1423
1424         /*
1425          * If a non-default network is enabled, add the host routes that
1426          * will allow it's DNS servers to be accessed.
1427          */
1428         handleDnsConfigurationChange(netType);
1429
1430         if (mNetTrackers[netType].getNetworkInfo().isConnected()) {
1431             LinkProperties newLp = mNetTrackers[netType].getLinkProperties();
1432             LinkProperties curLp = mCurrentLinkProperties[netType];
1433             mCurrentLinkProperties[netType] = newLp;
1434             if (VDBG) {
1435                 log("handleConnectivityChange: changed linkProperty[" + netType + "]:" +
1436                         " doReset=" + doReset + " resetMask=" + resetMask +
1437                         "\n   curLp=" + curLp +
1438                         "\n   newLp=" + newLp);
1439             }
1440
1441             if (curLp.isIdenticalInterfaceName(newLp)) {
1442                 CompareAddressesResult car = curLp.compareAddresses(newLp);
1443                 if ((car.removed.size() != 0) || (car.added.size() != 0)) {
1444                     for (LinkAddress linkAddr : car.removed) {
1445                         if (linkAddr.getAddress() instanceof Inet4Address) {
1446                             resetMask |= NetworkUtils.RESET_IPV4_ADDRESSES;
1447                         }
1448                         if (linkAddr.getAddress() instanceof Inet6Address) {
1449                             resetMask |= NetworkUtils.RESET_IPV6_ADDRESSES;
1450                         }
1451                     }
1452                     if (DBG) {
1453                         log("handleConnectivityChange: addresses changed" +
1454                                 " linkProperty[" + netType + "]:" + " resetMask=" + resetMask +
1455                                 "\n   car=" + car);
1456                     }
1457                 } else {
1458                     if (DBG) {
1459                         log("handleConnectivityChange: address are the same reset per doReset" +
1460                                " linkProperty[" + netType + "]:" +
1461                                " resetMask=" + resetMask);
1462                     }
1463                 }
1464             } else {
1465                 resetMask = NetworkUtils.RESET_ALL_ADDRESSES;
1466                 log("handleConnectivityChange: interface not not equivalent reset both" +
1467                         " linkProperty[" + netType + "]:" +
1468                         " resetMask=" + resetMask);
1469             }
1470             if (mNetConfigs[netType].isDefault()) {
1471                 handleApplyDefaultProxy(netType);
1472                 addDefaultRoute(mNetTrackers[netType]);
1473             } else {
1474                 addPrivateDnsRoutes(mNetTrackers[netType]);
1475             }
1476         } else {
1477             if (mNetConfigs[netType].isDefault()) {
1478                 removeDefaultRoute(mNetTrackers[netType]);
1479             } else {
1480                 removePrivateDnsRoutes(mNetTrackers[netType]);
1481             }
1482         }
1483
1484         if (doReset || resetMask != 0) {
1485             LinkProperties linkProperties = mNetTrackers[netType].getLinkProperties();
1486             if (linkProperties != null) {
1487                 String iface = linkProperties.getInterfaceName();
1488                 if (TextUtils.isEmpty(iface) == false) {
1489                     if (DBG) log("resetConnections(" + iface + ", " + resetMask + ")");
1490                     NetworkUtils.resetConnections(iface, resetMask);
1491                 }
1492             }
1493         }
1494
1495         // TODO: Temporary notifying upstread change to Tethering.
1496         //       @see bug/4455071
1497         /** Notify TetheringService if interface name has been changed. */
1498         if (TextUtils.equals(mNetTrackers[netType].getNetworkInfo().getReason(),
1499                              Phone.REASON_LINK_PROPERTIES_CHANGED)) {
1500             if (isTetheringSupported()) {
1501                 mTethering.handleTetherIfaceChange();
1502             }
1503         }
1504     }
1505
1506     private void addPrivateDnsRoutes(NetworkStateTracker nt) {
1507         boolean privateDnsRouteSet = nt.isPrivateDnsRouteSet();
1508         LinkProperties p = nt.getLinkProperties();
1509         if (p == null) return;
1510         String interfaceName = p.getInterfaceName();
1511
1512         if (DBG) {
1513             log("addPrivateDnsRoutes for " + nt +
1514                     "(" + interfaceName + ") - mPrivateDnsRouteSet = " + privateDnsRouteSet);
1515         }
1516         if (interfaceName != null && !privateDnsRouteSet) {
1517             Collection<InetAddress> dnsList = p.getDnses();
1518             for (InetAddress dns : dnsList) {
1519                 addHostRoute(nt, dns, 0);
1520             }
1521             nt.privateDnsRouteSet(true);
1522         }
1523     }
1524
1525     private void removePrivateDnsRoutes(NetworkStateTracker nt) {
1526         LinkProperties p = nt.getLinkProperties();
1527         if (p == null) return;
1528         String interfaceName = p.getInterfaceName();
1529         boolean privateDnsRouteSet = nt.isPrivateDnsRouteSet();
1530         if (interfaceName != null && privateDnsRouteSet) {
1531             if (DBG) {
1532                 log("removePrivateDnsRoutes for " + nt.getNetworkInfo().getTypeName() +
1533                         " (" + interfaceName + ")");
1534             }
1535
1536             Collection<InetAddress> dnsList = p.getDnses();
1537             for (InetAddress dns : dnsList) {
1538                 if (DBG) log("  removing " + dns);
1539                 RouteInfo route = RouteInfo.makeHostRoute(dns);
1540                 try {
1541                     mNetd.removeRoute(interfaceName, route);
1542                 } catch (Exception ex) {
1543                     loge("error (" + ex + ") removing dns route " + route);
1544                 }
1545             }
1546             nt.privateDnsRouteSet(false);
1547         }
1548     }
1549
1550
1551     private void addDefaultRoute(NetworkStateTracker nt) {
1552         LinkProperties p = nt.getLinkProperties();
1553         if (p == null) return;
1554         String interfaceName = p.getInterfaceName();
1555         if (TextUtils.isEmpty(interfaceName)) return;
1556
1557         for (RouteInfo route : p.getRoutes()) {
1558             //TODO - handle non-default routes
1559             if (route.isDefaultRoute()) {
1560                 if (DBG) log("adding default route " + route);
1561                 InetAddress gateway = route.getGateway();
1562                 if (addHostRoute(nt, gateway, 0)) {
1563                     try {
1564                         mNetd.addRoute(interfaceName, route);
1565                     } catch (Exception e) {
1566                         loge("error adding default route " + route);
1567                         continue;
1568                     }
1569                     if (DBG) {
1570                         NetworkInfo networkInfo = nt.getNetworkInfo();
1571                         log("addDefaultRoute for " + networkInfo.getTypeName() +
1572                                 " (" + interfaceName + "), GatewayAddr=" +
1573                                 gateway.getHostAddress());
1574                     }
1575                 } else {
1576                     loge("error adding host route for default route " + route);
1577                 }
1578             }
1579         }
1580     }
1581
1582
1583     public void removeDefaultRoute(NetworkStateTracker nt) {
1584         LinkProperties p = nt.getLinkProperties();
1585         if (p == null) return;
1586         String interfaceName = p.getInterfaceName();
1587
1588         if (interfaceName == null) return;
1589
1590         for (RouteInfo route : p.getRoutes()) {
1591             //TODO - handle non-default routes
1592             if (route.isDefaultRoute()) {
1593                 try {
1594                     mNetd.removeRoute(interfaceName, route);
1595                 } catch (Exception ex) {
1596                     loge("error (" + ex + ") removing default route " + route);
1597                     continue;
1598                 }
1599                 if (DBG) {
1600                     NetworkInfo networkInfo = nt.getNetworkInfo();
1601                     log("removeDefaultRoute for " + networkInfo.getTypeName() + " (" +
1602                             interfaceName + ")");
1603                 }
1604             }
1605         }
1606     }
1607
1608    /**
1609      * Reads the network specific TCP buffer sizes from SystemProperties
1610      * net.tcp.buffersize.[default|wifi|umts|edge|gprs] and set them for system
1611      * wide use
1612      */
1613    public void updateNetworkSettings(NetworkStateTracker nt) {
1614         String key = nt.getTcpBufferSizesPropName();
1615         String bufferSizes = SystemProperties.get(key);
1616
1617         if (bufferSizes.length() == 0) {
1618             loge(key + " not found in system properties. Using defaults");
1619
1620             // Setting to default values so we won't be stuck to previous values
1621             key = "net.tcp.buffersize.default";
1622             bufferSizes = SystemProperties.get(key);
1623         }
1624
1625         // Set values in kernel
1626         if (bufferSizes.length() != 0) {
1627             if (DBG) {
1628                 log("Setting TCP values: [" + bufferSizes
1629                         + "] which comes from [" + key + "]");
1630             }
1631             setBufferSize(bufferSizes);
1632         }
1633     }
1634
1635    /**
1636      * Writes TCP buffer sizes to /sys/kernel/ipv4/tcp_[r/w]mem_[min/def/max]
1637      * which maps to /proc/sys/net/ipv4/tcp_rmem and tcpwmem
1638      *
1639      * @param bufferSizes in the format of "readMin, readInitial, readMax,
1640      *        writeMin, writeInitial, writeMax"
1641      */
1642     private void setBufferSize(String bufferSizes) {
1643         try {
1644             String[] values = bufferSizes.split(",");
1645
1646             if (values.length == 6) {
1647               final String prefix = "/sys/kernel/ipv4/tcp_";
1648                 stringToFile(prefix + "rmem_min", values[0]);
1649                 stringToFile(prefix + "rmem_def", values[1]);
1650                 stringToFile(prefix + "rmem_max", values[2]);
1651                 stringToFile(prefix + "wmem_min", values[3]);
1652                 stringToFile(prefix + "wmem_def", values[4]);
1653                 stringToFile(prefix + "wmem_max", values[5]);
1654             } else {
1655                 loge("Invalid buffersize string: " + bufferSizes);
1656             }
1657         } catch (IOException e) {
1658             loge("Can't set tcp buffer sizes:" + e);
1659         }
1660     }
1661
1662    /**
1663      * Writes string to file. Basically same as "echo -n $string > $filename"
1664      *
1665      * @param filename
1666      * @param string
1667      * @throws IOException
1668      */
1669     private void stringToFile(String filename, String string) throws IOException {
1670         FileWriter out = new FileWriter(filename);
1671         try {
1672             out.write(string);
1673         } finally {
1674             out.close();
1675         }
1676     }
1677
1678
1679     /**
1680      * Adjust the per-process dns entries (net.dns<x>.<pid>) based
1681      * on the highest priority active net which this process requested.
1682      * If there aren't any, clear it out
1683      */
1684     private void reassessPidDns(int myPid, boolean doBump)
1685     {
1686         if (DBG) log("reassessPidDns for pid " + myPid);
1687         for(int i : mPriorityList) {
1688             if (mNetConfigs[i].isDefault()) {
1689                 continue;
1690             }
1691             NetworkStateTracker nt = mNetTrackers[i];
1692             if (nt.getNetworkInfo().isConnected() &&
1693                     !nt.isTeardownRequested()) {
1694                 LinkProperties p = nt.getLinkProperties();
1695                 if (p == null) continue;
1696                 List pids = mNetRequestersPids[i];
1697                 for (int j=0; j<pids.size(); j++) {
1698                     Integer pid = (Integer)pids.get(j);
1699                     if (pid.intValue() == myPid) {
1700                         Collection<InetAddress> dnses = p.getDnses();
1701                         writePidDns(dnses, myPid);
1702                         if (doBump) {
1703                             bumpDns();
1704                         }
1705                         return;
1706                     }
1707                 }
1708            }
1709         }
1710         // nothing found - delete
1711         for (int i = 1; ; i++) {
1712             String prop = "net.dns" + i + "." + myPid;
1713             if (SystemProperties.get(prop).length() == 0) {
1714                 if (doBump) {
1715                     bumpDns();
1716                 }
1717                 return;
1718             }
1719             SystemProperties.set(prop, "");
1720         }
1721     }
1722
1723     // return true if results in a change
1724     private boolean writePidDns(Collection <InetAddress> dnses, int pid) {
1725         int j = 1;
1726         boolean changed = false;
1727         for (InetAddress dns : dnses) {
1728             String dnsString = dns.getHostAddress();
1729             if (changed || !dnsString.equals(SystemProperties.get("net.dns" + j + "." + pid))) {
1730                 changed = true;
1731                 SystemProperties.set("net.dns" + j++ + "." + pid, dns.getHostAddress());
1732             }
1733         }
1734         return changed;
1735     }
1736
1737     private void bumpDns() {
1738         /*
1739          * Bump the property that tells the name resolver library to reread
1740          * the DNS server list from the properties.
1741          */
1742         String propVal = SystemProperties.get("net.dnschange");
1743         int n = 0;
1744         if (propVal.length() != 0) {
1745             try {
1746                 n = Integer.parseInt(propVal);
1747             } catch (NumberFormatException e) {}
1748         }
1749         SystemProperties.set("net.dnschange", "" + (n+1));
1750         /*
1751          * Tell the VMs to toss their DNS caches
1752          */
1753         Intent intent = new Intent(Intent.ACTION_CLEAR_DNS_CACHE);
1754         intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
1755         /*
1756          * Connectivity events can happen before boot has completed ...
1757          */
1758         intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
1759         mContext.sendBroadcast(intent);
1760     }
1761
1762     private void handleDnsConfigurationChange(int netType) {
1763         // add default net's dns entries
1764         NetworkStateTracker nt = mNetTrackers[netType];
1765         if (nt != null && nt.getNetworkInfo().isConnected() && !nt.isTeardownRequested()) {
1766             LinkProperties p = nt.getLinkProperties();
1767             if (p == null) return;
1768             Collection<InetAddress> dnses = p.getDnses();
1769             boolean changed = false;
1770             if (mNetConfigs[netType].isDefault()) {
1771                 int j = 1;
1772                 if (dnses.size() == 0 && mDefaultDns != null) {
1773                     String dnsString = mDefaultDns.getHostAddress();
1774                     if (!dnsString.equals(SystemProperties.get("net.dns1"))) {
1775                         if (DBG) {
1776                             log("no dns provided - using " + dnsString);
1777                         }
1778                         changed = true;
1779                         SystemProperties.set("net.dns1", dnsString);
1780                     }
1781                     j++;
1782                 } else {
1783                     for (InetAddress dns : dnses) {
1784                         String dnsString = dns.getHostAddress();
1785                         if (!changed && dnsString.equals(SystemProperties.get("net.dns" + j))) {
1786                             j++;
1787                             continue;
1788                         }
1789                         if (DBG) {
1790                             log("adding dns " + dns + " for " +
1791                                     nt.getNetworkInfo().getTypeName());
1792                         }
1793                         changed = true;
1794                         SystemProperties.set("net.dns" + j++, dnsString);
1795                     }
1796                 }
1797                 for (int k=j ; k<mNumDnsEntries; k++) {
1798                     if (changed || !TextUtils.isEmpty(SystemProperties.get("net.dns" + k))) {
1799                         if (DBG) log("erasing net.dns" + k);
1800                         changed = true;
1801                         SystemProperties.set("net.dns" + k, "");
1802                     }
1803                 }
1804                 mNumDnsEntries = j;
1805             } else {
1806                 // set per-pid dns for attached secondary nets
1807                 List pids = mNetRequestersPids[netType];
1808                 for (int y=0; y< pids.size(); y++) {
1809                     Integer pid = (Integer)pids.get(y);
1810                     changed = writePidDns(dnses, pid.intValue());
1811                 }
1812             }
1813             if (changed) bumpDns();
1814         }
1815     }
1816
1817     private int getRestoreDefaultNetworkDelay(int networkType) {
1818         String restoreDefaultNetworkDelayStr = SystemProperties.get(
1819                 NETWORK_RESTORE_DELAY_PROP_NAME);
1820         if(restoreDefaultNetworkDelayStr != null &&
1821                 restoreDefaultNetworkDelayStr.length() != 0) {
1822             try {
1823                 return Integer.valueOf(restoreDefaultNetworkDelayStr);
1824             } catch (NumberFormatException e) {
1825             }
1826         }
1827         // if the system property isn't set, use the value for the apn type
1828         int ret = RESTORE_DEFAULT_NETWORK_DELAY;
1829
1830         if ((networkType <= ConnectivityManager.MAX_NETWORK_TYPE) &&
1831                 (mNetConfigs[networkType] != null)) {
1832             ret = mNetConfigs[networkType].restoreTime;
1833         }
1834         return ret;
1835     }
1836
1837     @Override
1838     protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1839         if (mContext.checkCallingOrSelfPermission(
1840                 android.Manifest.permission.DUMP)
1841                 != PackageManager.PERMISSION_GRANTED) {
1842             pw.println("Permission Denial: can't dump ConnectivityService " +
1843                     "from from pid=" + Binder.getCallingPid() + ", uid=" +
1844                     Binder.getCallingUid());
1845             return;
1846         }
1847         pw.println();
1848         for (NetworkStateTracker nst : mNetTrackers) {
1849             if (nst != null) {
1850                 if (nst.getNetworkInfo().isConnected()) {
1851                     pw.println("Active network: " + nst.getNetworkInfo().
1852                             getTypeName());
1853                 }
1854                 pw.println(nst.getNetworkInfo());
1855                 pw.println(nst);
1856                 pw.println();
1857             }
1858         }
1859
1860         pw.println("Network Requester Pids:");
1861         for (int net : mPriorityList) {
1862             String pidString = net + ": ";
1863             for (Object pid : mNetRequestersPids[net]) {
1864                 pidString = pidString + pid.toString() + ", ";
1865             }
1866             pw.println(pidString);
1867         }
1868         pw.println();
1869
1870         pw.println("FeatureUsers:");
1871         for (Object requester : mFeatureUsers) {
1872             pw.println(requester.toString());
1873         }
1874         pw.println();
1875
1876         synchronized (this) {
1877             pw.println("NetworkTranstionWakeLock is currently " +
1878                     (mNetTransitionWakeLock.isHeld() ? "" : "not ") + "held.");
1879             pw.println("It was last requested for "+mNetTransitionWakeLockCausedBy);
1880         }
1881         pw.println();
1882
1883         mTethering.dump(fd, pw, args);
1884
1885         if (mInetLog != null) {
1886             pw.println();
1887             pw.println("Inet condition reports:");
1888             for(int i = 0; i < mInetLog.size(); i++) {
1889                 pw.println(mInetLog.get(i));
1890             }
1891         }
1892     }
1893
1894     // must be stateless - things change under us.
1895     private class MyHandler extends Handler {
1896         public MyHandler(Looper looper) {
1897             super(looper);
1898         }
1899
1900         @Override
1901         public void handleMessage(Message msg) {
1902             NetworkInfo info;
1903             switch (msg.what) {
1904                 case NetworkStateTracker.EVENT_STATE_CHANGED:
1905                     info = (NetworkInfo) msg.obj;
1906                     int type = info.getType();
1907                     NetworkInfo.State state = info.getState();
1908
1909                     if (DBG) log("ConnectivityChange for " +
1910                             info.getTypeName() + ": " +
1911                             state + "/" + info.getDetailedState());
1912
1913                     // Connectivity state changed:
1914                     // [31-13] Reserved for future use
1915                     // [12-9] Network subtype (for mobile network, as defined
1916                     //         by TelephonyManager)
1917                     // [8-3] Detailed state ordinal (as defined by
1918                     //         NetworkInfo.DetailedState)
1919                     // [2-0] Network type (as defined by ConnectivityManager)
1920                     int eventLogParam = (info.getType() & 0x7) |
1921                             ((info.getDetailedState().ordinal() & 0x3f) << 3) |
1922                             (info.getSubtype() << 9);
1923                     EventLog.writeEvent(EventLogTags.CONNECTIVITY_STATE_CHANGED,
1924                             eventLogParam);
1925
1926                     if (info.getDetailedState() ==
1927                             NetworkInfo.DetailedState.FAILED) {
1928                         handleConnectionFailure(info);
1929                     } else if (state == NetworkInfo.State.DISCONNECTED) {
1930                         handleDisconnect(info);
1931                     } else if (state == NetworkInfo.State.SUSPENDED) {
1932                         // TODO: need to think this over.
1933                         // the logic here is, handle SUSPENDED the same as
1934                         // DISCONNECTED. The only difference being we are
1935                         // broadcasting an intent with NetworkInfo that's
1936                         // suspended. This allows the applications an
1937                         // opportunity to handle DISCONNECTED and SUSPENDED
1938                         // differently, or not.
1939                         handleDisconnect(info);
1940                     } else if (state == NetworkInfo.State.CONNECTED) {
1941                         handleConnect(info);
1942                     }
1943                     break;
1944                 case NetworkStateTracker.EVENT_CONFIGURATION_CHANGED:
1945                     info = (NetworkInfo) msg.obj;
1946                     // TODO: Temporary allowing network configuration
1947                     //       change not resetting sockets.
1948                     //       @see bug/4455071
1949                     handleConnectivityChange(info.getType(), false);
1950                     break;
1951                 case EVENT_CLEAR_NET_TRANSITION_WAKELOCK:
1952                     String causedBy = null;
1953                     synchronized (ConnectivityService.this) {
1954                         if (msg.arg1 == mNetTransitionWakeLockSerialNumber &&
1955                                 mNetTransitionWakeLock.isHeld()) {
1956                             mNetTransitionWakeLock.release();
1957                             causedBy = mNetTransitionWakeLockCausedBy;
1958                         }
1959                     }
1960                     if (causedBy != null) {
1961                         log("NetTransition Wakelock for " + causedBy + " released by timeout");
1962                     }
1963                     break;
1964                 case EVENT_RESTORE_DEFAULT_NETWORK:
1965                     FeatureUser u = (FeatureUser)msg.obj;
1966                     u.expire();
1967                     break;
1968                 case EVENT_INET_CONDITION_CHANGE:
1969                 {
1970                     int netType = msg.arg1;
1971                     int condition = msg.arg2;
1972                     handleInetConditionChange(netType, condition);
1973                     break;
1974                 }
1975                 case EVENT_INET_CONDITION_HOLD_END:
1976                 {
1977                     int netType = msg.arg1;
1978                     int sequence = msg.arg2;
1979                     handleInetConditionHoldEnd(netType, sequence);
1980                     break;
1981                 }
1982                 case EVENT_SET_NETWORK_PREFERENCE:
1983                 {
1984                     int preference = msg.arg1;
1985                     handleSetNetworkPreference(preference);
1986                     break;
1987                 }
1988                 case EVENT_SET_BACKGROUND_DATA:
1989                 {
1990                     boolean enabled = (msg.arg1 == ENABLED);
1991                     handleSetBackgroundData(enabled);
1992                     break;
1993                 }
1994                 case EVENT_SET_MOBILE_DATA:
1995                 {
1996                     boolean enabled = (msg.arg1 == ENABLED);
1997                     handleSetMobileData(enabled);
1998                     break;
1999                 }
2000                 case EVENT_APPLY_GLOBAL_HTTP_PROXY:
2001                 {
2002                     handleDeprecatedGlobalHttpProxy();
2003                     break;
2004                 }
2005                 case EVENT_SET_DEPENDENCY_MET:
2006                 {
2007                     boolean met = (msg.arg1 == ENABLED);
2008                     handleSetDependencyMet(msg.arg2, met);
2009                     break;
2010                 }
2011             }
2012         }
2013     }
2014
2015     // javadoc from interface
2016     public int tether(String iface) {
2017         enforceTetherChangePermission();
2018
2019         if (isTetheringSupported()) {
2020             return mTethering.tether(iface);
2021         } else {
2022             return ConnectivityManager.TETHER_ERROR_UNSUPPORTED;
2023         }
2024     }
2025
2026     // javadoc from interface
2027     public int untether(String iface) {
2028         enforceTetherChangePermission();
2029
2030         if (isTetheringSupported()) {
2031             return mTethering.untether(iface);
2032         } else {
2033             return ConnectivityManager.TETHER_ERROR_UNSUPPORTED;
2034         }
2035     }
2036
2037     // javadoc from interface
2038     public int getLastTetherError(String iface) {
2039         enforceTetherAccessPermission();
2040
2041         if (isTetheringSupported()) {
2042             return mTethering.getLastTetherError(iface);
2043         } else {
2044             return ConnectivityManager.TETHER_ERROR_UNSUPPORTED;
2045         }
2046     }
2047
2048     // TODO - proper iface API for selection by property, inspection, etc
2049     public String[] getTetherableUsbRegexs() {
2050         enforceTetherAccessPermission();
2051         if (isTetheringSupported()) {
2052             return mTethering.getTetherableUsbRegexs();
2053         } else {
2054             return new String[0];
2055         }
2056     }
2057
2058     public String[] getTetherableWifiRegexs() {
2059         enforceTetherAccessPermission();
2060         if (isTetheringSupported()) {
2061             return mTethering.getTetherableWifiRegexs();
2062         } else {
2063             return new String[0];
2064         }
2065     }
2066
2067     public String[] getTetherableBluetoothRegexs() {
2068         enforceTetherAccessPermission();
2069         if (isTetheringSupported()) {
2070             return mTethering.getTetherableBluetoothRegexs();
2071         } else {
2072             return new String[0];
2073         }
2074     }
2075
2076     // TODO - move iface listing, queries, etc to new module
2077     // javadoc from interface
2078     public String[] getTetherableIfaces() {
2079         enforceTetherAccessPermission();
2080         return mTethering.getTetherableIfaces();
2081     }
2082
2083     public String[] getTetheredIfaces() {
2084         enforceTetherAccessPermission();
2085         return mTethering.getTetheredIfaces();
2086     }
2087
2088     public String[] getTetheringErroredIfaces() {
2089         enforceTetherAccessPermission();
2090         return mTethering.getErroredIfaces();
2091     }
2092
2093     // if ro.tether.denied = true we default to no tethering
2094     // gservices could set the secure setting to 1 though to enable it on a build where it
2095     // had previously been turned off.
2096     public boolean isTetheringSupported() {
2097         enforceTetherAccessPermission();
2098         int defaultVal = (SystemProperties.get("ro.tether.denied").equals("true") ? 0 : 1);
2099         boolean tetherEnabledInSettings = (Settings.Secure.getInt(mContext.getContentResolver(),
2100                 Settings.Secure.TETHER_SUPPORTED, defaultVal) != 0);
2101         return tetherEnabledInSettings && mTetheringConfigValid;
2102     }
2103
2104     // An API NetworkStateTrackers can call when they lose their network.
2105     // This will automatically be cleared after X seconds or a network becomes CONNECTED,
2106     // whichever happens first.  The timer is started by the first caller and not
2107     // restarted by subsequent callers.
2108     public void requestNetworkTransitionWakelock(String forWhom) {
2109         enforceConnectivityInternalPermission();
2110         synchronized (this) {
2111             if (mNetTransitionWakeLock.isHeld()) return;
2112             mNetTransitionWakeLockSerialNumber++;
2113             mNetTransitionWakeLock.acquire();
2114             mNetTransitionWakeLockCausedBy = forWhom;
2115         }
2116         mHandler.sendMessageDelayed(mHandler.obtainMessage(
2117                 EVENT_CLEAR_NET_TRANSITION_WAKELOCK,
2118                 mNetTransitionWakeLockSerialNumber, 0),
2119                 mNetTransitionWakeLockTimeout);
2120         return;
2121     }
2122
2123     // 100 percent is full good, 0 is full bad.
2124     public void reportInetCondition(int networkType, int percentage) {
2125         if (DBG) log("reportNetworkCondition(" + networkType + ", " + percentage + ")");
2126         mContext.enforceCallingOrSelfPermission(
2127                 android.Manifest.permission.STATUS_BAR,
2128                 "ConnectivityService");
2129
2130         if (DBG) {
2131             int pid = getCallingPid();
2132             int uid = getCallingUid();
2133             String s = pid + "(" + uid + ") reports inet is " +
2134                 (percentage > 50 ? "connected" : "disconnected") + " (" + percentage + ") on " +
2135                 "network Type " + networkType + " at " + GregorianCalendar.getInstance().getTime();
2136             mInetLog.add(s);
2137             while(mInetLog.size() > INET_CONDITION_LOG_MAX_SIZE) {
2138                 mInetLog.remove(0);
2139             }
2140         }
2141         mHandler.sendMessage(mHandler.obtainMessage(
2142             EVENT_INET_CONDITION_CHANGE, networkType, percentage));
2143     }
2144
2145     private void handleInetConditionChange(int netType, int condition) {
2146         if (DBG) {
2147             log("Inet connectivity change, net=" +
2148                     netType + ", condition=" + condition +
2149                     ",mActiveDefaultNetwork=" + mActiveDefaultNetwork);
2150         }
2151         if (mActiveDefaultNetwork == -1) {
2152             if (DBG) log("no active default network - aborting");
2153             return;
2154         }
2155         if (mActiveDefaultNetwork != netType) {
2156             if (DBG) log("given net not default - aborting");
2157             return;
2158         }
2159         mDefaultInetCondition = condition;
2160         int delay;
2161         if (mInetConditionChangeInFlight == false) {
2162             if (DBG) log("starting a change hold");
2163             // setup a new hold to debounce this
2164             if (mDefaultInetCondition > 50) {
2165                 delay = Settings.Secure.getInt(mContext.getContentResolver(),
2166                         Settings.Secure.INET_CONDITION_DEBOUNCE_UP_DELAY, 500);
2167             } else {
2168                 delay = Settings.Secure.getInt(mContext.getContentResolver(),
2169                 Settings.Secure.INET_CONDITION_DEBOUNCE_DOWN_DELAY, 3000);
2170             }
2171             mInetConditionChangeInFlight = true;
2172             mHandler.sendMessageDelayed(mHandler.obtainMessage(EVENT_INET_CONDITION_HOLD_END,
2173                     mActiveDefaultNetwork, mDefaultConnectionSequence), delay);
2174         } else {
2175             // we've set the new condition, when this hold ends that will get
2176             // picked up
2177             if (DBG) log("currently in hold - not setting new end evt");
2178         }
2179     }
2180
2181     private void handleInetConditionHoldEnd(int netType, int sequence) {
2182         if (DBG) {
2183             log("Inet hold end, net=" + netType +
2184                     ", condition =" + mDefaultInetCondition +
2185                     ", published condition =" + mDefaultInetConditionPublished);
2186         }
2187         mInetConditionChangeInFlight = false;
2188
2189         if (mActiveDefaultNetwork == -1) {
2190             if (DBG) log("no active default network - aborting");
2191             return;
2192         }
2193         if (mDefaultConnectionSequence != sequence) {
2194             if (DBG) log("event hold for obsolete network - aborting");
2195             return;
2196         }
2197         if (mDefaultInetConditionPublished == mDefaultInetCondition) {
2198             if (DBG) log("no change in condition - aborting");
2199             return;
2200         }
2201         NetworkInfo networkInfo = mNetTrackers[mActiveDefaultNetwork].getNetworkInfo();
2202         if (networkInfo.isConnected() == false) {
2203             if (DBG) log("default network not connected - aborting");
2204             return;
2205         }
2206         mDefaultInetConditionPublished = mDefaultInetCondition;
2207         sendInetConditionBroadcast(networkInfo);
2208         return;
2209     }
2210
2211     public synchronized ProxyProperties getProxy() {
2212         if (mGlobalProxy != null) return mGlobalProxy;
2213         if (mDefaultProxy != null) return mDefaultProxy;
2214         return null;
2215     }
2216
2217     public void setGlobalProxy(ProxyProperties proxyProperties) {
2218         enforceChangePermission();
2219         synchronized (mGlobalProxyLock) {
2220             if (proxyProperties == mGlobalProxy) return;
2221             if (proxyProperties != null && proxyProperties.equals(mGlobalProxy)) return;
2222             if (mGlobalProxy != null && mGlobalProxy.equals(proxyProperties)) return;
2223
2224             String host = "";
2225             int port = 0;
2226             String exclList = "";
2227             if (proxyProperties != null && !TextUtils.isEmpty(proxyProperties.getHost())) {
2228                 mGlobalProxy = new ProxyProperties(proxyProperties);
2229                 host = mGlobalProxy.getHost();
2230                 port = mGlobalProxy.getPort();
2231                 exclList = mGlobalProxy.getExclusionList();
2232             } else {
2233                 mGlobalProxy = null;
2234             }
2235             ContentResolver res = mContext.getContentResolver();
2236             Settings.Secure.putString(res, Settings.Secure.GLOBAL_HTTP_PROXY_HOST, host);
2237             Settings.Secure.putInt(res, Settings.Secure.GLOBAL_HTTP_PROXY_PORT, port);
2238             Settings.Secure.putString(res, Settings.Secure.GLOBAL_HTTP_PROXY_EXCLUSION_LIST,
2239                     exclList);
2240         }
2241
2242         if (mGlobalProxy == null) {
2243             proxyProperties = mDefaultProxy;
2244         }
2245         sendProxyBroadcast(proxyProperties);
2246     }
2247
2248     private void loadGlobalProxy() {
2249         ContentResolver res = mContext.getContentResolver();
2250         String host = Settings.Secure.getString(res, Settings.Secure.GLOBAL_HTTP_PROXY_HOST);
2251         int port = Settings.Secure.getInt(res, Settings.Secure.GLOBAL_HTTP_PROXY_PORT, 0);
2252         String exclList = Settings.Secure.getString(res,
2253                 Settings.Secure.GLOBAL_HTTP_PROXY_EXCLUSION_LIST);
2254         if (!TextUtils.isEmpty(host)) {
2255             ProxyProperties proxyProperties = new ProxyProperties(host, port, exclList);
2256             synchronized (mGlobalProxyLock) {
2257                 mGlobalProxy = proxyProperties;
2258             }
2259         }
2260     }
2261
2262     public ProxyProperties getGlobalProxy() {
2263         synchronized (mGlobalProxyLock) {
2264             return mGlobalProxy;
2265         }
2266     }
2267
2268     private void handleApplyDefaultProxy(int type) {
2269         // check if new default - push it out to all VM if so
2270         ProxyProperties proxy = mNetTrackers[type].getLinkProperties().getHttpProxy();
2271         synchronized (this) {
2272             if (mDefaultProxy != null && mDefaultProxy.equals(proxy)) return;
2273             if (mDefaultProxy == proxy) return;
2274             if (!TextUtils.isEmpty(proxy.getHost())) {
2275                 mDefaultProxy = proxy;
2276             } else {
2277                 mDefaultProxy = null;
2278             }
2279         }
2280         if (DBG) log("changing default proxy to " + proxy);
2281         if ((proxy == null && mGlobalProxy == null) || proxy.equals(mGlobalProxy)) return;
2282         if (mGlobalProxy != null) return;
2283         sendProxyBroadcast(proxy);
2284     }
2285
2286     private void handleDeprecatedGlobalHttpProxy() {
2287         String proxy = Settings.Secure.getString(mContext.getContentResolver(),
2288                 Settings.Secure.HTTP_PROXY);
2289         if (!TextUtils.isEmpty(proxy)) {
2290             String data[] = proxy.split(":");
2291             String proxyHost =  data[0];
2292             int proxyPort = 8080;
2293             if (data.length > 1) {
2294                 try {
2295                     proxyPort = Integer.parseInt(data[1]);
2296                 } catch (NumberFormatException e) {
2297                     return;
2298                 }
2299             }
2300             ProxyProperties p = new ProxyProperties(data[0], proxyPort, "");
2301             setGlobalProxy(p);
2302         }
2303     }
2304
2305     private void sendProxyBroadcast(ProxyProperties proxy) {
2306         if (proxy == null) proxy = new ProxyProperties("", 0, "");
2307         log("sending Proxy Broadcast for " + proxy);
2308         Intent intent = new Intent(Proxy.PROXY_CHANGE_ACTION);
2309         intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING |
2310             Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
2311         intent.putExtra(Proxy.EXTRA_PROXY_INFO, proxy);
2312         mContext.sendStickyBroadcast(intent);
2313     }
2314
2315     private static class SettingsObserver extends ContentObserver {
2316         private int mWhat;
2317         private Handler mHandler;
2318         SettingsObserver(Handler handler, int what) {
2319             super(handler);
2320             mHandler = handler;
2321             mWhat = what;
2322         }
2323
2324         void observe(Context context) {
2325             ContentResolver resolver = context.getContentResolver();
2326             resolver.registerContentObserver(Settings.Secure.getUriFor(
2327                     Settings.Secure.HTTP_PROXY), false, this);
2328         }
2329
2330         @Override
2331         public void onChange(boolean selfChange) {
2332             mHandler.obtainMessage(mWhat).sendToTarget();
2333         }
2334     }
2335
2336     private void log(String s) {
2337         Slog.d(TAG, s);
2338     }
2339
2340     private void loge(String s) {
2341         Slog.e(TAG, s);
2342     }
2343     int convertFeatureToNetworkType(String feature){
2344         int networkType = -1;
2345         if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_MMS)) {
2346             networkType = ConnectivityManager.TYPE_MOBILE_MMS;
2347         } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_SUPL)) {
2348             networkType = ConnectivityManager.TYPE_MOBILE_SUPL;
2349         } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_DUN) ||
2350                 TextUtils.equals(feature, Phone.FEATURE_ENABLE_DUN_ALWAYS)) {
2351             networkType = ConnectivityManager.TYPE_MOBILE_DUN;
2352         } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_HIPRI)) {
2353             networkType = ConnectivityManager.TYPE_MOBILE_HIPRI;
2354         } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_FOTA)) {
2355             networkType = ConnectivityManager.TYPE_MOBILE_FOTA;
2356         } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_IMS)) {
2357             networkType = ConnectivityManager.TYPE_MOBILE_IMS;
2358         } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_CBS)) {
2359             networkType = ConnectivityManager.TYPE_MOBILE_CBS;
2360         }
2361         return networkType;
2362     }
2363 }