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