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