ConnectivityService.java revision 82f8521d386f3109147c477d04e5e90e5c715fa0
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.NotificationManager;
35import android.app.PendingIntent;
36import android.bluetooth.BluetoothTetheringDataTracker;
37import android.content.ContentResolver;
38import android.content.Context;
39import android.content.ContextWrapper;
40import android.content.Intent;
41import android.content.pm.PackageManager;
42import android.content.res.Resources;
43import android.database.ContentObserver;
44import android.net.ConnectivityManager;
45import android.net.DummyDataStateTracker;
46import android.net.EthernetDataTracker;
47import android.net.IConnectivityManager;
48import android.net.INetworkManagementEventObserver;
49import android.net.INetworkPolicyListener;
50import android.net.INetworkPolicyManager;
51import android.net.INetworkStatsService;
52import android.net.LinkAddress;
53import android.net.LinkProperties;
54import android.net.LinkProperties.CompareResult;
55import android.net.MobileDataStateTracker;
56import android.net.NetworkConfig;
57import android.net.NetworkInfo;
58import android.net.NetworkInfo.DetailedState;
59import android.net.NetworkQuotaInfo;
60import android.net.NetworkState;
61import android.net.NetworkStateTracker;
62import android.net.NetworkUtils;
63import android.net.Proxy;
64import android.net.ProxyProperties;
65import android.net.RouteInfo;
66import android.net.wifi.WifiStateTracker;
67import android.net.wimax.WimaxManagerConstants;
68import android.os.Binder;
69import android.os.FileUtils;
70import android.os.Handler;
71import android.os.HandlerThread;
72import android.os.IBinder;
73import android.os.INetworkManagementService;
74import android.os.Looper;
75import android.os.Message;
76import android.os.ParcelFileDescriptor;
77import android.os.PowerManager;
78import android.os.RemoteException;
79import android.os.ServiceManager;
80import android.os.SystemClock;
81import android.os.SystemProperties;
82import android.provider.Settings;
83import android.security.KeyStore;
84import android.text.TextUtils;
85import android.util.EventLog;
86import android.util.Slog;
87import android.util.SparseIntArray;
88
89import com.android.internal.net.LegacyVpnInfo;
90import com.android.internal.net.VpnConfig;
91import com.android.internal.net.VpnProfile;
92import com.android.internal.telephony.Phone;
93import com.android.internal.telephony.PhoneConstants;
94import com.android.internal.util.Preconditions;
95import com.android.server.am.BatteryStatsService;
96import com.android.server.connectivity.Tethering;
97import com.android.server.connectivity.Vpn;
98import com.android.server.net.BaseNetworkObserver;
99import com.google.android.collect.Lists;
100import com.google.android.collect.Sets;
101
102import dalvik.system.DexClassLoader;
103
104import java.io.FileDescriptor;
105import java.io.IOException;
106import java.io.PrintWriter;
107import java.lang.reflect.Constructor;
108import java.net.Inet4Address;
109import java.net.Inet6Address;
110import java.net.InetAddress;
111import java.net.UnknownHostException;
112import java.util.ArrayList;
113import java.util.Arrays;
114import java.util.Collection;
115import java.util.GregorianCalendar;
116import java.util.HashSet;
117import java.util.List;
118
119/**
120 * @hide
121 */
122public class ConnectivityService extends IConnectivityManager.Stub {
123    private static final String TAG = "ConnectivityService";
124
125    private static final boolean DBG = true;
126    private static final boolean VDBG = false;
127
128    private static final boolean LOGD_RULES = false;
129
130    // TODO: create better separation between radio types and network types
131
132    // how long to wait before switching back to a radio's default network
133    private static final int RESTORE_DEFAULT_NETWORK_DELAY = 1 * 60 * 1000;
134    // system property that can override the above value
135    private static final String NETWORK_RESTORE_DELAY_PROP_NAME =
136            "android.telephony.apn-restore";
137
138    // used in recursive route setting to add gateways for the host for which
139    // a host route was requested.
140    private static final int MAX_HOSTROUTE_CYCLE_COUNT = 10;
141
142    private Tethering mTethering;
143    private boolean mTetheringConfigValid = false;
144
145    private final KeyStore mKeyStore;
146
147    private Vpn mVpn;
148    private VpnCallback mVpnCallback = new VpnCallback();
149
150    /** Lock around {@link #mUidRules} and {@link #mMeteredIfaces}. */
151    private Object mRulesLock = new Object();
152    /** Currently active network rules by UID. */
153    private SparseIntArray mUidRules = new SparseIntArray();
154    /** Set of ifaces that are costly. */
155    private HashSet<String> mMeteredIfaces = Sets.newHashSet();
156
157    /**
158     * Sometimes we want to refer to the individual network state
159     * trackers separately, and sometimes we just want to treat them
160     * abstractly.
161     */
162    private NetworkStateTracker mNetTrackers[];
163
164    /**
165     * The link properties that define the current links
166     */
167    private LinkProperties mCurrentLinkProperties[];
168
169    /**
170     * A per Net list of the PID's that requested access to the net
171     * used both as a refcount and for per-PID DNS selection
172     */
173    private List mNetRequestersPids[];
174
175    // priority order of the nettrackers
176    // (excluding dynamically set mNetworkPreference)
177    // TODO - move mNetworkTypePreference into this
178    private int[] mPriorityList;
179
180    private Context mContext;
181    private int mNetworkPreference;
182    private int mActiveDefaultNetwork = -1;
183    // 0 is full bad, 100 is full good
184    private int mDefaultInetCondition = 0;
185    private int mDefaultInetConditionPublished = 0;
186    private boolean mInetConditionChangeInFlight = false;
187    private int mDefaultConnectionSequence = 0;
188
189    private Object mDnsLock = new Object();
190    private int mNumDnsEntries;
191    private boolean mDnsOverridden = false;
192
193    private boolean mTestMode;
194    private static ConnectivityService sServiceInstance;
195
196    private INetworkManagementService mNetd;
197    private INetworkPolicyManager mPolicyManager;
198
199    private static final int ENABLED  = 1;
200    private static final int DISABLED = 0;
201
202    private static final boolean ADD = true;
203    private static final boolean REMOVE = false;
204
205    private static final boolean TO_DEFAULT_TABLE = true;
206    private static final boolean TO_SECONDARY_TABLE = false;
207
208    /**
209     * used internally as a delayed event to make us switch back to the
210     * default network
211     */
212    private static final int EVENT_RESTORE_DEFAULT_NETWORK = 1;
213
214    /**
215     * used internally to change our mobile data enabled flag
216     */
217    private static final int EVENT_CHANGE_MOBILE_DATA_ENABLED = 2;
218
219    /**
220     * used internally to change our network preference setting
221     * arg1 = networkType to prefer
222     */
223    private static final int EVENT_SET_NETWORK_PREFERENCE = 3;
224
225    /**
226     * used internally to synchronize inet condition reports
227     * arg1 = networkType
228     * arg2 = condition (0 bad, 100 good)
229     */
230    private static final int EVENT_INET_CONDITION_CHANGE = 4;
231
232    /**
233     * used internally to mark the end of inet condition hold periods
234     * arg1 = networkType
235     */
236    private static final int EVENT_INET_CONDITION_HOLD_END = 5;
237
238    /**
239     * used internally to set enable/disable cellular data
240     * arg1 = ENBALED or DISABLED
241     */
242    private static final int EVENT_SET_MOBILE_DATA = 7;
243
244    /**
245     * used internally to clear a wakelock when transitioning
246     * from one net to another
247     */
248    private static final int EVENT_CLEAR_NET_TRANSITION_WAKELOCK = 8;
249
250    /**
251     * used internally to reload global proxy settings
252     */
253    private static final int EVENT_APPLY_GLOBAL_HTTP_PROXY = 9;
254
255    /**
256     * used internally to set external dependency met/unmet
257     * arg1 = ENABLED (met) or DISABLED (unmet)
258     * arg2 = NetworkType
259     */
260    private static final int EVENT_SET_DEPENDENCY_MET = 10;
261
262    /**
263     * used internally to restore DNS properties back to the
264     * default network
265     */
266    private static final int EVENT_RESTORE_DNS = 11;
267
268    /**
269     * used internally to send a sticky broadcast delayed.
270     */
271    private static final int EVENT_SEND_STICKY_BROADCAST_INTENT = 12;
272
273    /**
274     * Used internally to
275     * {@link NetworkStateTracker#setPolicyDataEnable(boolean)}.
276     */
277    private static final int EVENT_SET_POLICY_DATA_ENABLE = 13;
278
279    /** Handler used for internal events. */
280    private InternalHandler mHandler;
281    /** Handler used for incoming {@link NetworkStateTracker} events. */
282    private NetworkStateTrackerHandler mTrackerHandler;
283
284    // list of DeathRecipients used to make sure features are turned off when
285    // a process dies
286    private List<FeatureUser> mFeatureUsers;
287
288    private boolean mSystemReady;
289    private Intent mInitialBroadcast;
290
291    private PowerManager.WakeLock mNetTransitionWakeLock;
292    private String mNetTransitionWakeLockCausedBy = "";
293    private int mNetTransitionWakeLockSerialNumber;
294    private int mNetTransitionWakeLockTimeout;
295
296    private InetAddress mDefaultDns;
297
298    // this collection is used to refcount the added routes - if there are none left
299    // it's time to remove the route from the route table
300    private Collection<RouteInfo> mAddedRoutes = new ArrayList<RouteInfo>();
301
302    // used in DBG mode to track inet condition reports
303    private static final int INET_CONDITION_LOG_MAX_SIZE = 15;
304    private ArrayList mInetLog;
305
306    // track the current default http proxy - tell the world if we get a new one (real change)
307    private ProxyProperties mDefaultProxy = null;
308    private Object mDefaultProxyLock = new Object();
309    private boolean mDefaultProxyDisabled = false;
310
311    // track the global proxy.
312    private ProxyProperties mGlobalProxy = null;
313    private final Object mGlobalProxyLock = new Object();
314
315    private SettingsObserver mSettingsObserver;
316
317    NetworkConfig[] mNetConfigs;
318    int mNetworksDefined;
319
320    private static class RadioAttributes {
321        public int mSimultaneity;
322        public int mType;
323        public RadioAttributes(String init) {
324            String fragments[] = init.split(",");
325            mType = Integer.parseInt(fragments[0]);
326            mSimultaneity = Integer.parseInt(fragments[1]);
327        }
328    }
329    RadioAttributes[] mRadioAttributes;
330
331    // the set of network types that can only be enabled by system/sig apps
332    List mProtectedNetworks;
333
334    public ConnectivityService(Context context, INetworkManagementService netd,
335            INetworkStatsService statsService, INetworkPolicyManager policyManager) {
336        // Currently, omitting a NetworkFactory will create one internally
337        // TODO: create here when we have cleaner WiMAX support
338        this(context, netd, statsService, policyManager, null);
339    }
340
341    public ConnectivityService(Context context, INetworkManagementService netManager,
342            INetworkStatsService statsService, INetworkPolicyManager policyManager,
343            NetworkFactory netFactory) {
344        if (DBG) log("ConnectivityService starting up");
345
346        HandlerThread handlerThread = new HandlerThread("ConnectivityServiceThread");
347        handlerThread.start();
348        mHandler = new InternalHandler(handlerThread.getLooper());
349        mTrackerHandler = new NetworkStateTrackerHandler(handlerThread.getLooper());
350
351        if (netFactory == null) {
352            netFactory = new DefaultNetworkFactory(context, mTrackerHandler);
353        }
354
355        // setup our unique device name
356        if (TextUtils.isEmpty(SystemProperties.get("net.hostname"))) {
357            String id = Settings.Secure.getString(context.getContentResolver(),
358                    Settings.Secure.ANDROID_ID);
359            if (id != null && id.length() > 0) {
360                String name = new String("android-").concat(id);
361                SystemProperties.set("net.hostname", name);
362            }
363        }
364
365        // read our default dns server ip
366        String dns = Settings.Secure.getString(context.getContentResolver(),
367                Settings.Secure.DEFAULT_DNS_SERVER);
368        if (dns == null || dns.length() == 0) {
369            dns = context.getResources().getString(
370                    com.android.internal.R.string.config_default_dns_server);
371        }
372        try {
373            mDefaultDns = NetworkUtils.numericToInetAddress(dns);
374        } catch (IllegalArgumentException e) {
375            loge("Error setting defaultDns using " + dns);
376        }
377
378        mContext = checkNotNull(context, "missing Context");
379        mNetd = checkNotNull(netManager, "missing INetworkManagementService");
380        mPolicyManager = checkNotNull(policyManager, "missing INetworkPolicyManager");
381        mKeyStore = KeyStore.getInstance();
382
383        try {
384            mPolicyManager.registerListener(mPolicyListener);
385        } catch (RemoteException e) {
386            // ouch, no rules updates means some processes may never get network
387            loge("unable to register INetworkPolicyListener" + e.toString());
388        }
389
390        final PowerManager powerManager = (PowerManager) context.getSystemService(
391                Context.POWER_SERVICE);
392        mNetTransitionWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
393        mNetTransitionWakeLockTimeout = mContext.getResources().getInteger(
394                com.android.internal.R.integer.config_networkTransitionTimeout);
395
396        mNetTrackers = new NetworkStateTracker[
397                ConnectivityManager.MAX_NETWORK_TYPE+1];
398        mCurrentLinkProperties = new LinkProperties[ConnectivityManager.MAX_NETWORK_TYPE+1];
399
400        mNetworkPreference = getPersistedNetworkPreference();
401
402        mRadioAttributes = new RadioAttributes[ConnectivityManager.MAX_RADIO_TYPE+1];
403        mNetConfigs = new NetworkConfig[ConnectivityManager.MAX_NETWORK_TYPE+1];
404
405        // Load device network attributes from resources
406        String[] raStrings = context.getResources().getStringArray(
407                com.android.internal.R.array.radioAttributes);
408        for (String raString : raStrings) {
409            RadioAttributes r = new RadioAttributes(raString);
410            if (r.mType > ConnectivityManager.MAX_RADIO_TYPE) {
411                loge("Error in radioAttributes - ignoring attempt to define type " + r.mType);
412                continue;
413            }
414            if (mRadioAttributes[r.mType] != null) {
415                loge("Error in radioAttributes - ignoring attempt to redefine type " +
416                        r.mType);
417                continue;
418            }
419            mRadioAttributes[r.mType] = r;
420        }
421
422        String[] naStrings = context.getResources().getStringArray(
423                com.android.internal.R.array.networkAttributes);
424        for (String naString : naStrings) {
425            try {
426                NetworkConfig n = new NetworkConfig(naString);
427                if (n.type > ConnectivityManager.MAX_NETWORK_TYPE) {
428                    loge("Error in networkAttributes - ignoring attempt to define type " +
429                            n.type);
430                    continue;
431                }
432                if (mNetConfigs[n.type] != null) {
433                    loge("Error in networkAttributes - ignoring attempt to redefine type " +
434                            n.type);
435                    continue;
436                }
437                if (mRadioAttributes[n.radio] == null) {
438                    loge("Error in networkAttributes - ignoring attempt to use undefined " +
439                            "radio " + n.radio + " in network type " + n.type);
440                    continue;
441                }
442                mNetConfigs[n.type] = n;
443                mNetworksDefined++;
444            } catch(Exception e) {
445                // ignore it - leave the entry null
446            }
447        }
448
449        mProtectedNetworks = new ArrayList<Integer>();
450        int[] protectedNetworks = context.getResources().getIntArray(
451                com.android.internal.R.array.config_protectedNetworks);
452        for (int p : protectedNetworks) {
453            if ((mNetConfigs[p] != null) && (mProtectedNetworks.contains(p) == false)) {
454                mProtectedNetworks.add(p);
455            } else {
456                if (DBG) loge("Ignoring protectedNetwork " + p);
457            }
458        }
459
460        // high priority first
461        mPriorityList = new int[mNetworksDefined];
462        {
463            int insertionPoint = mNetworksDefined-1;
464            int currentLowest = 0;
465            int nextLowest = 0;
466            while (insertionPoint > -1) {
467                for (NetworkConfig na : mNetConfigs) {
468                    if (na == null) continue;
469                    if (na.priority < currentLowest) continue;
470                    if (na.priority > currentLowest) {
471                        if (na.priority < nextLowest || nextLowest == 0) {
472                            nextLowest = na.priority;
473                        }
474                        continue;
475                    }
476                    mPriorityList[insertionPoint--] = na.type;
477                }
478                currentLowest = nextLowest;
479                nextLowest = 0;
480            }
481        }
482
483        mNetRequestersPids = new ArrayList[ConnectivityManager.MAX_NETWORK_TYPE+1];
484        for (int i : mPriorityList) {
485            mNetRequestersPids[i] = new ArrayList();
486        }
487
488        mFeatureUsers = new ArrayList<FeatureUser>();
489
490        mNumDnsEntries = 0;
491
492        mTestMode = SystemProperties.get("cm.test.mode").equals("true")
493                && SystemProperties.get("ro.build.type").equals("eng");
494
495        // Create and start trackers for hard-coded networks
496        for (int targetNetworkType : mPriorityList) {
497            final NetworkConfig config = mNetConfigs[targetNetworkType];
498            final NetworkStateTracker tracker;
499            try {
500                tracker = netFactory.createTracker(targetNetworkType, config);
501                mNetTrackers[targetNetworkType] = tracker;
502            } catch (IllegalArgumentException e) {
503                Slog.e(TAG, "Problem creating " + getNetworkTypeName(targetNetworkType)
504                        + " tracker: " + e);
505                continue;
506            }
507
508            tracker.startMonitoring(context, mTrackerHandler);
509            if (config.isDefault()) {
510                tracker.reconnect();
511            }
512        }
513
514        mTethering = new Tethering(mContext, mNetd, statsService, this, mHandler.getLooper());
515        mTetheringConfigValid = ((mTethering.getTetherableUsbRegexs().length != 0 ||
516                                  mTethering.getTetherableWifiRegexs().length != 0 ||
517                                  mTethering.getTetherableBluetoothRegexs().length != 0) &&
518                                 mTethering.getUpstreamIfaceTypes().length != 0);
519
520        mVpn = new Vpn(mContext, mVpnCallback, mNetd);
521        mVpn.startMonitoring(mContext, mTrackerHandler);
522
523        try {
524            mNetd.registerObserver(mTethering);
525            mNetd.registerObserver(mDataActivityObserver);
526        } catch (RemoteException e) {
527            loge("Error registering observer :" + e);
528        }
529
530        if (DBG) {
531            mInetLog = new ArrayList();
532        }
533
534        mSettingsObserver = new SettingsObserver(mHandler, EVENT_APPLY_GLOBAL_HTTP_PROXY);
535        mSettingsObserver.observe(mContext);
536
537        loadGlobalProxy();
538    }
539
540    /**
541     * Factory that creates {@link NetworkStateTracker} instances using given
542     * {@link NetworkConfig}.
543     */
544    public interface NetworkFactory {
545        public NetworkStateTracker createTracker(int targetNetworkType, NetworkConfig config);
546    }
547
548    private static class DefaultNetworkFactory implements NetworkFactory {
549        private final Context mContext;
550        private final Handler mTrackerHandler;
551
552        public DefaultNetworkFactory(Context context, Handler trackerHandler) {
553            mContext = context;
554            mTrackerHandler = trackerHandler;
555        }
556
557        @Override
558        public NetworkStateTracker createTracker(int targetNetworkType, NetworkConfig config) {
559            switch (config.radio) {
560                case TYPE_WIFI:
561                    return new WifiStateTracker(targetNetworkType, config.name);
562                case TYPE_MOBILE:
563                    return new MobileDataStateTracker(targetNetworkType, config.name);
564                case TYPE_DUMMY:
565                    return new DummyDataStateTracker(targetNetworkType, config.name);
566                case TYPE_BLUETOOTH:
567                    return BluetoothTetheringDataTracker.getInstance();
568                case TYPE_WIMAX:
569                    return makeWimaxStateTracker(mContext, mTrackerHandler);
570                case TYPE_ETHERNET:
571                    return EthernetDataTracker.getInstance();
572                default:
573                    throw new IllegalArgumentException(
574                            "Trying to create a NetworkStateTracker for an unknown radio type: "
575                            + config.radio);
576            }
577        }
578    }
579
580    /**
581     * Loads external WiMAX library and registers as system service, returning a
582     * {@link NetworkStateTracker} for WiMAX. Caller is still responsible for
583     * invoking {@link NetworkStateTracker#startMonitoring(Context, Handler)}.
584     */
585    private static NetworkStateTracker makeWimaxStateTracker(
586            Context context, Handler trackerHandler) {
587        // Initialize Wimax
588        DexClassLoader wimaxClassLoader;
589        Class wimaxStateTrackerClass = null;
590        Class wimaxServiceClass = null;
591        Class wimaxManagerClass;
592        String wimaxJarLocation;
593        String wimaxLibLocation;
594        String wimaxManagerClassName;
595        String wimaxServiceClassName;
596        String wimaxStateTrackerClassName;
597
598        NetworkStateTracker wimaxStateTracker = null;
599
600        boolean isWimaxEnabled = context.getResources().getBoolean(
601                com.android.internal.R.bool.config_wimaxEnabled);
602
603        if (isWimaxEnabled) {
604            try {
605                wimaxJarLocation = context.getResources().getString(
606                        com.android.internal.R.string.config_wimaxServiceJarLocation);
607                wimaxLibLocation = context.getResources().getString(
608                        com.android.internal.R.string.config_wimaxNativeLibLocation);
609                wimaxManagerClassName = context.getResources().getString(
610                        com.android.internal.R.string.config_wimaxManagerClassname);
611                wimaxServiceClassName = context.getResources().getString(
612                        com.android.internal.R.string.config_wimaxServiceClassname);
613                wimaxStateTrackerClassName = context.getResources().getString(
614                        com.android.internal.R.string.config_wimaxStateTrackerClassname);
615
616                log("wimaxJarLocation: " + wimaxJarLocation);
617                wimaxClassLoader =  new DexClassLoader(wimaxJarLocation,
618                        new ContextWrapper(context).getCacheDir().getAbsolutePath(),
619                        wimaxLibLocation, ClassLoader.getSystemClassLoader());
620
621                try {
622                    wimaxManagerClass = wimaxClassLoader.loadClass(wimaxManagerClassName);
623                    wimaxStateTrackerClass = wimaxClassLoader.loadClass(wimaxStateTrackerClassName);
624                    wimaxServiceClass = wimaxClassLoader.loadClass(wimaxServiceClassName);
625                } catch (ClassNotFoundException ex) {
626                    loge("Exception finding Wimax classes: " + ex.toString());
627                    return null;
628                }
629            } catch(Resources.NotFoundException ex) {
630                loge("Wimax Resources does not exist!!! ");
631                return null;
632            }
633
634            try {
635                log("Starting Wimax Service... ");
636
637                Constructor wmxStTrkrConst = wimaxStateTrackerClass.getConstructor
638                        (new Class[] {Context.class, Handler.class});
639                wimaxStateTracker = (NetworkStateTracker) wmxStTrkrConst.newInstance(
640                        context, trackerHandler);
641
642                Constructor wmxSrvConst = wimaxServiceClass.getDeclaredConstructor
643                        (new Class[] {Context.class, wimaxStateTrackerClass});
644                wmxSrvConst.setAccessible(true);
645                IBinder svcInvoker = (IBinder)wmxSrvConst.newInstance(context, wimaxStateTracker);
646                wmxSrvConst.setAccessible(false);
647
648                ServiceManager.addService(WimaxManagerConstants.WIMAX_SERVICE, svcInvoker);
649
650            } catch(Exception ex) {
651                loge("Exception creating Wimax classes: " + ex.toString());
652                return null;
653            }
654        } else {
655            loge("Wimax is not enabled or not added to the network attributes!!! ");
656            return null;
657        }
658
659        return wimaxStateTracker;
660    }
661
662    /**
663     * Sets the preferred network.
664     * @param preference the new preference
665     */
666    public void setNetworkPreference(int preference) {
667        enforceChangePermission();
668
669        mHandler.sendMessage(
670                mHandler.obtainMessage(EVENT_SET_NETWORK_PREFERENCE, preference, 0));
671    }
672
673    public int getNetworkPreference() {
674        enforceAccessPermission();
675        int preference;
676        synchronized(this) {
677            preference = mNetworkPreference;
678        }
679        return preference;
680    }
681
682    private void handleSetNetworkPreference(int preference) {
683        if (ConnectivityManager.isNetworkTypeValid(preference) &&
684                mNetConfigs[preference] != null &&
685                mNetConfigs[preference].isDefault()) {
686            if (mNetworkPreference != preference) {
687                final ContentResolver cr = mContext.getContentResolver();
688                Settings.Secure.putInt(cr, Settings.Secure.NETWORK_PREFERENCE, preference);
689                synchronized(this) {
690                    mNetworkPreference = preference;
691                }
692                enforcePreference();
693            }
694        }
695    }
696
697    private int getConnectivityChangeDelay() {
698        final ContentResolver cr = mContext.getContentResolver();
699
700        /** Check system properties for the default value then use secure settings value, if any. */
701        int defaultDelay = SystemProperties.getInt(
702                "conn." + Settings.Secure.CONNECTIVITY_CHANGE_DELAY,
703                Settings.Secure.CONNECTIVITY_CHANGE_DELAY_DEFAULT);
704        return Settings.Secure.getInt(cr, Settings.Secure.CONNECTIVITY_CHANGE_DELAY,
705                defaultDelay);
706    }
707
708    private int getPersistedNetworkPreference() {
709        final ContentResolver cr = mContext.getContentResolver();
710
711        final int networkPrefSetting = Settings.Secure
712                .getInt(cr, Settings.Secure.NETWORK_PREFERENCE, -1);
713        if (networkPrefSetting != -1) {
714            return networkPrefSetting;
715        }
716
717        return ConnectivityManager.DEFAULT_NETWORK_PREFERENCE;
718    }
719
720    /**
721     * Make the state of network connectivity conform to the preference settings
722     * In this method, we only tear down a non-preferred network. Establishing
723     * a connection to the preferred network is taken care of when we handle
724     * the disconnect event from the non-preferred network
725     * (see {@link #handleDisconnect(NetworkInfo)}).
726     */
727    private void enforcePreference() {
728        if (mNetTrackers[mNetworkPreference].getNetworkInfo().isConnected())
729            return;
730
731        if (!mNetTrackers[mNetworkPreference].isAvailable())
732            return;
733
734        for (int t=0; t <= ConnectivityManager.MAX_RADIO_TYPE; t++) {
735            if (t != mNetworkPreference && mNetTrackers[t] != null &&
736                    mNetTrackers[t].getNetworkInfo().isConnected()) {
737                if (DBG) {
738                    log("tearing down " + mNetTrackers[t].getNetworkInfo() +
739                            " in enforcePreference");
740                }
741                teardown(mNetTrackers[t]);
742            }
743        }
744    }
745
746    private boolean teardown(NetworkStateTracker netTracker) {
747        if (netTracker.teardown()) {
748            netTracker.setTeardownRequested(true);
749            return true;
750        } else {
751            return false;
752        }
753    }
754
755    /**
756     * Check if UID should be blocked from using the network represented by the
757     * given {@link NetworkStateTracker}.
758     */
759    private boolean isNetworkBlocked(NetworkStateTracker tracker, int uid) {
760        final String iface = tracker.getLinkProperties().getInterfaceName();
761
762        final boolean networkCostly;
763        final int uidRules;
764        synchronized (mRulesLock) {
765            networkCostly = mMeteredIfaces.contains(iface);
766            uidRules = mUidRules.get(uid, RULE_ALLOW_ALL);
767        }
768
769        if (networkCostly && (uidRules & RULE_REJECT_METERED) != 0) {
770            return true;
771        }
772
773        // no restrictive rules; network is visible
774        return false;
775    }
776
777    /**
778     * Return a filtered {@link NetworkInfo}, potentially marked
779     * {@link DetailedState#BLOCKED} based on
780     * {@link #isNetworkBlocked(NetworkStateTracker, int)}.
781     */
782    private NetworkInfo getFilteredNetworkInfo(NetworkStateTracker tracker, int uid) {
783        NetworkInfo info = tracker.getNetworkInfo();
784        if (isNetworkBlocked(tracker, uid)) {
785            // network is blocked; clone and override state
786            info = new NetworkInfo(info);
787            info.setDetailedState(DetailedState.BLOCKED, null, null);
788        }
789        return info;
790    }
791
792    /**
793     * Return NetworkInfo for the active (i.e., connected) network interface.
794     * It is assumed that at most one network is active at a time. If more
795     * than one is active, it is indeterminate which will be returned.
796     * @return the info for the active network, or {@code null} if none is
797     * active
798     */
799    @Override
800    public NetworkInfo getActiveNetworkInfo() {
801        enforceAccessPermission();
802        final int uid = Binder.getCallingUid();
803        return getNetworkInfo(mActiveDefaultNetwork, uid);
804    }
805
806    @Override
807    public NetworkInfo getActiveNetworkInfoForUid(int uid) {
808        enforceConnectivityInternalPermission();
809        return getNetworkInfo(mActiveDefaultNetwork, uid);
810    }
811
812    @Override
813    public NetworkInfo getNetworkInfo(int networkType) {
814        enforceAccessPermission();
815        final int uid = Binder.getCallingUid();
816        return getNetworkInfo(networkType, uid);
817    }
818
819    private NetworkInfo getNetworkInfo(int networkType, int uid) {
820        NetworkInfo info = null;
821        if (isNetworkTypeValid(networkType)) {
822            final NetworkStateTracker tracker = mNetTrackers[networkType];
823            if (tracker != null) {
824                info = getFilteredNetworkInfo(tracker, uid);
825            }
826        }
827        return info;
828    }
829
830    @Override
831    public NetworkInfo[] getAllNetworkInfo() {
832        enforceAccessPermission();
833        final int uid = Binder.getCallingUid();
834        final ArrayList<NetworkInfo> result = Lists.newArrayList();
835        synchronized (mRulesLock) {
836            for (NetworkStateTracker tracker : mNetTrackers) {
837                if (tracker != null) {
838                    result.add(getFilteredNetworkInfo(tracker, uid));
839                }
840            }
841        }
842        return result.toArray(new NetworkInfo[result.size()]);
843    }
844
845    @Override
846    public boolean isNetworkSupported(int networkType) {
847        enforceAccessPermission();
848        return (isNetworkTypeValid(networkType) && (mNetTrackers[networkType] != null));
849    }
850
851    /**
852     * Return LinkProperties for the active (i.e., connected) default
853     * network interface.  It is assumed that at most one default network
854     * is active at a time. If more than one is active, it is indeterminate
855     * which will be returned.
856     * @return the ip properties for the active network, or {@code null} if
857     * none is active
858     */
859    @Override
860    public LinkProperties getActiveLinkProperties() {
861        return getLinkProperties(mActiveDefaultNetwork);
862    }
863
864    @Override
865    public LinkProperties getLinkProperties(int networkType) {
866        enforceAccessPermission();
867        if (isNetworkTypeValid(networkType)) {
868            final NetworkStateTracker tracker = mNetTrackers[networkType];
869            if (tracker != null) {
870                return tracker.getLinkProperties();
871            }
872        }
873        return null;
874    }
875
876    @Override
877    public NetworkState[] getAllNetworkState() {
878        enforceAccessPermission();
879        final int uid = Binder.getCallingUid();
880        final ArrayList<NetworkState> result = Lists.newArrayList();
881        synchronized (mRulesLock) {
882            for (NetworkStateTracker tracker : mNetTrackers) {
883                if (tracker != null) {
884                    final NetworkInfo info = getFilteredNetworkInfo(tracker, uid);
885                    result.add(new NetworkState(
886                            info, tracker.getLinkProperties(), tracker.getLinkCapabilities()));
887                }
888            }
889        }
890        return result.toArray(new NetworkState[result.size()]);
891    }
892
893    private NetworkState getNetworkStateUnchecked(int networkType) {
894        if (isNetworkTypeValid(networkType)) {
895            final NetworkStateTracker tracker = mNetTrackers[networkType];
896            if (tracker != null) {
897                return new NetworkState(tracker.getNetworkInfo(), tracker.getLinkProperties(),
898                        tracker.getLinkCapabilities());
899            }
900        }
901        return null;
902    }
903
904    @Override
905    public NetworkQuotaInfo getActiveNetworkQuotaInfo() {
906        enforceAccessPermission();
907
908        final long token = Binder.clearCallingIdentity();
909        try {
910            final NetworkState state = getNetworkStateUnchecked(mActiveDefaultNetwork);
911            if (state != null) {
912                try {
913                    return mPolicyManager.getNetworkQuotaInfo(state);
914                } catch (RemoteException e) {
915                }
916            }
917            return null;
918        } finally {
919            Binder.restoreCallingIdentity(token);
920        }
921    }
922
923    @Override
924    public boolean isActiveNetworkMetered() {
925        enforceAccessPermission();
926        final long token = Binder.clearCallingIdentity();
927        try {
928            return isNetworkMeteredUnchecked(mActiveDefaultNetwork);
929        } finally {
930            Binder.restoreCallingIdentity(token);
931        }
932    }
933
934    private boolean isNetworkMeteredUnchecked(int networkType) {
935        final NetworkState state = getNetworkStateUnchecked(networkType);
936        if (state != null) {
937            try {
938                return mPolicyManager.isNetworkMetered(state);
939            } catch (RemoteException e) {
940            }
941        }
942        return false;
943    }
944
945    public boolean setRadios(boolean turnOn) {
946        boolean result = true;
947        enforceChangePermission();
948        for (NetworkStateTracker t : mNetTrackers) {
949            if (t != null) result = t.setRadio(turnOn) && result;
950        }
951        return result;
952    }
953
954    public boolean setRadio(int netType, boolean turnOn) {
955        enforceChangePermission();
956        if (!ConnectivityManager.isNetworkTypeValid(netType)) {
957            return false;
958        }
959        NetworkStateTracker tracker = mNetTrackers[netType];
960        return tracker != null && tracker.setRadio(turnOn);
961    }
962
963    private INetworkManagementEventObserver mDataActivityObserver = new BaseNetworkObserver() {
964        @Override
965        public void interfaceClassDataActivityChanged(String label, boolean active) {
966            int deviceType = Integer.parseInt(label);
967            sendDataActivityBroadcast(deviceType, active);
968        }
969    };
970
971    /**
972     * Used to notice when the calling process dies so we can self-expire
973     *
974     * Also used to know if the process has cleaned up after itself when
975     * our auto-expire timer goes off.  The timer has a link to an object.
976     *
977     */
978    private class FeatureUser implements IBinder.DeathRecipient {
979        int mNetworkType;
980        String mFeature;
981        IBinder mBinder;
982        int mPid;
983        int mUid;
984        long mCreateTime;
985
986        FeatureUser(int type, String feature, IBinder binder) {
987            super();
988            mNetworkType = type;
989            mFeature = feature;
990            mBinder = binder;
991            mPid = getCallingPid();
992            mUid = getCallingUid();
993            mCreateTime = System.currentTimeMillis();
994
995            try {
996                mBinder.linkToDeath(this, 0);
997            } catch (RemoteException e) {
998                binderDied();
999            }
1000        }
1001
1002        void unlinkDeathRecipient() {
1003            mBinder.unlinkToDeath(this, 0);
1004        }
1005
1006        public void binderDied() {
1007            log("ConnectivityService FeatureUser binderDied(" +
1008                    mNetworkType + ", " + mFeature + ", " + mBinder + "), created " +
1009                    (System.currentTimeMillis() - mCreateTime) + " mSec ago");
1010            stopUsingNetworkFeature(this, false);
1011        }
1012
1013        public void expire() {
1014            if (VDBG) {
1015                log("ConnectivityService FeatureUser expire(" +
1016                        mNetworkType + ", " + mFeature + ", " + mBinder +"), created " +
1017                        (System.currentTimeMillis() - mCreateTime) + " mSec ago");
1018            }
1019            stopUsingNetworkFeature(this, false);
1020        }
1021
1022        public boolean isSameUser(FeatureUser u) {
1023            if (u == null) return false;
1024
1025            return isSameUser(u.mPid, u.mUid, u.mNetworkType, u.mFeature);
1026        }
1027
1028        public boolean isSameUser(int pid, int uid, int networkType, String feature) {
1029            if ((mPid == pid) && (mUid == uid) && (mNetworkType == networkType) &&
1030                TextUtils.equals(mFeature, feature)) {
1031                return true;
1032            }
1033            return false;
1034        }
1035
1036        public String toString() {
1037            return "FeatureUser("+mNetworkType+","+mFeature+","+mPid+","+mUid+"), created " +
1038                    (System.currentTimeMillis() - mCreateTime) + " mSec ago";
1039        }
1040    }
1041
1042    // javadoc from interface
1043    public int startUsingNetworkFeature(int networkType, String feature,
1044            IBinder binder) {
1045        long startTime = 0;
1046        if (DBG) {
1047            startTime = SystemClock.elapsedRealtime();
1048        }
1049        if (VDBG) {
1050            log("startUsingNetworkFeature for net " + networkType + ": " + feature + ", uid="
1051                    + Binder.getCallingUid());
1052        }
1053        enforceChangePermission();
1054        try {
1055            if (!ConnectivityManager.isNetworkTypeValid(networkType) ||
1056                    mNetConfigs[networkType] == null) {
1057                return PhoneConstants.APN_REQUEST_FAILED;
1058            }
1059
1060            FeatureUser f = new FeatureUser(networkType, feature, binder);
1061
1062            // TODO - move this into individual networktrackers
1063            int usedNetworkType = convertFeatureToNetworkType(networkType, feature);
1064
1065            if (mProtectedNetworks.contains(usedNetworkType)) {
1066                enforceConnectivityInternalPermission();
1067            }
1068
1069            // if UID is restricted, don't allow them to bring up metered APNs
1070            final boolean networkMetered = isNetworkMeteredUnchecked(usedNetworkType);
1071            final int uidRules;
1072            synchronized (mRulesLock) {
1073                uidRules = mUidRules.get(Binder.getCallingUid(), RULE_ALLOW_ALL);
1074            }
1075            if (networkMetered && (uidRules & RULE_REJECT_METERED) != 0) {
1076                return PhoneConstants.APN_REQUEST_FAILED;
1077            }
1078
1079            NetworkStateTracker network = mNetTrackers[usedNetworkType];
1080            if (network != null) {
1081                Integer currentPid = new Integer(getCallingPid());
1082                if (usedNetworkType != networkType) {
1083                    NetworkInfo ni = network.getNetworkInfo();
1084
1085                    if (ni.isAvailable() == false) {
1086                        if (!TextUtils.equals(feature,Phone.FEATURE_ENABLE_DUN_ALWAYS)) {
1087                            if (DBG) log("special network not available ni=" + ni.getTypeName());
1088                            return PhoneConstants.APN_TYPE_NOT_AVAILABLE;
1089                        } else {
1090                            // else make the attempt anyway - probably giving REQUEST_STARTED below
1091                            if (DBG) {
1092                                log("special network not available, but try anyway ni=" +
1093                                        ni.getTypeName());
1094                            }
1095                        }
1096                    }
1097
1098                    int restoreTimer = getRestoreDefaultNetworkDelay(usedNetworkType);
1099
1100                    synchronized(this) {
1101                        boolean addToList = true;
1102                        if (restoreTimer < 0) {
1103                            // In case there is no timer is specified for the feature,
1104                            // make sure we don't add duplicate entry with the same request.
1105                            for (FeatureUser u : mFeatureUsers) {
1106                                if (u.isSameUser(f)) {
1107                                    // Duplicate user is found. Do not add.
1108                                    addToList = false;
1109                                    break;
1110                                }
1111                            }
1112                        }
1113
1114                        if (addToList) mFeatureUsers.add(f);
1115                        if (!mNetRequestersPids[usedNetworkType].contains(currentPid)) {
1116                            // this gets used for per-pid dns when connected
1117                            mNetRequestersPids[usedNetworkType].add(currentPid);
1118                        }
1119                    }
1120
1121                    if (restoreTimer >= 0) {
1122                        mHandler.sendMessageDelayed(mHandler.obtainMessage(
1123                                EVENT_RESTORE_DEFAULT_NETWORK, f), restoreTimer);
1124                    }
1125
1126                    if ((ni.isConnectedOrConnecting() == true) &&
1127                            !network.isTeardownRequested()) {
1128                        if (ni.isConnected() == true) {
1129                            final long token = Binder.clearCallingIdentity();
1130                            try {
1131                                // add the pid-specific dns
1132                                handleDnsConfigurationChange(usedNetworkType);
1133                                if (VDBG) log("special network already active");
1134                            } finally {
1135                                Binder.restoreCallingIdentity(token);
1136                            }
1137                            return PhoneConstants.APN_ALREADY_ACTIVE;
1138                        }
1139                        if (VDBG) log("special network already connecting");
1140                        return PhoneConstants.APN_REQUEST_STARTED;
1141                    }
1142
1143                    // check if the radio in play can make another contact
1144                    // assume if cannot for now
1145
1146                    if (DBG) {
1147                        log("startUsingNetworkFeature reconnecting to " + networkType + ": " +
1148                                feature);
1149                    }
1150                    network.reconnect();
1151                    return PhoneConstants.APN_REQUEST_STARTED;
1152                } else {
1153                    // need to remember this unsupported request so we respond appropriately on stop
1154                    synchronized(this) {
1155                        mFeatureUsers.add(f);
1156                        if (!mNetRequestersPids[usedNetworkType].contains(currentPid)) {
1157                            // this gets used for per-pid dns when connected
1158                            mNetRequestersPids[usedNetworkType].add(currentPid);
1159                        }
1160                    }
1161                    return -1;
1162                }
1163            }
1164            return PhoneConstants.APN_TYPE_NOT_AVAILABLE;
1165         } finally {
1166            if (DBG) {
1167                final long execTime = SystemClock.elapsedRealtime() - startTime;
1168                if (execTime > 250) {
1169                    loge("startUsingNetworkFeature took too long: " + execTime + "ms");
1170                } else {
1171                    if (VDBG) log("startUsingNetworkFeature took " + execTime + "ms");
1172                }
1173            }
1174         }
1175    }
1176
1177    // javadoc from interface
1178    public int stopUsingNetworkFeature(int networkType, String feature) {
1179        enforceChangePermission();
1180
1181        int pid = getCallingPid();
1182        int uid = getCallingUid();
1183
1184        FeatureUser u = null;
1185        boolean found = false;
1186
1187        synchronized(this) {
1188            for (FeatureUser x : mFeatureUsers) {
1189                if (x.isSameUser(pid, uid, networkType, feature)) {
1190                    u = x;
1191                    found = true;
1192                    break;
1193                }
1194            }
1195        }
1196        if (found && u != null) {
1197            // stop regardless of how many other time this proc had called start
1198            return stopUsingNetworkFeature(u, true);
1199        } else {
1200            // none found!
1201            if (VDBG) log("stopUsingNetworkFeature - not a live request, ignoring");
1202            return 1;
1203        }
1204    }
1205
1206    private int stopUsingNetworkFeature(FeatureUser u, boolean ignoreDups) {
1207        int networkType = u.mNetworkType;
1208        String feature = u.mFeature;
1209        int pid = u.mPid;
1210        int uid = u.mUid;
1211
1212        NetworkStateTracker tracker = null;
1213        boolean callTeardown = false;  // used to carry our decision outside of sync block
1214
1215        if (VDBG) {
1216            log("stopUsingNetworkFeature: net " + networkType + ": " + feature);
1217        }
1218
1219        if (!ConnectivityManager.isNetworkTypeValid(networkType)) {
1220            if (DBG) {
1221                log("stopUsingNetworkFeature: net " + networkType + ": " + feature +
1222                        ", net is invalid");
1223            }
1224            return -1;
1225        }
1226
1227        // need to link the mFeatureUsers list with the mNetRequestersPids state in this
1228        // sync block
1229        synchronized(this) {
1230            // check if this process still has an outstanding start request
1231            if (!mFeatureUsers.contains(u)) {
1232                if (VDBG) {
1233                    log("stopUsingNetworkFeature: this process has no outstanding requests" +
1234                        ", ignoring");
1235                }
1236                return 1;
1237            }
1238            u.unlinkDeathRecipient();
1239            mFeatureUsers.remove(mFeatureUsers.indexOf(u));
1240            // If we care about duplicate requests, check for that here.
1241            //
1242            // This is done to support the extension of a request - the app
1243            // can request we start the network feature again and renew the
1244            // auto-shutoff delay.  Normal "stop" calls from the app though
1245            // do not pay attention to duplicate requests - in effect the
1246            // API does not refcount and a single stop will counter multiple starts.
1247            if (ignoreDups == false) {
1248                for (FeatureUser x : mFeatureUsers) {
1249                    if (x.isSameUser(u)) {
1250                        if (VDBG) log("stopUsingNetworkFeature: dup is found, ignoring");
1251                        return 1;
1252                    }
1253                }
1254            }
1255
1256            // TODO - move to individual network trackers
1257            int usedNetworkType = convertFeatureToNetworkType(networkType, feature);
1258
1259            tracker =  mNetTrackers[usedNetworkType];
1260            if (tracker == null) {
1261                if (DBG) {
1262                    log("stopUsingNetworkFeature: net " + networkType + ": " + feature +
1263                            " no known tracker for used net type " + usedNetworkType);
1264                }
1265                return -1;
1266            }
1267            if (usedNetworkType != networkType) {
1268                Integer currentPid = new Integer(pid);
1269                mNetRequestersPids[usedNetworkType].remove(currentPid);
1270                reassessPidDns(pid, true);
1271                if (mNetRequestersPids[usedNetworkType].size() != 0) {
1272                    if (VDBG) {
1273                        log("stopUsingNetworkFeature: net " + networkType + ": " + feature +
1274                                " others still using it");
1275                    }
1276                    return 1;
1277                }
1278                callTeardown = true;
1279            } else {
1280                if (DBG) {
1281                    log("stopUsingNetworkFeature: net " + networkType + ": " + feature +
1282                            " not a known feature - dropping");
1283                }
1284            }
1285        }
1286
1287        if (callTeardown) {
1288            if (DBG) {
1289                log("stopUsingNetworkFeature: teardown net " + networkType + ": " + feature);
1290            }
1291            tracker.teardown();
1292            return 1;
1293        } else {
1294            return -1;
1295        }
1296    }
1297
1298    /**
1299     * @deprecated use requestRouteToHostAddress instead
1300     *
1301     * Ensure that a network route exists to deliver traffic to the specified
1302     * host via the specified network interface.
1303     * @param networkType the type of the network over which traffic to the
1304     * specified host is to be routed
1305     * @param hostAddress the IP address of the host to which the route is
1306     * desired
1307     * @return {@code true} on success, {@code false} on failure
1308     */
1309    public boolean requestRouteToHost(int networkType, int hostAddress) {
1310        InetAddress inetAddress = NetworkUtils.intToInetAddress(hostAddress);
1311
1312        if (inetAddress == null) {
1313            return false;
1314        }
1315
1316        return requestRouteToHostAddress(networkType, inetAddress.getAddress());
1317    }
1318
1319    /**
1320     * Ensure that a network route exists to deliver traffic to the specified
1321     * host via the specified network interface.
1322     * @param networkType the type of the network over which traffic to the
1323     * specified host is to be routed
1324     * @param hostAddress the IP address of the host to which the route is
1325     * desired
1326     * @return {@code true} on success, {@code false} on failure
1327     */
1328    public boolean requestRouteToHostAddress(int networkType, byte[] hostAddress) {
1329        enforceChangePermission();
1330        if (mProtectedNetworks.contains(networkType)) {
1331            enforceConnectivityInternalPermission();
1332        }
1333
1334        if (!ConnectivityManager.isNetworkTypeValid(networkType)) {
1335            if (DBG) log("requestRouteToHostAddress on invalid network: " + networkType);
1336            return false;
1337        }
1338        NetworkStateTracker tracker = mNetTrackers[networkType];
1339
1340        if (tracker == null || !tracker.getNetworkInfo().isConnected() ||
1341                tracker.isTeardownRequested()) {
1342            if (VDBG) {
1343                log("requestRouteToHostAddress on down network " +
1344                           "(" + networkType + ") - dropped");
1345            }
1346            return false;
1347        }
1348        final long token = Binder.clearCallingIdentity();
1349        try {
1350            InetAddress addr = InetAddress.getByAddress(hostAddress);
1351            LinkProperties lp = tracker.getLinkProperties();
1352            return addRouteToAddress(lp, addr);
1353        } catch (UnknownHostException e) {
1354            if (DBG) log("requestRouteToHostAddress got " + e.toString());
1355        } finally {
1356            Binder.restoreCallingIdentity(token);
1357        }
1358        return false;
1359    }
1360
1361    private boolean addRoute(LinkProperties p, RouteInfo r, boolean toDefaultTable) {
1362        return modifyRoute(p.getInterfaceName(), p, r, 0, ADD, toDefaultTable);
1363    }
1364
1365    private boolean removeRoute(LinkProperties p, RouteInfo r, boolean toDefaultTable) {
1366        return modifyRoute(p.getInterfaceName(), p, r, 0, REMOVE, toDefaultTable);
1367    }
1368
1369    private boolean addRouteToAddress(LinkProperties lp, InetAddress addr) {
1370        return modifyRouteToAddress(lp, addr, ADD, TO_DEFAULT_TABLE);
1371    }
1372
1373    private boolean removeRouteToAddress(LinkProperties lp, InetAddress addr) {
1374        return modifyRouteToAddress(lp, addr, REMOVE, TO_DEFAULT_TABLE);
1375    }
1376
1377    private boolean modifyRouteToAddress(LinkProperties lp, InetAddress addr, boolean doAdd,
1378            boolean toDefaultTable) {
1379        RouteInfo bestRoute = RouteInfo.selectBestRoute(lp.getRoutes(), addr);
1380        if (bestRoute == null) {
1381            bestRoute = RouteInfo.makeHostRoute(addr);
1382        } else {
1383            if (bestRoute.getGateway().equals(addr)) {
1384                // if there is no better route, add the implied hostroute for our gateway
1385                bestRoute = RouteInfo.makeHostRoute(addr);
1386            } else {
1387                // if we will connect to this through another route, add a direct route
1388                // to it's gateway
1389                bestRoute = RouteInfo.makeHostRoute(addr, bestRoute.getGateway());
1390            }
1391        }
1392        return modifyRoute(lp.getInterfaceName(), lp, bestRoute, 0, doAdd, toDefaultTable);
1393    }
1394
1395    private boolean modifyRoute(String ifaceName, LinkProperties lp, RouteInfo r, int cycleCount,
1396            boolean doAdd, boolean toDefaultTable) {
1397        if ((ifaceName == null) || (lp == null) || (r == null)) {
1398            if (DBG) log("modifyRoute got unexpected null: " + ifaceName + ", " + lp + ", " + r);
1399            return false;
1400        }
1401
1402        if (cycleCount > MAX_HOSTROUTE_CYCLE_COUNT) {
1403            loge("Error modifying route - too much recursion");
1404            return false;
1405        }
1406
1407        if (r.isHostRoute() == false) {
1408            RouteInfo bestRoute = RouteInfo.selectBestRoute(lp.getRoutes(), r.getGateway());
1409            if (bestRoute != null) {
1410                if (bestRoute.getGateway().equals(r.getGateway())) {
1411                    // if there is no better route, add the implied hostroute for our gateway
1412                    bestRoute = RouteInfo.makeHostRoute(r.getGateway());
1413                } else {
1414                    // if we will connect to our gateway through another route, add a direct
1415                    // route to it's gateway
1416                    bestRoute = RouteInfo.makeHostRoute(r.getGateway(), bestRoute.getGateway());
1417                }
1418                modifyRoute(ifaceName, lp, bestRoute, cycleCount+1, doAdd, toDefaultTable);
1419            }
1420        }
1421        if (doAdd) {
1422            if (VDBG) log("Adding " + r + " for interface " + ifaceName);
1423            try {
1424                if (toDefaultTable) {
1425                    mAddedRoutes.add(r);  // only track default table - only one apps can effect
1426                    mNetd.addRoute(ifaceName, r);
1427                } else {
1428                    mNetd.addSecondaryRoute(ifaceName, r);
1429                }
1430            } catch (Exception e) {
1431                // never crash - catch them all
1432                if (DBG) loge("Exception trying to add a route: " + e);
1433                return false;
1434            }
1435        } else {
1436            // if we remove this one and there are no more like it, then refcount==0 and
1437            // we can remove it from the table
1438            if (toDefaultTable) {
1439                mAddedRoutes.remove(r);
1440                if (mAddedRoutes.contains(r) == false) {
1441                    if (VDBG) log("Removing " + r + " for interface " + ifaceName);
1442                    try {
1443                        mNetd.removeRoute(ifaceName, r);
1444                    } catch (Exception e) {
1445                        // never crash - catch them all
1446                        if (VDBG) loge("Exception trying to remove a route: " + e);
1447                        return false;
1448                    }
1449                } else {
1450                    if (VDBG) log("not removing " + r + " as it's still in use");
1451                }
1452            } else {
1453                if (VDBG) log("Removing " + r + " for interface " + ifaceName);
1454                try {
1455                    mNetd.removeSecondaryRoute(ifaceName, r);
1456                } catch (Exception e) {
1457                    // never crash - catch them all
1458                    if (VDBG) loge("Exception trying to remove a route: " + e);
1459                    return false;
1460                }
1461            }
1462        }
1463        return true;
1464    }
1465
1466    /**
1467     * @see ConnectivityManager#getMobileDataEnabled()
1468     */
1469    public boolean getMobileDataEnabled() {
1470        // TODO: This detail should probably be in DataConnectionTracker's
1471        //       which is where we store the value and maybe make this
1472        //       asynchronous.
1473        enforceAccessPermission();
1474        boolean retVal = Settings.Secure.getInt(mContext.getContentResolver(),
1475                Settings.Secure.MOBILE_DATA, 1) == 1;
1476        if (VDBG) log("getMobileDataEnabled returning " + retVal);
1477        return retVal;
1478    }
1479
1480    public void setDataDependency(int networkType, boolean met) {
1481        enforceConnectivityInternalPermission();
1482
1483        mHandler.sendMessage(mHandler.obtainMessage(EVENT_SET_DEPENDENCY_MET,
1484                (met ? ENABLED : DISABLED), networkType));
1485    }
1486
1487    private void handleSetDependencyMet(int networkType, boolean met) {
1488        if (mNetTrackers[networkType] != null) {
1489            if (DBG) {
1490                log("handleSetDependencyMet(" + networkType + ", " + met + ")");
1491            }
1492            mNetTrackers[networkType].setDependencyMet(met);
1493        }
1494    }
1495
1496    private INetworkPolicyListener mPolicyListener = new INetworkPolicyListener.Stub() {
1497        @Override
1498        public void onUidRulesChanged(int uid, int uidRules) {
1499            // caller is NPMS, since we only register with them
1500            if (LOGD_RULES) {
1501                log("onUidRulesChanged(uid=" + uid + ", uidRules=" + uidRules + ")");
1502            }
1503
1504            synchronized (mRulesLock) {
1505                // skip update when we've already applied rules
1506                final int oldRules = mUidRules.get(uid, RULE_ALLOW_ALL);
1507                if (oldRules == uidRules) return;
1508
1509                mUidRules.put(uid, uidRules);
1510            }
1511
1512            // TODO: notify UID when it has requested targeted updates
1513        }
1514
1515        @Override
1516        public void onMeteredIfacesChanged(String[] meteredIfaces) {
1517            // caller is NPMS, since we only register with them
1518            if (LOGD_RULES) {
1519                log("onMeteredIfacesChanged(ifaces=" + Arrays.toString(meteredIfaces) + ")");
1520            }
1521
1522            synchronized (mRulesLock) {
1523                mMeteredIfaces.clear();
1524                for (String iface : meteredIfaces) {
1525                    mMeteredIfaces.add(iface);
1526                }
1527            }
1528        }
1529
1530        @Override
1531        public void onRestrictBackgroundChanged(boolean restrictBackground) {
1532            // caller is NPMS, since we only register with them
1533            if (LOGD_RULES) {
1534                log("onRestrictBackgroundChanged(restrictBackground=" + restrictBackground + ")");
1535            }
1536
1537            // kick off connectivity change broadcast for active network, since
1538            // global background policy change is radical.
1539            final int networkType = mActiveDefaultNetwork;
1540            if (isNetworkTypeValid(networkType)) {
1541                final NetworkStateTracker tracker = mNetTrackers[networkType];
1542                if (tracker != null) {
1543                    final NetworkInfo info = tracker.getNetworkInfo();
1544                    if (info != null && info.isConnected()) {
1545                        sendConnectedBroadcast(info);
1546                    }
1547                }
1548            }
1549        }
1550    };
1551
1552    /**
1553     * @see ConnectivityManager#setMobileDataEnabled(boolean)
1554     */
1555    public void setMobileDataEnabled(boolean enabled) {
1556        enforceChangePermission();
1557        if (DBG) log("setMobileDataEnabled(" + enabled + ")");
1558
1559        mHandler.sendMessage(mHandler.obtainMessage(EVENT_SET_MOBILE_DATA,
1560                (enabled ? ENABLED : DISABLED), 0));
1561    }
1562
1563    private void handleSetMobileData(boolean enabled) {
1564        if (mNetTrackers[ConnectivityManager.TYPE_MOBILE] != null) {
1565            if (VDBG) {
1566                log(mNetTrackers[ConnectivityManager.TYPE_MOBILE].toString() + enabled);
1567            }
1568            mNetTrackers[ConnectivityManager.TYPE_MOBILE].setUserDataEnable(enabled);
1569        }
1570        if (mNetTrackers[ConnectivityManager.TYPE_WIMAX] != null) {
1571            if (VDBG) {
1572                log(mNetTrackers[ConnectivityManager.TYPE_WIMAX].toString() + enabled);
1573            }
1574            mNetTrackers[ConnectivityManager.TYPE_WIMAX].setUserDataEnable(enabled);
1575        }
1576    }
1577
1578    @Override
1579    public void setPolicyDataEnable(int networkType, boolean enabled) {
1580        // only someone like NPMS should only be calling us
1581        mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
1582
1583        mHandler.sendMessage(mHandler.obtainMessage(
1584                EVENT_SET_POLICY_DATA_ENABLE, networkType, (enabled ? ENABLED : DISABLED)));
1585    }
1586
1587    private void handleSetPolicyDataEnable(int networkType, boolean enabled) {
1588        if (isNetworkTypeValid(networkType)) {
1589            final NetworkStateTracker tracker = mNetTrackers[networkType];
1590            if (tracker != null) {
1591                tracker.setPolicyDataEnable(enabled);
1592            }
1593        }
1594    }
1595
1596    private void enforceAccessPermission() {
1597        mContext.enforceCallingOrSelfPermission(
1598                android.Manifest.permission.ACCESS_NETWORK_STATE,
1599                "ConnectivityService");
1600    }
1601
1602    private void enforceChangePermission() {
1603        mContext.enforceCallingOrSelfPermission(
1604                android.Manifest.permission.CHANGE_NETWORK_STATE,
1605                "ConnectivityService");
1606    }
1607
1608    // TODO Make this a special check when it goes public
1609    private void enforceTetherChangePermission() {
1610        mContext.enforceCallingOrSelfPermission(
1611                android.Manifest.permission.CHANGE_NETWORK_STATE,
1612                "ConnectivityService");
1613    }
1614
1615    private void enforceTetherAccessPermission() {
1616        mContext.enforceCallingOrSelfPermission(
1617                android.Manifest.permission.ACCESS_NETWORK_STATE,
1618                "ConnectivityService");
1619    }
1620
1621    private void enforceConnectivityInternalPermission() {
1622        mContext.enforceCallingOrSelfPermission(
1623                android.Manifest.permission.CONNECTIVITY_INTERNAL,
1624                "ConnectivityService");
1625    }
1626
1627    /**
1628     * Handle a {@code DISCONNECTED} event. If this pertains to the non-active
1629     * network, we ignore it. If it is for the active network, we send out a
1630     * broadcast. But first, we check whether it might be possible to connect
1631     * to a different network.
1632     * @param info the {@code NetworkInfo} for the network
1633     */
1634    private void handleDisconnect(NetworkInfo info) {
1635
1636        int prevNetType = info.getType();
1637
1638        mNetTrackers[prevNetType].setTeardownRequested(false);
1639
1640        // Remove idletimer previously setup in {@code handleConnect}
1641        removeDataActivityTracking(prevNetType);
1642
1643        /*
1644         * If the disconnected network is not the active one, then don't report
1645         * this as a loss of connectivity. What probably happened is that we're
1646         * getting the disconnect for a network that we explicitly disabled
1647         * in accordance with network preference policies.
1648         */
1649        if (!mNetConfigs[prevNetType].isDefault()) {
1650            List pids = mNetRequestersPids[prevNetType];
1651            for (int i = 0; i<pids.size(); i++) {
1652                Integer pid = (Integer)pids.get(i);
1653                // will remove them because the net's no longer connected
1654                // need to do this now as only now do we know the pids and
1655                // can properly null things that are no longer referenced.
1656                reassessPidDns(pid.intValue(), false);
1657            }
1658        }
1659
1660        Intent intent = new Intent(ConnectivityManager.CONNECTIVITY_ACTION);
1661        intent.putExtra(ConnectivityManager.EXTRA_NETWORK_INFO, info);
1662        intent.putExtra(ConnectivityManager.EXTRA_NETWORK_TYPE, info.getType());
1663        if (info.isFailover()) {
1664            intent.putExtra(ConnectivityManager.EXTRA_IS_FAILOVER, true);
1665            info.setFailover(false);
1666        }
1667        if (info.getReason() != null) {
1668            intent.putExtra(ConnectivityManager.EXTRA_REASON, info.getReason());
1669        }
1670        if (info.getExtraInfo() != null) {
1671            intent.putExtra(ConnectivityManager.EXTRA_EXTRA_INFO,
1672                    info.getExtraInfo());
1673        }
1674
1675        if (mNetConfigs[prevNetType].isDefault()) {
1676            tryFailover(prevNetType);
1677            if (mActiveDefaultNetwork != -1) {
1678                NetworkInfo switchTo = mNetTrackers[mActiveDefaultNetwork].getNetworkInfo();
1679                intent.putExtra(ConnectivityManager.EXTRA_OTHER_NETWORK_INFO, switchTo);
1680            } else {
1681                mDefaultInetConditionPublished = 0; // we're not connected anymore
1682                intent.putExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, true);
1683            }
1684        }
1685        intent.putExtra(ConnectivityManager.EXTRA_INET_CONDITION, mDefaultInetConditionPublished);
1686
1687        // Reset interface if no other connections are using the same interface
1688        boolean doReset = true;
1689        LinkProperties linkProperties = mNetTrackers[prevNetType].getLinkProperties();
1690        if (linkProperties != null) {
1691            String oldIface = linkProperties.getInterfaceName();
1692            if (TextUtils.isEmpty(oldIface) == false) {
1693                for (NetworkStateTracker networkStateTracker : mNetTrackers) {
1694                    if (networkStateTracker == null) continue;
1695                    NetworkInfo networkInfo = networkStateTracker.getNetworkInfo();
1696                    if (networkInfo.isConnected() && networkInfo.getType() != prevNetType) {
1697                        LinkProperties l = networkStateTracker.getLinkProperties();
1698                        if (l == null) continue;
1699                        if (oldIface.equals(l.getInterfaceName())) {
1700                            doReset = false;
1701                            break;
1702                        }
1703                    }
1704                }
1705            }
1706        }
1707
1708        // do this before we broadcast the change
1709        handleConnectivityChange(prevNetType, doReset);
1710
1711        final Intent immediateIntent = new Intent(intent);
1712        immediateIntent.setAction(CONNECTIVITY_ACTION_IMMEDIATE);
1713        sendStickyBroadcast(immediateIntent);
1714        sendStickyBroadcastDelayed(intent, getConnectivityChangeDelay());
1715        /*
1716         * If the failover network is already connected, then immediately send
1717         * out a followup broadcast indicating successful failover
1718         */
1719        if (mActiveDefaultNetwork != -1) {
1720            sendConnectedBroadcastDelayed(mNetTrackers[mActiveDefaultNetwork].getNetworkInfo(),
1721                    getConnectivityChangeDelay());
1722        }
1723    }
1724
1725    private void tryFailover(int prevNetType) {
1726        /*
1727         * If this is a default network, check if other defaults are available.
1728         * Try to reconnect on all available and let them hash it out when
1729         * more than one connects.
1730         */
1731        if (mNetConfigs[prevNetType].isDefault()) {
1732            if (mActiveDefaultNetwork == prevNetType) {
1733                mActiveDefaultNetwork = -1;
1734            }
1735
1736            // don't signal a reconnect for anything lower or equal priority than our
1737            // current connected default
1738            // TODO - don't filter by priority now - nice optimization but risky
1739//            int currentPriority = -1;
1740//            if (mActiveDefaultNetwork != -1) {
1741//                currentPriority = mNetConfigs[mActiveDefaultNetwork].mPriority;
1742//            }
1743            for (int checkType=0; checkType <= ConnectivityManager.MAX_NETWORK_TYPE; checkType++) {
1744                if (checkType == prevNetType) continue;
1745                if (mNetConfigs[checkType] == null) continue;
1746                if (!mNetConfigs[checkType].isDefault()) continue;
1747                if (mNetTrackers[checkType] == null) continue;
1748
1749// Enabling the isAvailable() optimization caused mobile to not get
1750// selected if it was in the middle of error handling. Specifically
1751// a moble connection that took 30 seconds to complete the DEACTIVATE_DATA_CALL
1752// would not be available and we wouldn't get connected to anything.
1753// So removing the isAvailable() optimization below for now. TODO: This
1754// optimization should work and we need to investigate why it doesn't work.
1755// This could be related to how DEACTIVATE_DATA_CALL is reporting its
1756// complete before it is really complete.
1757//                if (!mNetTrackers[checkType].isAvailable()) continue;
1758
1759//                if (currentPriority >= mNetConfigs[checkType].mPriority) continue;
1760
1761                NetworkStateTracker checkTracker = mNetTrackers[checkType];
1762                NetworkInfo checkInfo = checkTracker.getNetworkInfo();
1763                if (!checkInfo.isConnectedOrConnecting() || checkTracker.isTeardownRequested()) {
1764                    checkInfo.setFailover(true);
1765                    checkTracker.reconnect();
1766                }
1767                if (DBG) log("Attempting to switch to " + checkInfo.getTypeName());
1768            }
1769        }
1770    }
1771
1772    private void sendConnectedBroadcast(NetworkInfo info) {
1773        sendGeneralBroadcast(info, CONNECTIVITY_ACTION_IMMEDIATE);
1774        sendGeneralBroadcast(info, CONNECTIVITY_ACTION);
1775    }
1776
1777    private void sendConnectedBroadcastDelayed(NetworkInfo info, int delayMs) {
1778        sendGeneralBroadcast(info, CONNECTIVITY_ACTION_IMMEDIATE);
1779        sendGeneralBroadcastDelayed(info, CONNECTIVITY_ACTION, delayMs);
1780    }
1781
1782    private void sendInetConditionBroadcast(NetworkInfo info) {
1783        sendGeneralBroadcast(info, ConnectivityManager.INET_CONDITION_ACTION);
1784    }
1785
1786    private Intent makeGeneralIntent(NetworkInfo info, String bcastType) {
1787        Intent intent = new Intent(bcastType);
1788        intent.putExtra(ConnectivityManager.EXTRA_NETWORK_INFO, info);
1789        intent.putExtra(ConnectivityManager.EXTRA_NETWORK_TYPE, info.getType());
1790        if (info.isFailover()) {
1791            intent.putExtra(ConnectivityManager.EXTRA_IS_FAILOVER, true);
1792            info.setFailover(false);
1793        }
1794        if (info.getReason() != null) {
1795            intent.putExtra(ConnectivityManager.EXTRA_REASON, info.getReason());
1796        }
1797        if (info.getExtraInfo() != null) {
1798            intent.putExtra(ConnectivityManager.EXTRA_EXTRA_INFO,
1799                    info.getExtraInfo());
1800        }
1801        intent.putExtra(ConnectivityManager.EXTRA_INET_CONDITION, mDefaultInetConditionPublished);
1802        return intent;
1803    }
1804
1805    private void sendGeneralBroadcast(NetworkInfo info, String bcastType) {
1806        sendStickyBroadcast(makeGeneralIntent(info, bcastType));
1807    }
1808
1809    private void sendGeneralBroadcastDelayed(NetworkInfo info, String bcastType, int delayMs) {
1810        sendStickyBroadcastDelayed(makeGeneralIntent(info, bcastType), delayMs);
1811    }
1812
1813    private void sendDataActivityBroadcast(int deviceType, boolean active) {
1814        Intent intent = new Intent(ConnectivityManager.ACTION_DATA_ACTIVITY_CHANGE);
1815        intent.putExtra(ConnectivityManager.EXTRA_DEVICE_TYPE, deviceType);
1816        intent.putExtra(ConnectivityManager.EXTRA_IS_ACTIVE, active);
1817        mContext.sendOrderedBroadcast(intent, RECEIVE_DATA_ACTIVITY_CHANGE);
1818    }
1819
1820    /**
1821     * Called when an attempt to fail over to another network has failed.
1822     * @param info the {@link NetworkInfo} for the failed network
1823     */
1824    private void handleConnectionFailure(NetworkInfo info) {
1825        mNetTrackers[info.getType()].setTeardownRequested(false);
1826
1827        String reason = info.getReason();
1828        String extraInfo = info.getExtraInfo();
1829
1830        String reasonText;
1831        if (reason == null) {
1832            reasonText = ".";
1833        } else {
1834            reasonText = " (" + reason + ").";
1835        }
1836        loge("Attempt to connect to " + info.getTypeName() + " failed" + reasonText);
1837
1838        Intent intent = new Intent(ConnectivityManager.CONNECTIVITY_ACTION);
1839        intent.putExtra(ConnectivityManager.EXTRA_NETWORK_INFO, info);
1840        intent.putExtra(ConnectivityManager.EXTRA_NETWORK_TYPE, info.getType());
1841        if (getActiveNetworkInfo() == null) {
1842            intent.putExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, true);
1843        }
1844        if (reason != null) {
1845            intent.putExtra(ConnectivityManager.EXTRA_REASON, reason);
1846        }
1847        if (extraInfo != null) {
1848            intent.putExtra(ConnectivityManager.EXTRA_EXTRA_INFO, extraInfo);
1849        }
1850        if (info.isFailover()) {
1851            intent.putExtra(ConnectivityManager.EXTRA_IS_FAILOVER, true);
1852            info.setFailover(false);
1853        }
1854
1855        if (mNetConfigs[info.getType()].isDefault()) {
1856            tryFailover(info.getType());
1857            if (mActiveDefaultNetwork != -1) {
1858                NetworkInfo switchTo = mNetTrackers[mActiveDefaultNetwork].getNetworkInfo();
1859                intent.putExtra(ConnectivityManager.EXTRA_OTHER_NETWORK_INFO, switchTo);
1860            } else {
1861                mDefaultInetConditionPublished = 0;
1862                intent.putExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, true);
1863            }
1864        }
1865
1866        intent.putExtra(ConnectivityManager.EXTRA_INET_CONDITION, mDefaultInetConditionPublished);
1867
1868        final Intent immediateIntent = new Intent(intent);
1869        immediateIntent.setAction(CONNECTIVITY_ACTION_IMMEDIATE);
1870        sendStickyBroadcast(immediateIntent);
1871        sendStickyBroadcast(intent);
1872        /*
1873         * If the failover network is already connected, then immediately send
1874         * out a followup broadcast indicating successful failover
1875         */
1876        if (mActiveDefaultNetwork != -1) {
1877            sendConnectedBroadcast(mNetTrackers[mActiveDefaultNetwork].getNetworkInfo());
1878        }
1879    }
1880
1881    private void sendStickyBroadcast(Intent intent) {
1882        synchronized(this) {
1883            if (!mSystemReady) {
1884                mInitialBroadcast = new Intent(intent);
1885            }
1886            intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
1887            if (VDBG) {
1888                log("sendStickyBroadcast: action=" + intent.getAction());
1889            }
1890
1891            mContext.sendStickyBroadcast(intent);
1892        }
1893    }
1894
1895    private void sendStickyBroadcastDelayed(Intent intent, int delayMs) {
1896        if (delayMs <= 0) {
1897            sendStickyBroadcast(intent);
1898        } else {
1899            if (VDBG) {
1900                log("sendStickyBroadcastDelayed: delayMs=" + delayMs + ", action="
1901                        + intent.getAction());
1902            }
1903            mHandler.sendMessageDelayed(mHandler.obtainMessage(
1904                    EVENT_SEND_STICKY_BROADCAST_INTENT, intent), delayMs);
1905        }
1906    }
1907
1908    void systemReady() {
1909        synchronized(this) {
1910            mSystemReady = true;
1911            if (mInitialBroadcast != null) {
1912                mContext.sendStickyBroadcast(mInitialBroadcast);
1913                mInitialBroadcast = null;
1914            }
1915        }
1916        // load the global proxy at startup
1917        mHandler.sendMessage(mHandler.obtainMessage(EVENT_APPLY_GLOBAL_HTTP_PROXY));
1918    }
1919
1920    private void handleConnect(NetworkInfo info) {
1921        final int type = info.getType();
1922
1923        setupDataActivityTracking(type);
1924
1925        // snapshot isFailover, because sendConnectedBroadcast() resets it
1926        boolean isFailover = info.isFailover();
1927        final NetworkStateTracker thisNet = mNetTrackers[type];
1928        final String thisIface = thisNet.getLinkProperties().getInterfaceName();
1929
1930        // if this is a default net and other default is running
1931        // kill the one not preferred
1932        if (mNetConfigs[type].isDefault()) {
1933            if (mActiveDefaultNetwork != -1 && mActiveDefaultNetwork != type) {
1934                if ((type != mNetworkPreference &&
1935                        mNetConfigs[mActiveDefaultNetwork].priority >
1936                        mNetConfigs[type].priority) ||
1937                        mNetworkPreference == mActiveDefaultNetwork) {
1938                        // don't accept this one
1939                        if (VDBG) {
1940                            log("Not broadcasting CONNECT_ACTION " +
1941                                "to torn down network " + info.getTypeName());
1942                        }
1943                        teardown(thisNet);
1944                        return;
1945                } else {
1946                    // tear down the other
1947                    NetworkStateTracker otherNet =
1948                            mNetTrackers[mActiveDefaultNetwork];
1949                    if (DBG) {
1950                        log("Policy requires " + otherNet.getNetworkInfo().getTypeName() +
1951                            " teardown");
1952                    }
1953                    if (!teardown(otherNet)) {
1954                        loge("Network declined teardown request");
1955                        teardown(thisNet);
1956                        return;
1957                    }
1958                }
1959            }
1960            synchronized (ConnectivityService.this) {
1961                // have a new default network, release the transition wakelock in a second
1962                // if it's held.  The second pause is to allow apps to reconnect over the
1963                // new network
1964                if (mNetTransitionWakeLock.isHeld()) {
1965                    mHandler.sendMessageDelayed(mHandler.obtainMessage(
1966                            EVENT_CLEAR_NET_TRANSITION_WAKELOCK,
1967                            mNetTransitionWakeLockSerialNumber, 0),
1968                            1000);
1969                }
1970            }
1971            mActiveDefaultNetwork = type;
1972            // this will cause us to come up initially as unconnected and switching
1973            // to connected after our normal pause unless somebody reports us as reall
1974            // disconnected
1975            mDefaultInetConditionPublished = 0;
1976            mDefaultConnectionSequence++;
1977            mInetConditionChangeInFlight = false;
1978            // Don't do this - if we never sign in stay, grey
1979            //reportNetworkCondition(mActiveDefaultNetwork, 100);
1980        }
1981        thisNet.setTeardownRequested(false);
1982        updateNetworkSettings(thisNet);
1983        handleConnectivityChange(type, false);
1984        sendConnectedBroadcastDelayed(info, getConnectivityChangeDelay());
1985
1986        // notify battery stats service about this network
1987        if (thisIface != null) {
1988            try {
1989                BatteryStatsService.getService().noteNetworkInterfaceType(thisIface, type);
1990            } catch (RemoteException e) {
1991                // ignored; service lives in system_server
1992            }
1993        }
1994    }
1995
1996    /**
1997     * Setup data activity tracking for the given network interface.
1998     *
1999     * Every {@code setupDataActivityTracking} should be paired with a
2000     * {@link removeDataActivityTracking} for cleanup.
2001     */
2002    private void setupDataActivityTracking(int type) {
2003        final NetworkStateTracker thisNet = mNetTrackers[type];
2004        final String iface = thisNet.getLinkProperties().getInterfaceName();
2005
2006        final int timeout;
2007
2008        if (ConnectivityManager.isNetworkTypeMobile(type)) {
2009            timeout = Settings.Secure.getInt(mContext.getContentResolver(),
2010                                             Settings.Secure.DATA_ACTIVITY_TIMEOUT_MOBILE,
2011                                             0);
2012            // Canonicalize mobile network type
2013            type = ConnectivityManager.TYPE_MOBILE;
2014        } else if (ConnectivityManager.TYPE_WIFI == type) {
2015            timeout = Settings.Secure.getInt(mContext.getContentResolver(),
2016                                             Settings.Secure.DATA_ACTIVITY_TIMEOUT_WIFI,
2017                                             0);
2018        } else {
2019            // do not track any other networks
2020            timeout = 0;
2021        }
2022
2023        if (timeout > 0 && iface != null) {
2024            try {
2025                mNetd.addIdleTimer(iface, timeout, Integer.toString(type));
2026            } catch (RemoteException e) {
2027            }
2028        }
2029    }
2030
2031    /**
2032     * Remove data activity tracking when network disconnects.
2033     */
2034    private void removeDataActivityTracking(int type) {
2035        final NetworkStateTracker net = mNetTrackers[type];
2036        final String iface = net.getLinkProperties().getInterfaceName();
2037
2038        if (iface != null && (ConnectivityManager.isNetworkTypeMobile(type) ||
2039                              ConnectivityManager.TYPE_WIFI == type)) {
2040            try {
2041                // the call fails silently if no idletimer setup for this interface
2042                mNetd.removeIdleTimer(iface);
2043            } catch (RemoteException e) {
2044            }
2045        }
2046    }
2047
2048    /**
2049     * After a change in the connectivity state of a network. We're mainly
2050     * concerned with making sure that the list of DNS servers is set up
2051     * according to which networks are connected, and ensuring that the
2052     * right routing table entries exist.
2053     */
2054    private void handleConnectivityChange(int netType, boolean doReset) {
2055        int resetMask = doReset ? NetworkUtils.RESET_ALL_ADDRESSES : 0;
2056
2057        /*
2058         * If a non-default network is enabled, add the host routes that
2059         * will allow it's DNS servers to be accessed.
2060         */
2061        handleDnsConfigurationChange(netType);
2062
2063        LinkProperties curLp = mCurrentLinkProperties[netType];
2064        LinkProperties newLp = null;
2065
2066        if (mNetTrackers[netType].getNetworkInfo().isConnected()) {
2067            newLp = mNetTrackers[netType].getLinkProperties();
2068            if (VDBG) {
2069                log("handleConnectivityChange: changed linkProperty[" + netType + "]:" +
2070                        " doReset=" + doReset + " resetMask=" + resetMask +
2071                        "\n   curLp=" + curLp +
2072                        "\n   newLp=" + newLp);
2073            }
2074
2075            if (curLp != null) {
2076                if (curLp.isIdenticalInterfaceName(newLp)) {
2077                    CompareResult<LinkAddress> car = curLp.compareAddresses(newLp);
2078                    if ((car.removed.size() != 0) || (car.added.size() != 0)) {
2079                        for (LinkAddress linkAddr : car.removed) {
2080                            if (linkAddr.getAddress() instanceof Inet4Address) {
2081                                resetMask |= NetworkUtils.RESET_IPV4_ADDRESSES;
2082                            }
2083                            if (linkAddr.getAddress() instanceof Inet6Address) {
2084                                resetMask |= NetworkUtils.RESET_IPV6_ADDRESSES;
2085                            }
2086                        }
2087                        if (DBG) {
2088                            log("handleConnectivityChange: addresses changed" +
2089                                    " linkProperty[" + netType + "]:" + " resetMask=" + resetMask +
2090                                    "\n   car=" + car);
2091                        }
2092                    } else {
2093                        if (DBG) {
2094                            log("handleConnectivityChange: address are the same reset per doReset" +
2095                                   " linkProperty[" + netType + "]:" +
2096                                   " resetMask=" + resetMask);
2097                        }
2098                    }
2099                } else {
2100                    resetMask = NetworkUtils.RESET_ALL_ADDRESSES;
2101                    if (DBG) {
2102                        log("handleConnectivityChange: interface not not equivalent reset both" +
2103                                " linkProperty[" + netType + "]:" +
2104                                " resetMask=" + resetMask);
2105                    }
2106                }
2107            }
2108            if (mNetConfigs[netType].isDefault()) {
2109                handleApplyDefaultProxy(newLp.getHttpProxy());
2110            }
2111        } else {
2112            if (VDBG) {
2113                log("handleConnectivityChange: changed linkProperty[" + netType + "]:" +
2114                        " doReset=" + doReset + " resetMask=" + resetMask +
2115                        "\n  curLp=" + curLp +
2116                        "\n  newLp= null");
2117            }
2118        }
2119        mCurrentLinkProperties[netType] = newLp;
2120        boolean resetDns = updateRoutes(newLp, curLp, mNetConfigs[netType].isDefault());
2121
2122        if (resetMask != 0 || resetDns) {
2123            LinkProperties linkProperties = mNetTrackers[netType].getLinkProperties();
2124            if (linkProperties != null) {
2125                String iface = linkProperties.getInterfaceName();
2126                if (TextUtils.isEmpty(iface) == false) {
2127                    if (resetMask != 0) {
2128                        if (DBG) log("resetConnections(" + iface + ", " + resetMask + ")");
2129                        NetworkUtils.resetConnections(iface, resetMask);
2130
2131                        // Tell VPN the interface is down. It is a temporary
2132                        // but effective fix to make VPN aware of the change.
2133                        if ((resetMask & NetworkUtils.RESET_IPV4_ADDRESSES) != 0) {
2134                            mVpn.interfaceStatusChanged(iface, false);
2135                        }
2136                    }
2137                    if (resetDns) {
2138                        if (VDBG) log("resetting DNS cache for " + iface);
2139                        try {
2140                            mNetd.flushInterfaceDnsCache(iface);
2141                        } catch (Exception e) {
2142                            // never crash - catch them all
2143                            if (DBG) loge("Exception resetting dns cache: " + e);
2144                        }
2145                    }
2146                }
2147            }
2148        }
2149
2150        // TODO: Temporary notifying upstread change to Tethering.
2151        //       @see bug/4455071
2152        /** Notify TetheringService if interface name has been changed. */
2153        if (TextUtils.equals(mNetTrackers[netType].getNetworkInfo().getReason(),
2154                             PhoneConstants.REASON_LINK_PROPERTIES_CHANGED)) {
2155            if (isTetheringSupported()) {
2156                mTethering.handleTetherIfaceChange();
2157            }
2158        }
2159    }
2160
2161    /**
2162     * Add and remove routes using the old properties (null if not previously connected),
2163     * new properties (null if becoming disconnected).  May even be double null, which
2164     * is a noop.
2165     * Uses isLinkDefault to determine if default routes should be set or conversely if
2166     * host routes should be set to the dns servers
2167     * returns a boolean indicating the routes changed
2168     */
2169    private boolean updateRoutes(LinkProperties newLp, LinkProperties curLp,
2170            boolean isLinkDefault) {
2171        Collection<RouteInfo> routesToAdd = null;
2172        CompareResult<InetAddress> dnsDiff = new CompareResult<InetAddress>();
2173        CompareResult<RouteInfo> routeDiff = new CompareResult<RouteInfo>();
2174        if (curLp != null) {
2175            // check for the delta between the current set and the new
2176            routeDiff = curLp.compareRoutes(newLp);
2177            dnsDiff = curLp.compareDnses(newLp);
2178        } else if (newLp != null) {
2179            routeDiff.added = newLp.getRoutes();
2180            dnsDiff.added = newLp.getDnses();
2181        }
2182
2183        boolean routesChanged = (routeDiff.removed.size() != 0 || routeDiff.added.size() != 0);
2184
2185        for (RouteInfo r : routeDiff.removed) {
2186            if (isLinkDefault || ! r.isDefaultRoute()) {
2187                removeRoute(curLp, r, TO_DEFAULT_TABLE);
2188            }
2189            if (isLinkDefault == false) {
2190                // remove from a secondary route table
2191                removeRoute(curLp, r, TO_SECONDARY_TABLE);
2192            }
2193        }
2194
2195        for (RouteInfo r :  routeDiff.added) {
2196            if (isLinkDefault || ! r.isDefaultRoute()) {
2197                addRoute(newLp, r, TO_DEFAULT_TABLE);
2198            } else {
2199                // add to a secondary route table
2200                addRoute(newLp, r, TO_SECONDARY_TABLE);
2201
2202                // many radios add a default route even when we don't want one.
2203                // remove the default route unless somebody else has asked for it
2204                String ifaceName = newLp.getInterfaceName();
2205                if (TextUtils.isEmpty(ifaceName) == false && mAddedRoutes.contains(r) == false) {
2206                    if (VDBG) log("Removing " + r + " for interface " + ifaceName);
2207                    try {
2208                        mNetd.removeRoute(ifaceName, r);
2209                    } catch (Exception e) {
2210                        // never crash - catch them all
2211                        if (DBG) loge("Exception trying to remove a route: " + e);
2212                    }
2213                }
2214            }
2215        }
2216
2217        if (!isLinkDefault) {
2218            // handle DNS routes
2219            if (routesChanged) {
2220                // routes changed - remove all old dns entries and add new
2221                if (curLp != null) {
2222                    for (InetAddress oldDns : curLp.getDnses()) {
2223                        removeRouteToAddress(curLp, oldDns);
2224                    }
2225                }
2226                if (newLp != null) {
2227                    for (InetAddress newDns : newLp.getDnses()) {
2228                        addRouteToAddress(newLp, newDns);
2229                    }
2230                }
2231            } else {
2232                // no change in routes, check for change in dns themselves
2233                for (InetAddress oldDns : dnsDiff.removed) {
2234                    removeRouteToAddress(curLp, oldDns);
2235                }
2236                for (InetAddress newDns : dnsDiff.added) {
2237                    addRouteToAddress(newLp, newDns);
2238                }
2239            }
2240        }
2241        return routesChanged;
2242    }
2243
2244
2245   /**
2246     * Reads the network specific TCP buffer sizes from SystemProperties
2247     * net.tcp.buffersize.[default|wifi|umts|edge|gprs] and set them for system
2248     * wide use
2249     */
2250   public void updateNetworkSettings(NetworkStateTracker nt) {
2251        String key = nt.getTcpBufferSizesPropName();
2252        String bufferSizes = key == null ? null : SystemProperties.get(key);
2253
2254        if (TextUtils.isEmpty(bufferSizes)) {
2255            if (VDBG) log(key + " not found in system properties. Using defaults");
2256
2257            // Setting to default values so we won't be stuck to previous values
2258            key = "net.tcp.buffersize.default";
2259            bufferSizes = SystemProperties.get(key);
2260        }
2261
2262        // Set values in kernel
2263        if (bufferSizes.length() != 0) {
2264            if (VDBG) {
2265                log("Setting TCP values: [" + bufferSizes
2266                        + "] which comes from [" + key + "]");
2267            }
2268            setBufferSize(bufferSizes);
2269        }
2270    }
2271
2272   /**
2273     * Writes TCP buffer sizes to /sys/kernel/ipv4/tcp_[r/w]mem_[min/def/max]
2274     * which maps to /proc/sys/net/ipv4/tcp_rmem and tcpwmem
2275     *
2276     * @param bufferSizes in the format of "readMin, readInitial, readMax,
2277     *        writeMin, writeInitial, writeMax"
2278     */
2279    private void setBufferSize(String bufferSizes) {
2280        try {
2281            String[] values = bufferSizes.split(",");
2282
2283            if (values.length == 6) {
2284              final String prefix = "/sys/kernel/ipv4/tcp_";
2285                FileUtils.stringToFile(prefix + "rmem_min", values[0]);
2286                FileUtils.stringToFile(prefix + "rmem_def", values[1]);
2287                FileUtils.stringToFile(prefix + "rmem_max", values[2]);
2288                FileUtils.stringToFile(prefix + "wmem_min", values[3]);
2289                FileUtils.stringToFile(prefix + "wmem_def", values[4]);
2290                FileUtils.stringToFile(prefix + "wmem_max", values[5]);
2291            } else {
2292                loge("Invalid buffersize string: " + bufferSizes);
2293            }
2294        } catch (IOException e) {
2295            loge("Can't set tcp buffer sizes:" + e);
2296        }
2297    }
2298
2299    /**
2300     * Adjust the per-process dns entries (net.dns<x>.<pid>) based
2301     * on the highest priority active net which this process requested.
2302     * If there aren't any, clear it out
2303     */
2304    private void reassessPidDns(int myPid, boolean doBump)
2305    {
2306        if (VDBG) log("reassessPidDns for pid " + myPid);
2307        for(int i : mPriorityList) {
2308            if (mNetConfigs[i].isDefault()) {
2309                continue;
2310            }
2311            NetworkStateTracker nt = mNetTrackers[i];
2312            if (nt.getNetworkInfo().isConnected() &&
2313                    !nt.isTeardownRequested()) {
2314                LinkProperties p = nt.getLinkProperties();
2315                if (p == null) continue;
2316                List pids = mNetRequestersPids[i];
2317                for (int j=0; j<pids.size(); j++) {
2318                    Integer pid = (Integer)pids.get(j);
2319                    if (pid.intValue() == myPid) {
2320                        Collection<InetAddress> dnses = p.getDnses();
2321                        writePidDns(dnses, myPid);
2322                        if (doBump) {
2323                            bumpDns();
2324                        }
2325                        return;
2326                    }
2327                }
2328           }
2329        }
2330        // nothing found - delete
2331        for (int i = 1; ; i++) {
2332            String prop = "net.dns" + i + "." + myPid;
2333            if (SystemProperties.get(prop).length() == 0) {
2334                if (doBump) {
2335                    bumpDns();
2336                }
2337                return;
2338            }
2339            SystemProperties.set(prop, "");
2340        }
2341    }
2342
2343    // return true if results in a change
2344    private boolean writePidDns(Collection <InetAddress> dnses, int pid) {
2345        int j = 1;
2346        boolean changed = false;
2347        for (InetAddress dns : dnses) {
2348            String dnsString = dns.getHostAddress();
2349            if (changed || !dnsString.equals(SystemProperties.get("net.dns" + j + "." + pid))) {
2350                changed = true;
2351                SystemProperties.set("net.dns" + j + "." + pid, dns.getHostAddress());
2352            }
2353            j++;
2354        }
2355        return changed;
2356    }
2357
2358    private void bumpDns() {
2359        /*
2360         * Bump the property that tells the name resolver library to reread
2361         * the DNS server list from the properties.
2362         */
2363        String propVal = SystemProperties.get("net.dnschange");
2364        int n = 0;
2365        if (propVal.length() != 0) {
2366            try {
2367                n = Integer.parseInt(propVal);
2368            } catch (NumberFormatException e) {}
2369        }
2370        SystemProperties.set("net.dnschange", "" + (n+1));
2371        /*
2372         * Tell the VMs to toss their DNS caches
2373         */
2374        Intent intent = new Intent(Intent.ACTION_CLEAR_DNS_CACHE);
2375        intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
2376        /*
2377         * Connectivity events can happen before boot has completed ...
2378         */
2379        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
2380        mContext.sendBroadcast(intent);
2381    }
2382
2383    // Caller must grab mDnsLock.
2384    private boolean updateDns(String network, String iface,
2385            Collection<InetAddress> dnses, String domains) {
2386        boolean changed = false;
2387        int last = 0;
2388        if (dnses.size() == 0 && mDefaultDns != null) {
2389            ++last;
2390            String value = mDefaultDns.getHostAddress();
2391            if (!value.equals(SystemProperties.get("net.dns1"))) {
2392                if (DBG) {
2393                    loge("no dns provided for " + network + " - using " + value);
2394                }
2395                changed = true;
2396                SystemProperties.set("net.dns1", value);
2397            }
2398        } else {
2399            for (InetAddress dns : dnses) {
2400                ++last;
2401                String key = "net.dns" + last;
2402                String value = dns.getHostAddress();
2403                if (!changed && value.equals(SystemProperties.get(key))) {
2404                    continue;
2405                }
2406                if (VDBG) {
2407                    log("adding dns " + value + " for " + network);
2408                }
2409                changed = true;
2410                SystemProperties.set(key, value);
2411            }
2412        }
2413        for (int i = last + 1; i <= mNumDnsEntries; ++i) {
2414            String key = "net.dns" + i;
2415            if (VDBG) log("erasing " + key);
2416            changed = true;
2417            SystemProperties.set(key, "");
2418        }
2419        mNumDnsEntries = last;
2420
2421        if (changed) {
2422            try {
2423                mNetd.setDnsServersForInterface(iface, NetworkUtils.makeStrings(dnses));
2424                mNetd.setDefaultInterfaceForDns(iface);
2425            } catch (Exception e) {
2426                if (DBG) loge("exception setting default dns interface: " + e);
2427            }
2428        }
2429        if (!domains.equals(SystemProperties.get("net.dns.search"))) {
2430            SystemProperties.set("net.dns.search", domains);
2431            changed = true;
2432        }
2433        return changed;
2434    }
2435
2436    private void handleDnsConfigurationChange(int netType) {
2437        // add default net's dns entries
2438        NetworkStateTracker nt = mNetTrackers[netType];
2439        if (nt != null && nt.getNetworkInfo().isConnected() && !nt.isTeardownRequested()) {
2440            LinkProperties p = nt.getLinkProperties();
2441            if (p == null) return;
2442            Collection<InetAddress> dnses = p.getDnses();
2443            boolean changed = false;
2444            if (mNetConfigs[netType].isDefault()) {
2445                String network = nt.getNetworkInfo().getTypeName();
2446                synchronized (mDnsLock) {
2447                    if (!mDnsOverridden) {
2448                        changed = updateDns(network, p.getInterfaceName(), dnses, "");
2449                    }
2450                }
2451            } else {
2452                try {
2453                    mNetd.setDnsServersForInterface(p.getInterfaceName(),
2454                            NetworkUtils.makeStrings(dnses));
2455                } catch (Exception e) {
2456                    if (DBG) loge("exception setting dns servers: " + e);
2457                }
2458                // set per-pid dns for attached secondary nets
2459                List pids = mNetRequestersPids[netType];
2460                for (int y=0; y< pids.size(); y++) {
2461                    Integer pid = (Integer)pids.get(y);
2462                    changed = writePidDns(dnses, pid.intValue());
2463                }
2464            }
2465            if (changed) bumpDns();
2466        }
2467    }
2468
2469    private int getRestoreDefaultNetworkDelay(int networkType) {
2470        String restoreDefaultNetworkDelayStr = SystemProperties.get(
2471                NETWORK_RESTORE_DELAY_PROP_NAME);
2472        if(restoreDefaultNetworkDelayStr != null &&
2473                restoreDefaultNetworkDelayStr.length() != 0) {
2474            try {
2475                return Integer.valueOf(restoreDefaultNetworkDelayStr);
2476            } catch (NumberFormatException e) {
2477            }
2478        }
2479        // if the system property isn't set, use the value for the apn type
2480        int ret = RESTORE_DEFAULT_NETWORK_DELAY;
2481
2482        if ((networkType <= ConnectivityManager.MAX_NETWORK_TYPE) &&
2483                (mNetConfigs[networkType] != null)) {
2484            ret = mNetConfigs[networkType].restoreTime;
2485        }
2486        return ret;
2487    }
2488
2489    @Override
2490    protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
2491        if (mContext.checkCallingOrSelfPermission(
2492                android.Manifest.permission.DUMP)
2493                != PackageManager.PERMISSION_GRANTED) {
2494            pw.println("Permission Denial: can't dump ConnectivityService " +
2495                    "from from pid=" + Binder.getCallingPid() + ", uid=" +
2496                    Binder.getCallingUid());
2497            return;
2498        }
2499        pw.println();
2500        for (NetworkStateTracker nst : mNetTrackers) {
2501            if (nst != null) {
2502                if (nst.getNetworkInfo().isConnected()) {
2503                    pw.println("Active network: " + nst.getNetworkInfo().
2504                            getTypeName());
2505                }
2506                pw.println(nst.getNetworkInfo());
2507                pw.println(nst);
2508                pw.println();
2509            }
2510        }
2511
2512        pw.println("Network Requester Pids:");
2513        for (int net : mPriorityList) {
2514            String pidString = net + ": ";
2515            for (Object pid : mNetRequestersPids[net]) {
2516                pidString = pidString + pid.toString() + ", ";
2517            }
2518            pw.println(pidString);
2519        }
2520        pw.println();
2521
2522        pw.println("FeatureUsers:");
2523        for (Object requester : mFeatureUsers) {
2524            pw.println(requester.toString());
2525        }
2526        pw.println();
2527
2528        synchronized (this) {
2529            pw.println("NetworkTranstionWakeLock is currently " +
2530                    (mNetTransitionWakeLock.isHeld() ? "" : "not ") + "held.");
2531            pw.println("It was last requested for "+mNetTransitionWakeLockCausedBy);
2532        }
2533        pw.println();
2534
2535        mTethering.dump(fd, pw, args);
2536
2537        if (mInetLog != null) {
2538            pw.println();
2539            pw.println("Inet condition reports:");
2540            for(int i = 0; i < mInetLog.size(); i++) {
2541                pw.println(mInetLog.get(i));
2542            }
2543        }
2544    }
2545
2546    // must be stateless - things change under us.
2547    private class NetworkStateTrackerHandler extends Handler {
2548        public NetworkStateTrackerHandler(Looper looper) {
2549            super(looper);
2550        }
2551
2552        @Override
2553        public void handleMessage(Message msg) {
2554            NetworkInfo info;
2555            switch (msg.what) {
2556                case NetworkStateTracker.EVENT_STATE_CHANGED:
2557                    info = (NetworkInfo) msg.obj;
2558                    int type = info.getType();
2559                    NetworkInfo.State state = info.getState();
2560
2561                    if (VDBG || (state == NetworkInfo.State.CONNECTED) ||
2562                            (state == NetworkInfo.State.DISCONNECTED)) {
2563                        log("ConnectivityChange for " +
2564                            info.getTypeName() + ": " +
2565                            state + "/" + info.getDetailedState());
2566                    }
2567
2568                    // Connectivity state changed:
2569                    // [31-14] Reserved for future use
2570                    // [13-10] Network subtype (for mobile network, as defined
2571                    //         by TelephonyManager)
2572                    // [9-4] Detailed state ordinal (as defined by
2573                    //         NetworkInfo.DetailedState)
2574                    // [3-0] Network type (as defined by ConnectivityManager)
2575                    int eventLogParam = (info.getType() & 0xf) |
2576                            ((info.getDetailedState().ordinal() & 0x3f) << 4) |
2577                            (info.getSubtype() << 10);
2578                    EventLog.writeEvent(EventLogTags.CONNECTIVITY_STATE_CHANGED,
2579                            eventLogParam);
2580
2581                    if (info.getDetailedState() ==
2582                            NetworkInfo.DetailedState.FAILED) {
2583                        handleConnectionFailure(info);
2584                    } else if (state == NetworkInfo.State.DISCONNECTED) {
2585                        handleDisconnect(info);
2586                    } else if (state == NetworkInfo.State.SUSPENDED) {
2587                        // TODO: need to think this over.
2588                        // the logic here is, handle SUSPENDED the same as
2589                        // DISCONNECTED. The only difference being we are
2590                        // broadcasting an intent with NetworkInfo that's
2591                        // suspended. This allows the applications an
2592                        // opportunity to handle DISCONNECTED and SUSPENDED
2593                        // differently, or not.
2594                        handleDisconnect(info);
2595                    } else if (state == NetworkInfo.State.CONNECTED) {
2596                        handleConnect(info);
2597                    }
2598                    break;
2599                case NetworkStateTracker.EVENT_CONFIGURATION_CHANGED:
2600                    info = (NetworkInfo) msg.obj;
2601                    // TODO: Temporary allowing network configuration
2602                    //       change not resetting sockets.
2603                    //       @see bug/4455071
2604                    handleConnectivityChange(info.getType(), false);
2605                    break;
2606                case NetworkStateTracker.EVENT_NETWORK_SUBTYPE_CHANGED:
2607                    info = (NetworkInfo) msg.obj;
2608                    type = info.getType();
2609                    updateNetworkSettings(mNetTrackers[type]);
2610                    break;
2611            }
2612        }
2613    }
2614
2615    private class InternalHandler extends Handler {
2616        public InternalHandler(Looper looper) {
2617            super(looper);
2618        }
2619
2620        @Override
2621        public void handleMessage(Message msg) {
2622            NetworkInfo info;
2623            switch (msg.what) {
2624                case EVENT_CLEAR_NET_TRANSITION_WAKELOCK:
2625                    String causedBy = null;
2626                    synchronized (ConnectivityService.this) {
2627                        if (msg.arg1 == mNetTransitionWakeLockSerialNumber &&
2628                                mNetTransitionWakeLock.isHeld()) {
2629                            mNetTransitionWakeLock.release();
2630                            causedBy = mNetTransitionWakeLockCausedBy;
2631                        }
2632                    }
2633                    if (causedBy != null) {
2634                        log("NetTransition Wakelock for " + causedBy + " released by timeout");
2635                    }
2636                    break;
2637                case EVENT_RESTORE_DEFAULT_NETWORK:
2638                    FeatureUser u = (FeatureUser)msg.obj;
2639                    u.expire();
2640                    break;
2641                case EVENT_INET_CONDITION_CHANGE:
2642                {
2643                    int netType = msg.arg1;
2644                    int condition = msg.arg2;
2645                    handleInetConditionChange(netType, condition);
2646                    break;
2647                }
2648                case EVENT_INET_CONDITION_HOLD_END:
2649                {
2650                    int netType = msg.arg1;
2651                    int sequence = msg.arg2;
2652                    handleInetConditionHoldEnd(netType, sequence);
2653                    break;
2654                }
2655                case EVENT_SET_NETWORK_PREFERENCE:
2656                {
2657                    int preference = msg.arg1;
2658                    handleSetNetworkPreference(preference);
2659                    break;
2660                }
2661                case EVENT_SET_MOBILE_DATA:
2662                {
2663                    boolean enabled = (msg.arg1 == ENABLED);
2664                    handleSetMobileData(enabled);
2665                    break;
2666                }
2667                case EVENT_APPLY_GLOBAL_HTTP_PROXY:
2668                {
2669                    handleDeprecatedGlobalHttpProxy();
2670                    break;
2671                }
2672                case EVENT_SET_DEPENDENCY_MET:
2673                {
2674                    boolean met = (msg.arg1 == ENABLED);
2675                    handleSetDependencyMet(msg.arg2, met);
2676                    break;
2677                }
2678                case EVENT_RESTORE_DNS:
2679                {
2680                    if (mActiveDefaultNetwork != -1) {
2681                        handleDnsConfigurationChange(mActiveDefaultNetwork);
2682                    }
2683                    break;
2684                }
2685                case EVENT_SEND_STICKY_BROADCAST_INTENT:
2686                {
2687                    Intent intent = (Intent)msg.obj;
2688                    sendStickyBroadcast(intent);
2689                    break;
2690                }
2691                case EVENT_SET_POLICY_DATA_ENABLE: {
2692                    final int networkType = msg.arg1;
2693                    final boolean enabled = msg.arg2 == ENABLED;
2694                    handleSetPolicyDataEnable(networkType, enabled);
2695                }
2696            }
2697        }
2698    }
2699
2700    // javadoc from interface
2701    public int tether(String iface) {
2702        enforceTetherChangePermission();
2703
2704        if (isTetheringSupported()) {
2705            return mTethering.tether(iface);
2706        } else {
2707            return ConnectivityManager.TETHER_ERROR_UNSUPPORTED;
2708        }
2709    }
2710
2711    // javadoc from interface
2712    public int untether(String iface) {
2713        enforceTetherChangePermission();
2714
2715        if (isTetheringSupported()) {
2716            return mTethering.untether(iface);
2717        } else {
2718            return ConnectivityManager.TETHER_ERROR_UNSUPPORTED;
2719        }
2720    }
2721
2722    // javadoc from interface
2723    public int getLastTetherError(String iface) {
2724        enforceTetherAccessPermission();
2725
2726        if (isTetheringSupported()) {
2727            return mTethering.getLastTetherError(iface);
2728        } else {
2729            return ConnectivityManager.TETHER_ERROR_UNSUPPORTED;
2730        }
2731    }
2732
2733    // TODO - proper iface API for selection by property, inspection, etc
2734    public String[] getTetherableUsbRegexs() {
2735        enforceTetherAccessPermission();
2736        if (isTetheringSupported()) {
2737            return mTethering.getTetherableUsbRegexs();
2738        } else {
2739            return new String[0];
2740        }
2741    }
2742
2743    public String[] getTetherableWifiRegexs() {
2744        enforceTetherAccessPermission();
2745        if (isTetheringSupported()) {
2746            return mTethering.getTetherableWifiRegexs();
2747        } else {
2748            return new String[0];
2749        }
2750    }
2751
2752    public String[] getTetherableBluetoothRegexs() {
2753        enforceTetherAccessPermission();
2754        if (isTetheringSupported()) {
2755            return mTethering.getTetherableBluetoothRegexs();
2756        } else {
2757            return new String[0];
2758        }
2759    }
2760
2761    public int setUsbTethering(boolean enable) {
2762        enforceTetherAccessPermission();
2763        if (isTetheringSupported()) {
2764            return mTethering.setUsbTethering(enable);
2765        } else {
2766            return ConnectivityManager.TETHER_ERROR_UNSUPPORTED;
2767        }
2768    }
2769
2770    // TODO - move iface listing, queries, etc to new module
2771    // javadoc from interface
2772    public String[] getTetherableIfaces() {
2773        enforceTetherAccessPermission();
2774        return mTethering.getTetherableIfaces();
2775    }
2776
2777    public String[] getTetheredIfaces() {
2778        enforceTetherAccessPermission();
2779        return mTethering.getTetheredIfaces();
2780    }
2781
2782    @Override
2783    public String[] getTetheredIfacePairs() {
2784        enforceTetherAccessPermission();
2785        return mTethering.getTetheredIfacePairs();
2786    }
2787
2788    public String[] getTetheringErroredIfaces() {
2789        enforceTetherAccessPermission();
2790        return mTethering.getErroredIfaces();
2791    }
2792
2793    // if ro.tether.denied = true we default to no tethering
2794    // gservices could set the secure setting to 1 though to enable it on a build where it
2795    // had previously been turned off.
2796    public boolean isTetheringSupported() {
2797        enforceTetherAccessPermission();
2798        int defaultVal = (SystemProperties.get("ro.tether.denied").equals("true") ? 0 : 1);
2799        boolean tetherEnabledInSettings = (Settings.Secure.getInt(mContext.getContentResolver(),
2800                Settings.Secure.TETHER_SUPPORTED, defaultVal) != 0);
2801        return tetherEnabledInSettings && mTetheringConfigValid;
2802    }
2803
2804    // An API NetworkStateTrackers can call when they lose their network.
2805    // This will automatically be cleared after X seconds or a network becomes CONNECTED,
2806    // whichever happens first.  The timer is started by the first caller and not
2807    // restarted by subsequent callers.
2808    public void requestNetworkTransitionWakelock(String forWhom) {
2809        enforceConnectivityInternalPermission();
2810        synchronized (this) {
2811            if (mNetTransitionWakeLock.isHeld()) return;
2812            mNetTransitionWakeLockSerialNumber++;
2813            mNetTransitionWakeLock.acquire();
2814            mNetTransitionWakeLockCausedBy = forWhom;
2815        }
2816        mHandler.sendMessageDelayed(mHandler.obtainMessage(
2817                EVENT_CLEAR_NET_TRANSITION_WAKELOCK,
2818                mNetTransitionWakeLockSerialNumber, 0),
2819                mNetTransitionWakeLockTimeout);
2820        return;
2821    }
2822
2823    // 100 percent is full good, 0 is full bad.
2824    public void reportInetCondition(int networkType, int percentage) {
2825        if (VDBG) log("reportNetworkCondition(" + networkType + ", " + percentage + ")");
2826        mContext.enforceCallingOrSelfPermission(
2827                android.Manifest.permission.STATUS_BAR,
2828                "ConnectivityService");
2829
2830        if (DBG) {
2831            int pid = getCallingPid();
2832            int uid = getCallingUid();
2833            String s = pid + "(" + uid + ") reports inet is " +
2834                (percentage > 50 ? "connected" : "disconnected") + " (" + percentage + ") on " +
2835                "network Type " + networkType + " at " + GregorianCalendar.getInstance().getTime();
2836            mInetLog.add(s);
2837            while(mInetLog.size() > INET_CONDITION_LOG_MAX_SIZE) {
2838                mInetLog.remove(0);
2839            }
2840        }
2841        mHandler.sendMessage(mHandler.obtainMessage(
2842            EVENT_INET_CONDITION_CHANGE, networkType, percentage));
2843    }
2844
2845    private void handleInetConditionChange(int netType, int condition) {
2846        if (mActiveDefaultNetwork == -1) {
2847            if (DBG) log("handleInetConditionChange: no active default network - ignore");
2848            return;
2849        }
2850        if (mActiveDefaultNetwork != netType) {
2851            if (DBG) log("handleInetConditionChange: net=" + netType +
2852                            " != default=" + mActiveDefaultNetwork + " - ignore");
2853            return;
2854        }
2855        if (VDBG) {
2856            log("handleInetConditionChange: net=" +
2857                    netType + ", condition=" + condition +
2858                    ",mActiveDefaultNetwork=" + mActiveDefaultNetwork);
2859        }
2860        mDefaultInetCondition = condition;
2861        int delay;
2862        if (mInetConditionChangeInFlight == false) {
2863            if (VDBG) log("handleInetConditionChange: starting a change hold");
2864            // setup a new hold to debounce this
2865            if (mDefaultInetCondition > 50) {
2866                delay = Settings.Secure.getInt(mContext.getContentResolver(),
2867                        Settings.Secure.INET_CONDITION_DEBOUNCE_UP_DELAY, 500);
2868            } else {
2869                delay = Settings.Secure.getInt(mContext.getContentResolver(),
2870                Settings.Secure.INET_CONDITION_DEBOUNCE_DOWN_DELAY, 3000);
2871            }
2872            mInetConditionChangeInFlight = true;
2873            mHandler.sendMessageDelayed(mHandler.obtainMessage(EVENT_INET_CONDITION_HOLD_END,
2874                    mActiveDefaultNetwork, mDefaultConnectionSequence), delay);
2875        } else {
2876            // we've set the new condition, when this hold ends that will get picked up
2877            if (VDBG) log("handleInetConditionChange: currently in hold - not setting new end evt");
2878        }
2879    }
2880
2881    private void handleInetConditionHoldEnd(int netType, int sequence) {
2882        if (DBG) {
2883            log("handleInetConditionHoldEnd: net=" + netType +
2884                    ", condition=" + mDefaultInetCondition +
2885                    ", published condition=" + mDefaultInetConditionPublished);
2886        }
2887        mInetConditionChangeInFlight = false;
2888
2889        if (mActiveDefaultNetwork == -1) {
2890            if (DBG) log("handleInetConditionHoldEnd: no active default network - ignoring");
2891            return;
2892        }
2893        if (mDefaultConnectionSequence != sequence) {
2894            if (DBG) log("handleInetConditionHoldEnd: event hold for obsolete network - ignoring");
2895            return;
2896        }
2897        // TODO: Figure out why this optimization sometimes causes a
2898        //       change in mDefaultInetCondition to be missed and the
2899        //       UI to not be updated.
2900        //if (mDefaultInetConditionPublished == mDefaultInetCondition) {
2901        //    if (DBG) log("no change in condition - aborting");
2902        //    return;
2903        //}
2904        NetworkInfo networkInfo = mNetTrackers[mActiveDefaultNetwork].getNetworkInfo();
2905        if (networkInfo.isConnected() == false) {
2906            if (DBG) log("handleInetConditionHoldEnd: default network not connected - ignoring");
2907            return;
2908        }
2909        mDefaultInetConditionPublished = mDefaultInetCondition;
2910        sendInetConditionBroadcast(networkInfo);
2911        return;
2912    }
2913
2914    public ProxyProperties getProxy() {
2915        synchronized (mDefaultProxyLock) {
2916            return mDefaultProxyDisabled ? null : mDefaultProxy;
2917        }
2918    }
2919
2920    public void setGlobalProxy(ProxyProperties proxyProperties) {
2921        enforceChangePermission();
2922        synchronized (mGlobalProxyLock) {
2923            if (proxyProperties == mGlobalProxy) return;
2924            if (proxyProperties != null && proxyProperties.equals(mGlobalProxy)) return;
2925            if (mGlobalProxy != null && mGlobalProxy.equals(proxyProperties)) return;
2926
2927            String host = "";
2928            int port = 0;
2929            String exclList = "";
2930            if (proxyProperties != null && !TextUtils.isEmpty(proxyProperties.getHost())) {
2931                mGlobalProxy = new ProxyProperties(proxyProperties);
2932                host = mGlobalProxy.getHost();
2933                port = mGlobalProxy.getPort();
2934                exclList = mGlobalProxy.getExclusionList();
2935            } else {
2936                mGlobalProxy = null;
2937            }
2938            ContentResolver res = mContext.getContentResolver();
2939            Settings.Secure.putString(res, Settings.Secure.GLOBAL_HTTP_PROXY_HOST, host);
2940            Settings.Secure.putInt(res, Settings.Secure.GLOBAL_HTTP_PROXY_PORT, port);
2941            Settings.Secure.putString(res, Settings.Secure.GLOBAL_HTTP_PROXY_EXCLUSION_LIST,
2942                    exclList);
2943        }
2944
2945        if (mGlobalProxy == null) {
2946            proxyProperties = mDefaultProxy;
2947        }
2948        //sendProxyBroadcast(proxyProperties);
2949    }
2950
2951    private void loadGlobalProxy() {
2952        ContentResolver res = mContext.getContentResolver();
2953        String host = Settings.Secure.getString(res, Settings.Secure.GLOBAL_HTTP_PROXY_HOST);
2954        int port = Settings.Secure.getInt(res, Settings.Secure.GLOBAL_HTTP_PROXY_PORT, 0);
2955        String exclList = Settings.Secure.getString(res,
2956                Settings.Secure.GLOBAL_HTTP_PROXY_EXCLUSION_LIST);
2957        if (!TextUtils.isEmpty(host)) {
2958            ProxyProperties proxyProperties = new ProxyProperties(host, port, exclList);
2959            synchronized (mGlobalProxyLock) {
2960                mGlobalProxy = proxyProperties;
2961            }
2962        }
2963    }
2964
2965    public ProxyProperties getGlobalProxy() {
2966        synchronized (mGlobalProxyLock) {
2967            return mGlobalProxy;
2968        }
2969    }
2970
2971    private void handleApplyDefaultProxy(ProxyProperties proxy) {
2972        if (proxy != null && TextUtils.isEmpty(proxy.getHost())) {
2973            proxy = null;
2974        }
2975        synchronized (mDefaultProxyLock) {
2976            if (mDefaultProxy != null && mDefaultProxy.equals(proxy)) return;
2977            if (mDefaultProxy == proxy) return;
2978            mDefaultProxy = proxy;
2979
2980            if (!mDefaultProxyDisabled) {
2981                sendProxyBroadcast(proxy);
2982            }
2983        }
2984    }
2985
2986    private void handleDeprecatedGlobalHttpProxy() {
2987        String proxy = Settings.Secure.getString(mContext.getContentResolver(),
2988                Settings.Secure.HTTP_PROXY);
2989        if (!TextUtils.isEmpty(proxy)) {
2990            String data[] = proxy.split(":");
2991            String proxyHost =  data[0];
2992            int proxyPort = 8080;
2993            if (data.length > 1) {
2994                try {
2995                    proxyPort = Integer.parseInt(data[1]);
2996                } catch (NumberFormatException e) {
2997                    return;
2998                }
2999            }
3000            ProxyProperties p = new ProxyProperties(data[0], proxyPort, "");
3001            setGlobalProxy(p);
3002        }
3003    }
3004
3005    private void sendProxyBroadcast(ProxyProperties proxy) {
3006        if (proxy == null) proxy = new ProxyProperties("", 0, "");
3007        if (DBG) log("sending Proxy Broadcast for " + proxy);
3008        Intent intent = new Intent(Proxy.PROXY_CHANGE_ACTION);
3009        intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING |
3010            Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
3011        intent.putExtra(Proxy.EXTRA_PROXY_INFO, proxy);
3012        mContext.sendStickyBroadcast(intent);
3013    }
3014
3015    private static class SettingsObserver extends ContentObserver {
3016        private int mWhat;
3017        private Handler mHandler;
3018        SettingsObserver(Handler handler, int what) {
3019            super(handler);
3020            mHandler = handler;
3021            mWhat = what;
3022        }
3023
3024        void observe(Context context) {
3025            ContentResolver resolver = context.getContentResolver();
3026            resolver.registerContentObserver(Settings.Secure.getUriFor(
3027                    Settings.Secure.HTTP_PROXY), false, this);
3028        }
3029
3030        @Override
3031        public void onChange(boolean selfChange) {
3032            mHandler.obtainMessage(mWhat).sendToTarget();
3033        }
3034    }
3035
3036    private static void log(String s) {
3037        Slog.d(TAG, s);
3038    }
3039
3040    private static void loge(String s) {
3041        Slog.e(TAG, s);
3042    }
3043
3044    int convertFeatureToNetworkType(int networkType, String feature) {
3045        int usedNetworkType = networkType;
3046
3047        if(networkType == ConnectivityManager.TYPE_MOBILE) {
3048            if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_MMS)) {
3049                usedNetworkType = ConnectivityManager.TYPE_MOBILE_MMS;
3050            } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_SUPL)) {
3051                usedNetworkType = ConnectivityManager.TYPE_MOBILE_SUPL;
3052            } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_DUN) ||
3053                    TextUtils.equals(feature, Phone.FEATURE_ENABLE_DUN_ALWAYS)) {
3054                usedNetworkType = ConnectivityManager.TYPE_MOBILE_DUN;
3055            } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_HIPRI)) {
3056                usedNetworkType = ConnectivityManager.TYPE_MOBILE_HIPRI;
3057            } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_FOTA)) {
3058                usedNetworkType = ConnectivityManager.TYPE_MOBILE_FOTA;
3059            } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_IMS)) {
3060                usedNetworkType = ConnectivityManager.TYPE_MOBILE_IMS;
3061            } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_CBS)) {
3062                usedNetworkType = ConnectivityManager.TYPE_MOBILE_CBS;
3063            } else {
3064                Slog.e(TAG, "Can't match any mobile netTracker!");
3065            }
3066        } else if (networkType == ConnectivityManager.TYPE_WIFI) {
3067            if (TextUtils.equals(feature, "p2p")) {
3068                usedNetworkType = ConnectivityManager.TYPE_WIFI_P2P;
3069            } else {
3070                Slog.e(TAG, "Can't match any wifi netTracker!");
3071            }
3072        } else {
3073            Slog.e(TAG, "Unexpected network type");
3074        }
3075        return usedNetworkType;
3076    }
3077
3078    private static <T> T checkNotNull(T value, String message) {
3079        if (value == null) {
3080            throw new NullPointerException(message);
3081        }
3082        return value;
3083    }
3084
3085    /**
3086     * Protect a socket from VPN routing rules. This method is used by
3087     * VpnBuilder and not available in ConnectivityManager. Permissions
3088     * are checked in Vpn class.
3089     * @hide
3090     */
3091    @Override
3092    public boolean protectVpn(ParcelFileDescriptor socket) {
3093        try {
3094            int type = mActiveDefaultNetwork;
3095            if (ConnectivityManager.isNetworkTypeValid(type)) {
3096                mVpn.protect(socket, mNetTrackers[type].getLinkProperties().getInterfaceName());
3097                return true;
3098            }
3099        } catch (Exception e) {
3100            // ignore
3101        } finally {
3102            try {
3103                socket.close();
3104            } catch (Exception e) {
3105                // ignore
3106            }
3107        }
3108        return false;
3109    }
3110
3111    /**
3112     * Prepare for a VPN application. This method is used by VpnDialogs
3113     * and not available in ConnectivityManager. Permissions are checked
3114     * in Vpn class.
3115     * @hide
3116     */
3117    @Override
3118    public boolean prepareVpn(String oldPackage, String newPackage) {
3119        return mVpn.prepare(oldPackage, newPackage);
3120    }
3121
3122    /**
3123     * Configure a TUN interface and return its file descriptor. Parameters
3124     * are encoded and opaque to this class. This method is used by VpnBuilder
3125     * and not available in ConnectivityManager. Permissions are checked in
3126     * Vpn class.
3127     * @hide
3128     */
3129    @Override
3130    public ParcelFileDescriptor establishVpn(VpnConfig config) {
3131        return mVpn.establish(config);
3132    }
3133
3134    /**
3135     * Start legacy VPN, controlling native daemons as needed. Creates a
3136     * secondary thread to perform connection work, returning quickly.
3137     */
3138    @Override
3139    public void startLegacyVpn(VpnProfile profile) {
3140        final LinkProperties egress = getActiveLinkProperties();
3141        if (egress == null) {
3142            throw new IllegalStateException("Missing active network connection");
3143        }
3144        mVpn.startLegacyVpn(profile, mKeyStore, egress);
3145    }
3146
3147    /**
3148     * Return the information of the ongoing legacy VPN. This method is used
3149     * by VpnSettings and not available in ConnectivityManager. Permissions
3150     * are checked in Vpn class.
3151     * @hide
3152     */
3153    @Override
3154    public LegacyVpnInfo getLegacyVpnInfo() {
3155        return mVpn.getLegacyVpnInfo();
3156    }
3157
3158    /**
3159     * Callback for VPN subsystem. Currently VPN is not adapted to the service
3160     * through NetworkStateTracker since it works differently. For example, it
3161     * needs to override DNS servers but never takes the default routes. It
3162     * relies on another data network, and it could keep existing connections
3163     * alive after reconnecting, switching between networks, or even resuming
3164     * from deep sleep. Calls from applications should be done synchronously
3165     * to avoid race conditions. As these are all hidden APIs, refactoring can
3166     * be done whenever a better abstraction is developed.
3167     */
3168    public class VpnCallback {
3169        private VpnCallback() {
3170        }
3171
3172        public void onStateChanged(NetworkInfo info) {
3173            // TODO: if connected, release delayed broadcast
3174            // TODO: if disconnected, consider kicking off reconnect
3175        }
3176
3177        public void override(List<String> dnsServers, List<String> searchDomains) {
3178            if (dnsServers == null) {
3179                restore();
3180                return;
3181            }
3182
3183            // Convert DNS servers into addresses.
3184            List<InetAddress> addresses = new ArrayList<InetAddress>();
3185            for (String address : dnsServers) {
3186                // Double check the addresses and remove invalid ones.
3187                try {
3188                    addresses.add(InetAddress.parseNumericAddress(address));
3189                } catch (Exception e) {
3190                    // ignore
3191                }
3192            }
3193            if (addresses.isEmpty()) {
3194                restore();
3195                return;
3196            }
3197
3198            // Concatenate search domains into a string.
3199            StringBuilder buffer = new StringBuilder();
3200            if (searchDomains != null) {
3201                for (String domain : searchDomains) {
3202                    buffer.append(domain).append(' ');
3203                }
3204            }
3205            String domains = buffer.toString().trim();
3206
3207            // Apply DNS changes.
3208            boolean changed = false;
3209            synchronized (mDnsLock) {
3210                changed = updateDns("VPN", "VPN", addresses, domains);
3211                mDnsOverridden = true;
3212            }
3213            if (changed) {
3214                bumpDns();
3215            }
3216
3217            // Temporarily disable the default proxy.
3218            synchronized (mDefaultProxyLock) {
3219                mDefaultProxyDisabled = true;
3220                if (mDefaultProxy != null) {
3221                    sendProxyBroadcast(null);
3222                }
3223            }
3224
3225            // TODO: support proxy per network.
3226        }
3227
3228        public void restore() {
3229            synchronized (mDnsLock) {
3230                if (mDnsOverridden) {
3231                    mDnsOverridden = false;
3232                    mHandler.sendEmptyMessage(EVENT_RESTORE_DNS);
3233                }
3234            }
3235            synchronized (mDefaultProxyLock) {
3236                mDefaultProxyDisabled = false;
3237                if (mDefaultProxy != null) {
3238                    sendProxyBroadcast(mDefaultProxy);
3239                }
3240            }
3241        }
3242    }
3243}
3244