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