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