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