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