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