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