OSDN Git Service

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