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