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