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