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