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