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