ConnectivityService.java revision 75fbb4bdfde9188081f000506845d852f31362f0
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.Manifest.permission.RECEIVE_DATA_ACTIVITY_CHANGE;
21import static android.net.ConnectivityManager.CONNECTIVITY_ACTION;
22import static android.net.ConnectivityManager.CONNECTIVITY_ACTION_IMMEDIATE;
23import static android.net.ConnectivityManager.isNetworkTypeValid;
24import static android.net.NetworkPolicyManager.RULE_ALLOW_ALL;
25import static android.net.NetworkPolicyManager.RULE_REJECT_METERED;
26
27import android.bluetooth.BluetoothTetheringDataTracker;
28import android.content.ContentResolver;
29import android.content.Context;
30import android.content.ContextWrapper;
31import android.content.Intent;
32import android.content.pm.PackageManager;
33import android.content.res.Resources;
34import android.database.ContentObserver;
35import android.net.ConnectivityManager;
36import android.net.DummyDataStateTracker;
37import android.net.EthernetDataTracker;
38import android.net.IConnectivityManager;
39import android.net.INetworkManagementEventObserver;
40import android.net.INetworkPolicyListener;
41import android.net.INetworkPolicyManager;
42import android.net.INetworkStatsService;
43import android.net.LinkAddress;
44import android.net.LinkProperties;
45import android.net.LinkProperties.CompareResult;
46import android.net.MobileDataStateTracker;
47import android.net.NetworkConfig;
48import android.net.NetworkInfo;
49import android.net.NetworkInfo.DetailedState;
50import android.net.NetworkQuotaInfo;
51import android.net.NetworkState;
52import android.net.NetworkStateTracker;
53import android.net.NetworkUtils;
54import android.net.Proxy;
55import android.net.ProxyProperties;
56import android.net.RouteInfo;
57import android.net.wifi.WifiStateTracker;
58import android.net.wimax.WimaxManagerConstants;
59import android.os.Binder;
60import android.os.FileUtils;
61import android.os.Handler;
62import android.os.HandlerThread;
63import android.os.IBinder;
64import android.os.INetworkManagementService;
65import android.os.Looper;
66import android.os.Message;
67import android.os.ParcelFileDescriptor;
68import android.os.PowerManager;
69import android.os.RemoteException;
70import android.os.ServiceManager;
71import android.os.SystemClock;
72import android.os.SystemProperties;
73import android.provider.Settings;
74import android.text.TextUtils;
75import android.util.EventLog;
76import android.util.Slog;
77import android.util.SparseIntArray;
78
79import com.android.internal.net.LegacyVpnInfo;
80import com.android.internal.net.VpnConfig;
81import com.android.internal.telephony.Phone;
82import com.android.internal.telephony.PhoneConstants;
83import com.android.server.am.BatteryStatsService;
84import com.android.server.connectivity.Tethering;
85import com.android.server.connectivity.Vpn;
86import com.google.android.collect.Lists;
87import com.google.android.collect.Sets;
88import dalvik.system.DexClassLoader;
89import java.io.FileDescriptor;
90import java.io.IOException;
91import java.io.PrintWriter;
92import java.lang.reflect.Constructor;
93import java.lang.reflect.Method;
94import java.lang.reflect.Modifier;
95import java.lang.reflect.InvocationTargetException;
96import java.net.Inet4Address;
97import java.net.Inet6Address;
98import java.net.InetAddress;
99import java.net.UnknownHostException;
100import java.util.ArrayList;
101import java.util.Arrays;
102import java.util.Collection;
103import java.util.GregorianCalendar;
104import java.util.HashSet;
105import java.util.List;
106
107/**
108 * @hide
109 */
110public class ConnectivityService extends IConnectivityManager.Stub {
111
112    private static final boolean DBG = true;
113    private static final boolean VDBG = false;
114    private static final String TAG = "ConnectivityService";
115
116    private static final boolean LOGD_RULES = false;
117
118    // how long to wait before switching back to a radio's default network
119    private static final int RESTORE_DEFAULT_NETWORK_DELAY = 1 * 60 * 1000;
120    // system property that can override the above value
121    private static final String NETWORK_RESTORE_DELAY_PROP_NAME =
122            "android.telephony.apn-restore";
123
124    // used in recursive route setting to add gateways for the host for which
125    // a host route was requested.
126    private static final int MAX_HOSTROUTE_CYCLE_COUNT = 10;
127
128    private Tethering mTethering;
129    private boolean mTetheringConfigValid = false;
130
131    private Vpn mVpn;
132
133    /** Lock around {@link #mUidRules} and {@link #mMeteredIfaces}. */
134    private Object mRulesLock = new Object();
135    /** Currently active network rules by UID. */
136    private SparseIntArray mUidRules = new SparseIntArray();
137    /** Set of ifaces that are costly. */
138    private HashSet<String> mMeteredIfaces = Sets.newHashSet();
139
140    /**
141     * Sometimes we want to refer to the individual network state
142     * trackers separately, and sometimes we just want to treat them
143     * abstractly.
144     */
145    private NetworkStateTracker mNetTrackers[];
146
147    /**
148     * The link properties that define the current links
149     */
150    private LinkProperties mCurrentLinkProperties[];
151
152    /**
153     * A per Net list of the PID's that requested access to the net
154     * used both as a refcount and for per-PID DNS selection
155     */
156    private List mNetRequestersPids[];
157
158    // priority order of the nettrackers
159    // (excluding dynamically set mNetworkPreference)
160    // TODO - move mNetworkTypePreference into this
161    private int[] mPriorityList;
162
163    private Context mContext;
164    private int mNetworkPreference;
165    private int mActiveDefaultNetwork = -1;
166    // 0 is full bad, 100 is full good
167    private int mDefaultInetCondition = 0;
168    private int mDefaultInetConditionPublished = 0;
169    private boolean mInetConditionChangeInFlight = false;
170    private int mDefaultConnectionSequence = 0;
171
172    private Object mDnsLock = new Object();
173    private int mNumDnsEntries;
174    private boolean mDnsOverridden = false;
175
176    private boolean mTestMode;
177    private static ConnectivityService sServiceInstance;
178
179    private INetworkManagementService mNetd;
180    private INetworkPolicyManager mPolicyManager;
181
182    private static final int ENABLED  = 1;
183    private static final int DISABLED = 0;
184
185    private static final boolean ADD = true;
186    private static final boolean REMOVE = false;
187
188    private static final boolean TO_DEFAULT_TABLE = true;
189    private static final boolean TO_SECONDARY_TABLE = false;
190
191    /**
192     * used internally as a delayed event to make us switch back to the
193     * default network
194     */
195    private static final int EVENT_RESTORE_DEFAULT_NETWORK = 1;
196
197    /**
198     * used internally to change our mobile data enabled flag
199     */
200    private static final int EVENT_CHANGE_MOBILE_DATA_ENABLED = 2;
201
202    /**
203     * used internally to change our network preference setting
204     * arg1 = networkType to prefer
205     */
206    private static final int EVENT_SET_NETWORK_PREFERENCE = 3;
207
208    /**
209     * used internally to synchronize inet condition reports
210     * arg1 = networkType
211     * arg2 = condition (0 bad, 100 good)
212     */
213    private static final int EVENT_INET_CONDITION_CHANGE = 4;
214
215    /**
216     * used internally to mark the end of inet condition hold periods
217     * arg1 = networkType
218     */
219    private static final int EVENT_INET_CONDITION_HOLD_END = 5;
220
221    /**
222     * used internally to set enable/disable cellular data
223     * arg1 = ENBALED or DISABLED
224     */
225    private static final int EVENT_SET_MOBILE_DATA = 7;
226
227    /**
228     * used internally to clear a wakelock when transitioning
229     * from one net to another
230     */
231    private static final int EVENT_CLEAR_NET_TRANSITION_WAKELOCK = 8;
232
233    /**
234     * used internally to reload global proxy settings
235     */
236    private static final int EVENT_APPLY_GLOBAL_HTTP_PROXY = 9;
237
238    /**
239     * used internally to set external dependency met/unmet
240     * arg1 = ENABLED (met) or DISABLED (unmet)
241     * arg2 = NetworkType
242     */
243    private static final int EVENT_SET_DEPENDENCY_MET = 10;
244
245    /**
246     * used internally to restore DNS properties back to the
247     * default network
248     */
249    private static final int EVENT_RESTORE_DNS = 11;
250
251    /**
252     * used internally to send a sticky broadcast delayed.
253     */
254    private static final int EVENT_SEND_STICKY_BROADCAST_INTENT = 12;
255
256    /**
257     * Used internally to
258     * {@link NetworkStateTracker#setPolicyDataEnable(boolean)}.
259     */
260    private static final int EVENT_SET_POLICY_DATA_ENABLE = 13;
261
262    /** Handler used for internal events. */
263    private InternalHandler mHandler;
264    /** Handler used for incoming {@link NetworkStateTracker} events. */
265    private NetworkStateTrackerHandler mTrackerHandler;
266
267    // list of DeathRecipients used to make sure features are turned off when
268    // a process dies
269    private List<FeatureUser> mFeatureUsers;
270
271    private boolean mSystemReady;
272    private Intent mInitialBroadcast;
273
274    private PowerManager.WakeLock mNetTransitionWakeLock;
275    private String mNetTransitionWakeLockCausedBy = "";
276    private int mNetTransitionWakeLockSerialNumber;
277    private int mNetTransitionWakeLockTimeout;
278
279    private InetAddress mDefaultDns;
280
281    // this collection is used to refcount the added routes - if there are none left
282    // it's time to remove the route from the route table
283    private Collection<RouteInfo> mAddedRoutes = new ArrayList<RouteInfo>();
284
285    // used in DBG mode to track inet condition reports
286    private static final int INET_CONDITION_LOG_MAX_SIZE = 15;
287    private ArrayList mInetLog;
288
289    // track the current default http proxy - tell the world if we get a new one (real change)
290    private ProxyProperties mDefaultProxy = null;
291    private Object mDefaultProxyLock = new Object();
292    private boolean mDefaultProxyDisabled = false;
293
294    // track the global proxy.
295    private ProxyProperties mGlobalProxy = null;
296    private final Object mGlobalProxyLock = new Object();
297
298    private SettingsObserver mSettingsObserver;
299
300    NetworkConfig[] mNetConfigs;
301    int mNetworksDefined;
302
303    private static class RadioAttributes {
304        public int mSimultaneity;
305        public int mType;
306        public RadioAttributes(String init) {
307            String fragments[] = init.split(",");
308            mType = Integer.parseInt(fragments[0]);
309            mSimultaneity = Integer.parseInt(fragments[1]);
310        }
311    }
312    RadioAttributes[] mRadioAttributes;
313
314    // the set of network types that can only be enabled by system/sig apps
315    List mProtectedNetworks;
316
317    public ConnectivityService(Context context, INetworkManagementService netd,
318            INetworkStatsService statsService, INetworkPolicyManager policyManager) {
319        if (DBG) log("ConnectivityService starting up");
320
321        HandlerThread handlerThread = new HandlerThread("ConnectivityServiceThread");
322        handlerThread.start();
323        mHandler = new InternalHandler(handlerThread.getLooper());
324        mTrackerHandler = new NetworkStateTrackerHandler(handlerThread.getLooper());
325
326        // setup our unique device name
327        if (TextUtils.isEmpty(SystemProperties.get("net.hostname"))) {
328            String id = Settings.Secure.getString(context.getContentResolver(),
329                    Settings.Secure.ANDROID_ID);
330            if (id != null && id.length() > 0) {
331                String name = new String("android-").concat(id);
332                SystemProperties.set("net.hostname", name);
333            }
334        }
335
336        // read our default dns server ip
337        String dns = Settings.Secure.getString(context.getContentResolver(),
338                Settings.Secure.DEFAULT_DNS_SERVER);
339        if (dns == null || dns.length() == 0) {
340            dns = context.getResources().getString(
341                    com.android.internal.R.string.config_default_dns_server);
342        }
343        try {
344            mDefaultDns = NetworkUtils.numericToInetAddress(dns);
345        } catch (IllegalArgumentException e) {
346            loge("Error setting defaultDns using " + dns);
347        }
348
349        mContext = checkNotNull(context, "missing Context");
350        mNetd = checkNotNull(netd, "missing INetworkManagementService");
351        mPolicyManager = checkNotNull(policyManager, "missing INetworkPolicyManager");
352
353        try {
354            mPolicyManager.registerListener(mPolicyListener);
355        } catch (RemoteException e) {
356            // ouch, no rules updates means some processes may never get network
357            loge("unable to register INetworkPolicyListener" + e.toString());
358        }
359
360        final PowerManager powerManager = (PowerManager) context.getSystemService(
361                Context.POWER_SERVICE);
362        mNetTransitionWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
363        mNetTransitionWakeLockTimeout = mContext.getResources().getInteger(
364                com.android.internal.R.integer.config_networkTransitionTimeout);
365
366        mNetTrackers = new NetworkStateTracker[
367                ConnectivityManager.MAX_NETWORK_TYPE+1];
368        mCurrentLinkProperties = new LinkProperties[ConnectivityManager.MAX_NETWORK_TYPE+1];
369
370        mNetworkPreference = getPersistedNetworkPreference();
371
372        mRadioAttributes = new RadioAttributes[ConnectivityManager.MAX_RADIO_TYPE+1];
373        mNetConfigs = new NetworkConfig[ConnectivityManager.MAX_NETWORK_TYPE+1];
374
375        // Load device network attributes from resources
376        String[] raStrings = context.getResources().getStringArray(
377                com.android.internal.R.array.radioAttributes);
378        for (String raString : raStrings) {
379            RadioAttributes r = new RadioAttributes(raString);
380            if (r.mType > ConnectivityManager.MAX_RADIO_TYPE) {
381                loge("Error in radioAttributes - ignoring attempt to define type " + r.mType);
382                continue;
383            }
384            if (mRadioAttributes[r.mType] != null) {
385                loge("Error in radioAttributes - ignoring attempt to redefine type " +
386                        r.mType);
387                continue;
388            }
389            mRadioAttributes[r.mType] = r;
390        }
391
392        String[] naStrings = context.getResources().getStringArray(
393                com.android.internal.R.array.networkAttributes);
394        for (String naString : naStrings) {
395            try {
396                NetworkConfig n = new NetworkConfig(naString);
397                if (n.type > ConnectivityManager.MAX_NETWORK_TYPE) {
398                    loge("Error in networkAttributes - ignoring attempt to define type " +
399                            n.type);
400                    continue;
401                }
402                if (mNetConfigs[n.type] != null) {
403                    loge("Error in networkAttributes - ignoring attempt to redefine type " +
404                            n.type);
405                    continue;
406                }
407                if (mRadioAttributes[n.radio] == null) {
408                    loge("Error in networkAttributes - ignoring attempt to use undefined " +
409                            "radio " + n.radio + " in network type " + n.type);
410                    continue;
411                }
412                mNetConfigs[n.type] = n;
413                mNetworksDefined++;
414            } catch(Exception e) {
415                // ignore it - leave the entry null
416            }
417        }
418
419        mProtectedNetworks = new ArrayList<Integer>();
420        int[] protectedNetworks = context.getResources().getIntArray(
421                com.android.internal.R.array.config_protectedNetworks);
422        for (int p : protectedNetworks) {
423            if ((mNetConfigs[p] != null) && (mProtectedNetworks.contains(p) == false)) {
424                mProtectedNetworks.add(p);
425            } else {
426                if (DBG) loge("Ignoring protectedNetwork " + p);
427            }
428        }
429
430        // high priority first
431        mPriorityList = new int[mNetworksDefined];
432        {
433            int insertionPoint = mNetworksDefined-1;
434            int currentLowest = 0;
435            int nextLowest = 0;
436            while (insertionPoint > -1) {
437                for (NetworkConfig na : mNetConfigs) {
438                    if (na == null) continue;
439                    if (na.priority < currentLowest) continue;
440                    if (na.priority > currentLowest) {
441                        if (na.priority < nextLowest || nextLowest == 0) {
442                            nextLowest = na.priority;
443                        }
444                        continue;
445                    }
446                    mPriorityList[insertionPoint--] = na.type;
447                }
448                currentLowest = nextLowest;
449                nextLowest = 0;
450            }
451        }
452
453        mNetRequestersPids = new ArrayList[ConnectivityManager.MAX_NETWORK_TYPE+1];
454        for (int i : mPriorityList) {
455            mNetRequestersPids[i] = new ArrayList();
456        }
457
458        mFeatureUsers = new ArrayList<FeatureUser>();
459
460        mNumDnsEntries = 0;
461
462        mTestMode = SystemProperties.get("cm.test.mode").equals("true")
463                && SystemProperties.get("ro.build.type").equals("eng");
464        /*
465         * Create the network state trackers for Wi-Fi and mobile
466         * data. Maybe this could be done with a factory class,
467         * but it's not clear that it's worth it, given that
468         * the number of different network types is not going
469         * to change very often.
470         */
471        for (int netType : mPriorityList) {
472            switch (mNetConfigs[netType].radio) {
473            case ConnectivityManager.TYPE_WIFI:
474                mNetTrackers[netType] = new WifiStateTracker(
475                        netType, mNetConfigs[netType].name);
476                mNetTrackers[netType].startMonitoring(context, mTrackerHandler);
477                break;
478            case ConnectivityManager.TYPE_MOBILE:
479                mNetTrackers[netType] = new MobileDataStateTracker(netType,
480                        mNetConfigs[netType].name);
481                mNetTrackers[netType].startMonitoring(context, mTrackerHandler);
482                break;
483            case ConnectivityManager.TYPE_DUMMY:
484                mNetTrackers[netType] = new DummyDataStateTracker(netType,
485                        mNetConfigs[netType].name);
486                mNetTrackers[netType].startMonitoring(context, mTrackerHandler);
487                break;
488            case ConnectivityManager.TYPE_BLUETOOTH:
489                mNetTrackers[netType] = BluetoothTetheringDataTracker.getInstance();
490                mNetTrackers[netType].startMonitoring(context, mTrackerHandler);
491                break;
492            case ConnectivityManager.TYPE_WIMAX:
493                mNetTrackers[netType] = makeWimaxStateTracker();
494                if (mNetTrackers[netType]!= null) {
495                    mNetTrackers[netType].startMonitoring(context, mTrackerHandler);
496                }
497                break;
498            case ConnectivityManager.TYPE_ETHERNET:
499                mNetTrackers[netType] = EthernetDataTracker.getInstance();
500                mNetTrackers[netType].startMonitoring(context, mTrackerHandler);
501                break;
502            default:
503                loge("Trying to create a DataStateTracker for an unknown radio type " +
504                        mNetConfigs[netType].radio);
505                continue;
506            }
507            mCurrentLinkProperties[netType] = null;
508            if (mNetTrackers[netType] != null && mNetConfigs[netType].isDefault()) {
509                mNetTrackers[netType].reconnect();
510            }
511        }
512
513        IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
514        INetworkManagementService nmService = INetworkManagementService.Stub.asInterface(b);
515
516        mTethering = new Tethering(mContext, nmService, statsService, this, mHandler.getLooper());
517        mTetheringConfigValid = ((mTethering.getTetherableUsbRegexs().length != 0 ||
518                                  mTethering.getTetherableWifiRegexs().length != 0 ||
519                                  mTethering.getTetherableBluetoothRegexs().length != 0) &&
520                                 mTethering.getUpstreamIfaceTypes().length != 0);
521
522        mVpn = new Vpn(mContext, new VpnCallback());
523
524        try {
525            nmService.registerObserver(mTethering);
526            nmService.registerObserver(mVpn);
527        } catch (RemoteException e) {
528            loge("Error registering observer :" + e);
529        }
530
531        if (DBG) {
532            mInetLog = new ArrayList();
533        }
534
535        mSettingsObserver = new SettingsObserver(mHandler, EVENT_APPLY_GLOBAL_HTTP_PROXY);
536        mSettingsObserver.observe(mContext);
537
538        INetworkManagementEventObserver netdObserver = new NetdObserver();
539        try {
540            mNetd.registerObserver(netdObserver);
541        } catch (RemoteException e) {
542            loge("Error registering observer :" + e);
543        }
544
545        loadGlobalProxy();
546    }
547
548    private NetworkStateTracker makeWimaxStateTracker() {
549        // Initialize Wimax
550        DexClassLoader wimaxClassLoader;
551        Class wimaxStateTrackerClass = null;
552        Class wimaxServiceClass = null;
553        Class wimaxManagerClass;
554        String wimaxJarLocation;
555        String wimaxLibLocation;
556        String wimaxManagerClassName;
557        String wimaxServiceClassName;
558        String wimaxStateTrackerClassName;
559
560        NetworkStateTracker wimaxStateTracker = null;
561
562        boolean isWimaxEnabled = mContext.getResources().getBoolean(
563                com.android.internal.R.bool.config_wimaxEnabled);
564
565        if (isWimaxEnabled) {
566            try {
567                wimaxJarLocation = mContext.getResources().getString(
568                        com.android.internal.R.string.config_wimaxServiceJarLocation);
569                wimaxLibLocation = mContext.getResources().getString(
570                        com.android.internal.R.string.config_wimaxNativeLibLocation);
571                wimaxManagerClassName = mContext.getResources().getString(
572                        com.android.internal.R.string.config_wimaxManagerClassname);
573                wimaxServiceClassName = mContext.getResources().getString(
574                        com.android.internal.R.string.config_wimaxServiceClassname);
575                wimaxStateTrackerClassName = mContext.getResources().getString(
576                        com.android.internal.R.string.config_wimaxStateTrackerClassname);
577
578                log("wimaxJarLocation: " + wimaxJarLocation);
579                wimaxClassLoader =  new DexClassLoader(wimaxJarLocation,
580                        new ContextWrapper(mContext).getCacheDir().getAbsolutePath(),
581                        wimaxLibLocation, ClassLoader.getSystemClassLoader());
582
583                try {
584                    wimaxManagerClass = wimaxClassLoader.loadClass(wimaxManagerClassName);
585                    wimaxStateTrackerClass = wimaxClassLoader.loadClass(wimaxStateTrackerClassName);
586                    wimaxServiceClass = wimaxClassLoader.loadClass(wimaxServiceClassName);
587                } catch (ClassNotFoundException ex) {
588                    loge("Exception finding Wimax classes: " + ex.toString());
589                    return null;
590                }
591            } catch(Resources.NotFoundException ex) {
592                loge("Wimax Resources does not exist!!! ");
593                return null;
594            }
595
596            try {
597                log("Starting Wimax Service... ");
598
599                Constructor wmxStTrkrConst = wimaxStateTrackerClass.getConstructor
600                        (new Class[] {Context.class, Handler.class});
601                wimaxStateTracker = (NetworkStateTracker)wmxStTrkrConst.newInstance(mContext,
602                        mTrackerHandler);
603
604                Constructor wmxSrvConst = wimaxServiceClass.getDeclaredConstructor
605                        (new Class[] {Context.class, wimaxStateTrackerClass});
606                wmxSrvConst.setAccessible(true);
607                IBinder svcInvoker = (IBinder)wmxSrvConst.newInstance(mContext, wimaxStateTracker);
608                wmxSrvConst.setAccessible(false);
609
610                ServiceManager.addService(WimaxManagerConstants.WIMAX_SERVICE, svcInvoker);
611
612            } catch(Exception ex) {
613                loge("Exception creating Wimax classes: " + ex.toString());
614                return null;
615            }
616        } else {
617            loge("Wimax is not enabled or not added to the network attributes!!! ");
618            return null;
619        }
620
621        return wimaxStateTracker;
622    }
623
624    /**
625     * Sets the preferred network.
626     * @param preference the new preference
627     */
628    public void setNetworkPreference(int preference) {
629        enforceChangePermission();
630
631        mHandler.sendMessage(
632                mHandler.obtainMessage(EVENT_SET_NETWORK_PREFERENCE, preference, 0));
633    }
634
635    public int getNetworkPreference() {
636        enforceAccessPermission();
637        int preference;
638        synchronized(this) {
639            preference = mNetworkPreference;
640        }
641        return preference;
642    }
643
644    private void handleSetNetworkPreference(int preference) {
645        if (ConnectivityManager.isNetworkTypeValid(preference) &&
646                mNetConfigs[preference] != null &&
647                mNetConfigs[preference].isDefault()) {
648            if (mNetworkPreference != preference) {
649                final ContentResolver cr = mContext.getContentResolver();
650                Settings.Secure.putInt(cr, Settings.Secure.NETWORK_PREFERENCE, preference);
651                synchronized(this) {
652                    mNetworkPreference = preference;
653                }
654                enforcePreference();
655            }
656        }
657    }
658
659    private int getConnectivityChangeDelay() {
660        final ContentResolver cr = mContext.getContentResolver();
661
662        /** Check system properties for the default value then use secure settings value, if any. */
663        int defaultDelay = SystemProperties.getInt(
664                "conn." + Settings.Secure.CONNECTIVITY_CHANGE_DELAY,
665                Settings.Secure.CONNECTIVITY_CHANGE_DELAY_DEFAULT);
666        return Settings.Secure.getInt(cr, Settings.Secure.CONNECTIVITY_CHANGE_DELAY,
667                defaultDelay);
668    }
669
670    private int getPersistedNetworkPreference() {
671        final ContentResolver cr = mContext.getContentResolver();
672
673        final int networkPrefSetting = Settings.Secure
674                .getInt(cr, Settings.Secure.NETWORK_PREFERENCE, -1);
675        if (networkPrefSetting != -1) {
676            return networkPrefSetting;
677        }
678
679        return ConnectivityManager.DEFAULT_NETWORK_PREFERENCE;
680    }
681
682    /**
683     * Make the state of network connectivity conform to the preference settings
684     * In this method, we only tear down a non-preferred network. Establishing
685     * a connection to the preferred network is taken care of when we handle
686     * the disconnect event from the non-preferred network
687     * (see {@link #handleDisconnect(NetworkInfo)}).
688     */
689    private void enforcePreference() {
690        if (mNetTrackers[mNetworkPreference].getNetworkInfo().isConnected())
691            return;
692
693        if (!mNetTrackers[mNetworkPreference].isAvailable())
694            return;
695
696        for (int t=0; t <= ConnectivityManager.MAX_RADIO_TYPE; t++) {
697            if (t != mNetworkPreference && mNetTrackers[t] != null &&
698                    mNetTrackers[t].getNetworkInfo().isConnected()) {
699                if (DBG) {
700                    log("tearing down " + mNetTrackers[t].getNetworkInfo() +
701                            " in enforcePreference");
702                }
703                teardown(mNetTrackers[t]);
704            }
705        }
706    }
707
708    private boolean teardown(NetworkStateTracker netTracker) {
709        if (netTracker.teardown()) {
710            netTracker.setTeardownRequested(true);
711            return true;
712        } else {
713            return false;
714        }
715    }
716
717    /**
718     * Check if UID should be blocked from using the network represented by the
719     * given {@link NetworkStateTracker}.
720     */
721    private boolean isNetworkBlocked(NetworkStateTracker tracker, int uid) {
722        final String iface = tracker.getLinkProperties().getInterfaceName();
723
724        final boolean networkCostly;
725        final int uidRules;
726        synchronized (mRulesLock) {
727            networkCostly = mMeteredIfaces.contains(iface);
728            uidRules = mUidRules.get(uid, RULE_ALLOW_ALL);
729        }
730
731        if (networkCostly && (uidRules & RULE_REJECT_METERED) != 0) {
732            return true;
733        }
734
735        // no restrictive rules; network is visible
736        return false;
737    }
738
739    /**
740     * Return a filtered {@link NetworkInfo}, potentially marked
741     * {@link DetailedState#BLOCKED} based on
742     * {@link #isNetworkBlocked(NetworkStateTracker, int)}.
743     */
744    private NetworkInfo getFilteredNetworkInfo(NetworkStateTracker tracker, int uid) {
745        NetworkInfo info = tracker.getNetworkInfo();
746        if (isNetworkBlocked(tracker, uid)) {
747            // network is blocked; clone and override state
748            info = new NetworkInfo(info);
749            info.setDetailedState(DetailedState.BLOCKED, null, null);
750        }
751        return info;
752    }
753
754    /**
755     * Return NetworkInfo for the active (i.e., connected) network interface.
756     * It is assumed that at most one network is active at a time. If more
757     * than one is active, it is indeterminate which will be returned.
758     * @return the info for the active network, or {@code null} if none is
759     * active
760     */
761    @Override
762    public NetworkInfo getActiveNetworkInfo() {
763        enforceAccessPermission();
764        final int uid = Binder.getCallingUid();
765        return getNetworkInfo(mActiveDefaultNetwork, uid);
766    }
767
768    @Override
769    public NetworkInfo getActiveNetworkInfoForUid(int uid) {
770        enforceConnectivityInternalPermission();
771        return getNetworkInfo(mActiveDefaultNetwork, uid);
772    }
773
774    @Override
775    public NetworkInfo getNetworkInfo(int networkType) {
776        enforceAccessPermission();
777        final int uid = Binder.getCallingUid();
778        return getNetworkInfo(networkType, uid);
779    }
780
781    private NetworkInfo getNetworkInfo(int networkType, int uid) {
782        NetworkInfo info = null;
783        if (isNetworkTypeValid(networkType)) {
784            final NetworkStateTracker tracker = mNetTrackers[networkType];
785            if (tracker != null) {
786                info = getFilteredNetworkInfo(tracker, uid);
787            }
788        }
789        return info;
790    }
791
792    @Override
793    public NetworkInfo[] getAllNetworkInfo() {
794        enforceAccessPermission();
795        final int uid = Binder.getCallingUid();
796        final ArrayList<NetworkInfo> result = Lists.newArrayList();
797        synchronized (mRulesLock) {
798            for (NetworkStateTracker tracker : mNetTrackers) {
799                if (tracker != null) {
800                    result.add(getFilteredNetworkInfo(tracker, uid));
801                }
802            }
803        }
804        return result.toArray(new NetworkInfo[result.size()]);
805    }
806
807    @Override
808    public boolean isNetworkSupported(int networkType) {
809        enforceAccessPermission();
810        return (isNetworkTypeValid(networkType) && (mNetTrackers[networkType] != null));
811    }
812
813    /**
814     * Return LinkProperties for the active (i.e., connected) default
815     * network interface.  It is assumed that at most one default network
816     * is active at a time. If more than one is active, it is indeterminate
817     * which will be returned.
818     * @return the ip properties for the active network, or {@code null} if
819     * none is active
820     */
821    @Override
822    public LinkProperties getActiveLinkProperties() {
823        return getLinkProperties(mActiveDefaultNetwork);
824    }
825
826    @Override
827    public LinkProperties getLinkProperties(int networkType) {
828        enforceAccessPermission();
829        if (isNetworkTypeValid(networkType)) {
830            final NetworkStateTracker tracker = mNetTrackers[networkType];
831            if (tracker != null) {
832                return tracker.getLinkProperties();
833            }
834        }
835        return null;
836    }
837
838    @Override
839    public NetworkState[] getAllNetworkState() {
840        enforceAccessPermission();
841        final int uid = Binder.getCallingUid();
842        final ArrayList<NetworkState> result = Lists.newArrayList();
843        synchronized (mRulesLock) {
844            for (NetworkStateTracker tracker : mNetTrackers) {
845                if (tracker != null) {
846                    final NetworkInfo info = getFilteredNetworkInfo(tracker, uid);
847                    result.add(new NetworkState(
848                            info, tracker.getLinkProperties(), tracker.getLinkCapabilities()));
849                }
850            }
851        }
852        return result.toArray(new NetworkState[result.size()]);
853    }
854
855    private NetworkState getNetworkStateUnchecked(int networkType) {
856        if (isNetworkTypeValid(networkType)) {
857            final NetworkStateTracker tracker = mNetTrackers[networkType];
858            if (tracker != null) {
859                return new NetworkState(tracker.getNetworkInfo(), tracker.getLinkProperties(),
860                        tracker.getLinkCapabilities());
861            }
862        }
863        return null;
864    }
865
866    @Override
867    public NetworkQuotaInfo getActiveNetworkQuotaInfo() {
868        enforceAccessPermission();
869
870        final long token = Binder.clearCallingIdentity();
871        try {
872            final NetworkState state = getNetworkStateUnchecked(mActiveDefaultNetwork);
873            if (state != null) {
874                try {
875                    return mPolicyManager.getNetworkQuotaInfo(state);
876                } catch (RemoteException e) {
877                }
878            }
879            return null;
880        } finally {
881            Binder.restoreCallingIdentity(token);
882        }
883    }
884
885    @Override
886    public boolean isActiveNetworkMetered() {
887        enforceAccessPermission();
888        final long token = Binder.clearCallingIdentity();
889        try {
890            return isNetworkMeteredUnchecked(mActiveDefaultNetwork);
891        } finally {
892            Binder.restoreCallingIdentity(token);
893        }
894    }
895
896    private boolean isNetworkMeteredUnchecked(int networkType) {
897        final NetworkState state = getNetworkStateUnchecked(networkType);
898        if (state != null) {
899            try {
900                return mPolicyManager.isNetworkMetered(state);
901            } catch (RemoteException e) {
902            }
903        }
904        return false;
905    }
906
907    public boolean setRadios(boolean turnOn) {
908        boolean result = true;
909        enforceChangePermission();
910        for (NetworkStateTracker t : mNetTrackers) {
911            if (t != null) result = t.setRadio(turnOn) && result;
912        }
913        return result;
914    }
915
916    public boolean setRadio(int netType, boolean turnOn) {
917        enforceChangePermission();
918        if (!ConnectivityManager.isNetworkTypeValid(netType)) {
919            return false;
920        }
921        NetworkStateTracker tracker = mNetTrackers[netType];
922        return tracker != null && tracker.setRadio(turnOn);
923    }
924
925    private class NetdObserver extends INetworkManagementEventObserver.Stub {
926        public void interfaceClassDataActivityChanged(String label, boolean active) {
927            int deviceType = Integer.parseInt(label);
928            sendDataActivityBroadcast(deviceType, active);
929        }
930
931        public void interfaceStatusChanged(String iface, boolean up) {}
932        public void interfaceLinkStateChanged(String iface, boolean up) {}
933        public void interfaceAdded(String iface) {}
934        public void interfaceRemoved(String iface) {}
935        public void limitReached(String limitName, String iface) {}
936    }
937
938    /**
939     * Used to notice when the calling process dies so we can self-expire
940     *
941     * Also used to know if the process has cleaned up after itself when
942     * our auto-expire timer goes off.  The timer has a link to an object.
943     *
944     */
945    private class FeatureUser implements IBinder.DeathRecipient {
946        int mNetworkType;
947        String mFeature;
948        IBinder mBinder;
949        int mPid;
950        int mUid;
951        long mCreateTime;
952
953        FeatureUser(int type, String feature, IBinder binder) {
954            super();
955            mNetworkType = type;
956            mFeature = feature;
957            mBinder = binder;
958            mPid = getCallingPid();
959            mUid = getCallingUid();
960            mCreateTime = System.currentTimeMillis();
961
962            try {
963                mBinder.linkToDeath(this, 0);
964            } catch (RemoteException e) {
965                binderDied();
966            }
967        }
968
969        void unlinkDeathRecipient() {
970            mBinder.unlinkToDeath(this, 0);
971        }
972
973        public void binderDied() {
974            log("ConnectivityService FeatureUser binderDied(" +
975                    mNetworkType + ", " + mFeature + ", " + mBinder + "), created " +
976                    (System.currentTimeMillis() - mCreateTime) + " mSec ago");
977            stopUsingNetworkFeature(this, false);
978        }
979
980        public void expire() {
981            if (VDBG) {
982                log("ConnectivityService FeatureUser expire(" +
983                        mNetworkType + ", " + mFeature + ", " + mBinder +"), created " +
984                        (System.currentTimeMillis() - mCreateTime) + " mSec ago");
985            }
986            stopUsingNetworkFeature(this, false);
987        }
988
989        public boolean isSameUser(FeatureUser u) {
990            if (u == null) return false;
991
992            return isSameUser(u.mPid, u.mUid, u.mNetworkType, u.mFeature);
993        }
994
995        public boolean isSameUser(int pid, int uid, int networkType, String feature) {
996            if ((mPid == pid) && (mUid == uid) && (mNetworkType == networkType) &&
997                TextUtils.equals(mFeature, feature)) {
998                return true;
999            }
1000            return false;
1001        }
1002
1003        public String toString() {
1004            return "FeatureUser("+mNetworkType+","+mFeature+","+mPid+","+mUid+"), created " +
1005                    (System.currentTimeMillis() - mCreateTime) + " mSec ago";
1006        }
1007    }
1008
1009    // javadoc from interface
1010    public int startUsingNetworkFeature(int networkType, String feature,
1011            IBinder binder) {
1012        long startTime = 0;
1013        if (DBG) {
1014            startTime = SystemClock.elapsedRealtime();
1015        }
1016        if (VDBG) {
1017            log("startUsingNetworkFeature for net " + networkType + ": " + feature + ", uid="
1018                    + Binder.getCallingUid());
1019        }
1020        enforceChangePermission();
1021        try {
1022            if (!ConnectivityManager.isNetworkTypeValid(networkType) ||
1023                    mNetConfigs[networkType] == null) {
1024                return PhoneConstants.APN_REQUEST_FAILED;
1025            }
1026
1027            FeatureUser f = new FeatureUser(networkType, feature, binder);
1028
1029            // TODO - move this into individual networktrackers
1030            int usedNetworkType = convertFeatureToNetworkType(networkType, feature);
1031
1032            if (mProtectedNetworks.contains(usedNetworkType)) {
1033                enforceConnectivityInternalPermission();
1034            }
1035
1036            // if UID is restricted, don't allow them to bring up metered APNs
1037            final boolean networkMetered = isNetworkMeteredUnchecked(usedNetworkType);
1038            final int uidRules;
1039            synchronized (mRulesLock) {
1040                uidRules = mUidRules.get(Binder.getCallingUid(), RULE_ALLOW_ALL);
1041            }
1042            if (networkMetered && (uidRules & RULE_REJECT_METERED) != 0) {
1043                return PhoneConstants.APN_REQUEST_FAILED;
1044            }
1045
1046            NetworkStateTracker network = mNetTrackers[usedNetworkType];
1047            if (network != null) {
1048                Integer currentPid = new Integer(getCallingPid());
1049                if (usedNetworkType != networkType) {
1050                    NetworkInfo ni = network.getNetworkInfo();
1051
1052                    if (ni.isAvailable() == false) {
1053                        if (!TextUtils.equals(feature,Phone.FEATURE_ENABLE_DUN_ALWAYS)) {
1054                            if (DBG) log("special network not available ni=" + ni.getTypeName());
1055                            return PhoneConstants.APN_TYPE_NOT_AVAILABLE;
1056                        } else {
1057                            // else make the attempt anyway - probably giving REQUEST_STARTED below
1058                            if (DBG) {
1059                                log("special network not available, but try anyway ni=" +
1060                                        ni.getTypeName());
1061                            }
1062                        }
1063                    }
1064
1065                    int restoreTimer = getRestoreDefaultNetworkDelay(usedNetworkType);
1066
1067                    synchronized(this) {
1068                        boolean addToList = true;
1069                        if (restoreTimer < 0) {
1070                            // In case there is no timer is specified for the feature,
1071                            // make sure we don't add duplicate entry with the same request.
1072                            for (FeatureUser u : mFeatureUsers) {
1073                                if (u.isSameUser(f)) {
1074                                    // Duplicate user is found. Do not add.
1075                                    addToList = false;
1076                                    break;
1077                                }
1078                            }
1079                        }
1080
1081                        if (addToList) mFeatureUsers.add(f);
1082                        if (!mNetRequestersPids[usedNetworkType].contains(currentPid)) {
1083                            // this gets used for per-pid dns when connected
1084                            mNetRequestersPids[usedNetworkType].add(currentPid);
1085                        }
1086                    }
1087
1088                    if (restoreTimer >= 0) {
1089                        mHandler.sendMessageDelayed(mHandler.obtainMessage(
1090                                EVENT_RESTORE_DEFAULT_NETWORK, f), restoreTimer);
1091                    }
1092
1093                    if ((ni.isConnectedOrConnecting() == true) &&
1094                            !network.isTeardownRequested()) {
1095                        if (ni.isConnected() == true) {
1096                            final long token = Binder.clearCallingIdentity();
1097                            try {
1098                                // add the pid-specific dns
1099                                handleDnsConfigurationChange(usedNetworkType);
1100                                if (VDBG) log("special network already active");
1101                            } finally {
1102                                Binder.restoreCallingIdentity(token);
1103                            }
1104                            return PhoneConstants.APN_ALREADY_ACTIVE;
1105                        }
1106                        if (VDBG) log("special network already connecting");
1107                        return PhoneConstants.APN_REQUEST_STARTED;
1108                    }
1109
1110                    // check if the radio in play can make another contact
1111                    // assume if cannot for now
1112
1113                    if (DBG) {
1114                        log("startUsingNetworkFeature reconnecting to " + networkType + ": " +
1115                                feature);
1116                    }
1117                    network.reconnect();
1118                    return PhoneConstants.APN_REQUEST_STARTED;
1119                } else {
1120                    // need to remember this unsupported request so we respond appropriately on stop
1121                    synchronized(this) {
1122                        mFeatureUsers.add(f);
1123                        if (!mNetRequestersPids[usedNetworkType].contains(currentPid)) {
1124                            // this gets used for per-pid dns when connected
1125                            mNetRequestersPids[usedNetworkType].add(currentPid);
1126                        }
1127                    }
1128                    return -1;
1129                }
1130            }
1131            return PhoneConstants.APN_TYPE_NOT_AVAILABLE;
1132         } finally {
1133            if (DBG) {
1134                final long execTime = SystemClock.elapsedRealtime() - startTime;
1135                if (execTime > 250) {
1136                    loge("startUsingNetworkFeature took too long: " + execTime + "ms");
1137                } else {
1138                    if (VDBG) log("startUsingNetworkFeature took " + execTime + "ms");
1139                }
1140            }
1141         }
1142    }
1143
1144    // javadoc from interface
1145    public int stopUsingNetworkFeature(int networkType, String feature) {
1146        enforceChangePermission();
1147
1148        int pid = getCallingPid();
1149        int uid = getCallingUid();
1150
1151        FeatureUser u = null;
1152        boolean found = false;
1153
1154        synchronized(this) {
1155            for (FeatureUser x : mFeatureUsers) {
1156                if (x.isSameUser(pid, uid, networkType, feature)) {
1157                    u = x;
1158                    found = true;
1159                    break;
1160                }
1161            }
1162        }
1163        if (found && u != null) {
1164            // stop regardless of how many other time this proc had called start
1165            return stopUsingNetworkFeature(u, true);
1166        } else {
1167            // none found!
1168            if (VDBG) log("stopUsingNetworkFeature - not a live request, ignoring");
1169            return 1;
1170        }
1171    }
1172
1173    private int stopUsingNetworkFeature(FeatureUser u, boolean ignoreDups) {
1174        int networkType = u.mNetworkType;
1175        String feature = u.mFeature;
1176        int pid = u.mPid;
1177        int uid = u.mUid;
1178
1179        NetworkStateTracker tracker = null;
1180        boolean callTeardown = false;  // used to carry our decision outside of sync block
1181
1182        if (VDBG) {
1183            log("stopUsingNetworkFeature: net " + networkType + ": " + feature);
1184        }
1185
1186        if (!ConnectivityManager.isNetworkTypeValid(networkType)) {
1187            if (DBG) {
1188                log("stopUsingNetworkFeature: net " + networkType + ": " + feature +
1189                        ", net is invalid");
1190            }
1191            return -1;
1192        }
1193
1194        // need to link the mFeatureUsers list with the mNetRequestersPids state in this
1195        // sync block
1196        synchronized(this) {
1197            // check if this process still has an outstanding start request
1198            if (!mFeatureUsers.contains(u)) {
1199                if (VDBG) {
1200                    log("stopUsingNetworkFeature: this process has no outstanding requests" +
1201                        ", ignoring");
1202                }
1203                return 1;
1204            }
1205            u.unlinkDeathRecipient();
1206            mFeatureUsers.remove(mFeatureUsers.indexOf(u));
1207            // If we care about duplicate requests, check for that here.
1208            //
1209            // This is done to support the extension of a request - the app
1210            // can request we start the network feature again and renew the
1211            // auto-shutoff delay.  Normal "stop" calls from the app though
1212            // do not pay attention to duplicate requests - in effect the
1213            // API does not refcount and a single stop will counter multiple starts.
1214            if (ignoreDups == false) {
1215                for (FeatureUser x : mFeatureUsers) {
1216                    if (x.isSameUser(u)) {
1217                        if (VDBG) log("stopUsingNetworkFeature: dup is found, ignoring");
1218                        return 1;
1219                    }
1220                }
1221            }
1222
1223            // TODO - move to individual network trackers
1224            int usedNetworkType = convertFeatureToNetworkType(networkType, feature);
1225
1226            tracker =  mNetTrackers[usedNetworkType];
1227            if (tracker == null) {
1228                if (DBG) {
1229                    log("stopUsingNetworkFeature: net " + networkType + ": " + feature +
1230                            " no known tracker for used net type " + usedNetworkType);
1231                }
1232                return -1;
1233            }
1234            if (usedNetworkType != networkType) {
1235                Integer currentPid = new Integer(pid);
1236                mNetRequestersPids[usedNetworkType].remove(currentPid);
1237                reassessPidDns(pid, true);
1238                if (mNetRequestersPids[usedNetworkType].size() != 0) {
1239                    if (VDBG) {
1240                        log("stopUsingNetworkFeature: net " + networkType + ": " + feature +
1241                                " others still using it");
1242                    }
1243                    return 1;
1244                }
1245                callTeardown = true;
1246            } else {
1247                if (DBG) {
1248                    log("stopUsingNetworkFeature: net " + networkType + ": " + feature +
1249                            " not a known feature - dropping");
1250                }
1251            }
1252        }
1253
1254        if (callTeardown) {
1255            if (DBG) {
1256                log("stopUsingNetworkFeature: teardown net " + networkType + ": " + feature);
1257            }
1258            tracker.teardown();
1259            return 1;
1260        } else {
1261            return -1;
1262        }
1263    }
1264
1265    /**
1266     * @deprecated use requestRouteToHostAddress instead
1267     *
1268     * Ensure that a network route exists to deliver traffic to the specified
1269     * host via the specified network interface.
1270     * @param networkType the type of the network over which traffic to the
1271     * specified host is to be routed
1272     * @param hostAddress the IP address of the host to which the route is
1273     * desired
1274     * @return {@code true} on success, {@code false} on failure
1275     */
1276    public boolean requestRouteToHost(int networkType, int hostAddress) {
1277        InetAddress inetAddress = NetworkUtils.intToInetAddress(hostAddress);
1278
1279        if (inetAddress == null) {
1280            return false;
1281        }
1282
1283        return requestRouteToHostAddress(networkType, inetAddress.getAddress());
1284    }
1285
1286    /**
1287     * Ensure that a network route exists to deliver traffic to the specified
1288     * host via the specified network interface.
1289     * @param networkType the type of the network over which traffic to the
1290     * specified host is to be routed
1291     * @param hostAddress the IP address of the host to which the route is
1292     * desired
1293     * @return {@code true} on success, {@code false} on failure
1294     */
1295    public boolean requestRouteToHostAddress(int networkType, byte[] hostAddress) {
1296        enforceChangePermission();
1297        if (mProtectedNetworks.contains(networkType)) {
1298            enforceConnectivityInternalPermission();
1299        }
1300
1301        if (!ConnectivityManager.isNetworkTypeValid(networkType)) {
1302            if (DBG) log("requestRouteToHostAddress on invalid network: " + networkType);
1303            return false;
1304        }
1305        NetworkStateTracker tracker = mNetTrackers[networkType];
1306
1307        if (tracker == null || !tracker.getNetworkInfo().isConnected() ||
1308                tracker.isTeardownRequested()) {
1309            if (VDBG) {
1310                log("requestRouteToHostAddress on down network " +
1311                           "(" + networkType + ") - dropped");
1312            }
1313            return false;
1314        }
1315        final long token = Binder.clearCallingIdentity();
1316        try {
1317            InetAddress addr = InetAddress.getByAddress(hostAddress);
1318            LinkProperties lp = tracker.getLinkProperties();
1319            return addRouteToAddress(lp, addr);
1320        } catch (UnknownHostException e) {
1321            if (DBG) log("requestRouteToHostAddress got " + e.toString());
1322        } finally {
1323            Binder.restoreCallingIdentity(token);
1324        }
1325        return false;
1326    }
1327
1328    private boolean addRoute(LinkProperties p, RouteInfo r, boolean toDefaultTable) {
1329        return modifyRoute(p.getInterfaceName(), p, r, 0, ADD, toDefaultTable);
1330    }
1331
1332    private boolean removeRoute(LinkProperties p, RouteInfo r, boolean toDefaultTable) {
1333        return modifyRoute(p.getInterfaceName(), p, r, 0, REMOVE, toDefaultTable);
1334    }
1335
1336    private boolean addRouteToAddress(LinkProperties lp, InetAddress addr) {
1337        return modifyRouteToAddress(lp, addr, ADD, TO_DEFAULT_TABLE);
1338    }
1339
1340    private boolean removeRouteToAddress(LinkProperties lp, InetAddress addr) {
1341        return modifyRouteToAddress(lp, addr, REMOVE, TO_DEFAULT_TABLE);
1342    }
1343
1344    private boolean modifyRouteToAddress(LinkProperties lp, InetAddress addr, boolean doAdd,
1345            boolean toDefaultTable) {
1346        RouteInfo bestRoute = RouteInfo.selectBestRoute(lp.getRoutes(), addr);
1347        if (bestRoute == null) {
1348            bestRoute = RouteInfo.makeHostRoute(addr);
1349        } else {
1350            if (bestRoute.getGateway().equals(addr)) {
1351                // if there is no better route, add the implied hostroute for our gateway
1352                bestRoute = RouteInfo.makeHostRoute(addr);
1353            } else {
1354                // if we will connect to this through another route, add a direct route
1355                // to it's gateway
1356                bestRoute = RouteInfo.makeHostRoute(addr, bestRoute.getGateway());
1357            }
1358        }
1359        return modifyRoute(lp.getInterfaceName(), lp, bestRoute, 0, doAdd, toDefaultTable);
1360    }
1361
1362    private boolean modifyRoute(String ifaceName, LinkProperties lp, RouteInfo r, int cycleCount,
1363            boolean doAdd, boolean toDefaultTable) {
1364        if ((ifaceName == null) || (lp == null) || (r == null)) {
1365            if (DBG) log("modifyRoute got unexpected null: " + ifaceName + ", " + lp + ", " + r);
1366            return false;
1367        }
1368
1369        if (cycleCount > MAX_HOSTROUTE_CYCLE_COUNT) {
1370            loge("Error modifying route - too much recursion");
1371            return false;
1372        }
1373
1374        if (r.isHostRoute() == false) {
1375            RouteInfo bestRoute = RouteInfo.selectBestRoute(lp.getRoutes(), r.getGateway());
1376            if (bestRoute != null) {
1377                if (bestRoute.getGateway().equals(r.getGateway())) {
1378                    // if there is no better route, add the implied hostroute for our gateway
1379                    bestRoute = RouteInfo.makeHostRoute(r.getGateway());
1380                } else {
1381                    // if we will connect to our gateway through another route, add a direct
1382                    // route to it's gateway
1383                    bestRoute = RouteInfo.makeHostRoute(r.getGateway(), bestRoute.getGateway());
1384                }
1385                modifyRoute(ifaceName, lp, bestRoute, cycleCount+1, doAdd, toDefaultTable);
1386            }
1387        }
1388        if (doAdd) {
1389            if (VDBG) log("Adding " + r + " for interface " + ifaceName);
1390            try {
1391                if (toDefaultTable) {
1392                    mAddedRoutes.add(r);  // only track default table - only one apps can effect
1393                    mNetd.addRoute(ifaceName, r);
1394                } else {
1395                    mNetd.addSecondaryRoute(ifaceName, r);
1396                }
1397            } catch (Exception e) {
1398                // never crash - catch them all
1399                if (DBG) loge("Exception trying to add a route: " + e);
1400                return false;
1401            }
1402        } else {
1403            // if we remove this one and there are no more like it, then refcount==0 and
1404            // we can remove it from the table
1405            if (toDefaultTable) {
1406                mAddedRoutes.remove(r);
1407                if (mAddedRoutes.contains(r) == false) {
1408                    if (VDBG) log("Removing " + r + " for interface " + ifaceName);
1409                    try {
1410                        mNetd.removeRoute(ifaceName, r);
1411                    } catch (Exception e) {
1412                        // never crash - catch them all
1413                        if (VDBG) loge("Exception trying to remove a route: " + e);
1414                        return false;
1415                    }
1416                } else {
1417                    if (VDBG) log("not removing " + r + " as it's still in use");
1418                }
1419            } else {
1420                if (VDBG) log("Removing " + r + " for interface " + ifaceName);
1421                try {
1422                    mNetd.removeSecondaryRoute(ifaceName, r);
1423                } catch (Exception e) {
1424                    // never crash - catch them all
1425                    if (VDBG) loge("Exception trying to remove a route: " + e);
1426                    return false;
1427                }
1428            }
1429        }
1430        return true;
1431    }
1432
1433    /**
1434     * @see ConnectivityManager#getMobileDataEnabled()
1435     */
1436    public boolean getMobileDataEnabled() {
1437        // TODO: This detail should probably be in DataConnectionTracker's
1438        //       which is where we store the value and maybe make this
1439        //       asynchronous.
1440        enforceAccessPermission();
1441        boolean retVal = Settings.Secure.getInt(mContext.getContentResolver(),
1442                Settings.Secure.MOBILE_DATA, 1) == 1;
1443        if (VDBG) log("getMobileDataEnabled returning " + retVal);
1444        return retVal;
1445    }
1446
1447    public void setDataDependency(int networkType, boolean met) {
1448        enforceConnectivityInternalPermission();
1449
1450        mHandler.sendMessage(mHandler.obtainMessage(EVENT_SET_DEPENDENCY_MET,
1451                (met ? ENABLED : DISABLED), networkType));
1452    }
1453
1454    private void handleSetDependencyMet(int networkType, boolean met) {
1455        if (mNetTrackers[networkType] != null) {
1456            if (DBG) {
1457                log("handleSetDependencyMet(" + networkType + ", " + met + ")");
1458            }
1459            mNetTrackers[networkType].setDependencyMet(met);
1460        }
1461    }
1462
1463    private INetworkPolicyListener mPolicyListener = new INetworkPolicyListener.Stub() {
1464        @Override
1465        public void onUidRulesChanged(int uid, int uidRules) {
1466            // caller is NPMS, since we only register with them
1467            if (LOGD_RULES) {
1468                log("onUidRulesChanged(uid=" + uid + ", uidRules=" + uidRules + ")");
1469            }
1470
1471            synchronized (mRulesLock) {
1472                // skip update when we've already applied rules
1473                final int oldRules = mUidRules.get(uid, RULE_ALLOW_ALL);
1474                if (oldRules == uidRules) return;
1475
1476                mUidRules.put(uid, uidRules);
1477            }
1478
1479            // TODO: notify UID when it has requested targeted updates
1480        }
1481
1482        @Override
1483        public void onMeteredIfacesChanged(String[] meteredIfaces) {
1484            // caller is NPMS, since we only register with them
1485            if (LOGD_RULES) {
1486                log("onMeteredIfacesChanged(ifaces=" + Arrays.toString(meteredIfaces) + ")");
1487            }
1488
1489            synchronized (mRulesLock) {
1490                mMeteredIfaces.clear();
1491                for (String iface : meteredIfaces) {
1492                    mMeteredIfaces.add(iface);
1493                }
1494            }
1495        }
1496
1497        @Override
1498        public void onRestrictBackgroundChanged(boolean restrictBackground) {
1499            // caller is NPMS, since we only register with them
1500            if (LOGD_RULES) {
1501                log("onRestrictBackgroundChanged(restrictBackground=" + restrictBackground + ")");
1502            }
1503
1504            // kick off connectivity change broadcast for active network, since
1505            // global background policy change is radical.
1506            final int networkType = mActiveDefaultNetwork;
1507            if (isNetworkTypeValid(networkType)) {
1508                final NetworkStateTracker tracker = mNetTrackers[networkType];
1509                if (tracker != null) {
1510                    final NetworkInfo info = tracker.getNetworkInfo();
1511                    if (info != null && info.isConnected()) {
1512                        sendConnectedBroadcast(info);
1513                    }
1514                }
1515            }
1516        }
1517    };
1518
1519    /**
1520     * @see ConnectivityManager#setMobileDataEnabled(boolean)
1521     */
1522    public void setMobileDataEnabled(boolean enabled) {
1523        enforceChangePermission();
1524        if (DBG) log("setMobileDataEnabled(" + enabled + ")");
1525
1526        mHandler.sendMessage(mHandler.obtainMessage(EVENT_SET_MOBILE_DATA,
1527                (enabled ? ENABLED : DISABLED), 0));
1528    }
1529
1530    private void handleSetMobileData(boolean enabled) {
1531        if (mNetTrackers[ConnectivityManager.TYPE_MOBILE] != null) {
1532            if (VDBG) {
1533                log(mNetTrackers[ConnectivityManager.TYPE_MOBILE].toString() + enabled);
1534            }
1535            mNetTrackers[ConnectivityManager.TYPE_MOBILE].setUserDataEnable(enabled);
1536        }
1537        if (mNetTrackers[ConnectivityManager.TYPE_WIMAX] != null) {
1538            if (VDBG) {
1539                log(mNetTrackers[ConnectivityManager.TYPE_WIMAX].toString() + enabled);
1540            }
1541            mNetTrackers[ConnectivityManager.TYPE_WIMAX].setUserDataEnable(enabled);
1542        }
1543    }
1544
1545    @Override
1546    public void setPolicyDataEnable(int networkType, boolean enabled) {
1547        // only someone like NPMS should only be calling us
1548        mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
1549
1550        mHandler.sendMessage(mHandler.obtainMessage(
1551                EVENT_SET_POLICY_DATA_ENABLE, networkType, (enabled ? ENABLED : DISABLED)));
1552    }
1553
1554    private void handleSetPolicyDataEnable(int networkType, boolean enabled) {
1555        if (isNetworkTypeValid(networkType)) {
1556            final NetworkStateTracker tracker = mNetTrackers[networkType];
1557            if (tracker != null) {
1558                tracker.setPolicyDataEnable(enabled);
1559            }
1560        }
1561    }
1562
1563    private void enforceAccessPermission() {
1564        mContext.enforceCallingOrSelfPermission(
1565                android.Manifest.permission.ACCESS_NETWORK_STATE,
1566                "ConnectivityService");
1567    }
1568
1569    private void enforceChangePermission() {
1570        mContext.enforceCallingOrSelfPermission(
1571                android.Manifest.permission.CHANGE_NETWORK_STATE,
1572                "ConnectivityService");
1573    }
1574
1575    // TODO Make this a special check when it goes public
1576    private void enforceTetherChangePermission() {
1577        mContext.enforceCallingOrSelfPermission(
1578                android.Manifest.permission.CHANGE_NETWORK_STATE,
1579                "ConnectivityService");
1580    }
1581
1582    private void enforceTetherAccessPermission() {
1583        mContext.enforceCallingOrSelfPermission(
1584                android.Manifest.permission.ACCESS_NETWORK_STATE,
1585                "ConnectivityService");
1586    }
1587
1588    private void enforceConnectivityInternalPermission() {
1589        mContext.enforceCallingOrSelfPermission(
1590                android.Manifest.permission.CONNECTIVITY_INTERNAL,
1591                "ConnectivityService");
1592    }
1593
1594    /**
1595     * Handle a {@code DISCONNECTED} event. If this pertains to the non-active
1596     * network, we ignore it. If it is for the active network, we send out a
1597     * broadcast. But first, we check whether it might be possible to connect
1598     * to a different network.
1599     * @param info the {@code NetworkInfo} for the network
1600     */
1601    private void handleDisconnect(NetworkInfo info) {
1602
1603        int prevNetType = info.getType();
1604
1605        mNetTrackers[prevNetType].setTeardownRequested(false);
1606        /*
1607         * If the disconnected network is not the active one, then don't report
1608         * this as a loss of connectivity. What probably happened is that we're
1609         * getting the disconnect for a network that we explicitly disabled
1610         * in accordance with network preference policies.
1611         */
1612        if (!mNetConfigs[prevNetType].isDefault()) {
1613            List pids = mNetRequestersPids[prevNetType];
1614            for (int i = 0; i<pids.size(); i++) {
1615                Integer pid = (Integer)pids.get(i);
1616                // will remove them because the net's no longer connected
1617                // need to do this now as only now do we know the pids and
1618                // can properly null things that are no longer referenced.
1619                reassessPidDns(pid.intValue(), false);
1620            }
1621        }
1622
1623        Intent intent = new Intent(ConnectivityManager.CONNECTIVITY_ACTION);
1624        intent.putExtra(ConnectivityManager.EXTRA_NETWORK_INFO, info);
1625        intent.putExtra(ConnectivityManager.EXTRA_NETWORK_TYPE, info.getType());
1626        if (info.isFailover()) {
1627            intent.putExtra(ConnectivityManager.EXTRA_IS_FAILOVER, true);
1628            info.setFailover(false);
1629        }
1630        if (info.getReason() != null) {
1631            intent.putExtra(ConnectivityManager.EXTRA_REASON, info.getReason());
1632        }
1633        if (info.getExtraInfo() != null) {
1634            intent.putExtra(ConnectivityManager.EXTRA_EXTRA_INFO,
1635                    info.getExtraInfo());
1636        }
1637
1638        if (mNetConfigs[prevNetType].isDefault()) {
1639            tryFailover(prevNetType);
1640            if (mActiveDefaultNetwork != -1) {
1641                NetworkInfo switchTo = mNetTrackers[mActiveDefaultNetwork].getNetworkInfo();
1642                intent.putExtra(ConnectivityManager.EXTRA_OTHER_NETWORK_INFO, switchTo);
1643            } else {
1644                mDefaultInetConditionPublished = 0; // we're not connected anymore
1645                intent.putExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, true);
1646            }
1647        }
1648        intent.putExtra(ConnectivityManager.EXTRA_INET_CONDITION, mDefaultInetConditionPublished);
1649
1650        // Reset interface if no other connections are using the same interface
1651        boolean doReset = true;
1652        LinkProperties linkProperties = mNetTrackers[prevNetType].getLinkProperties();
1653        if (linkProperties != null) {
1654            String oldIface = linkProperties.getInterfaceName();
1655            if (TextUtils.isEmpty(oldIface) == false) {
1656                for (NetworkStateTracker networkStateTracker : mNetTrackers) {
1657                    if (networkStateTracker == null) continue;
1658                    NetworkInfo networkInfo = networkStateTracker.getNetworkInfo();
1659                    if (networkInfo.isConnected() && networkInfo.getType() != prevNetType) {
1660                        LinkProperties l = networkStateTracker.getLinkProperties();
1661                        if (l == null) continue;
1662                        if (oldIface.equals(l.getInterfaceName())) {
1663                            doReset = false;
1664                            break;
1665                        }
1666                    }
1667                }
1668            }
1669        }
1670
1671        // do this before we broadcast the change
1672        handleConnectivityChange(prevNetType, doReset);
1673
1674        final Intent immediateIntent = new Intent(intent);
1675        immediateIntent.setAction(CONNECTIVITY_ACTION_IMMEDIATE);
1676        sendStickyBroadcast(immediateIntent);
1677        sendStickyBroadcastDelayed(intent, getConnectivityChangeDelay());
1678        /*
1679         * If the failover network is already connected, then immediately send
1680         * out a followup broadcast indicating successful failover
1681         */
1682        if (mActiveDefaultNetwork != -1) {
1683            sendConnectedBroadcastDelayed(mNetTrackers[mActiveDefaultNetwork].getNetworkInfo(),
1684                    getConnectivityChangeDelay());
1685        }
1686    }
1687
1688    private void tryFailover(int prevNetType) {
1689        /*
1690         * If this is a default network, check if other defaults are available.
1691         * Try to reconnect on all available and let them hash it out when
1692         * more than one connects.
1693         */
1694        if (mNetConfigs[prevNetType].isDefault()) {
1695            if (mActiveDefaultNetwork == prevNetType) {
1696                mActiveDefaultNetwork = -1;
1697            }
1698
1699            // don't signal a reconnect for anything lower or equal priority than our
1700            // current connected default
1701            // TODO - don't filter by priority now - nice optimization but risky
1702//            int currentPriority = -1;
1703//            if (mActiveDefaultNetwork != -1) {
1704//                currentPriority = mNetConfigs[mActiveDefaultNetwork].mPriority;
1705//            }
1706            for (int checkType=0; checkType <= ConnectivityManager.MAX_NETWORK_TYPE; checkType++) {
1707                if (checkType == prevNetType) continue;
1708                if (mNetConfigs[checkType] == null) continue;
1709                if (!mNetConfigs[checkType].isDefault()) continue;
1710                if (mNetTrackers[checkType] == null) continue;
1711
1712// Enabling the isAvailable() optimization caused mobile to not get
1713// selected if it was in the middle of error handling. Specifically
1714// a moble connection that took 30 seconds to complete the DEACTIVATE_DATA_CALL
1715// would not be available and we wouldn't get connected to anything.
1716// So removing the isAvailable() optimization below for now. TODO: This
1717// optimization should work and we need to investigate why it doesn't work.
1718// This could be related to how DEACTIVATE_DATA_CALL is reporting its
1719// complete before it is really complete.
1720//                if (!mNetTrackers[checkType].isAvailable()) continue;
1721
1722//                if (currentPriority >= mNetConfigs[checkType].mPriority) continue;
1723
1724                NetworkStateTracker checkTracker = mNetTrackers[checkType];
1725                NetworkInfo checkInfo = checkTracker.getNetworkInfo();
1726                if (!checkInfo.isConnectedOrConnecting() || checkTracker.isTeardownRequested()) {
1727                    checkInfo.setFailover(true);
1728                    checkTracker.reconnect();
1729                }
1730                if (DBG) log("Attempting to switch to " + checkInfo.getTypeName());
1731            }
1732        }
1733    }
1734
1735    private void sendConnectedBroadcast(NetworkInfo info) {
1736        sendGeneralBroadcast(info, CONNECTIVITY_ACTION_IMMEDIATE);
1737        sendGeneralBroadcast(info, CONNECTIVITY_ACTION);
1738    }
1739
1740    private void sendConnectedBroadcastDelayed(NetworkInfo info, int delayMs) {
1741        sendGeneralBroadcast(info, CONNECTIVITY_ACTION_IMMEDIATE);
1742        sendGeneralBroadcastDelayed(info, CONNECTIVITY_ACTION, delayMs);
1743    }
1744
1745    private void sendInetConditionBroadcast(NetworkInfo info) {
1746        sendGeneralBroadcast(info, ConnectivityManager.INET_CONDITION_ACTION);
1747    }
1748
1749    private Intent makeGeneralIntent(NetworkInfo info, String bcastType) {
1750        Intent intent = new Intent(bcastType);
1751        intent.putExtra(ConnectivityManager.EXTRA_NETWORK_INFO, info);
1752        intent.putExtra(ConnectivityManager.EXTRA_NETWORK_TYPE, info.getType());
1753        if (info.isFailover()) {
1754            intent.putExtra(ConnectivityManager.EXTRA_IS_FAILOVER, true);
1755            info.setFailover(false);
1756        }
1757        if (info.getReason() != null) {
1758            intent.putExtra(ConnectivityManager.EXTRA_REASON, info.getReason());
1759        }
1760        if (info.getExtraInfo() != null) {
1761            intent.putExtra(ConnectivityManager.EXTRA_EXTRA_INFO,
1762                    info.getExtraInfo());
1763        }
1764        intent.putExtra(ConnectivityManager.EXTRA_INET_CONDITION, mDefaultInetConditionPublished);
1765        return intent;
1766    }
1767
1768    private void sendGeneralBroadcast(NetworkInfo info, String bcastType) {
1769        sendStickyBroadcast(makeGeneralIntent(info, bcastType));
1770    }
1771
1772    private void sendGeneralBroadcastDelayed(NetworkInfo info, String bcastType, int delayMs) {
1773        sendStickyBroadcastDelayed(makeGeneralIntent(info, bcastType), delayMs);
1774    }
1775
1776    private void sendDataActivityBroadcast(int deviceType, boolean active) {
1777        Intent intent = new Intent(ConnectivityManager.ACTION_DATA_ACTIVITY_CHANGE);
1778        intent.putExtra(ConnectivityManager.EXTRA_DEVICE_TYPE, deviceType);
1779        intent.putExtra(ConnectivityManager.EXTRA_IS_ACTIVE, active);
1780        mContext.sendOrderedBroadcast(intent, RECEIVE_DATA_ACTIVITY_CHANGE);
1781    }
1782
1783    /**
1784     * Called when an attempt to fail over to another network has failed.
1785     * @param info the {@link NetworkInfo} for the failed network
1786     */
1787    private void handleConnectionFailure(NetworkInfo info) {
1788        mNetTrackers[info.getType()].setTeardownRequested(false);
1789
1790        String reason = info.getReason();
1791        String extraInfo = info.getExtraInfo();
1792
1793        String reasonText;
1794        if (reason == null) {
1795            reasonText = ".";
1796        } else {
1797            reasonText = " (" + reason + ").";
1798        }
1799        loge("Attempt to connect to " + info.getTypeName() + " failed" + reasonText);
1800
1801        Intent intent = new Intent(ConnectivityManager.CONNECTIVITY_ACTION);
1802        intent.putExtra(ConnectivityManager.EXTRA_NETWORK_INFO, info);
1803        intent.putExtra(ConnectivityManager.EXTRA_NETWORK_TYPE, info.getType());
1804        if (getActiveNetworkInfo() == null) {
1805            intent.putExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, true);
1806        }
1807        if (reason != null) {
1808            intent.putExtra(ConnectivityManager.EXTRA_REASON, reason);
1809        }
1810        if (extraInfo != null) {
1811            intent.putExtra(ConnectivityManager.EXTRA_EXTRA_INFO, extraInfo);
1812        }
1813        if (info.isFailover()) {
1814            intent.putExtra(ConnectivityManager.EXTRA_IS_FAILOVER, true);
1815            info.setFailover(false);
1816        }
1817
1818        if (mNetConfigs[info.getType()].isDefault()) {
1819            tryFailover(info.getType());
1820            if (mActiveDefaultNetwork != -1) {
1821                NetworkInfo switchTo = mNetTrackers[mActiveDefaultNetwork].getNetworkInfo();
1822                intent.putExtra(ConnectivityManager.EXTRA_OTHER_NETWORK_INFO, switchTo);
1823            } else {
1824                mDefaultInetConditionPublished = 0;
1825                intent.putExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, true);
1826            }
1827        }
1828
1829        intent.putExtra(ConnectivityManager.EXTRA_INET_CONDITION, mDefaultInetConditionPublished);
1830
1831        final Intent immediateIntent = new Intent(intent);
1832        immediateIntent.setAction(CONNECTIVITY_ACTION_IMMEDIATE);
1833        sendStickyBroadcast(immediateIntent);
1834        sendStickyBroadcast(intent);
1835        /*
1836         * If the failover network is already connected, then immediately send
1837         * out a followup broadcast indicating successful failover
1838         */
1839        if (mActiveDefaultNetwork != -1) {
1840            sendConnectedBroadcast(mNetTrackers[mActiveDefaultNetwork].getNetworkInfo());
1841        }
1842    }
1843
1844    private void sendStickyBroadcast(Intent intent) {
1845        synchronized(this) {
1846            if (!mSystemReady) {
1847                mInitialBroadcast = new Intent(intent);
1848            }
1849            intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
1850            if (VDBG) {
1851                log("sendStickyBroadcast: action=" + intent.getAction());
1852            }
1853
1854            mContext.sendStickyBroadcast(intent);
1855        }
1856    }
1857
1858    private void sendStickyBroadcastDelayed(Intent intent, int delayMs) {
1859        if (delayMs <= 0) {
1860            sendStickyBroadcast(intent);
1861        } else {
1862            if (VDBG) {
1863                log("sendStickyBroadcastDelayed: delayMs=" + delayMs + ", action="
1864                        + intent.getAction());
1865            }
1866            mHandler.sendMessageDelayed(mHandler.obtainMessage(
1867                    EVENT_SEND_STICKY_BROADCAST_INTENT, intent), delayMs);
1868        }
1869    }
1870
1871    void systemReady() {
1872        synchronized(this) {
1873            mSystemReady = true;
1874            if (mInitialBroadcast != null) {
1875                mContext.sendStickyBroadcast(mInitialBroadcast);
1876                mInitialBroadcast = null;
1877            }
1878        }
1879        // load the global proxy at startup
1880        mHandler.sendMessage(mHandler.obtainMessage(EVENT_APPLY_GLOBAL_HTTP_PROXY));
1881    }
1882
1883    private void handleConnect(NetworkInfo info) {
1884        final int type = info.getType();
1885
1886        // snapshot isFailover, because sendConnectedBroadcast() resets it
1887        boolean isFailover = info.isFailover();
1888        final NetworkStateTracker thisNet = mNetTrackers[type];
1889
1890        // if this is a default net and other default is running
1891        // kill the one not preferred
1892        if (mNetConfigs[type].isDefault()) {
1893            if (mActiveDefaultNetwork != -1 && mActiveDefaultNetwork != type) {
1894                if ((type != mNetworkPreference &&
1895                        mNetConfigs[mActiveDefaultNetwork].priority >
1896                        mNetConfigs[type].priority) ||
1897                        mNetworkPreference == mActiveDefaultNetwork) {
1898                        // don't accept this one
1899                        if (VDBG) {
1900                            log("Not broadcasting CONNECT_ACTION " +
1901                                "to torn down network " + info.getTypeName());
1902                        }
1903                        teardown(thisNet);
1904                        return;
1905                } else {
1906                    // tear down the other
1907                    NetworkStateTracker otherNet =
1908                            mNetTrackers[mActiveDefaultNetwork];
1909                    if (DBG) {
1910                        log("Policy requires " + otherNet.getNetworkInfo().getTypeName() +
1911                            " teardown");
1912                    }
1913                    if (!teardown(otherNet)) {
1914                        loge("Network declined teardown request");
1915                        teardown(thisNet);
1916                        return;
1917                    }
1918                }
1919            }
1920            synchronized (ConnectivityService.this) {
1921                // have a new default network, release the transition wakelock in a second
1922                // if it's held.  The second pause is to allow apps to reconnect over the
1923                // new network
1924                if (mNetTransitionWakeLock.isHeld()) {
1925                    mHandler.sendMessageDelayed(mHandler.obtainMessage(
1926                            EVENT_CLEAR_NET_TRANSITION_WAKELOCK,
1927                            mNetTransitionWakeLockSerialNumber, 0),
1928                            1000);
1929                }
1930            }
1931            mActiveDefaultNetwork = type;
1932            // this will cause us to come up initially as unconnected and switching
1933            // to connected after our normal pause unless somebody reports us as reall
1934            // disconnected
1935            mDefaultInetConditionPublished = 0;
1936            mDefaultConnectionSequence++;
1937            mInetConditionChangeInFlight = false;
1938            // Don't do this - if we never sign in stay, grey
1939            //reportNetworkCondition(mActiveDefaultNetwork, 100);
1940        }
1941        thisNet.setTeardownRequested(false);
1942        updateNetworkSettings(thisNet);
1943        handleConnectivityChange(type, false);
1944        sendConnectedBroadcastDelayed(info, getConnectivityChangeDelay());
1945
1946        // notify battery stats service about this network
1947        final String iface = thisNet.getLinkProperties().getInterfaceName();
1948        if (iface != null) {
1949            try {
1950                BatteryStatsService.getService().noteNetworkInterfaceType(iface, type);
1951            } catch (RemoteException e) {
1952                // ignored; service lives in system_server
1953            }
1954        }
1955    }
1956
1957    /**
1958     * After a change in the connectivity state of a network. We're mainly
1959     * concerned with making sure that the list of DNS servers is set up
1960     * according to which networks are connected, and ensuring that the
1961     * right routing table entries exist.
1962     */
1963    private void handleConnectivityChange(int netType, boolean doReset) {
1964        int resetMask = doReset ? NetworkUtils.RESET_ALL_ADDRESSES : 0;
1965
1966        /*
1967         * If a non-default network is enabled, add the host routes that
1968         * will allow it's DNS servers to be accessed.
1969         */
1970        handleDnsConfigurationChange(netType);
1971
1972        LinkProperties curLp = mCurrentLinkProperties[netType];
1973        LinkProperties newLp = null;
1974
1975        if (mNetTrackers[netType].getNetworkInfo().isConnected()) {
1976            newLp = mNetTrackers[netType].getLinkProperties();
1977            if (VDBG) {
1978                log("handleConnectivityChange: changed linkProperty[" + netType + "]:" +
1979                        " doReset=" + doReset + " resetMask=" + resetMask +
1980                        "\n   curLp=" + curLp +
1981                        "\n   newLp=" + newLp);
1982            }
1983
1984            if (curLp != null) {
1985                if (curLp.isIdenticalInterfaceName(newLp)) {
1986                    CompareResult<LinkAddress> car = curLp.compareAddresses(newLp);
1987                    if ((car.removed.size() != 0) || (car.added.size() != 0)) {
1988                        for (LinkAddress linkAddr : car.removed) {
1989                            if (linkAddr.getAddress() instanceof Inet4Address) {
1990                                resetMask |= NetworkUtils.RESET_IPV4_ADDRESSES;
1991                            }
1992                            if (linkAddr.getAddress() instanceof Inet6Address) {
1993                                resetMask |= NetworkUtils.RESET_IPV6_ADDRESSES;
1994                            }
1995                        }
1996                        if (DBG) {
1997                            log("handleConnectivityChange: addresses changed" +
1998                                    " linkProperty[" + netType + "]:" + " resetMask=" + resetMask +
1999                                    "\n   car=" + car);
2000                        }
2001                    } else {
2002                        if (DBG) {
2003                            log("handleConnectivityChange: address are the same reset per doReset" +
2004                                   " linkProperty[" + netType + "]:" +
2005                                   " resetMask=" + resetMask);
2006                        }
2007                    }
2008                } else {
2009                    resetMask = NetworkUtils.RESET_ALL_ADDRESSES;
2010                    if (DBG) {
2011                        log("handleConnectivityChange: interface not not equivalent reset both" +
2012                                " linkProperty[" + netType + "]:" +
2013                                " resetMask=" + resetMask);
2014                    }
2015                }
2016            }
2017            if (mNetConfigs[netType].isDefault()) {
2018                handleApplyDefaultProxy(newLp.getHttpProxy());
2019            }
2020        } else {
2021            if (VDBG) {
2022                log("handleConnectivityChange: changed linkProperty[" + netType + "]:" +
2023                        " doReset=" + doReset + " resetMask=" + resetMask +
2024                        "\n  curLp=" + curLp +
2025                        "\n  newLp= null");
2026            }
2027        }
2028        mCurrentLinkProperties[netType] = newLp;
2029        boolean resetDns = updateRoutes(newLp, curLp, mNetConfigs[netType].isDefault());
2030
2031        if (resetMask != 0 || resetDns) {
2032            LinkProperties linkProperties = mNetTrackers[netType].getLinkProperties();
2033            if (linkProperties != null) {
2034                String iface = linkProperties.getInterfaceName();
2035                if (TextUtils.isEmpty(iface) == false) {
2036                    if (resetMask != 0) {
2037                        if (DBG) log("resetConnections(" + iface + ", " + resetMask + ")");
2038                        NetworkUtils.resetConnections(iface, resetMask);
2039
2040                        // Tell VPN the interface is down. It is a temporary
2041                        // but effective fix to make VPN aware of the change.
2042                        if ((resetMask & NetworkUtils.RESET_IPV4_ADDRESSES) != 0) {
2043                            mVpn.interfaceStatusChanged(iface, false);
2044                        }
2045                    }
2046                    if (resetDns) {
2047                        if (VDBG) log("resetting DNS cache for " + iface);
2048                        try {
2049                            mNetd.flushInterfaceDnsCache(iface);
2050                        } catch (Exception e) {
2051                            // never crash - catch them all
2052                            if (DBG) loge("Exception resetting dns cache: " + e);
2053                        }
2054                    }
2055                }
2056            }
2057        }
2058
2059        // TODO: Temporary notifying upstread change to Tethering.
2060        //       @see bug/4455071
2061        /** Notify TetheringService if interface name has been changed. */
2062        if (TextUtils.equals(mNetTrackers[netType].getNetworkInfo().getReason(),
2063                             PhoneConstants.REASON_LINK_PROPERTIES_CHANGED)) {
2064            if (isTetheringSupported()) {
2065                mTethering.handleTetherIfaceChange();
2066            }
2067        }
2068    }
2069
2070    /**
2071     * Add and remove routes using the old properties (null if not previously connected),
2072     * new properties (null if becoming disconnected).  May even be double null, which
2073     * is a noop.
2074     * Uses isLinkDefault to determine if default routes should be set or conversely if
2075     * host routes should be set to the dns servers
2076     * returns a boolean indicating the routes changed
2077     */
2078    private boolean updateRoutes(LinkProperties newLp, LinkProperties curLp,
2079            boolean isLinkDefault) {
2080        Collection<RouteInfo> routesToAdd = null;
2081        CompareResult<InetAddress> dnsDiff = new CompareResult<InetAddress>();
2082        CompareResult<RouteInfo> routeDiff = new CompareResult<RouteInfo>();
2083        if (curLp != null) {
2084            // check for the delta between the current set and the new
2085            routeDiff = curLp.compareRoutes(newLp);
2086            dnsDiff = curLp.compareDnses(newLp);
2087        } else if (newLp != null) {
2088            routeDiff.added = newLp.getRoutes();
2089            dnsDiff.added = newLp.getDnses();
2090        }
2091
2092        boolean routesChanged = (routeDiff.removed.size() != 0 || routeDiff.added.size() != 0);
2093
2094        for (RouteInfo r : routeDiff.removed) {
2095            if (isLinkDefault || ! r.isDefaultRoute()) {
2096                removeRoute(curLp, r, TO_DEFAULT_TABLE);
2097            }
2098            if (isLinkDefault == false) {
2099                // remove from a secondary route table
2100                removeRoute(curLp, r, TO_SECONDARY_TABLE);
2101            }
2102        }
2103
2104        for (RouteInfo r :  routeDiff.added) {
2105            if (isLinkDefault || ! r.isDefaultRoute()) {
2106                addRoute(newLp, r, TO_DEFAULT_TABLE);
2107            } else {
2108                // add to a secondary route table
2109                addRoute(newLp, r, TO_SECONDARY_TABLE);
2110
2111                // many radios add a default route even when we don't want one.
2112                // remove the default route unless somebody else has asked for it
2113                String ifaceName = newLp.getInterfaceName();
2114                if (TextUtils.isEmpty(ifaceName) == false && mAddedRoutes.contains(r) == false) {
2115                    if (VDBG) log("Removing " + r + " for interface " + ifaceName);
2116                    try {
2117                        mNetd.removeRoute(ifaceName, r);
2118                    } catch (Exception e) {
2119                        // never crash - catch them all
2120                        if (DBG) loge("Exception trying to remove a route: " + e);
2121                    }
2122                }
2123            }
2124        }
2125
2126        if (!isLinkDefault) {
2127            // handle DNS routes
2128            if (routesChanged) {
2129                // routes changed - remove all old dns entries and add new
2130                if (curLp != null) {
2131                    for (InetAddress oldDns : curLp.getDnses()) {
2132                        removeRouteToAddress(curLp, oldDns);
2133                    }
2134                }
2135                if (newLp != null) {
2136                    for (InetAddress newDns : newLp.getDnses()) {
2137                        addRouteToAddress(newLp, newDns);
2138                    }
2139                }
2140            } else {
2141                // no change in routes, check for change in dns themselves
2142                for (InetAddress oldDns : dnsDiff.removed) {
2143                    removeRouteToAddress(curLp, oldDns);
2144                }
2145                for (InetAddress newDns : dnsDiff.added) {
2146                    addRouteToAddress(newLp, newDns);
2147                }
2148            }
2149        }
2150        return routesChanged;
2151    }
2152
2153
2154   /**
2155     * Reads the network specific TCP buffer sizes from SystemProperties
2156     * net.tcp.buffersize.[default|wifi|umts|edge|gprs] and set them for system
2157     * wide use
2158     */
2159   public void updateNetworkSettings(NetworkStateTracker nt) {
2160        String key = nt.getTcpBufferSizesPropName();
2161        String bufferSizes = SystemProperties.get(key);
2162
2163        if (bufferSizes.length() == 0) {
2164            if (VDBG) log(key + " not found in system properties. Using defaults");
2165
2166            // Setting to default values so we won't be stuck to previous values
2167            key = "net.tcp.buffersize.default";
2168            bufferSizes = SystemProperties.get(key);
2169        }
2170
2171        // Set values in kernel
2172        if (bufferSizes.length() != 0) {
2173            if (VDBG) {
2174                log("Setting TCP values: [" + bufferSizes
2175                        + "] which comes from [" + key + "]");
2176            }
2177            setBufferSize(bufferSizes);
2178        }
2179    }
2180
2181   /**
2182     * Writes TCP buffer sizes to /sys/kernel/ipv4/tcp_[r/w]mem_[min/def/max]
2183     * which maps to /proc/sys/net/ipv4/tcp_rmem and tcpwmem
2184     *
2185     * @param bufferSizes in the format of "readMin, readInitial, readMax,
2186     *        writeMin, writeInitial, writeMax"
2187     */
2188    private void setBufferSize(String bufferSizes) {
2189        try {
2190            String[] values = bufferSizes.split(",");
2191
2192            if (values.length == 6) {
2193              final String prefix = "/sys/kernel/ipv4/tcp_";
2194                FileUtils.stringToFile(prefix + "rmem_min", values[0]);
2195                FileUtils.stringToFile(prefix + "rmem_def", values[1]);
2196                FileUtils.stringToFile(prefix + "rmem_max", values[2]);
2197                FileUtils.stringToFile(prefix + "wmem_min", values[3]);
2198                FileUtils.stringToFile(prefix + "wmem_def", values[4]);
2199                FileUtils.stringToFile(prefix + "wmem_max", values[5]);
2200            } else {
2201                loge("Invalid buffersize string: " + bufferSizes);
2202            }
2203        } catch (IOException e) {
2204            loge("Can't set tcp buffer sizes:" + e);
2205        }
2206    }
2207
2208    /**
2209     * Adjust the per-process dns entries (net.dns<x>.<pid>) based
2210     * on the highest priority active net which this process requested.
2211     * If there aren't any, clear it out
2212     */
2213    private void reassessPidDns(int myPid, boolean doBump)
2214    {
2215        if (VDBG) log("reassessPidDns for pid " + myPid);
2216        for(int i : mPriorityList) {
2217            if (mNetConfigs[i].isDefault()) {
2218                continue;
2219            }
2220            NetworkStateTracker nt = mNetTrackers[i];
2221            if (nt.getNetworkInfo().isConnected() &&
2222                    !nt.isTeardownRequested()) {
2223                LinkProperties p = nt.getLinkProperties();
2224                if (p == null) continue;
2225                List pids = mNetRequestersPids[i];
2226                for (int j=0; j<pids.size(); j++) {
2227                    Integer pid = (Integer)pids.get(j);
2228                    if (pid.intValue() == myPid) {
2229                        Collection<InetAddress> dnses = p.getDnses();
2230                        writePidDns(dnses, myPid);
2231                        if (doBump) {
2232                            bumpDns();
2233                        }
2234                        return;
2235                    }
2236                }
2237           }
2238        }
2239        // nothing found - delete
2240        for (int i = 1; ; i++) {
2241            String prop = "net.dns" + i + "." + myPid;
2242            if (SystemProperties.get(prop).length() == 0) {
2243                if (doBump) {
2244                    bumpDns();
2245                }
2246                return;
2247            }
2248            SystemProperties.set(prop, "");
2249        }
2250    }
2251
2252    // return true if results in a change
2253    private boolean writePidDns(Collection <InetAddress> dnses, int pid) {
2254        int j = 1;
2255        boolean changed = false;
2256        for (InetAddress dns : dnses) {
2257            String dnsString = dns.getHostAddress();
2258            if (changed || !dnsString.equals(SystemProperties.get("net.dns" + j + "." + pid))) {
2259                changed = true;
2260                SystemProperties.set("net.dns" + j + "." + pid, dns.getHostAddress());
2261            }
2262            j++;
2263        }
2264        return changed;
2265    }
2266
2267    private void bumpDns() {
2268        /*
2269         * Bump the property that tells the name resolver library to reread
2270         * the DNS server list from the properties.
2271         */
2272        String propVal = SystemProperties.get("net.dnschange");
2273        int n = 0;
2274        if (propVal.length() != 0) {
2275            try {
2276                n = Integer.parseInt(propVal);
2277            } catch (NumberFormatException e) {}
2278        }
2279        SystemProperties.set("net.dnschange", "" + (n+1));
2280        /*
2281         * Tell the VMs to toss their DNS caches
2282         */
2283        Intent intent = new Intent(Intent.ACTION_CLEAR_DNS_CACHE);
2284        intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
2285        /*
2286         * Connectivity events can happen before boot has completed ...
2287         */
2288        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
2289        mContext.sendBroadcast(intent);
2290    }
2291
2292    // Caller must grab mDnsLock.
2293    private boolean updateDns(String network, String iface,
2294            Collection<InetAddress> dnses, String domains) {
2295        boolean changed = false;
2296        int last = 0;
2297        if (dnses.size() == 0 && mDefaultDns != null) {
2298            ++last;
2299            String value = mDefaultDns.getHostAddress();
2300            if (!value.equals(SystemProperties.get("net.dns1"))) {
2301                if (DBG) {
2302                    loge("no dns provided for " + network + " - using " + value);
2303                }
2304                changed = true;
2305                SystemProperties.set("net.dns1", value);
2306            }
2307        } else {
2308            for (InetAddress dns : dnses) {
2309                ++last;
2310                String key = "net.dns" + last;
2311                String value = dns.getHostAddress();
2312                if (!changed && value.equals(SystemProperties.get(key))) {
2313                    continue;
2314                }
2315                if (VDBG) {
2316                    log("adding dns " + value + " for " + network);
2317                }
2318                changed = true;
2319                SystemProperties.set(key, value);
2320            }
2321        }
2322        for (int i = last + 1; i <= mNumDnsEntries; ++i) {
2323            String key = "net.dns" + i;
2324            if (VDBG) log("erasing " + key);
2325            changed = true;
2326            SystemProperties.set(key, "");
2327        }
2328        mNumDnsEntries = last;
2329
2330        if (changed) {
2331            try {
2332                mNetd.setDnsServersForInterface(iface, NetworkUtils.makeStrings(dnses));
2333                mNetd.setDefaultInterfaceForDns(iface);
2334            } catch (Exception e) {
2335                if (DBG) loge("exception setting default dns interface: " + e);
2336            }
2337        }
2338        if (!domains.equals(SystemProperties.get("net.dns.search"))) {
2339            SystemProperties.set("net.dns.search", domains);
2340            changed = true;
2341        }
2342        return changed;
2343    }
2344
2345    private void handleDnsConfigurationChange(int netType) {
2346        // add default net's dns entries
2347        NetworkStateTracker nt = mNetTrackers[netType];
2348        if (nt != null && nt.getNetworkInfo().isConnected() && !nt.isTeardownRequested()) {
2349            LinkProperties p = nt.getLinkProperties();
2350            if (p == null) return;
2351            Collection<InetAddress> dnses = p.getDnses();
2352            boolean changed = false;
2353            if (mNetConfigs[netType].isDefault()) {
2354                String network = nt.getNetworkInfo().getTypeName();
2355                synchronized (mDnsLock) {
2356                    if (!mDnsOverridden) {
2357                        changed = updateDns(network, p.getInterfaceName(), dnses, "");
2358                    }
2359                }
2360            } else {
2361                try {
2362                    mNetd.setDnsServersForInterface(p.getInterfaceName(),
2363                            NetworkUtils.makeStrings(dnses));
2364                } catch (Exception e) {
2365                    if (DBG) loge("exception setting dns servers: " + e);
2366                }
2367                // set per-pid dns for attached secondary nets
2368                List pids = mNetRequestersPids[netType];
2369                for (int y=0; y< pids.size(); y++) {
2370                    Integer pid = (Integer)pids.get(y);
2371                    changed = writePidDns(dnses, pid.intValue());
2372                }
2373            }
2374            if (changed) bumpDns();
2375        }
2376    }
2377
2378    private int getRestoreDefaultNetworkDelay(int networkType) {
2379        String restoreDefaultNetworkDelayStr = SystemProperties.get(
2380                NETWORK_RESTORE_DELAY_PROP_NAME);
2381        if(restoreDefaultNetworkDelayStr != null &&
2382                restoreDefaultNetworkDelayStr.length() != 0) {
2383            try {
2384                return Integer.valueOf(restoreDefaultNetworkDelayStr);
2385            } catch (NumberFormatException e) {
2386            }
2387        }
2388        // if the system property isn't set, use the value for the apn type
2389        int ret = RESTORE_DEFAULT_NETWORK_DELAY;
2390
2391        if ((networkType <= ConnectivityManager.MAX_NETWORK_TYPE) &&
2392                (mNetConfigs[networkType] != null)) {
2393            ret = mNetConfigs[networkType].restoreTime;
2394        }
2395        return ret;
2396    }
2397
2398    @Override
2399    protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
2400        if (mContext.checkCallingOrSelfPermission(
2401                android.Manifest.permission.DUMP)
2402                != PackageManager.PERMISSION_GRANTED) {
2403            pw.println("Permission Denial: can't dump ConnectivityService " +
2404                    "from from pid=" + Binder.getCallingPid() + ", uid=" +
2405                    Binder.getCallingUid());
2406            return;
2407        }
2408        pw.println();
2409        for (NetworkStateTracker nst : mNetTrackers) {
2410            if (nst != null) {
2411                if (nst.getNetworkInfo().isConnected()) {
2412                    pw.println("Active network: " + nst.getNetworkInfo().
2413                            getTypeName());
2414                }
2415                pw.println(nst.getNetworkInfo());
2416                pw.println(nst);
2417                pw.println();
2418            }
2419        }
2420
2421        pw.println("Network Requester Pids:");
2422        for (int net : mPriorityList) {
2423            String pidString = net + ": ";
2424            for (Object pid : mNetRequestersPids[net]) {
2425                pidString = pidString + pid.toString() + ", ";
2426            }
2427            pw.println(pidString);
2428        }
2429        pw.println();
2430
2431        pw.println("FeatureUsers:");
2432        for (Object requester : mFeatureUsers) {
2433            pw.println(requester.toString());
2434        }
2435        pw.println();
2436
2437        synchronized (this) {
2438            pw.println("NetworkTranstionWakeLock is currently " +
2439                    (mNetTransitionWakeLock.isHeld() ? "" : "not ") + "held.");
2440            pw.println("It was last requested for "+mNetTransitionWakeLockCausedBy);
2441        }
2442        pw.println();
2443
2444        mTethering.dump(fd, pw, args);
2445
2446        if (mInetLog != null) {
2447            pw.println();
2448            pw.println("Inet condition reports:");
2449            for(int i = 0; i < mInetLog.size(); i++) {
2450                pw.println(mInetLog.get(i));
2451            }
2452        }
2453    }
2454
2455    // must be stateless - things change under us.
2456    private class NetworkStateTrackerHandler extends Handler {
2457        public NetworkStateTrackerHandler(Looper looper) {
2458            super(looper);
2459        }
2460
2461        @Override
2462        public void handleMessage(Message msg) {
2463            NetworkInfo info;
2464            switch (msg.what) {
2465                case NetworkStateTracker.EVENT_STATE_CHANGED:
2466                    info = (NetworkInfo) msg.obj;
2467                    int type = info.getType();
2468                    NetworkInfo.State state = info.getState();
2469
2470                    if (VDBG || (state == NetworkInfo.State.CONNECTED) ||
2471                            (state == NetworkInfo.State.DISCONNECTED)) {
2472                        log("ConnectivityChange for " +
2473                            info.getTypeName() + ": " +
2474                            state + "/" + info.getDetailedState());
2475                    }
2476
2477                    // Connectivity state changed:
2478                    // [31-14] Reserved for future use
2479                    // [13-10] Network subtype (for mobile network, as defined
2480                    //         by TelephonyManager)
2481                    // [9-4] Detailed state ordinal (as defined by
2482                    //         NetworkInfo.DetailedState)
2483                    // [3-0] Network type (as defined by ConnectivityManager)
2484                    int eventLogParam = (info.getType() & 0xf) |
2485                            ((info.getDetailedState().ordinal() & 0x3f) << 4) |
2486                            (info.getSubtype() << 10);
2487                    EventLog.writeEvent(EventLogTags.CONNECTIVITY_STATE_CHANGED,
2488                            eventLogParam);
2489
2490                    if (info.getDetailedState() ==
2491                            NetworkInfo.DetailedState.FAILED) {
2492                        handleConnectionFailure(info);
2493                    } else if (state == NetworkInfo.State.DISCONNECTED) {
2494                        handleDisconnect(info);
2495                    } else if (state == NetworkInfo.State.SUSPENDED) {
2496                        // TODO: need to think this over.
2497                        // the logic here is, handle SUSPENDED the same as
2498                        // DISCONNECTED. The only difference being we are
2499                        // broadcasting an intent with NetworkInfo that's
2500                        // suspended. This allows the applications an
2501                        // opportunity to handle DISCONNECTED and SUSPENDED
2502                        // differently, or not.
2503                        handleDisconnect(info);
2504                    } else if (state == NetworkInfo.State.CONNECTED) {
2505                        handleConnect(info);
2506                    }
2507                    break;
2508                case NetworkStateTracker.EVENT_CONFIGURATION_CHANGED:
2509                    info = (NetworkInfo) msg.obj;
2510                    // TODO: Temporary allowing network configuration
2511                    //       change not resetting sockets.
2512                    //       @see bug/4455071
2513                    handleConnectivityChange(info.getType(), false);
2514                    break;
2515            }
2516        }
2517    }
2518
2519    private class InternalHandler extends Handler {
2520        public InternalHandler(Looper looper) {
2521            super(looper);
2522        }
2523
2524        @Override
2525        public void handleMessage(Message msg) {
2526            NetworkInfo info;
2527            switch (msg.what) {
2528                case EVENT_CLEAR_NET_TRANSITION_WAKELOCK:
2529                    String causedBy = null;
2530                    synchronized (ConnectivityService.this) {
2531                        if (msg.arg1 == mNetTransitionWakeLockSerialNumber &&
2532                                mNetTransitionWakeLock.isHeld()) {
2533                            mNetTransitionWakeLock.release();
2534                            causedBy = mNetTransitionWakeLockCausedBy;
2535                        }
2536                    }
2537                    if (causedBy != null) {
2538                        log("NetTransition Wakelock for " + causedBy + " released by timeout");
2539                    }
2540                    break;
2541                case EVENT_RESTORE_DEFAULT_NETWORK:
2542                    FeatureUser u = (FeatureUser)msg.obj;
2543                    u.expire();
2544                    break;
2545                case EVENT_INET_CONDITION_CHANGE:
2546                {
2547                    int netType = msg.arg1;
2548                    int condition = msg.arg2;
2549                    handleInetConditionChange(netType, condition);
2550                    break;
2551                }
2552                case EVENT_INET_CONDITION_HOLD_END:
2553                {
2554                    int netType = msg.arg1;
2555                    int sequence = msg.arg2;
2556                    handleInetConditionHoldEnd(netType, sequence);
2557                    break;
2558                }
2559                case EVENT_SET_NETWORK_PREFERENCE:
2560                {
2561                    int preference = msg.arg1;
2562                    handleSetNetworkPreference(preference);
2563                    break;
2564                }
2565                case EVENT_SET_MOBILE_DATA:
2566                {
2567                    boolean enabled = (msg.arg1 == ENABLED);
2568                    handleSetMobileData(enabled);
2569                    break;
2570                }
2571                case EVENT_APPLY_GLOBAL_HTTP_PROXY:
2572                {
2573                    handleDeprecatedGlobalHttpProxy();
2574                    break;
2575                }
2576                case EVENT_SET_DEPENDENCY_MET:
2577                {
2578                    boolean met = (msg.arg1 == ENABLED);
2579                    handleSetDependencyMet(msg.arg2, met);
2580                    break;
2581                }
2582                case EVENT_RESTORE_DNS:
2583                {
2584                    if (mActiveDefaultNetwork != -1) {
2585                        handleDnsConfigurationChange(mActiveDefaultNetwork);
2586                    }
2587                    break;
2588                }
2589                case EVENT_SEND_STICKY_BROADCAST_INTENT:
2590                {
2591                    Intent intent = (Intent)msg.obj;
2592                    sendStickyBroadcast(intent);
2593                    break;
2594                }
2595                case EVENT_SET_POLICY_DATA_ENABLE: {
2596                    final int networkType = msg.arg1;
2597                    final boolean enabled = msg.arg2 == ENABLED;
2598                    handleSetPolicyDataEnable(networkType, enabled);
2599                }
2600            }
2601        }
2602    }
2603
2604    // javadoc from interface
2605    public int tether(String iface) {
2606        enforceTetherChangePermission();
2607
2608        if (isTetheringSupported()) {
2609            return mTethering.tether(iface);
2610        } else {
2611            return ConnectivityManager.TETHER_ERROR_UNSUPPORTED;
2612        }
2613    }
2614
2615    // javadoc from interface
2616    public int untether(String iface) {
2617        enforceTetherChangePermission();
2618
2619        if (isTetheringSupported()) {
2620            return mTethering.untether(iface);
2621        } else {
2622            return ConnectivityManager.TETHER_ERROR_UNSUPPORTED;
2623        }
2624    }
2625
2626    // javadoc from interface
2627    public int getLastTetherError(String iface) {
2628        enforceTetherAccessPermission();
2629
2630        if (isTetheringSupported()) {
2631            return mTethering.getLastTetherError(iface);
2632        } else {
2633            return ConnectivityManager.TETHER_ERROR_UNSUPPORTED;
2634        }
2635    }
2636
2637    // TODO - proper iface API for selection by property, inspection, etc
2638    public String[] getTetherableUsbRegexs() {
2639        enforceTetherAccessPermission();
2640        if (isTetheringSupported()) {
2641            return mTethering.getTetherableUsbRegexs();
2642        } else {
2643            return new String[0];
2644        }
2645    }
2646
2647    public String[] getTetherableWifiRegexs() {
2648        enforceTetherAccessPermission();
2649        if (isTetheringSupported()) {
2650            return mTethering.getTetherableWifiRegexs();
2651        } else {
2652            return new String[0];
2653        }
2654    }
2655
2656    public String[] getTetherableBluetoothRegexs() {
2657        enforceTetherAccessPermission();
2658        if (isTetheringSupported()) {
2659            return mTethering.getTetherableBluetoothRegexs();
2660        } else {
2661            return new String[0];
2662        }
2663    }
2664
2665    public int setUsbTethering(boolean enable) {
2666        enforceTetherAccessPermission();
2667        if (isTetheringSupported()) {
2668            return mTethering.setUsbTethering(enable);
2669        } else {
2670            return ConnectivityManager.TETHER_ERROR_UNSUPPORTED;
2671        }
2672    }
2673
2674    // TODO - move iface listing, queries, etc to new module
2675    // javadoc from interface
2676    public String[] getTetherableIfaces() {
2677        enforceTetherAccessPermission();
2678        return mTethering.getTetherableIfaces();
2679    }
2680
2681    public String[] getTetheredIfaces() {
2682        enforceTetherAccessPermission();
2683        return mTethering.getTetheredIfaces();
2684    }
2685
2686    @Override
2687    public String[] getTetheredIfacePairs() {
2688        enforceTetherAccessPermission();
2689        return mTethering.getTetheredIfacePairs();
2690    }
2691
2692    public String[] getTetheringErroredIfaces() {
2693        enforceTetherAccessPermission();
2694        return mTethering.getErroredIfaces();
2695    }
2696
2697    // if ro.tether.denied = true we default to no tethering
2698    // gservices could set the secure setting to 1 though to enable it on a build where it
2699    // had previously been turned off.
2700    public boolean isTetheringSupported() {
2701        enforceTetherAccessPermission();
2702        int defaultVal = (SystemProperties.get("ro.tether.denied").equals("true") ? 0 : 1);
2703        boolean tetherEnabledInSettings = (Settings.Secure.getInt(mContext.getContentResolver(),
2704                Settings.Secure.TETHER_SUPPORTED, defaultVal) != 0);
2705        return tetherEnabledInSettings && mTetheringConfigValid;
2706    }
2707
2708    // An API NetworkStateTrackers can call when they lose their network.
2709    // This will automatically be cleared after X seconds or a network becomes CONNECTED,
2710    // whichever happens first.  The timer is started by the first caller and not
2711    // restarted by subsequent callers.
2712    public void requestNetworkTransitionWakelock(String forWhom) {
2713        enforceConnectivityInternalPermission();
2714        synchronized (this) {
2715            if (mNetTransitionWakeLock.isHeld()) return;
2716            mNetTransitionWakeLockSerialNumber++;
2717            mNetTransitionWakeLock.acquire();
2718            mNetTransitionWakeLockCausedBy = forWhom;
2719        }
2720        mHandler.sendMessageDelayed(mHandler.obtainMessage(
2721                EVENT_CLEAR_NET_TRANSITION_WAKELOCK,
2722                mNetTransitionWakeLockSerialNumber, 0),
2723                mNetTransitionWakeLockTimeout);
2724        return;
2725    }
2726
2727    // 100 percent is full good, 0 is full bad.
2728    public void reportInetCondition(int networkType, int percentage) {
2729        if (VDBG) log("reportNetworkCondition(" + networkType + ", " + percentage + ")");
2730        mContext.enforceCallingOrSelfPermission(
2731                android.Manifest.permission.STATUS_BAR,
2732                "ConnectivityService");
2733
2734        if (DBG) {
2735            int pid = getCallingPid();
2736            int uid = getCallingUid();
2737            String s = pid + "(" + uid + ") reports inet is " +
2738                (percentage > 50 ? "connected" : "disconnected") + " (" + percentage + ") on " +
2739                "network Type " + networkType + " at " + GregorianCalendar.getInstance().getTime();
2740            mInetLog.add(s);
2741            while(mInetLog.size() > INET_CONDITION_LOG_MAX_SIZE) {
2742                mInetLog.remove(0);
2743            }
2744        }
2745        mHandler.sendMessage(mHandler.obtainMessage(
2746            EVENT_INET_CONDITION_CHANGE, networkType, percentage));
2747    }
2748
2749    private void handleInetConditionChange(int netType, int condition) {
2750        if (mActiveDefaultNetwork == -1) {
2751            if (DBG) log("handleInetConditionChange: no active default network - ignore");
2752            return;
2753        }
2754        if (mActiveDefaultNetwork != netType) {
2755            if (DBG) log("handleInetConditionChange: net=" + netType +
2756                            " != default=" + mActiveDefaultNetwork + " - ignore");
2757            return;
2758        }
2759        if (VDBG) {
2760            log("handleInetConditionChange: net=" +
2761                    netType + ", condition=" + condition +
2762                    ",mActiveDefaultNetwork=" + mActiveDefaultNetwork);
2763        }
2764        mDefaultInetCondition = condition;
2765        int delay;
2766        if (mInetConditionChangeInFlight == false) {
2767            if (VDBG) log("handleInetConditionChange: starting a change hold");
2768            // setup a new hold to debounce this
2769            if (mDefaultInetCondition > 50) {
2770                delay = Settings.Secure.getInt(mContext.getContentResolver(),
2771                        Settings.Secure.INET_CONDITION_DEBOUNCE_UP_DELAY, 500);
2772            } else {
2773                delay = Settings.Secure.getInt(mContext.getContentResolver(),
2774                Settings.Secure.INET_CONDITION_DEBOUNCE_DOWN_DELAY, 3000);
2775            }
2776            mInetConditionChangeInFlight = true;
2777            mHandler.sendMessageDelayed(mHandler.obtainMessage(EVENT_INET_CONDITION_HOLD_END,
2778                    mActiveDefaultNetwork, mDefaultConnectionSequence), delay);
2779        } else {
2780            // we've set the new condition, when this hold ends that will get picked up
2781            if (VDBG) log("handleInetConditionChange: currently in hold - not setting new end evt");
2782        }
2783    }
2784
2785    private void handleInetConditionHoldEnd(int netType, int sequence) {
2786        if (DBG) {
2787            log("handleInetConditionHoldEnd: net=" + netType +
2788                    ", condition=" + mDefaultInetCondition +
2789                    ", published condition=" + mDefaultInetConditionPublished);
2790        }
2791        mInetConditionChangeInFlight = false;
2792
2793        if (mActiveDefaultNetwork == -1) {
2794            if (DBG) log("handleInetConditionHoldEnd: no active default network - ignoring");
2795            return;
2796        }
2797        if (mDefaultConnectionSequence != sequence) {
2798            if (DBG) log("handleInetConditionHoldEnd: event hold for obsolete network - ignoring");
2799            return;
2800        }
2801        // TODO: Figure out why this optimization sometimes causes a
2802        //       change in mDefaultInetCondition to be missed and the
2803        //       UI to not be updated.
2804        //if (mDefaultInetConditionPublished == mDefaultInetCondition) {
2805        //    if (DBG) log("no change in condition - aborting");
2806        //    return;
2807        //}
2808        NetworkInfo networkInfo = mNetTrackers[mActiveDefaultNetwork].getNetworkInfo();
2809        if (networkInfo.isConnected() == false) {
2810            if (DBG) log("handleInetConditionHoldEnd: default network not connected - ignoring");
2811            return;
2812        }
2813        mDefaultInetConditionPublished = mDefaultInetCondition;
2814        sendInetConditionBroadcast(networkInfo);
2815        return;
2816    }
2817
2818    public ProxyProperties getProxy() {
2819        synchronized (mDefaultProxyLock) {
2820            return mDefaultProxyDisabled ? null : mDefaultProxy;
2821        }
2822    }
2823
2824    public void setGlobalProxy(ProxyProperties proxyProperties) {
2825        enforceChangePermission();
2826        synchronized (mGlobalProxyLock) {
2827            if (proxyProperties == mGlobalProxy) return;
2828            if (proxyProperties != null && proxyProperties.equals(mGlobalProxy)) return;
2829            if (mGlobalProxy != null && mGlobalProxy.equals(proxyProperties)) return;
2830
2831            String host = "";
2832            int port = 0;
2833            String exclList = "";
2834            if (proxyProperties != null && !TextUtils.isEmpty(proxyProperties.getHost())) {
2835                mGlobalProxy = new ProxyProperties(proxyProperties);
2836                host = mGlobalProxy.getHost();
2837                port = mGlobalProxy.getPort();
2838                exclList = mGlobalProxy.getExclusionList();
2839            } else {
2840                mGlobalProxy = null;
2841            }
2842            ContentResolver res = mContext.getContentResolver();
2843            Settings.Secure.putString(res, Settings.Secure.GLOBAL_HTTP_PROXY_HOST, host);
2844            Settings.Secure.putInt(res, Settings.Secure.GLOBAL_HTTP_PROXY_PORT, port);
2845            Settings.Secure.putString(res, Settings.Secure.GLOBAL_HTTP_PROXY_EXCLUSION_LIST,
2846                    exclList);
2847        }
2848
2849        if (mGlobalProxy == null) {
2850            proxyProperties = mDefaultProxy;
2851        }
2852        //sendProxyBroadcast(proxyProperties);
2853    }
2854
2855    private void loadGlobalProxy() {
2856        ContentResolver res = mContext.getContentResolver();
2857        String host = Settings.Secure.getString(res, Settings.Secure.GLOBAL_HTTP_PROXY_HOST);
2858        int port = Settings.Secure.getInt(res, Settings.Secure.GLOBAL_HTTP_PROXY_PORT, 0);
2859        String exclList = Settings.Secure.getString(res,
2860                Settings.Secure.GLOBAL_HTTP_PROXY_EXCLUSION_LIST);
2861        if (!TextUtils.isEmpty(host)) {
2862            ProxyProperties proxyProperties = new ProxyProperties(host, port, exclList);
2863            synchronized (mGlobalProxyLock) {
2864                mGlobalProxy = proxyProperties;
2865            }
2866        }
2867    }
2868
2869    public ProxyProperties getGlobalProxy() {
2870        synchronized (mGlobalProxyLock) {
2871            return mGlobalProxy;
2872        }
2873    }
2874
2875    private void handleApplyDefaultProxy(ProxyProperties proxy) {
2876        if (proxy != null && TextUtils.isEmpty(proxy.getHost())) {
2877            proxy = null;
2878        }
2879        synchronized (mDefaultProxyLock) {
2880            if (mDefaultProxy != null && mDefaultProxy.equals(proxy)) return;
2881            if (mDefaultProxy == proxy) return;
2882            mDefaultProxy = proxy;
2883
2884            if (!mDefaultProxyDisabled) {
2885                sendProxyBroadcast(proxy);
2886            }
2887        }
2888    }
2889
2890    private void handleDeprecatedGlobalHttpProxy() {
2891        String proxy = Settings.Secure.getString(mContext.getContentResolver(),
2892                Settings.Secure.HTTP_PROXY);
2893        if (!TextUtils.isEmpty(proxy)) {
2894            String data[] = proxy.split(":");
2895            String proxyHost =  data[0];
2896            int proxyPort = 8080;
2897            if (data.length > 1) {
2898                try {
2899                    proxyPort = Integer.parseInt(data[1]);
2900                } catch (NumberFormatException e) {
2901                    return;
2902                }
2903            }
2904            ProxyProperties p = new ProxyProperties(data[0], proxyPort, "");
2905            setGlobalProxy(p);
2906        }
2907    }
2908
2909    private void sendProxyBroadcast(ProxyProperties proxy) {
2910        if (proxy == null) proxy = new ProxyProperties("", 0, "");
2911        if (DBG) log("sending Proxy Broadcast for " + proxy);
2912        Intent intent = new Intent(Proxy.PROXY_CHANGE_ACTION);
2913        intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING |
2914            Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
2915        intent.putExtra(Proxy.EXTRA_PROXY_INFO, proxy);
2916        mContext.sendStickyBroadcast(intent);
2917    }
2918
2919    private static class SettingsObserver extends ContentObserver {
2920        private int mWhat;
2921        private Handler mHandler;
2922        SettingsObserver(Handler handler, int what) {
2923            super(handler);
2924            mHandler = handler;
2925            mWhat = what;
2926        }
2927
2928        void observe(Context context) {
2929            ContentResolver resolver = context.getContentResolver();
2930            resolver.registerContentObserver(Settings.Secure.getUriFor(
2931                    Settings.Secure.HTTP_PROXY), false, this);
2932        }
2933
2934        @Override
2935        public void onChange(boolean selfChange) {
2936            mHandler.obtainMessage(mWhat).sendToTarget();
2937        }
2938    }
2939
2940    private void log(String s) {
2941        Slog.d(TAG, s);
2942    }
2943
2944    private void loge(String s) {
2945        Slog.e(TAG, s);
2946    }
2947
2948    int convertFeatureToNetworkType(int networkType, String feature) {
2949        int usedNetworkType = networkType;
2950
2951        if(networkType == ConnectivityManager.TYPE_MOBILE) {
2952            if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_MMS)) {
2953                usedNetworkType = ConnectivityManager.TYPE_MOBILE_MMS;
2954            } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_SUPL)) {
2955                usedNetworkType = ConnectivityManager.TYPE_MOBILE_SUPL;
2956            } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_DUN) ||
2957                    TextUtils.equals(feature, Phone.FEATURE_ENABLE_DUN_ALWAYS)) {
2958                usedNetworkType = ConnectivityManager.TYPE_MOBILE_DUN;
2959            } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_HIPRI)) {
2960                usedNetworkType = ConnectivityManager.TYPE_MOBILE_HIPRI;
2961            } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_FOTA)) {
2962                usedNetworkType = ConnectivityManager.TYPE_MOBILE_FOTA;
2963            } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_IMS)) {
2964                usedNetworkType = ConnectivityManager.TYPE_MOBILE_IMS;
2965            } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_CBS)) {
2966                usedNetworkType = ConnectivityManager.TYPE_MOBILE_CBS;
2967            } else {
2968                Slog.e(TAG, "Can't match any mobile netTracker!");
2969            }
2970        } else if (networkType == ConnectivityManager.TYPE_WIFI) {
2971            if (TextUtils.equals(feature, "p2p")) {
2972                usedNetworkType = ConnectivityManager.TYPE_WIFI_P2P;
2973            } else {
2974                Slog.e(TAG, "Can't match any wifi netTracker!");
2975            }
2976        } else {
2977            Slog.e(TAG, "Unexpected network type");
2978        }
2979        return usedNetworkType;
2980    }
2981
2982    private static <T> T checkNotNull(T value, String message) {
2983        if (value == null) {
2984            throw new NullPointerException(message);
2985        }
2986        return value;
2987    }
2988
2989    /**
2990     * Protect a socket from VPN routing rules. This method is used by
2991     * VpnBuilder and not available in ConnectivityManager. Permissions
2992     * are checked in Vpn class.
2993     * @hide
2994     */
2995    @Override
2996    public boolean protectVpn(ParcelFileDescriptor socket) {
2997        try {
2998            int type = mActiveDefaultNetwork;
2999            if (ConnectivityManager.isNetworkTypeValid(type)) {
3000                mVpn.protect(socket, mNetTrackers[type].getLinkProperties().getInterfaceName());
3001                return true;
3002            }
3003        } catch (Exception e) {
3004            // ignore
3005        } finally {
3006            try {
3007                socket.close();
3008            } catch (Exception e) {
3009                // ignore
3010            }
3011        }
3012        return false;
3013    }
3014
3015    /**
3016     * Prepare for a VPN application. This method is used by VpnDialogs
3017     * and not available in ConnectivityManager. Permissions are checked
3018     * in Vpn class.
3019     * @hide
3020     */
3021    @Override
3022    public boolean prepareVpn(String oldPackage, String newPackage) {
3023        return mVpn.prepare(oldPackage, newPackage);
3024    }
3025
3026    /**
3027     * Configure a TUN interface and return its file descriptor. Parameters
3028     * are encoded and opaque to this class. This method is used by VpnBuilder
3029     * and not available in ConnectivityManager. Permissions are checked in
3030     * Vpn class.
3031     * @hide
3032     */
3033    @Override
3034    public ParcelFileDescriptor establishVpn(VpnConfig config) {
3035        return mVpn.establish(config);
3036    }
3037
3038    /**
3039     * Start legacy VPN and return an intent to VpnDialogs. This method is
3040     * used by VpnSettings and not available in ConnectivityManager.
3041     * Permissions are checked in Vpn class.
3042     * @hide
3043     */
3044    @Override
3045    public void startLegacyVpn(VpnConfig config, String[] racoon, String[] mtpd) {
3046        mVpn.startLegacyVpn(config, racoon, mtpd);
3047    }
3048
3049    /**
3050     * Return the information of the ongoing legacy VPN. This method is used
3051     * by VpnSettings and not available in ConnectivityManager. Permissions
3052     * are checked in Vpn class.
3053     * @hide
3054     */
3055    @Override
3056    public LegacyVpnInfo getLegacyVpnInfo() {
3057        return mVpn.getLegacyVpnInfo();
3058    }
3059
3060    /**
3061     * Callback for VPN subsystem. Currently VPN is not adapted to the service
3062     * through NetworkStateTracker since it works differently. For example, it
3063     * needs to override DNS servers but never takes the default routes. It
3064     * relies on another data network, and it could keep existing connections
3065     * alive after reconnecting, switching between networks, or even resuming
3066     * from deep sleep. Calls from applications should be done synchronously
3067     * to avoid race conditions. As these are all hidden APIs, refactoring can
3068     * be done whenever a better abstraction is developed.
3069     */
3070    public class VpnCallback {
3071
3072        private VpnCallback() {
3073        }
3074
3075        public void override(List<String> dnsServers, List<String> searchDomains) {
3076            if (dnsServers == null) {
3077                restore();
3078                return;
3079            }
3080
3081            // Convert DNS servers into addresses.
3082            List<InetAddress> addresses = new ArrayList<InetAddress>();
3083            for (String address : dnsServers) {
3084                // Double check the addresses and remove invalid ones.
3085                try {
3086                    addresses.add(InetAddress.parseNumericAddress(address));
3087                } catch (Exception e) {
3088                    // ignore
3089                }
3090            }
3091            if (addresses.isEmpty()) {
3092                restore();
3093                return;
3094            }
3095
3096            // Concatenate search domains into a string.
3097            StringBuilder buffer = new StringBuilder();
3098            if (searchDomains != null) {
3099                for (String domain : searchDomains) {
3100                    buffer.append(domain).append(' ');
3101                }
3102            }
3103            String domains = buffer.toString().trim();
3104
3105            // Apply DNS changes.
3106            boolean changed = false;
3107            synchronized (mDnsLock) {
3108                changed = updateDns("VPN", "VPN", addresses, domains);
3109                mDnsOverridden = true;
3110            }
3111            if (changed) {
3112                bumpDns();
3113            }
3114
3115            // Temporarily disable the default proxy.
3116            synchronized (mDefaultProxyLock) {
3117                mDefaultProxyDisabled = true;
3118                if (mDefaultProxy != null) {
3119                    sendProxyBroadcast(null);
3120                }
3121            }
3122
3123            // TODO: support proxy per network.
3124        }
3125
3126        public void restore() {
3127            synchronized (mDnsLock) {
3128                if (mDnsOverridden) {
3129                    mDnsOverridden = false;
3130                    mHandler.sendEmptyMessage(EVENT_RESTORE_DNS);
3131                }
3132            }
3133            synchronized (mDefaultProxyLock) {
3134                mDefaultProxyDisabled = false;
3135                if (mDefaultProxy != null) {
3136                    sendProxyBroadcast(mDefaultProxy);
3137                }
3138            }
3139        }
3140    }
3141}
3142