ConnectivityService.java revision 47d4caf41b052ab88f747ccc789754be5f44f8af
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<FeatureUser> 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<FeatureUser>();
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 boolean isSameUser(FeatureUser u) {
799            if (u == null) return false;
800
801            return isSameUser(u.mPid, u.mUid, u.mNetworkType, u.mFeature);
802        }
803
804        public boolean isSameUser(int pid, int uid, int networkType, String feature) {
805            if ((mPid == pid) && (mUid == uid) && (mNetworkType == networkType) &&
806                TextUtils.equals(mFeature, feature)) {
807                return true;
808            }
809            return false;
810        }
811
812        public String toString() {
813            return "FeatureUser("+mNetworkType+","+mFeature+","+mPid+","+mUid+"), created " +
814                    (System.currentTimeMillis() - mCreateTime) + " mSec ago";
815        }
816    }
817
818    // javadoc from interface
819    public int startUsingNetworkFeature(int networkType, String feature,
820            IBinder binder) {
821        if (DBG) {
822            log("startUsingNetworkFeature for net " + networkType + ": " + feature);
823        }
824        enforceChangePermission();
825        if (!ConnectivityManager.isNetworkTypeValid(networkType) ||
826                mNetConfigs[networkType] == null) {
827            return Phone.APN_REQUEST_FAILED;
828        }
829
830        FeatureUser f = new FeatureUser(networkType, feature, binder);
831
832        // TODO - move this into the MobileDataStateTracker
833        int usedNetworkType = networkType;
834        if(networkType == ConnectivityManager.TYPE_MOBILE) {
835            usedNetworkType = convertFeatureToNetworkType(feature);
836            if (usedNetworkType < 0) {
837                Slog.e(TAG, "Can't match any netTracker!");
838                usedNetworkType = networkType;
839            }
840        }
841
842        if (mProtectedNetworks.contains(usedNetworkType)) {
843            enforceConnectivityInternalPermission();
844        }
845
846        NetworkStateTracker network = mNetTrackers[usedNetworkType];
847        if (network != null) {
848            Integer currentPid = new Integer(getCallingPid());
849            if (usedNetworkType != networkType) {
850                NetworkStateTracker radio = mNetTrackers[networkType];
851                NetworkInfo ni = network.getNetworkInfo();
852
853                if (ni.isAvailable() == false) {
854                    if (DBG) log("special network not available");
855                    if (!TextUtils.equals(feature,Phone.FEATURE_ENABLE_DUN_ALWAYS)) {
856                        return Phone.APN_TYPE_NOT_AVAILABLE;
857                    } else {
858                        // else make the attempt anyway - probably giving REQUEST_STARTED below
859                    }
860                }
861
862                int restoreTimer = getRestoreDefaultNetworkDelay(usedNetworkType);
863
864                synchronized(this) {
865                    boolean addToList = true;
866                    if (restoreTimer < 0) {
867                        // In case there is no timer is specified for the feature,
868                        // make sure we don't add duplicate entry with the same request.
869                        for (FeatureUser u : mFeatureUsers) {
870                            if (u.isSameUser(f)) {
871                                // Duplicate user is found. Do not add.
872                                addToList = false;
873                                break;
874                            }
875                        }
876                    }
877
878                    if (addToList) mFeatureUsers.add(f);
879                    if (!mNetRequestersPids[usedNetworkType].contains(currentPid)) {
880                        // this gets used for per-pid dns when connected
881                        mNetRequestersPids[usedNetworkType].add(currentPid);
882                    }
883                }
884
885                if (restoreTimer >= 0) {
886                    mHandler.sendMessageDelayed(
887                            mHandler.obtainMessage(EVENT_RESTORE_DEFAULT_NETWORK, f), restoreTimer);
888                }
889
890                if ((ni.isConnectedOrConnecting() == true) &&
891                        !network.isTeardownRequested()) {
892                    if (ni.isConnected() == true) {
893                        // add the pid-specific dns
894                        handleDnsConfigurationChange(networkType);
895                        if (DBG) log("special network already active");
896                        return Phone.APN_ALREADY_ACTIVE;
897                    }
898                    if (DBG) log("special network already connecting");
899                    return Phone.APN_REQUEST_STARTED;
900                }
901
902                // check if the radio in play can make another contact
903                // assume if cannot for now
904
905                if (DBG) log("reconnecting to special network");
906                network.reconnect();
907                return Phone.APN_REQUEST_STARTED;
908            } else {
909                // need to remember this unsupported request so we respond appropriately on stop
910                synchronized(this) {
911                    mFeatureUsers.add(f);
912                    if (!mNetRequestersPids[usedNetworkType].contains(currentPid)) {
913                        // this gets used for per-pid dns when connected
914                        mNetRequestersPids[usedNetworkType].add(currentPid);
915                    }
916                }
917                return -1;
918            }
919        }
920        return Phone.APN_TYPE_NOT_AVAILABLE;
921    }
922
923    // javadoc from interface
924    public int stopUsingNetworkFeature(int networkType, String feature) {
925        enforceChangePermission();
926
927        int pid = getCallingPid();
928        int uid = getCallingUid();
929
930        FeatureUser u = null;
931        boolean found = false;
932
933        synchronized(this) {
934            for (FeatureUser x : mFeatureUsers) {
935                if (x.isSameUser(pid, uid, networkType, feature)) {
936                    u = x;
937                    found = true;
938                    break;
939                }
940            }
941        }
942        if (found && u != null) {
943            // stop regardless of how many other time this proc had called start
944            return stopUsingNetworkFeature(u, true);
945        } else {
946            // none found!
947            if (DBG) log("ignoring stopUsingNetworkFeature - not a live request");
948            return 1;
949        }
950    }
951
952    private int stopUsingNetworkFeature(FeatureUser u, boolean ignoreDups) {
953        int networkType = u.mNetworkType;
954        String feature = u.mFeature;
955        int pid = u.mPid;
956        int uid = u.mUid;
957
958        NetworkStateTracker tracker = null;
959        boolean callTeardown = false;  // used to carry our decision outside of sync block
960
961        if (DBG) {
962            log("stopUsingNetworkFeature for net " + networkType +
963                    ": " + feature);
964        }
965
966        if (!ConnectivityManager.isNetworkTypeValid(networkType)) {
967            return -1;
968        }
969
970        // need to link the mFeatureUsers list with the mNetRequestersPids state in this
971        // sync block
972        synchronized(this) {
973            // check if this process still has an outstanding start request
974            if (!mFeatureUsers.contains(u)) {
975                if (DBG) log("ignoring - this process has no outstanding requests");
976                return 1;
977            }
978            u.unlinkDeathRecipient();
979            mFeatureUsers.remove(mFeatureUsers.indexOf(u));
980            // If we care about duplicate requests, check for that here.
981            //
982            // This is done to support the extension of a request - the app
983            // can request we start the network feature again and renew the
984            // auto-shutoff delay.  Normal "stop" calls from the app though
985            // do not pay attention to duplicate requests - in effect the
986            // API does not refcount and a single stop will counter multiple starts.
987            if (ignoreDups == false) {
988                for (FeatureUser x : mFeatureUsers) {
989                    if (x.isSameUser(u)) {
990                        if (DBG) log("ignoring stopUsingNetworkFeature as dup is found");
991                        return 1;
992                    }
993                }
994            }
995
996            // TODO - move to MobileDataStateTracker
997            int usedNetworkType = networkType;
998            if (networkType == ConnectivityManager.TYPE_MOBILE) {
999                usedNetworkType = convertFeatureToNetworkType(feature);
1000                if (usedNetworkType < 0) {
1001                    usedNetworkType = networkType;
1002                }
1003            }
1004            tracker =  mNetTrackers[usedNetworkType];
1005            if (tracker == null) {
1006                if (DBG) log("ignoring - no known tracker for net type " + usedNetworkType);
1007                return -1;
1008            }
1009            if (usedNetworkType != networkType) {
1010                Integer currentPid = new Integer(pid);
1011                mNetRequestersPids[usedNetworkType].remove(currentPid);
1012                reassessPidDns(pid, true);
1013                if (mNetRequestersPids[usedNetworkType].size() != 0) {
1014                    if (DBG) log("not tearing down special network - " +
1015                           "others still using it");
1016                    return 1;
1017                }
1018                callTeardown = true;
1019            } else {
1020                if (DBG) log("not a known feature - dropping");
1021            }
1022        }
1023        if (DBG) log("Doing network teardown");
1024        if (callTeardown) {
1025            tracker.teardown();
1026            return 1;
1027        } else {
1028            return -1;
1029        }
1030    }
1031
1032    /**
1033     * @deprecated use requestRouteToHostAddress instead
1034     *
1035     * Ensure that a network route exists to deliver traffic to the specified
1036     * host via the specified network interface.
1037     * @param networkType the type of the network over which traffic to the
1038     * specified host is to be routed
1039     * @param hostAddress the IP address of the host to which the route is
1040     * desired
1041     * @return {@code true} on success, {@code false} on failure
1042     */
1043    public boolean requestRouteToHost(int networkType, int hostAddress) {
1044        InetAddress inetAddress = NetworkUtils.intToInetAddress(hostAddress);
1045
1046        if (inetAddress == null) {
1047            return false;
1048        }
1049
1050        return requestRouteToHostAddress(networkType, inetAddress.getAddress());
1051    }
1052
1053    /**
1054     * Ensure that a network route exists to deliver traffic to the specified
1055     * host via the specified network interface.
1056     * @param networkType the type of the network over which traffic to the
1057     * specified host is to be routed
1058     * @param hostAddress the IP address of the host to which the route is
1059     * desired
1060     * @return {@code true} on success, {@code false} on failure
1061     */
1062    public boolean requestRouteToHostAddress(int networkType, byte[] hostAddress) {
1063        enforceChangePermission();
1064        if (mProtectedNetworks.contains(networkType)) {
1065            enforceConnectivityInternalPermission();
1066        }
1067
1068        if (!ConnectivityManager.isNetworkTypeValid(networkType)) {
1069            return false;
1070        }
1071        NetworkStateTracker tracker = mNetTrackers[networkType];
1072
1073        if (tracker == null || !tracker.getNetworkInfo().isConnected() ||
1074                tracker.isTeardownRequested()) {
1075            if (DBG) {
1076                log("requestRouteToHostAddress on down network " +
1077                           "(" + networkType + ") - dropped");
1078            }
1079            return false;
1080        }
1081        try {
1082            InetAddress addr = InetAddress.getByAddress(hostAddress);
1083            LinkProperties lp = tracker.getLinkProperties();
1084            return addRoute(lp, RouteInfo.makeHostRoute(addr));
1085        } catch (UnknownHostException e) {}
1086        return false;
1087    }
1088
1089    private boolean addRoute(LinkProperties p, RouteInfo r) {
1090        return modifyRoute(p.getInterfaceName(), p, r, 0, true);
1091    }
1092
1093    private boolean removeRoute(LinkProperties p, RouteInfo r) {
1094        return modifyRoute(p.getInterfaceName(), p, r, 0, false);
1095    }
1096
1097    private boolean modifyRoute(String ifaceName, LinkProperties lp, RouteInfo r, int cycleCount,
1098            boolean doAdd) {
1099        if ((ifaceName == null) || (lp == null) || (r == null)) return false;
1100
1101        if (cycleCount > MAX_HOSTROUTE_CYCLE_COUNT) {
1102            loge("Error adding route - too much recursion");
1103            return false;
1104        }
1105
1106        if (r.isHostRoute() == false) {
1107            RouteInfo bestRoute = RouteInfo.selectBestRoute(lp.getRoutes(), r.getGateway());
1108            if (bestRoute != null) {
1109                if (bestRoute.getGateway().equals(r.getGateway())) {
1110                    // if there is no better route, add the implied hostroute for our gateway
1111                    bestRoute = RouteInfo.makeHostRoute(r.getGateway());
1112                } else {
1113                    // if we will connect to our gateway through another route, add a direct
1114                    // route to it's gateway
1115                    bestRoute = RouteInfo.makeHostRoute(r.getGateway(), bestRoute.getGateway());
1116                }
1117                modifyRoute(ifaceName, lp, bestRoute, cycleCount+1, doAdd);
1118            }
1119        }
1120        if (doAdd) {
1121            if (DBG) log("Adding " + r + " for interface " + ifaceName);
1122            mAddedRoutes.add(r);
1123            try {
1124                mNetd.addRoute(ifaceName, r);
1125            } catch (Exception e) {
1126                // never crash - catch them all
1127                loge("Exception trying to add a route: " + e);
1128                return false;
1129            }
1130        } else {
1131            // if we remove this one and there are no more like it, then refcount==0 and
1132            // we can remove it from the table
1133            mAddedRoutes.remove(r);
1134            if (mAddedRoutes.contains(r) == false) {
1135                if (DBG) log("Removing " + r + " for interface " + ifaceName);
1136                try {
1137                    mNetd.removeRoute(ifaceName, r);
1138                } catch (Exception e) {
1139                    // never crash - catch them all
1140                    loge("Exception trying to remove a route: " + e);
1141                    return false;
1142                }
1143            } else {
1144                if (DBG) log("not removing " + r + " as it's still in use");
1145            }
1146        }
1147        return true;
1148    }
1149
1150    /**
1151     * @see ConnectivityManager#getBackgroundDataSetting()
1152     */
1153    public boolean getBackgroundDataSetting() {
1154        return mBackgroundDataEnabled.get();
1155    }
1156
1157    /**
1158     * @see ConnectivityManager#setBackgroundDataSetting(boolean)
1159     */
1160    public void setBackgroundDataSetting(boolean allowBackgroundDataUsage) {
1161        mContext.enforceCallingOrSelfPermission(
1162                android.Manifest.permission.CHANGE_BACKGROUND_DATA_SETTING,
1163                "ConnectivityService");
1164
1165        mBackgroundDataEnabled.set(allowBackgroundDataUsage);
1166
1167        mHandler.sendMessage(mHandler.obtainMessage(EVENT_SET_BACKGROUND_DATA,
1168                (allowBackgroundDataUsage ? ENABLED : DISABLED), 0));
1169    }
1170
1171    private void handleSetBackgroundData(boolean enabled) {
1172        Settings.Secure.putInt(mContext.getContentResolver(),
1173                Settings.Secure.BACKGROUND_DATA, enabled ? 1 : 0);
1174        Intent broadcast = new Intent(
1175                ConnectivityManager.ACTION_BACKGROUND_DATA_SETTING_CHANGED);
1176        mContext.sendBroadcast(broadcast);
1177    }
1178
1179    /**
1180     * @see ConnectivityManager#getMobileDataEnabled()
1181     */
1182    public boolean getMobileDataEnabled() {
1183        // TODO: This detail should probably be in DataConnectionTracker's
1184        //       which is where we store the value and maybe make this
1185        //       asynchronous.
1186        enforceAccessPermission();
1187        boolean retVal = Settings.Secure.getInt(mContext.getContentResolver(),
1188                Settings.Secure.MOBILE_DATA, 1) == 1;
1189        if (DBG) log("getMobileDataEnabled returning " + retVal);
1190        return retVal;
1191    }
1192
1193    public void setDataDependency(int networkType, boolean met) {
1194        enforceConnectivityInternalPermission();
1195
1196        mHandler.sendMessage(mHandler.obtainMessage(EVENT_SET_DEPENDENCY_MET,
1197                (met ? ENABLED : DISABLED), networkType));
1198    }
1199
1200    private void handleSetDependencyMet(int networkType, boolean met) {
1201        if (mNetTrackers[networkType] != null) {
1202            if (DBG) {
1203                log("handleSetDependencyMet(" + networkType + ", " + met + ")");
1204            }
1205            mNetTrackers[networkType].setDependencyMet(met);
1206        }
1207    }
1208
1209    private INetworkPolicyListener mPolicyListener = new INetworkPolicyListener.Stub() {
1210        @Override
1211        public void onUidRulesChanged(int uid, int uidRules) {
1212            // only someone like NPMS should only be calling us
1213            mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
1214
1215            if (LOGD_RULES) {
1216                Slog.d(TAG, "onUidRulesChanged(uid=" + uid + ", uidRules=" + uidRules + ")");
1217            }
1218
1219            synchronized (mRulesLock) {
1220                // skip update when we've already applied rules
1221                final int oldRules = mUidRules.get(uid, RULE_ALLOW_ALL);
1222                if (oldRules == uidRules) return;
1223
1224                mUidRules.put(uid, uidRules);
1225            }
1226
1227            // TODO: dispatch into NMS to push rules towards kernel module
1228            // TODO: notify UID when it has requested targeted updates
1229        }
1230
1231        @Override
1232        public void onMeteredIfacesChanged(String[] meteredIfaces) {
1233            // only someone like NPMS should only be calling us
1234            mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
1235
1236            if (LOGD_RULES) {
1237                Slog.d(TAG,
1238                        "onMeteredIfacesChanged(ifaces=" + Arrays.toString(meteredIfaces) + ")");
1239            }
1240
1241            synchronized (mRulesLock) {
1242                mMeteredIfaces.clear();
1243                for (String iface : meteredIfaces) {
1244                    mMeteredIfaces.add(iface);
1245                }
1246            }
1247        }
1248    };
1249
1250    /**
1251     * @see ConnectivityManager#setMobileDataEnabled(boolean)
1252     */
1253    public void setMobileDataEnabled(boolean enabled) {
1254        enforceChangePermission();
1255        if (DBG) log("setMobileDataEnabled(" + enabled + ")");
1256
1257        mHandler.sendMessage(mHandler.obtainMessage(EVENT_SET_MOBILE_DATA,
1258                (enabled ? ENABLED : DISABLED), 0));
1259    }
1260
1261    private void handleSetMobileData(boolean enabled) {
1262        if (mNetTrackers[ConnectivityManager.TYPE_MOBILE] != null) {
1263            if (DBG) {
1264                Slog.d(TAG, mNetTrackers[ConnectivityManager.TYPE_MOBILE].toString() + enabled);
1265            }
1266            mNetTrackers[ConnectivityManager.TYPE_MOBILE].setDataEnable(enabled);
1267        }
1268    }
1269
1270    private void enforceAccessPermission() {
1271        mContext.enforceCallingOrSelfPermission(
1272                android.Manifest.permission.ACCESS_NETWORK_STATE,
1273                "ConnectivityService");
1274    }
1275
1276    private void enforceChangePermission() {
1277        mContext.enforceCallingOrSelfPermission(
1278                android.Manifest.permission.CHANGE_NETWORK_STATE,
1279                "ConnectivityService");
1280    }
1281
1282    // TODO Make this a special check when it goes public
1283    private void enforceTetherChangePermission() {
1284        mContext.enforceCallingOrSelfPermission(
1285                android.Manifest.permission.CHANGE_NETWORK_STATE,
1286                "ConnectivityService");
1287    }
1288
1289    private void enforceTetherAccessPermission() {
1290        mContext.enforceCallingOrSelfPermission(
1291                android.Manifest.permission.ACCESS_NETWORK_STATE,
1292                "ConnectivityService");
1293    }
1294
1295    private void enforceConnectivityInternalPermission() {
1296        mContext.enforceCallingOrSelfPermission(
1297                android.Manifest.permission.CONNECTIVITY_INTERNAL,
1298                "ConnectivityService");
1299    }
1300
1301    /**
1302     * Handle a {@code DISCONNECTED} event. If this pertains to the non-active
1303     * network, we ignore it. If it is for the active network, we send out a
1304     * broadcast. But first, we check whether it might be possible to connect
1305     * to a different network.
1306     * @param info the {@code NetworkInfo} for the network
1307     */
1308    private void handleDisconnect(NetworkInfo info) {
1309
1310        int prevNetType = info.getType();
1311
1312        mNetTrackers[prevNetType].setTeardownRequested(false);
1313        /*
1314         * If the disconnected network is not the active one, then don't report
1315         * this as a loss of connectivity. What probably happened is that we're
1316         * getting the disconnect for a network that we explicitly disabled
1317         * in accordance with network preference policies.
1318         */
1319        if (!mNetConfigs[prevNetType].isDefault()) {
1320            List pids = mNetRequestersPids[prevNetType];
1321            for (int i = 0; i<pids.size(); i++) {
1322                Integer pid = (Integer)pids.get(i);
1323                // will remove them because the net's no longer connected
1324                // need to do this now as only now do we know the pids and
1325                // can properly null things that are no longer referenced.
1326                reassessPidDns(pid.intValue(), false);
1327            }
1328        }
1329
1330        Intent intent = new Intent(ConnectivityManager.CONNECTIVITY_ACTION);
1331        intent.putExtra(ConnectivityManager.EXTRA_NETWORK_INFO, info);
1332        if (info.isFailover()) {
1333            intent.putExtra(ConnectivityManager.EXTRA_IS_FAILOVER, true);
1334            info.setFailover(false);
1335        }
1336        if (info.getReason() != null) {
1337            intent.putExtra(ConnectivityManager.EXTRA_REASON, info.getReason());
1338        }
1339        if (info.getExtraInfo() != null) {
1340            intent.putExtra(ConnectivityManager.EXTRA_EXTRA_INFO,
1341                    info.getExtraInfo());
1342        }
1343
1344        if (mNetConfigs[prevNetType].isDefault()) {
1345            tryFailover(prevNetType);
1346            if (mActiveDefaultNetwork != -1) {
1347                NetworkInfo switchTo = mNetTrackers[mActiveDefaultNetwork].getNetworkInfo();
1348                intent.putExtra(ConnectivityManager.EXTRA_OTHER_NETWORK_INFO, switchTo);
1349            } else {
1350                mDefaultInetConditionPublished = 0; // we're not connected anymore
1351                intent.putExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, true);
1352            }
1353        }
1354        intent.putExtra(ConnectivityManager.EXTRA_INET_CONDITION, mDefaultInetConditionPublished);
1355
1356        // Reset interface if no other connections are using the same interface
1357        boolean doReset = true;
1358        LinkProperties linkProperties = mNetTrackers[prevNetType].getLinkProperties();
1359        if (linkProperties != null) {
1360            String oldIface = linkProperties.getInterfaceName();
1361            if (TextUtils.isEmpty(oldIface) == false) {
1362                for (NetworkStateTracker networkStateTracker : mNetTrackers) {
1363                    if (networkStateTracker == null) continue;
1364                    NetworkInfo networkInfo = networkStateTracker.getNetworkInfo();
1365                    if (networkInfo.isConnected() && networkInfo.getType() != prevNetType) {
1366                        LinkProperties l = networkStateTracker.getLinkProperties();
1367                        if (l == null) continue;
1368                        if (oldIface.equals(l.getInterfaceName())) {
1369                            doReset = false;
1370                            break;
1371                        }
1372                    }
1373                }
1374            }
1375        }
1376
1377        // do this before we broadcast the change
1378        handleConnectivityChange(prevNetType, doReset);
1379
1380        sendStickyBroadcast(intent);
1381        /*
1382         * If the failover network is already connected, then immediately send
1383         * out a followup broadcast indicating successful failover
1384         */
1385        if (mActiveDefaultNetwork != -1) {
1386            sendConnectedBroadcast(mNetTrackers[mActiveDefaultNetwork].getNetworkInfo());
1387        }
1388    }
1389
1390    private void tryFailover(int prevNetType) {
1391        /*
1392         * If this is a default network, check if other defaults are available.
1393         * Try to reconnect on all available and let them hash it out when
1394         * more than one connects.
1395         */
1396        if (mNetConfigs[prevNetType].isDefault()) {
1397            if (mActiveDefaultNetwork == prevNetType) {
1398                mActiveDefaultNetwork = -1;
1399            }
1400
1401            // don't signal a reconnect for anything lower or equal priority than our
1402            // current connected default
1403            // TODO - don't filter by priority now - nice optimization but risky
1404//            int currentPriority = -1;
1405//            if (mActiveDefaultNetwork != -1) {
1406//                currentPriority = mNetConfigs[mActiveDefaultNetwork].mPriority;
1407//            }
1408            for (int checkType=0; checkType <= ConnectivityManager.MAX_NETWORK_TYPE; checkType++) {
1409                if (checkType == prevNetType) continue;
1410                if (mNetConfigs[checkType] == null) continue;
1411                if (!mNetConfigs[checkType].isDefault()) continue;
1412
1413// Enabling the isAvailable() optimization caused mobile to not get
1414// selected if it was in the middle of error handling. Specifically
1415// a moble connection that took 30 seconds to complete the DEACTIVATE_DATA_CALL
1416// would not be available and we wouldn't get connected to anything.
1417// So removing the isAvailable() optimization below for now. TODO: This
1418// optimization should work and we need to investigate why it doesn't work.
1419// This could be related to how DEACTIVATE_DATA_CALL is reporting its
1420// complete before it is really complete.
1421//                if (!mNetTrackers[checkType].isAvailable()) continue;
1422
1423//                if (currentPriority >= mNetConfigs[checkType].mPriority) continue;
1424
1425                NetworkStateTracker checkTracker = mNetTrackers[checkType];
1426                NetworkInfo checkInfo = checkTracker.getNetworkInfo();
1427                if (!checkInfo.isConnectedOrConnecting() || checkTracker.isTeardownRequested()) {
1428                    checkInfo.setFailover(true);
1429                    checkTracker.reconnect();
1430                }
1431                if (DBG) log("Attempting to switch to " + checkInfo.getTypeName());
1432            }
1433        }
1434    }
1435
1436    private void sendConnectedBroadcast(NetworkInfo info) {
1437        sendGeneralBroadcast(info, ConnectivityManager.CONNECTIVITY_ACTION);
1438    }
1439
1440    private void sendInetConditionBroadcast(NetworkInfo info) {
1441        sendGeneralBroadcast(info, ConnectivityManager.INET_CONDITION_ACTION);
1442    }
1443
1444    private void sendGeneralBroadcast(NetworkInfo info, String bcastType) {
1445        Intent intent = new Intent(bcastType);
1446        intent.putExtra(ConnectivityManager.EXTRA_NETWORK_INFO, info);
1447        if (info.isFailover()) {
1448            intent.putExtra(ConnectivityManager.EXTRA_IS_FAILOVER, true);
1449            info.setFailover(false);
1450        }
1451        if (info.getReason() != null) {
1452            intent.putExtra(ConnectivityManager.EXTRA_REASON, info.getReason());
1453        }
1454        if (info.getExtraInfo() != null) {
1455            intent.putExtra(ConnectivityManager.EXTRA_EXTRA_INFO,
1456                    info.getExtraInfo());
1457        }
1458        intent.putExtra(ConnectivityManager.EXTRA_INET_CONDITION, mDefaultInetConditionPublished);
1459        sendStickyBroadcast(intent);
1460    }
1461
1462    /**
1463     * Called when an attempt to fail over to another network has failed.
1464     * @param info the {@link NetworkInfo} for the failed network
1465     */
1466    private void handleConnectionFailure(NetworkInfo info) {
1467        mNetTrackers[info.getType()].setTeardownRequested(false);
1468
1469        String reason = info.getReason();
1470        String extraInfo = info.getExtraInfo();
1471
1472        String reasonText;
1473        if (reason == null) {
1474            reasonText = ".";
1475        } else {
1476            reasonText = " (" + reason + ").";
1477        }
1478        loge("Attempt to connect to " + info.getTypeName() + " failed" + reasonText);
1479
1480        Intent intent = new Intent(ConnectivityManager.CONNECTIVITY_ACTION);
1481        intent.putExtra(ConnectivityManager.EXTRA_NETWORK_INFO, info);
1482        if (getActiveNetworkInfo() == null) {
1483            intent.putExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, true);
1484        }
1485        if (reason != null) {
1486            intent.putExtra(ConnectivityManager.EXTRA_REASON, reason);
1487        }
1488        if (extraInfo != null) {
1489            intent.putExtra(ConnectivityManager.EXTRA_EXTRA_INFO, extraInfo);
1490        }
1491        if (info.isFailover()) {
1492            intent.putExtra(ConnectivityManager.EXTRA_IS_FAILOVER, true);
1493            info.setFailover(false);
1494        }
1495
1496        if (mNetConfigs[info.getType()].isDefault()) {
1497            tryFailover(info.getType());
1498            if (mActiveDefaultNetwork != -1) {
1499                NetworkInfo switchTo = mNetTrackers[mActiveDefaultNetwork].getNetworkInfo();
1500                intent.putExtra(ConnectivityManager.EXTRA_OTHER_NETWORK_INFO, switchTo);
1501            } else {
1502                mDefaultInetConditionPublished = 0;
1503                intent.putExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, true);
1504            }
1505        }
1506
1507        intent.putExtra(ConnectivityManager.EXTRA_INET_CONDITION, mDefaultInetConditionPublished);
1508        sendStickyBroadcast(intent);
1509        /*
1510         * If the failover network is already connected, then immediately send
1511         * out a followup broadcast indicating successful failover
1512         */
1513        if (mActiveDefaultNetwork != -1) {
1514            sendConnectedBroadcast(mNetTrackers[mActiveDefaultNetwork].getNetworkInfo());
1515        }
1516    }
1517
1518    private void sendStickyBroadcast(Intent intent) {
1519        synchronized(this) {
1520            if (!mSystemReady) {
1521                mInitialBroadcast = new Intent(intent);
1522            }
1523            intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
1524            mContext.sendStickyBroadcast(intent);
1525        }
1526    }
1527
1528    void systemReady() {
1529        synchronized(this) {
1530            mSystemReady = true;
1531            if (mInitialBroadcast != null) {
1532                mContext.sendStickyBroadcast(mInitialBroadcast);
1533                mInitialBroadcast = null;
1534            }
1535        }
1536        // load the global proxy at startup
1537        mHandler.sendMessage(mHandler.obtainMessage(EVENT_APPLY_GLOBAL_HTTP_PROXY));
1538    }
1539
1540    private void handleConnect(NetworkInfo info) {
1541        int type = info.getType();
1542
1543        // snapshot isFailover, because sendConnectedBroadcast() resets it
1544        boolean isFailover = info.isFailover();
1545        NetworkStateTracker thisNet = mNetTrackers[type];
1546
1547        // if this is a default net and other default is running
1548        // kill the one not preferred
1549        if (mNetConfigs[type].isDefault()) {
1550            if (mActiveDefaultNetwork != -1 && mActiveDefaultNetwork != type) {
1551                if ((type != mNetworkPreference &&
1552                        mNetConfigs[mActiveDefaultNetwork].priority >
1553                        mNetConfigs[type].priority) ||
1554                        mNetworkPreference == mActiveDefaultNetwork) {
1555                        // don't accept this one
1556                        if (DBG) {
1557                            log("Not broadcasting CONNECT_ACTION " +
1558                                "to torn down network " + info.getTypeName());
1559                        }
1560                        teardown(thisNet);
1561                        return;
1562                } else {
1563                    // tear down the other
1564                    NetworkStateTracker otherNet =
1565                            mNetTrackers[mActiveDefaultNetwork];
1566                    if (DBG) {
1567                        log("Policy requires " + otherNet.getNetworkInfo().getTypeName() +
1568                            " teardown");
1569                    }
1570                    if (!teardown(otherNet)) {
1571                        loge("Network declined teardown request");
1572                        teardown(thisNet);
1573                        return;
1574                    }
1575                }
1576            }
1577            synchronized (ConnectivityService.this) {
1578                // have a new default network, release the transition wakelock in a second
1579                // if it's held.  The second pause is to allow apps to reconnect over the
1580                // new network
1581                if (mNetTransitionWakeLock.isHeld()) {
1582                    mHandler.sendMessageDelayed(mHandler.obtainMessage(
1583                            EVENT_CLEAR_NET_TRANSITION_WAKELOCK,
1584                            mNetTransitionWakeLockSerialNumber, 0),
1585                            1000);
1586                }
1587            }
1588            mActiveDefaultNetwork = type;
1589            // this will cause us to come up initially as unconnected and switching
1590            // to connected after our normal pause unless somebody reports us as reall
1591            // disconnected
1592            mDefaultInetConditionPublished = 0;
1593            mDefaultConnectionSequence++;
1594            mInetConditionChangeInFlight = false;
1595            // Don't do this - if we never sign in stay, grey
1596            //reportNetworkCondition(mActiveDefaultNetwork, 100);
1597        }
1598        thisNet.setTeardownRequested(false);
1599        updateNetworkSettings(thisNet);
1600        handleConnectivityChange(type, false);
1601        sendConnectedBroadcast(info);
1602    }
1603
1604    /**
1605     * After a change in the connectivity state of a network. We're mainly
1606     * concerned with making sure that the list of DNS servers is set up
1607     * according to which networks are connected, and ensuring that the
1608     * right routing table entries exist.
1609     */
1610    private void handleConnectivityChange(int netType, boolean doReset) {
1611        int resetMask = doReset ? NetworkUtils.RESET_ALL_ADDRESSES : 0;
1612
1613        /*
1614         * If a non-default network is enabled, add the host routes that
1615         * will allow it's DNS servers to be accessed.
1616         */
1617        handleDnsConfigurationChange(netType);
1618
1619        LinkProperties curLp = mCurrentLinkProperties[netType];
1620        LinkProperties newLp = null;
1621
1622        if (mNetTrackers[netType].getNetworkInfo().isConnected()) {
1623            newLp = mNetTrackers[netType].getLinkProperties();
1624            if (VDBG) {
1625                log("handleConnectivityChange: changed linkProperty[" + netType + "]:" +
1626                        " doReset=" + doReset + " resetMask=" + resetMask +
1627                        "\n   curLp=" + curLp +
1628                        "\n   newLp=" + newLp);
1629            }
1630
1631            if (curLp != null) {
1632                if (curLp.isIdenticalInterfaceName(newLp)) {
1633                    CompareResult<LinkAddress> car = curLp.compareAddresses(newLp);
1634                    if ((car.removed.size() != 0) || (car.added.size() != 0)) {
1635                        for (LinkAddress linkAddr : car.removed) {
1636                            if (linkAddr.getAddress() instanceof Inet4Address) {
1637                                resetMask |= NetworkUtils.RESET_IPV4_ADDRESSES;
1638                            }
1639                            if (linkAddr.getAddress() instanceof Inet6Address) {
1640                                resetMask |= NetworkUtils.RESET_IPV6_ADDRESSES;
1641                            }
1642                        }
1643                        if (DBG) {
1644                            log("handleConnectivityChange: addresses changed" +
1645                                    " linkProperty[" + netType + "]:" + " resetMask=" + resetMask +
1646                                    "\n   car=" + car);
1647                        }
1648                    } else {
1649                        if (DBG) {
1650                            log("handleConnectivityChange: address are the same reset per doReset" +
1651                                   " linkProperty[" + netType + "]:" +
1652                                   " resetMask=" + resetMask);
1653                        }
1654                    }
1655                } else {
1656                    resetMask = NetworkUtils.RESET_ALL_ADDRESSES;
1657                    log("handleConnectivityChange: interface not not equivalent reset both" +
1658                            " linkProperty[" + netType + "]:" +
1659                            " resetMask=" + resetMask);
1660                }
1661            }
1662            if (mNetConfigs[netType].isDefault()) {
1663                handleApplyDefaultProxy(netType);
1664            }
1665        } else {
1666            if (VDBG) {
1667                log("handleConnectivityChange: changed linkProperty[" + netType + "]:" +
1668                        " doReset=" + doReset + " resetMask=" + resetMask +
1669                        "\n  curLp=" + curLp +
1670                        "\n  newLp= null");
1671            }
1672        }
1673        mCurrentLinkProperties[netType] = newLp;
1674        updateRoutes(newLp, curLp, mNetConfigs[netType].isDefault());
1675
1676        if (doReset || resetMask != 0) {
1677            LinkProperties linkProperties = mNetTrackers[netType].getLinkProperties();
1678            if (linkProperties != null) {
1679                String iface = linkProperties.getInterfaceName();
1680                if (TextUtils.isEmpty(iface) == false) {
1681                    if (DBG) log("resetConnections(" + iface + ", " + resetMask + ")");
1682                    NetworkUtils.resetConnections(iface, resetMask);
1683                }
1684            }
1685        }
1686
1687        // TODO: Temporary notifying upstread change to Tethering.
1688        //       @see bug/4455071
1689        /** Notify TetheringService if interface name has been changed. */
1690        if (TextUtils.equals(mNetTrackers[netType].getNetworkInfo().getReason(),
1691                             Phone.REASON_LINK_PROPERTIES_CHANGED)) {
1692            if (isTetheringSupported()) {
1693                mTethering.handleTetherIfaceChange();
1694            }
1695        }
1696    }
1697
1698    /**
1699     * Add and remove routes using the old properties (null if not previously connected),
1700     * new properties (null if becoming disconnected).  May even be double null, which
1701     * is a noop.
1702     * Uses isLinkDefault to determine if default routes should be set or conversely if
1703     * host routes should be set to the dns servers
1704     */
1705    private void updateRoutes(LinkProperties newLp, LinkProperties curLp, boolean isLinkDefault) {
1706        Collection<RouteInfo> routesToAdd = null;
1707        CompareResult<InetAddress> dnsDiff = null;
1708
1709        if (curLp != null) {
1710            // check for the delta between the current set and the new
1711            CompareResult<RouteInfo> routeDiff = curLp.compareRoutes(newLp);
1712            dnsDiff = curLp.compareDnses(newLp);
1713
1714            for (RouteInfo r : routeDiff.removed) {
1715                if (isLinkDefault || ! r.isDefaultRoute()) {
1716                    removeRoute(curLp, r);
1717                }
1718            }
1719            routesToAdd = routeDiff.added;
1720        }
1721
1722        if (newLp != null) {
1723            // if we didn't get a diff from cur -> new, then just use the new
1724            if (routesToAdd == null) {
1725                routesToAdd = newLp.getRoutes();
1726            }
1727
1728            for (RouteInfo r :  routesToAdd) {
1729                if (isLinkDefault || ! r.isDefaultRoute()) {
1730                    addRoute(newLp, r);
1731                }
1732            }
1733        }
1734
1735        if (!isLinkDefault) {
1736            // handle DNS routes
1737            Collection<InetAddress> dnsToAdd = null;
1738            if (dnsDiff != null) {
1739                dnsToAdd = dnsDiff.added;
1740                for (InetAddress dnsAddress : dnsDiff.removed) {
1741                    removeRoute(curLp, RouteInfo.makeHostRoute(dnsAddress));
1742                }
1743            }
1744            if (newLp != null) {
1745                if (dnsToAdd == null) {
1746                    dnsToAdd = newLp.getDnses();
1747                }
1748                for(InetAddress dnsAddress : dnsToAdd) {
1749                    addRoute(newLp, RouteInfo.makeHostRoute(dnsAddress));
1750                }
1751            }
1752        }
1753    }
1754
1755
1756   /**
1757     * Reads the network specific TCP buffer sizes from SystemProperties
1758     * net.tcp.buffersize.[default|wifi|umts|edge|gprs] and set them for system
1759     * wide use
1760     */
1761   public void updateNetworkSettings(NetworkStateTracker nt) {
1762        String key = nt.getTcpBufferSizesPropName();
1763        String bufferSizes = SystemProperties.get(key);
1764
1765        if (bufferSizes.length() == 0) {
1766            loge(key + " not found in system properties. Using defaults");
1767
1768            // Setting to default values so we won't be stuck to previous values
1769            key = "net.tcp.buffersize.default";
1770            bufferSizes = SystemProperties.get(key);
1771        }
1772
1773        // Set values in kernel
1774        if (bufferSizes.length() != 0) {
1775            if (DBG) {
1776                log("Setting TCP values: [" + bufferSizes
1777                        + "] which comes from [" + key + "]");
1778            }
1779            setBufferSize(bufferSizes);
1780        }
1781    }
1782
1783   /**
1784     * Writes TCP buffer sizes to /sys/kernel/ipv4/tcp_[r/w]mem_[min/def/max]
1785     * which maps to /proc/sys/net/ipv4/tcp_rmem and tcpwmem
1786     *
1787     * @param bufferSizes in the format of "readMin, readInitial, readMax,
1788     *        writeMin, writeInitial, writeMax"
1789     */
1790    private void setBufferSize(String bufferSizes) {
1791        try {
1792            String[] values = bufferSizes.split(",");
1793
1794            if (values.length == 6) {
1795              final String prefix = "/sys/kernel/ipv4/tcp_";
1796                FileUtils.stringToFile(prefix + "rmem_min", values[0]);
1797                FileUtils.stringToFile(prefix + "rmem_def", values[1]);
1798                FileUtils.stringToFile(prefix + "rmem_max", values[2]);
1799                FileUtils.stringToFile(prefix + "wmem_min", values[3]);
1800                FileUtils.stringToFile(prefix + "wmem_def", values[4]);
1801                FileUtils.stringToFile(prefix + "wmem_max", values[5]);
1802            } else {
1803                loge("Invalid buffersize string: " + bufferSizes);
1804            }
1805        } catch (IOException e) {
1806            loge("Can't set tcp buffer sizes:" + e);
1807        }
1808    }
1809
1810    /**
1811     * Adjust the per-process dns entries (net.dns<x>.<pid>) based
1812     * on the highest priority active net which this process requested.
1813     * If there aren't any, clear it out
1814     */
1815    private void reassessPidDns(int myPid, boolean doBump)
1816    {
1817        if (DBG) log("reassessPidDns for pid " + myPid);
1818        for(int i : mPriorityList) {
1819            if (mNetConfigs[i].isDefault()) {
1820                continue;
1821            }
1822            NetworkStateTracker nt = mNetTrackers[i];
1823            if (nt.getNetworkInfo().isConnected() &&
1824                    !nt.isTeardownRequested()) {
1825                LinkProperties p = nt.getLinkProperties();
1826                if (p == null) continue;
1827                List pids = mNetRequestersPids[i];
1828                for (int j=0; j<pids.size(); j++) {
1829                    Integer pid = (Integer)pids.get(j);
1830                    if (pid.intValue() == myPid) {
1831                        Collection<InetAddress> dnses = p.getDnses();
1832                        writePidDns(dnses, myPid);
1833                        if (doBump) {
1834                            bumpDns();
1835                        }
1836                        return;
1837                    }
1838                }
1839           }
1840        }
1841        // nothing found - delete
1842        for (int i = 1; ; i++) {
1843            String prop = "net.dns" + i + "." + myPid;
1844            if (SystemProperties.get(prop).length() == 0) {
1845                if (doBump) {
1846                    bumpDns();
1847                }
1848                return;
1849            }
1850            SystemProperties.set(prop, "");
1851        }
1852    }
1853
1854    // return true if results in a change
1855    private boolean writePidDns(Collection <InetAddress> dnses, int pid) {
1856        int j = 1;
1857        boolean changed = false;
1858        for (InetAddress dns : dnses) {
1859            String dnsString = dns.getHostAddress();
1860            if (changed || !dnsString.equals(SystemProperties.get("net.dns" + j + "." + pid))) {
1861                changed = true;
1862                SystemProperties.set("net.dns" + j++ + "." + pid, dns.getHostAddress());
1863            }
1864        }
1865        return changed;
1866    }
1867
1868    private void bumpDns() {
1869        /*
1870         * Bump the property that tells the name resolver library to reread
1871         * the DNS server list from the properties.
1872         */
1873        String propVal = SystemProperties.get("net.dnschange");
1874        int n = 0;
1875        if (propVal.length() != 0) {
1876            try {
1877                n = Integer.parseInt(propVal);
1878            } catch (NumberFormatException e) {}
1879        }
1880        SystemProperties.set("net.dnschange", "" + (n+1));
1881        /*
1882         * Tell the VMs to toss their DNS caches
1883         */
1884        Intent intent = new Intent(Intent.ACTION_CLEAR_DNS_CACHE);
1885        intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
1886        /*
1887         * Connectivity events can happen before boot has completed ...
1888         */
1889        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
1890        mContext.sendBroadcast(intent);
1891    }
1892
1893    private void handleDnsConfigurationChange(int netType) {
1894        // add default net's dns entries
1895        NetworkStateTracker nt = mNetTrackers[netType];
1896        if (nt != null && nt.getNetworkInfo().isConnected() && !nt.isTeardownRequested()) {
1897            LinkProperties p = nt.getLinkProperties();
1898            if (p == null) return;
1899            Collection<InetAddress> dnses = p.getDnses();
1900            boolean changed = false;
1901            if (mNetConfigs[netType].isDefault()) {
1902                int j = 1;
1903                if (dnses.size() == 0 && mDefaultDns != null) {
1904                    String dnsString = mDefaultDns.getHostAddress();
1905                    if (!dnsString.equals(SystemProperties.get("net.dns1"))) {
1906                        if (DBG) {
1907                            log("no dns provided - using " + dnsString);
1908                        }
1909                        changed = true;
1910                        SystemProperties.set("net.dns1", dnsString);
1911                    }
1912                    j++;
1913                } else {
1914                    for (InetAddress dns : dnses) {
1915                        String dnsString = dns.getHostAddress();
1916                        if (!changed && dnsString.equals(SystemProperties.get("net.dns" + j))) {
1917                            j++;
1918                            continue;
1919                        }
1920                        if (DBG) {
1921                            log("adding dns " + dns + " for " +
1922                                    nt.getNetworkInfo().getTypeName());
1923                        }
1924                        changed = true;
1925                        SystemProperties.set("net.dns" + j++, dnsString);
1926                    }
1927                }
1928                for (int k=j ; k<mNumDnsEntries; k++) {
1929                    if (changed || !TextUtils.isEmpty(SystemProperties.get("net.dns" + k))) {
1930                        if (DBG) log("erasing net.dns" + k);
1931                        changed = true;
1932                        SystemProperties.set("net.dns" + k, "");
1933                    }
1934                }
1935                mNumDnsEntries = j;
1936            } else {
1937                // set per-pid dns for attached secondary nets
1938                List pids = mNetRequestersPids[netType];
1939                for (int y=0; y< pids.size(); y++) {
1940                    Integer pid = (Integer)pids.get(y);
1941                    changed = writePidDns(dnses, pid.intValue());
1942                }
1943            }
1944            if (changed) bumpDns();
1945        }
1946    }
1947
1948    private int getRestoreDefaultNetworkDelay(int networkType) {
1949        String restoreDefaultNetworkDelayStr = SystemProperties.get(
1950                NETWORK_RESTORE_DELAY_PROP_NAME);
1951        if(restoreDefaultNetworkDelayStr != null &&
1952                restoreDefaultNetworkDelayStr.length() != 0) {
1953            try {
1954                return Integer.valueOf(restoreDefaultNetworkDelayStr);
1955            } catch (NumberFormatException e) {
1956            }
1957        }
1958        // if the system property isn't set, use the value for the apn type
1959        int ret = RESTORE_DEFAULT_NETWORK_DELAY;
1960
1961        if ((networkType <= ConnectivityManager.MAX_NETWORK_TYPE) &&
1962                (mNetConfigs[networkType] != null)) {
1963            ret = mNetConfigs[networkType].restoreTime;
1964        }
1965        return ret;
1966    }
1967
1968    @Override
1969    protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1970        if (mContext.checkCallingOrSelfPermission(
1971                android.Manifest.permission.DUMP)
1972                != PackageManager.PERMISSION_GRANTED) {
1973            pw.println("Permission Denial: can't dump ConnectivityService " +
1974                    "from from pid=" + Binder.getCallingPid() + ", uid=" +
1975                    Binder.getCallingUid());
1976            return;
1977        }
1978        pw.println();
1979        for (NetworkStateTracker nst : mNetTrackers) {
1980            if (nst != null) {
1981                if (nst.getNetworkInfo().isConnected()) {
1982                    pw.println("Active network: " + nst.getNetworkInfo().
1983                            getTypeName());
1984                }
1985                pw.println(nst.getNetworkInfo());
1986                pw.println(nst);
1987                pw.println();
1988            }
1989        }
1990
1991        pw.println("Network Requester Pids:");
1992        for (int net : mPriorityList) {
1993            String pidString = net + ": ";
1994            for (Object pid : mNetRequestersPids[net]) {
1995                pidString = pidString + pid.toString() + ", ";
1996            }
1997            pw.println(pidString);
1998        }
1999        pw.println();
2000
2001        pw.println("FeatureUsers:");
2002        for (Object requester : mFeatureUsers) {
2003            pw.println(requester.toString());
2004        }
2005        pw.println();
2006
2007        synchronized (this) {
2008            pw.println("NetworkTranstionWakeLock is currently " +
2009                    (mNetTransitionWakeLock.isHeld() ? "" : "not ") + "held.");
2010            pw.println("It was last requested for "+mNetTransitionWakeLockCausedBy);
2011        }
2012        pw.println();
2013
2014        mTethering.dump(fd, pw, args);
2015
2016        if (mInetLog != null) {
2017            pw.println();
2018            pw.println("Inet condition reports:");
2019            for(int i = 0; i < mInetLog.size(); i++) {
2020                pw.println(mInetLog.get(i));
2021            }
2022        }
2023    }
2024
2025    // must be stateless - things change under us.
2026    private class MyHandler extends Handler {
2027        public MyHandler(Looper looper) {
2028            super(looper);
2029        }
2030
2031        @Override
2032        public void handleMessage(Message msg) {
2033            NetworkInfo info;
2034            switch (msg.what) {
2035                case NetworkStateTracker.EVENT_STATE_CHANGED:
2036                    info = (NetworkInfo) msg.obj;
2037                    int type = info.getType();
2038                    NetworkInfo.State state = info.getState();
2039
2040                    if (DBG) log("ConnectivityChange for " +
2041                            info.getTypeName() + ": " +
2042                            state + "/" + info.getDetailedState());
2043
2044                    // Connectivity state changed:
2045                    // [31-13] Reserved for future use
2046                    // [12-9] Network subtype (for mobile network, as defined
2047                    //         by TelephonyManager)
2048                    // [8-3] Detailed state ordinal (as defined by
2049                    //         NetworkInfo.DetailedState)
2050                    // [2-0] Network type (as defined by ConnectivityManager)
2051                    int eventLogParam = (info.getType() & 0x7) |
2052                            ((info.getDetailedState().ordinal() & 0x3f) << 3) |
2053                            (info.getSubtype() << 9);
2054                    EventLog.writeEvent(EventLogTags.CONNECTIVITY_STATE_CHANGED,
2055                            eventLogParam);
2056
2057                    if (info.getDetailedState() ==
2058                            NetworkInfo.DetailedState.FAILED) {
2059                        handleConnectionFailure(info);
2060                    } else if (state == NetworkInfo.State.DISCONNECTED) {
2061                        handleDisconnect(info);
2062                    } else if (state == NetworkInfo.State.SUSPENDED) {
2063                        // TODO: need to think this over.
2064                        // the logic here is, handle SUSPENDED the same as
2065                        // DISCONNECTED. The only difference being we are
2066                        // broadcasting an intent with NetworkInfo that's
2067                        // suspended. This allows the applications an
2068                        // opportunity to handle DISCONNECTED and SUSPENDED
2069                        // differently, or not.
2070                        handleDisconnect(info);
2071                    } else if (state == NetworkInfo.State.CONNECTED) {
2072                        handleConnect(info);
2073                    }
2074                    break;
2075                case NetworkStateTracker.EVENT_CONFIGURATION_CHANGED:
2076                    info = (NetworkInfo) msg.obj;
2077                    // TODO: Temporary allowing network configuration
2078                    //       change not resetting sockets.
2079                    //       @see bug/4455071
2080                    handleConnectivityChange(info.getType(), false);
2081                    break;
2082                case EVENT_CLEAR_NET_TRANSITION_WAKELOCK:
2083                    String causedBy = null;
2084                    synchronized (ConnectivityService.this) {
2085                        if (msg.arg1 == mNetTransitionWakeLockSerialNumber &&
2086                                mNetTransitionWakeLock.isHeld()) {
2087                            mNetTransitionWakeLock.release();
2088                            causedBy = mNetTransitionWakeLockCausedBy;
2089                        }
2090                    }
2091                    if (causedBy != null) {
2092                        log("NetTransition Wakelock for " + causedBy + " released by timeout");
2093                    }
2094                    break;
2095                case EVENT_RESTORE_DEFAULT_NETWORK:
2096                    FeatureUser u = (FeatureUser)msg.obj;
2097                    u.expire();
2098                    break;
2099                case EVENT_INET_CONDITION_CHANGE:
2100                {
2101                    int netType = msg.arg1;
2102                    int condition = msg.arg2;
2103                    handleInetConditionChange(netType, condition);
2104                    break;
2105                }
2106                case EVENT_INET_CONDITION_HOLD_END:
2107                {
2108                    int netType = msg.arg1;
2109                    int sequence = msg.arg2;
2110                    handleInetConditionHoldEnd(netType, sequence);
2111                    break;
2112                }
2113                case EVENT_SET_NETWORK_PREFERENCE:
2114                {
2115                    int preference = msg.arg1;
2116                    handleSetNetworkPreference(preference);
2117                    break;
2118                }
2119                case EVENT_SET_BACKGROUND_DATA:
2120                {
2121                    boolean enabled = (msg.arg1 == ENABLED);
2122                    handleSetBackgroundData(enabled);
2123                    break;
2124                }
2125                case EVENT_SET_MOBILE_DATA:
2126                {
2127                    boolean enabled = (msg.arg1 == ENABLED);
2128                    handleSetMobileData(enabled);
2129                    break;
2130                }
2131                case EVENT_APPLY_GLOBAL_HTTP_PROXY:
2132                {
2133                    handleDeprecatedGlobalHttpProxy();
2134                    break;
2135                }
2136                case EVENT_SET_DEPENDENCY_MET:
2137                {
2138                    boolean met = (msg.arg1 == ENABLED);
2139                    handleSetDependencyMet(msg.arg2, met);
2140                    break;
2141                }
2142            }
2143        }
2144    }
2145
2146    // javadoc from interface
2147    public int tether(String iface) {
2148        enforceTetherChangePermission();
2149
2150        if (isTetheringSupported()) {
2151            return mTethering.tether(iface);
2152        } else {
2153            return ConnectivityManager.TETHER_ERROR_UNSUPPORTED;
2154        }
2155    }
2156
2157    // javadoc from interface
2158    public int untether(String iface) {
2159        enforceTetherChangePermission();
2160
2161        if (isTetheringSupported()) {
2162            return mTethering.untether(iface);
2163        } else {
2164            return ConnectivityManager.TETHER_ERROR_UNSUPPORTED;
2165        }
2166    }
2167
2168    // javadoc from interface
2169    public int getLastTetherError(String iface) {
2170        enforceTetherAccessPermission();
2171
2172        if (isTetheringSupported()) {
2173            return mTethering.getLastTetherError(iface);
2174        } else {
2175            return ConnectivityManager.TETHER_ERROR_UNSUPPORTED;
2176        }
2177    }
2178
2179    // TODO - proper iface API for selection by property, inspection, etc
2180    public String[] getTetherableUsbRegexs() {
2181        enforceTetherAccessPermission();
2182        if (isTetheringSupported()) {
2183            return mTethering.getTetherableUsbRegexs();
2184        } else {
2185            return new String[0];
2186        }
2187    }
2188
2189    public String[] getTetherableWifiRegexs() {
2190        enforceTetherAccessPermission();
2191        if (isTetheringSupported()) {
2192            return mTethering.getTetherableWifiRegexs();
2193        } else {
2194            return new String[0];
2195        }
2196    }
2197
2198    public String[] getTetherableBluetoothRegexs() {
2199        enforceTetherAccessPermission();
2200        if (isTetheringSupported()) {
2201            return mTethering.getTetherableBluetoothRegexs();
2202        } else {
2203            return new String[0];
2204        }
2205    }
2206
2207    // TODO - move iface listing, queries, etc to new module
2208    // javadoc from interface
2209    public String[] getTetherableIfaces() {
2210        enforceTetherAccessPermission();
2211        return mTethering.getTetherableIfaces();
2212    }
2213
2214    public String[] getTetheredIfaces() {
2215        enforceTetherAccessPermission();
2216        return mTethering.getTetheredIfaces();
2217    }
2218
2219    public String[] getTetheringErroredIfaces() {
2220        enforceTetherAccessPermission();
2221        return mTethering.getErroredIfaces();
2222    }
2223
2224    // if ro.tether.denied = true we default to no tethering
2225    // gservices could set the secure setting to 1 though to enable it on a build where it
2226    // had previously been turned off.
2227    public boolean isTetheringSupported() {
2228        enforceTetherAccessPermission();
2229        int defaultVal = (SystemProperties.get("ro.tether.denied").equals("true") ? 0 : 1);
2230        boolean tetherEnabledInSettings = (Settings.Secure.getInt(mContext.getContentResolver(),
2231                Settings.Secure.TETHER_SUPPORTED, defaultVal) != 0);
2232        return tetherEnabledInSettings && mTetheringConfigValid;
2233    }
2234
2235    // An API NetworkStateTrackers can call when they lose their network.
2236    // This will automatically be cleared after X seconds or a network becomes CONNECTED,
2237    // whichever happens first.  The timer is started by the first caller and not
2238    // restarted by subsequent callers.
2239    public void requestNetworkTransitionWakelock(String forWhom) {
2240        enforceConnectivityInternalPermission();
2241        synchronized (this) {
2242            if (mNetTransitionWakeLock.isHeld()) return;
2243            mNetTransitionWakeLockSerialNumber++;
2244            mNetTransitionWakeLock.acquire();
2245            mNetTransitionWakeLockCausedBy = forWhom;
2246        }
2247        mHandler.sendMessageDelayed(mHandler.obtainMessage(
2248                EVENT_CLEAR_NET_TRANSITION_WAKELOCK,
2249                mNetTransitionWakeLockSerialNumber, 0),
2250                mNetTransitionWakeLockTimeout);
2251        return;
2252    }
2253
2254    // 100 percent is full good, 0 is full bad.
2255    public void reportInetCondition(int networkType, int percentage) {
2256        if (DBG) log("reportNetworkCondition(" + networkType + ", " + percentage + ")");
2257        mContext.enforceCallingOrSelfPermission(
2258                android.Manifest.permission.STATUS_BAR,
2259                "ConnectivityService");
2260
2261        if (DBG) {
2262            int pid = getCallingPid();
2263            int uid = getCallingUid();
2264            String s = pid + "(" + uid + ") reports inet is " +
2265                (percentage > 50 ? "connected" : "disconnected") + " (" + percentage + ") on " +
2266                "network Type " + networkType + " at " + GregorianCalendar.getInstance().getTime();
2267            mInetLog.add(s);
2268            while(mInetLog.size() > INET_CONDITION_LOG_MAX_SIZE) {
2269                mInetLog.remove(0);
2270            }
2271        }
2272        mHandler.sendMessage(mHandler.obtainMessage(
2273            EVENT_INET_CONDITION_CHANGE, networkType, percentage));
2274    }
2275
2276    private void handleInetConditionChange(int netType, int condition) {
2277        if (DBG) {
2278            log("Inet connectivity change, net=" +
2279                    netType + ", condition=" + condition +
2280                    ",mActiveDefaultNetwork=" + mActiveDefaultNetwork);
2281        }
2282        if (mActiveDefaultNetwork == -1) {
2283            if (DBG) log("no active default network - aborting");
2284            return;
2285        }
2286        if (mActiveDefaultNetwork != netType) {
2287            if (DBG) log("given net not default - aborting");
2288            return;
2289        }
2290        mDefaultInetCondition = condition;
2291        int delay;
2292        if (mInetConditionChangeInFlight == false) {
2293            if (DBG) log("starting a change hold");
2294            // setup a new hold to debounce this
2295            if (mDefaultInetCondition > 50) {
2296                delay = Settings.Secure.getInt(mContext.getContentResolver(),
2297                        Settings.Secure.INET_CONDITION_DEBOUNCE_UP_DELAY, 500);
2298            } else {
2299                delay = Settings.Secure.getInt(mContext.getContentResolver(),
2300                Settings.Secure.INET_CONDITION_DEBOUNCE_DOWN_DELAY, 3000);
2301            }
2302            mInetConditionChangeInFlight = true;
2303            mHandler.sendMessageDelayed(mHandler.obtainMessage(EVENT_INET_CONDITION_HOLD_END,
2304                    mActiveDefaultNetwork, mDefaultConnectionSequence), delay);
2305        } else {
2306            // we've set the new condition, when this hold ends that will get
2307            // picked up
2308            if (DBG) log("currently in hold - not setting new end evt");
2309        }
2310    }
2311
2312    private void handleInetConditionHoldEnd(int netType, int sequence) {
2313        if (DBG) {
2314            log("Inet hold end, net=" + netType +
2315                    ", condition =" + mDefaultInetCondition +
2316                    ", published condition =" + mDefaultInetConditionPublished);
2317        }
2318        mInetConditionChangeInFlight = false;
2319
2320        if (mActiveDefaultNetwork == -1) {
2321            if (DBG) log("no active default network - aborting");
2322            return;
2323        }
2324        if (mDefaultConnectionSequence != sequence) {
2325            if (DBG) log("event hold for obsolete network - aborting");
2326            return;
2327        }
2328        if (mDefaultInetConditionPublished == mDefaultInetCondition) {
2329            if (DBG) log("no change in condition - aborting");
2330            return;
2331        }
2332        NetworkInfo networkInfo = mNetTrackers[mActiveDefaultNetwork].getNetworkInfo();
2333        if (networkInfo.isConnected() == false) {
2334            if (DBG) log("default network not connected - aborting");
2335            return;
2336        }
2337        mDefaultInetConditionPublished = mDefaultInetCondition;
2338        sendInetConditionBroadcast(networkInfo);
2339        return;
2340    }
2341
2342    public synchronized ProxyProperties getProxy() {
2343        if (mGlobalProxy != null) return mGlobalProxy;
2344        if (mDefaultProxy != null) return mDefaultProxy;
2345        return null;
2346    }
2347
2348    public void setGlobalProxy(ProxyProperties proxyProperties) {
2349        enforceChangePermission();
2350        synchronized (mGlobalProxyLock) {
2351            if (proxyProperties == mGlobalProxy) return;
2352            if (proxyProperties != null && proxyProperties.equals(mGlobalProxy)) return;
2353            if (mGlobalProxy != null && mGlobalProxy.equals(proxyProperties)) return;
2354
2355            String host = "";
2356            int port = 0;
2357            String exclList = "";
2358            if (proxyProperties != null && !TextUtils.isEmpty(proxyProperties.getHost())) {
2359                mGlobalProxy = new ProxyProperties(proxyProperties);
2360                host = mGlobalProxy.getHost();
2361                port = mGlobalProxy.getPort();
2362                exclList = mGlobalProxy.getExclusionList();
2363            } else {
2364                mGlobalProxy = null;
2365            }
2366            ContentResolver res = mContext.getContentResolver();
2367            Settings.Secure.putString(res, Settings.Secure.GLOBAL_HTTP_PROXY_HOST, host);
2368            Settings.Secure.putInt(res, Settings.Secure.GLOBAL_HTTP_PROXY_PORT, port);
2369            Settings.Secure.putString(res, Settings.Secure.GLOBAL_HTTP_PROXY_EXCLUSION_LIST,
2370                    exclList);
2371        }
2372
2373        if (mGlobalProxy == null) {
2374            proxyProperties = mDefaultProxy;
2375        }
2376        sendProxyBroadcast(proxyProperties);
2377    }
2378
2379    private void loadGlobalProxy() {
2380        ContentResolver res = mContext.getContentResolver();
2381        String host = Settings.Secure.getString(res, Settings.Secure.GLOBAL_HTTP_PROXY_HOST);
2382        int port = Settings.Secure.getInt(res, Settings.Secure.GLOBAL_HTTP_PROXY_PORT, 0);
2383        String exclList = Settings.Secure.getString(res,
2384                Settings.Secure.GLOBAL_HTTP_PROXY_EXCLUSION_LIST);
2385        if (!TextUtils.isEmpty(host)) {
2386            ProxyProperties proxyProperties = new ProxyProperties(host, port, exclList);
2387            synchronized (mGlobalProxyLock) {
2388                mGlobalProxy = proxyProperties;
2389            }
2390        }
2391    }
2392
2393    public ProxyProperties getGlobalProxy() {
2394        synchronized (mGlobalProxyLock) {
2395            return mGlobalProxy;
2396        }
2397    }
2398
2399    private void handleApplyDefaultProxy(int type) {
2400        // check if new default - push it out to all VM if so
2401        ProxyProperties proxy = mNetTrackers[type].getLinkProperties().getHttpProxy();
2402        synchronized (this) {
2403            if (mDefaultProxy != null && mDefaultProxy.equals(proxy)) return;
2404            if (mDefaultProxy == proxy) return;
2405            if (!TextUtils.isEmpty(proxy.getHost())) {
2406                mDefaultProxy = proxy;
2407            } else {
2408                mDefaultProxy = null;
2409            }
2410        }
2411        if (DBG) log("changing default proxy to " + proxy);
2412        if ((proxy == null && mGlobalProxy == null) || proxy.equals(mGlobalProxy)) return;
2413        if (mGlobalProxy != null) return;
2414        sendProxyBroadcast(proxy);
2415    }
2416
2417    private void handleDeprecatedGlobalHttpProxy() {
2418        String proxy = Settings.Secure.getString(mContext.getContentResolver(),
2419                Settings.Secure.HTTP_PROXY);
2420        if (!TextUtils.isEmpty(proxy)) {
2421            String data[] = proxy.split(":");
2422            String proxyHost =  data[0];
2423            int proxyPort = 8080;
2424            if (data.length > 1) {
2425                try {
2426                    proxyPort = Integer.parseInt(data[1]);
2427                } catch (NumberFormatException e) {
2428                    return;
2429                }
2430            }
2431            ProxyProperties p = new ProxyProperties(data[0], proxyPort, "");
2432            setGlobalProxy(p);
2433        }
2434    }
2435
2436    private void sendProxyBroadcast(ProxyProperties proxy) {
2437        if (proxy == null) proxy = new ProxyProperties("", 0, "");
2438        log("sending Proxy Broadcast for " + proxy);
2439        Intent intent = new Intent(Proxy.PROXY_CHANGE_ACTION);
2440        intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING |
2441            Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
2442        intent.putExtra(Proxy.EXTRA_PROXY_INFO, proxy);
2443        mContext.sendStickyBroadcast(intent);
2444    }
2445
2446    private static class SettingsObserver extends ContentObserver {
2447        private int mWhat;
2448        private Handler mHandler;
2449        SettingsObserver(Handler handler, int what) {
2450            super(handler);
2451            mHandler = handler;
2452            mWhat = what;
2453        }
2454
2455        void observe(Context context) {
2456            ContentResolver resolver = context.getContentResolver();
2457            resolver.registerContentObserver(Settings.Secure.getUriFor(
2458                    Settings.Secure.HTTP_PROXY), false, this);
2459        }
2460
2461        @Override
2462        public void onChange(boolean selfChange) {
2463            mHandler.obtainMessage(mWhat).sendToTarget();
2464        }
2465    }
2466
2467    private void log(String s) {
2468        Slog.d(TAG, s);
2469    }
2470
2471    private void loge(String s) {
2472        Slog.e(TAG, s);
2473    }
2474
2475    int convertFeatureToNetworkType(String feature){
2476        int networkType = -1;
2477        if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_MMS)) {
2478            networkType = ConnectivityManager.TYPE_MOBILE_MMS;
2479        } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_SUPL)) {
2480            networkType = ConnectivityManager.TYPE_MOBILE_SUPL;
2481        } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_DUN) ||
2482                TextUtils.equals(feature, Phone.FEATURE_ENABLE_DUN_ALWAYS)) {
2483            networkType = ConnectivityManager.TYPE_MOBILE_DUN;
2484        } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_HIPRI)) {
2485            networkType = ConnectivityManager.TYPE_MOBILE_HIPRI;
2486        } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_FOTA)) {
2487            networkType = ConnectivityManager.TYPE_MOBILE_FOTA;
2488        } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_IMS)) {
2489            networkType = ConnectivityManager.TYPE_MOBILE_IMS;
2490        } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_CBS)) {
2491            networkType = ConnectivityManager.TYPE_MOBILE_CBS;
2492        }
2493        return networkType;
2494    }
2495
2496    private static <T> T checkNotNull(T value, String message) {
2497        if (value == null) {
2498            throw new NullPointerException(message);
2499        }
2500        return value;
2501    }
2502
2503    /**
2504     * Protect a socket from VPN routing rules. This method is used by
2505     * VpnBuilder and not available in ConnectivityManager. Permissions
2506     * are checked in Vpn class.
2507     * @hide
2508     */
2509    @Override
2510    public boolean protectVpn(ParcelFileDescriptor socket) {
2511        try {
2512            int type = mActiveDefaultNetwork;
2513            if (ConnectivityManager.isNetworkTypeValid(type)) {
2514                mVpn.protect(socket, mNetTrackers[type].getLinkProperties().getInterfaceName());
2515                return true;
2516            }
2517        } catch (Exception e) {
2518            // ignore
2519        } finally {
2520            try {
2521                socket.close();
2522            } catch (Exception e) {
2523                // ignore
2524            }
2525        }
2526        return false;
2527    }
2528
2529    /**
2530     * Prepare for a VPN application. This method is used by VpnDialogs
2531     * and not available in ConnectivityManager. Permissions are checked
2532     * in Vpn class.
2533     * @hide
2534     */
2535    @Override
2536    public boolean prepareVpn(String oldPackage, String newPackage) {
2537        return mVpn.prepare(oldPackage, newPackage);
2538    }
2539
2540    /**
2541     * Configure a TUN interface and return its file descriptor. Parameters
2542     * are encoded and opaque to this class. This method is used by VpnBuilder
2543     * and not available in ConnectivityManager. Permissions are checked in
2544     * Vpn class.
2545     * @hide
2546     */
2547    @Override
2548    public ParcelFileDescriptor establishVpn(VpnConfig config) {
2549        return mVpn.establish(config);
2550    }
2551
2552    /**
2553     * Start legacy VPN and return an intent to VpnDialogs. This method is
2554     * used by VpnSettings and not available in ConnectivityManager.
2555     * Permissions are checked in Vpn class.
2556     * @hide
2557     */
2558    @Override
2559    public void startLegacyVpn(VpnConfig config, String[] racoon, String[] mtpd) {
2560        mVpn.startLegacyVpn(config, racoon, mtpd);
2561    }
2562
2563    /**
2564     * Return the information of the ongoing legacy VPN. This method is used
2565     * by VpnSettings and not available in ConnectivityManager. Permissions
2566     * are checked in Vpn class.
2567     * @hide
2568     */
2569    @Override
2570    public LegacyVpnInfo getLegacyVpnInfo() {
2571        return mVpn.getLegacyVpnInfo();
2572    }
2573
2574    /**
2575     * Callback for VPN subsystem. Currently VPN is not adapted to the service
2576     * through NetworkStateTracker since it works differently. For example, it
2577     * needs to override DNS servers but never takes the default routes. It
2578     * relies on another data network, and it could keep existing connections
2579     * alive after reconnecting, switching between networks, or even resuming
2580     * from deep sleep. Calls from applications should be done synchronously
2581     * to avoid race conditions. As these are all hidden APIs, refactoring can
2582     * be done whenever a better abstraction is developed.
2583     */
2584    public class VpnCallback {
2585
2586        private VpnCallback() {
2587        }
2588
2589        public synchronized void override(List<String> dnsServers, List<String> searchDomains) {
2590            // TODO: override DNS servers and http proxy.
2591        }
2592
2593        public synchronized void restore() {
2594            // TODO: restore VPN changes.
2595        }
2596    }
2597}
2598