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