ConnectivityService.java revision 2771181c9b82b6b41da7ebd47fbe1baf8791c8ac
1/*
2 * Copyright (C) 2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.server;
18
19import static android.Manifest.permission.MANAGE_NETWORK_POLICY;
20import static android.Manifest.permission.RECEIVE_DATA_ACTIVITY_CHANGE;
21import static android.net.ConnectivityManager.CONNECTIVITY_ACTION;
22import static android.net.ConnectivityManager.CONNECTIVITY_ACTION_IMMEDIATE;
23import static android.net.ConnectivityManager.TYPE_BLUETOOTH;
24import static android.net.ConnectivityManager.TYPE_DUMMY;
25import static android.net.ConnectivityManager.TYPE_MOBILE;
26import static android.net.ConnectivityManager.TYPE_MOBILE_MMS;
27import static android.net.ConnectivityManager.TYPE_MOBILE_SUPL;
28import static android.net.ConnectivityManager.TYPE_MOBILE_DUN;
29import static android.net.ConnectivityManager.TYPE_MOBILE_FOTA;
30import static android.net.ConnectivityManager.TYPE_MOBILE_IMS;
31import static android.net.ConnectivityManager.TYPE_MOBILE_CBS;
32import static android.net.ConnectivityManager.TYPE_MOBILE_IA;
33import static android.net.ConnectivityManager.TYPE_MOBILE_HIPRI;
34import static android.net.ConnectivityManager.TYPE_NONE;
35import static android.net.ConnectivityManager.TYPE_WIFI;
36import static android.net.ConnectivityManager.TYPE_WIMAX;
37import static android.net.ConnectivityManager.TYPE_PROXY;
38import static android.net.ConnectivityManager.getNetworkTypeName;
39import static android.net.ConnectivityManager.isNetworkTypeValid;
40import static android.net.NetworkPolicyManager.RULE_ALLOW_ALL;
41import static android.net.NetworkPolicyManager.RULE_REJECT_METERED;
42
43import android.app.AlarmManager;
44import android.app.AppOpsManager;
45import android.app.Notification;
46import android.app.NotificationManager;
47import android.app.PendingIntent;
48import android.content.ActivityNotFoundException;
49import android.content.BroadcastReceiver;
50import android.content.ContentResolver;
51import android.content.Context;
52import android.content.ContextWrapper;
53import android.content.Intent;
54import android.content.IntentFilter;
55import android.content.pm.ApplicationInfo;
56import android.content.pm.PackageManager;
57import android.content.pm.PackageManager.NameNotFoundException;
58import android.content.res.Configuration;
59import android.content.res.Resources;
60import android.database.ContentObserver;
61import android.net.CaptivePortalTracker;
62import android.net.ConnectivityManager;
63import android.net.DummyDataStateTracker;
64import android.net.IConnectivityManager;
65import android.net.INetworkManagementEventObserver;
66import android.net.INetworkPolicyListener;
67import android.net.INetworkPolicyManager;
68import android.net.INetworkStatsService;
69import android.net.LinkAddress;
70import android.net.LinkProperties;
71import android.net.LinkProperties.CompareResult;
72import android.net.LinkQualityInfo;
73import android.net.MobileDataStateTracker;
74import android.net.Network;
75import android.net.NetworkAgent;
76import android.net.NetworkCapabilities;
77import android.net.NetworkConfig;
78import android.net.NetworkInfo;
79import android.net.NetworkInfo.DetailedState;
80import android.net.NetworkFactory;
81import android.net.NetworkQuotaInfo;
82import android.net.NetworkRequest;
83import android.net.NetworkState;
84import android.net.NetworkStateTracker;
85import android.net.NetworkUtils;
86import android.net.Proxy;
87import android.net.ProxyDataTracker;
88import android.net.ProxyInfo;
89import android.net.RouteInfo;
90import android.net.SamplingDataTracker;
91import android.net.Uri;
92import android.net.wimax.WimaxManagerConstants;
93import android.os.AsyncTask;
94import android.os.Binder;
95import android.os.Build;
96import android.os.FileUtils;
97import android.os.Handler;
98import android.os.HandlerThread;
99import android.os.IBinder;
100import android.os.INetworkManagementService;
101import android.os.Looper;
102import android.os.Message;
103import android.os.Messenger;
104import android.os.ParcelFileDescriptor;
105import android.os.PowerManager;
106import android.os.Process;
107import android.os.RemoteException;
108import android.os.ServiceManager;
109import android.os.SystemClock;
110import android.os.SystemProperties;
111import android.os.UserHandle;
112import android.provider.Settings;
113import android.security.Credentials;
114import android.security.KeyStore;
115import android.telephony.TelephonyManager;
116import android.text.TextUtils;
117import android.util.Slog;
118import android.util.SparseArray;
119import android.util.SparseIntArray;
120import android.util.Xml;
121
122import com.android.internal.R;
123import com.android.internal.annotations.GuardedBy;
124import com.android.internal.net.LegacyVpnInfo;
125import com.android.internal.net.VpnConfig;
126import com.android.internal.net.VpnProfile;
127import com.android.internal.telephony.DctConstants;
128import com.android.internal.telephony.Phone;
129import com.android.internal.telephony.PhoneConstants;
130import com.android.internal.telephony.TelephonyIntents;
131import com.android.internal.util.AsyncChannel;
132import com.android.internal.util.IndentingPrintWriter;
133import com.android.internal.util.XmlUtils;
134import com.android.server.am.BatteryStatsService;
135import com.android.server.connectivity.DataConnectionStats;
136import com.android.server.connectivity.Nat464Xlat;
137import com.android.server.connectivity.NetworkAgentInfo;
138import com.android.server.connectivity.NetworkMonitor;
139import com.android.server.connectivity.PacManager;
140import com.android.server.connectivity.Tethering;
141import com.android.server.connectivity.Vpn;
142import com.android.server.net.BaseNetworkObserver;
143import com.android.server.net.LockdownVpnTracker;
144import com.google.android.collect.Lists;
145import com.google.android.collect.Sets;
146
147import dalvik.system.DexClassLoader;
148
149import org.xmlpull.v1.XmlPullParser;
150import org.xmlpull.v1.XmlPullParserException;
151
152import java.io.File;
153import java.io.FileDescriptor;
154import java.io.FileNotFoundException;
155import java.io.FileReader;
156import java.io.IOException;
157import java.io.PrintWriter;
158import java.lang.reflect.Constructor;
159import java.net.HttpURLConnection;
160import java.net.Inet4Address;
161import java.net.Inet6Address;
162import java.net.InetAddress;
163import java.net.URL;
164import java.net.UnknownHostException;
165import java.util.ArrayList;
166import java.util.Arrays;
167import java.util.Collection;
168import java.util.GregorianCalendar;
169import java.util.HashMap;
170import java.util.HashSet;
171import java.util.List;
172import java.util.Map;
173import java.util.Random;
174import java.util.concurrent.atomic.AtomicBoolean;
175import java.util.concurrent.atomic.AtomicInteger;
176
177import javax.net.ssl.HostnameVerifier;
178import javax.net.ssl.HttpsURLConnection;
179import javax.net.ssl.SSLSession;
180
181import static android.net.ConnectivityManager.INVALID_NET_ID;
182
183/**
184 * @hide
185 */
186public class ConnectivityService extends IConnectivityManager.Stub {
187    private static final String TAG = "ConnectivityService";
188
189    private static final boolean DBG = true;
190    private static final boolean VDBG = true; // STOPSHIP
191
192    // network sampling debugging
193    private static final boolean SAMPLE_DBG = false;
194
195    private static final boolean LOGD_RULES = false;
196
197    // TODO: create better separation between radio types and network types
198
199    // how long to wait before switching back to a radio's default network
200    private static final int RESTORE_DEFAULT_NETWORK_DELAY = 1 * 60 * 1000;
201    // system property that can override the above value
202    private static final String NETWORK_RESTORE_DELAY_PROP_NAME =
203            "android.telephony.apn-restore";
204
205    // Default value if FAIL_FAST_TIME_MS is not set
206    private static final int DEFAULT_FAIL_FAST_TIME_MS = 1 * 60 * 1000;
207    // system property that can override DEFAULT_FAIL_FAST_TIME_MS
208    private static final String FAIL_FAST_TIME_MS =
209            "persist.radio.fail_fast_time_ms";
210
211    private static final String ACTION_PKT_CNT_SAMPLE_INTERVAL_ELAPSED =
212            "android.net.ConnectivityService.action.PKT_CNT_SAMPLE_INTERVAL_ELAPSED";
213
214    private static final int SAMPLE_INTERVAL_ELAPSED_REQUEST_CODE = 0;
215
216    private PendingIntent mSampleIntervalElapsedIntent;
217
218    // Set network sampling interval at 12 minutes, this way, even if the timers get
219    // aggregated, it will fire at around 15 minutes, which should allow us to
220    // aggregate this timer with other timers (specially the socket keep alive timers)
221    private static final int DEFAULT_SAMPLING_INTERVAL_IN_SECONDS = (SAMPLE_DBG ? 30 : 12 * 60);
222
223    // start network sampling a minute after booting ...
224    private static final int DEFAULT_START_SAMPLING_INTERVAL_IN_SECONDS = (SAMPLE_DBG ? 30 : 60);
225
226    AlarmManager mAlarmManager;
227
228    // used in recursive route setting to add gateways for the host for which
229    // a host route was requested.
230    private static final int MAX_HOSTROUTE_CYCLE_COUNT = 10;
231
232    private Tethering mTethering;
233
234    private KeyStore mKeyStore;
235
236    @GuardedBy("mVpns")
237    private final SparseArray<Vpn> mVpns = new SparseArray<Vpn>();
238    private VpnCallback mVpnCallback = new VpnCallback();
239
240    private boolean mLockdownEnabled;
241    private LockdownVpnTracker mLockdownTracker;
242
243    private Nat464Xlat mClat;
244
245    /** Lock around {@link #mUidRules} and {@link #mMeteredIfaces}. */
246    private Object mRulesLock = new Object();
247    /** Currently active network rules by UID. */
248    private SparseIntArray mUidRules = new SparseIntArray();
249    /** Set of ifaces that are costly. */
250    private HashSet<String> mMeteredIfaces = Sets.newHashSet();
251
252    /**
253     * Sometimes we want to refer to the individual network state
254     * trackers separately, and sometimes we just want to treat them
255     * abstractly.
256     */
257    private NetworkStateTracker mNetTrackers[];
258
259    /* Handles captive portal check on a network */
260    private CaptivePortalTracker mCaptivePortalTracker;
261
262    /**
263     * The link properties that define the current links
264     */
265    private LinkProperties mCurrentLinkProperties[];
266
267    /**
268     * A per Net list of the PID's that requested access to the net
269     * used both as a refcount and for per-PID DNS selection
270     */
271    private List<Integer> mNetRequestersPids[];
272
273    // priority order of the nettrackers
274    // (excluding dynamically set mNetworkPreference)
275    // TODO - move mNetworkTypePreference into this
276    private int[] mPriorityList;
277
278    private Context mContext;
279    private int mNetworkPreference;
280    private int mActiveDefaultNetwork = -1;
281    // 0 is full bad, 100 is full good
282    private int mDefaultInetCondition = 0;
283    private int mDefaultInetConditionPublished = 0;
284    private boolean mInetConditionChangeInFlight = false;
285    private int mDefaultConnectionSequence = 0;
286
287    private Object mDnsLock = new Object();
288    private int mNumDnsEntries;
289
290    private boolean mTestMode;
291    private static ConnectivityService sServiceInstance;
292
293    private INetworkManagementService mNetd;
294    private INetworkPolicyManager mPolicyManager;
295
296    private static final int ENABLED  = 1;
297    private static final int DISABLED = 0;
298
299    private static final boolean ADD = true;
300    private static final boolean REMOVE = false;
301
302    private static final boolean TO_DEFAULT_TABLE = true;
303    private static final boolean TO_SECONDARY_TABLE = false;
304
305    private static final boolean EXEMPT = true;
306    private static final boolean UNEXEMPT = false;
307
308    /**
309     * used internally as a delayed event to make us switch back to the
310     * default network
311     */
312    private static final int EVENT_RESTORE_DEFAULT_NETWORK = 1;
313
314    /**
315     * used internally to change our mobile data enabled flag
316     */
317    private static final int EVENT_CHANGE_MOBILE_DATA_ENABLED = 2;
318
319    /**
320     * used internally to synchronize inet condition reports
321     * arg1 = networkType
322     * arg2 = condition (0 bad, 100 good)
323     */
324    private static final int EVENT_INET_CONDITION_CHANGE = 4;
325
326    /**
327     * used internally to mark the end of inet condition hold periods
328     * arg1 = networkType
329     */
330    private static final int EVENT_INET_CONDITION_HOLD_END = 5;
331
332    /**
333     * used internally to clear a wakelock when transitioning
334     * from one net to another.  Clear happens when we get a new
335     * network - EVENT_EXPIRE_NET_TRANSITION_WAKELOCK happens
336     * after a timeout if no network is found (typically 1 min).
337     */
338    private static final int EVENT_CLEAR_NET_TRANSITION_WAKELOCK = 8;
339
340    /**
341     * used internally to reload global proxy settings
342     */
343    private static final int EVENT_APPLY_GLOBAL_HTTP_PROXY = 9;
344
345    /**
346     * used internally to set external dependency met/unmet
347     * arg1 = ENABLED (met) or DISABLED (unmet)
348     * arg2 = NetworkType
349     */
350    private static final int EVENT_SET_DEPENDENCY_MET = 10;
351
352    /**
353     * used internally to send a sticky broadcast delayed.
354     */
355    private static final int EVENT_SEND_STICKY_BROADCAST_INTENT = 11;
356
357    /**
358     * Used internally to
359     * {@link NetworkStateTracker#setPolicyDataEnable(boolean)}.
360     */
361    private static final int EVENT_SET_POLICY_DATA_ENABLE = 12;
362
363    private static final int EVENT_VPN_STATE_CHANGED = 13;
364
365    /**
366     * Used internally to disable fail fast of mobile data
367     */
368    private static final int EVENT_ENABLE_FAIL_FAST_MOBILE_DATA = 14;
369
370    /**
371     * used internally to indicate that data sampling interval is up
372     */
373    private static final int EVENT_SAMPLE_INTERVAL_ELAPSED = 15;
374
375    /**
376     * PAC manager has received new port.
377     */
378    private static final int EVENT_PROXY_HAS_CHANGED = 16;
379
380    /**
381     * used internally when registering NetworkFactories
382     * obj = NetworkFactoryInfo
383     */
384    private static final int EVENT_REGISTER_NETWORK_FACTORY = 17;
385
386    /**
387     * used internally when registering NetworkAgents
388     * obj = Messenger
389     */
390    private static final int EVENT_REGISTER_NETWORK_AGENT = 18;
391
392    /**
393     * used to add a network request
394     * includes a NetworkRequestInfo
395     */
396    private static final int EVENT_REGISTER_NETWORK_REQUEST = 19;
397
398    /**
399     * indicates a timeout period is over - check if we had a network yet or not
400     * and if not, call the timeout calback (but leave the request live until they
401     * cancel it.
402     * includes a NetworkRequestInfo
403     */
404    private static final int EVENT_TIMEOUT_NETWORK_REQUEST = 20;
405
406    /**
407     * used to add a network listener - no request
408     * includes a NetworkRequestInfo
409     */
410    private static final int EVENT_REGISTER_NETWORK_LISTENER = 21;
411
412    /**
413     * used to remove a network request, either a listener or a real request
414     * arg1 = UID of caller
415     * obj  = NetworkRequest
416     */
417    private static final int EVENT_RELEASE_NETWORK_REQUEST = 22;
418
419    /**
420     * used internally when registering NetworkFactories
421     * obj = Messenger
422     */
423    private static final int EVENT_UNREGISTER_NETWORK_FACTORY = 23;
424
425    /**
426     * used internally to expire a wakelock when transitioning
427     * from one net to another.  Expire happens when we fail to find
428     * a new network (typically after 1 minute) -
429     * EVENT_CLEAR_NET_TRANSITION_WAKELOCK happens if we had found
430     * a replacement network.
431     */
432    private static final int EVENT_EXPIRE_NET_TRANSITION_WAKELOCK = 24;
433
434
435    /** Handler used for internal events. */
436    final private InternalHandler mHandler;
437    /** Handler used for incoming {@link NetworkStateTracker} events. */
438    final private NetworkStateTrackerHandler mTrackerHandler;
439
440    // list of DeathRecipients used to make sure features are turned off when
441    // a process dies
442    private List<FeatureUser> mFeatureUsers;
443
444    private boolean mSystemReady;
445    private Intent mInitialBroadcast;
446
447    private PowerManager.WakeLock mNetTransitionWakeLock;
448    private String mNetTransitionWakeLockCausedBy = "";
449    private int mNetTransitionWakeLockSerialNumber;
450    private int mNetTransitionWakeLockTimeout;
451
452    private InetAddress mDefaultDns;
453
454    // Lock for protecting access to mAddedRoutes and mExemptAddresses
455    private final Object mRoutesLock = new Object();
456
457    // this collection is used to refcount the added routes - if there are none left
458    // it's time to remove the route from the route table
459    @GuardedBy("mRoutesLock")
460    private Collection<RouteInfo> mAddedRoutes = new ArrayList<RouteInfo>();
461
462    // this collection corresponds to the entries of mAddedRoutes that have routing exemptions
463    // used to handle cleanup of exempt rules
464    @GuardedBy("mRoutesLock")
465    private Collection<LinkAddress> mExemptAddresses = new ArrayList<LinkAddress>();
466
467    // used in DBG mode to track inet condition reports
468    private static final int INET_CONDITION_LOG_MAX_SIZE = 15;
469    private ArrayList mInetLog;
470
471    // track the current default http proxy - tell the world if we get a new one (real change)
472    private ProxyInfo mDefaultProxy = null;
473    private Object mProxyLock = new Object();
474    private boolean mDefaultProxyDisabled = false;
475
476    // track the global proxy.
477    private ProxyInfo mGlobalProxy = null;
478
479    private PacManager mPacManager = null;
480
481    private SettingsObserver mSettingsObserver;
482
483    private AppOpsManager mAppOpsManager;
484
485    NetworkConfig[] mNetConfigs;
486    int mNetworksDefined;
487
488    private static class RadioAttributes {
489        public int mSimultaneity;
490        public int mType;
491        public RadioAttributes(String init) {
492            String fragments[] = init.split(",");
493            mType = Integer.parseInt(fragments[0]);
494            mSimultaneity = Integer.parseInt(fragments[1]);
495        }
496    }
497    RadioAttributes[] mRadioAttributes;
498
499    // the set of network types that can only be enabled by system/sig apps
500    List mProtectedNetworks;
501
502    private DataConnectionStats mDataConnectionStats;
503
504    private AtomicInteger mEnableFailFastMobileDataTag = new AtomicInteger(0);
505
506    TelephonyManager mTelephonyManager;
507
508    // sequence number for Networks
509    private final static int MIN_NET_ID = 10; // some reserved marks
510    private final static int MAX_NET_ID = 65535;
511    private int mNextNetId = MIN_NET_ID;
512
513    // sequence number of NetworkRequests
514    private int mNextNetworkRequestId = 1;
515
516    private static final int UID_UNUSED = -1;
517
518    /**
519     * Implements support for the legacy "one network per network type" model.
520     *
521     * We used to have a static array of NetworkStateTrackers, one for each
522     * network type, but that doesn't work any more now that we can have,
523     * for example, more that one wifi network. This class stores all the
524     * NetworkAgentInfo objects that support a given type, but the legacy
525     * API will only see the first one.
526     *
527     * It serves two main purposes:
528     *
529     * 1. Provide information about "the network for a given type" (since this
530     *    API only supports one).
531     * 2. Send legacy connectivity change broadcasts. Broadcasts are sent if
532     *    the first network for a given type changes, or if the default network
533     *    changes.
534     */
535    private class LegacyTypeTracker {
536        /**
537         * Array of lists, one per legacy network type (e.g., TYPE_MOBILE_MMS).
538         * Each list holds references to all NetworkAgentInfos that are used to
539         * satisfy requests for that network type.
540         *
541         * This array is built out at startup such that an unsupported network
542         * doesn't get an ArrayList instance, making this a tristate:
543         * unsupported, supported but not active and active.
544         *
545         * The actual lists are populated when we scan the network types that
546         * are supported on this device.
547         */
548        private ArrayList<NetworkAgentInfo> mTypeLists[];
549
550        public LegacyTypeTracker() {
551            mTypeLists = (ArrayList<NetworkAgentInfo>[])
552                    new ArrayList[ConnectivityManager.MAX_NETWORK_TYPE + 1];
553        }
554
555        public void addSupportedType(int type) {
556            if (mTypeLists[type] != null) {
557                throw new IllegalStateException(
558                        "legacy list for type " + type + "already initialized");
559            }
560            mTypeLists[type] = new ArrayList<NetworkAgentInfo>();
561        }
562
563        private boolean isDefaultNetwork(NetworkAgentInfo nai) {
564            return mNetworkForRequestId.get(mDefaultRequest.requestId) == nai;
565        }
566
567        public boolean isTypeSupported(int type) {
568            return isNetworkTypeValid(type) && mTypeLists[type] != null;
569        }
570
571        public NetworkAgentInfo getNetworkForType(int type) {
572            if (isTypeSupported(type) && !mTypeLists[type].isEmpty()) {
573                return mTypeLists[type].get(0);
574            } else {
575                return null;
576            }
577        }
578
579        public void add(int type, NetworkAgentInfo nai) {
580            if (!isTypeSupported(type)) {
581                return;  // Invalid network type.
582            }
583            if (VDBG) log("Adding agent " + nai + " for legacy network type " + type);
584
585            ArrayList<NetworkAgentInfo> list = mTypeLists[type];
586            if (list.contains(nai)) {
587                loge("Attempting to register duplicate agent for type " + type + ": " + nai);
588                return;
589            }
590
591            if (list.isEmpty() || isDefaultNetwork(nai)) {
592                if (VDBG) log("Sending connected broadcast for type " + type +
593                              "isDefaultNetwork=" + isDefaultNetwork(nai));
594                sendLegacyNetworkBroadcast(nai, true, type);
595            }
596            list.add(nai);
597        }
598
599        public void remove(NetworkAgentInfo nai) {
600            if (VDBG) log("Removing agent " + nai);
601            for (int type = 0; type < mTypeLists.length; type++) {
602                ArrayList<NetworkAgentInfo> list = mTypeLists[type];
603                if (list == null || list.isEmpty()) {
604                    continue;
605                }
606
607                boolean wasFirstNetwork = false;
608                if (list.get(0).equals(nai)) {
609                    // This network was the first in the list. Send broadcast.
610                    wasFirstNetwork = true;
611                }
612                list.remove(nai);
613
614                if (wasFirstNetwork || isDefaultNetwork(nai)) {
615                    if (VDBG) log("Sending disconnected broadcast for type " + type +
616                                  "isDefaultNetwork=" + isDefaultNetwork(nai));
617                    sendLegacyNetworkBroadcast(nai, false, type);
618                }
619
620                if (!list.isEmpty() && wasFirstNetwork) {
621                    if (VDBG) log("Other network available for type " + type +
622                                  ", sending connected broadcast");
623                    sendLegacyNetworkBroadcast(list.get(0), false, type);
624                }
625            }
626        }
627    }
628    private LegacyTypeTracker mLegacyTypeTracker = new LegacyTypeTracker();
629
630    public ConnectivityService(Context context, INetworkManagementService netd,
631            INetworkStatsService statsService, INetworkPolicyManager policyManager) {
632        // Currently, omitting a NetworkFactory will create one internally
633        // TODO: create here when we have cleaner WiMAX support
634        this(context, netd, statsService, policyManager, null);
635    }
636
637    public ConnectivityService(Context context, INetworkManagementService netManager,
638            INetworkStatsService statsService, INetworkPolicyManager policyManager,
639            NetworkFactory netFactory) {
640        if (DBG) log("ConnectivityService starting up");
641
642        NetworkCapabilities netCap = new NetworkCapabilities();
643        netCap.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
644        netCap.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED);
645        mDefaultRequest = new NetworkRequest(netCap, TYPE_NONE, nextNetworkRequestId());
646        NetworkRequestInfo nri = new NetworkRequestInfo(null, mDefaultRequest, new Binder(),
647                NetworkRequestInfo.REQUEST);
648        mNetworkRequests.put(mDefaultRequest, nri);
649
650        HandlerThread handlerThread = new HandlerThread("ConnectivityServiceThread");
651        handlerThread.start();
652        mHandler = new InternalHandler(handlerThread.getLooper());
653        mTrackerHandler = new NetworkStateTrackerHandler(handlerThread.getLooper());
654
655        if (netFactory == null) {
656            netFactory = new DefaultNetworkFactory(context, mTrackerHandler);
657        }
658
659        // setup our unique device name
660        if (TextUtils.isEmpty(SystemProperties.get("net.hostname"))) {
661            String id = Settings.Secure.getString(context.getContentResolver(),
662                    Settings.Secure.ANDROID_ID);
663            if (id != null && id.length() > 0) {
664                String name = new String("android-").concat(id);
665                SystemProperties.set("net.hostname", name);
666            }
667        }
668
669        // read our default dns server ip
670        String dns = Settings.Global.getString(context.getContentResolver(),
671                Settings.Global.DEFAULT_DNS_SERVER);
672        if (dns == null || dns.length() == 0) {
673            dns = context.getResources().getString(
674                    com.android.internal.R.string.config_default_dns_server);
675        }
676        try {
677            mDefaultDns = NetworkUtils.numericToInetAddress(dns);
678        } catch (IllegalArgumentException e) {
679            loge("Error setting defaultDns using " + dns);
680        }
681
682        mContext = checkNotNull(context, "missing Context");
683        mNetd = checkNotNull(netManager, "missing INetworkManagementService");
684        mPolicyManager = checkNotNull(policyManager, "missing INetworkPolicyManager");
685        mKeyStore = KeyStore.getInstance();
686        mTelephonyManager = (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
687
688        try {
689            mPolicyManager.registerListener(mPolicyListener);
690        } catch (RemoteException e) {
691            // ouch, no rules updates means some processes may never get network
692            loge("unable to register INetworkPolicyListener" + e.toString());
693        }
694
695        final PowerManager powerManager = (PowerManager) context.getSystemService(
696                Context.POWER_SERVICE);
697        mNetTransitionWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
698        mNetTransitionWakeLockTimeout = mContext.getResources().getInteger(
699                com.android.internal.R.integer.config_networkTransitionTimeout);
700
701        mNetTrackers = new NetworkStateTracker[
702                ConnectivityManager.MAX_NETWORK_TYPE+1];
703        mCurrentLinkProperties = new LinkProperties[ConnectivityManager.MAX_NETWORK_TYPE+1];
704
705        mRadioAttributes = new RadioAttributes[ConnectivityManager.MAX_RADIO_TYPE+1];
706        mNetConfigs = new NetworkConfig[ConnectivityManager.MAX_NETWORK_TYPE+1];
707
708        // Load device network attributes from resources
709        String[] raStrings = context.getResources().getStringArray(
710                com.android.internal.R.array.radioAttributes);
711        for (String raString : raStrings) {
712            RadioAttributes r = new RadioAttributes(raString);
713            if (VDBG) log("raString=" + raString + " r=" + r);
714            if (r.mType > ConnectivityManager.MAX_RADIO_TYPE) {
715                loge("Error in radioAttributes - ignoring attempt to define type " + r.mType);
716                continue;
717            }
718            if (mRadioAttributes[r.mType] != null) {
719                loge("Error in radioAttributes - ignoring attempt to redefine type " +
720                        r.mType);
721                continue;
722            }
723            mRadioAttributes[r.mType] = r;
724        }
725
726        // TODO: What is the "correct" way to do determine if this is a wifi only device?
727        boolean wifiOnly = SystemProperties.getBoolean("ro.radio.noril", false);
728        log("wifiOnly=" + wifiOnly);
729        String[] naStrings = context.getResources().getStringArray(
730                com.android.internal.R.array.networkAttributes);
731        for (String naString : naStrings) {
732            try {
733                NetworkConfig n = new NetworkConfig(naString);
734                if (VDBG) log("naString=" + naString + " config=" + n);
735                if (n.type > ConnectivityManager.MAX_NETWORK_TYPE) {
736                    loge("Error in networkAttributes - ignoring attempt to define type " +
737                            n.type);
738                    continue;
739                }
740                if (wifiOnly && ConnectivityManager.isNetworkTypeMobile(n.type)) {
741                    log("networkAttributes - ignoring mobile as this dev is wifiOnly " +
742                            n.type);
743                    continue;
744                }
745                if (mNetConfigs[n.type] != null) {
746                    loge("Error in networkAttributes - ignoring attempt to redefine type " +
747                            n.type);
748                    continue;
749                }
750                if (mRadioAttributes[n.radio] == null) {
751                    loge("Error in networkAttributes - ignoring attempt to use undefined " +
752                            "radio " + n.radio + " in network type " + n.type);
753                    continue;
754                }
755                mLegacyTypeTracker.addSupportedType(n.type);
756
757                mNetConfigs[n.type] = n;
758                mNetworksDefined++;
759            } catch(Exception e) {
760                // ignore it - leave the entry null
761            }
762        }
763        if (VDBG) log("mNetworksDefined=" + mNetworksDefined);
764
765        mProtectedNetworks = new ArrayList<Integer>();
766        int[] protectedNetworks = context.getResources().getIntArray(
767                com.android.internal.R.array.config_protectedNetworks);
768        for (int p : protectedNetworks) {
769            if ((mNetConfigs[p] != null) && (mProtectedNetworks.contains(p) == false)) {
770                mProtectedNetworks.add(p);
771            } else {
772                if (DBG) loge("Ignoring protectedNetwork " + p);
773            }
774        }
775
776        // high priority first
777        mPriorityList = new int[mNetworksDefined];
778        {
779            int insertionPoint = mNetworksDefined-1;
780            int currentLowest = 0;
781            int nextLowest = 0;
782            while (insertionPoint > -1) {
783                for (NetworkConfig na : mNetConfigs) {
784                    if (na == null) continue;
785                    if (na.priority < currentLowest) continue;
786                    if (na.priority > currentLowest) {
787                        if (na.priority < nextLowest || nextLowest == 0) {
788                            nextLowest = na.priority;
789                        }
790                        continue;
791                    }
792                    mPriorityList[insertionPoint--] = na.type;
793                }
794                currentLowest = nextLowest;
795                nextLowest = 0;
796            }
797        }
798
799        mNetRequestersPids =
800                (List<Integer> [])new ArrayList[ConnectivityManager.MAX_NETWORK_TYPE+1];
801        for (int i : mPriorityList) {
802            mNetRequestersPids[i] = new ArrayList<Integer>();
803        }
804
805        mFeatureUsers = new ArrayList<FeatureUser>();
806
807        mTestMode = SystemProperties.get("cm.test.mode").equals("true")
808                && SystemProperties.get("ro.build.type").equals("eng");
809
810        // Create and start trackers for hard-coded networks
811        for (int targetNetworkType : mPriorityList) {
812            final NetworkConfig config = mNetConfigs[targetNetworkType];
813            final NetworkStateTracker tracker;
814            try {
815                tracker = netFactory.createTracker(targetNetworkType, config);
816                mNetTrackers[targetNetworkType] = tracker;
817            } catch (IllegalArgumentException e) {
818                Slog.e(TAG, "Problem creating " + getNetworkTypeName(targetNetworkType)
819                        + " tracker: " + e);
820                continue;
821            }
822
823            tracker.startMonitoring(context, mTrackerHandler);
824            if (config.isDefault()) {
825                tracker.reconnect();
826            }
827        }
828
829        mTethering = new Tethering(mContext, mNetd, statsService, this, mHandler.getLooper());
830
831        //set up the listener for user state for creating user VPNs
832        IntentFilter intentFilter = new IntentFilter();
833        intentFilter.addAction(Intent.ACTION_USER_STARTING);
834        intentFilter.addAction(Intent.ACTION_USER_STOPPING);
835        mContext.registerReceiverAsUser(
836                mUserIntentReceiver, UserHandle.ALL, intentFilter, null, null);
837        mClat = new Nat464Xlat(mContext, mNetd, this, mTrackerHandler);
838
839        try {
840            mNetd.registerObserver(mTethering);
841            mNetd.registerObserver(mDataActivityObserver);
842            mNetd.registerObserver(mClat);
843        } catch (RemoteException e) {
844            loge("Error registering observer :" + e);
845        }
846
847        if (DBG) {
848            mInetLog = new ArrayList();
849        }
850
851        mSettingsObserver = new SettingsObserver(mHandler, EVENT_APPLY_GLOBAL_HTTP_PROXY);
852        mSettingsObserver.observe(mContext);
853
854        mDataConnectionStats = new DataConnectionStats(mContext);
855        mDataConnectionStats.startMonitoring();
856
857        // start network sampling ..
858        Intent intent = new Intent(ACTION_PKT_CNT_SAMPLE_INTERVAL_ELAPSED, null);
859        mSampleIntervalElapsedIntent = PendingIntent.getBroadcast(mContext,
860                SAMPLE_INTERVAL_ELAPSED_REQUEST_CODE, intent, 0);
861
862        mAlarmManager = (AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE);
863        setAlarm(DEFAULT_START_SAMPLING_INTERVAL_IN_SECONDS * 1000, mSampleIntervalElapsedIntent);
864
865        IntentFilter filter = new IntentFilter();
866        filter.addAction(ACTION_PKT_CNT_SAMPLE_INTERVAL_ELAPSED);
867        mContext.registerReceiver(
868                new BroadcastReceiver() {
869                    @Override
870                    public void onReceive(Context context, Intent intent) {
871                        String action = intent.getAction();
872                        if (action.equals(ACTION_PKT_CNT_SAMPLE_INTERVAL_ELAPSED)) {
873                            mHandler.sendMessage(mHandler.obtainMessage
874                                    (EVENT_SAMPLE_INTERVAL_ELAPSED));
875                        }
876                    }
877                },
878                new IntentFilter(filter));
879
880        mPacManager = new PacManager(mContext, mHandler, EVENT_PROXY_HAS_CHANGED);
881
882        filter = new IntentFilter();
883        filter.addAction(CONNECTED_TO_PROVISIONING_NETWORK_ACTION);
884        mContext.registerReceiver(mProvisioningReceiver, filter);
885
886        mAppOpsManager = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
887    }
888
889    private synchronized int nextNetworkRequestId() {
890        return mNextNetworkRequestId++;
891    }
892
893    private synchronized int nextNetId() {
894        int netId = mNextNetId;
895        if (++mNextNetId > MAX_NET_ID) mNextNetId = MIN_NET_ID;
896        return netId;
897    }
898
899    /**
900     * Factory that creates {@link NetworkStateTracker} instances using given
901     * {@link NetworkConfig}.
902     *
903     * TODO - this is obsolete and will be deleted.  It's replaced by the
904     * registerNetworkFactory call and protocol.
905     * @Deprecated in favor of registerNetworkFactory dynamic bindings
906     */
907    public interface NetworkFactory {
908        public NetworkStateTracker createTracker(int targetNetworkType, NetworkConfig config);
909    }
910
911    private static class DefaultNetworkFactory implements NetworkFactory {
912        private final Context mContext;
913        private final Handler mTrackerHandler;
914
915        public DefaultNetworkFactory(Context context, Handler trackerHandler) {
916            mContext = context;
917            mTrackerHandler = trackerHandler;
918        }
919
920        @Override
921        public NetworkStateTracker createTracker(int targetNetworkType, NetworkConfig config) {
922            switch (config.radio) {
923                case TYPE_DUMMY:
924                    return new DummyDataStateTracker(targetNetworkType, config.name);
925                case TYPE_WIMAX:
926                    return makeWimaxStateTracker(mContext, mTrackerHandler);
927                case TYPE_PROXY:
928                    return new ProxyDataTracker();
929                default:
930                    throw new IllegalArgumentException(
931                            "Trying to create a NetworkStateTracker for an unknown radio type: "
932                            + config.radio);
933            }
934        }
935    }
936
937    /**
938     * Loads external WiMAX library and registers as system service, returning a
939     * {@link NetworkStateTracker} for WiMAX. Caller is still responsible for
940     * invoking {@link NetworkStateTracker#startMonitoring(Context, Handler)}.
941     */
942    private static NetworkStateTracker makeWimaxStateTracker(
943            Context context, Handler trackerHandler) {
944        // Initialize Wimax
945        DexClassLoader wimaxClassLoader;
946        Class wimaxStateTrackerClass = null;
947        Class wimaxServiceClass = null;
948        Class wimaxManagerClass;
949        String wimaxJarLocation;
950        String wimaxLibLocation;
951        String wimaxManagerClassName;
952        String wimaxServiceClassName;
953        String wimaxStateTrackerClassName;
954
955        NetworkStateTracker wimaxStateTracker = null;
956
957        boolean isWimaxEnabled = context.getResources().getBoolean(
958                com.android.internal.R.bool.config_wimaxEnabled);
959
960        if (isWimaxEnabled) {
961            try {
962                wimaxJarLocation = context.getResources().getString(
963                        com.android.internal.R.string.config_wimaxServiceJarLocation);
964                wimaxLibLocation = context.getResources().getString(
965                        com.android.internal.R.string.config_wimaxNativeLibLocation);
966                wimaxManagerClassName = context.getResources().getString(
967                        com.android.internal.R.string.config_wimaxManagerClassname);
968                wimaxServiceClassName = context.getResources().getString(
969                        com.android.internal.R.string.config_wimaxServiceClassname);
970                wimaxStateTrackerClassName = context.getResources().getString(
971                        com.android.internal.R.string.config_wimaxStateTrackerClassname);
972
973                if (DBG) log("wimaxJarLocation: " + wimaxJarLocation);
974                wimaxClassLoader =  new DexClassLoader(wimaxJarLocation,
975                        new ContextWrapper(context).getCacheDir().getAbsolutePath(),
976                        wimaxLibLocation, ClassLoader.getSystemClassLoader());
977
978                try {
979                    wimaxManagerClass = wimaxClassLoader.loadClass(wimaxManagerClassName);
980                    wimaxStateTrackerClass = wimaxClassLoader.loadClass(wimaxStateTrackerClassName);
981                    wimaxServiceClass = wimaxClassLoader.loadClass(wimaxServiceClassName);
982                } catch (ClassNotFoundException ex) {
983                    loge("Exception finding Wimax classes: " + ex.toString());
984                    return null;
985                }
986            } catch(Resources.NotFoundException ex) {
987                loge("Wimax Resources does not exist!!! ");
988                return null;
989            }
990
991            try {
992                if (DBG) log("Starting Wimax Service... ");
993
994                Constructor wmxStTrkrConst = wimaxStateTrackerClass.getConstructor
995                        (new Class[] {Context.class, Handler.class});
996                wimaxStateTracker = (NetworkStateTracker) wmxStTrkrConst.newInstance(
997                        context, trackerHandler);
998
999                Constructor wmxSrvConst = wimaxServiceClass.getDeclaredConstructor
1000                        (new Class[] {Context.class, wimaxStateTrackerClass});
1001                wmxSrvConst.setAccessible(true);
1002                IBinder svcInvoker = (IBinder)wmxSrvConst.newInstance(context, wimaxStateTracker);
1003                wmxSrvConst.setAccessible(false);
1004
1005                ServiceManager.addService(WimaxManagerConstants.WIMAX_SERVICE, svcInvoker);
1006
1007            } catch(Exception ex) {
1008                loge("Exception creating Wimax classes: " + ex.toString());
1009                return null;
1010            }
1011        } else {
1012            loge("Wimax is not enabled or not added to the network attributes!!! ");
1013            return null;
1014        }
1015
1016        return wimaxStateTracker;
1017    }
1018
1019    private int getConnectivityChangeDelay() {
1020        final ContentResolver cr = mContext.getContentResolver();
1021
1022        /** Check system properties for the default value then use secure settings value, if any. */
1023        int defaultDelay = SystemProperties.getInt(
1024                "conn." + Settings.Global.CONNECTIVITY_CHANGE_DELAY,
1025                ConnectivityManager.CONNECTIVITY_CHANGE_DELAY_DEFAULT);
1026        return Settings.Global.getInt(cr, Settings.Global.CONNECTIVITY_CHANGE_DELAY,
1027                defaultDelay);
1028    }
1029
1030    private boolean teardown(NetworkStateTracker netTracker) {
1031        if (netTracker.teardown()) {
1032            netTracker.setTeardownRequested(true);
1033            return true;
1034        } else {
1035            return false;
1036        }
1037    }
1038
1039    /**
1040     * Check if UID should be blocked from using the network represented by the
1041     * given {@link NetworkStateTracker}.
1042     */
1043    private boolean isNetworkBlocked(int networkType, int uid) {
1044        final boolean networkCostly;
1045        final int uidRules;
1046
1047        LinkProperties lp = getLinkPropertiesForType(networkType);
1048        final String iface = (lp == null ? "" : lp.getInterfaceName());
1049        synchronized (mRulesLock) {
1050            networkCostly = mMeteredIfaces.contains(iface);
1051            uidRules = mUidRules.get(uid, RULE_ALLOW_ALL);
1052        }
1053
1054        if (networkCostly && (uidRules & RULE_REJECT_METERED) != 0) {
1055            return true;
1056        }
1057
1058        // no restrictive rules; network is visible
1059        return false;
1060    }
1061
1062    /**
1063     * Return a filtered {@link NetworkInfo}, potentially marked
1064     * {@link DetailedState#BLOCKED} based on
1065     * {@link #isNetworkBlocked}.
1066     */
1067    private NetworkInfo getFilteredNetworkInfo(int networkType, int uid) {
1068        NetworkInfo info = getNetworkInfoForType(networkType);
1069        if (isNetworkBlocked(networkType, uid)) {
1070            // network is blocked; clone and override state
1071            info = new NetworkInfo(info);
1072            info.setDetailedState(DetailedState.BLOCKED, null, null);
1073        }
1074        if (mLockdownTracker != null) {
1075            info = mLockdownTracker.augmentNetworkInfo(info);
1076        }
1077        return info;
1078    }
1079
1080    /**
1081     * Return NetworkInfo for the active (i.e., connected) network interface.
1082     * It is assumed that at most one network is active at a time. If more
1083     * than one is active, it is indeterminate which will be returned.
1084     * @return the info for the active network, or {@code null} if none is
1085     * active
1086     */
1087    @Override
1088    public NetworkInfo getActiveNetworkInfo() {
1089        enforceAccessPermission();
1090        final int uid = Binder.getCallingUid();
1091        return getNetworkInfo(mActiveDefaultNetwork, uid);
1092    }
1093
1094    // only called when the default request is satisfied
1095    private void updateActiveDefaultNetwork(NetworkAgentInfo nai) {
1096        if (nai != null) {
1097            mActiveDefaultNetwork = nai.networkInfo.getType();
1098        } else {
1099            mActiveDefaultNetwork = TYPE_NONE;
1100        }
1101    }
1102
1103    /**
1104     * Find the first Provisioning network.
1105     *
1106     * @return NetworkInfo or null if none.
1107     */
1108    private NetworkInfo getProvisioningNetworkInfo() {
1109        enforceAccessPermission();
1110
1111        // Find the first Provisioning Network
1112        NetworkInfo provNi = null;
1113        for (NetworkInfo ni : getAllNetworkInfo()) {
1114            if (ni.isConnectedToProvisioningNetwork()) {
1115                provNi = ni;
1116                break;
1117            }
1118        }
1119        if (DBG) log("getProvisioningNetworkInfo: X provNi=" + provNi);
1120        return provNi;
1121    }
1122
1123    /**
1124     * Find the first Provisioning network or the ActiveDefaultNetwork
1125     * if there is no Provisioning network
1126     *
1127     * @return NetworkInfo or null if none.
1128     */
1129    @Override
1130    public NetworkInfo getProvisioningOrActiveNetworkInfo() {
1131        enforceAccessPermission();
1132
1133        NetworkInfo provNi = getProvisioningNetworkInfo();
1134        if (provNi == null) {
1135            final int uid = Binder.getCallingUid();
1136            provNi = getNetworkInfo(mActiveDefaultNetwork, uid);
1137        }
1138        if (DBG) log("getProvisioningOrActiveNetworkInfo: X provNi=" + provNi);
1139        return provNi;
1140    }
1141
1142    public NetworkInfo getActiveNetworkInfoUnfiltered() {
1143        enforceAccessPermission();
1144        if (isNetworkTypeValid(mActiveDefaultNetwork)) {
1145            return getNetworkInfoForType(mActiveDefaultNetwork);
1146        }
1147        return null;
1148    }
1149
1150    @Override
1151    public NetworkInfo getActiveNetworkInfoForUid(int uid) {
1152        enforceConnectivityInternalPermission();
1153        return getNetworkInfo(mActiveDefaultNetwork, uid);
1154    }
1155
1156    @Override
1157    public NetworkInfo getNetworkInfo(int networkType) {
1158        enforceAccessPermission();
1159        final int uid = Binder.getCallingUid();
1160        return getNetworkInfo(networkType, uid);
1161    }
1162
1163    private NetworkInfo getNetworkInfo(int networkType, int uid) {
1164        NetworkInfo info = null;
1165        if (isNetworkTypeValid(networkType)) {
1166            if (getNetworkInfoForType(networkType) != null) {
1167                info = getFilteredNetworkInfo(networkType, uid);
1168            }
1169        }
1170        return info;
1171    }
1172
1173    @Override
1174    public NetworkInfo[] getAllNetworkInfo() {
1175        enforceAccessPermission();
1176        final int uid = Binder.getCallingUid();
1177        final ArrayList<NetworkInfo> result = Lists.newArrayList();
1178        synchronized (mRulesLock) {
1179            for (int networkType = 0; networkType <= ConnectivityManager.MAX_NETWORK_TYPE;
1180                    networkType++) {
1181                if (getNetworkInfoForType(networkType) != null) {
1182                    result.add(getFilteredNetworkInfo(networkType, uid));
1183                }
1184            }
1185        }
1186        return result.toArray(new NetworkInfo[result.size()]);
1187    }
1188
1189    @Override
1190    public boolean isNetworkSupported(int networkType) {
1191        enforceAccessPermission();
1192        return (isNetworkTypeValid(networkType) && (getNetworkInfoForType(networkType) != null));
1193    }
1194
1195    /**
1196     * Return LinkProperties for the active (i.e., connected) default
1197     * network interface.  It is assumed that at most one default network
1198     * is active at a time. If more than one is active, it is indeterminate
1199     * which will be returned.
1200     * @return the ip properties for the active network, or {@code null} if
1201     * none is active
1202     */
1203    @Override
1204    public LinkProperties getActiveLinkProperties() {
1205        return getLinkPropertiesForType(mActiveDefaultNetwork);
1206    }
1207
1208    @Override
1209    public LinkProperties getLinkPropertiesForType(int networkType) {
1210        enforceAccessPermission();
1211        if (isNetworkTypeValid(networkType)) {
1212            return getLinkPropertiesForTypeInternal(networkType);
1213        }
1214        return null;
1215    }
1216
1217    // TODO - this should be ALL networks
1218    @Override
1219    public LinkProperties getLinkProperties(Network network) {
1220        enforceAccessPermission();
1221        NetworkAgentInfo nai = mNetworkForNetId.get(network.netId);
1222        if (nai != null) return new LinkProperties(nai.linkProperties);
1223        return null;
1224    }
1225
1226    @Override
1227    public NetworkCapabilities getNetworkCapabilities(Network network) {
1228        enforceAccessPermission();
1229        NetworkAgentInfo nai = mNetworkForNetId.get(network.netId);
1230        if (nai != null) return new NetworkCapabilities(nai.networkCapabilities);
1231        return null;
1232    }
1233
1234    @Override
1235    public NetworkState[] getAllNetworkState() {
1236        enforceAccessPermission();
1237        final int uid = Binder.getCallingUid();
1238        final ArrayList<NetworkState> result = Lists.newArrayList();
1239        synchronized (mRulesLock) {
1240            for (int networkType = 0; networkType <= ConnectivityManager.MAX_NETWORK_TYPE;
1241                    networkType++) {
1242                if (getNetworkInfoForType(networkType) != null) {
1243                    final NetworkInfo info = getFilteredNetworkInfo(networkType, uid);
1244                    final LinkProperties lp = getLinkPropertiesForTypeInternal(networkType);
1245                    final NetworkCapabilities netcap = getNetworkCapabilitiesForType(networkType);
1246                    result.add(new NetworkState(info, lp, netcap));
1247                }
1248            }
1249        }
1250        return result.toArray(new NetworkState[result.size()]);
1251    }
1252
1253    private NetworkState getNetworkStateUnchecked(int networkType) {
1254        if (isNetworkTypeValid(networkType)) {
1255            NetworkInfo info = getNetworkInfoForType(networkType);
1256            if (info != null) {
1257                return new NetworkState(info,
1258                        getLinkPropertiesForTypeInternal(networkType),
1259                        getNetworkCapabilitiesForType(networkType));
1260            }
1261        }
1262        return null;
1263    }
1264
1265    @Override
1266    public NetworkQuotaInfo getActiveNetworkQuotaInfo() {
1267        enforceAccessPermission();
1268
1269        final long token = Binder.clearCallingIdentity();
1270        try {
1271            final NetworkState state = getNetworkStateUnchecked(mActiveDefaultNetwork);
1272            if (state != null) {
1273                try {
1274                    return mPolicyManager.getNetworkQuotaInfo(state);
1275                } catch (RemoteException e) {
1276                }
1277            }
1278            return null;
1279        } finally {
1280            Binder.restoreCallingIdentity(token);
1281        }
1282    }
1283
1284    @Override
1285    public boolean isActiveNetworkMetered() {
1286        enforceAccessPermission();
1287        final long token = Binder.clearCallingIdentity();
1288        try {
1289            return isNetworkMeteredUnchecked(mActiveDefaultNetwork);
1290        } finally {
1291            Binder.restoreCallingIdentity(token);
1292        }
1293    }
1294
1295    private boolean isNetworkMeteredUnchecked(int networkType) {
1296        final NetworkState state = getNetworkStateUnchecked(networkType);
1297        if (state != null) {
1298            try {
1299                return mPolicyManager.isNetworkMetered(state);
1300            } catch (RemoteException e) {
1301            }
1302        }
1303        return false;
1304    }
1305
1306    private INetworkManagementEventObserver mDataActivityObserver = new BaseNetworkObserver() {
1307        @Override
1308        public void interfaceClassDataActivityChanged(String label, boolean active, long tsNanos) {
1309            int deviceType = Integer.parseInt(label);
1310            sendDataActivityBroadcast(deviceType, active, tsNanos);
1311        }
1312    };
1313
1314    /**
1315     * Used to notice when the calling process dies so we can self-expire
1316     *
1317     * Also used to know if the process has cleaned up after itself when
1318     * our auto-expire timer goes off.  The timer has a link to an object.
1319     *
1320     */
1321    private class FeatureUser implements IBinder.DeathRecipient {
1322        int mNetworkType;
1323        String mFeature;
1324        IBinder mBinder;
1325        int mPid;
1326        int mUid;
1327        long mCreateTime;
1328
1329        FeatureUser(int type, String feature, IBinder binder) {
1330            super();
1331            mNetworkType = type;
1332            mFeature = feature;
1333            mBinder = binder;
1334            mPid = getCallingPid();
1335            mUid = getCallingUid();
1336            mCreateTime = System.currentTimeMillis();
1337
1338            try {
1339                mBinder.linkToDeath(this, 0);
1340            } catch (RemoteException e) {
1341                binderDied();
1342            }
1343        }
1344
1345        void unlinkDeathRecipient() {
1346            mBinder.unlinkToDeath(this, 0);
1347        }
1348
1349        public void binderDied() {
1350            log("ConnectivityService FeatureUser binderDied(" +
1351                    mNetworkType + ", " + mFeature + ", " + mBinder + "), created " +
1352                    (System.currentTimeMillis() - mCreateTime) + " mSec ago");
1353            stopUsingNetworkFeature(this, false);
1354        }
1355
1356        public void expire() {
1357            if (VDBG) {
1358                log("ConnectivityService FeatureUser expire(" +
1359                        mNetworkType + ", " + mFeature + ", " + mBinder +"), created " +
1360                        (System.currentTimeMillis() - mCreateTime) + " mSec ago");
1361            }
1362            stopUsingNetworkFeature(this, false);
1363        }
1364
1365        public boolean isSameUser(FeatureUser u) {
1366            if (u == null) return false;
1367
1368            return isSameUser(u.mPid, u.mUid, u.mNetworkType, u.mFeature);
1369        }
1370
1371        public boolean isSameUser(int pid, int uid, int networkType, String feature) {
1372            if ((mPid == pid) && (mUid == uid) && (mNetworkType == networkType) &&
1373                TextUtils.equals(mFeature, feature)) {
1374                return true;
1375            }
1376            return false;
1377        }
1378
1379        public String toString() {
1380            return "FeatureUser("+mNetworkType+","+mFeature+","+mPid+","+mUid+"), created " +
1381                    (System.currentTimeMillis() - mCreateTime) + " mSec ago";
1382        }
1383    }
1384
1385    // javadoc from interface
1386    public int startUsingNetworkFeature(int networkType, String feature,
1387            IBinder binder) {
1388        long startTime = 0;
1389        if (DBG) {
1390            startTime = SystemClock.elapsedRealtime();
1391        }
1392        if (VDBG) {
1393            log("startUsingNetworkFeature for net " + networkType + ": " + feature + ", uid="
1394                    + Binder.getCallingUid());
1395        }
1396        enforceChangePermission();
1397        try {
1398            if (!ConnectivityManager.isNetworkTypeValid(networkType) ||
1399                    mNetConfigs[networkType] == null) {
1400                return PhoneConstants.APN_REQUEST_FAILED;
1401            }
1402
1403            FeatureUser f = new FeatureUser(networkType, feature, binder);
1404
1405            // TODO - move this into individual networktrackers
1406            int usedNetworkType = convertFeatureToNetworkType(networkType, feature);
1407
1408            if (mLockdownEnabled) {
1409                // Since carrier APNs usually aren't available from VPN
1410                // endpoint, mark them as unavailable.
1411                return PhoneConstants.APN_TYPE_NOT_AVAILABLE;
1412            }
1413
1414            if (mProtectedNetworks.contains(usedNetworkType)) {
1415                enforceConnectivityInternalPermission();
1416            }
1417
1418            // if UID is restricted, don't allow them to bring up metered APNs
1419            final boolean networkMetered = isNetworkMeteredUnchecked(usedNetworkType);
1420            final int uidRules;
1421            synchronized (mRulesLock) {
1422                uidRules = mUidRules.get(Binder.getCallingUid(), RULE_ALLOW_ALL);
1423            }
1424            if (networkMetered && (uidRules & RULE_REJECT_METERED) != 0) {
1425                return PhoneConstants.APN_REQUEST_FAILED;
1426            }
1427
1428            NetworkStateTracker network = mNetTrackers[usedNetworkType];
1429            if (network != null) {
1430                Integer currentPid = new Integer(getCallingPid());
1431                if (usedNetworkType != networkType) {
1432                    NetworkInfo ni = network.getNetworkInfo();
1433
1434                    if (ni.isAvailable() == false) {
1435                        if (!TextUtils.equals(feature,Phone.FEATURE_ENABLE_DUN_ALWAYS)) {
1436                            if (DBG) log("special network not available ni=" + ni.getTypeName());
1437                            return PhoneConstants.APN_TYPE_NOT_AVAILABLE;
1438                        } else {
1439                            // else make the attempt anyway - probably giving REQUEST_STARTED below
1440                            if (DBG) {
1441                                log("special network not available, but try anyway ni=" +
1442                                        ni.getTypeName());
1443                            }
1444                        }
1445                    }
1446
1447                    int restoreTimer = getRestoreDefaultNetworkDelay(usedNetworkType);
1448
1449                    synchronized(this) {
1450                        boolean addToList = true;
1451                        if (restoreTimer < 0) {
1452                            // In case there is no timer is specified for the feature,
1453                            // make sure we don't add duplicate entry with the same request.
1454                            for (FeatureUser u : mFeatureUsers) {
1455                                if (u.isSameUser(f)) {
1456                                    // Duplicate user is found. Do not add.
1457                                    addToList = false;
1458                                    break;
1459                                }
1460                            }
1461                        }
1462
1463                        if (addToList) mFeatureUsers.add(f);
1464                        if (!mNetRequestersPids[usedNetworkType].contains(currentPid)) {
1465                            // this gets used for per-pid dns when connected
1466                            mNetRequestersPids[usedNetworkType].add(currentPid);
1467                        }
1468                    }
1469
1470                    if (restoreTimer >= 0) {
1471                        mHandler.sendMessageDelayed(mHandler.obtainMessage(
1472                                EVENT_RESTORE_DEFAULT_NETWORK, f), restoreTimer);
1473                    }
1474
1475                    if ((ni.isConnectedOrConnecting() == true) &&
1476                            !network.isTeardownRequested()) {
1477                        if (ni.isConnected() == true) {
1478                            final long token = Binder.clearCallingIdentity();
1479                            try {
1480                                // add the pid-specific dns
1481                                handleDnsConfigurationChange(usedNetworkType);
1482                                if (VDBG) log("special network already active");
1483                            } finally {
1484                                Binder.restoreCallingIdentity(token);
1485                            }
1486                            return PhoneConstants.APN_ALREADY_ACTIVE;
1487                        }
1488                        if (VDBG) log("special network already connecting");
1489                        return PhoneConstants.APN_REQUEST_STARTED;
1490                    }
1491
1492                    // check if the radio in play can make another contact
1493                    // assume if cannot for now
1494
1495                    if (DBG) {
1496                        log("startUsingNetworkFeature reconnecting to " + networkType + ": " +
1497                                feature);
1498                    }
1499                    if (network.reconnect()) {
1500                        if (DBG) log("startUsingNetworkFeature X: return APN_REQUEST_STARTED");
1501                        return PhoneConstants.APN_REQUEST_STARTED;
1502                    } else {
1503                        if (DBG) log("startUsingNetworkFeature X: return APN_REQUEST_FAILED");
1504                        return PhoneConstants.APN_REQUEST_FAILED;
1505                    }
1506                } else {
1507                    // need to remember this unsupported request so we respond appropriately on stop
1508                    synchronized(this) {
1509                        mFeatureUsers.add(f);
1510                        if (!mNetRequestersPids[usedNetworkType].contains(currentPid)) {
1511                            // this gets used for per-pid dns when connected
1512                            mNetRequestersPids[usedNetworkType].add(currentPid);
1513                        }
1514                    }
1515                    if (DBG) log("startUsingNetworkFeature X: return -1 unsupported feature.");
1516                    return -1;
1517                }
1518            }
1519            if (DBG) log("startUsingNetworkFeature X: return APN_TYPE_NOT_AVAILABLE");
1520            return PhoneConstants.APN_TYPE_NOT_AVAILABLE;
1521         } finally {
1522            if (DBG) {
1523                final long execTime = SystemClock.elapsedRealtime() - startTime;
1524                if (execTime > 250) {
1525                    loge("startUsingNetworkFeature took too long: " + execTime + "ms");
1526                } else {
1527                    if (VDBG) log("startUsingNetworkFeature took " + execTime + "ms");
1528                }
1529            }
1530         }
1531    }
1532
1533    // javadoc from interface
1534    public int stopUsingNetworkFeature(int networkType, String feature) {
1535        enforceChangePermission();
1536
1537        int pid = getCallingPid();
1538        int uid = getCallingUid();
1539
1540        FeatureUser u = null;
1541        boolean found = false;
1542
1543        synchronized(this) {
1544            for (FeatureUser x : mFeatureUsers) {
1545                if (x.isSameUser(pid, uid, networkType, feature)) {
1546                    u = x;
1547                    found = true;
1548                    break;
1549                }
1550            }
1551        }
1552        if (found && u != null) {
1553            if (VDBG) log("stopUsingNetworkFeature: X");
1554            // stop regardless of how many other time this proc had called start
1555            return stopUsingNetworkFeature(u, true);
1556        } else {
1557            // none found!
1558            if (VDBG) log("stopUsingNetworkFeature: X not a live request, ignoring");
1559            return 1;
1560        }
1561    }
1562
1563    private int stopUsingNetworkFeature(FeatureUser u, boolean ignoreDups) {
1564        int networkType = u.mNetworkType;
1565        String feature = u.mFeature;
1566        int pid = u.mPid;
1567        int uid = u.mUid;
1568
1569        NetworkStateTracker tracker = null;
1570        boolean callTeardown = false;  // used to carry our decision outside of sync block
1571
1572        if (VDBG) {
1573            log("stopUsingNetworkFeature: net " + networkType + ": " + feature);
1574        }
1575
1576        if (!ConnectivityManager.isNetworkTypeValid(networkType)) {
1577            if (DBG) {
1578                log("stopUsingNetworkFeature: net " + networkType + ": " + feature +
1579                        ", net is invalid");
1580            }
1581            return -1;
1582        }
1583
1584        // need to link the mFeatureUsers list with the mNetRequestersPids state in this
1585        // sync block
1586        synchronized(this) {
1587            // check if this process still has an outstanding start request
1588            if (!mFeatureUsers.contains(u)) {
1589                if (VDBG) {
1590                    log("stopUsingNetworkFeature: this process has no outstanding requests" +
1591                        ", ignoring");
1592                }
1593                return 1;
1594            }
1595            u.unlinkDeathRecipient();
1596            mFeatureUsers.remove(mFeatureUsers.indexOf(u));
1597            // If we care about duplicate requests, check for that here.
1598            //
1599            // This is done to support the extension of a request - the app
1600            // can request we start the network feature again and renew the
1601            // auto-shutoff delay.  Normal "stop" calls from the app though
1602            // do not pay attention to duplicate requests - in effect the
1603            // API does not refcount and a single stop will counter multiple starts.
1604            if (ignoreDups == false) {
1605                for (FeatureUser x : mFeatureUsers) {
1606                    if (x.isSameUser(u)) {
1607                        if (VDBG) log("stopUsingNetworkFeature: dup is found, ignoring");
1608                        return 1;
1609                    }
1610                }
1611            }
1612
1613            // TODO - move to individual network trackers
1614            int usedNetworkType = convertFeatureToNetworkType(networkType, feature);
1615
1616            tracker =  mNetTrackers[usedNetworkType];
1617            if (tracker == null) {
1618                if (DBG) {
1619                    log("stopUsingNetworkFeature: net " + networkType + ": " + feature +
1620                            " no known tracker for used net type " + usedNetworkType);
1621                }
1622                return -1;
1623            }
1624            if (usedNetworkType != networkType) {
1625                Integer currentPid = new Integer(pid);
1626                mNetRequestersPids[usedNetworkType].remove(currentPid);
1627
1628                final long token = Binder.clearCallingIdentity();
1629                try {
1630                    reassessPidDns(pid, true);
1631                } finally {
1632                    Binder.restoreCallingIdentity(token);
1633                }
1634                flushVmDnsCache();
1635                if (mNetRequestersPids[usedNetworkType].size() != 0) {
1636                    if (VDBG) {
1637                        log("stopUsingNetworkFeature: net " + networkType + ": " + feature +
1638                                " others still using it");
1639                    }
1640                    return 1;
1641                }
1642                callTeardown = true;
1643            } else {
1644                if (DBG) {
1645                    log("stopUsingNetworkFeature: net " + networkType + ": " + feature +
1646                            " not a known feature - dropping");
1647                }
1648            }
1649        }
1650
1651        if (callTeardown) {
1652            if (DBG) {
1653                log("stopUsingNetworkFeature: teardown net " + networkType + ": " + feature);
1654            }
1655            tracker.teardown();
1656            return 1;
1657        } else {
1658            return -1;
1659        }
1660    }
1661
1662    /**
1663     * Check if the address falls into any of currently running VPN's route's.
1664     */
1665    private boolean isAddressUnderVpn(InetAddress address) {
1666        synchronized (mVpns) {
1667            synchronized (mRoutesLock) {
1668                int uid = UserHandle.getCallingUserId();
1669                Vpn vpn = mVpns.get(uid);
1670                if (vpn == null) {
1671                    return false;
1672                }
1673
1674                // Check if an exemption exists for this address.
1675                for (LinkAddress destination : mExemptAddresses) {
1676                    if (!NetworkUtils.addressTypeMatches(address, destination.getAddress())) {
1677                        continue;
1678                    }
1679
1680                    int prefix = destination.getPrefixLength();
1681                    InetAddress addrMasked = NetworkUtils.getNetworkPart(address, prefix);
1682                    InetAddress destMasked = NetworkUtils.getNetworkPart(destination.getAddress(),
1683                            prefix);
1684
1685                    if (addrMasked.equals(destMasked)) {
1686                        return false;
1687                    }
1688                }
1689
1690                // Finally check if the address is covered by the VPN.
1691                return vpn.isAddressCovered(address);
1692            }
1693        }
1694    }
1695
1696    /**
1697     * @deprecated use requestRouteToHostAddress instead
1698     *
1699     * Ensure that a network route exists to deliver traffic to the specified
1700     * host via the specified network interface.
1701     * @param networkType the type of the network over which traffic to the
1702     * specified host is to be routed
1703     * @param hostAddress the IP address of the host to which the route is
1704     * desired
1705     * @return {@code true} on success, {@code false} on failure
1706     */
1707    public boolean requestRouteToHost(int networkType, int hostAddress, String packageName) {
1708        InetAddress inetAddress = NetworkUtils.intToInetAddress(hostAddress);
1709
1710        if (inetAddress == null) {
1711            return false;
1712        }
1713
1714        return requestRouteToHostAddress(networkType, inetAddress.getAddress(), packageName);
1715    }
1716
1717    /**
1718     * Ensure that a network route exists to deliver traffic to the specified
1719     * host via the specified network interface.
1720     * @param networkType the type of the network over which traffic to the
1721     * specified host is to be routed
1722     * @param hostAddress the IP address of the host to which the route is
1723     * desired
1724     * @return {@code true} on success, {@code false} on failure
1725     */
1726    public boolean requestRouteToHostAddress(int networkType, byte[] hostAddress,
1727            String packageName) {
1728        enforceChangePermission();
1729        if (mProtectedNetworks.contains(networkType)) {
1730            enforceConnectivityInternalPermission();
1731        }
1732        boolean exempt;
1733        InetAddress addr;
1734        try {
1735            addr = InetAddress.getByAddress(hostAddress);
1736        } catch (UnknownHostException e) {
1737            if (DBG) log("requestRouteToHostAddress got " + e.toString());
1738            return false;
1739        }
1740        // System apps may request routes bypassing the VPN to keep other networks working.
1741        if (Binder.getCallingUid() == Process.SYSTEM_UID) {
1742            exempt = true;
1743        } else {
1744            mAppOpsManager.checkPackage(Binder.getCallingUid(), packageName);
1745            try {
1746                ApplicationInfo info = mContext.getPackageManager().getApplicationInfo(packageName,
1747                        0);
1748                exempt = (info.flags & ApplicationInfo.FLAG_SYSTEM) != 0;
1749            } catch (NameNotFoundException e) {
1750                throw new IllegalArgumentException("Failed to find calling package details", e);
1751            }
1752        }
1753
1754        // Non-exempt routeToHost's can only be added if the host is not covered by the VPN.
1755        // This can be either because the VPN's routes do not cover the destination or a
1756        // system application added an exemption that covers this destination.
1757        if (!exempt && isAddressUnderVpn(addr)) {
1758            return false;
1759        }
1760
1761        if (!ConnectivityManager.isNetworkTypeValid(networkType)) {
1762            if (DBG) log("requestRouteToHostAddress on invalid network: " + networkType);
1763            return false;
1764        }
1765
1766        NetworkAgentInfo nai = mLegacyTypeTracker.getNetworkForType(networkType);
1767        if (nai == null) {
1768            if (mLegacyTypeTracker.isTypeSupported(networkType) == false) {
1769                if (DBG) log("requestRouteToHostAddress on unsupported network: " + networkType);
1770            } else {
1771                if (DBG) log("requestRouteToHostAddress on down network: " + networkType);
1772            }
1773            return false;
1774        }
1775
1776        DetailedState netState = nai.networkInfo.getDetailedState();
1777
1778        if ((netState != DetailedState.CONNECTED &&
1779                netState != DetailedState.CAPTIVE_PORTAL_CHECK)) {
1780            if (VDBG) {
1781                log("requestRouteToHostAddress on down network "
1782                        + "(" + networkType + ") - dropped"
1783                        + " netState=" + netState);
1784            }
1785            return false;
1786        }
1787        final int uid = Binder.getCallingUid();
1788        final long token = Binder.clearCallingIdentity();
1789        try {
1790            LinkProperties lp = nai.linkProperties;
1791            boolean ok = modifyRouteToAddress(lp, addr, ADD, TO_DEFAULT_TABLE, exempt,
1792                    nai.network.netId, uid);
1793            if (DBG) log("requestRouteToHostAddress ok=" + ok);
1794            return ok;
1795        } finally {
1796            Binder.restoreCallingIdentity(token);
1797        }
1798    }
1799
1800    private boolean addRoute(LinkProperties p, RouteInfo r, boolean toDefaultTable,
1801            boolean exempt, int netId) {
1802        return modifyRoute(p, r, 0, ADD, toDefaultTable, exempt, netId, false, UID_UNUSED);
1803    }
1804
1805    private boolean removeRoute(LinkProperties p, RouteInfo r, boolean toDefaultTable, int netId) {
1806        return modifyRoute(p, r, 0, REMOVE, toDefaultTable, UNEXEMPT, netId, false, UID_UNUSED);
1807    }
1808
1809    private boolean modifyRouteToAddress(LinkProperties lp, InetAddress addr, boolean doAdd,
1810            boolean toDefaultTable, boolean exempt, int netId, int uid) {
1811        RouteInfo bestRoute = RouteInfo.selectBestRoute(lp.getAllRoutes(), addr);
1812        if (bestRoute == null) {
1813            bestRoute = RouteInfo.makeHostRoute(addr, lp.getInterfaceName());
1814        } else {
1815            String iface = bestRoute.getInterface();
1816            if (bestRoute.getGateway().equals(addr)) {
1817                // if there is no better route, add the implied hostroute for our gateway
1818                bestRoute = RouteInfo.makeHostRoute(addr, iface);
1819            } else {
1820                // if we will connect to this through another route, add a direct route
1821                // to it's gateway
1822                bestRoute = RouteInfo.makeHostRoute(addr, bestRoute.getGateway(), iface);
1823            }
1824        }
1825        return modifyRoute(lp, bestRoute, 0, doAdd, toDefaultTable, exempt, netId, true, uid);
1826    }
1827
1828    /*
1829     * TODO: Clean all this stuff up. Once we have UID-based routing, stuff will break due to
1830     *       incorrect tracking of mAddedRoutes, so a cleanup becomes necessary and urgent. But at
1831     *       the same time, there'll be no more need to track mAddedRoutes or mExemptAddresses,
1832     *       or even have the concept of an exempt address, or do things like "selectBestRoute", or
1833     *       determine "default" vs "secondary" table, etc., so the cleanup becomes possible.
1834     */
1835    private boolean modifyRoute(LinkProperties lp, RouteInfo r, int cycleCount, boolean doAdd,
1836            boolean toDefaultTable, boolean exempt, int netId, boolean legacy, int uid) {
1837        if ((lp == null) || (r == null)) {
1838            if (DBG) log("modifyRoute got unexpected null: " + lp + ", " + r);
1839            return false;
1840        }
1841
1842        if (cycleCount > MAX_HOSTROUTE_CYCLE_COUNT) {
1843            loge("Error modifying route - too much recursion");
1844            return false;
1845        }
1846
1847        String ifaceName = r.getInterface();
1848        if(ifaceName == null) {
1849            loge("Error modifying route - no interface name");
1850            return false;
1851        }
1852        if (r.hasGateway()) {
1853            RouteInfo bestRoute = RouteInfo.selectBestRoute(lp.getAllRoutes(), r.getGateway());
1854            if (bestRoute != null) {
1855                if (bestRoute.getGateway().equals(r.getGateway())) {
1856                    // if there is no better route, add the implied hostroute for our gateway
1857                    bestRoute = RouteInfo.makeHostRoute(r.getGateway(), ifaceName);
1858                } else {
1859                    // if we will connect to our gateway through another route, add a direct
1860                    // route to it's gateway
1861                    bestRoute = RouteInfo.makeHostRoute(r.getGateway(),
1862                                                        bestRoute.getGateway(),
1863                                                        ifaceName);
1864                }
1865                modifyRoute(lp, bestRoute, cycleCount+1, doAdd, toDefaultTable, exempt, netId,
1866                        legacy, uid);
1867            }
1868        }
1869        if (doAdd) {
1870            if (VDBG) log("Adding " + r + " for interface " + ifaceName);
1871            try {
1872                if (toDefaultTable) {
1873                    synchronized (mRoutesLock) {
1874                        // only track default table - only one apps can effect
1875                        mAddedRoutes.add(r);
1876                        if (legacy) {
1877                            mNetd.addLegacyRouteForNetId(netId, r, uid);
1878                        } else {
1879                            mNetd.addRoute(netId, r);
1880                        }
1881                        if (exempt) {
1882                            LinkAddress dest = r.getDestinationLinkAddress();
1883                            if (!mExemptAddresses.contains(dest)) {
1884                                mNetd.setHostExemption(dest);
1885                                mExemptAddresses.add(dest);
1886                            }
1887                        }
1888                    }
1889                } else {
1890                    if (legacy) {
1891                        mNetd.addLegacyRouteForNetId(netId, r, uid);
1892                    } else {
1893                        mNetd.addRoute(netId, r);
1894                    }
1895                }
1896            } catch (Exception e) {
1897                // never crash - catch them all
1898                if (DBG) loge("Exception trying to add a route: " + e);
1899                return false;
1900            }
1901        } else {
1902            // if we remove this one and there are no more like it, then refcount==0 and
1903            // we can remove it from the table
1904            if (toDefaultTable) {
1905                synchronized (mRoutesLock) {
1906                    mAddedRoutes.remove(r);
1907                    if (mAddedRoutes.contains(r) == false) {
1908                        if (VDBG) log("Removing " + r + " for interface " + ifaceName);
1909                        try {
1910                            if (legacy) {
1911                                mNetd.removeLegacyRouteForNetId(netId, r, uid);
1912                            } else {
1913                                mNetd.removeRoute(netId, r);
1914                            }
1915                            LinkAddress dest = r.getDestinationLinkAddress();
1916                            if (mExemptAddresses.contains(dest)) {
1917                                mNetd.clearHostExemption(dest);
1918                                mExemptAddresses.remove(dest);
1919                            }
1920                        } catch (Exception e) {
1921                            // never crash - catch them all
1922                            if (VDBG) loge("Exception trying to remove a route: " + e);
1923                            return false;
1924                        }
1925                    } else {
1926                        if (VDBG) log("not removing " + r + " as it's still in use");
1927                    }
1928                }
1929            } else {
1930                if (VDBG) log("Removing " + r + " for interface " + ifaceName);
1931                try {
1932                    if (legacy) {
1933                        mNetd.removeLegacyRouteForNetId(netId, r, uid);
1934                    } else {
1935                        mNetd.removeRoute(netId, r);
1936                    }
1937                } catch (Exception e) {
1938                    // never crash - catch them all
1939                    if (VDBG) loge("Exception trying to remove a route: " + e);
1940                    return false;
1941                }
1942            }
1943        }
1944        return true;
1945    }
1946
1947    public void setDataDependency(int networkType, boolean met) {
1948        enforceConnectivityInternalPermission();
1949
1950        mHandler.sendMessage(mHandler.obtainMessage(EVENT_SET_DEPENDENCY_MET,
1951                (met ? ENABLED : DISABLED), networkType));
1952    }
1953
1954    private void handleSetDependencyMet(int networkType, boolean met) {
1955        if (mNetTrackers[networkType] != null) {
1956            if (DBG) {
1957                log("handleSetDependencyMet(" + networkType + ", " + met + ")");
1958            }
1959            mNetTrackers[networkType].setDependencyMet(met);
1960        }
1961    }
1962
1963    private INetworkPolicyListener mPolicyListener = new INetworkPolicyListener.Stub() {
1964        @Override
1965        public void onUidRulesChanged(int uid, int uidRules) {
1966            // caller is NPMS, since we only register with them
1967            if (LOGD_RULES) {
1968                log("onUidRulesChanged(uid=" + uid + ", uidRules=" + uidRules + ")");
1969            }
1970
1971            synchronized (mRulesLock) {
1972                // skip update when we've already applied rules
1973                final int oldRules = mUidRules.get(uid, RULE_ALLOW_ALL);
1974                if (oldRules == uidRules) return;
1975
1976                mUidRules.put(uid, uidRules);
1977            }
1978
1979            // TODO: notify UID when it has requested targeted updates
1980        }
1981
1982        @Override
1983        public void onMeteredIfacesChanged(String[] meteredIfaces) {
1984            // caller is NPMS, since we only register with them
1985            if (LOGD_RULES) {
1986                log("onMeteredIfacesChanged(ifaces=" + Arrays.toString(meteredIfaces) + ")");
1987            }
1988
1989            synchronized (mRulesLock) {
1990                mMeteredIfaces.clear();
1991                for (String iface : meteredIfaces) {
1992                    mMeteredIfaces.add(iface);
1993                }
1994            }
1995        }
1996
1997        @Override
1998        public void onRestrictBackgroundChanged(boolean restrictBackground) {
1999            // caller is NPMS, since we only register with them
2000            if (LOGD_RULES) {
2001                log("onRestrictBackgroundChanged(restrictBackground=" + restrictBackground + ")");
2002            }
2003
2004            // kick off connectivity change broadcast for active network, since
2005            // global background policy change is radical.
2006            final int networkType = mActiveDefaultNetwork;
2007            if (isNetworkTypeValid(networkType)) {
2008                final NetworkStateTracker tracker = mNetTrackers[networkType];
2009                if (tracker != null) {
2010                    final NetworkInfo info = tracker.getNetworkInfo();
2011                    if (info != null && info.isConnected()) {
2012                        sendConnectedBroadcast(info);
2013                    }
2014                }
2015            }
2016        }
2017    };
2018
2019    @Override
2020    public void setPolicyDataEnable(int networkType, boolean enabled) {
2021        // only someone like NPMS should only be calling us
2022        mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
2023
2024        mHandler.sendMessage(mHandler.obtainMessage(
2025                EVENT_SET_POLICY_DATA_ENABLE, networkType, (enabled ? ENABLED : DISABLED)));
2026    }
2027
2028    private void handleSetPolicyDataEnable(int networkType, boolean enabled) {
2029   // TODO - handle this passing to factories
2030//        if (isNetworkTypeValid(networkType)) {
2031//            final NetworkStateTracker tracker = mNetTrackers[networkType];
2032//            if (tracker != null) {
2033//                tracker.setPolicyDataEnable(enabled);
2034//            }
2035//        }
2036    }
2037
2038    private void enforceAccessPermission() {
2039        mContext.enforceCallingOrSelfPermission(
2040                android.Manifest.permission.ACCESS_NETWORK_STATE,
2041                "ConnectivityService");
2042    }
2043
2044    private void enforceChangePermission() {
2045        mContext.enforceCallingOrSelfPermission(
2046                android.Manifest.permission.CHANGE_NETWORK_STATE,
2047                "ConnectivityService");
2048    }
2049
2050    // TODO Make this a special check when it goes public
2051    private void enforceTetherChangePermission() {
2052        mContext.enforceCallingOrSelfPermission(
2053                android.Manifest.permission.CHANGE_NETWORK_STATE,
2054                "ConnectivityService");
2055    }
2056
2057    private void enforceTetherAccessPermission() {
2058        mContext.enforceCallingOrSelfPermission(
2059                android.Manifest.permission.ACCESS_NETWORK_STATE,
2060                "ConnectivityService");
2061    }
2062
2063    private void enforceConnectivityInternalPermission() {
2064        mContext.enforceCallingOrSelfPermission(
2065                android.Manifest.permission.CONNECTIVITY_INTERNAL,
2066                "ConnectivityService");
2067    }
2068
2069    private void enforceMarkNetworkSocketPermission() {
2070        //Media server special case
2071        if (Binder.getCallingUid() == Process.MEDIA_UID) {
2072            return;
2073        }
2074        mContext.enforceCallingOrSelfPermission(
2075                android.Manifest.permission.MARK_NETWORK_SOCKET,
2076                "ConnectivityService");
2077    }
2078
2079    /**
2080     * Handle a {@code DISCONNECTED} event. If this pertains to the non-active
2081     * network, we ignore it. If it is for the active network, we send out a
2082     * broadcast. But first, we check whether it might be possible to connect
2083     * to a different network.
2084     * @param info the {@code NetworkInfo} for the network
2085     */
2086    private void handleDisconnect(NetworkInfo info) {
2087
2088        int prevNetType = info.getType();
2089
2090        mNetTrackers[prevNetType].setTeardownRequested(false);
2091        int thisNetId = mNetTrackers[prevNetType].getNetwork().netId;
2092
2093        // Remove idletimer previously setup in {@code handleConnect}
2094// Already in place in new function. This is dead code.
2095//        if (mNetConfigs[prevNetType].isDefault()) {
2096//            removeDataActivityTracking(prevNetType);
2097//        }
2098
2099        /*
2100         * If the disconnected network is not the active one, then don't report
2101         * this as a loss of connectivity. What probably happened is that we're
2102         * getting the disconnect for a network that we explicitly disabled
2103         * in accordance with network preference policies.
2104         */
2105        if (!mNetConfigs[prevNetType].isDefault()) {
2106            List<Integer> pids = mNetRequestersPids[prevNetType];
2107            for (Integer pid : pids) {
2108                // will remove them because the net's no longer connected
2109                // need to do this now as only now do we know the pids and
2110                // can properly null things that are no longer referenced.
2111                reassessPidDns(pid.intValue(), false);
2112            }
2113        }
2114
2115        Intent intent = new Intent(ConnectivityManager.CONNECTIVITY_ACTION);
2116        intent.putExtra(ConnectivityManager.EXTRA_NETWORK_INFO, new NetworkInfo(info));
2117        intent.putExtra(ConnectivityManager.EXTRA_NETWORK_TYPE, info.getType());
2118        if (info.isFailover()) {
2119            intent.putExtra(ConnectivityManager.EXTRA_IS_FAILOVER, true);
2120            info.setFailover(false);
2121        }
2122        if (info.getReason() != null) {
2123            intent.putExtra(ConnectivityManager.EXTRA_REASON, info.getReason());
2124        }
2125        if (info.getExtraInfo() != null) {
2126            intent.putExtra(ConnectivityManager.EXTRA_EXTRA_INFO,
2127                    info.getExtraInfo());
2128        }
2129
2130        if (mNetConfigs[prevNetType].isDefault()) {
2131            tryFailover(prevNetType);
2132            if (mActiveDefaultNetwork != -1) {
2133                NetworkInfo switchTo = mNetTrackers[mActiveDefaultNetwork].getNetworkInfo();
2134                intent.putExtra(ConnectivityManager.EXTRA_OTHER_NETWORK_INFO, switchTo);
2135            } else {
2136                mDefaultInetConditionPublished = 0; // we're not connected anymore
2137                intent.putExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, true);
2138            }
2139        }
2140        intent.putExtra(ConnectivityManager.EXTRA_INET_CONDITION, mDefaultInetConditionPublished);
2141
2142        // Reset interface if no other connections are using the same interface
2143        boolean doReset = true;
2144        LinkProperties linkProperties = mNetTrackers[prevNetType].getLinkProperties();
2145        if (linkProperties != null) {
2146            String oldIface = linkProperties.getInterfaceName();
2147            if (TextUtils.isEmpty(oldIface) == false) {
2148                for (NetworkStateTracker networkStateTracker : mNetTrackers) {
2149                    if (networkStateTracker == null) continue;
2150                    NetworkInfo networkInfo = networkStateTracker.getNetworkInfo();
2151                    if (networkInfo.isConnected() && networkInfo.getType() != prevNetType) {
2152                        LinkProperties l = networkStateTracker.getLinkProperties();
2153                        if (l == null) continue;
2154                        if (oldIface.equals(l.getInterfaceName())) {
2155                            doReset = false;
2156                            break;
2157                        }
2158                    }
2159                }
2160            }
2161        }
2162
2163        // do this before we broadcast the change
2164// Already done in new function. This is dead code.
2165//        handleConnectivityChange(prevNetType, doReset);
2166
2167        final Intent immediateIntent = new Intent(intent);
2168        immediateIntent.setAction(CONNECTIVITY_ACTION_IMMEDIATE);
2169        sendStickyBroadcast(immediateIntent);
2170        sendStickyBroadcastDelayed(intent, getConnectivityChangeDelay());
2171        /*
2172         * If the failover network is already connected, then immediately send
2173         * out a followup broadcast indicating successful failover
2174         */
2175        if (mActiveDefaultNetwork != -1) {
2176            sendConnectedBroadcastDelayed(mNetTrackers[mActiveDefaultNetwork].getNetworkInfo(),
2177                    getConnectivityChangeDelay());
2178        }
2179        try {
2180//            mNetd.removeNetwork(thisNetId);
2181        } catch (Exception e) {
2182            loge("Exception removing network: " + e);
2183        } finally {
2184            mNetTrackers[prevNetType].setNetId(INVALID_NET_ID);
2185        }
2186    }
2187
2188    private void tryFailover(int prevNetType) {
2189        /*
2190         * If this is a default network, check if other defaults are available.
2191         * Try to reconnect on all available and let them hash it out when
2192         * more than one connects.
2193         */
2194        if (mNetConfigs[prevNetType].isDefault()) {
2195            if (mActiveDefaultNetwork == prevNetType) {
2196                if (DBG) {
2197                    log("tryFailover: set mActiveDefaultNetwork=-1, prevNetType=" + prevNetType);
2198                }
2199                mActiveDefaultNetwork = -1;
2200                try {
2201                    mNetd.clearDefaultNetId();
2202                } catch (Exception e) {
2203                    loge("Exception clearing default network :" + e);
2204                }
2205            }
2206
2207            // don't signal a reconnect for anything lower or equal priority than our
2208            // current connected default
2209            // TODO - don't filter by priority now - nice optimization but risky
2210//            int currentPriority = -1;
2211//            if (mActiveDefaultNetwork != -1) {
2212//                currentPriority = mNetConfigs[mActiveDefaultNetwork].mPriority;
2213//            }
2214
2215            for (int checkType=0; checkType <= ConnectivityManager.MAX_NETWORK_TYPE; checkType++) {
2216                if (checkType == prevNetType) continue;
2217                if (mNetConfigs[checkType] == null) continue;
2218                if (!mNetConfigs[checkType].isDefault()) continue;
2219                if (mNetTrackers[checkType] == null) continue;
2220
2221// Enabling the isAvailable() optimization caused mobile to not get
2222// selected if it was in the middle of error handling. Specifically
2223// a moble connection that took 30 seconds to complete the DEACTIVATE_DATA_CALL
2224// would not be available and we wouldn't get connected to anything.
2225// So removing the isAvailable() optimization below for now. TODO: This
2226// optimization should work and we need to investigate why it doesn't work.
2227// This could be related to how DEACTIVATE_DATA_CALL is reporting its
2228// complete before it is really complete.
2229
2230//                if (!mNetTrackers[checkType].isAvailable()) continue;
2231
2232//                if (currentPriority >= mNetConfigs[checkType].mPriority) continue;
2233
2234                NetworkStateTracker checkTracker = mNetTrackers[checkType];
2235                NetworkInfo checkInfo = checkTracker.getNetworkInfo();
2236                if (!checkInfo.isConnectedOrConnecting() || checkTracker.isTeardownRequested()) {
2237                    checkInfo.setFailover(true);
2238                    checkTracker.reconnect();
2239                }
2240                if (DBG) log("Attempting to switch to " + checkInfo.getTypeName());
2241            }
2242        }
2243    }
2244
2245    public void sendConnectedBroadcast(NetworkInfo info) {
2246        enforceConnectivityInternalPermission();
2247        sendGeneralBroadcast(info, CONNECTIVITY_ACTION_IMMEDIATE);
2248        sendGeneralBroadcast(info, CONNECTIVITY_ACTION);
2249    }
2250
2251    private void sendConnectedBroadcastDelayed(NetworkInfo info, int delayMs) {
2252        sendGeneralBroadcast(info, CONNECTIVITY_ACTION_IMMEDIATE);
2253        sendGeneralBroadcastDelayed(info, CONNECTIVITY_ACTION, delayMs);
2254    }
2255
2256    private void sendInetConditionBroadcast(NetworkInfo info) {
2257        sendGeneralBroadcast(info, ConnectivityManager.INET_CONDITION_ACTION);
2258    }
2259
2260    private Intent makeGeneralIntent(NetworkInfo info, String bcastType) {
2261        if (mLockdownTracker != null) {
2262            info = mLockdownTracker.augmentNetworkInfo(info);
2263        }
2264
2265        Intent intent = new Intent(bcastType);
2266        intent.putExtra(ConnectivityManager.EXTRA_NETWORK_INFO, new NetworkInfo(info));
2267        intent.putExtra(ConnectivityManager.EXTRA_NETWORK_TYPE, info.getType());
2268        if (info.isFailover()) {
2269            intent.putExtra(ConnectivityManager.EXTRA_IS_FAILOVER, true);
2270            info.setFailover(false);
2271        }
2272        if (info.getReason() != null) {
2273            intent.putExtra(ConnectivityManager.EXTRA_REASON, info.getReason());
2274        }
2275        if (info.getExtraInfo() != null) {
2276            intent.putExtra(ConnectivityManager.EXTRA_EXTRA_INFO,
2277                    info.getExtraInfo());
2278        }
2279        intent.putExtra(ConnectivityManager.EXTRA_INET_CONDITION, mDefaultInetConditionPublished);
2280        return intent;
2281    }
2282
2283    private void sendGeneralBroadcast(NetworkInfo info, String bcastType) {
2284        sendStickyBroadcast(makeGeneralIntent(info, bcastType));
2285    }
2286
2287    private void sendGeneralBroadcastDelayed(NetworkInfo info, String bcastType, int delayMs) {
2288        sendStickyBroadcastDelayed(makeGeneralIntent(info, bcastType), delayMs);
2289    }
2290
2291    private void sendDataActivityBroadcast(int deviceType, boolean active, long tsNanos) {
2292        Intent intent = new Intent(ConnectivityManager.ACTION_DATA_ACTIVITY_CHANGE);
2293        intent.putExtra(ConnectivityManager.EXTRA_DEVICE_TYPE, deviceType);
2294        intent.putExtra(ConnectivityManager.EXTRA_IS_ACTIVE, active);
2295        intent.putExtra(ConnectivityManager.EXTRA_REALTIME_NS, tsNanos);
2296        final long ident = Binder.clearCallingIdentity();
2297        try {
2298            mContext.sendOrderedBroadcastAsUser(intent, UserHandle.ALL,
2299                    RECEIVE_DATA_ACTIVITY_CHANGE, null, null, 0, null, null);
2300        } finally {
2301            Binder.restoreCallingIdentity(ident);
2302        }
2303    }
2304
2305    private void sendStickyBroadcast(Intent intent) {
2306        synchronized(this) {
2307            if (!mSystemReady) {
2308                mInitialBroadcast = new Intent(intent);
2309            }
2310            intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
2311            if (VDBG) {
2312                log("sendStickyBroadcast: action=" + intent.getAction());
2313            }
2314
2315            final long ident = Binder.clearCallingIdentity();
2316            try {
2317                mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
2318            } finally {
2319                Binder.restoreCallingIdentity(ident);
2320            }
2321        }
2322    }
2323
2324    private void sendStickyBroadcastDelayed(Intent intent, int delayMs) {
2325        if (delayMs <= 0) {
2326            sendStickyBroadcast(intent);
2327        } else {
2328            if (VDBG) {
2329                log("sendStickyBroadcastDelayed: delayMs=" + delayMs + ", action="
2330                        + intent.getAction());
2331            }
2332            mHandler.sendMessageDelayed(mHandler.obtainMessage(
2333                    EVENT_SEND_STICKY_BROADCAST_INTENT, intent), delayMs);
2334        }
2335    }
2336
2337    void systemReady() {
2338        mCaptivePortalTracker = CaptivePortalTracker.makeCaptivePortalTracker(mContext, this);
2339        loadGlobalProxy();
2340
2341        synchronized(this) {
2342            mSystemReady = true;
2343            if (mInitialBroadcast != null) {
2344                mContext.sendStickyBroadcastAsUser(mInitialBroadcast, UserHandle.ALL);
2345                mInitialBroadcast = null;
2346            }
2347        }
2348        // load the global proxy at startup
2349        mHandler.sendMessage(mHandler.obtainMessage(EVENT_APPLY_GLOBAL_HTTP_PROXY));
2350
2351        // Try bringing up tracker, but if KeyStore isn't ready yet, wait
2352        // for user to unlock device.
2353        if (!updateLockdownVpn()) {
2354            final IntentFilter filter = new IntentFilter(Intent.ACTION_USER_PRESENT);
2355            mContext.registerReceiver(mUserPresentReceiver, filter);
2356        }
2357    }
2358
2359    private BroadcastReceiver mUserPresentReceiver = new BroadcastReceiver() {
2360        @Override
2361        public void onReceive(Context context, Intent intent) {
2362            // Try creating lockdown tracker, since user present usually means
2363            // unlocked keystore.
2364            if (updateLockdownVpn()) {
2365                mContext.unregisterReceiver(this);
2366            }
2367        }
2368    };
2369
2370    private boolean isNewNetTypePreferredOverCurrentNetType(int type) {
2371        if (((type != mNetworkPreference)
2372                      && (mNetConfigs[mActiveDefaultNetwork].priority > mNetConfigs[type].priority))
2373                   || (mNetworkPreference == mActiveDefaultNetwork)) {
2374            return false;
2375        }
2376        return true;
2377    }
2378
2379    private void handleConnect(NetworkInfo info) {
2380        final int newNetType = info.getType();
2381
2382        // snapshot isFailover, because sendConnectedBroadcast() resets it
2383        boolean isFailover = info.isFailover();
2384        final NetworkStateTracker thisNet = mNetTrackers[newNetType];
2385        final String thisIface = thisNet.getLinkProperties().getInterfaceName();
2386
2387        if (VDBG) {
2388            log("handleConnect: E newNetType=" + newNetType + " thisIface=" + thisIface
2389                    + " isFailover" + isFailover);
2390        }
2391
2392        // if this is a default net and other default is running
2393        // kill the one not preferred
2394        if (mNetConfigs[newNetType].isDefault()) {
2395            if (mActiveDefaultNetwork != -1 && mActiveDefaultNetwork != newNetType) {
2396                if (isNewNetTypePreferredOverCurrentNetType(newNetType)) {
2397                   String teardownPolicy = SystemProperties.get("net.teardownPolicy");
2398                   if (TextUtils.equals(teardownPolicy, "keep") == false) {
2399                        // tear down the other
2400                        NetworkStateTracker otherNet =
2401                                mNetTrackers[mActiveDefaultNetwork];
2402                        if (DBG) {
2403                            log("Policy requires " + otherNet.getNetworkInfo().getTypeName() +
2404                                " teardown");
2405                        }
2406                        if (!teardown(otherNet)) {
2407                            loge("Network declined teardown request");
2408                            teardown(thisNet);
2409                            return;
2410                        }
2411                    } else {
2412                        //TODO - remove
2413                        loge("network teardown skipped due to net.teardownPolicy setting");
2414                    }
2415                } else {
2416                       // don't accept this one
2417                        if (VDBG) {
2418                            log("Not broadcasting CONNECT_ACTION " +
2419                                "to torn down network " + info.getTypeName());
2420                        }
2421                        teardown(thisNet);
2422                        return;
2423                }
2424            }
2425            int thisNetId = nextNetId();
2426            thisNet.setNetId(thisNetId);
2427            try {
2428//                mNetd.createNetwork(thisNetId, thisIface);
2429            } catch (Exception e) {
2430                loge("Exception creating network :" + e);
2431                teardown(thisNet);
2432                return;
2433            }
2434// Already in place in new function. This is dead code.
2435//            setupDataActivityTracking(newNetType);
2436            synchronized (ConnectivityService.this) {
2437                // have a new default network, release the transition wakelock in a second
2438                // if it's held.  The second pause is to allow apps to reconnect over the
2439                // new network
2440                if (mNetTransitionWakeLock.isHeld()) {
2441                    mHandler.sendMessageDelayed(mHandler.obtainMessage(
2442                            EVENT_CLEAR_NET_TRANSITION_WAKELOCK,
2443                            mNetTransitionWakeLockSerialNumber, 0),
2444                            1000);
2445                }
2446            }
2447            mActiveDefaultNetwork = newNetType;
2448            try {
2449                mNetd.setDefaultNetId(thisNetId);
2450            } catch (Exception e) {
2451                loge("Exception setting default network :" + e);
2452            }
2453            // this will cause us to come up initially as unconnected and switching
2454            // to connected after our normal pause unless somebody reports us as reall
2455            // disconnected
2456            mDefaultInetConditionPublished = 0;
2457            mDefaultConnectionSequence++;
2458            mInetConditionChangeInFlight = false;
2459            // Don't do this - if we never sign in stay, grey
2460            //reportNetworkCondition(mActiveDefaultNetwork, 100);
2461            updateNetworkSettings(thisNet);
2462        } else {
2463            int thisNetId = nextNetId();
2464            thisNet.setNetId(thisNetId);
2465            try {
2466//                mNetd.createNetwork(thisNetId, thisIface);
2467            } catch (Exception e) {
2468                loge("Exception creating network :" + e);
2469                teardown(thisNet);
2470                return;
2471            }
2472        }
2473        thisNet.setTeardownRequested(false);
2474// Already in place in new function. This is dead code.
2475//        updateMtuSizeSettings(thisNet);
2476//        handleConnectivityChange(newNetType, false);
2477        sendConnectedBroadcastDelayed(info, getConnectivityChangeDelay());
2478
2479        // notify battery stats service about this network
2480        if (thisIface != null) {
2481            try {
2482                BatteryStatsService.getService().noteNetworkInterfaceType(thisIface, newNetType);
2483            } catch (RemoteException e) {
2484                // ignored; service lives in system_server
2485            }
2486        }
2487    }
2488
2489    /** @hide */
2490    @Override
2491    public void captivePortalCheckCompleted(NetworkInfo info, boolean isCaptivePortal) {
2492        enforceConnectivityInternalPermission();
2493        if (DBG) log("captivePortalCheckCompleted: ni=" + info + " captive=" + isCaptivePortal);
2494//        mNetTrackers[info.getType()].captivePortalCheckCompleted(isCaptivePortal);
2495    }
2496
2497    /**
2498     * Setup data activity tracking for the given network.
2499     *
2500     * Every {@code setupDataActivityTracking} should be paired with a
2501     * {@link #removeDataActivityTracking} for cleanup.
2502     */
2503    private void setupDataActivityTracking(NetworkAgentInfo networkAgent) {
2504        final String iface = networkAgent.linkProperties.getInterfaceName();
2505
2506        final int timeout;
2507        int type = ConnectivityManager.TYPE_NONE;
2508
2509        if (networkAgent.networkCapabilities.hasTransport(
2510                NetworkCapabilities.TRANSPORT_CELLULAR)) {
2511            timeout = Settings.Global.getInt(mContext.getContentResolver(),
2512                                             Settings.Global.DATA_ACTIVITY_TIMEOUT_MOBILE,
2513                                             5);
2514            type = ConnectivityManager.TYPE_MOBILE;
2515        } else if (networkAgent.networkCapabilities.hasTransport(
2516                NetworkCapabilities.TRANSPORT_WIFI)) {
2517            timeout = Settings.Global.getInt(mContext.getContentResolver(),
2518                                             Settings.Global.DATA_ACTIVITY_TIMEOUT_WIFI,
2519                                             0);
2520            type = ConnectivityManager.TYPE_WIFI;
2521        } else {
2522            // do not track any other networks
2523            timeout = 0;
2524        }
2525
2526        if (timeout > 0 && iface != null && type != ConnectivityManager.TYPE_NONE) {
2527            try {
2528                mNetd.addIdleTimer(iface, timeout, type);
2529            } catch (Exception e) {
2530                // You shall not crash!
2531                loge("Exception in setupDataActivityTracking " + e);
2532            }
2533        }
2534    }
2535
2536    /**
2537     * Remove data activity tracking when network disconnects.
2538     */
2539    private void removeDataActivityTracking(NetworkAgentInfo networkAgent) {
2540        final String iface = networkAgent.linkProperties.getInterfaceName();
2541        final NetworkCapabilities caps = networkAgent.networkCapabilities;
2542
2543        if (iface != null && (caps.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) ||
2544                              caps.hasTransport(NetworkCapabilities.TRANSPORT_WIFI))) {
2545            try {
2546                // the call fails silently if no idletimer setup for this interface
2547                mNetd.removeIdleTimer(iface);
2548            } catch (Exception e) {
2549                loge("Exception in removeDataActivityTracking " + e);
2550            }
2551        }
2552    }
2553
2554    /**
2555     * After a change in the connectivity state of a network. We're mainly
2556     * concerned with making sure that the list of DNS servers is set up
2557     * according to which networks are connected, and ensuring that the
2558     * right routing table entries exist.
2559     *
2560     * TODO - delete when we're sure all this functionallity is captured.
2561     */
2562    private void handleConnectivityChange(int netType, LinkProperties curLp, boolean doReset) {
2563        int resetMask = doReset ? NetworkUtils.RESET_ALL_ADDRESSES : 0;
2564        boolean exempt = ConnectivityManager.isNetworkTypeExempt(netType);
2565        if (VDBG) {
2566            log("handleConnectivityChange: netType=" + netType + " doReset=" + doReset
2567                    + " resetMask=" + resetMask);
2568        }
2569
2570        /*
2571         * If a non-default network is enabled, add the host routes that
2572         * will allow it's DNS servers to be accessed.
2573         */
2574        handleDnsConfigurationChange(netType);
2575
2576        LinkProperties newLp = null;
2577
2578        if (mNetTrackers[netType].getNetworkInfo().isConnected()) {
2579            newLp = mNetTrackers[netType].getLinkProperties();
2580            if (VDBG) {
2581                log("handleConnectivityChange: changed linkProperty[" + netType + "]:" +
2582                        " doReset=" + doReset + " resetMask=" + resetMask +
2583                        "\n   curLp=" + curLp +
2584                        "\n   newLp=" + newLp);
2585            }
2586
2587            if (curLp != null) {
2588                if (curLp.isIdenticalInterfaceName(newLp)) {
2589                    CompareResult<LinkAddress> car = curLp.compareAddresses(newLp);
2590                    if ((car.removed.size() != 0) || (car.added.size() != 0)) {
2591                        for (LinkAddress linkAddr : car.removed) {
2592                            if (linkAddr.getAddress() instanceof Inet4Address) {
2593                                resetMask |= NetworkUtils.RESET_IPV4_ADDRESSES;
2594                            }
2595                            if (linkAddr.getAddress() instanceof Inet6Address) {
2596                                resetMask |= NetworkUtils.RESET_IPV6_ADDRESSES;
2597                            }
2598                        }
2599                        if (DBG) {
2600                            log("handleConnectivityChange: addresses changed" +
2601                                    " linkProperty[" + netType + "]:" + " resetMask=" + resetMask +
2602                                    "\n   car=" + car);
2603                        }
2604                    } else {
2605                        if (VDBG) {
2606                            log("handleConnectivityChange: addresses are the same reset per" +
2607                                   " doReset linkProperty[" + netType + "]:" +
2608                                   " resetMask=" + resetMask);
2609                        }
2610                    }
2611                } else {
2612                    resetMask = NetworkUtils.RESET_ALL_ADDRESSES;
2613                    if (DBG) {
2614                        log("handleConnectivityChange: interface not not equivalent reset both" +
2615                                " linkProperty[" + netType + "]:" +
2616                                " resetMask=" + resetMask);
2617                    }
2618                }
2619            }
2620            if (mNetConfigs[netType].isDefault()) {
2621                handleApplyDefaultProxy(newLp.getHttpProxy());
2622            }
2623        } else {
2624            if (VDBG) {
2625                log("handleConnectivityChange: changed linkProperty[" + netType + "]:" +
2626                        " doReset=" + doReset + " resetMask=" + resetMask +
2627                        "\n  curLp=" + curLp +
2628                        "\n  newLp= null");
2629            }
2630        }
2631        mCurrentLinkProperties[netType] = newLp;
2632        boolean resetDns = updateRoutes(newLp, curLp, mNetConfigs[netType].isDefault(), exempt,
2633                                        mNetTrackers[netType].getNetwork().netId);
2634
2635        if (resetMask != 0 || resetDns) {
2636            if (VDBG) log("handleConnectivityChange: resetting");
2637            if (curLp != null) {
2638                if (VDBG) log("handleConnectivityChange: resetting curLp=" + curLp);
2639                for (String iface : curLp.getAllInterfaceNames()) {
2640                    if (TextUtils.isEmpty(iface) == false) {
2641                        if (resetMask != 0) {
2642                            if (DBG) log("resetConnections(" + iface + ", " + resetMask + ")");
2643                            NetworkUtils.resetConnections(iface, resetMask);
2644
2645                            // Tell VPN the interface is down. It is a temporary
2646                            // but effective fix to make VPN aware of the change.
2647                            if ((resetMask & NetworkUtils.RESET_IPV4_ADDRESSES) != 0) {
2648                                synchronized(mVpns) {
2649                                    for (int i = 0; i < mVpns.size(); i++) {
2650                                        mVpns.valueAt(i).interfaceStatusChanged(iface, false);
2651                                    }
2652                                }
2653                            }
2654                        }
2655                    } else {
2656                        loge("Can't reset connection for type "+netType);
2657                    }
2658                }
2659                if (resetDns) {
2660                    flushVmDnsCache();
2661                    if (VDBG) log("resetting DNS cache for type " + netType);
2662                    try {
2663                        mNetd.flushNetworkDnsCache(mNetTrackers[netType].getNetwork().netId);
2664                    } catch (Exception e) {
2665                        // never crash - catch them all
2666                        if (DBG) loge("Exception resetting dns cache: " + e);
2667                    }
2668                }
2669            }
2670        }
2671
2672        // TODO: Temporary notifying upstread change to Tethering.
2673        //       @see bug/4455071
2674        /** Notify TetheringService if interface name has been changed. */
2675        if (TextUtils.equals(mNetTrackers[netType].getNetworkInfo().getReason(),
2676                             PhoneConstants.REASON_LINK_PROPERTIES_CHANGED)) {
2677            if (isTetheringSupported()) {
2678                mTethering.handleTetherIfaceChange();
2679            }
2680        }
2681    }
2682
2683    /**
2684     * Add and remove routes using the old properties (null if not previously connected),
2685     * new properties (null if becoming disconnected).  May even be double null, which
2686     * is a noop.
2687     * Uses isLinkDefault to determine if default routes should be set or conversely if
2688     * host routes should be set to the dns servers
2689     * returns a boolean indicating the routes changed
2690     */
2691    private boolean updateRoutes(LinkProperties newLp, LinkProperties curLp,
2692            boolean isLinkDefault, boolean exempt, int netId) {
2693        Collection<RouteInfo> routesToAdd = null;
2694        CompareResult<InetAddress> dnsDiff = new CompareResult<InetAddress>();
2695        CompareResult<RouteInfo> routeDiff = new CompareResult<RouteInfo>();
2696        if (curLp != null) {
2697            // check for the delta between the current set and the new
2698            routeDiff = curLp.compareAllRoutes(newLp);
2699            dnsDiff = curLp.compareDnses(newLp);
2700        } else if (newLp != null) {
2701            routeDiff.added = newLp.getAllRoutes();
2702            dnsDiff.added = newLp.getDnsServers();
2703        }
2704
2705        boolean routesChanged = (routeDiff.removed.size() != 0 || routeDiff.added.size() != 0);
2706
2707        for (RouteInfo r : routeDiff.removed) {
2708            if (isLinkDefault || ! r.isDefaultRoute()) {
2709                if (VDBG) log("updateRoutes: default remove route r=" + r);
2710                removeRoute(curLp, r, TO_DEFAULT_TABLE, netId);
2711            }
2712            if (isLinkDefault == false) {
2713                // remove from a secondary route table
2714                removeRoute(curLp, r, TO_SECONDARY_TABLE, netId);
2715            }
2716        }
2717
2718        for (RouteInfo r :  routeDiff.added) {
2719            if (isLinkDefault || ! r.isDefaultRoute()) {
2720                addRoute(newLp, r, TO_DEFAULT_TABLE, exempt, netId);
2721            } else {
2722                // add to a secondary route table
2723                addRoute(newLp, r, TO_SECONDARY_TABLE, UNEXEMPT, netId);
2724
2725                // many radios add a default route even when we don't want one.
2726                // remove the default route unless somebody else has asked for it
2727                String ifaceName = newLp.getInterfaceName();
2728                synchronized (mRoutesLock) {
2729                    if (!TextUtils.isEmpty(ifaceName) && !mAddedRoutes.contains(r)) {
2730                        if (VDBG) log("Removing " + r + " for interface " + ifaceName);
2731                        try {
2732                            mNetd.removeRoute(netId, r);
2733                        } catch (Exception e) {
2734                            // never crash - catch them all
2735                            if (DBG) loge("Exception trying to remove a route: " + e);
2736                        }
2737                    }
2738                }
2739            }
2740        }
2741
2742        return routesChanged;
2743    }
2744
2745    /**
2746     * Reads the network specific MTU size from reources.
2747     * and set it on it's iface.
2748     */
2749    private void updateMtu(LinkProperties newLp, LinkProperties oldLp) {
2750        final String iface = newLp.getInterfaceName();
2751        final int mtu = newLp.getMtu();
2752        if (oldLp != null && newLp.isIdenticalMtu(oldLp)) {
2753            if (VDBG) log("identical MTU - not setting");
2754            return;
2755        }
2756
2757        if (mtu < 68 || mtu > 10000) {
2758            loge("Unexpected mtu value: " + mtu + ", " + iface);
2759            return;
2760        }
2761
2762        try {
2763            if (VDBG) log("Setting MTU size: " + iface + ", " + mtu);
2764            mNetd.setMtu(iface, mtu);
2765        } catch (Exception e) {
2766            Slog.e(TAG, "exception in setMtu()" + e);
2767        }
2768    }
2769
2770    /**
2771     * Reads the network specific TCP buffer sizes from SystemProperties
2772     * net.tcp.buffersize.[default|wifi|umts|edge|gprs] and set them for system
2773     * wide use
2774     */
2775    private void updateNetworkSettings(NetworkStateTracker nt) {
2776        String key = nt.getTcpBufferSizesPropName();
2777        String bufferSizes = key == null ? null : SystemProperties.get(key);
2778
2779        if (TextUtils.isEmpty(bufferSizes)) {
2780            if (VDBG) log(key + " not found in system properties. Using defaults");
2781
2782            // Setting to default values so we won't be stuck to previous values
2783            key = "net.tcp.buffersize.default";
2784            bufferSizes = SystemProperties.get(key);
2785        }
2786
2787        // Set values in kernel
2788        if (bufferSizes.length() != 0) {
2789            if (VDBG) {
2790                log("Setting TCP values: [" + bufferSizes
2791                        + "] which comes from [" + key + "]");
2792            }
2793            setBufferSize(bufferSizes);
2794        }
2795
2796        final String defaultRwndKey = "net.tcp.default_init_rwnd";
2797        int defaultRwndValue = SystemProperties.getInt(defaultRwndKey, 0);
2798        Integer rwndValue = Settings.Global.getInt(mContext.getContentResolver(),
2799            Settings.Global.TCP_DEFAULT_INIT_RWND, defaultRwndValue);
2800        final String sysctlKey = "sys.sysctl.tcp_def_init_rwnd";
2801        if (rwndValue != 0) {
2802            SystemProperties.set(sysctlKey, rwndValue.toString());
2803        }
2804    }
2805
2806    /**
2807     * Writes TCP buffer sizes to /sys/kernel/ipv4/tcp_[r/w]mem_[min/def/max]
2808     * which maps to /proc/sys/net/ipv4/tcp_rmem and tcpwmem
2809     *
2810     * @param bufferSizes in the format of "readMin, readInitial, readMax,
2811     *        writeMin, writeInitial, writeMax"
2812     */
2813    private void setBufferSize(String bufferSizes) {
2814        try {
2815            String[] values = bufferSizes.split(",");
2816
2817            if (values.length == 6) {
2818              final String prefix = "/sys/kernel/ipv4/tcp_";
2819                FileUtils.stringToFile(prefix + "rmem_min", values[0]);
2820                FileUtils.stringToFile(prefix + "rmem_def", values[1]);
2821                FileUtils.stringToFile(prefix + "rmem_max", values[2]);
2822                FileUtils.stringToFile(prefix + "wmem_min", values[3]);
2823                FileUtils.stringToFile(prefix + "wmem_def", values[4]);
2824                FileUtils.stringToFile(prefix + "wmem_max", values[5]);
2825            } else {
2826                loge("Invalid buffersize string: " + bufferSizes);
2827            }
2828        } catch (IOException e) {
2829            loge("Can't set tcp buffer sizes:" + e);
2830        }
2831    }
2832
2833    /**
2834     * Adjust the per-process dns entries (net.dns<x>.<pid>) based
2835     * on the highest priority active net which this process requested.
2836     * If there aren't any, clear it out
2837     */
2838    private void reassessPidDns(int pid, boolean doBump)
2839    {
2840        if (VDBG) log("reassessPidDns for pid " + pid);
2841        Integer myPid = new Integer(pid);
2842        for(int i : mPriorityList) {
2843            if (mNetConfigs[i].isDefault()) {
2844                continue;
2845            }
2846            NetworkStateTracker nt = mNetTrackers[i];
2847            if (nt.getNetworkInfo().isConnected() &&
2848                    !nt.isTeardownRequested()) {
2849                LinkProperties p = nt.getLinkProperties();
2850                if (p == null) continue;
2851                if (mNetRequestersPids[i].contains(myPid)) {
2852                    try {
2853                        // TODO: Reimplement this via local variable in bionic.
2854                        // mNetd.setDnsNetworkForPid(nt.getNetwork().netId, pid);
2855                    } catch (Exception e) {
2856                        Slog.e(TAG, "exception reasseses pid dns: " + e);
2857                    }
2858                    return;
2859                }
2860           }
2861        }
2862        // nothing found - delete
2863        try {
2864            // TODO: Reimplement this via local variable in bionic.
2865            // mNetd.clearDnsNetworkForPid(pid);
2866        } catch (Exception e) {
2867            Slog.e(TAG, "exception clear interface from pid: " + e);
2868        }
2869    }
2870
2871    private void flushVmDnsCache() {
2872        /*
2873         * Tell the VMs to toss their DNS caches
2874         */
2875        Intent intent = new Intent(Intent.ACTION_CLEAR_DNS_CACHE);
2876        intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
2877        /*
2878         * Connectivity events can happen before boot has completed ...
2879         */
2880        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
2881        final long ident = Binder.clearCallingIdentity();
2882        try {
2883            mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
2884        } finally {
2885            Binder.restoreCallingIdentity(ident);
2886        }
2887    }
2888
2889    // Caller must grab mDnsLock.
2890    private void updateDnsLocked(String network, int netId,
2891            Collection<InetAddress> dnses, String domains) {
2892        int last = 0;
2893        if (dnses.size() == 0 && mDefaultDns != null) {
2894            dnses = new ArrayList();
2895            dnses.add(mDefaultDns);
2896            if (DBG) {
2897                loge("no dns provided for " + network + " - using " + mDefaultDns.getHostAddress());
2898            }
2899        }
2900
2901        try {
2902            mNetd.setDnsServersForNetwork(netId, NetworkUtils.makeStrings(dnses), domains);
2903
2904            for (InetAddress dns : dnses) {
2905                ++last;
2906                String key = "net.dns" + last;
2907                String value = dns.getHostAddress();
2908                SystemProperties.set(key, value);
2909            }
2910            for (int i = last + 1; i <= mNumDnsEntries; ++i) {
2911                String key = "net.dns" + i;
2912                SystemProperties.set(key, "");
2913            }
2914            mNumDnsEntries = last;
2915        } catch (Exception e) {
2916            loge("exception setting default dns interface: " + e);
2917        }
2918    }
2919
2920    private void handleDnsConfigurationChange(int netType) {
2921        // add default net's dns entries
2922        NetworkStateTracker nt = mNetTrackers[netType];
2923        if (nt != null && nt.getNetworkInfo().isConnected() && !nt.isTeardownRequested()) {
2924            LinkProperties p = nt.getLinkProperties();
2925            if (p == null) return;
2926            Collection<InetAddress> dnses = p.getDnsServers();
2927            int netId = nt.getNetwork().netId;
2928            if (mNetConfigs[netType].isDefault()) {
2929                String network = nt.getNetworkInfo().getTypeName();
2930                synchronized (mDnsLock) {
2931                    updateDnsLocked(network, netId, dnses, p.getDomains());
2932                }
2933            } else {
2934                try {
2935                    mNetd.setDnsServersForNetwork(netId,
2936                            NetworkUtils.makeStrings(dnses), p.getDomains());
2937                } catch (Exception e) {
2938                    if (DBG) loge("exception setting dns servers: " + e);
2939                }
2940                // set per-pid dns for attached secondary nets
2941                List<Integer> pids = mNetRequestersPids[netType];
2942                for (Integer pid : pids) {
2943                    try {
2944                        // TODO: Reimplement this via local variable in bionic.
2945                        // mNetd.setDnsNetworkForPid(netId, pid);
2946                    } catch (Exception e) {
2947                        Slog.e(TAG, "exception setting interface for pid: " + e);
2948                    }
2949                }
2950            }
2951            flushVmDnsCache();
2952        }
2953    }
2954
2955    @Override
2956    public int getRestoreDefaultNetworkDelay(int networkType) {
2957        String restoreDefaultNetworkDelayStr = SystemProperties.get(
2958                NETWORK_RESTORE_DELAY_PROP_NAME);
2959        if(restoreDefaultNetworkDelayStr != null &&
2960                restoreDefaultNetworkDelayStr.length() != 0) {
2961            try {
2962                return Integer.valueOf(restoreDefaultNetworkDelayStr);
2963            } catch (NumberFormatException e) {
2964            }
2965        }
2966        // if the system property isn't set, use the value for the apn type
2967        int ret = RESTORE_DEFAULT_NETWORK_DELAY;
2968
2969        if ((networkType <= ConnectivityManager.MAX_NETWORK_TYPE) &&
2970                (mNetConfigs[networkType] != null)) {
2971            ret = mNetConfigs[networkType].restoreTime;
2972        }
2973        return ret;
2974    }
2975
2976    @Override
2977    protected void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
2978        final IndentingPrintWriter pw = new IndentingPrintWriter(writer, "  ");
2979        if (mContext.checkCallingOrSelfPermission(
2980                android.Manifest.permission.DUMP)
2981                != PackageManager.PERMISSION_GRANTED) {
2982            pw.println("Permission Denial: can't dump ConnectivityService " +
2983                    "from from pid=" + Binder.getCallingPid() + ", uid=" +
2984                    Binder.getCallingUid());
2985            return;
2986        }
2987
2988        pw.println("NetworkFactories for:");
2989        pw.increaseIndent();
2990        for (NetworkFactoryInfo nfi : mNetworkFactoryInfos.values()) {
2991            pw.println(nfi.name);
2992        }
2993        pw.decreaseIndent();
2994        pw.println();
2995
2996        NetworkAgentInfo defaultNai = mNetworkForRequestId.get(mDefaultRequest.requestId);
2997        pw.print("Active default network: ");
2998        if (defaultNai == null) {
2999            pw.println("none");
3000        } else {
3001            pw.println(defaultNai.network.netId);
3002        }
3003        pw.println();
3004
3005        pw.println("Current Networks:");
3006        pw.increaseIndent();
3007        for (NetworkAgentInfo nai : mNetworkAgentInfos.values()) {
3008            pw.println(nai.toString());
3009            pw.increaseIndent();
3010            pw.println("Requests:");
3011            pw.increaseIndent();
3012            for (int i = 0; i < nai.networkRequests.size(); i++) {
3013                pw.println(nai.networkRequests.valueAt(i).toString());
3014            }
3015            pw.decreaseIndent();
3016            pw.println("Lingered:");
3017            pw.increaseIndent();
3018            for (NetworkRequest nr : nai.networkLingered) pw.println(nr.toString());
3019            pw.decreaseIndent();
3020            pw.decreaseIndent();
3021        }
3022        pw.decreaseIndent();
3023        pw.println();
3024
3025        pw.println("Network Requests:");
3026        pw.increaseIndent();
3027        for (NetworkRequestInfo nri : mNetworkRequests.values()) {
3028            pw.println(nri.toString());
3029        }
3030        pw.println();
3031        pw.decreaseIndent();
3032
3033        synchronized (this) {
3034            pw.println("NetworkTranstionWakeLock is currently " +
3035                    (mNetTransitionWakeLock.isHeld() ? "" : "not ") + "held.");
3036            pw.println("It was last requested for "+mNetTransitionWakeLockCausedBy);
3037        }
3038        pw.println();
3039
3040        mTethering.dump(fd, pw, args);
3041
3042        if (mInetLog != null) {
3043            pw.println();
3044            pw.println("Inet condition reports:");
3045            pw.increaseIndent();
3046            for(int i = 0; i < mInetLog.size(); i++) {
3047                pw.println(mInetLog.get(i));
3048            }
3049            pw.decreaseIndent();
3050        }
3051    }
3052
3053    // must be stateless - things change under us.
3054    private class NetworkStateTrackerHandler extends Handler {
3055        public NetworkStateTrackerHandler(Looper looper) {
3056            super(looper);
3057        }
3058
3059        @Override
3060        public void handleMessage(Message msg) {
3061            NetworkInfo info;
3062            switch (msg.what) {
3063                case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED: {
3064                    handleAsyncChannelHalfConnect(msg);
3065                    break;
3066                }
3067                case AsyncChannel.CMD_CHANNEL_DISCONNECT: {
3068                    NetworkAgentInfo nai = mNetworkAgentInfos.get(msg.replyTo);
3069                    if (nai != null) nai.asyncChannel.disconnect();
3070                    break;
3071                }
3072                case AsyncChannel.CMD_CHANNEL_DISCONNECTED: {
3073                    handleAsyncChannelDisconnected(msg);
3074                    break;
3075                }
3076                case NetworkAgent.EVENT_NETWORK_CAPABILITIES_CHANGED: {
3077                    NetworkAgentInfo nai = mNetworkAgentInfos.get(msg.replyTo);
3078                    if (nai == null) {
3079                        loge("EVENT_NETWORK_CAPABILITIES_CHANGED from unknown NetworkAgent");
3080                    } else {
3081                        updateCapabilities(nai, (NetworkCapabilities)msg.obj);
3082                    }
3083                    break;
3084                }
3085                case NetworkAgent.EVENT_NETWORK_PROPERTIES_CHANGED: {
3086                    NetworkAgentInfo nai = mNetworkAgentInfos.get(msg.replyTo);
3087                    if (nai == null) {
3088                        loge("NetworkAgent not found for EVENT_NETWORK_PROPERTIES_CHANGED");
3089                    } else {
3090                        if (VDBG) log("Update of Linkproperties for " + nai.name());
3091                        LinkProperties oldLp = nai.linkProperties;
3092                        nai.linkProperties = (LinkProperties)msg.obj;
3093                        updateLinkProperties(nai, oldLp);
3094                    }
3095                    break;
3096                }
3097                case NetworkAgent.EVENT_NETWORK_INFO_CHANGED: {
3098                    NetworkAgentInfo nai = mNetworkAgentInfos.get(msg.replyTo);
3099                    if (nai == null) {
3100                        loge("EVENT_NETWORK_INFO_CHANGED from unknown NetworkAgent");
3101                        break;
3102                    }
3103                    info = (NetworkInfo) msg.obj;
3104                    updateNetworkInfo(nai, info);
3105                    break;
3106                }
3107                case NetworkAgent.EVENT_NETWORK_SCORE_CHANGED: {
3108                    NetworkAgentInfo nai = mNetworkAgentInfos.get(msg.replyTo);
3109                    if (nai == null) {
3110                        loge("EVENT_NETWORK_SCORE_CHANGED from unknown NetworkAgent");
3111                        break;
3112                    }
3113                    Integer score = (Integer) msg.obj;
3114                    if (score != null) updateNetworkScore(nai, score.intValue());
3115                    break;
3116                }
3117                case NetworkMonitor.EVENT_NETWORK_VALIDATED: {
3118                    NetworkAgentInfo nai = (NetworkAgentInfo)msg.obj;
3119                    handleConnectionValidated(nai);
3120                    break;
3121                }
3122                case NetworkMonitor.EVENT_NETWORK_LINGER_COMPLETE: {
3123                    NetworkAgentInfo nai = (NetworkAgentInfo)msg.obj;
3124                    handleLingerComplete(nai);
3125                    break;
3126                }
3127                case NetworkStateTracker.EVENT_STATE_CHANGED: {
3128                    info = (NetworkInfo) msg.obj;
3129                    NetworkInfo.State state = info.getState();
3130
3131                    if (VDBG || (state == NetworkInfo.State.CONNECTED) ||
3132                            (state == NetworkInfo.State.DISCONNECTED) ||
3133                            (state == NetworkInfo.State.SUSPENDED)) {
3134                        log("ConnectivityChange for " +
3135                            info.getTypeName() + ": " +
3136                            state + "/" + info.getDetailedState());
3137                    }
3138
3139                    // Since mobile has the notion of a network/apn that can be used for
3140                    // provisioning we need to check every time we're connected as
3141                    // CaptiveProtalTracker won't detected it because DCT doesn't report it
3142                    // as connected as ACTION_ANY_DATA_CONNECTION_STATE_CHANGED instead its
3143                    // reported as ACTION_DATA_CONNECTION_CONNECTED_TO_PROVISIONING_APN. Which
3144                    // is received by MDST and sent here as EVENT_STATE_CHANGED.
3145                    if (ConnectivityManager.isNetworkTypeMobile(info.getType())
3146                            && (0 != Settings.Global.getInt(mContext.getContentResolver(),
3147                                        Settings.Global.DEVICE_PROVISIONED, 0))
3148                            && (((state == NetworkInfo.State.CONNECTED)
3149                                    && (info.getType() == ConnectivityManager.TYPE_MOBILE))
3150                                || info.isConnectedToProvisioningNetwork())) {
3151                        log("ConnectivityChange checkMobileProvisioning for"
3152                                + " TYPE_MOBILE or ProvisioningNetwork");
3153                        checkMobileProvisioning(CheckMp.MAX_TIMEOUT_MS);
3154                    }
3155
3156                    EventLogTags.writeConnectivityStateChanged(
3157                            info.getType(), info.getSubtype(), info.getDetailedState().ordinal());
3158
3159                    if (info.isConnectedToProvisioningNetwork()) {
3160                        /**
3161                         * TODO: Create ConnectivityManager.TYPE_MOBILE_PROVISIONING
3162                         * for now its an in between network, its a network that
3163                         * is actually a default network but we don't want it to be
3164                         * announced as such to keep background applications from
3165                         * trying to use it. It turns out that some still try so we
3166                         * take the additional step of clearing any default routes
3167                         * to the link that may have incorrectly setup by the lower
3168                         * levels.
3169                         */
3170                        LinkProperties lp = getLinkPropertiesForTypeInternal(info.getType());
3171                        if (DBG) {
3172                            log("EVENT_STATE_CHANGED: connected to provisioning network, lp=" + lp);
3173                        }
3174
3175                        // Clear any default routes setup by the radio so
3176                        // any activity by applications trying to use this
3177                        // connection will fail until the provisioning network
3178                        // is enabled.
3179                        for (RouteInfo r : lp.getRoutes()) {
3180                            removeRoute(lp, r, TO_DEFAULT_TABLE,
3181                                        mNetTrackers[info.getType()].getNetwork().netId);
3182                        }
3183                    } else if (state == NetworkInfo.State.DISCONNECTED) {
3184                    } else if (state == NetworkInfo.State.SUSPENDED) {
3185                    } else if (state == NetworkInfo.State.CONNECTED) {
3186                    //    handleConnect(info);
3187                    }
3188                    if (mLockdownTracker != null) {
3189                        mLockdownTracker.onNetworkInfoChanged(info);
3190                    }
3191                    break;
3192                }
3193                case NetworkStateTracker.EVENT_CONFIGURATION_CHANGED: {
3194                    info = (NetworkInfo) msg.obj;
3195                    // TODO: Temporary allowing network configuration
3196                    //       change not resetting sockets.
3197                    //       @see bug/4455071
3198                    handleConnectivityChange(info.getType(), mCurrentLinkProperties[info.getType()],
3199                            false);
3200                    break;
3201                }
3202                case NetworkStateTracker.EVENT_NETWORK_SUBTYPE_CHANGED: {
3203                    info = (NetworkInfo) msg.obj;
3204                    int type = info.getType();
3205                    if (mNetConfigs[type].isDefault()) updateNetworkSettings(mNetTrackers[type]);
3206                    break;
3207                }
3208            }
3209        }
3210    }
3211
3212    private void handleAsyncChannelHalfConnect(Message msg) {
3213        AsyncChannel ac = (AsyncChannel) msg.obj;
3214        if (mNetworkFactoryInfos.containsKey(msg.replyTo)) {
3215            if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) {
3216                if (VDBG) log("NetworkFactory connected");
3217                // A network factory has connected.  Send it all current NetworkRequests.
3218                for (NetworkRequestInfo nri : mNetworkRequests.values()) {
3219                    if (nri.isRequest == false) continue;
3220                    NetworkAgentInfo nai = mNetworkForRequestId.get(nri.request.requestId);
3221                    ac.sendMessage(android.net.NetworkFactory.CMD_REQUEST_NETWORK,
3222                            (nai != null ? nai.currentScore : 0), 0, nri.request);
3223                }
3224            } else {
3225                loge("Error connecting NetworkFactory");
3226                mNetworkFactoryInfos.remove(msg.obj);
3227            }
3228        } else if (mNetworkAgentInfos.containsKey(msg.replyTo)) {
3229            if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) {
3230                if (VDBG) log("NetworkAgent connected");
3231                // A network agent has requested a connection.  Establish the connection.
3232                mNetworkAgentInfos.get(msg.replyTo).asyncChannel.
3233                        sendMessage(AsyncChannel.CMD_CHANNEL_FULL_CONNECTION);
3234            } else {
3235                loge("Error connecting NetworkAgent");
3236                NetworkAgentInfo nai = mNetworkAgentInfos.remove(msg.replyTo);
3237                if (nai != null) {
3238                    mNetworkForNetId.remove(nai.network.netId);
3239                    mLegacyTypeTracker.remove(nai);
3240                }
3241            }
3242        }
3243    }
3244    private void handleAsyncChannelDisconnected(Message msg) {
3245        NetworkAgentInfo nai = mNetworkAgentInfos.get(msg.replyTo);
3246        if (nai != null) {
3247            if (DBG) {
3248                log(nai.name() + " got DISCONNECTED, was satisfying " + nai.networkRequests.size());
3249            }
3250            // A network agent has disconnected.
3251            // Tell netd to clean up the configuration for this network
3252            // (routing rules, DNS, etc).
3253            try {
3254                mNetd.removeNetwork(nai.network.netId);
3255            } catch (Exception e) {
3256                loge("Exception removing network: " + e);
3257            }
3258            // TODO - if we move the logic to the network agent (have them disconnect
3259            // because they lost all their requests or because their score isn't good)
3260            // then they would disconnect organically, report their new state and then
3261            // disconnect the channel.
3262            if (nai.networkInfo.isConnected()) {
3263                nai.networkInfo.setDetailedState(NetworkInfo.DetailedState.DISCONNECTED,
3264                        null, null);
3265            }
3266            notifyNetworkCallbacks(nai, ConnectivityManager.CALLBACK_LOST);
3267            nai.networkMonitor.sendMessage(NetworkMonitor.CMD_NETWORK_DISCONNECTED);
3268            mNetworkAgentInfos.remove(msg.replyTo);
3269            updateClat(null, nai.linkProperties, nai);
3270            mLegacyTypeTracker.remove(nai);
3271            mNetworkForNetId.remove(nai.network.netId);
3272            // Since we've lost the network, go through all the requests that
3273            // it was satisfying and see if any other factory can satisfy them.
3274            final ArrayList<NetworkAgentInfo> toActivate = new ArrayList<NetworkAgentInfo>();
3275            for (int i = 0; i < nai.networkRequests.size(); i++) {
3276                NetworkRequest request = nai.networkRequests.valueAt(i);
3277                NetworkAgentInfo currentNetwork = mNetworkForRequestId.get(request.requestId);
3278                if (VDBG) {
3279                    log(" checking request " + request + ", currentNetwork = " +
3280                            (currentNetwork != null ? currentNetwork.name() : "null"));
3281                }
3282                if (currentNetwork != null && currentNetwork.network.netId == nai.network.netId) {
3283                    mNetworkForRequestId.remove(request.requestId);
3284                    sendUpdatedScoreToFactories(request, 0);
3285                    NetworkAgentInfo alternative = null;
3286                    for (Map.Entry entry : mNetworkAgentInfos.entrySet()) {
3287                        NetworkAgentInfo existing = (NetworkAgentInfo)entry.getValue();
3288                        if (existing.networkInfo.isConnected() &&
3289                                request.networkCapabilities.satisfiedByNetworkCapabilities(
3290                                existing.networkCapabilities) &&
3291                                (alternative == null ||
3292                                 alternative.currentScore < existing.currentScore)) {
3293                            alternative = existing;
3294                        }
3295                    }
3296                    if (alternative != null && !toActivate.contains(alternative)) {
3297                        toActivate.add(alternative);
3298                    }
3299                }
3300            }
3301            if (nai.networkRequests.get(mDefaultRequest.requestId) != null) {
3302                removeDataActivityTracking(nai);
3303                mActiveDefaultNetwork = ConnectivityManager.TYPE_NONE;
3304                requestNetworkTransitionWakelock(nai.name());
3305            }
3306            for (NetworkAgentInfo networkToActivate : toActivate) {
3307                networkToActivate.networkMonitor.sendMessage(NetworkMonitor.CMD_NETWORK_CONNECTED);
3308            }
3309        }
3310    }
3311
3312    private void handleRegisterNetworkRequest(Message msg) {
3313        final NetworkRequestInfo nri = (NetworkRequestInfo) (msg.obj);
3314        final NetworkCapabilities newCap = nri.request.networkCapabilities;
3315        int score = 0;
3316
3317        // Check for the best currently alive network that satisfies this request
3318        NetworkAgentInfo bestNetwork = null;
3319        for (NetworkAgentInfo network : mNetworkAgentInfos.values()) {
3320            if (VDBG) log("handleRegisterNetworkRequest checking " + network.name());
3321            if (newCap.satisfiedByNetworkCapabilities(network.networkCapabilities)) {
3322                if (VDBG) log("apparently satisfied.  currentScore=" + network.currentScore);
3323                if ((bestNetwork == null) || bestNetwork.currentScore < network.currentScore) {
3324                    bestNetwork = network;
3325                }
3326            }
3327        }
3328        if (bestNetwork != null) {
3329            if (VDBG) log("using " + bestNetwork.name());
3330            bestNetwork.addRequest(nri.request);
3331            mNetworkForRequestId.put(nri.request.requestId, bestNetwork);
3332            int legacyType = nri.request.legacyType;
3333            if (legacyType != TYPE_NONE) {
3334                mLegacyTypeTracker.add(legacyType, bestNetwork);
3335            }
3336            notifyNetworkCallback(bestNetwork, nri);
3337            score = bestNetwork.currentScore;
3338        }
3339        mNetworkRequests.put(nri.request, nri);
3340        if (msg.what == EVENT_REGISTER_NETWORK_REQUEST) {
3341            if (DBG) log("sending new NetworkRequest to factories");
3342            for (NetworkFactoryInfo nfi : mNetworkFactoryInfos.values()) {
3343                nfi.asyncChannel.sendMessage(android.net.NetworkFactory.CMD_REQUEST_NETWORK, score,
3344                        0, nri.request);
3345            }
3346        }
3347    }
3348
3349    private void handleReleaseNetworkRequest(NetworkRequest request, int callingUid) {
3350        NetworkRequestInfo nri = mNetworkRequests.get(request);
3351        if (nri != null) {
3352            if (nri.mUid != callingUid) {
3353                if (DBG) log("Attempt to release unowned NetworkRequest " + request);
3354                return;
3355            }
3356            if (DBG) log("releasing NetworkRequest " + request);
3357            mNetworkRequests.remove(request);
3358            // tell the network currently servicing this that it's no longer interested
3359            NetworkAgentInfo affectedNetwork = mNetworkForRequestId.get(nri.request.requestId);
3360            if (affectedNetwork != null) {
3361                mNetworkForRequestId.remove(nri.request.requestId);
3362                affectedNetwork.networkRequests.remove(nri.request.requestId);
3363                if (VDBG) {
3364                    log(" Removing from current network " + affectedNetwork.name() + ", leaving " +
3365                            affectedNetwork.networkRequests.size() + " requests.");
3366                }
3367            }
3368
3369            if (nri.isRequest) {
3370                for (NetworkFactoryInfo nfi : mNetworkFactoryInfos.values()) {
3371                    nfi.asyncChannel.sendMessage(android.net.NetworkFactory.CMD_CANCEL_REQUEST,
3372                            nri.request);
3373                }
3374
3375                if (affectedNetwork != null) {
3376                    // check if this network still has live requests - otherwise, tear down
3377                    // TODO - probably push this to the NF/NA
3378                    boolean keep = false;
3379                    for (int i = 0; i < affectedNetwork.networkRequests.size(); i++) {
3380                        NetworkRequest r = affectedNetwork.networkRequests.valueAt(i);
3381                        if (mNetworkRequests.get(r).isRequest) {
3382                            keep = true;
3383                            break;
3384                        }
3385                    }
3386                    if (keep == false) {
3387                        if (DBG) log("no live requests for " + affectedNetwork.name() +
3388                                "; disconnecting");
3389                        affectedNetwork.asyncChannel.disconnect();
3390                    }
3391                }
3392            }
3393            callCallbackForRequest(nri, null, ConnectivityManager.CALLBACK_RELEASED);
3394        }
3395    }
3396
3397    private class InternalHandler extends Handler {
3398        public InternalHandler(Looper looper) {
3399            super(looper);
3400        }
3401
3402        @Override
3403        public void handleMessage(Message msg) {
3404            NetworkInfo info;
3405            switch (msg.what) {
3406                case EVENT_EXPIRE_NET_TRANSITION_WAKELOCK:
3407                case EVENT_CLEAR_NET_TRANSITION_WAKELOCK: {
3408                    String causedBy = null;
3409                    synchronized (ConnectivityService.this) {
3410                        if (msg.arg1 == mNetTransitionWakeLockSerialNumber &&
3411                                mNetTransitionWakeLock.isHeld()) {
3412                            mNetTransitionWakeLock.release();
3413                            causedBy = mNetTransitionWakeLockCausedBy;
3414                        } else {
3415                            break;
3416                        }
3417                    }
3418                    if (msg.what == EVENT_EXPIRE_NET_TRANSITION_WAKELOCK) {
3419                        log("Failed to find a new network - expiring NetTransition Wakelock");
3420                    } else {
3421                        log("NetTransition Wakelock (" + (causedBy == null ? "unknown" : causedBy) +
3422                                " cleared because we found a replacement network");
3423                    }
3424                    break;
3425                }
3426                case EVENT_RESTORE_DEFAULT_NETWORK: {
3427                    FeatureUser u = (FeatureUser)msg.obj;
3428                    u.expire();
3429                    break;
3430                }
3431                case EVENT_INET_CONDITION_CHANGE: {
3432                    int netType = msg.arg1;
3433                    int condition = msg.arg2;
3434                    handleInetConditionChange(netType, condition);
3435                    break;
3436                }
3437                case EVENT_INET_CONDITION_HOLD_END: {
3438                    int netType = msg.arg1;
3439                    int sequence = msg.arg2;
3440                    handleInetConditionHoldEnd(netType, sequence);
3441                    break;
3442                }
3443                case EVENT_APPLY_GLOBAL_HTTP_PROXY: {
3444                    handleDeprecatedGlobalHttpProxy();
3445                    break;
3446                }
3447                case EVENT_SET_DEPENDENCY_MET: {
3448                    boolean met = (msg.arg1 == ENABLED);
3449                    handleSetDependencyMet(msg.arg2, met);
3450                    break;
3451                }
3452                case EVENT_SEND_STICKY_BROADCAST_INTENT: {
3453                    Intent intent = (Intent)msg.obj;
3454                    sendStickyBroadcast(intent);
3455                    break;
3456                }
3457                case EVENT_SET_POLICY_DATA_ENABLE: {
3458                    final int networkType = msg.arg1;
3459                    final boolean enabled = msg.arg2 == ENABLED;
3460                    handleSetPolicyDataEnable(networkType, enabled);
3461                    break;
3462                }
3463                case EVENT_VPN_STATE_CHANGED: {
3464                    if (mLockdownTracker != null) {
3465                        mLockdownTracker.onVpnStateChanged((NetworkInfo) msg.obj);
3466                    }
3467                    break;
3468                }
3469                case EVENT_ENABLE_FAIL_FAST_MOBILE_DATA: {
3470                    int tag = mEnableFailFastMobileDataTag.get();
3471                    if (msg.arg1 == tag) {
3472                        MobileDataStateTracker mobileDst =
3473                            (MobileDataStateTracker) mNetTrackers[ConnectivityManager.TYPE_MOBILE];
3474                        if (mobileDst != null) {
3475                            mobileDst.setEnableFailFastMobileData(msg.arg2);
3476                        }
3477                    } else {
3478                        log("EVENT_ENABLE_FAIL_FAST_MOBILE_DATA: stale arg1:" + msg.arg1
3479                                + " != tag:" + tag);
3480                    }
3481                    break;
3482                }
3483                case EVENT_SAMPLE_INTERVAL_ELAPSED: {
3484                    handleNetworkSamplingTimeout();
3485                    break;
3486                }
3487                case EVENT_PROXY_HAS_CHANGED: {
3488                    handleApplyDefaultProxy((ProxyInfo)msg.obj);
3489                    break;
3490                }
3491                case EVENT_REGISTER_NETWORK_FACTORY: {
3492                    handleRegisterNetworkFactory((NetworkFactoryInfo)msg.obj);
3493                    break;
3494                }
3495                case EVENT_UNREGISTER_NETWORK_FACTORY: {
3496                    handleUnregisterNetworkFactory((Messenger)msg.obj);
3497                    break;
3498                }
3499                case EVENT_REGISTER_NETWORK_AGENT: {
3500                    handleRegisterNetworkAgent((NetworkAgentInfo)msg.obj);
3501                    break;
3502                }
3503                case EVENT_REGISTER_NETWORK_REQUEST:
3504                case EVENT_REGISTER_NETWORK_LISTENER: {
3505                    handleRegisterNetworkRequest(msg);
3506                    break;
3507                }
3508                case EVENT_RELEASE_NETWORK_REQUEST: {
3509                    handleReleaseNetworkRequest((NetworkRequest) msg.obj, msg.arg1);
3510                    break;
3511                }
3512            }
3513        }
3514    }
3515
3516    // javadoc from interface
3517    public int tether(String iface) {
3518        enforceTetherChangePermission();
3519
3520        if (isTetheringSupported()) {
3521            return mTethering.tether(iface);
3522        } else {
3523            return ConnectivityManager.TETHER_ERROR_UNSUPPORTED;
3524        }
3525    }
3526
3527    // javadoc from interface
3528    public int untether(String iface) {
3529        enforceTetherChangePermission();
3530
3531        if (isTetheringSupported()) {
3532            return mTethering.untether(iface);
3533        } else {
3534            return ConnectivityManager.TETHER_ERROR_UNSUPPORTED;
3535        }
3536    }
3537
3538    // javadoc from interface
3539    public int getLastTetherError(String iface) {
3540        enforceTetherAccessPermission();
3541
3542        if (isTetheringSupported()) {
3543            return mTethering.getLastTetherError(iface);
3544        } else {
3545            return ConnectivityManager.TETHER_ERROR_UNSUPPORTED;
3546        }
3547    }
3548
3549    // TODO - proper iface API for selection by property, inspection, etc
3550    public String[] getTetherableUsbRegexs() {
3551        enforceTetherAccessPermission();
3552        if (isTetheringSupported()) {
3553            return mTethering.getTetherableUsbRegexs();
3554        } else {
3555            return new String[0];
3556        }
3557    }
3558
3559    public String[] getTetherableWifiRegexs() {
3560        enforceTetherAccessPermission();
3561        if (isTetheringSupported()) {
3562            return mTethering.getTetherableWifiRegexs();
3563        } else {
3564            return new String[0];
3565        }
3566    }
3567
3568    public String[] getTetherableBluetoothRegexs() {
3569        enforceTetherAccessPermission();
3570        if (isTetheringSupported()) {
3571            return mTethering.getTetherableBluetoothRegexs();
3572        } else {
3573            return new String[0];
3574        }
3575    }
3576
3577    public int setUsbTethering(boolean enable) {
3578        enforceTetherChangePermission();
3579        if (isTetheringSupported()) {
3580            return mTethering.setUsbTethering(enable);
3581        } else {
3582            return ConnectivityManager.TETHER_ERROR_UNSUPPORTED;
3583        }
3584    }
3585
3586    // TODO - move iface listing, queries, etc to new module
3587    // javadoc from interface
3588    public String[] getTetherableIfaces() {
3589        enforceTetherAccessPermission();
3590        return mTethering.getTetherableIfaces();
3591    }
3592
3593    public String[] getTetheredIfaces() {
3594        enforceTetherAccessPermission();
3595        return mTethering.getTetheredIfaces();
3596    }
3597
3598    public String[] getTetheringErroredIfaces() {
3599        enforceTetherAccessPermission();
3600        return mTethering.getErroredIfaces();
3601    }
3602
3603    // if ro.tether.denied = true we default to no tethering
3604    // gservices could set the secure setting to 1 though to enable it on a build where it
3605    // had previously been turned off.
3606    public boolean isTetheringSupported() {
3607        enforceTetherAccessPermission();
3608        int defaultVal = (SystemProperties.get("ro.tether.denied").equals("true") ? 0 : 1);
3609        boolean tetherEnabledInSettings = (Settings.Global.getInt(mContext.getContentResolver(),
3610                Settings.Global.TETHER_SUPPORTED, defaultVal) != 0);
3611        return tetherEnabledInSettings && ((mTethering.getTetherableUsbRegexs().length != 0 ||
3612                mTethering.getTetherableWifiRegexs().length != 0 ||
3613                mTethering.getTetherableBluetoothRegexs().length != 0) &&
3614                mTethering.getUpstreamIfaceTypes().length != 0);
3615    }
3616
3617    // An API NetworkStateTrackers can call when they lose their network.
3618    // This will automatically be cleared after X seconds or a network becomes CONNECTED,
3619    // whichever happens first.  The timer is started by the first caller and not
3620    // restarted by subsequent callers.
3621    public void requestNetworkTransitionWakelock(String forWhom) {
3622        enforceConnectivityInternalPermission();
3623        int serialNum = 0;
3624        synchronized (this) {
3625            if (mNetTransitionWakeLock.isHeld()) return;
3626            serialNum = ++mNetTransitionWakeLockSerialNumber;
3627            mNetTransitionWakeLock.acquire();
3628            mNetTransitionWakeLockCausedBy = forWhom;
3629        }
3630        mHandler.sendMessageDelayed(mHandler.obtainMessage(
3631                EVENT_EXPIRE_NET_TRANSITION_WAKELOCK, serialNum, 0),
3632                mNetTransitionWakeLockTimeout);
3633        return;
3634    }
3635
3636    // 100 percent is full good, 0 is full bad.
3637    public void reportInetCondition(int networkType, int percentage) {
3638        if (VDBG) log("reportNetworkCondition(" + networkType + ", " + percentage + ")");
3639        mContext.enforceCallingOrSelfPermission(
3640                android.Manifest.permission.STATUS_BAR,
3641                "ConnectivityService");
3642
3643        if (DBG) {
3644            int pid = getCallingPid();
3645            int uid = getCallingUid();
3646            String s = pid + "(" + uid + ") reports inet is " +
3647                (percentage > 50 ? "connected" : "disconnected") + " (" + percentage + ") on " +
3648                "network Type " + networkType + " at " + GregorianCalendar.getInstance().getTime();
3649            mInetLog.add(s);
3650            while(mInetLog.size() > INET_CONDITION_LOG_MAX_SIZE) {
3651                mInetLog.remove(0);
3652            }
3653        }
3654        mHandler.sendMessage(mHandler.obtainMessage(
3655            EVENT_INET_CONDITION_CHANGE, networkType, percentage));
3656    }
3657
3658    public void reportBadNetwork(Network network) {
3659        //TODO
3660    }
3661
3662    private void handleInetConditionChange(int netType, int condition) {
3663        if (mActiveDefaultNetwork == -1) {
3664            if (DBG) log("handleInetConditionChange: no active default network - ignore");
3665            return;
3666        }
3667        if (mActiveDefaultNetwork != netType) {
3668            if (DBG) log("handleInetConditionChange: net=" + netType +
3669                            " != default=" + mActiveDefaultNetwork + " - ignore");
3670            return;
3671        }
3672        if (VDBG) {
3673            log("handleInetConditionChange: net=" +
3674                    netType + ", condition=" + condition +
3675                    ",mActiveDefaultNetwork=" + mActiveDefaultNetwork);
3676        }
3677        mDefaultInetCondition = condition;
3678        int delay;
3679        if (mInetConditionChangeInFlight == false) {
3680            if (VDBG) log("handleInetConditionChange: starting a change hold");
3681            // setup a new hold to debounce this
3682            if (mDefaultInetCondition > 50) {
3683                delay = Settings.Global.getInt(mContext.getContentResolver(),
3684                        Settings.Global.INET_CONDITION_DEBOUNCE_UP_DELAY, 500);
3685            } else {
3686                delay = Settings.Global.getInt(mContext.getContentResolver(),
3687                        Settings.Global.INET_CONDITION_DEBOUNCE_DOWN_DELAY, 3000);
3688            }
3689            mInetConditionChangeInFlight = true;
3690            mHandler.sendMessageDelayed(mHandler.obtainMessage(EVENT_INET_CONDITION_HOLD_END,
3691                    mActiveDefaultNetwork, mDefaultConnectionSequence), delay);
3692        } else {
3693            // we've set the new condition, when this hold ends that will get picked up
3694            if (VDBG) log("handleInetConditionChange: currently in hold - not setting new end evt");
3695        }
3696    }
3697
3698    private void handleInetConditionHoldEnd(int netType, int sequence) {
3699        if (DBG) {
3700            log("handleInetConditionHoldEnd: net=" + netType +
3701                    ", condition=" + mDefaultInetCondition +
3702                    ", published condition=" + mDefaultInetConditionPublished);
3703        }
3704        mInetConditionChangeInFlight = false;
3705
3706        if (mActiveDefaultNetwork == -1) {
3707            if (DBG) log("handleInetConditionHoldEnd: no active default network - ignoring");
3708            return;
3709        }
3710        if (mDefaultConnectionSequence != sequence) {
3711            if (DBG) log("handleInetConditionHoldEnd: event hold for obsolete network - ignoring");
3712            return;
3713        }
3714        // TODO: Figure out why this optimization sometimes causes a
3715        //       change in mDefaultInetCondition to be missed and the
3716        //       UI to not be updated.
3717        //if (mDefaultInetConditionPublished == mDefaultInetCondition) {
3718        //    if (DBG) log("no change in condition - aborting");
3719        //    return;
3720        //}
3721        NetworkInfo networkInfo = getNetworkInfoForType(mActiveDefaultNetwork);
3722        if (networkInfo.isConnected() == false) {
3723            if (DBG) log("handleInetConditionHoldEnd: default network not connected - ignoring");
3724            return;
3725        }
3726        mDefaultInetConditionPublished = mDefaultInetCondition;
3727        sendInetConditionBroadcast(networkInfo);
3728        return;
3729    }
3730
3731    public ProxyInfo getProxy() {
3732        // this information is already available as a world read/writable jvm property
3733        // so this API change wouldn't have a benifit.  It also breaks the passing
3734        // of proxy info to all the JVMs.
3735        // enforceAccessPermission();
3736        synchronized (mProxyLock) {
3737            ProxyInfo ret = mGlobalProxy;
3738            if ((ret == null) && !mDefaultProxyDisabled) ret = mDefaultProxy;
3739            return ret;
3740        }
3741    }
3742
3743    public void setGlobalProxy(ProxyInfo proxyProperties) {
3744        enforceConnectivityInternalPermission();
3745
3746        synchronized (mProxyLock) {
3747            if (proxyProperties == mGlobalProxy) return;
3748            if (proxyProperties != null && proxyProperties.equals(mGlobalProxy)) return;
3749            if (mGlobalProxy != null && mGlobalProxy.equals(proxyProperties)) return;
3750
3751            String host = "";
3752            int port = 0;
3753            String exclList = "";
3754            String pacFileUrl = "";
3755            if (proxyProperties != null && (!TextUtils.isEmpty(proxyProperties.getHost()) ||
3756                    (proxyProperties.getPacFileUrl() != null))) {
3757                if (!proxyProperties.isValid()) {
3758                    if (DBG)
3759                        log("Invalid proxy properties, ignoring: " + proxyProperties.toString());
3760                    return;
3761                }
3762                mGlobalProxy = new ProxyInfo(proxyProperties);
3763                host = mGlobalProxy.getHost();
3764                port = mGlobalProxy.getPort();
3765                exclList = mGlobalProxy.getExclusionListAsString();
3766                if (proxyProperties.getPacFileUrl() != null) {
3767                    pacFileUrl = proxyProperties.getPacFileUrl().toString();
3768                }
3769            } else {
3770                mGlobalProxy = null;
3771            }
3772            ContentResolver res = mContext.getContentResolver();
3773            final long token = Binder.clearCallingIdentity();
3774            try {
3775                Settings.Global.putString(res, Settings.Global.GLOBAL_HTTP_PROXY_HOST, host);
3776                Settings.Global.putInt(res, Settings.Global.GLOBAL_HTTP_PROXY_PORT, port);
3777                Settings.Global.putString(res, Settings.Global.GLOBAL_HTTP_PROXY_EXCLUSION_LIST,
3778                        exclList);
3779                Settings.Global.putString(res, Settings.Global.GLOBAL_HTTP_PROXY_PAC, pacFileUrl);
3780            } finally {
3781                Binder.restoreCallingIdentity(token);
3782            }
3783        }
3784
3785        if (mGlobalProxy == null) {
3786            proxyProperties = mDefaultProxy;
3787        }
3788        sendProxyBroadcast(proxyProperties);
3789    }
3790
3791    private void loadGlobalProxy() {
3792        ContentResolver res = mContext.getContentResolver();
3793        String host = Settings.Global.getString(res, Settings.Global.GLOBAL_HTTP_PROXY_HOST);
3794        int port = Settings.Global.getInt(res, Settings.Global.GLOBAL_HTTP_PROXY_PORT, 0);
3795        String exclList = Settings.Global.getString(res,
3796                Settings.Global.GLOBAL_HTTP_PROXY_EXCLUSION_LIST);
3797        String pacFileUrl = Settings.Global.getString(res, Settings.Global.GLOBAL_HTTP_PROXY_PAC);
3798        if (!TextUtils.isEmpty(host) || !TextUtils.isEmpty(pacFileUrl)) {
3799            ProxyInfo proxyProperties;
3800            if (!TextUtils.isEmpty(pacFileUrl)) {
3801                proxyProperties = new ProxyInfo(pacFileUrl);
3802            } else {
3803                proxyProperties = new ProxyInfo(host, port, exclList);
3804            }
3805            if (!proxyProperties.isValid()) {
3806                if (DBG) log("Invalid proxy properties, ignoring: " + proxyProperties.toString());
3807                return;
3808            }
3809
3810            synchronized (mProxyLock) {
3811                mGlobalProxy = proxyProperties;
3812            }
3813        }
3814    }
3815
3816    public ProxyInfo getGlobalProxy() {
3817        // this information is already available as a world read/writable jvm property
3818        // so this API change wouldn't have a benifit.  It also breaks the passing
3819        // of proxy info to all the JVMs.
3820        // enforceAccessPermission();
3821        synchronized (mProxyLock) {
3822            return mGlobalProxy;
3823        }
3824    }
3825
3826    private void handleApplyDefaultProxy(ProxyInfo proxy) {
3827        if (proxy != null && TextUtils.isEmpty(proxy.getHost())
3828                && (proxy.getPacFileUrl() == null)) {
3829            proxy = null;
3830        }
3831        synchronized (mProxyLock) {
3832            if (mDefaultProxy != null && mDefaultProxy.equals(proxy)) return;
3833            if (mDefaultProxy == proxy) return; // catches repeated nulls
3834            if (proxy != null &&  !proxy.isValid()) {
3835                if (DBG) log("Invalid proxy properties, ignoring: " + proxy.toString());
3836                return;
3837            }
3838
3839            // This call could be coming from the PacManager, containing the port of the local
3840            // proxy.  If this new proxy matches the global proxy then copy this proxy to the
3841            // global (to get the correct local port), and send a broadcast.
3842            // TODO: Switch PacManager to have its own message to send back rather than
3843            // reusing EVENT_HAS_CHANGED_PROXY and this call to handleApplyDefaultProxy.
3844            if ((mGlobalProxy != null) && (proxy != null) && (proxy.getPacFileUrl() != null)
3845                    && proxy.getPacFileUrl().equals(mGlobalProxy.getPacFileUrl())) {
3846                mGlobalProxy = proxy;
3847                sendProxyBroadcast(mGlobalProxy);
3848                return;
3849            }
3850            mDefaultProxy = proxy;
3851
3852            if (mGlobalProxy != null) return;
3853            if (!mDefaultProxyDisabled) {
3854                sendProxyBroadcast(proxy);
3855            }
3856        }
3857    }
3858
3859    private void handleDeprecatedGlobalHttpProxy() {
3860        String proxy = Settings.Global.getString(mContext.getContentResolver(),
3861                Settings.Global.HTTP_PROXY);
3862        if (!TextUtils.isEmpty(proxy)) {
3863            String data[] = proxy.split(":");
3864            if (data.length == 0) {
3865                return;
3866            }
3867
3868            String proxyHost =  data[0];
3869            int proxyPort = 8080;
3870            if (data.length > 1) {
3871                try {
3872                    proxyPort = Integer.parseInt(data[1]);
3873                } catch (NumberFormatException e) {
3874                    return;
3875                }
3876            }
3877            ProxyInfo p = new ProxyInfo(data[0], proxyPort, "");
3878            setGlobalProxy(p);
3879        }
3880    }
3881
3882    private void sendProxyBroadcast(ProxyInfo proxy) {
3883        if (proxy == null) proxy = new ProxyInfo("", 0, "");
3884        if (mPacManager.setCurrentProxyScriptUrl(proxy)) return;
3885        if (DBG) log("sending Proxy Broadcast for " + proxy);
3886        Intent intent = new Intent(Proxy.PROXY_CHANGE_ACTION);
3887        intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING |
3888            Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
3889        intent.putExtra(Proxy.EXTRA_PROXY_INFO, proxy);
3890        final long ident = Binder.clearCallingIdentity();
3891        try {
3892            mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
3893        } finally {
3894            Binder.restoreCallingIdentity(ident);
3895        }
3896    }
3897
3898    private static class SettingsObserver extends ContentObserver {
3899        private int mWhat;
3900        private Handler mHandler;
3901        SettingsObserver(Handler handler, int what) {
3902            super(handler);
3903            mHandler = handler;
3904            mWhat = what;
3905        }
3906
3907        void observe(Context context) {
3908            ContentResolver resolver = context.getContentResolver();
3909            resolver.registerContentObserver(Settings.Global.getUriFor(
3910                    Settings.Global.HTTP_PROXY), false, this);
3911        }
3912
3913        @Override
3914        public void onChange(boolean selfChange) {
3915            mHandler.obtainMessage(mWhat).sendToTarget();
3916        }
3917    }
3918
3919    private static void log(String s) {
3920        Slog.d(TAG, s);
3921    }
3922
3923    private static void loge(String s) {
3924        Slog.e(TAG, s);
3925    }
3926
3927    int convertFeatureToNetworkType(int networkType, String feature) {
3928        int usedNetworkType = networkType;
3929
3930        if(networkType == ConnectivityManager.TYPE_MOBILE) {
3931            if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_MMS)) {
3932                usedNetworkType = ConnectivityManager.TYPE_MOBILE_MMS;
3933            } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_SUPL)) {
3934                usedNetworkType = ConnectivityManager.TYPE_MOBILE_SUPL;
3935            } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_DUN) ||
3936                    TextUtils.equals(feature, Phone.FEATURE_ENABLE_DUN_ALWAYS)) {
3937                usedNetworkType = ConnectivityManager.TYPE_MOBILE_DUN;
3938            } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_HIPRI)) {
3939                usedNetworkType = ConnectivityManager.TYPE_MOBILE_HIPRI;
3940            } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_FOTA)) {
3941                usedNetworkType = ConnectivityManager.TYPE_MOBILE_FOTA;
3942            } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_IMS)) {
3943                usedNetworkType = ConnectivityManager.TYPE_MOBILE_IMS;
3944            } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_CBS)) {
3945                usedNetworkType = ConnectivityManager.TYPE_MOBILE_CBS;
3946            } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_EMERGENCY)) {
3947                usedNetworkType = ConnectivityManager.TYPE_MOBILE_EMERGENCY;
3948            } else {
3949                Slog.e(TAG, "Can't match any mobile netTracker!");
3950            }
3951        } else if (networkType == ConnectivityManager.TYPE_WIFI) {
3952            if (TextUtils.equals(feature, "p2p")) {
3953                usedNetworkType = ConnectivityManager.TYPE_WIFI_P2P;
3954            } else {
3955                Slog.e(TAG, "Can't match any wifi netTracker!");
3956            }
3957        } else {
3958            Slog.e(TAG, "Unexpected network type");
3959        }
3960        return usedNetworkType;
3961    }
3962
3963    private static <T> T checkNotNull(T value, String message) {
3964        if (value == null) {
3965            throw new NullPointerException(message);
3966        }
3967        return value;
3968    }
3969
3970    /**
3971     * Protect a socket from VPN routing rules. This method is used by
3972     * VpnBuilder and not available in ConnectivityManager. Permissions
3973     * are checked in Vpn class.
3974     * @hide
3975     */
3976    @Override
3977    public boolean protectVpn(ParcelFileDescriptor socket) {
3978        throwIfLockdownEnabled();
3979        try {
3980            int type = mActiveDefaultNetwork;
3981            int user = UserHandle.getUserId(Binder.getCallingUid());
3982            if (ConnectivityManager.isNetworkTypeValid(type) && mNetTrackers[type] != null) {
3983                synchronized(mVpns) {
3984                    mVpns.get(user).protect(socket);
3985                }
3986                return true;
3987            }
3988        } catch (Exception e) {
3989            // ignore
3990        } finally {
3991            try {
3992                socket.close();
3993            } catch (Exception e) {
3994                // ignore
3995            }
3996        }
3997        return false;
3998    }
3999
4000    /**
4001     * Prepare for a VPN application. This method is used by VpnDialogs
4002     * and not available in ConnectivityManager. Permissions are checked
4003     * in Vpn class.
4004     * @hide
4005     */
4006    @Override
4007    public boolean prepareVpn(String oldPackage, String newPackage) {
4008        throwIfLockdownEnabled();
4009        int user = UserHandle.getUserId(Binder.getCallingUid());
4010        synchronized(mVpns) {
4011            return mVpns.get(user).prepare(oldPackage, newPackage);
4012        }
4013    }
4014
4015    @Override
4016    public void markSocketAsUser(ParcelFileDescriptor socket, int uid) {
4017        enforceMarkNetworkSocketPermission();
4018        final long token = Binder.clearCallingIdentity();
4019        try {
4020            int mark = mNetd.getMarkForUid(uid);
4021            // Clear the mark on the socket if no mark is needed to prevent socket reuse issues
4022            if (mark == -1) {
4023                mark = 0;
4024            }
4025            NetworkUtils.markSocket(socket.getFd(), mark);
4026        } catch (RemoteException e) {
4027        } finally {
4028            Binder.restoreCallingIdentity(token);
4029        }
4030    }
4031
4032    /**
4033     * Configure a TUN interface and return its file descriptor. Parameters
4034     * are encoded and opaque to this class. This method is used by VpnBuilder
4035     * and not available in ConnectivityManager. Permissions are checked in
4036     * Vpn class.
4037     * @hide
4038     */
4039    @Override
4040    public ParcelFileDescriptor establishVpn(VpnConfig config) {
4041        throwIfLockdownEnabled();
4042        int user = UserHandle.getUserId(Binder.getCallingUid());
4043        synchronized(mVpns) {
4044            return mVpns.get(user).establish(config);
4045        }
4046    }
4047
4048    /**
4049     * Start legacy VPN, controlling native daemons as needed. Creates a
4050     * secondary thread to perform connection work, returning quickly.
4051     */
4052    @Override
4053    public void startLegacyVpn(VpnProfile profile) {
4054        throwIfLockdownEnabled();
4055        final LinkProperties egress = getActiveLinkProperties();
4056        if (egress == null) {
4057            throw new IllegalStateException("Missing active network connection");
4058        }
4059        int user = UserHandle.getUserId(Binder.getCallingUid());
4060        synchronized(mVpns) {
4061            mVpns.get(user).startLegacyVpn(profile, mKeyStore, egress);
4062        }
4063    }
4064
4065    /**
4066     * Return the information of the ongoing legacy VPN. This method is used
4067     * by VpnSettings and not available in ConnectivityManager. Permissions
4068     * are checked in Vpn class.
4069     * @hide
4070     */
4071    @Override
4072    public LegacyVpnInfo getLegacyVpnInfo() {
4073        throwIfLockdownEnabled();
4074        int user = UserHandle.getUserId(Binder.getCallingUid());
4075        synchronized(mVpns) {
4076            return mVpns.get(user).getLegacyVpnInfo();
4077        }
4078    }
4079
4080    /**
4081     * Returns the information of the ongoing VPN. This method is used by VpnDialogs and
4082     * not available in ConnectivityManager.
4083     * Permissions are checked in Vpn class.
4084     * @hide
4085     */
4086    @Override
4087    public VpnConfig getVpnConfig() {
4088        int user = UserHandle.getUserId(Binder.getCallingUid());
4089        synchronized(mVpns) {
4090            return mVpns.get(user).getVpnConfig();
4091        }
4092    }
4093
4094    /**
4095     * Callback for VPN subsystem. Currently VPN is not adapted to the service
4096     * through NetworkStateTracker since it works differently. For example, it
4097     * needs to override DNS servers but never takes the default routes. It
4098     * relies on another data network, and it could keep existing connections
4099     * alive after reconnecting, switching between networks, or even resuming
4100     * from deep sleep. Calls from applications should be done synchronously
4101     * to avoid race conditions. As these are all hidden APIs, refactoring can
4102     * be done whenever a better abstraction is developed.
4103     */
4104    public class VpnCallback {
4105        private VpnCallback() {
4106        }
4107
4108        public void onStateChanged(NetworkInfo info) {
4109            mHandler.obtainMessage(EVENT_VPN_STATE_CHANGED, info).sendToTarget();
4110        }
4111
4112        public void override(String iface, List<String> dnsServers, List<String> searchDomains) {
4113            if (dnsServers == null) {
4114                restore();
4115                return;
4116            }
4117
4118            // Convert DNS servers into addresses.
4119            List<InetAddress> addresses = new ArrayList<InetAddress>();
4120            for (String address : dnsServers) {
4121                // Double check the addresses and remove invalid ones.
4122                try {
4123                    addresses.add(InetAddress.parseNumericAddress(address));
4124                } catch (Exception e) {
4125                    // ignore
4126                }
4127            }
4128            if (addresses.isEmpty()) {
4129                restore();
4130                return;
4131            }
4132
4133            // Concatenate search domains into a string.
4134            StringBuilder buffer = new StringBuilder();
4135            if (searchDomains != null) {
4136                for (String domain : searchDomains) {
4137                    buffer.append(domain).append(' ');
4138                }
4139            }
4140            String domains = buffer.toString().trim();
4141
4142            // Apply DNS changes.
4143            synchronized (mDnsLock) {
4144                // TODO: Re-enable this when the netId of the VPN is known.
4145                // updateDnsLocked("VPN", netId, addresses, domains);
4146            }
4147
4148            // Temporarily disable the default proxy (not global).
4149            synchronized (mProxyLock) {
4150                mDefaultProxyDisabled = true;
4151                if (mGlobalProxy == null && mDefaultProxy != null) {
4152                    sendProxyBroadcast(null);
4153                }
4154            }
4155
4156            // TODO: support proxy per network.
4157        }
4158
4159        public void restore() {
4160            synchronized (mProxyLock) {
4161                mDefaultProxyDisabled = false;
4162                if (mGlobalProxy == null && mDefaultProxy != null) {
4163                    sendProxyBroadcast(mDefaultProxy);
4164                }
4165            }
4166        }
4167
4168        public void protect(ParcelFileDescriptor socket) {
4169            try {
4170                final int mark = mNetd.getMarkForProtect();
4171                NetworkUtils.markSocket(socket.getFd(), mark);
4172            } catch (RemoteException e) {
4173            }
4174        }
4175
4176        public void setRoutes(String interfaze, List<RouteInfo> routes) {
4177            for (RouteInfo route : routes) {
4178                try {
4179                    mNetd.setMarkedForwardingRoute(interfaze, route);
4180                } catch (RemoteException e) {
4181                }
4182            }
4183        }
4184
4185        public void setMarkedForwarding(String interfaze) {
4186            try {
4187                mNetd.setMarkedForwarding(interfaze);
4188            } catch (RemoteException e) {
4189            }
4190        }
4191
4192        public void clearMarkedForwarding(String interfaze) {
4193            try {
4194                mNetd.clearMarkedForwarding(interfaze);
4195            } catch (RemoteException e) {
4196            }
4197        }
4198
4199        public void addUserForwarding(String interfaze, int uid, boolean forwardDns) {
4200            int uidStart = uid * UserHandle.PER_USER_RANGE;
4201            int uidEnd = uidStart + UserHandle.PER_USER_RANGE - 1;
4202            addUidForwarding(interfaze, uidStart, uidEnd, forwardDns);
4203        }
4204
4205        public void clearUserForwarding(String interfaze, int uid, boolean forwardDns) {
4206            int uidStart = uid * UserHandle.PER_USER_RANGE;
4207            int uidEnd = uidStart + UserHandle.PER_USER_RANGE - 1;
4208            clearUidForwarding(interfaze, uidStart, uidEnd, forwardDns);
4209        }
4210
4211        public void addUidForwarding(String interfaze, int uidStart, int uidEnd,
4212                boolean forwardDns) {
4213            // TODO: Re-enable this when the netId of the VPN is known.
4214            // try {
4215            //     mNetd.setUidRangeRoute(netId, uidStart, uidEnd, forwardDns);
4216            // } catch (RemoteException e) {
4217            // }
4218
4219        }
4220
4221        public void clearUidForwarding(String interfaze, int uidStart, int uidEnd,
4222                boolean forwardDns) {
4223            // TODO: Re-enable this when the netId of the VPN is known.
4224            // try {
4225            //     mNetd.clearUidRangeRoute(interfaze, uidStart, uidEnd);
4226            // } catch (RemoteException e) {
4227            // }
4228
4229        }
4230    }
4231
4232    @Override
4233    public boolean updateLockdownVpn() {
4234        if (Binder.getCallingUid() != Process.SYSTEM_UID) {
4235            Slog.w(TAG, "Lockdown VPN only available to AID_SYSTEM");
4236            return false;
4237        }
4238
4239        // Tear down existing lockdown if profile was removed
4240        mLockdownEnabled = LockdownVpnTracker.isEnabled();
4241        if (mLockdownEnabled) {
4242            if (!mKeyStore.isUnlocked()) {
4243                Slog.w(TAG, "KeyStore locked; unable to create LockdownTracker");
4244                return false;
4245            }
4246
4247            final String profileName = new String(mKeyStore.get(Credentials.LOCKDOWN_VPN));
4248            final VpnProfile profile = VpnProfile.decode(
4249                    profileName, mKeyStore.get(Credentials.VPN + profileName));
4250            int user = UserHandle.getUserId(Binder.getCallingUid());
4251            synchronized(mVpns) {
4252                setLockdownTracker(new LockdownVpnTracker(mContext, mNetd, this, mVpns.get(user),
4253                            profile));
4254            }
4255        } else {
4256            setLockdownTracker(null);
4257        }
4258
4259        return true;
4260    }
4261
4262    /**
4263     * Internally set new {@link LockdownVpnTracker}, shutting down any existing
4264     * {@link LockdownVpnTracker}. Can be {@code null} to disable lockdown.
4265     */
4266    private void setLockdownTracker(LockdownVpnTracker tracker) {
4267        // Shutdown any existing tracker
4268        final LockdownVpnTracker existing = mLockdownTracker;
4269        mLockdownTracker = null;
4270        if (existing != null) {
4271            existing.shutdown();
4272        }
4273
4274        try {
4275            if (tracker != null) {
4276                mNetd.setFirewallEnabled(true);
4277                mNetd.setFirewallInterfaceRule("lo", true);
4278                mLockdownTracker = tracker;
4279                mLockdownTracker.init();
4280            } else {
4281                mNetd.setFirewallEnabled(false);
4282            }
4283        } catch (RemoteException e) {
4284            // ignored; NMS lives inside system_server
4285        }
4286    }
4287
4288    private void throwIfLockdownEnabled() {
4289        if (mLockdownEnabled) {
4290            throw new IllegalStateException("Unavailable in lockdown mode");
4291        }
4292    }
4293
4294    public void supplyMessenger(int networkType, Messenger messenger) {
4295        enforceConnectivityInternalPermission();
4296
4297        if (isNetworkTypeValid(networkType) && mNetTrackers[networkType] != null) {
4298            mNetTrackers[networkType].supplyMessenger(messenger);
4299        }
4300    }
4301
4302    public int findConnectionTypeForIface(String iface) {
4303        enforceConnectivityInternalPermission();
4304
4305        if (TextUtils.isEmpty(iface)) return ConnectivityManager.TYPE_NONE;
4306        for (NetworkStateTracker tracker : mNetTrackers) {
4307            if (tracker != null) {
4308                LinkProperties lp = tracker.getLinkProperties();
4309                if (lp != null && iface.equals(lp.getInterfaceName())) {
4310                    return tracker.getNetworkInfo().getType();
4311                }
4312            }
4313        }
4314        return ConnectivityManager.TYPE_NONE;
4315    }
4316
4317    /**
4318     * Have mobile data fail fast if enabled.
4319     *
4320     * @param enabled DctConstants.ENABLED/DISABLED
4321     */
4322    private void setEnableFailFastMobileData(int enabled) {
4323        int tag;
4324
4325        if (enabled == DctConstants.ENABLED) {
4326            tag = mEnableFailFastMobileDataTag.incrementAndGet();
4327        } else {
4328            tag = mEnableFailFastMobileDataTag.get();
4329        }
4330        mHandler.sendMessage(mHandler.obtainMessage(EVENT_ENABLE_FAIL_FAST_MOBILE_DATA, tag,
4331                         enabled));
4332    }
4333
4334    private boolean isMobileDataStateTrackerReady() {
4335        MobileDataStateTracker mdst =
4336                (MobileDataStateTracker) mNetTrackers[ConnectivityManager.TYPE_MOBILE_HIPRI];
4337        return (mdst != null) && (mdst.isReady());
4338    }
4339
4340    /**
4341     * The ResultReceiver resultCode for checkMobileProvisioning (CMP_RESULT_CODE)
4342     */
4343
4344    /**
4345     * No connection was possible to the network.
4346     * This is NOT a warm sim.
4347     */
4348    private static final int CMP_RESULT_CODE_NO_CONNECTION = 0;
4349
4350    /**
4351     * A connection was made to the internet, all is well.
4352     * This is NOT a warm sim.
4353     */
4354    private static final int CMP_RESULT_CODE_CONNECTABLE = 1;
4355
4356    /**
4357     * A connection was made but no dns server was available to resolve a name to address.
4358     * This is NOT a warm sim since provisioning network is supported.
4359     */
4360    private static final int CMP_RESULT_CODE_NO_DNS = 2;
4361
4362    /**
4363     * A connection was made but could not open a TCP connection.
4364     * This is NOT a warm sim since provisioning network is supported.
4365     */
4366    private static final int CMP_RESULT_CODE_NO_TCP_CONNECTION = 3;
4367
4368    /**
4369     * A connection was made but there was a redirection, we appear to be in walled garden.
4370     * This is an indication of a warm sim on a mobile network such as T-Mobile.
4371     */
4372    private static final int CMP_RESULT_CODE_REDIRECTED = 4;
4373
4374    /**
4375     * The mobile network is a provisioning network.
4376     * This is an indication of a warm sim on a mobile network such as AT&T.
4377     */
4378    private static final int CMP_RESULT_CODE_PROVISIONING_NETWORK = 5;
4379
4380    /**
4381     * The mobile network is provisioning
4382     */
4383    private static final int CMP_RESULT_CODE_IS_PROVISIONING = 6;
4384
4385    private AtomicBoolean mIsProvisioningNetwork = new AtomicBoolean(false);
4386    private AtomicBoolean mIsStartingProvisioning = new AtomicBoolean(false);
4387
4388    private AtomicBoolean mIsCheckingMobileProvisioning = new AtomicBoolean(false);
4389
4390    @Override
4391    public int checkMobileProvisioning(int suggestedTimeOutMs) {
4392        int timeOutMs = -1;
4393        if (DBG) log("checkMobileProvisioning: E suggestedTimeOutMs=" + suggestedTimeOutMs);
4394        enforceConnectivityInternalPermission();
4395
4396        final long token = Binder.clearCallingIdentity();
4397        try {
4398            timeOutMs = suggestedTimeOutMs;
4399            if (suggestedTimeOutMs > CheckMp.MAX_TIMEOUT_MS) {
4400                timeOutMs = CheckMp.MAX_TIMEOUT_MS;
4401            }
4402
4403            // Check that mobile networks are supported
4404            if (!isNetworkSupported(ConnectivityManager.TYPE_MOBILE)
4405                    || !isNetworkSupported(ConnectivityManager.TYPE_MOBILE_HIPRI)) {
4406                if (DBG) log("checkMobileProvisioning: X no mobile network");
4407                return timeOutMs;
4408            }
4409
4410            // If we're already checking don't do it again
4411            // TODO: Add a queue of results...
4412            if (mIsCheckingMobileProvisioning.getAndSet(true)) {
4413                if (DBG) log("checkMobileProvisioning: X already checking ignore for the moment");
4414                return timeOutMs;
4415            }
4416
4417            // Start off with mobile notification off
4418            setProvNotificationVisible(false, ConnectivityManager.TYPE_MOBILE_HIPRI, null, null);
4419
4420            CheckMp checkMp = new CheckMp(mContext, this);
4421            CheckMp.CallBack cb = new CheckMp.CallBack() {
4422                @Override
4423                void onComplete(Integer result) {
4424                    if (DBG) log("CheckMp.onComplete: result=" + result);
4425                    NetworkInfo ni =
4426                            mNetTrackers[ConnectivityManager.TYPE_MOBILE_HIPRI].getNetworkInfo();
4427                    switch(result) {
4428                        case CMP_RESULT_CODE_CONNECTABLE:
4429                        case CMP_RESULT_CODE_NO_CONNECTION:
4430                        case CMP_RESULT_CODE_NO_DNS:
4431                        case CMP_RESULT_CODE_NO_TCP_CONNECTION: {
4432                            if (DBG) log("CheckMp.onComplete: ignore, connected or no connection");
4433                            break;
4434                        }
4435                        case CMP_RESULT_CODE_REDIRECTED: {
4436                            if (DBG) log("CheckMp.onComplete: warm sim");
4437                            String url = getMobileProvisioningUrl();
4438                            if (TextUtils.isEmpty(url)) {
4439                                url = getMobileRedirectedProvisioningUrl();
4440                            }
4441                            if (TextUtils.isEmpty(url) == false) {
4442                                if (DBG) log("CheckMp.onComplete: warm (redirected), url=" + url);
4443                                setProvNotificationVisible(true,
4444                                        ConnectivityManager.TYPE_MOBILE_HIPRI, ni.getExtraInfo(),
4445                                        url);
4446                            } else {
4447                                if (DBG) log("CheckMp.onComplete: warm (redirected), no url");
4448                            }
4449                            break;
4450                        }
4451                        case CMP_RESULT_CODE_PROVISIONING_NETWORK: {
4452                            String url = getMobileProvisioningUrl();
4453                            if (TextUtils.isEmpty(url) == false) {
4454                                if (DBG) log("CheckMp.onComplete: warm (no dns/tcp), url=" + url);
4455                                setProvNotificationVisible(true,
4456                                        ConnectivityManager.TYPE_MOBILE_HIPRI, ni.getExtraInfo(),
4457                                        url);
4458                                // Mark that we've got a provisioning network and
4459                                // Disable Mobile Data until user actually starts provisioning.
4460                                mIsProvisioningNetwork.set(true);
4461                                MobileDataStateTracker mdst = (MobileDataStateTracker)
4462                                        mNetTrackers[ConnectivityManager.TYPE_MOBILE];
4463
4464                                // Disable radio until user starts provisioning
4465                                mdst.setRadio(false);
4466                            } else {
4467                                if (DBG) log("CheckMp.onComplete: warm (no dns/tcp), no url");
4468                            }
4469                            break;
4470                        }
4471                        case CMP_RESULT_CODE_IS_PROVISIONING: {
4472                            // FIXME: Need to know when provisioning is done. Probably we can
4473                            // check the completion status if successful we're done if we
4474                            // "timedout" or still connected to provisioning APN turn off data?
4475                            if (DBG) log("CheckMp.onComplete: provisioning started");
4476                            mIsStartingProvisioning.set(false);
4477                            break;
4478                        }
4479                        default: {
4480                            loge("CheckMp.onComplete: ignore unexpected result=" + result);
4481                            break;
4482                        }
4483                    }
4484                    mIsCheckingMobileProvisioning.set(false);
4485                }
4486            };
4487            CheckMp.Params params =
4488                    new CheckMp.Params(checkMp.getDefaultUrl(), timeOutMs, cb);
4489            if (DBG) log("checkMobileProvisioning: params=" + params);
4490            // TODO: Reenable when calls to the now defunct
4491            //       MobileDataStateTracker.isProvisioningNetwork() are removed.
4492            //       This code should be moved to the Telephony code.
4493            // checkMp.execute(params);
4494        } finally {
4495            Binder.restoreCallingIdentity(token);
4496            if (DBG) log("checkMobileProvisioning: X");
4497        }
4498        return timeOutMs;
4499    }
4500
4501    static class CheckMp extends
4502            AsyncTask<CheckMp.Params, Void, Integer> {
4503        private static final String CHECKMP_TAG = "CheckMp";
4504
4505        // adb shell setprop persist.checkmp.testfailures 1 to enable testing failures
4506        private static boolean mTestingFailures;
4507
4508        // Choosing 4 loops as half of them will use HTTPS and the other half HTTP
4509        private static final int MAX_LOOPS = 4;
4510
4511        // Number of milli-seconds to complete all of the retires
4512        public static final int MAX_TIMEOUT_MS =  60000;
4513
4514        // The socket should retry only 5 seconds, the default is longer
4515        private static final int SOCKET_TIMEOUT_MS = 5000;
4516
4517        // Sleep time for network errors
4518        private static final int NET_ERROR_SLEEP_SEC = 3;
4519
4520        // Sleep time for network route establishment
4521        private static final int NET_ROUTE_ESTABLISHMENT_SLEEP_SEC = 3;
4522
4523        // Short sleep time for polling :(
4524        private static final int POLLING_SLEEP_SEC = 1;
4525
4526        private Context mContext;
4527        private ConnectivityService mCs;
4528        private TelephonyManager mTm;
4529        private Params mParams;
4530
4531        /**
4532         * Parameters for AsyncTask.execute
4533         */
4534        static class Params {
4535            private String mUrl;
4536            private long mTimeOutMs;
4537            private CallBack mCb;
4538
4539            Params(String url, long timeOutMs, CallBack cb) {
4540                mUrl = url;
4541                mTimeOutMs = timeOutMs;
4542                mCb = cb;
4543            }
4544
4545            @Override
4546            public String toString() {
4547                return "{" + " url=" + mUrl + " mTimeOutMs=" + mTimeOutMs + " mCb=" + mCb + "}";
4548            }
4549        }
4550
4551        // As explained to me by Brian Carlstrom and Kenny Root, Certificates can be
4552        // issued by name or ip address, for Google its by name so when we construct
4553        // this HostnameVerifier we'll pass the original Uri and use it to verify
4554        // the host. If the host name in the original uril fails we'll test the
4555        // hostname parameter just incase things change.
4556        static class CheckMpHostnameVerifier implements HostnameVerifier {
4557            Uri mOrgUri;
4558
4559            CheckMpHostnameVerifier(Uri orgUri) {
4560                mOrgUri = orgUri;
4561            }
4562
4563            @Override
4564            public boolean verify(String hostname, SSLSession session) {
4565                HostnameVerifier hv = HttpsURLConnection.getDefaultHostnameVerifier();
4566                String orgUriHost = mOrgUri.getHost();
4567                boolean retVal = hv.verify(orgUriHost, session) || hv.verify(hostname, session);
4568                if (DBG) {
4569                    log("isMobileOk: hostnameVerify retVal=" + retVal + " hostname=" + hostname
4570                        + " orgUriHost=" + orgUriHost);
4571                }
4572                return retVal;
4573            }
4574        }
4575
4576        /**
4577         * The call back object passed in Params. onComplete will be called
4578         * on the main thread.
4579         */
4580        abstract static class CallBack {
4581            // Called on the main thread.
4582            abstract void onComplete(Integer result);
4583        }
4584
4585        public CheckMp(Context context, ConnectivityService cs) {
4586            if (Build.IS_DEBUGGABLE) {
4587                mTestingFailures =
4588                        SystemProperties.getInt("persist.checkmp.testfailures", 0) == 1;
4589            } else {
4590                mTestingFailures = false;
4591            }
4592
4593            mContext = context;
4594            mCs = cs;
4595
4596            // Setup access to TelephonyService we'll be using.
4597            mTm = (TelephonyManager) mContext.getSystemService(
4598                    Context.TELEPHONY_SERVICE);
4599        }
4600
4601        /**
4602         * Get the default url to use for the test.
4603         */
4604        public String getDefaultUrl() {
4605            // See http://go/clientsdns for usage approval
4606            String server = Settings.Global.getString(mContext.getContentResolver(),
4607                    Settings.Global.CAPTIVE_PORTAL_SERVER);
4608            if (server == null) {
4609                server = "clients3.google.com";
4610            }
4611            return "http://" + server + "/generate_204";
4612        }
4613
4614        /**
4615         * Detect if its possible to connect to the http url. DNS based detection techniques
4616         * do not work at all hotspots. The best way to check is to perform a request to
4617         * a known address that fetches the data we expect.
4618         */
4619        private synchronized Integer isMobileOk(Params params) {
4620            Integer result = CMP_RESULT_CODE_NO_CONNECTION;
4621            Uri orgUri = Uri.parse(params.mUrl);
4622            Random rand = new Random();
4623            mParams = params;
4624
4625            if (mCs.isNetworkSupported(ConnectivityManager.TYPE_MOBILE) == false) {
4626                result = CMP_RESULT_CODE_NO_CONNECTION;
4627                log("isMobileOk: X not mobile capable result=" + result);
4628                return result;
4629            }
4630
4631            if (mCs.mIsStartingProvisioning.get()) {
4632                result = CMP_RESULT_CODE_IS_PROVISIONING;
4633                log("isMobileOk: X is provisioning result=" + result);
4634                return result;
4635            }
4636
4637            // See if we've already determined we've got a provisioning connection,
4638            // if so we don't need to do anything active.
4639            MobileDataStateTracker mdstDefault = (MobileDataStateTracker)
4640                    mCs.mNetTrackers[ConnectivityManager.TYPE_MOBILE];
4641            boolean isDefaultProvisioning = mdstDefault.isProvisioningNetwork();
4642            log("isMobileOk: isDefaultProvisioning=" + isDefaultProvisioning);
4643
4644            MobileDataStateTracker mdstHipri = (MobileDataStateTracker)
4645                    mCs.mNetTrackers[ConnectivityManager.TYPE_MOBILE_HIPRI];
4646            boolean isHipriProvisioning = mdstHipri.isProvisioningNetwork();
4647            log("isMobileOk: isHipriProvisioning=" + isHipriProvisioning);
4648
4649            if (isDefaultProvisioning || isHipriProvisioning) {
4650                result = CMP_RESULT_CODE_PROVISIONING_NETWORK;
4651                log("isMobileOk: X default || hipri is provisioning result=" + result);
4652                return result;
4653            }
4654
4655            try {
4656                // Continue trying to connect until time has run out
4657                long endTime = SystemClock.elapsedRealtime() + params.mTimeOutMs;
4658
4659                if (!mCs.isMobileDataStateTrackerReady()) {
4660                    // Wait for MobileDataStateTracker to be ready.
4661                    if (DBG) log("isMobileOk: mdst is not ready");
4662                    while(SystemClock.elapsedRealtime() < endTime) {
4663                        if (mCs.isMobileDataStateTrackerReady()) {
4664                            // Enable fail fast as we'll do retries here and use a
4665                            // hipri connection so the default connection stays active.
4666                            if (DBG) log("isMobileOk: mdst ready, enable fail fast of mobile data");
4667                            mCs.setEnableFailFastMobileData(DctConstants.ENABLED);
4668                            break;
4669                        }
4670                        sleep(POLLING_SLEEP_SEC);
4671                    }
4672                }
4673
4674                log("isMobileOk: start hipri url=" + params.mUrl);
4675
4676                // First wait until we can start using hipri
4677                Binder binder = new Binder();
4678                while(SystemClock.elapsedRealtime() < endTime) {
4679                    int ret = mCs.startUsingNetworkFeature(ConnectivityManager.TYPE_MOBILE,
4680                            Phone.FEATURE_ENABLE_HIPRI, binder);
4681                    if ((ret == PhoneConstants.APN_ALREADY_ACTIVE)
4682                        || (ret == PhoneConstants.APN_REQUEST_STARTED)) {
4683                            log("isMobileOk: hipri started");
4684                            break;
4685                    }
4686                    if (VDBG) log("isMobileOk: hipri not started yet");
4687                    result = CMP_RESULT_CODE_NO_CONNECTION;
4688                    sleep(POLLING_SLEEP_SEC);
4689                }
4690
4691                // Continue trying to connect until time has run out
4692                while(SystemClock.elapsedRealtime() < endTime) {
4693                    try {
4694                        // Wait for hipri to connect.
4695                        // TODO: Don't poll and handle situation where hipri fails
4696                        // because default is retrying. See b/9569540
4697                        NetworkInfo.State state = mCs
4698                                .getNetworkInfo(ConnectivityManager.TYPE_MOBILE_HIPRI).getState();
4699                        if (state != NetworkInfo.State.CONNECTED) {
4700                            if (true/*VDBG*/) {
4701                                log("isMobileOk: not connected ni=" +
4702                                    mCs.getNetworkInfo(ConnectivityManager.TYPE_MOBILE_HIPRI));
4703                            }
4704                            sleep(POLLING_SLEEP_SEC);
4705                            result = CMP_RESULT_CODE_NO_CONNECTION;
4706                            continue;
4707                        }
4708
4709                        // Hipri has started check if this is a provisioning url
4710                        MobileDataStateTracker mdst = (MobileDataStateTracker)
4711                                mCs.mNetTrackers[ConnectivityManager.TYPE_MOBILE_HIPRI];
4712                        if (mdst.isProvisioningNetwork()) {
4713                            result = CMP_RESULT_CODE_PROVISIONING_NETWORK;
4714                            if (DBG) log("isMobileOk: X isProvisioningNetwork result=" + result);
4715                            return result;
4716                        } else {
4717                            if (DBG) log("isMobileOk: isProvisioningNetwork is false, continue");
4718                        }
4719
4720                        // Get of the addresses associated with the url host. We need to use the
4721                        // address otherwise HttpURLConnection object will use the name to get
4722                        // the addresses and will try every address but that will bypass the
4723                        // route to host we setup and the connection could succeed as the default
4724                        // interface might be connected to the internet via wifi or other interface.
4725                        InetAddress[] addresses;
4726                        try {
4727                            addresses = InetAddress.getAllByName(orgUri.getHost());
4728                        } catch (UnknownHostException e) {
4729                            result = CMP_RESULT_CODE_NO_DNS;
4730                            log("isMobileOk: X UnknownHostException result=" + result);
4731                            return result;
4732                        }
4733                        log("isMobileOk: addresses=" + inetAddressesToString(addresses));
4734
4735                        // Get the type of addresses supported by this link
4736                        LinkProperties lp = mCs.getLinkPropertiesForTypeInternal(
4737                                ConnectivityManager.TYPE_MOBILE_HIPRI);
4738                        boolean linkHasIpv4 = lp.hasIPv4Address();
4739                        boolean linkHasIpv6 = lp.hasGlobalIPv6Address();
4740                        log("isMobileOk: linkHasIpv4=" + linkHasIpv4
4741                                + " linkHasIpv6=" + linkHasIpv6);
4742
4743                        final ArrayList<InetAddress> validAddresses =
4744                                new ArrayList<InetAddress>(addresses.length);
4745
4746                        for (InetAddress addr : addresses) {
4747                            if (((addr instanceof Inet4Address) && linkHasIpv4) ||
4748                                    ((addr instanceof Inet6Address) && linkHasIpv6)) {
4749                                validAddresses.add(addr);
4750                            }
4751                        }
4752
4753                        if (validAddresses.size() == 0) {
4754                            return CMP_RESULT_CODE_NO_CONNECTION;
4755                        }
4756
4757                        int addrTried = 0;
4758                        while (true) {
4759                            // Loop through at most MAX_LOOPS valid addresses or until
4760                            // we run out of time
4761                            if (addrTried++ >= MAX_LOOPS) {
4762                                log("isMobileOk: too many loops tried - giving up");
4763                                break;
4764                            }
4765                            if (SystemClock.elapsedRealtime() >= endTime) {
4766                                log("isMobileOk: spend too much time - giving up");
4767                                break;
4768                            }
4769
4770                            InetAddress hostAddr = validAddresses.get(rand.nextInt(
4771                                    validAddresses.size()));
4772
4773                            // Make a route to host so we check the specific interface.
4774                            if (mCs.requestRouteToHostAddress(ConnectivityManager.TYPE_MOBILE_HIPRI,
4775                                    hostAddr.getAddress(), null)) {
4776                                // Wait a short time to be sure the route is established ??
4777                                log("isMobileOk:"
4778                                        + " wait to establish route to hostAddr=" + hostAddr);
4779                                sleep(NET_ROUTE_ESTABLISHMENT_SLEEP_SEC);
4780                            } else {
4781                                log("isMobileOk:"
4782                                        + " could not establish route to hostAddr=" + hostAddr);
4783                                // Wait a short time before the next attempt
4784                                sleep(NET_ERROR_SLEEP_SEC);
4785                                continue;
4786                            }
4787
4788                            // Rewrite the url to have numeric address to use the specific route
4789                            // using http for half the attempts and https for the other half.
4790                            // Doing https first and http second as on a redirected walled garden
4791                            // such as t-mobile uses we get a SocketTimeoutException: "SSL
4792                            // handshake timed out" which we declare as
4793                            // CMP_RESULT_CODE_NO_TCP_CONNECTION. We could change this, but by
4794                            // having http second we will be using logic used for some time.
4795                            URL newUrl;
4796                            String scheme = (addrTried <= (MAX_LOOPS/2)) ? "https" : "http";
4797                            newUrl = new URL(scheme, hostAddr.getHostAddress(),
4798                                        orgUri.getPath());
4799                            log("isMobileOk: newUrl=" + newUrl);
4800
4801                            HttpURLConnection urlConn = null;
4802                            try {
4803                                // Open the connection set the request headers and get the response
4804                                urlConn = (HttpURLConnection)newUrl.openConnection(
4805                                        java.net.Proxy.NO_PROXY);
4806                                if (scheme.equals("https")) {
4807                                    ((HttpsURLConnection)urlConn).setHostnameVerifier(
4808                                            new CheckMpHostnameVerifier(orgUri));
4809                                }
4810                                urlConn.setInstanceFollowRedirects(false);
4811                                urlConn.setConnectTimeout(SOCKET_TIMEOUT_MS);
4812                                urlConn.setReadTimeout(SOCKET_TIMEOUT_MS);
4813                                urlConn.setUseCaches(false);
4814                                urlConn.setAllowUserInteraction(false);
4815                                // Set the "Connection" to "Close" as by default "Keep-Alive"
4816                                // is used which is useless in this case.
4817                                urlConn.setRequestProperty("Connection", "close");
4818                                int responseCode = urlConn.getResponseCode();
4819
4820                                // For debug display the headers
4821                                Map<String, List<String>> headers = urlConn.getHeaderFields();
4822                                log("isMobileOk: headers=" + headers);
4823
4824                                // Close the connection
4825                                urlConn.disconnect();
4826                                urlConn = null;
4827
4828                                if (mTestingFailures) {
4829                                    // Pretend no connection, this tests using http and https
4830                                    result = CMP_RESULT_CODE_NO_CONNECTION;
4831                                    log("isMobileOk: TESTING_FAILURES, pretend no connction");
4832                                    continue;
4833                                }
4834
4835                                if (responseCode == 204) {
4836                                    // Return
4837                                    result = CMP_RESULT_CODE_CONNECTABLE;
4838                                    log("isMobileOk: X got expected responseCode=" + responseCode
4839                                            + " result=" + result);
4840                                    return result;
4841                                } else {
4842                                    // Retry to be sure this was redirected, we've gotten
4843                                    // occasions where a server returned 200 even though
4844                                    // the device didn't have a "warm" sim.
4845                                    log("isMobileOk: not expected responseCode=" + responseCode);
4846                                    // TODO - it would be nice in the single-address case to do
4847                                    // another DNS resolve here, but flushing the cache is a bit
4848                                    // heavy-handed.
4849                                    result = CMP_RESULT_CODE_REDIRECTED;
4850                                }
4851                            } catch (Exception e) {
4852                                log("isMobileOk: HttpURLConnection Exception" + e);
4853                                result = CMP_RESULT_CODE_NO_TCP_CONNECTION;
4854                                if (urlConn != null) {
4855                                    urlConn.disconnect();
4856                                    urlConn = null;
4857                                }
4858                                sleep(NET_ERROR_SLEEP_SEC);
4859                                continue;
4860                            }
4861                        }
4862                        log("isMobileOk: X loops|timed out result=" + result);
4863                        return result;
4864                    } catch (Exception e) {
4865                        log("isMobileOk: Exception e=" + e);
4866                        continue;
4867                    }
4868                }
4869                log("isMobileOk: timed out");
4870            } finally {
4871                log("isMobileOk: F stop hipri");
4872                mCs.setEnableFailFastMobileData(DctConstants.DISABLED);
4873                mCs.stopUsingNetworkFeature(ConnectivityManager.TYPE_MOBILE,
4874                        Phone.FEATURE_ENABLE_HIPRI);
4875
4876                // Wait for hipri to disconnect.
4877                long endTime = SystemClock.elapsedRealtime() + 5000;
4878
4879                while(SystemClock.elapsedRealtime() < endTime) {
4880                    NetworkInfo.State state = mCs
4881                            .getNetworkInfo(ConnectivityManager.TYPE_MOBILE_HIPRI).getState();
4882                    if (state != NetworkInfo.State.DISCONNECTED) {
4883                        if (VDBG) {
4884                            log("isMobileOk: connected ni=" +
4885                                mCs.getNetworkInfo(ConnectivityManager.TYPE_MOBILE_HIPRI));
4886                        }
4887                        sleep(POLLING_SLEEP_SEC);
4888                        continue;
4889                    }
4890                }
4891
4892                log("isMobileOk: X result=" + result);
4893            }
4894            return result;
4895        }
4896
4897        @Override
4898        protected Integer doInBackground(Params... params) {
4899            return isMobileOk(params[0]);
4900        }
4901
4902        @Override
4903        protected void onPostExecute(Integer result) {
4904            log("onPostExecute: result=" + result);
4905            if ((mParams != null) && (mParams.mCb != null)) {
4906                mParams.mCb.onComplete(result);
4907            }
4908        }
4909
4910        private String inetAddressesToString(InetAddress[] addresses) {
4911            StringBuffer sb = new StringBuffer();
4912            boolean firstTime = true;
4913            for(InetAddress addr : addresses) {
4914                if (firstTime) {
4915                    firstTime = false;
4916                } else {
4917                    sb.append(",");
4918                }
4919                sb.append(addr);
4920            }
4921            return sb.toString();
4922        }
4923
4924        private void printNetworkInfo() {
4925            boolean hasIccCard = mTm.hasIccCard();
4926            int simState = mTm.getSimState();
4927            log("hasIccCard=" + hasIccCard
4928                    + " simState=" + simState);
4929            NetworkInfo[] ni = mCs.getAllNetworkInfo();
4930            if (ni != null) {
4931                log("ni.length=" + ni.length);
4932                for (NetworkInfo netInfo: ni) {
4933                    log("netInfo=" + netInfo.toString());
4934                }
4935            } else {
4936                log("no network info ni=null");
4937            }
4938        }
4939
4940        /**
4941         * Sleep for a few seconds then return.
4942         * @param seconds
4943         */
4944        private static void sleep(int seconds) {
4945            long stopTime = System.nanoTime() + (seconds * 1000000000);
4946            long sleepTime;
4947            while ((sleepTime = stopTime - System.nanoTime()) > 0) {
4948                try {
4949                    Thread.sleep(sleepTime / 1000000);
4950                } catch (InterruptedException ignored) {
4951                }
4952            }
4953        }
4954
4955        private static void log(String s) {
4956            Slog.d(ConnectivityService.TAG, "[" + CHECKMP_TAG + "] " + s);
4957        }
4958    }
4959
4960    // TODO: Move to ConnectivityManager and make public?
4961    private static final String CONNECTED_TO_PROVISIONING_NETWORK_ACTION =
4962            "com.android.server.connectivityservice.CONNECTED_TO_PROVISIONING_NETWORK_ACTION";
4963
4964    private BroadcastReceiver mProvisioningReceiver = new BroadcastReceiver() {
4965        @Override
4966        public void onReceive(Context context, Intent intent) {
4967            if (intent.getAction().equals(CONNECTED_TO_PROVISIONING_NETWORK_ACTION)) {
4968                handleMobileProvisioningAction(intent.getStringExtra("EXTRA_URL"));
4969            }
4970        }
4971    };
4972
4973    private void handleMobileProvisioningAction(String url) {
4974        // Mark notification as not visible
4975        setProvNotificationVisible(false, ConnectivityManager.TYPE_MOBILE_HIPRI, null, null);
4976
4977        // Check airplane mode
4978        boolean isAirplaneModeOn = Settings.System.getInt(mContext.getContentResolver(),
4979                Settings.Global.AIRPLANE_MODE_ON, 0) == 1;
4980        // If provisioning network and not in airplane mode handle as a special case,
4981        // otherwise launch browser with the intent directly.
4982        if (mIsProvisioningNetwork.get() && !isAirplaneModeOn) {
4983            if (DBG) log("handleMobileProvisioningAction: on prov network enable then launch");
4984            mIsProvisioningNetwork.set(false);
4985//            mIsStartingProvisioning.set(true);
4986//            MobileDataStateTracker mdst = (MobileDataStateTracker)
4987//                    mNetTrackers[ConnectivityManager.TYPE_MOBILE];
4988            // Radio was disabled on CMP_RESULT_CODE_PROVISIONING_NETWORK, enable it here
4989//            mdst.setRadio(true);
4990//            mdst.setEnableFailFastMobileData(DctConstants.ENABLED);
4991//            mdst.enableMobileProvisioning(url);
4992        } else {
4993            if (DBG) log("handleMobileProvisioningAction: not prov network");
4994            mIsProvisioningNetwork.set(false);
4995            // Check for  apps that can handle provisioning first
4996            Intent provisioningIntent = new Intent(TelephonyIntents.ACTION_CARRIER_SETUP);
4997            provisioningIntent.addCategory(TelephonyIntents.CATEGORY_MCCMNC_PREFIX
4998                    + mTelephonyManager.getSimOperator());
4999            if (mContext.getPackageManager().resolveActivity(provisioningIntent, 0 /* flags */)
5000                    != null) {
5001                provisioningIntent.setFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT |
5002                        Intent.FLAG_ACTIVITY_NEW_TASK);
5003                mContext.startActivity(provisioningIntent);
5004            } else {
5005                // If no apps exist, use standard URL ACTION_VIEW method
5006                Intent newIntent = Intent.makeMainSelectorActivity(Intent.ACTION_MAIN,
5007                        Intent.CATEGORY_APP_BROWSER);
5008                newIntent.setData(Uri.parse(url));
5009                newIntent.setFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT |
5010                        Intent.FLAG_ACTIVITY_NEW_TASK);
5011                try {
5012                    mContext.startActivity(newIntent);
5013                } catch (ActivityNotFoundException e) {
5014                    loge("handleMobileProvisioningAction: startActivity failed" + e);
5015                }
5016            }
5017        }
5018    }
5019
5020    private static final String NOTIFICATION_ID = "CaptivePortal.Notification";
5021    private volatile boolean mIsNotificationVisible = false;
5022
5023    private void setProvNotificationVisible(boolean visible, int networkType, String extraInfo,
5024            String url) {
5025        if (DBG) {
5026            log("setProvNotificationVisible: E visible=" + visible + " networkType=" + networkType
5027                + " extraInfo=" + extraInfo + " url=" + url);
5028        }
5029
5030        Resources r = Resources.getSystem();
5031        NotificationManager notificationManager = (NotificationManager) mContext
5032            .getSystemService(Context.NOTIFICATION_SERVICE);
5033
5034        if (visible) {
5035            CharSequence title;
5036            CharSequence details;
5037            int icon;
5038            Intent intent;
5039            Notification notification = new Notification();
5040            switch (networkType) {
5041                case ConnectivityManager.TYPE_WIFI:
5042                    title = r.getString(R.string.wifi_available_sign_in, 0);
5043                    details = r.getString(R.string.network_available_sign_in_detailed,
5044                            extraInfo);
5045                    icon = R.drawable.stat_notify_wifi_in_range;
5046                    intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
5047                    intent.setFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT |
5048                            Intent.FLAG_ACTIVITY_NEW_TASK);
5049                    notification.contentIntent = PendingIntent.getActivity(mContext, 0, intent, 0);
5050                    break;
5051                case ConnectivityManager.TYPE_MOBILE:
5052                case ConnectivityManager.TYPE_MOBILE_HIPRI:
5053                    title = r.getString(R.string.network_available_sign_in, 0);
5054                    // TODO: Change this to pull from NetworkInfo once a printable
5055                    // name has been added to it
5056                    details = mTelephonyManager.getNetworkOperatorName();
5057                    icon = R.drawable.stat_notify_rssi_in_range;
5058                    intent = new Intent(CONNECTED_TO_PROVISIONING_NETWORK_ACTION);
5059                    intent.putExtra("EXTRA_URL", url);
5060                    intent.setFlags(0);
5061                    notification.contentIntent = PendingIntent.getBroadcast(mContext, 0, intent, 0);
5062                    break;
5063                default:
5064                    title = r.getString(R.string.network_available_sign_in, 0);
5065                    details = r.getString(R.string.network_available_sign_in_detailed,
5066                            extraInfo);
5067                    icon = R.drawable.stat_notify_rssi_in_range;
5068                    intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
5069                    intent.setFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT |
5070                            Intent.FLAG_ACTIVITY_NEW_TASK);
5071                    notification.contentIntent = PendingIntent.getActivity(mContext, 0, intent, 0);
5072                    break;
5073            }
5074
5075            notification.when = 0;
5076            notification.icon = icon;
5077            notification.flags = Notification.FLAG_AUTO_CANCEL;
5078            notification.tickerText = title;
5079            notification.setLatestEventInfo(mContext, title, details, notification.contentIntent);
5080
5081            try {
5082                notificationManager.notify(NOTIFICATION_ID, networkType, notification);
5083            } catch (NullPointerException npe) {
5084                loge("setNotificaitionVisible: visible notificationManager npe=" + npe);
5085                npe.printStackTrace();
5086            }
5087        } else {
5088            try {
5089                notificationManager.cancel(NOTIFICATION_ID, networkType);
5090            } catch (NullPointerException npe) {
5091                loge("setNotificaitionVisible: cancel notificationManager npe=" + npe);
5092                npe.printStackTrace();
5093            }
5094        }
5095        mIsNotificationVisible = visible;
5096    }
5097
5098    /** Location to an updatable file listing carrier provisioning urls.
5099     *  An example:
5100     *
5101     * <?xml version="1.0" encoding="utf-8"?>
5102     *  <provisioningUrls>
5103     *   <provisioningUrl mcc="310" mnc="4">http://myserver.com/foo?mdn=%3$s&iccid=%1$s&imei=%2$s</provisioningUrl>
5104     *   <redirectedUrl mcc="310" mnc="4">http://www.google.com</redirectedUrl>
5105     *  </provisioningUrls>
5106     */
5107    private static final String PROVISIONING_URL_PATH =
5108            "/data/misc/radio/provisioning_urls.xml";
5109    private final File mProvisioningUrlFile = new File(PROVISIONING_URL_PATH);
5110
5111    /** XML tag for root element. */
5112    private static final String TAG_PROVISIONING_URLS = "provisioningUrls";
5113    /** XML tag for individual url */
5114    private static final String TAG_PROVISIONING_URL = "provisioningUrl";
5115    /** XML tag for redirected url */
5116    private static final String TAG_REDIRECTED_URL = "redirectedUrl";
5117    /** XML attribute for mcc */
5118    private static final String ATTR_MCC = "mcc";
5119    /** XML attribute for mnc */
5120    private static final String ATTR_MNC = "mnc";
5121
5122    private static final int REDIRECTED_PROVISIONING = 1;
5123    private static final int PROVISIONING = 2;
5124
5125    private String getProvisioningUrlBaseFromFile(int type) {
5126        FileReader fileReader = null;
5127        XmlPullParser parser = null;
5128        Configuration config = mContext.getResources().getConfiguration();
5129        String tagType;
5130
5131        switch (type) {
5132            case PROVISIONING:
5133                tagType = TAG_PROVISIONING_URL;
5134                break;
5135            case REDIRECTED_PROVISIONING:
5136                tagType = TAG_REDIRECTED_URL;
5137                break;
5138            default:
5139                throw new RuntimeException("getProvisioningUrlBaseFromFile: Unexpected parameter " +
5140                        type);
5141        }
5142
5143        try {
5144            fileReader = new FileReader(mProvisioningUrlFile);
5145            parser = Xml.newPullParser();
5146            parser.setInput(fileReader);
5147            XmlUtils.beginDocument(parser, TAG_PROVISIONING_URLS);
5148
5149            while (true) {
5150                XmlUtils.nextElement(parser);
5151
5152                String element = parser.getName();
5153                if (element == null) break;
5154
5155                if (element.equals(tagType)) {
5156                    String mcc = parser.getAttributeValue(null, ATTR_MCC);
5157                    try {
5158                        if (mcc != null && Integer.parseInt(mcc) == config.mcc) {
5159                            String mnc = parser.getAttributeValue(null, ATTR_MNC);
5160                            if (mnc != null && Integer.parseInt(mnc) == config.mnc) {
5161                                parser.next();
5162                                if (parser.getEventType() == XmlPullParser.TEXT) {
5163                                    return parser.getText();
5164                                }
5165                            }
5166                        }
5167                    } catch (NumberFormatException e) {
5168                        loge("NumberFormatException in getProvisioningUrlBaseFromFile: " + e);
5169                    }
5170                }
5171            }
5172            return null;
5173        } catch (FileNotFoundException e) {
5174            loge("Carrier Provisioning Urls file not found");
5175        } catch (XmlPullParserException e) {
5176            loge("Xml parser exception reading Carrier Provisioning Urls file: " + e);
5177        } catch (IOException e) {
5178            loge("I/O exception reading Carrier Provisioning Urls file: " + e);
5179        } finally {
5180            if (fileReader != null) {
5181                try {
5182                    fileReader.close();
5183                } catch (IOException e) {}
5184            }
5185        }
5186        return null;
5187    }
5188
5189    @Override
5190    public String getMobileRedirectedProvisioningUrl() {
5191        enforceConnectivityInternalPermission();
5192        String url = getProvisioningUrlBaseFromFile(REDIRECTED_PROVISIONING);
5193        if (TextUtils.isEmpty(url)) {
5194            url = mContext.getResources().getString(R.string.mobile_redirected_provisioning_url);
5195        }
5196        return url;
5197    }
5198
5199    @Override
5200    public String getMobileProvisioningUrl() {
5201        enforceConnectivityInternalPermission();
5202        String url = getProvisioningUrlBaseFromFile(PROVISIONING);
5203        if (TextUtils.isEmpty(url)) {
5204            url = mContext.getResources().getString(R.string.mobile_provisioning_url);
5205            log("getMobileProvisioningUrl: mobile_provisioining_url from resource =" + url);
5206        } else {
5207            log("getMobileProvisioningUrl: mobile_provisioning_url from File =" + url);
5208        }
5209        // populate the iccid, imei and phone number in the provisioning url.
5210        if (!TextUtils.isEmpty(url)) {
5211            String phoneNumber = mTelephonyManager.getLine1Number();
5212            if (TextUtils.isEmpty(phoneNumber)) {
5213                phoneNumber = "0000000000";
5214            }
5215            url = String.format(url,
5216                    mTelephonyManager.getSimSerialNumber() /* ICCID */,
5217                    mTelephonyManager.getDeviceId() /* IMEI */,
5218                    phoneNumber /* Phone numer */);
5219        }
5220
5221        return url;
5222    }
5223
5224    @Override
5225    public void setProvisioningNotificationVisible(boolean visible, int networkType,
5226            String extraInfo, String url) {
5227        enforceConnectivityInternalPermission();
5228        setProvNotificationVisible(visible, networkType, extraInfo, url);
5229    }
5230
5231    @Override
5232    public void setAirplaneMode(boolean enable) {
5233        enforceConnectivityInternalPermission();
5234        final long ident = Binder.clearCallingIdentity();
5235        try {
5236            final ContentResolver cr = mContext.getContentResolver();
5237            Settings.Global.putInt(cr, Settings.Global.AIRPLANE_MODE_ON, enable ? 1 : 0);
5238            Intent intent = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED);
5239            intent.putExtra("state", enable);
5240            mContext.sendBroadcast(intent);
5241        } finally {
5242            Binder.restoreCallingIdentity(ident);
5243        }
5244    }
5245
5246    private void onUserStart(int userId) {
5247        synchronized(mVpns) {
5248            Vpn userVpn = mVpns.get(userId);
5249            if (userVpn != null) {
5250                loge("Starting user already has a VPN");
5251                return;
5252            }
5253            userVpn = new Vpn(mContext, mVpnCallback, mNetd, this, userId);
5254            mVpns.put(userId, userVpn);
5255            userVpn.startMonitoring(mContext, mTrackerHandler);
5256        }
5257    }
5258
5259    private void onUserStop(int userId) {
5260        synchronized(mVpns) {
5261            Vpn userVpn = mVpns.get(userId);
5262            if (userVpn == null) {
5263                loge("Stopping user has no VPN");
5264                return;
5265            }
5266            mVpns.delete(userId);
5267        }
5268    }
5269
5270    private BroadcastReceiver mUserIntentReceiver = new BroadcastReceiver() {
5271        @Override
5272        public void onReceive(Context context, Intent intent) {
5273            final String action = intent.getAction();
5274            final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
5275            if (userId == UserHandle.USER_NULL) return;
5276
5277            if (Intent.ACTION_USER_STARTING.equals(action)) {
5278                onUserStart(userId);
5279            } else if (Intent.ACTION_USER_STOPPING.equals(action)) {
5280                onUserStop(userId);
5281            }
5282        }
5283    };
5284
5285    @Override
5286    public LinkQualityInfo getLinkQualityInfo(int networkType) {
5287        enforceAccessPermission();
5288        if (isNetworkTypeValid(networkType) && mNetTrackers[networkType] != null) {
5289            return mNetTrackers[networkType].getLinkQualityInfo();
5290        } else {
5291            return null;
5292        }
5293    }
5294
5295    @Override
5296    public LinkQualityInfo getActiveLinkQualityInfo() {
5297        enforceAccessPermission();
5298        if (isNetworkTypeValid(mActiveDefaultNetwork) &&
5299                mNetTrackers[mActiveDefaultNetwork] != null) {
5300            return mNetTrackers[mActiveDefaultNetwork].getLinkQualityInfo();
5301        } else {
5302            return null;
5303        }
5304    }
5305
5306    @Override
5307    public LinkQualityInfo[] getAllLinkQualityInfo() {
5308        enforceAccessPermission();
5309        final ArrayList<LinkQualityInfo> result = Lists.newArrayList();
5310        for (NetworkStateTracker tracker : mNetTrackers) {
5311            if (tracker != null) {
5312                LinkQualityInfo li = tracker.getLinkQualityInfo();
5313                if (li != null) {
5314                    result.add(li);
5315                }
5316            }
5317        }
5318
5319        return result.toArray(new LinkQualityInfo[result.size()]);
5320    }
5321
5322    /* Infrastructure for network sampling */
5323
5324    private void handleNetworkSamplingTimeout() {
5325
5326        log("Sampling interval elapsed, updating statistics ..");
5327
5328        // initialize list of interfaces ..
5329        Map<String, SamplingDataTracker.SamplingSnapshot> mapIfaceToSample =
5330                new HashMap<String, SamplingDataTracker.SamplingSnapshot>();
5331        for (NetworkStateTracker tracker : mNetTrackers) {
5332            if (tracker != null) {
5333                String ifaceName = tracker.getNetworkInterfaceName();
5334                if (ifaceName != null) {
5335                    mapIfaceToSample.put(ifaceName, null);
5336                }
5337            }
5338        }
5339
5340        // Read samples for all interfaces
5341        SamplingDataTracker.getSamplingSnapshots(mapIfaceToSample);
5342
5343        // process samples for all networks
5344        for (NetworkStateTracker tracker : mNetTrackers) {
5345            if (tracker != null) {
5346                String ifaceName = tracker.getNetworkInterfaceName();
5347                SamplingDataTracker.SamplingSnapshot ss = mapIfaceToSample.get(ifaceName);
5348                if (ss != null) {
5349                    // end the previous sampling cycle
5350                    tracker.stopSampling(ss);
5351                    // start a new sampling cycle ..
5352                    tracker.startSampling(ss);
5353                }
5354            }
5355        }
5356
5357        log("Done.");
5358
5359        int samplingIntervalInSeconds = Settings.Global.getInt(mContext.getContentResolver(),
5360                Settings.Global.CONNECTIVITY_SAMPLING_INTERVAL_IN_SECONDS,
5361                DEFAULT_SAMPLING_INTERVAL_IN_SECONDS);
5362
5363        if (DBG) log("Setting timer for " + String.valueOf(samplingIntervalInSeconds) + "seconds");
5364
5365        setAlarm(samplingIntervalInSeconds * 1000, mSampleIntervalElapsedIntent);
5366    }
5367
5368    void setAlarm(int timeoutInMilliseconds, PendingIntent intent) {
5369        long wakeupTime = SystemClock.elapsedRealtime() + timeoutInMilliseconds;
5370        mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, wakeupTime, intent);
5371    }
5372
5373    private final HashMap<Messenger, NetworkFactoryInfo> mNetworkFactoryInfos =
5374            new HashMap<Messenger, NetworkFactoryInfo>();
5375    private final HashMap<NetworkRequest, NetworkRequestInfo> mNetworkRequests =
5376            new HashMap<NetworkRequest, NetworkRequestInfo>();
5377
5378    private static class NetworkFactoryInfo {
5379        public final String name;
5380        public final Messenger messenger;
5381        public final AsyncChannel asyncChannel;
5382
5383        public NetworkFactoryInfo(String name, Messenger messenger, AsyncChannel asyncChannel) {
5384            this.name = name;
5385            this.messenger = messenger;
5386            this.asyncChannel = asyncChannel;
5387        }
5388    }
5389
5390    private class NetworkRequestInfo implements IBinder.DeathRecipient {
5391        static final boolean REQUEST = true;
5392        static final boolean LISTEN = false;
5393
5394        final NetworkRequest request;
5395        IBinder mBinder;
5396        final int mPid;
5397        final int mUid;
5398        final Messenger messenger;
5399        final boolean isRequest;
5400
5401        NetworkRequestInfo(Messenger m, NetworkRequest r, IBinder binder, boolean isRequest) {
5402            super();
5403            messenger = m;
5404            request = r;
5405            mBinder = binder;
5406            mPid = getCallingPid();
5407            mUid = getCallingUid();
5408            this.isRequest = isRequest;
5409
5410            try {
5411                mBinder.linkToDeath(this, 0);
5412            } catch (RemoteException e) {
5413                binderDied();
5414            }
5415        }
5416
5417        void unlinkDeathRecipient() {
5418            mBinder.unlinkToDeath(this, 0);
5419        }
5420
5421        public void binderDied() {
5422            log("ConnectivityService NetworkRequestInfo binderDied(" +
5423                    request + ", " + mBinder + ")");
5424            releaseNetworkRequest(request);
5425        }
5426
5427        public String toString() {
5428            return (isRequest ? "Request" : "Listen") + " from uid/pid:" + mUid + "/" +
5429                    mPid + " for " + request;
5430        }
5431    }
5432
5433    @Override
5434    public NetworkRequest requestNetwork(NetworkCapabilities networkCapabilities,
5435            Messenger messenger, int timeoutMs, IBinder binder, int legacyType) {
5436        if (networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED)
5437                == false) {
5438            enforceConnectivityInternalPermission();
5439        } else {
5440            enforceChangePermission();
5441        }
5442
5443        if (timeoutMs < 0 || timeoutMs > ConnectivityManager.MAX_NETWORK_REQUEST_TIMEOUT_MS) {
5444            throw new IllegalArgumentException("Bad timeout specified");
5445        }
5446        NetworkRequest networkRequest = new NetworkRequest(new NetworkCapabilities(
5447                networkCapabilities), legacyType, nextNetworkRequestId());
5448        if (DBG) log("requestNetwork for " + networkRequest);
5449        NetworkRequestInfo nri = new NetworkRequestInfo(messenger, networkRequest, binder,
5450                NetworkRequestInfo.REQUEST);
5451
5452        mHandler.sendMessage(mHandler.obtainMessage(EVENT_REGISTER_NETWORK_REQUEST, nri));
5453        if (timeoutMs > 0) {
5454            mHandler.sendMessageDelayed(mHandler.obtainMessage(EVENT_TIMEOUT_NETWORK_REQUEST,
5455                    nri), timeoutMs);
5456        }
5457        return networkRequest;
5458    }
5459
5460    @Override
5461    public NetworkRequest pendingRequestForNetwork(NetworkCapabilities networkCapabilities,
5462            PendingIntent operation) {
5463        // TODO
5464        return null;
5465    }
5466
5467    @Override
5468    public NetworkRequest listenForNetwork(NetworkCapabilities networkCapabilities,
5469            Messenger messenger, IBinder binder) {
5470        enforceAccessPermission();
5471
5472        NetworkRequest networkRequest = new NetworkRequest(new NetworkCapabilities(
5473                networkCapabilities), TYPE_NONE, nextNetworkRequestId());
5474        if (DBG) log("listenForNetwork for " + networkRequest);
5475        NetworkRequestInfo nri = new NetworkRequestInfo(messenger, networkRequest, binder,
5476                NetworkRequestInfo.LISTEN);
5477
5478        mHandler.sendMessage(mHandler.obtainMessage(EVENT_REGISTER_NETWORK_LISTENER, nri));
5479        return networkRequest;
5480    }
5481
5482    @Override
5483    public void pendingListenForNetwork(NetworkCapabilities networkCapabilities,
5484            PendingIntent operation) {
5485    }
5486
5487    @Override
5488    public void releaseNetworkRequest(NetworkRequest networkRequest) {
5489        mHandler.sendMessage(mHandler.obtainMessage(EVENT_RELEASE_NETWORK_REQUEST, getCallingUid(),
5490                0, networkRequest));
5491    }
5492
5493    @Override
5494    public void registerNetworkFactory(Messenger messenger, String name) {
5495        enforceConnectivityInternalPermission();
5496        NetworkFactoryInfo nfi = new NetworkFactoryInfo(name, messenger, new AsyncChannel());
5497        mHandler.sendMessage(mHandler.obtainMessage(EVENT_REGISTER_NETWORK_FACTORY, nfi));
5498    }
5499
5500    private void handleRegisterNetworkFactory(NetworkFactoryInfo nfi) {
5501        if (VDBG) log("Got NetworkFactory Messenger for " + nfi.name);
5502        mNetworkFactoryInfos.put(nfi.messenger, nfi);
5503        nfi.asyncChannel.connect(mContext, mTrackerHandler, nfi.messenger);
5504    }
5505
5506    @Override
5507    public void unregisterNetworkFactory(Messenger messenger) {
5508        enforceConnectivityInternalPermission();
5509        mHandler.sendMessage(mHandler.obtainMessage(EVENT_UNREGISTER_NETWORK_FACTORY, messenger));
5510    }
5511
5512    private void handleUnregisterNetworkFactory(Messenger messenger) {
5513        NetworkFactoryInfo nfi = mNetworkFactoryInfos.remove(messenger);
5514        if (nfi == null) {
5515            if (VDBG) log("Failed to find Messenger in unregisterNetworkFactory");
5516            return;
5517        }
5518        if (VDBG) log("unregisterNetworkFactory for " + nfi.name);
5519    }
5520
5521    /**
5522     * NetworkAgentInfo supporting a request by requestId.
5523     * These have already been vetted (their Capabilities satisfy the request)
5524     * and the are the highest scored network available.
5525     * the are keyed off the Requests requestId.
5526     */
5527    private final SparseArray<NetworkAgentInfo> mNetworkForRequestId =
5528            new SparseArray<NetworkAgentInfo>();
5529
5530    private final SparseArray<NetworkAgentInfo> mNetworkForNetId =
5531            new SparseArray<NetworkAgentInfo>();
5532
5533    // NetworkAgentInfo keyed off its connecting messenger
5534    // TODO - eval if we can reduce the number of lists/hashmaps/sparsearrays
5535    private final HashMap<Messenger, NetworkAgentInfo> mNetworkAgentInfos =
5536            new HashMap<Messenger, NetworkAgentInfo>();
5537
5538    private final NetworkRequest mDefaultRequest;
5539
5540    public void registerNetworkAgent(Messenger messenger, NetworkInfo networkInfo,
5541            LinkProperties linkProperties, NetworkCapabilities networkCapabilities,
5542            int currentScore) {
5543        enforceConnectivityInternalPermission();
5544
5545        NetworkAgentInfo nai = new NetworkAgentInfo(messenger, new AsyncChannel(), nextNetId(),
5546            new NetworkInfo(networkInfo), new LinkProperties(linkProperties),
5547            new NetworkCapabilities(networkCapabilities), currentScore, mContext, mTrackerHandler);
5548        if (VDBG) log("registerNetworkAgent " + nai);
5549        mHandler.sendMessage(mHandler.obtainMessage(EVENT_REGISTER_NETWORK_AGENT, nai));
5550    }
5551
5552    private void handleRegisterNetworkAgent(NetworkAgentInfo na) {
5553        if (VDBG) log("Got NetworkAgent Messenger");
5554        mNetworkAgentInfos.put(na.messenger, na);
5555        mNetworkForNetId.put(na.network.netId, na);
5556        na.asyncChannel.connect(mContext, mTrackerHandler, na.messenger);
5557        NetworkInfo networkInfo = na.networkInfo;
5558        na.networkInfo = null;
5559        updateNetworkInfo(na, networkInfo);
5560    }
5561
5562    private void updateLinkProperties(NetworkAgentInfo networkAgent, LinkProperties oldLp) {
5563        LinkProperties newLp = networkAgent.linkProperties;
5564        int netId = networkAgent.network.netId;
5565
5566        updateInterfaces(newLp, oldLp, netId);
5567        updateMtu(newLp, oldLp);
5568        // TODO - figure out what to do for clat
5569//        for (LinkProperties lp : newLp.getStackedLinks()) {
5570//            updateMtu(lp, null);
5571//        }
5572        updateRoutes(newLp, oldLp, netId);
5573        updateDnses(newLp, oldLp, netId);
5574        updateClat(newLp, oldLp, networkAgent);
5575    }
5576
5577    private void updateClat(LinkProperties newLp, LinkProperties oldLp, NetworkAgentInfo na) {
5578        // Update 464xlat state.
5579        if (mClat.requiresClat(na)) {
5580
5581            // If the connection was previously using clat, but is not using it now, stop the clat
5582            // daemon. Normally, this happens automatically when the connection disconnects, but if
5583            // the disconnect is not reported, or if the connection's LinkProperties changed for
5584            // some other reason (e.g., handoff changes the IP addresses on the link), it would
5585            // still be running. If it's not running, then stopping it is a no-op.
5586            if (Nat464Xlat.isRunningClat(oldLp) && !Nat464Xlat.isRunningClat(newLp)) {
5587                mClat.stopClat();
5588            }
5589            // If the link requires clat to be running, then start the daemon now.
5590            if (na.networkInfo.isConnected()) {
5591                mClat.startClat(na);
5592            } else {
5593                mClat.stopClat();
5594            }
5595        }
5596    }
5597
5598    private void updateInterfaces(LinkProperties newLp, LinkProperties oldLp, int netId) {
5599        CompareResult<String> interfaceDiff = new CompareResult<String>();
5600        if (oldLp != null) {
5601            interfaceDiff = oldLp.compareAllInterfaceNames(newLp);
5602        } else if (newLp != null) {
5603            interfaceDiff.added = newLp.getAllInterfaceNames();
5604        }
5605        for (String iface : interfaceDiff.added) {
5606            try {
5607                mNetd.addInterfaceToNetwork(iface, netId);
5608            } catch (Exception e) {
5609                loge("Exception adding interface: " + e);
5610            }
5611        }
5612        for (String iface : interfaceDiff.removed) {
5613            try {
5614                mNetd.removeInterfaceFromNetwork(iface, netId);
5615            } catch (Exception e) {
5616                loge("Exception removing interface: " + e);
5617            }
5618        }
5619    }
5620
5621    private void updateRoutes(LinkProperties newLp, LinkProperties oldLp, int netId) {
5622        CompareResult<RouteInfo> routeDiff = new CompareResult<RouteInfo>();
5623        if (oldLp != null) {
5624            routeDiff = oldLp.compareAllRoutes(newLp);
5625        } else if (newLp != null) {
5626            routeDiff.added = newLp.getAllRoutes();
5627        }
5628
5629        // add routes before removing old in case it helps with continuous connectivity
5630
5631        // do this twice, adding non-nexthop routes first, then routes they are dependent on
5632        for (RouteInfo route : routeDiff.added) {
5633            if (route.hasGateway()) continue;
5634            try {
5635                mNetd.addRoute(netId, route);
5636            } catch (Exception e) {
5637                loge("Exception in addRoute for non-gateway: " + e);
5638            }
5639        }
5640        for (RouteInfo route : routeDiff.added) {
5641            if (route.hasGateway() == false) continue;
5642            try {
5643                mNetd.addRoute(netId, route);
5644            } catch (Exception e) {
5645                loge("Exception in addRoute for gateway: " + e);
5646            }
5647        }
5648
5649        for (RouteInfo route : routeDiff.removed) {
5650            try {
5651                mNetd.removeRoute(netId, route);
5652            } catch (Exception e) {
5653                loge("Exception in removeRoute: " + e);
5654            }
5655        }
5656    }
5657    private void updateDnses(LinkProperties newLp, LinkProperties oldLp, int netId) {
5658        if (oldLp == null || (newLp.isIdenticalDnses(oldLp) == false)) {
5659            Collection<InetAddress> dnses = newLp.getDnsServers();
5660            if (dnses.size() == 0 && mDefaultDns != null) {
5661                dnses = new ArrayList();
5662                dnses.add(mDefaultDns);
5663                if (DBG) {
5664                    loge("no dns provided for netId " + netId + ", so using defaults");
5665                }
5666            }
5667            try {
5668                mNetd.setDnsServersForNetwork(netId, NetworkUtils.makeStrings(dnses),
5669                    newLp.getDomains());
5670            } catch (Exception e) {
5671                loge("Exception in setDnsServersForNetwork: " + e);
5672            }
5673            NetworkAgentInfo defaultNai = mNetworkForRequestId.get(mDefaultRequest.requestId);
5674            if (defaultNai != null && defaultNai.network.netId == netId) {
5675                setDefaultDnsSystemProperties(dnses);
5676            }
5677        }
5678    }
5679
5680    private void setDefaultDnsSystemProperties(Collection<InetAddress> dnses) {
5681        int last = 0;
5682        for (InetAddress dns : dnses) {
5683            ++last;
5684            String key = "net.dns" + last;
5685            String value = dns.getHostAddress();
5686            SystemProperties.set(key, value);
5687        }
5688        for (int i = last + 1; i <= mNumDnsEntries; ++i) {
5689            String key = "net.dns" + i;
5690            SystemProperties.set(key, "");
5691        }
5692        mNumDnsEntries = last;
5693    }
5694
5695
5696    private void updateCapabilities(NetworkAgentInfo networkAgent,
5697            NetworkCapabilities networkCapabilities) {
5698        // TODO - what else here?  Verify still satisfies everybody?
5699        // Check if satisfies somebody new?  call callbacks?
5700        networkAgent.networkCapabilities = networkCapabilities;
5701    }
5702
5703    private void sendUpdatedScoreToFactories(NetworkRequest networkRequest, int score) {
5704        if (VDBG) log("sending new Min Network Score(" + score + "): " + networkRequest.toString());
5705        for (NetworkFactoryInfo nfi : mNetworkFactoryInfos.values()) {
5706            nfi.asyncChannel.sendMessage(android.net.NetworkFactory.CMD_REQUEST_NETWORK, score, 0,
5707                    networkRequest);
5708        }
5709    }
5710
5711    private void callCallbackForRequest(NetworkRequestInfo nri,
5712            NetworkAgentInfo networkAgent, int notificationType) {
5713        if (nri.messenger == null) return;  // Default request has no msgr
5714        Object o;
5715        int a1 = 0;
5716        int a2 = 0;
5717        switch (notificationType) {
5718            case ConnectivityManager.CALLBACK_LOSING:
5719                a1 = 30 * 1000; // TODO - read this from NetworkMonitor
5720                // fall through
5721            case ConnectivityManager.CALLBACK_PRECHECK:
5722            case ConnectivityManager.CALLBACK_AVAILABLE:
5723            case ConnectivityManager.CALLBACK_LOST:
5724            case ConnectivityManager.CALLBACK_CAP_CHANGED:
5725            case ConnectivityManager.CALLBACK_IP_CHANGED: {
5726                o = new NetworkRequest(nri.request);
5727                a2 = networkAgent.network.netId;
5728                break;
5729            }
5730            case ConnectivityManager.CALLBACK_UNAVAIL:
5731            case ConnectivityManager.CALLBACK_RELEASED: {
5732                o = new NetworkRequest(nri.request);
5733                break;
5734            }
5735            default: {
5736                loge("Unknown notificationType " + notificationType);
5737                return;
5738            }
5739        }
5740        Message msg = Message.obtain();
5741        msg.arg1 = a1;
5742        msg.arg2 = a2;
5743        msg.obj = o;
5744        msg.what = notificationType;
5745        try {
5746            if (VDBG) log("sending notification " + notificationType + " for " + nri.request);
5747            nri.messenger.send(msg);
5748        } catch (RemoteException e) {
5749            // may occur naturally in the race of binder death.
5750            loge("RemoteException caught trying to send a callback msg for " + nri.request);
5751        }
5752    }
5753
5754    private void handleLingerComplete(NetworkAgentInfo oldNetwork) {
5755        if (oldNetwork == null) {
5756            loge("Unknown NetworkAgentInfo in handleLingerComplete");
5757            return;
5758        }
5759        if (DBG) log("handleLingerComplete for " + oldNetwork.name());
5760        if (DBG) {
5761            if (oldNetwork.networkRequests.size() != 0) {
5762                loge("Dead network still had " + oldNetwork.networkRequests.size() + " requests");
5763            }
5764        }
5765        oldNetwork.asyncChannel.disconnect();
5766    }
5767
5768    private void handleConnectionValidated(NetworkAgentInfo newNetwork) {
5769        if (newNetwork == null) {
5770            loge("Unknown NetworkAgentInfo in handleConnectionValidated");
5771            return;
5772        }
5773        boolean keep = false;
5774        boolean isNewDefault = false;
5775        if (DBG) log("handleConnectionValidated for "+newNetwork.name());
5776        // check if any NetworkRequest wants this NetworkAgent
5777        ArrayList<NetworkAgentInfo> affectedNetworks = new ArrayList<NetworkAgentInfo>();
5778        if (VDBG) log(" new Network has: " + newNetwork.networkCapabilities);
5779        for (NetworkRequestInfo nri : mNetworkRequests.values()) {
5780            NetworkAgentInfo currentNetwork = mNetworkForRequestId.get(nri.request.requestId);
5781            if (newNetwork == currentNetwork) {
5782                if (VDBG) log("Network " + newNetwork.name() + " was already satisfying" +
5783                              " request " + nri.request.requestId + ". No change.");
5784                keep = true;
5785                continue;
5786            }
5787
5788            // check if it satisfies the NetworkCapabilities
5789            if (VDBG) log("  checking if request is satisfied: " + nri.request);
5790            if (nri.request.networkCapabilities.satisfiedByNetworkCapabilities(
5791                    newNetwork.networkCapabilities)) {
5792                // next check if it's better than any current network we're using for
5793                // this request
5794                if (VDBG) {
5795                    log("currentScore = " +
5796                            (currentNetwork != null ? currentNetwork.currentScore : 0) +
5797                            ", newScore = " + newNetwork.currentScore);
5798                }
5799                if (currentNetwork == null ||
5800                        currentNetwork.currentScore < newNetwork.currentScore) {
5801                    if (currentNetwork != null) {
5802                        if (VDBG) log("   accepting network in place of " + currentNetwork.name());
5803                        currentNetwork.networkRequests.remove(nri.request.requestId);
5804                        currentNetwork.networkLingered.add(nri.request);
5805                        affectedNetworks.add(currentNetwork);
5806                    } else {
5807                        if (VDBG) log("   accepting network in place of null");
5808                    }
5809                    mNetworkForRequestId.put(nri.request.requestId, newNetwork);
5810                    newNetwork.addRequest(nri.request);
5811                    int legacyType = nri.request.legacyType;
5812                    if (legacyType != TYPE_NONE) {
5813                        mLegacyTypeTracker.add(legacyType, newNetwork);
5814                    }
5815                    keep = true;
5816                    // TODO - this could get expensive if we have alot of requests for this
5817                    // network.  Think about if there is a way to reduce this.  Push
5818                    // netid->request mapping to each factory?
5819                    sendUpdatedScoreToFactories(nri.request, newNetwork.currentScore);
5820                    if (mDefaultRequest.requestId == nri.request.requestId) {
5821                        isNewDefault = true;
5822                        updateActiveDefaultNetwork(newNetwork);
5823                        if (newNetwork.linkProperties != null) {
5824                            setDefaultDnsSystemProperties(
5825                                    newNetwork.linkProperties.getDnsServers());
5826                        } else {
5827                            setDefaultDnsSystemProperties(new ArrayList<InetAddress>());
5828                        }
5829                        mLegacyTypeTracker.add(newNetwork.networkInfo.getType(), newNetwork);
5830                    }
5831                }
5832            }
5833        }
5834        for (NetworkAgentInfo nai : affectedNetworks) {
5835            boolean teardown = true;
5836            for (int i = 0; i < nai.networkRequests.size(); i++) {
5837                NetworkRequest nr = nai.networkRequests.valueAt(i);
5838                try {
5839                if (mNetworkRequests.get(nr).isRequest) {
5840                    teardown = false;
5841                }
5842                } catch (Exception e) {
5843                    loge("Request " + nr + " not found in mNetworkRequests.");
5844                    loge("  it came from request list  of " + nai.name());
5845                }
5846            }
5847            if (teardown) {
5848                nai.networkMonitor.sendMessage(NetworkMonitor.CMD_NETWORK_LINGER);
5849                notifyNetworkCallbacks(nai, ConnectivityManager.CALLBACK_LOSING);
5850            } else {
5851                // not going to linger, so kill the list of linger networks..  only
5852                // notify them of linger if it happens as the result of gaining another,
5853                // but if they transition and old network stays up, don't tell them of linger
5854                // or very delayed loss
5855                nai.networkLingered.clear();
5856                if (VDBG) log("Lingered for " + nai.name() + " cleared");
5857            }
5858        }
5859        if (keep) {
5860            if (isNewDefault) {
5861                if (VDBG) log("Switching to new default network: " + newNetwork);
5862                setupDataActivityTracking(newNetwork);
5863                try {
5864                    mNetd.setDefaultNetId(newNetwork.network.netId);
5865                } catch (Exception e) {
5866                    loge("Exception setting default network :" + e);
5867                }
5868                if (newNetwork.equals(mNetworkForRequestId.get(mDefaultRequest.requestId))) {
5869                    handleApplyDefaultProxy(newNetwork.linkProperties.getHttpProxy());
5870                }
5871                synchronized (ConnectivityService.this) {
5872                    // have a new default network, release the transition wakelock in
5873                    // a second if it's held.  The second pause is to allow apps
5874                    // to reconnect over the new network
5875                    if (mNetTransitionWakeLock.isHeld()) {
5876                        mHandler.sendMessageDelayed(mHandler.obtainMessage(
5877                                EVENT_CLEAR_NET_TRANSITION_WAKELOCK,
5878                                mNetTransitionWakeLockSerialNumber, 0),
5879                                1000);
5880                    }
5881                }
5882
5883                // this will cause us to come up initially as unconnected and switching
5884                // to connected after our normal pause unless somebody reports us as
5885                // really disconnected
5886                mDefaultInetConditionPublished = 0;
5887                mDefaultConnectionSequence++;
5888                mInetConditionChangeInFlight = false;
5889                // TODO - read the tcp buffer size config string from somewhere
5890                // updateNetworkSettings();
5891            }
5892            // notify battery stats service about this network
5893            try {
5894                BatteryStatsService.getService().noteNetworkInterfaceType(
5895                        newNetwork.linkProperties.getInterfaceName(),
5896                        newNetwork.networkInfo.getType());
5897            } catch (RemoteException e) { }
5898            notifyNetworkCallbacks(newNetwork, ConnectivityManager.CALLBACK_AVAILABLE);
5899        } else {
5900            if (DBG && newNetwork.networkRequests.size() != 0) {
5901                loge("tearing down network with live requests:");
5902                for (int i=0; i < newNetwork.networkRequests.size(); i++) {
5903                    loge("  " + newNetwork.networkRequests.valueAt(i));
5904                }
5905            }
5906            if (VDBG) log("Validated network turns out to be unwanted.  Tear it down.");
5907            newNetwork.asyncChannel.disconnect();
5908        }
5909    }
5910
5911
5912    private void updateNetworkInfo(NetworkAgentInfo networkAgent, NetworkInfo newInfo) {
5913        NetworkInfo.State state = newInfo.getState();
5914        NetworkInfo oldInfo = networkAgent.networkInfo;
5915        networkAgent.networkInfo = newInfo;
5916
5917        if (oldInfo != null && oldInfo.getState() == state) {
5918            if (VDBG) log("ignoring duplicate network state non-change");
5919            return;
5920        }
5921        if (DBG) {
5922            log(networkAgent.name() + " EVENT_NETWORK_INFO_CHANGED, going from " +
5923                    (oldInfo == null ? "null" : oldInfo.getState()) +
5924                    " to " + state);
5925        }
5926
5927        if (state == NetworkInfo.State.CONNECTED) {
5928            try {
5929                // This is likely caused by the fact that this network already
5930                // exists. An example is when a network goes from CONNECTED to
5931                // CONNECTING and back (like wifi on DHCP renew).
5932                // TODO: keep track of which networks we've created, or ask netd
5933                // to tell us whether we've already created this network or not.
5934                mNetd.createNetwork(networkAgent.network.netId);
5935            } catch (Exception e) {
5936                loge("Error creating network " + networkAgent.network.netId + ": "
5937                        + e.getMessage());
5938                return;
5939            }
5940
5941            updateLinkProperties(networkAgent, null);
5942            notifyNetworkCallbacks(networkAgent, ConnectivityManager.CALLBACK_PRECHECK);
5943            networkAgent.networkMonitor.sendMessage(NetworkMonitor.CMD_NETWORK_CONNECTED);
5944        } else if (state == NetworkInfo.State.DISCONNECTED ||
5945                state == NetworkInfo.State.SUSPENDED) {
5946            networkAgent.asyncChannel.disconnect();
5947        }
5948    }
5949
5950    private void updateNetworkScore(NetworkAgentInfo nai, int score) {
5951        if (DBG) log("updateNetworkScore for " + nai.name() + " to " + score);
5952
5953        nai.currentScore = score;
5954
5955        // TODO - This will not do the right thing if this network is lowering
5956        // its score and has requests that can be served by other
5957        // currently-active networks, or if the network is increasing its
5958        // score and other networks have requests that can be better served
5959        // by this network.
5960        //
5961        // Really we want to see if any of our requests migrate to other
5962        // active/lingered networks and if any other requests migrate to us (depending
5963        // on increasing/decreasing currentScore.  That's a bit of work and probably our
5964        // score checking/network allocation code needs to be modularized so we can understand
5965        // (see handleConnectionValided for an example).
5966        //
5967        // As a first order approx, lets just advertise the new score to factories.  If
5968        // somebody can beat it they will nominate a network and our normal net replacement
5969        // code will fire.
5970        for (int i = 0; i < nai.networkRequests.size(); i++) {
5971            NetworkRequest nr = nai.networkRequests.valueAt(i);
5972            sendUpdatedScoreToFactories(nr, score);
5973        }
5974    }
5975
5976    // notify only this one new request of the current state
5977    protected void notifyNetworkCallback(NetworkAgentInfo nai, NetworkRequestInfo nri) {
5978        int notifyType = ConnectivityManager.CALLBACK_AVAILABLE;
5979        // TODO - read state from monitor to decide what to send.
5980//        if (nai.networkMonitor.isLingering()) {
5981//            notifyType = NetworkCallbacks.LOSING;
5982//        } else if (nai.networkMonitor.isEvaluating()) {
5983//            notifyType = NetworkCallbacks.callCallbackForRequest(request, nai, notifyType);
5984//        }
5985        callCallbackForRequest(nri, nai, notifyType);
5986    }
5987
5988    private void sendLegacyNetworkBroadcast(NetworkAgentInfo nai, boolean connected, int type) {
5989        if (connected) {
5990            NetworkInfo info = new NetworkInfo(nai.networkInfo);
5991            info.setType(type);
5992            sendConnectedBroadcastDelayed(info, getConnectivityChangeDelay());
5993        } else {
5994            NetworkInfo info = new NetworkInfo(nai.networkInfo);
5995            info.setType(type);
5996            Intent intent = new Intent(ConnectivityManager.CONNECTIVITY_ACTION);
5997            intent.putExtra(ConnectivityManager.EXTRA_NETWORK_INFO, info);
5998            intent.putExtra(ConnectivityManager.EXTRA_NETWORK_TYPE, info.getType());
5999            if (info.isFailover()) {
6000                intent.putExtra(ConnectivityManager.EXTRA_IS_FAILOVER, true);
6001                nai.networkInfo.setFailover(false);
6002            }
6003            if (info.getReason() != null) {
6004                intent.putExtra(ConnectivityManager.EXTRA_REASON, info.getReason());
6005            }
6006            if (info.getExtraInfo() != null) {
6007                intent.putExtra(ConnectivityManager.EXTRA_EXTRA_INFO, info.getExtraInfo());
6008            }
6009            NetworkAgentInfo newDefaultAgent = null;
6010            if (nai.networkRequests.get(mDefaultRequest.requestId) != null) {
6011                newDefaultAgent = mNetworkForRequestId.get(mDefaultRequest.requestId);
6012                if (newDefaultAgent != null) {
6013                    intent.putExtra(ConnectivityManager.EXTRA_OTHER_NETWORK_INFO,
6014                            newDefaultAgent.networkInfo);
6015                } else {
6016                    intent.putExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, true);
6017                }
6018            }
6019            intent.putExtra(ConnectivityManager.EXTRA_INET_CONDITION,
6020                    mDefaultInetConditionPublished);
6021            final Intent immediateIntent = new Intent(intent);
6022            immediateIntent.setAction(CONNECTIVITY_ACTION_IMMEDIATE);
6023            sendStickyBroadcast(immediateIntent);
6024            sendStickyBroadcastDelayed(intent, getConnectivityChangeDelay());
6025            if (newDefaultAgent != null) {
6026                sendConnectedBroadcastDelayed(newDefaultAgent.networkInfo,
6027                getConnectivityChangeDelay());
6028            }
6029        }
6030    }
6031
6032    protected void notifyNetworkCallbacks(NetworkAgentInfo networkAgent, int notifyType) {
6033        if (VDBG) log("notifyType " + notifyType + " for " + networkAgent.name());
6034        for (int i = 0; i < networkAgent.networkRequests.size(); i++) {
6035            NetworkRequest nr = networkAgent.networkRequests.valueAt(i);
6036            NetworkRequestInfo nri = mNetworkRequests.get(nr);
6037            if (VDBG) log(" sending notification for " + nr);
6038            callCallbackForRequest(nri, networkAgent, notifyType);
6039        }
6040    }
6041
6042    private LinkProperties getLinkPropertiesForTypeInternal(int networkType) {
6043        NetworkAgentInfo nai = mLegacyTypeTracker.getNetworkForType(networkType);
6044        return (nai != null) ?
6045                new LinkProperties(nai.linkProperties) :
6046                new LinkProperties();
6047    }
6048
6049    private NetworkInfo getNetworkInfoForType(int networkType) {
6050        if (!mLegacyTypeTracker.isTypeSupported(networkType))
6051            return null;
6052
6053        NetworkAgentInfo nai = mLegacyTypeTracker.getNetworkForType(networkType);
6054        if (nai != null) {
6055            NetworkInfo result = new NetworkInfo(nai.networkInfo);
6056            result.setType(networkType);
6057            return result;
6058        } else {
6059           return new NetworkInfo(networkType, 0, "Unknown", "");
6060        }
6061    }
6062
6063    private NetworkCapabilities getNetworkCapabilitiesForType(int networkType) {
6064        NetworkAgentInfo nai = mLegacyTypeTracker.getNetworkForType(networkType);
6065        return (nai != null) ?
6066                new NetworkCapabilities(nai.networkCapabilities) :
6067                new NetworkCapabilities();
6068    }
6069}
6070