ConnectivityService.java revision 4c628eba480d271d5547af5d4fafc01e0e53a5eb
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        if (info.isFailover()) {
1626            intent.putExtra(ConnectivityManager.EXTRA_IS_FAILOVER, true);
1627            info.setFailover(false);
1628        }
1629        if (info.getReason() != null) {
1630            intent.putExtra(ConnectivityManager.EXTRA_REASON, info.getReason());
1631        }
1632        if (info.getExtraInfo() != null) {
1633            intent.putExtra(ConnectivityManager.EXTRA_EXTRA_INFO,
1634                    info.getExtraInfo());
1635        }
1636
1637        if (mNetConfigs[prevNetType].isDefault()) {
1638            tryFailover(prevNetType);
1639            if (mActiveDefaultNetwork != -1) {
1640                NetworkInfo switchTo = mNetTrackers[mActiveDefaultNetwork].getNetworkInfo();
1641                intent.putExtra(ConnectivityManager.EXTRA_OTHER_NETWORK_INFO, switchTo);
1642            } else {
1643                mDefaultInetConditionPublished = 0; // we're not connected anymore
1644                intent.putExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, true);
1645            }
1646        }
1647        intent.putExtra(ConnectivityManager.EXTRA_INET_CONDITION, mDefaultInetConditionPublished);
1648
1649        // Reset interface if no other connections are using the same interface
1650        boolean doReset = true;
1651        LinkProperties linkProperties = mNetTrackers[prevNetType].getLinkProperties();
1652        if (linkProperties != null) {
1653            String oldIface = linkProperties.getInterfaceName();
1654            if (TextUtils.isEmpty(oldIface) == false) {
1655                for (NetworkStateTracker networkStateTracker : mNetTrackers) {
1656                    if (networkStateTracker == null) continue;
1657                    NetworkInfo networkInfo = networkStateTracker.getNetworkInfo();
1658                    if (networkInfo.isConnected() && networkInfo.getType() != prevNetType) {
1659                        LinkProperties l = networkStateTracker.getLinkProperties();
1660                        if (l == null) continue;
1661                        if (oldIface.equals(l.getInterfaceName())) {
1662                            doReset = false;
1663                            break;
1664                        }
1665                    }
1666                }
1667            }
1668        }
1669
1670        // do this before we broadcast the change
1671        handleConnectivityChange(prevNetType, doReset);
1672
1673        final Intent immediateIntent = new Intent(intent);
1674        immediateIntent.setAction(CONNECTIVITY_ACTION_IMMEDIATE);
1675        sendStickyBroadcast(immediateIntent);
1676        sendStickyBroadcastDelayed(intent, getConnectivityChangeDelay());
1677        /*
1678         * If the failover network is already connected, then immediately send
1679         * out a followup broadcast indicating successful failover
1680         */
1681        if (mActiveDefaultNetwork != -1) {
1682            sendConnectedBroadcastDelayed(mNetTrackers[mActiveDefaultNetwork].getNetworkInfo(),
1683                    getConnectivityChangeDelay());
1684        }
1685    }
1686
1687    private void tryFailover(int prevNetType) {
1688        /*
1689         * If this is a default network, check if other defaults are available.
1690         * Try to reconnect on all available and let them hash it out when
1691         * more than one connects.
1692         */
1693        if (mNetConfigs[prevNetType].isDefault()) {
1694            if (mActiveDefaultNetwork == prevNetType) {
1695                mActiveDefaultNetwork = -1;
1696            }
1697
1698            // don't signal a reconnect for anything lower or equal priority than our
1699            // current connected default
1700            // TODO - don't filter by priority now - nice optimization but risky
1701//            int currentPriority = -1;
1702//            if (mActiveDefaultNetwork != -1) {
1703//                currentPriority = mNetConfigs[mActiveDefaultNetwork].mPriority;
1704//            }
1705            for (int checkType=0; checkType <= ConnectivityManager.MAX_NETWORK_TYPE; checkType++) {
1706                if (checkType == prevNetType) continue;
1707                if (mNetConfigs[checkType] == null) continue;
1708                if (!mNetConfigs[checkType].isDefault()) continue;
1709                if (mNetTrackers[checkType] == null) continue;
1710
1711// Enabling the isAvailable() optimization caused mobile to not get
1712// selected if it was in the middle of error handling. Specifically
1713// a moble connection that took 30 seconds to complete the DEACTIVATE_DATA_CALL
1714// would not be available and we wouldn't get connected to anything.
1715// So removing the isAvailable() optimization below for now. TODO: This
1716// optimization should work and we need to investigate why it doesn't work.
1717// This could be related to how DEACTIVATE_DATA_CALL is reporting its
1718// complete before it is really complete.
1719//                if (!mNetTrackers[checkType].isAvailable()) continue;
1720
1721//                if (currentPriority >= mNetConfigs[checkType].mPriority) continue;
1722
1723                NetworkStateTracker checkTracker = mNetTrackers[checkType];
1724                NetworkInfo checkInfo = checkTracker.getNetworkInfo();
1725                if (!checkInfo.isConnectedOrConnecting() || checkTracker.isTeardownRequested()) {
1726                    checkInfo.setFailover(true);
1727                    checkTracker.reconnect();
1728                }
1729                if (DBG) log("Attempting to switch to " + checkInfo.getTypeName());
1730            }
1731        }
1732    }
1733
1734    private void sendConnectedBroadcast(NetworkInfo info) {
1735        sendGeneralBroadcast(info, CONNECTIVITY_ACTION_IMMEDIATE);
1736        sendGeneralBroadcast(info, CONNECTIVITY_ACTION);
1737    }
1738
1739    private void sendConnectedBroadcastDelayed(NetworkInfo info, int delayMs) {
1740        sendGeneralBroadcast(info, CONNECTIVITY_ACTION_IMMEDIATE);
1741        sendGeneralBroadcastDelayed(info, CONNECTIVITY_ACTION, delayMs);
1742    }
1743
1744    private void sendInetConditionBroadcast(NetworkInfo info) {
1745        sendGeneralBroadcast(info, ConnectivityManager.INET_CONDITION_ACTION);
1746    }
1747
1748    private Intent makeGeneralIntent(NetworkInfo info, String bcastType) {
1749        Intent intent = new Intent(bcastType);
1750        intent.putExtra(ConnectivityManager.EXTRA_NETWORK_INFO, info);
1751        if (info.isFailover()) {
1752            intent.putExtra(ConnectivityManager.EXTRA_IS_FAILOVER, true);
1753            info.setFailover(false);
1754        }
1755        if (info.getReason() != null) {
1756            intent.putExtra(ConnectivityManager.EXTRA_REASON, info.getReason());
1757        }
1758        if (info.getExtraInfo() != null) {
1759            intent.putExtra(ConnectivityManager.EXTRA_EXTRA_INFO,
1760                    info.getExtraInfo());
1761        }
1762        intent.putExtra(ConnectivityManager.EXTRA_INET_CONDITION, mDefaultInetConditionPublished);
1763        return intent;
1764    }
1765
1766    private void sendGeneralBroadcast(NetworkInfo info, String bcastType) {
1767        sendStickyBroadcast(makeGeneralIntent(info, bcastType));
1768    }
1769
1770    private void sendGeneralBroadcastDelayed(NetworkInfo info, String bcastType, int delayMs) {
1771        sendStickyBroadcastDelayed(makeGeneralIntent(info, bcastType), delayMs);
1772    }
1773
1774    private void sendDataActivityBroadcast(int deviceType, boolean active) {
1775        Intent intent = new Intent(ConnectivityManager.ACTION_DATA_ACTIVITY_CHANGE);
1776        intent.putExtra(ConnectivityManager.EXTRA_DEVICE_TYPE, deviceType);
1777        intent.putExtra(ConnectivityManager.EXTRA_IS_ACTIVE, active);
1778        mContext.sendOrderedBroadcast(intent, RECEIVE_DATA_ACTIVITY_CHANGE);
1779    }
1780
1781    /**
1782     * Called when an attempt to fail over to another network has failed.
1783     * @param info the {@link NetworkInfo} for the failed network
1784     */
1785    private void handleConnectionFailure(NetworkInfo info) {
1786        mNetTrackers[info.getType()].setTeardownRequested(false);
1787
1788        String reason = info.getReason();
1789        String extraInfo = info.getExtraInfo();
1790
1791        String reasonText;
1792        if (reason == null) {
1793            reasonText = ".";
1794        } else {
1795            reasonText = " (" + reason + ").";
1796        }
1797        loge("Attempt to connect to " + info.getTypeName() + " failed" + reasonText);
1798
1799        Intent intent = new Intent(ConnectivityManager.CONNECTIVITY_ACTION);
1800        intent.putExtra(ConnectivityManager.EXTRA_NETWORK_INFO, info);
1801        if (getActiveNetworkInfo() == null) {
1802            intent.putExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, true);
1803        }
1804        if (reason != null) {
1805            intent.putExtra(ConnectivityManager.EXTRA_REASON, reason);
1806        }
1807        if (extraInfo != null) {
1808            intent.putExtra(ConnectivityManager.EXTRA_EXTRA_INFO, extraInfo);
1809        }
1810        if (info.isFailover()) {
1811            intent.putExtra(ConnectivityManager.EXTRA_IS_FAILOVER, true);
1812            info.setFailover(false);
1813        }
1814
1815        if (mNetConfigs[info.getType()].isDefault()) {
1816            tryFailover(info.getType());
1817            if (mActiveDefaultNetwork != -1) {
1818                NetworkInfo switchTo = mNetTrackers[mActiveDefaultNetwork].getNetworkInfo();
1819                intent.putExtra(ConnectivityManager.EXTRA_OTHER_NETWORK_INFO, switchTo);
1820            } else {
1821                mDefaultInetConditionPublished = 0;
1822                intent.putExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, true);
1823            }
1824        }
1825
1826        intent.putExtra(ConnectivityManager.EXTRA_INET_CONDITION, mDefaultInetConditionPublished);
1827
1828        final Intent immediateIntent = new Intent(intent);
1829        immediateIntent.setAction(CONNECTIVITY_ACTION_IMMEDIATE);
1830        sendStickyBroadcast(immediateIntent);
1831        sendStickyBroadcast(intent);
1832        /*
1833         * If the failover network is already connected, then immediately send
1834         * out a followup broadcast indicating successful failover
1835         */
1836        if (mActiveDefaultNetwork != -1) {
1837            sendConnectedBroadcast(mNetTrackers[mActiveDefaultNetwork].getNetworkInfo());
1838        }
1839    }
1840
1841    private void sendStickyBroadcast(Intent intent) {
1842        synchronized(this) {
1843            if (!mSystemReady) {
1844                mInitialBroadcast = new Intent(intent);
1845            }
1846            intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
1847            if (VDBG) {
1848                log("sendStickyBroadcast: action=" + intent.getAction());
1849            }
1850
1851            mContext.sendStickyBroadcast(intent);
1852        }
1853    }
1854
1855    private void sendStickyBroadcastDelayed(Intent intent, int delayMs) {
1856        if (delayMs <= 0) {
1857            sendStickyBroadcast(intent);
1858        } else {
1859            if (VDBG) {
1860                log("sendStickyBroadcastDelayed: delayMs=" + delayMs + ", action="
1861                        + intent.getAction());
1862            }
1863            mHandler.sendMessageDelayed(mHandler.obtainMessage(
1864                    EVENT_SEND_STICKY_BROADCAST_INTENT, intent), delayMs);
1865        }
1866    }
1867
1868    void systemReady() {
1869        synchronized(this) {
1870            mSystemReady = true;
1871            if (mInitialBroadcast != null) {
1872                mContext.sendStickyBroadcast(mInitialBroadcast);
1873                mInitialBroadcast = null;
1874            }
1875        }
1876        // load the global proxy at startup
1877        mHandler.sendMessage(mHandler.obtainMessage(EVENT_APPLY_GLOBAL_HTTP_PROXY));
1878    }
1879
1880    private void handleConnect(NetworkInfo info) {
1881        final int type = info.getType();
1882
1883        // snapshot isFailover, because sendConnectedBroadcast() resets it
1884        boolean isFailover = info.isFailover();
1885        final NetworkStateTracker thisNet = mNetTrackers[type];
1886
1887        // if this is a default net and other default is running
1888        // kill the one not preferred
1889        if (mNetConfigs[type].isDefault()) {
1890            if (mActiveDefaultNetwork != -1 && mActiveDefaultNetwork != type) {
1891                if ((type != mNetworkPreference &&
1892                        mNetConfigs[mActiveDefaultNetwork].priority >
1893                        mNetConfigs[type].priority) ||
1894                        mNetworkPreference == mActiveDefaultNetwork) {
1895                        // don't accept this one
1896                        if (VDBG) {
1897                            log("Not broadcasting CONNECT_ACTION " +
1898                                "to torn down network " + info.getTypeName());
1899                        }
1900                        teardown(thisNet);
1901                        return;
1902                } else {
1903                    // tear down the other
1904                    NetworkStateTracker otherNet =
1905                            mNetTrackers[mActiveDefaultNetwork];
1906                    if (DBG) {
1907                        log("Policy requires " + otherNet.getNetworkInfo().getTypeName() +
1908                            " teardown");
1909                    }
1910                    if (!teardown(otherNet)) {
1911                        loge("Network declined teardown request");
1912                        teardown(thisNet);
1913                        return;
1914                    }
1915                }
1916            }
1917            synchronized (ConnectivityService.this) {
1918                // have a new default network, release the transition wakelock in a second
1919                // if it's held.  The second pause is to allow apps to reconnect over the
1920                // new network
1921                if (mNetTransitionWakeLock.isHeld()) {
1922                    mHandler.sendMessageDelayed(mHandler.obtainMessage(
1923                            EVENT_CLEAR_NET_TRANSITION_WAKELOCK,
1924                            mNetTransitionWakeLockSerialNumber, 0),
1925                            1000);
1926                }
1927            }
1928            mActiveDefaultNetwork = type;
1929            // this will cause us to come up initially as unconnected and switching
1930            // to connected after our normal pause unless somebody reports us as reall
1931            // disconnected
1932            mDefaultInetConditionPublished = 0;
1933            mDefaultConnectionSequence++;
1934            mInetConditionChangeInFlight = false;
1935            // Don't do this - if we never sign in stay, grey
1936            //reportNetworkCondition(mActiveDefaultNetwork, 100);
1937        }
1938        thisNet.setTeardownRequested(false);
1939        updateNetworkSettings(thisNet);
1940        handleConnectivityChange(type, false);
1941        sendConnectedBroadcastDelayed(info, getConnectivityChangeDelay());
1942
1943        // notify battery stats service about this network
1944        final String iface = thisNet.getLinkProperties().getInterfaceName();
1945        if (iface != null) {
1946            try {
1947                BatteryStatsService.getService().noteNetworkInterfaceType(iface, type);
1948            } catch (RemoteException e) {
1949                // ignored; service lives in system_server
1950            }
1951        }
1952    }
1953
1954    /**
1955     * After a change in the connectivity state of a network. We're mainly
1956     * concerned with making sure that the list of DNS servers is set up
1957     * according to which networks are connected, and ensuring that the
1958     * right routing table entries exist.
1959     */
1960    private void handleConnectivityChange(int netType, boolean doReset) {
1961        int resetMask = doReset ? NetworkUtils.RESET_ALL_ADDRESSES : 0;
1962
1963        /*
1964         * If a non-default network is enabled, add the host routes that
1965         * will allow it's DNS servers to be accessed.
1966         */
1967        handleDnsConfigurationChange(netType);
1968
1969        LinkProperties curLp = mCurrentLinkProperties[netType];
1970        LinkProperties newLp = null;
1971
1972        if (mNetTrackers[netType].getNetworkInfo().isConnected()) {
1973            newLp = mNetTrackers[netType].getLinkProperties();
1974            if (VDBG) {
1975                log("handleConnectivityChange: changed linkProperty[" + netType + "]:" +
1976                        " doReset=" + doReset + " resetMask=" + resetMask +
1977                        "\n   curLp=" + curLp +
1978                        "\n   newLp=" + newLp);
1979            }
1980
1981            if (curLp != null) {
1982                if (curLp.isIdenticalInterfaceName(newLp)) {
1983                    CompareResult<LinkAddress> car = curLp.compareAddresses(newLp);
1984                    if ((car.removed.size() != 0) || (car.added.size() != 0)) {
1985                        for (LinkAddress linkAddr : car.removed) {
1986                            if (linkAddr.getAddress() instanceof Inet4Address) {
1987                                resetMask |= NetworkUtils.RESET_IPV4_ADDRESSES;
1988                            }
1989                            if (linkAddr.getAddress() instanceof Inet6Address) {
1990                                resetMask |= NetworkUtils.RESET_IPV6_ADDRESSES;
1991                            }
1992                        }
1993                        if (DBG) {
1994                            log("handleConnectivityChange: addresses changed" +
1995                                    " linkProperty[" + netType + "]:" + " resetMask=" + resetMask +
1996                                    "\n   car=" + car);
1997                        }
1998                    } else {
1999                        if (DBG) {
2000                            log("handleConnectivityChange: address are the same reset per doReset" +
2001                                   " linkProperty[" + netType + "]:" +
2002                                   " resetMask=" + resetMask);
2003                        }
2004                    }
2005                } else {
2006                    resetMask = NetworkUtils.RESET_ALL_ADDRESSES;
2007                    if (DBG) {
2008                        log("handleConnectivityChange: interface not not equivalent reset both" +
2009                                " linkProperty[" + netType + "]:" +
2010                                " resetMask=" + resetMask);
2011                    }
2012                }
2013            }
2014            if (mNetConfigs[netType].isDefault()) {
2015                handleApplyDefaultProxy(newLp.getHttpProxy());
2016            }
2017        } else {
2018            if (VDBG) {
2019                log("handleConnectivityChange: changed linkProperty[" + netType + "]:" +
2020                        " doReset=" + doReset + " resetMask=" + resetMask +
2021                        "\n  curLp=" + curLp +
2022                        "\n  newLp= null");
2023            }
2024        }
2025        mCurrentLinkProperties[netType] = newLp;
2026        boolean resetDns = updateRoutes(newLp, curLp, mNetConfigs[netType].isDefault());
2027
2028        if (resetMask != 0 || resetDns) {
2029            LinkProperties linkProperties = mNetTrackers[netType].getLinkProperties();
2030            if (linkProperties != null) {
2031                String iface = linkProperties.getInterfaceName();
2032                if (TextUtils.isEmpty(iface) == false) {
2033                    if (resetMask != 0) {
2034                        if (DBG) log("resetConnections(" + iface + ", " + resetMask + ")");
2035                        NetworkUtils.resetConnections(iface, resetMask);
2036
2037                        // Tell VPN the interface is down. It is a temporary
2038                        // but effective fix to make VPN aware of the change.
2039                        if ((resetMask & NetworkUtils.RESET_IPV4_ADDRESSES) != 0) {
2040                            mVpn.interfaceStatusChanged(iface, false);
2041                        }
2042                    }
2043                    if (resetDns) {
2044                        if (VDBG) log("resetting DNS cache for " + iface);
2045                        try {
2046                            mNetd.flushInterfaceDnsCache(iface);
2047                        } catch (Exception e) {
2048                            // never crash - catch them all
2049                            if (DBG) loge("Exception resetting dns cache: " + e);
2050                        }
2051                    }
2052                }
2053            }
2054        }
2055
2056        // TODO: Temporary notifying upstread change to Tethering.
2057        //       @see bug/4455071
2058        /** Notify TetheringService if interface name has been changed. */
2059        if (TextUtils.equals(mNetTrackers[netType].getNetworkInfo().getReason(),
2060                             PhoneConstants.REASON_LINK_PROPERTIES_CHANGED)) {
2061            if (isTetheringSupported()) {
2062                mTethering.handleTetherIfaceChange();
2063            }
2064        }
2065    }
2066
2067    /**
2068     * Add and remove routes using the old properties (null if not previously connected),
2069     * new properties (null if becoming disconnected).  May even be double null, which
2070     * is a noop.
2071     * Uses isLinkDefault to determine if default routes should be set or conversely if
2072     * host routes should be set to the dns servers
2073     * returns a boolean indicating the routes changed
2074     */
2075    private boolean updateRoutes(LinkProperties newLp, LinkProperties curLp,
2076            boolean isLinkDefault) {
2077        Collection<RouteInfo> routesToAdd = null;
2078        CompareResult<InetAddress> dnsDiff = new CompareResult<InetAddress>();
2079        CompareResult<RouteInfo> routeDiff = new CompareResult<RouteInfo>();
2080        if (curLp != null) {
2081            // check for the delta between the current set and the new
2082            routeDiff = curLp.compareRoutes(newLp);
2083            dnsDiff = curLp.compareDnses(newLp);
2084        } else if (newLp != null) {
2085            routeDiff.added = newLp.getRoutes();
2086            dnsDiff.added = newLp.getDnses();
2087        }
2088
2089        boolean routesChanged = (routeDiff.removed.size() != 0 || routeDiff.added.size() != 0);
2090
2091        for (RouteInfo r : routeDiff.removed) {
2092            if (isLinkDefault || ! r.isDefaultRoute()) {
2093                removeRoute(curLp, r, TO_DEFAULT_TABLE);
2094            }
2095            if (isLinkDefault == false) {
2096                // remove from a secondary route table
2097                removeRoute(curLp, r, TO_SECONDARY_TABLE);
2098            }
2099        }
2100
2101        for (RouteInfo r :  routeDiff.added) {
2102            if (isLinkDefault || ! r.isDefaultRoute()) {
2103                addRoute(newLp, r, TO_DEFAULT_TABLE);
2104            } else {
2105                // add to a secondary route table
2106                addRoute(newLp, r, TO_SECONDARY_TABLE);
2107
2108                // many radios add a default route even when we don't want one.
2109                // remove the default route unless somebody else has asked for it
2110                String ifaceName = newLp.getInterfaceName();
2111                if (TextUtils.isEmpty(ifaceName) == false && mAddedRoutes.contains(r) == false) {
2112                    if (VDBG) log("Removing " + r + " for interface " + ifaceName);
2113                    try {
2114                        mNetd.removeRoute(ifaceName, r);
2115                    } catch (Exception e) {
2116                        // never crash - catch them all
2117                        if (DBG) loge("Exception trying to remove a route: " + e);
2118                    }
2119                }
2120            }
2121        }
2122
2123        if (!isLinkDefault) {
2124            // handle DNS routes
2125            if (routesChanged) {
2126                // routes changed - remove all old dns entries and add new
2127                if (curLp != null) {
2128                    for (InetAddress oldDns : curLp.getDnses()) {
2129                        removeRouteToAddress(curLp, oldDns);
2130                    }
2131                }
2132                if (newLp != null) {
2133                    for (InetAddress newDns : newLp.getDnses()) {
2134                        addRouteToAddress(newLp, newDns);
2135                    }
2136                }
2137            } else {
2138                // no change in routes, check for change in dns themselves
2139                for (InetAddress oldDns : dnsDiff.removed) {
2140                    removeRouteToAddress(curLp, oldDns);
2141                }
2142                for (InetAddress newDns : dnsDiff.added) {
2143                    addRouteToAddress(newLp, newDns);
2144                }
2145            }
2146        }
2147        return routesChanged;
2148    }
2149
2150
2151   /**
2152     * Reads the network specific TCP buffer sizes from SystemProperties
2153     * net.tcp.buffersize.[default|wifi|umts|edge|gprs] and set them for system
2154     * wide use
2155     */
2156   public void updateNetworkSettings(NetworkStateTracker nt) {
2157        String key = nt.getTcpBufferSizesPropName();
2158        String bufferSizes = SystemProperties.get(key);
2159
2160        if (bufferSizes.length() == 0) {
2161            if (VDBG) log(key + " not found in system properties. Using defaults");
2162
2163            // Setting to default values so we won't be stuck to previous values
2164            key = "net.tcp.buffersize.default";
2165            bufferSizes = SystemProperties.get(key);
2166        }
2167
2168        // Set values in kernel
2169        if (bufferSizes.length() != 0) {
2170            if (VDBG) {
2171                log("Setting TCP values: [" + bufferSizes
2172                        + "] which comes from [" + key + "]");
2173            }
2174            setBufferSize(bufferSizes);
2175        }
2176    }
2177
2178   /**
2179     * Writes TCP buffer sizes to /sys/kernel/ipv4/tcp_[r/w]mem_[min/def/max]
2180     * which maps to /proc/sys/net/ipv4/tcp_rmem and tcpwmem
2181     *
2182     * @param bufferSizes in the format of "readMin, readInitial, readMax,
2183     *        writeMin, writeInitial, writeMax"
2184     */
2185    private void setBufferSize(String bufferSizes) {
2186        try {
2187            String[] values = bufferSizes.split(",");
2188
2189            if (values.length == 6) {
2190              final String prefix = "/sys/kernel/ipv4/tcp_";
2191                FileUtils.stringToFile(prefix + "rmem_min", values[0]);
2192                FileUtils.stringToFile(prefix + "rmem_def", values[1]);
2193                FileUtils.stringToFile(prefix + "rmem_max", values[2]);
2194                FileUtils.stringToFile(prefix + "wmem_min", values[3]);
2195                FileUtils.stringToFile(prefix + "wmem_def", values[4]);
2196                FileUtils.stringToFile(prefix + "wmem_max", values[5]);
2197            } else {
2198                loge("Invalid buffersize string: " + bufferSizes);
2199            }
2200        } catch (IOException e) {
2201            loge("Can't set tcp buffer sizes:" + e);
2202        }
2203    }
2204
2205    /**
2206     * Adjust the per-process dns entries (net.dns<x>.<pid>) based
2207     * on the highest priority active net which this process requested.
2208     * If there aren't any, clear it out
2209     */
2210    private void reassessPidDns(int myPid, boolean doBump)
2211    {
2212        if (VDBG) log("reassessPidDns for pid " + myPid);
2213        for(int i : mPriorityList) {
2214            if (mNetConfigs[i].isDefault()) {
2215                continue;
2216            }
2217            NetworkStateTracker nt = mNetTrackers[i];
2218            if (nt.getNetworkInfo().isConnected() &&
2219                    !nt.isTeardownRequested()) {
2220                LinkProperties p = nt.getLinkProperties();
2221                if (p == null) continue;
2222                List pids = mNetRequestersPids[i];
2223                for (int j=0; j<pids.size(); j++) {
2224                    Integer pid = (Integer)pids.get(j);
2225                    if (pid.intValue() == myPid) {
2226                        Collection<InetAddress> dnses = p.getDnses();
2227                        writePidDns(dnses, myPid);
2228                        if (doBump) {
2229                            bumpDns();
2230                        }
2231                        return;
2232                    }
2233                }
2234           }
2235        }
2236        // nothing found - delete
2237        for (int i = 1; ; i++) {
2238            String prop = "net.dns" + i + "." + myPid;
2239            if (SystemProperties.get(prop).length() == 0) {
2240                if (doBump) {
2241                    bumpDns();
2242                }
2243                return;
2244            }
2245            SystemProperties.set(prop, "");
2246        }
2247    }
2248
2249    // return true if results in a change
2250    private boolean writePidDns(Collection <InetAddress> dnses, int pid) {
2251        int j = 1;
2252        boolean changed = false;
2253        for (InetAddress dns : dnses) {
2254            String dnsString = dns.getHostAddress();
2255            if (changed || !dnsString.equals(SystemProperties.get("net.dns" + j + "." + pid))) {
2256                changed = true;
2257                SystemProperties.set("net.dns" + j + "." + pid, dns.getHostAddress());
2258            }
2259            j++;
2260        }
2261        return changed;
2262    }
2263
2264    private void bumpDns() {
2265        /*
2266         * Bump the property that tells the name resolver library to reread
2267         * the DNS server list from the properties.
2268         */
2269        String propVal = SystemProperties.get("net.dnschange");
2270        int n = 0;
2271        if (propVal.length() != 0) {
2272            try {
2273                n = Integer.parseInt(propVal);
2274            } catch (NumberFormatException e) {}
2275        }
2276        SystemProperties.set("net.dnschange", "" + (n+1));
2277        /*
2278         * Tell the VMs to toss their DNS caches
2279         */
2280        Intent intent = new Intent(Intent.ACTION_CLEAR_DNS_CACHE);
2281        intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
2282        /*
2283         * Connectivity events can happen before boot has completed ...
2284         */
2285        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
2286        mContext.sendBroadcast(intent);
2287    }
2288
2289    // Caller must grab mDnsLock.
2290    private boolean updateDns(String network, String iface,
2291            Collection<InetAddress> dnses, String domains) {
2292        boolean changed = false;
2293        int last = 0;
2294        if (dnses.size() == 0 && mDefaultDns != null) {
2295            ++last;
2296            String value = mDefaultDns.getHostAddress();
2297            if (!value.equals(SystemProperties.get("net.dns1"))) {
2298                if (DBG) {
2299                    loge("no dns provided for " + network + " - using " + value);
2300                }
2301                changed = true;
2302                SystemProperties.set("net.dns1", value);
2303            }
2304        } else {
2305            for (InetAddress dns : dnses) {
2306                ++last;
2307                String key = "net.dns" + last;
2308                String value = dns.getHostAddress();
2309                if (!changed && value.equals(SystemProperties.get(key))) {
2310                    continue;
2311                }
2312                if (VDBG) {
2313                    log("adding dns " + value + " for " + network);
2314                }
2315                changed = true;
2316                SystemProperties.set(key, value);
2317            }
2318        }
2319        for (int i = last + 1; i <= mNumDnsEntries; ++i) {
2320            String key = "net.dns" + i;
2321            if (VDBG) log("erasing " + key);
2322            changed = true;
2323            SystemProperties.set(key, "");
2324        }
2325        mNumDnsEntries = last;
2326
2327        if (changed) {
2328            try {
2329                mNetd.setDnsServersForInterface(iface, NetworkUtils.makeStrings(dnses));
2330                mNetd.setDefaultInterfaceForDns(iface);
2331            } catch (Exception e) {
2332                if (DBG) loge("exception setting default dns interface: " + e);
2333            }
2334        }
2335        if (!domains.equals(SystemProperties.get("net.dns.search"))) {
2336            SystemProperties.set("net.dns.search", domains);
2337            changed = true;
2338        }
2339        return changed;
2340    }
2341
2342    private void handleDnsConfigurationChange(int netType) {
2343        // add default net's dns entries
2344        NetworkStateTracker nt = mNetTrackers[netType];
2345        if (nt != null && nt.getNetworkInfo().isConnected() && !nt.isTeardownRequested()) {
2346            LinkProperties p = nt.getLinkProperties();
2347            if (p == null) return;
2348            Collection<InetAddress> dnses = p.getDnses();
2349            boolean changed = false;
2350            if (mNetConfigs[netType].isDefault()) {
2351                String network = nt.getNetworkInfo().getTypeName();
2352                synchronized (mDnsLock) {
2353                    if (!mDnsOverridden) {
2354                        changed = updateDns(network, p.getInterfaceName(), dnses, "");
2355                    }
2356                }
2357            } else {
2358                try {
2359                    mNetd.setDnsServersForInterface(p.getInterfaceName(),
2360                            NetworkUtils.makeStrings(dnses));
2361                } catch (Exception e) {
2362                    if (DBG) loge("exception setting dns servers: " + e);
2363                }
2364                // set per-pid dns for attached secondary nets
2365                List pids = mNetRequestersPids[netType];
2366                for (int y=0; y< pids.size(); y++) {
2367                    Integer pid = (Integer)pids.get(y);
2368                    changed = writePidDns(dnses, pid.intValue());
2369                }
2370            }
2371            if (changed) bumpDns();
2372        }
2373    }
2374
2375    private int getRestoreDefaultNetworkDelay(int networkType) {
2376        String restoreDefaultNetworkDelayStr = SystemProperties.get(
2377                NETWORK_RESTORE_DELAY_PROP_NAME);
2378        if(restoreDefaultNetworkDelayStr != null &&
2379                restoreDefaultNetworkDelayStr.length() != 0) {
2380            try {
2381                return Integer.valueOf(restoreDefaultNetworkDelayStr);
2382            } catch (NumberFormatException e) {
2383            }
2384        }
2385        // if the system property isn't set, use the value for the apn type
2386        int ret = RESTORE_DEFAULT_NETWORK_DELAY;
2387
2388        if ((networkType <= ConnectivityManager.MAX_NETWORK_TYPE) &&
2389                (mNetConfigs[networkType] != null)) {
2390            ret = mNetConfigs[networkType].restoreTime;
2391        }
2392        return ret;
2393    }
2394
2395    @Override
2396    protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
2397        if (mContext.checkCallingOrSelfPermission(
2398                android.Manifest.permission.DUMP)
2399                != PackageManager.PERMISSION_GRANTED) {
2400            pw.println("Permission Denial: can't dump ConnectivityService " +
2401                    "from from pid=" + Binder.getCallingPid() + ", uid=" +
2402                    Binder.getCallingUid());
2403            return;
2404        }
2405        pw.println();
2406        for (NetworkStateTracker nst : mNetTrackers) {
2407            if (nst != null) {
2408                if (nst.getNetworkInfo().isConnected()) {
2409                    pw.println("Active network: " + nst.getNetworkInfo().
2410                            getTypeName());
2411                }
2412                pw.println(nst.getNetworkInfo());
2413                pw.println(nst);
2414                pw.println();
2415            }
2416        }
2417
2418        pw.println("Network Requester Pids:");
2419        for (int net : mPriorityList) {
2420            String pidString = net + ": ";
2421            for (Object pid : mNetRequestersPids[net]) {
2422                pidString = pidString + pid.toString() + ", ";
2423            }
2424            pw.println(pidString);
2425        }
2426        pw.println();
2427
2428        pw.println("FeatureUsers:");
2429        for (Object requester : mFeatureUsers) {
2430            pw.println(requester.toString());
2431        }
2432        pw.println();
2433
2434        synchronized (this) {
2435            pw.println("NetworkTranstionWakeLock is currently " +
2436                    (mNetTransitionWakeLock.isHeld() ? "" : "not ") + "held.");
2437            pw.println("It was last requested for "+mNetTransitionWakeLockCausedBy);
2438        }
2439        pw.println();
2440
2441        mTethering.dump(fd, pw, args);
2442
2443        if (mInetLog != null) {
2444            pw.println();
2445            pw.println("Inet condition reports:");
2446            for(int i = 0; i < mInetLog.size(); i++) {
2447                pw.println(mInetLog.get(i));
2448            }
2449        }
2450    }
2451
2452    // must be stateless - things change under us.
2453    private class NetworkStateTrackerHandler extends Handler {
2454        public NetworkStateTrackerHandler(Looper looper) {
2455            super(looper);
2456        }
2457
2458        @Override
2459        public void handleMessage(Message msg) {
2460            NetworkInfo info;
2461            switch (msg.what) {
2462                case NetworkStateTracker.EVENT_STATE_CHANGED:
2463                    info = (NetworkInfo) msg.obj;
2464                    int type = info.getType();
2465                    NetworkInfo.State state = info.getState();
2466
2467                    if (VDBG || (state == NetworkInfo.State.CONNECTED) ||
2468                            (state == NetworkInfo.State.DISCONNECTED)) {
2469                        log("ConnectivityChange for " +
2470                            info.getTypeName() + ": " +
2471                            state + "/" + info.getDetailedState());
2472                    }
2473
2474                    // Connectivity state changed:
2475                    // [31-14] Reserved for future use
2476                    // [13-10] Network subtype (for mobile network, as defined
2477                    //         by TelephonyManager)
2478                    // [9-4] Detailed state ordinal (as defined by
2479                    //         NetworkInfo.DetailedState)
2480                    // [3-0] Network type (as defined by ConnectivityManager)
2481                    int eventLogParam = (info.getType() & 0xf) |
2482                            ((info.getDetailedState().ordinal() & 0x3f) << 4) |
2483                            (info.getSubtype() << 10);
2484                    EventLog.writeEvent(EventLogTags.CONNECTIVITY_STATE_CHANGED,
2485                            eventLogParam);
2486
2487                    if (info.getDetailedState() ==
2488                            NetworkInfo.DetailedState.FAILED) {
2489                        handleConnectionFailure(info);
2490                    } else if (state == NetworkInfo.State.DISCONNECTED) {
2491                        handleDisconnect(info);
2492                    } else if (state == NetworkInfo.State.SUSPENDED) {
2493                        // TODO: need to think this over.
2494                        // the logic here is, handle SUSPENDED the same as
2495                        // DISCONNECTED. The only difference being we are
2496                        // broadcasting an intent with NetworkInfo that's
2497                        // suspended. This allows the applications an
2498                        // opportunity to handle DISCONNECTED and SUSPENDED
2499                        // differently, or not.
2500                        handleDisconnect(info);
2501                    } else if (state == NetworkInfo.State.CONNECTED) {
2502                        handleConnect(info);
2503                    }
2504                    break;
2505                case NetworkStateTracker.EVENT_CONFIGURATION_CHANGED:
2506                    info = (NetworkInfo) msg.obj;
2507                    // TODO: Temporary allowing network configuration
2508                    //       change not resetting sockets.
2509                    //       @see bug/4455071
2510                    handleConnectivityChange(info.getType(), false);
2511                    break;
2512            }
2513        }
2514    }
2515
2516    private class InternalHandler extends Handler {
2517        public InternalHandler(Looper looper) {
2518            super(looper);
2519        }
2520
2521        @Override
2522        public void handleMessage(Message msg) {
2523            NetworkInfo info;
2524            switch (msg.what) {
2525                case EVENT_CLEAR_NET_TRANSITION_WAKELOCK:
2526                    String causedBy = null;
2527                    synchronized (ConnectivityService.this) {
2528                        if (msg.arg1 == mNetTransitionWakeLockSerialNumber &&
2529                                mNetTransitionWakeLock.isHeld()) {
2530                            mNetTransitionWakeLock.release();
2531                            causedBy = mNetTransitionWakeLockCausedBy;
2532                        }
2533                    }
2534                    if (causedBy != null) {
2535                        log("NetTransition Wakelock for " + causedBy + " released by timeout");
2536                    }
2537                    break;
2538                case EVENT_RESTORE_DEFAULT_NETWORK:
2539                    FeatureUser u = (FeatureUser)msg.obj;
2540                    u.expire();
2541                    break;
2542                case EVENT_INET_CONDITION_CHANGE:
2543                {
2544                    int netType = msg.arg1;
2545                    int condition = msg.arg2;
2546                    handleInetConditionChange(netType, condition);
2547                    break;
2548                }
2549                case EVENT_INET_CONDITION_HOLD_END:
2550                {
2551                    int netType = msg.arg1;
2552                    int sequence = msg.arg2;
2553                    handleInetConditionHoldEnd(netType, sequence);
2554                    break;
2555                }
2556                case EVENT_SET_NETWORK_PREFERENCE:
2557                {
2558                    int preference = msg.arg1;
2559                    handleSetNetworkPreference(preference);
2560                    break;
2561                }
2562                case EVENT_SET_MOBILE_DATA:
2563                {
2564                    boolean enabled = (msg.arg1 == ENABLED);
2565                    handleSetMobileData(enabled);
2566                    break;
2567                }
2568                case EVENT_APPLY_GLOBAL_HTTP_PROXY:
2569                {
2570                    handleDeprecatedGlobalHttpProxy();
2571                    break;
2572                }
2573                case EVENT_SET_DEPENDENCY_MET:
2574                {
2575                    boolean met = (msg.arg1 == ENABLED);
2576                    handleSetDependencyMet(msg.arg2, met);
2577                    break;
2578                }
2579                case EVENT_RESTORE_DNS:
2580                {
2581                    if (mActiveDefaultNetwork != -1) {
2582                        handleDnsConfigurationChange(mActiveDefaultNetwork);
2583                    }
2584                    break;
2585                }
2586                case EVENT_SEND_STICKY_BROADCAST_INTENT:
2587                {
2588                    Intent intent = (Intent)msg.obj;
2589                    sendStickyBroadcast(intent);
2590                    break;
2591                }
2592                case EVENT_SET_POLICY_DATA_ENABLE: {
2593                    final int networkType = msg.arg1;
2594                    final boolean enabled = msg.arg2 == ENABLED;
2595                    handleSetPolicyDataEnable(networkType, enabled);
2596                }
2597            }
2598        }
2599    }
2600
2601    // javadoc from interface
2602    public int tether(String iface) {
2603        enforceTetherChangePermission();
2604
2605        if (isTetheringSupported()) {
2606            return mTethering.tether(iface);
2607        } else {
2608            return ConnectivityManager.TETHER_ERROR_UNSUPPORTED;
2609        }
2610    }
2611
2612    // javadoc from interface
2613    public int untether(String iface) {
2614        enforceTetherChangePermission();
2615
2616        if (isTetheringSupported()) {
2617            return mTethering.untether(iface);
2618        } else {
2619            return ConnectivityManager.TETHER_ERROR_UNSUPPORTED;
2620        }
2621    }
2622
2623    // javadoc from interface
2624    public int getLastTetherError(String iface) {
2625        enforceTetherAccessPermission();
2626
2627        if (isTetheringSupported()) {
2628            return mTethering.getLastTetherError(iface);
2629        } else {
2630            return ConnectivityManager.TETHER_ERROR_UNSUPPORTED;
2631        }
2632    }
2633
2634    // TODO - proper iface API for selection by property, inspection, etc
2635    public String[] getTetherableUsbRegexs() {
2636        enforceTetherAccessPermission();
2637        if (isTetheringSupported()) {
2638            return mTethering.getTetherableUsbRegexs();
2639        } else {
2640            return new String[0];
2641        }
2642    }
2643
2644    public String[] getTetherableWifiRegexs() {
2645        enforceTetherAccessPermission();
2646        if (isTetheringSupported()) {
2647            return mTethering.getTetherableWifiRegexs();
2648        } else {
2649            return new String[0];
2650        }
2651    }
2652
2653    public String[] getTetherableBluetoothRegexs() {
2654        enforceTetherAccessPermission();
2655        if (isTetheringSupported()) {
2656            return mTethering.getTetherableBluetoothRegexs();
2657        } else {
2658            return new String[0];
2659        }
2660    }
2661
2662    public int setUsbTethering(boolean enable) {
2663        enforceTetherAccessPermission();
2664        if (isTetheringSupported()) {
2665            return mTethering.setUsbTethering(enable);
2666        } else {
2667            return ConnectivityManager.TETHER_ERROR_UNSUPPORTED;
2668        }
2669    }
2670
2671    // TODO - move iface listing, queries, etc to new module
2672    // javadoc from interface
2673    public String[] getTetherableIfaces() {
2674        enforceTetherAccessPermission();
2675        return mTethering.getTetherableIfaces();
2676    }
2677
2678    public String[] getTetheredIfaces() {
2679        enforceTetherAccessPermission();
2680        return mTethering.getTetheredIfaces();
2681    }
2682
2683    @Override
2684    public String[] getTetheredIfacePairs() {
2685        enforceTetherAccessPermission();
2686        return mTethering.getTetheredIfacePairs();
2687    }
2688
2689    public String[] getTetheringErroredIfaces() {
2690        enforceTetherAccessPermission();
2691        return mTethering.getErroredIfaces();
2692    }
2693
2694    // if ro.tether.denied = true we default to no tethering
2695    // gservices could set the secure setting to 1 though to enable it on a build where it
2696    // had previously been turned off.
2697    public boolean isTetheringSupported() {
2698        enforceTetherAccessPermission();
2699        int defaultVal = (SystemProperties.get("ro.tether.denied").equals("true") ? 0 : 1);
2700        boolean tetherEnabledInSettings = (Settings.Secure.getInt(mContext.getContentResolver(),
2701                Settings.Secure.TETHER_SUPPORTED, defaultVal) != 0);
2702        return tetherEnabledInSettings && mTetheringConfigValid;
2703    }
2704
2705    // An API NetworkStateTrackers can call when they lose their network.
2706    // This will automatically be cleared after X seconds or a network becomes CONNECTED,
2707    // whichever happens first.  The timer is started by the first caller and not
2708    // restarted by subsequent callers.
2709    public void requestNetworkTransitionWakelock(String forWhom) {
2710        enforceConnectivityInternalPermission();
2711        synchronized (this) {
2712            if (mNetTransitionWakeLock.isHeld()) return;
2713            mNetTransitionWakeLockSerialNumber++;
2714            mNetTransitionWakeLock.acquire();
2715            mNetTransitionWakeLockCausedBy = forWhom;
2716        }
2717        mHandler.sendMessageDelayed(mHandler.obtainMessage(
2718                EVENT_CLEAR_NET_TRANSITION_WAKELOCK,
2719                mNetTransitionWakeLockSerialNumber, 0),
2720                mNetTransitionWakeLockTimeout);
2721        return;
2722    }
2723
2724    // 100 percent is full good, 0 is full bad.
2725    public void reportInetCondition(int networkType, int percentage) {
2726        if (VDBG) log("reportNetworkCondition(" + networkType + ", " + percentage + ")");
2727        mContext.enforceCallingOrSelfPermission(
2728                android.Manifest.permission.STATUS_BAR,
2729                "ConnectivityService");
2730
2731        if (DBG) {
2732            int pid = getCallingPid();
2733            int uid = getCallingUid();
2734            String s = pid + "(" + uid + ") reports inet is " +
2735                (percentage > 50 ? "connected" : "disconnected") + " (" + percentage + ") on " +
2736                "network Type " + networkType + " at " + GregorianCalendar.getInstance().getTime();
2737            mInetLog.add(s);
2738            while(mInetLog.size() > INET_CONDITION_LOG_MAX_SIZE) {
2739                mInetLog.remove(0);
2740            }
2741        }
2742        mHandler.sendMessage(mHandler.obtainMessage(
2743            EVENT_INET_CONDITION_CHANGE, networkType, percentage));
2744    }
2745
2746    private void handleInetConditionChange(int netType, int condition) {
2747        if (mActiveDefaultNetwork == -1) {
2748            if (DBG) log("handleInetConditionChange: no active default network - ignore");
2749            return;
2750        }
2751        if (mActiveDefaultNetwork != netType) {
2752            if (DBG) log("handleInetConditionChange: net=" + netType +
2753                            " != default=" + mActiveDefaultNetwork + " - ignore");
2754            return;
2755        }
2756        if (VDBG) {
2757            log("handleInetConditionChange: net=" +
2758                    netType + ", condition=" + condition +
2759                    ",mActiveDefaultNetwork=" + mActiveDefaultNetwork);
2760        }
2761        mDefaultInetCondition = condition;
2762        int delay;
2763        if (mInetConditionChangeInFlight == false) {
2764            if (VDBG) log("handleInetConditionChange: starting a change hold");
2765            // setup a new hold to debounce this
2766            if (mDefaultInetCondition > 50) {
2767                delay = Settings.Secure.getInt(mContext.getContentResolver(),
2768                        Settings.Secure.INET_CONDITION_DEBOUNCE_UP_DELAY, 500);
2769            } else {
2770                delay = Settings.Secure.getInt(mContext.getContentResolver(),
2771                Settings.Secure.INET_CONDITION_DEBOUNCE_DOWN_DELAY, 3000);
2772            }
2773            mInetConditionChangeInFlight = true;
2774            mHandler.sendMessageDelayed(mHandler.obtainMessage(EVENT_INET_CONDITION_HOLD_END,
2775                    mActiveDefaultNetwork, mDefaultConnectionSequence), delay);
2776        } else {
2777            // we've set the new condition, when this hold ends that will get picked up
2778            if (VDBG) log("handleInetConditionChange: currently in hold - not setting new end evt");
2779        }
2780    }
2781
2782    private void handleInetConditionHoldEnd(int netType, int sequence) {
2783        if (DBG) {
2784            log("handleInetConditionHoldEnd: net=" + netType +
2785                    ", condition=" + mDefaultInetCondition +
2786                    ", published condition=" + mDefaultInetConditionPublished);
2787        }
2788        mInetConditionChangeInFlight = false;
2789
2790        if (mActiveDefaultNetwork == -1) {
2791            if (DBG) log("handleInetConditionHoldEnd: no active default network - ignoring");
2792            return;
2793        }
2794        if (mDefaultConnectionSequence != sequence) {
2795            if (DBG) log("handleInetConditionHoldEnd: event hold for obsolete network - ignoring");
2796            return;
2797        }
2798        // TODO: Figure out why this optimization sometimes causes a
2799        //       change in mDefaultInetCondition to be missed and the
2800        //       UI to not be updated.
2801        //if (mDefaultInetConditionPublished == mDefaultInetCondition) {
2802        //    if (DBG) log("no change in condition - aborting");
2803        //    return;
2804        //}
2805        NetworkInfo networkInfo = mNetTrackers[mActiveDefaultNetwork].getNetworkInfo();
2806        if (networkInfo.isConnected() == false) {
2807            if (DBG) log("handleInetConditionHoldEnd: default network not connected - ignoring");
2808            return;
2809        }
2810        mDefaultInetConditionPublished = mDefaultInetCondition;
2811        sendInetConditionBroadcast(networkInfo);
2812        return;
2813    }
2814
2815    public ProxyProperties getProxy() {
2816        synchronized (mDefaultProxyLock) {
2817            return mDefaultProxyDisabled ? null : mDefaultProxy;
2818        }
2819    }
2820
2821    public void setGlobalProxy(ProxyProperties proxyProperties) {
2822        enforceChangePermission();
2823        synchronized (mGlobalProxyLock) {
2824            if (proxyProperties == mGlobalProxy) return;
2825            if (proxyProperties != null && proxyProperties.equals(mGlobalProxy)) return;
2826            if (mGlobalProxy != null && mGlobalProxy.equals(proxyProperties)) return;
2827
2828            String host = "";
2829            int port = 0;
2830            String exclList = "";
2831            if (proxyProperties != null && !TextUtils.isEmpty(proxyProperties.getHost())) {
2832                mGlobalProxy = new ProxyProperties(proxyProperties);
2833                host = mGlobalProxy.getHost();
2834                port = mGlobalProxy.getPort();
2835                exclList = mGlobalProxy.getExclusionList();
2836            } else {
2837                mGlobalProxy = null;
2838            }
2839            ContentResolver res = mContext.getContentResolver();
2840            Settings.Secure.putString(res, Settings.Secure.GLOBAL_HTTP_PROXY_HOST, host);
2841            Settings.Secure.putInt(res, Settings.Secure.GLOBAL_HTTP_PROXY_PORT, port);
2842            Settings.Secure.putString(res, Settings.Secure.GLOBAL_HTTP_PROXY_EXCLUSION_LIST,
2843                    exclList);
2844        }
2845
2846        if (mGlobalProxy == null) {
2847            proxyProperties = mDefaultProxy;
2848        }
2849        //sendProxyBroadcast(proxyProperties);
2850    }
2851
2852    private void loadGlobalProxy() {
2853        ContentResolver res = mContext.getContentResolver();
2854        String host = Settings.Secure.getString(res, Settings.Secure.GLOBAL_HTTP_PROXY_HOST);
2855        int port = Settings.Secure.getInt(res, Settings.Secure.GLOBAL_HTTP_PROXY_PORT, 0);
2856        String exclList = Settings.Secure.getString(res,
2857                Settings.Secure.GLOBAL_HTTP_PROXY_EXCLUSION_LIST);
2858        if (!TextUtils.isEmpty(host)) {
2859            ProxyProperties proxyProperties = new ProxyProperties(host, port, exclList);
2860            synchronized (mGlobalProxyLock) {
2861                mGlobalProxy = proxyProperties;
2862            }
2863        }
2864    }
2865
2866    public ProxyProperties getGlobalProxy() {
2867        synchronized (mGlobalProxyLock) {
2868            return mGlobalProxy;
2869        }
2870    }
2871
2872    private void handleApplyDefaultProxy(ProxyProperties proxy) {
2873        if (proxy != null && TextUtils.isEmpty(proxy.getHost())) {
2874            proxy = null;
2875        }
2876        synchronized (mDefaultProxyLock) {
2877            if (mDefaultProxy != null && mDefaultProxy.equals(proxy)) return;
2878            if (mDefaultProxy == proxy) return;
2879            mDefaultProxy = proxy;
2880
2881            if (!mDefaultProxyDisabled) {
2882                sendProxyBroadcast(proxy);
2883            }
2884        }
2885    }
2886
2887    private void handleDeprecatedGlobalHttpProxy() {
2888        String proxy = Settings.Secure.getString(mContext.getContentResolver(),
2889                Settings.Secure.HTTP_PROXY);
2890        if (!TextUtils.isEmpty(proxy)) {
2891            String data[] = proxy.split(":");
2892            String proxyHost =  data[0];
2893            int proxyPort = 8080;
2894            if (data.length > 1) {
2895                try {
2896                    proxyPort = Integer.parseInt(data[1]);
2897                } catch (NumberFormatException e) {
2898                    return;
2899                }
2900            }
2901            ProxyProperties p = new ProxyProperties(data[0], proxyPort, "");
2902            setGlobalProxy(p);
2903        }
2904    }
2905
2906    private void sendProxyBroadcast(ProxyProperties proxy) {
2907        if (proxy == null) proxy = new ProxyProperties("", 0, "");
2908        if (DBG) log("sending Proxy Broadcast for " + proxy);
2909        Intent intent = new Intent(Proxy.PROXY_CHANGE_ACTION);
2910        intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING |
2911            Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
2912        intent.putExtra(Proxy.EXTRA_PROXY_INFO, proxy);
2913        mContext.sendStickyBroadcast(intent);
2914    }
2915
2916    private static class SettingsObserver extends ContentObserver {
2917        private int mWhat;
2918        private Handler mHandler;
2919        SettingsObserver(Handler handler, int what) {
2920            super(handler);
2921            mHandler = handler;
2922            mWhat = what;
2923        }
2924
2925        void observe(Context context) {
2926            ContentResolver resolver = context.getContentResolver();
2927            resolver.registerContentObserver(Settings.Secure.getUriFor(
2928                    Settings.Secure.HTTP_PROXY), false, this);
2929        }
2930
2931        @Override
2932        public void onChange(boolean selfChange) {
2933            mHandler.obtainMessage(mWhat).sendToTarget();
2934        }
2935    }
2936
2937    private void log(String s) {
2938        Slog.d(TAG, s);
2939    }
2940
2941    private void loge(String s) {
2942        Slog.e(TAG, s);
2943    }
2944
2945    int convertFeatureToNetworkType(int networkType, String feature) {
2946        int usedNetworkType = networkType;
2947
2948        if(networkType == ConnectivityManager.TYPE_MOBILE) {
2949            if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_MMS)) {
2950                usedNetworkType = ConnectivityManager.TYPE_MOBILE_MMS;
2951            } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_SUPL)) {
2952                usedNetworkType = ConnectivityManager.TYPE_MOBILE_SUPL;
2953            } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_DUN) ||
2954                    TextUtils.equals(feature, Phone.FEATURE_ENABLE_DUN_ALWAYS)) {
2955                usedNetworkType = ConnectivityManager.TYPE_MOBILE_DUN;
2956            } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_HIPRI)) {
2957                usedNetworkType = ConnectivityManager.TYPE_MOBILE_HIPRI;
2958            } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_FOTA)) {
2959                usedNetworkType = ConnectivityManager.TYPE_MOBILE_FOTA;
2960            } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_IMS)) {
2961                usedNetworkType = ConnectivityManager.TYPE_MOBILE_IMS;
2962            } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_CBS)) {
2963                usedNetworkType = ConnectivityManager.TYPE_MOBILE_CBS;
2964            } else {
2965                Slog.e(TAG, "Can't match any mobile netTracker!");
2966            }
2967        } else if (networkType == ConnectivityManager.TYPE_WIFI) {
2968            if (TextUtils.equals(feature, "p2p")) {
2969                usedNetworkType = ConnectivityManager.TYPE_WIFI_P2P;
2970            } else {
2971                Slog.e(TAG, "Can't match any wifi netTracker!");
2972            }
2973        } else {
2974            Slog.e(TAG, "Unexpected network type");
2975        }
2976        return usedNetworkType;
2977    }
2978
2979    private static <T> T checkNotNull(T value, String message) {
2980        if (value == null) {
2981            throw new NullPointerException(message);
2982        }
2983        return value;
2984    }
2985
2986    /**
2987     * Protect a socket from VPN routing rules. This method is used by
2988     * VpnBuilder and not available in ConnectivityManager. Permissions
2989     * are checked in Vpn class.
2990     * @hide
2991     */
2992    @Override
2993    public boolean protectVpn(ParcelFileDescriptor socket) {
2994        try {
2995            int type = mActiveDefaultNetwork;
2996            if (ConnectivityManager.isNetworkTypeValid(type)) {
2997                mVpn.protect(socket, mNetTrackers[type].getLinkProperties().getInterfaceName());
2998                return true;
2999            }
3000        } catch (Exception e) {
3001            // ignore
3002        } finally {
3003            try {
3004                socket.close();
3005            } catch (Exception e) {
3006                // ignore
3007            }
3008        }
3009        return false;
3010    }
3011
3012    /**
3013     * Prepare for a VPN application. This method is used by VpnDialogs
3014     * and not available in ConnectivityManager. Permissions are checked
3015     * in Vpn class.
3016     * @hide
3017     */
3018    @Override
3019    public boolean prepareVpn(String oldPackage, String newPackage) {
3020        return mVpn.prepare(oldPackage, newPackage);
3021    }
3022
3023    /**
3024     * Configure a TUN interface and return its file descriptor. Parameters
3025     * are encoded and opaque to this class. This method is used by VpnBuilder
3026     * and not available in ConnectivityManager. Permissions are checked in
3027     * Vpn class.
3028     * @hide
3029     */
3030    @Override
3031    public ParcelFileDescriptor establishVpn(VpnConfig config) {
3032        return mVpn.establish(config);
3033    }
3034
3035    /**
3036     * Start legacy VPN and return an intent to VpnDialogs. This method is
3037     * used by VpnSettings and not available in ConnectivityManager.
3038     * Permissions are checked in Vpn class.
3039     * @hide
3040     */
3041    @Override
3042    public void startLegacyVpn(VpnConfig config, String[] racoon, String[] mtpd) {
3043        mVpn.startLegacyVpn(config, racoon, mtpd);
3044    }
3045
3046    /**
3047     * Return the information of the ongoing legacy VPN. This method is used
3048     * by VpnSettings and not available in ConnectivityManager. Permissions
3049     * are checked in Vpn class.
3050     * @hide
3051     */
3052    @Override
3053    public LegacyVpnInfo getLegacyVpnInfo() {
3054        return mVpn.getLegacyVpnInfo();
3055    }
3056
3057    /**
3058     * Callback for VPN subsystem. Currently VPN is not adapted to the service
3059     * through NetworkStateTracker since it works differently. For example, it
3060     * needs to override DNS servers but never takes the default routes. It
3061     * relies on another data network, and it could keep existing connections
3062     * alive after reconnecting, switching between networks, or even resuming
3063     * from deep sleep. Calls from applications should be done synchronously
3064     * to avoid race conditions. As these are all hidden APIs, refactoring can
3065     * be done whenever a better abstraction is developed.
3066     */
3067    public class VpnCallback {
3068
3069        private VpnCallback() {
3070        }
3071
3072        public void override(List<String> dnsServers, List<String> searchDomains) {
3073            if (dnsServers == null) {
3074                restore();
3075                return;
3076            }
3077
3078            // Convert DNS servers into addresses.
3079            List<InetAddress> addresses = new ArrayList<InetAddress>();
3080            for (String address : dnsServers) {
3081                // Double check the addresses and remove invalid ones.
3082                try {
3083                    addresses.add(InetAddress.parseNumericAddress(address));
3084                } catch (Exception e) {
3085                    // ignore
3086                }
3087            }
3088            if (addresses.isEmpty()) {
3089                restore();
3090                return;
3091            }
3092
3093            // Concatenate search domains into a string.
3094            StringBuilder buffer = new StringBuilder();
3095            if (searchDomains != null) {
3096                for (String domain : searchDomains) {
3097                    buffer.append(domain).append(' ');
3098                }
3099            }
3100            String domains = buffer.toString().trim();
3101
3102            // Apply DNS changes.
3103            boolean changed = false;
3104            synchronized (mDnsLock) {
3105                changed = updateDns("VPN", "VPN", addresses, domains);
3106                mDnsOverridden = true;
3107            }
3108            if (changed) {
3109                bumpDns();
3110            }
3111
3112            // Temporarily disable the default proxy.
3113            synchronized (mDefaultProxyLock) {
3114                mDefaultProxyDisabled = true;
3115                if (mDefaultProxy != null) {
3116                    sendProxyBroadcast(null);
3117                }
3118            }
3119
3120            // TODO: support proxy per network.
3121        }
3122
3123        public void restore() {
3124            synchronized (mDnsLock) {
3125                if (mDnsOverridden) {
3126                    mDnsOverridden = false;
3127                    mHandler.sendEmptyMessage(EVENT_RESTORE_DNS);
3128                }
3129            }
3130            synchronized (mDefaultProxyLock) {
3131                mDefaultProxyDisabled = false;
3132                if (mDefaultProxy != null) {
3133                    sendProxyBroadcast(mDefaultProxy);
3134                }
3135            }
3136        }
3137    }
3138}
3139