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