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