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