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