ConnectivityService.java revision 7b00978dc739ed2213ed8e511c69cfb412798109
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.app.Notification;
20import android.app.NotificationManager;
21import android.content.ContentResolver;
22import android.content.Context;
23import android.content.Intent;
24import android.content.pm.PackageManager;
25import android.net.ConnectivityManager;
26import android.net.IConnectivityManager;
27import android.net.MobileDataStateTracker;
28import android.net.NetworkInfo;
29import android.net.NetworkStateTracker;
30import android.net.wifi.WifiStateTracker;
31import android.os.Binder;
32import android.os.Handler;
33import android.os.IBinder;
34import android.os.Looper;
35import android.os.Message;
36import android.os.RemoteException;
37import android.os.ServiceManager;
38import android.os.SystemProperties;
39import android.provider.Settings;
40import android.text.TextUtils;
41import android.util.EventLog;
42import android.util.Slog;
43
44import com.android.internal.telephony.Phone;
45
46import com.android.server.connectivity.Tethering;
47
48import java.io.FileDescriptor;
49import java.io.PrintWriter;
50import java.util.ArrayList;
51import java.util.List;
52
53/**
54 * @hide
55 */
56public class ConnectivityService extends IConnectivityManager.Stub {
57
58    private static final boolean DBG = true;
59    private static final String TAG = "ConnectivityService";
60
61    // how long to wait before switching back to a radio's default network
62    private static final int RESTORE_DEFAULT_NETWORK_DELAY = 1 * 60 * 1000;
63    // system property that can override the above value
64    private static final String NETWORK_RESTORE_DELAY_PROP_NAME =
65            "android.telephony.apn-restore";
66
67
68    private Tethering mTethering;
69    private boolean mTetheringConfigValid = false;
70
71    /**
72     * Sometimes we want to refer to the individual network state
73     * trackers separately, and sometimes we just want to treat them
74     * abstractly.
75     */
76    private NetworkStateTracker mNetTrackers[];
77
78    /**
79     * A per Net list of the PID's that requested access to the net
80     * used both as a refcount and for per-PID DNS selection
81     */
82    private List mNetRequestersPids[];
83
84    // priority order of the nettrackers
85    // (excluding dynamically set mNetworkPreference)
86    // TODO - move mNetworkTypePreference into this
87    private int[] mPriorityList;
88
89    private Context mContext;
90    private int mNetworkPreference;
91    private int mActiveDefaultNetwork = -1;
92
93    private int mNumDnsEntries;
94
95    private boolean mTestMode;
96    private static ConnectivityService sServiceInstance;
97
98    private Handler mHandler;
99
100    // list of DeathRecipients used to make sure features are turned off when
101    // a process dies
102    private List mFeatureUsers;
103
104    private boolean mSystemReady;
105    private Intent mInitialBroadcast;
106
107    private static class NetworkAttributes {
108        /**
109         * Class for holding settings read from resources.
110         */
111        public String mName;
112        public int mType;
113        public int mRadio;
114        public int mPriority;
115        public NetworkInfo.State mLastState;
116        public NetworkAttributes(String init) {
117            String fragments[] = init.split(",");
118            mName = fragments[0].toLowerCase();
119            mType = Integer.parseInt(fragments[1]);
120            mRadio = Integer.parseInt(fragments[2]);
121            mPriority = Integer.parseInt(fragments[3]);
122            mLastState = NetworkInfo.State.UNKNOWN;
123        }
124        public boolean isDefault() {
125            return (mType == mRadio);
126        }
127    }
128    NetworkAttributes[] mNetAttributes;
129    int mNetworksDefined;
130
131    private static class RadioAttributes {
132        public int mSimultaneity;
133        public int mType;
134        public RadioAttributes(String init) {
135            String fragments[] = init.split(",");
136            mType = Integer.parseInt(fragments[0]);
137            mSimultaneity = Integer.parseInt(fragments[1]);
138        }
139    }
140    RadioAttributes[] mRadioAttributes;
141
142    private static class ConnectivityThread extends Thread {
143        private Context mContext;
144
145        private ConnectivityThread(Context context) {
146            super("ConnectivityThread");
147            mContext = context;
148        }
149
150        @Override
151        public void run() {
152            Looper.prepare();
153            synchronized (this) {
154                sServiceInstance = new ConnectivityService(mContext);
155                notifyAll();
156            }
157            Looper.loop();
158        }
159
160        public static ConnectivityService getServiceInstance(Context context) {
161            ConnectivityThread thread = new ConnectivityThread(context);
162            thread.start();
163
164            synchronized (thread) {
165                while (sServiceInstance == null) {
166                    try {
167                        // Wait until sServiceInstance has been initialized.
168                        thread.wait();
169                    } catch (InterruptedException ignore) {
170                        Slog.e(TAG,
171                            "Unexpected InterruptedException while waiting"+
172                            " for ConnectivityService thread");
173                    }
174                }
175            }
176
177            return sServiceInstance;
178        }
179    }
180
181    public static ConnectivityService getInstance(Context context) {
182        return ConnectivityThread.getServiceInstance(context);
183    }
184
185    private ConnectivityService(Context context) {
186        if (DBG) Slog.v(TAG, "ConnectivityService starting up");
187
188        // setup our unique device name
189        String id = Settings.Secure.getString(context.getContentResolver(),
190                Settings.Secure.ANDROID_ID);
191        if (id != null && id.length() > 0) {
192            String name = new String("android_").concat(id);
193            SystemProperties.set("net.hostname", name);
194        }
195
196        mContext = context;
197        mNetTrackers = new NetworkStateTracker[
198                ConnectivityManager.MAX_NETWORK_TYPE+1];
199        mHandler = new MyHandler();
200
201        mNetworkPreference = getPersistedNetworkPreference();
202
203        mRadioAttributes = new RadioAttributes[ConnectivityManager.MAX_RADIO_TYPE+1];
204        mNetAttributes = new NetworkAttributes[ConnectivityManager.MAX_NETWORK_TYPE+1];
205
206        // Load device network attributes from resources
207        String[] raStrings = context.getResources().getStringArray(
208                com.android.internal.R.array.radioAttributes);
209        for (String raString : raStrings) {
210            RadioAttributes r = new RadioAttributes(raString);
211            if (r.mType > ConnectivityManager.MAX_RADIO_TYPE) {
212                Slog.e(TAG, "Error in radioAttributes - ignoring attempt to define type " + r.mType);
213                continue;
214            }
215            if (mRadioAttributes[r.mType] != null) {
216                Slog.e(TAG, "Error in radioAttributes - ignoring attempt to redefine type " +
217                        r.mType);
218                continue;
219            }
220            mRadioAttributes[r.mType] = r;
221        }
222
223        String[] naStrings = context.getResources().getStringArray(
224                com.android.internal.R.array.networkAttributes);
225        for (String naString : naStrings) {
226            try {
227                NetworkAttributes n = new NetworkAttributes(naString);
228                if (n.mType > ConnectivityManager.MAX_NETWORK_TYPE) {
229                    Slog.e(TAG, "Error in networkAttributes - ignoring attempt to define type " +
230                            n.mType);
231                    continue;
232                }
233                if (mNetAttributes[n.mType] != null) {
234                    Slog.e(TAG, "Error in networkAttributes - ignoring attempt to redefine type " +
235                            n.mType);
236                    continue;
237                }
238                if (mRadioAttributes[n.mRadio] == null) {
239                    Slog.e(TAG, "Error in networkAttributes - ignoring attempt to use undefined " +
240                            "radio " + n.mRadio + " in network type " + n.mType);
241                    continue;
242                }
243                mNetAttributes[n.mType] = n;
244                mNetworksDefined++;
245            } catch(Exception e) {
246                // ignore it - leave the entry null
247            }
248        }
249
250        // high priority first
251        mPriorityList = new int[mNetworksDefined];
252        {
253            int insertionPoint = mNetworksDefined-1;
254            int currentLowest = 0;
255            int nextLowest = 0;
256            while (insertionPoint > -1) {
257                for (NetworkAttributes na : mNetAttributes) {
258                    if (na == null) continue;
259                    if (na.mPriority < currentLowest) continue;
260                    if (na.mPriority > currentLowest) {
261                        if (na.mPriority < nextLowest || nextLowest == 0) {
262                            nextLowest = na.mPriority;
263                        }
264                        continue;
265                    }
266                    mPriorityList[insertionPoint--] = na.mType;
267                }
268                currentLowest = nextLowest;
269                nextLowest = 0;
270            }
271        }
272
273        mNetRequestersPids = new ArrayList[ConnectivityManager.MAX_NETWORK_TYPE+1];
274        for (int i : mPriorityList) {
275            mNetRequestersPids[i] = new ArrayList();
276        }
277
278        mFeatureUsers = new ArrayList();
279
280        mNumDnsEntries = 0;
281
282        mTestMode = SystemProperties.get("cm.test.mode").equals("true")
283                && SystemProperties.get("ro.build.type").equals("eng");
284        /*
285         * Create the network state trackers for Wi-Fi and mobile
286         * data. Maybe this could be done with a factory class,
287         * but it's not clear that it's worth it, given that
288         * the number of different network types is not going
289         * to change very often.
290         */
291        boolean noMobileData = !getMobileDataEnabled();
292        for (int netType : mPriorityList) {
293            switch (mNetAttributes[netType].mRadio) {
294            case ConnectivityManager.TYPE_WIFI:
295                if (DBG) Slog.v(TAG, "Starting Wifi Service.");
296                WifiStateTracker wst = new WifiStateTracker(context, mHandler);
297                WifiService wifiService = new WifiService(context, wst);
298                ServiceManager.addService(Context.WIFI_SERVICE, wifiService);
299                wifiService.startWifi();
300                mNetTrackers[ConnectivityManager.TYPE_WIFI] = wst;
301                wst.startMonitoring();
302
303                break;
304            case ConnectivityManager.TYPE_MOBILE:
305                mNetTrackers[netType] = new MobileDataStateTracker(context, mHandler,
306                    netType, mNetAttributes[netType].mName);
307                mNetTrackers[netType].startMonitoring();
308                if (noMobileData) {
309                    if (DBG) Slog.d(TAG, "tearing down Mobile networks due to setting");
310                    mNetTrackers[netType].teardown();
311                }
312                break;
313            default:
314                Slog.e(TAG, "Trying to create a DataStateTracker for an unknown radio type " +
315                        mNetAttributes[netType].mRadio);
316                continue;
317            }
318        }
319
320        mTethering = new Tethering(mContext, mHandler.getLooper());
321        mTetheringConfigValid = (((mNetTrackers[ConnectivityManager.TYPE_MOBILE_DUN] != null) ||
322                                  !mTethering.isDunRequired()) &&
323                                 (mTethering.getTetherableUsbRegexs().length != 0 ||
324                                  mTethering.getTetherableWifiRegexs().length != 0) &&
325                                 mTethering.getUpstreamIfaceRegexs().length != 0);
326
327    }
328
329
330    /**
331     * Sets the preferred network.
332     * @param preference the new preference
333     */
334    public synchronized void setNetworkPreference(int preference) {
335        enforceChangePermission();
336        if (ConnectivityManager.isNetworkTypeValid(preference) &&
337                mNetAttributes[preference] != null &&
338                mNetAttributes[preference].isDefault()) {
339            if (mNetworkPreference != preference) {
340                persistNetworkPreference(preference);
341                mNetworkPreference = preference;
342                enforcePreference();
343            }
344        }
345    }
346
347    public int getNetworkPreference() {
348        enforceAccessPermission();
349        return mNetworkPreference;
350    }
351
352    private void persistNetworkPreference(int networkPreference) {
353        final ContentResolver cr = mContext.getContentResolver();
354        Settings.Secure.putInt(cr, Settings.Secure.NETWORK_PREFERENCE,
355                networkPreference);
356    }
357
358    private int getPersistedNetworkPreference() {
359        final ContentResolver cr = mContext.getContentResolver();
360
361        final int networkPrefSetting = Settings.Secure
362                .getInt(cr, Settings.Secure.NETWORK_PREFERENCE, -1);
363        if (networkPrefSetting != -1) {
364            return networkPrefSetting;
365        }
366
367        return ConnectivityManager.DEFAULT_NETWORK_PREFERENCE;
368    }
369
370    /**
371     * Make the state of network connectivity conform to the preference settings
372     * In this method, we only tear down a non-preferred network. Establishing
373     * a connection to the preferred network is taken care of when we handle
374     * the disconnect event from the non-preferred network
375     * (see {@link #handleDisconnect(NetworkInfo)}).
376     */
377    private void enforcePreference() {
378        if (mNetTrackers[mNetworkPreference].getNetworkInfo().isConnected())
379            return;
380
381        if (!mNetTrackers[mNetworkPreference].isAvailable())
382            return;
383
384        for (int t=0; t <= ConnectivityManager.MAX_RADIO_TYPE; t++) {
385            if (t != mNetworkPreference && mNetTrackers[t] != null &&
386                    mNetTrackers[t].getNetworkInfo().isConnected()) {
387                if (DBG) {
388                    Slog.d(TAG, "tearing down " +
389                            mNetTrackers[t].getNetworkInfo() +
390                            " in enforcePreference");
391                }
392                teardown(mNetTrackers[t]);
393            }
394        }
395    }
396
397    private boolean teardown(NetworkStateTracker netTracker) {
398        if (netTracker.teardown()) {
399            netTracker.setTeardownRequested(true);
400            return true;
401        } else {
402            return false;
403        }
404    }
405
406    /**
407     * Return NetworkInfo for the active (i.e., connected) network interface.
408     * It is assumed that at most one network is active at a time. If more
409     * than one is active, it is indeterminate which will be returned.
410     * @return the info for the active network, or {@code null} if none is
411     * active
412     */
413    public NetworkInfo getActiveNetworkInfo() {
414        enforceAccessPermission();
415        for (int type=0; type <= ConnectivityManager.MAX_NETWORK_TYPE; type++) {
416            if (mNetAttributes[type] == null || !mNetAttributes[type].isDefault()) {
417                continue;
418            }
419            NetworkStateTracker t = mNetTrackers[type];
420            NetworkInfo info = t.getNetworkInfo();
421            if (info.isConnected()) {
422                if (DBG && type != mActiveDefaultNetwork) Slog.e(TAG,
423                        "connected default network is not " +
424                        "mActiveDefaultNetwork!");
425                return info;
426            }
427        }
428        return null;
429    }
430
431    public NetworkInfo getNetworkInfo(int networkType) {
432        enforceAccessPermission();
433        if (ConnectivityManager.isNetworkTypeValid(networkType)) {
434            NetworkStateTracker t = mNetTrackers[networkType];
435            if (t != null)
436                return t.getNetworkInfo();
437        }
438        return null;
439    }
440
441    public NetworkInfo[] getAllNetworkInfo() {
442        enforceAccessPermission();
443        NetworkInfo[] result = new NetworkInfo[mNetworksDefined];
444        int i = 0;
445        for (NetworkStateTracker t : mNetTrackers) {
446            if(t != null) result[i++] = t.getNetworkInfo();
447        }
448        return result;
449    }
450
451    public boolean setRadios(boolean turnOn) {
452        boolean result = true;
453        enforceChangePermission();
454        for (NetworkStateTracker t : mNetTrackers) {
455            if (t != null) result = t.setRadio(turnOn) && result;
456        }
457        return result;
458    }
459
460    public boolean setRadio(int netType, boolean turnOn) {
461        enforceChangePermission();
462        if (!ConnectivityManager.isNetworkTypeValid(netType)) {
463            return false;
464        }
465        NetworkStateTracker tracker = mNetTrackers[netType];
466        return tracker != null && tracker.setRadio(turnOn);
467    }
468
469    /**
470     * Used to notice when the calling process dies so we can self-expire
471     *
472     * Also used to know if the process has cleaned up after itself when
473     * our auto-expire timer goes off.  The timer has a link to an object.
474     *
475     */
476    private class FeatureUser implements IBinder.DeathRecipient {
477        int mNetworkType;
478        String mFeature;
479        IBinder mBinder;
480        int mPid;
481        int mUid;
482        long mCreateTime;
483
484        FeatureUser(int type, String feature, IBinder binder) {
485            super();
486            mNetworkType = type;
487            mFeature = feature;
488            mBinder = binder;
489            mPid = getCallingPid();
490            mUid = getCallingUid();
491            mCreateTime = System.currentTimeMillis();
492
493            try {
494                mBinder.linkToDeath(this, 0);
495            } catch (RemoteException e) {
496                binderDied();
497            }
498        }
499
500        void unlinkDeathRecipient() {
501            mBinder.unlinkToDeath(this, 0);
502        }
503
504        public void binderDied() {
505            Slog.d(TAG, "ConnectivityService FeatureUser binderDied(" +
506                    mNetworkType + ", " + mFeature + ", " + mBinder + "), created " +
507                    (System.currentTimeMillis() - mCreateTime) + " mSec ago");
508            stopUsingNetworkFeature(this, false);
509        }
510
511        public void expire() {
512            Slog.d(TAG, "ConnectivityService FeatureUser expire(" +
513                    mNetworkType + ", " + mFeature + ", " + mBinder +"), created " +
514                    (System.currentTimeMillis() - mCreateTime) + " mSec ago");
515            stopUsingNetworkFeature(this, false);
516        }
517
518        public String toString() {
519            return "FeatureUser("+mNetworkType+","+mFeature+","+mPid+","+mUid+"), created " +
520                    (System.currentTimeMillis() - mCreateTime) + " mSec ago";
521        }
522    }
523
524    // javadoc from interface
525    public int startUsingNetworkFeature(int networkType, String feature,
526            IBinder binder) {
527        if (DBG) {
528            Slog.d(TAG, "startUsingNetworkFeature for net " + networkType +
529                    ": " + feature);
530        }
531        enforceChangePermission();
532        if (!ConnectivityManager.isNetworkTypeValid(networkType) ||
533                mNetAttributes[networkType] == null) {
534            return Phone.APN_REQUEST_FAILED;
535        }
536
537        FeatureUser f = new FeatureUser(networkType, feature, binder);
538
539        // TODO - move this into the MobileDataStateTracker
540        int usedNetworkType = networkType;
541        if(networkType == ConnectivityManager.TYPE_MOBILE) {
542            if (!getMobileDataEnabled()) {
543                if (DBG) Slog.d(TAG, "requested special network with data disabled - rejected");
544                return Phone.APN_TYPE_NOT_AVAILABLE;
545            }
546            if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_MMS)) {
547                usedNetworkType = ConnectivityManager.TYPE_MOBILE_MMS;
548            } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_SUPL)) {
549                usedNetworkType = ConnectivityManager.TYPE_MOBILE_SUPL;
550            } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_DUN)) {
551                usedNetworkType = ConnectivityManager.TYPE_MOBILE_DUN;
552            } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_HIPRI)) {
553                usedNetworkType = ConnectivityManager.TYPE_MOBILE_HIPRI;
554            }
555        }
556        NetworkStateTracker network = mNetTrackers[usedNetworkType];
557        if (network != null) {
558            if (usedNetworkType != networkType) {
559                Integer currentPid = new Integer(getCallingPid());
560
561                NetworkStateTracker radio = mNetTrackers[networkType];
562                NetworkInfo ni = network.getNetworkInfo();
563
564                if (ni.isAvailable() == false) {
565                    if (DBG) Slog.d(TAG, "special network not available");
566                    return Phone.APN_TYPE_NOT_AVAILABLE;
567                }
568
569                synchronized(this) {
570                    mFeatureUsers.add(f);
571                    if (!mNetRequestersPids[usedNetworkType].contains(currentPid)) {
572                        // this gets used for per-pid dns when connected
573                        mNetRequestersPids[usedNetworkType].add(currentPid);
574                    }
575                }
576                mHandler.sendMessageDelayed(mHandler.obtainMessage(
577                        NetworkStateTracker.EVENT_RESTORE_DEFAULT_NETWORK,
578                        f), getRestoreDefaultNetworkDelay());
579
580
581                if ((ni.isConnectedOrConnecting() == true) &&
582                        !network.isTeardownRequested()) {
583                    if (ni.isConnected() == true) {
584                        // add the pid-specific dns
585                        handleDnsConfigurationChange();
586                        if (DBG) Slog.d(TAG, "special network already active");
587                        return Phone.APN_ALREADY_ACTIVE;
588                    }
589                    if (DBG) Slog.d(TAG, "special network already connecting");
590                    return Phone.APN_REQUEST_STARTED;
591                }
592
593                // check if the radio in play can make another contact
594                // assume if cannot for now
595
596                if (DBG) Slog.d(TAG, "reconnecting to special network");
597                network.reconnect();
598                return Phone.APN_REQUEST_STARTED;
599            } else {
600                synchronized(this) {
601                    mFeatureUsers.add(f);
602                }
603                mHandler.sendMessageDelayed(mHandler.obtainMessage(
604                        NetworkStateTracker.EVENT_RESTORE_DEFAULT_NETWORK,
605                        f), getRestoreDefaultNetworkDelay());
606
607                return network.startUsingNetworkFeature(feature,
608                        getCallingPid(), getCallingUid());
609            }
610        }
611        return Phone.APN_TYPE_NOT_AVAILABLE;
612    }
613
614    // javadoc from interface
615    public int stopUsingNetworkFeature(int networkType, String feature) {
616        enforceChangePermission();
617
618        int pid = getCallingPid();
619        int uid = getCallingUid();
620
621        FeatureUser u = null;
622        boolean found = false;
623
624        synchronized(this) {
625            for (int i = 0; i < mFeatureUsers.size() ; i++) {
626                u = (FeatureUser)mFeatureUsers.get(i);
627                if (uid == u.mUid && pid == u.mPid &&
628                        networkType == u.mNetworkType &&
629                        TextUtils.equals(feature, u.mFeature)) {
630                    found = true;
631                    break;
632                }
633            }
634        }
635        if (found && u != null) {
636            // stop regardless of how many other time this proc had called start
637            return stopUsingNetworkFeature(u, true);
638        } else {
639            // none found!
640            if (DBG) Slog.d(TAG, "ignoring stopUsingNetworkFeature - not a live request");
641            return 1;
642        }
643    }
644
645    private int stopUsingNetworkFeature(FeatureUser u, boolean ignoreDups) {
646        int networkType = u.mNetworkType;
647        String feature = u.mFeature;
648        int pid = u.mPid;
649        int uid = u.mUid;
650
651        NetworkStateTracker tracker = null;
652        boolean callTeardown = false;  // used to carry our decision outside of sync block
653
654        if (DBG) {
655            Slog.d(TAG, "stopUsingNetworkFeature for net " + networkType +
656                    ": " + feature);
657        }
658
659        if (!ConnectivityManager.isNetworkTypeValid(networkType)) {
660            return -1;
661        }
662
663        // need to link the mFeatureUsers list with the mNetRequestersPids state in this
664        // sync block
665        synchronized(this) {
666            // check if this process still has an outstanding start request
667            if (!mFeatureUsers.contains(u)) {
668                if (DBG) Slog.d(TAG, "ignoring - this process has no outstanding requests");
669                return 1;
670            }
671            u.unlinkDeathRecipient();
672            mFeatureUsers.remove(mFeatureUsers.indexOf(u));
673            // If we care about duplicate requests, check for that here.
674            //
675            // This is done to support the extension of a request - the app
676            // can request we start the network feature again and renew the
677            // auto-shutoff delay.  Normal "stop" calls from the app though
678            // do not pay attention to duplicate requests - in effect the
679            // API does not refcount and a single stop will counter multiple starts.
680            if (ignoreDups == false) {
681                for (int i = 0; i < mFeatureUsers.size() ; i++) {
682                    FeatureUser x = (FeatureUser)mFeatureUsers.get(i);
683                    if (x.mUid == u.mUid && x.mPid == u.mPid &&
684                            x.mNetworkType == u.mNetworkType &&
685                            TextUtils.equals(x.mFeature, u.mFeature)) {
686                        if (DBG) Slog.d(TAG, "ignoring stopUsingNetworkFeature as dup is found");
687                        return 1;
688                    }
689                }
690            }
691
692            // TODO - move to MobileDataStateTracker
693            int usedNetworkType = networkType;
694            if (networkType == ConnectivityManager.TYPE_MOBILE) {
695                if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_MMS)) {
696                    usedNetworkType = ConnectivityManager.TYPE_MOBILE_MMS;
697                } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_SUPL)) {
698                    usedNetworkType = ConnectivityManager.TYPE_MOBILE_SUPL;
699                } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_DUN)) {
700                    usedNetworkType = ConnectivityManager.TYPE_MOBILE_DUN;
701                } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_HIPRI)) {
702                    usedNetworkType = ConnectivityManager.TYPE_MOBILE_HIPRI;
703                }
704            }
705            tracker =  mNetTrackers[usedNetworkType];
706            if (tracker == null) {
707                if (DBG) Slog.d(TAG, "ignoring - no known tracker for net type " + usedNetworkType);
708                return -1;
709            }
710            if (usedNetworkType != networkType) {
711                Integer currentPid = new Integer(pid);
712                mNetRequestersPids[usedNetworkType].remove(currentPid);
713                reassessPidDns(pid, true);
714                if (mNetRequestersPids[usedNetworkType].size() != 0) {
715                    if (DBG) Slog.d(TAG, "not tearing down special network - " +
716                           "others still using it");
717                    return 1;
718                }
719                callTeardown = true;
720            }
721        }
722        if (DBG) Slog.d(TAG, "Doing network teardown");
723        if (callTeardown) {
724            tracker.teardown();
725            return 1;
726        } else {
727            // do it the old fashioned way
728            return tracker.stopUsingNetworkFeature(feature, pid, uid);
729        }
730    }
731
732    /**
733     * Ensure that a network route exists to deliver traffic to the specified
734     * host via the specified network interface.
735     * @param networkType the type of the network over which traffic to the
736     * specified host is to be routed
737     * @param hostAddress the IP address of the host to which the route is
738     * desired
739     * @return {@code true} on success, {@code false} on failure
740     */
741    public boolean requestRouteToHost(int networkType, int hostAddress) {
742        enforceChangePermission();
743        if (!ConnectivityManager.isNetworkTypeValid(networkType)) {
744            return false;
745        }
746        NetworkStateTracker tracker = mNetTrackers[networkType];
747
748        if (tracker == null || !tracker.getNetworkInfo().isConnected() ||
749                tracker.isTeardownRequested()) {
750            if (DBG) {
751                Slog.d(TAG, "requestRouteToHost on down network (" + networkType + ") - dropped");
752            }
753            return false;
754        }
755        return tracker.requestRouteToHost(hostAddress);
756    }
757
758    /**
759     * @see ConnectivityManager#getBackgroundDataSetting()
760     */
761    public boolean getBackgroundDataSetting() {
762        return Settings.Secure.getInt(mContext.getContentResolver(),
763                Settings.Secure.BACKGROUND_DATA, 1) == 1;
764    }
765
766    /**
767     * @see ConnectivityManager#setBackgroundDataSetting(boolean)
768     */
769    public void setBackgroundDataSetting(boolean allowBackgroundDataUsage) {
770        mContext.enforceCallingOrSelfPermission(
771                android.Manifest.permission.CHANGE_BACKGROUND_DATA_SETTING,
772                "ConnectivityService");
773
774        if (getBackgroundDataSetting() == allowBackgroundDataUsage) return;
775
776        Settings.Secure.putInt(mContext.getContentResolver(),
777                Settings.Secure.BACKGROUND_DATA,
778                allowBackgroundDataUsage ? 1 : 0);
779
780        Intent broadcast = new Intent(
781                ConnectivityManager.ACTION_BACKGROUND_DATA_SETTING_CHANGED);
782        mContext.sendBroadcast(broadcast);
783    }
784
785    /**
786     * @see ConnectivityManager#getMobileDataEnabled()
787     */
788    public boolean getMobileDataEnabled() {
789        enforceAccessPermission();
790        boolean retVal = Settings.Secure.getInt(mContext.getContentResolver(),
791                Settings.Secure.MOBILE_DATA, 1) == 1;
792        if (DBG) Slog.d(TAG, "getMobileDataEnabled returning " + retVal);
793        return retVal;
794    }
795
796    /**
797     * @see ConnectivityManager#setMobileDataEnabled(boolean)
798     */
799    public synchronized void setMobileDataEnabled(boolean enabled) {
800        enforceChangePermission();
801        if (DBG) Slog.d(TAG, "setMobileDataEnabled(" + enabled + ")");
802
803        if (getMobileDataEnabled() == enabled) return;
804
805        Settings.Secure.putInt(mContext.getContentResolver(),
806                Settings.Secure.MOBILE_DATA, enabled ? 1 : 0);
807
808        if (enabled) {
809            if (mNetTrackers[ConnectivityManager.TYPE_MOBILE] != null) {
810                if (DBG) Slog.d(TAG, "starting up " + mNetTrackers[ConnectivityManager.TYPE_MOBILE]);
811                mNetTrackers[ConnectivityManager.TYPE_MOBILE].reconnect();
812            }
813        } else {
814            for (NetworkStateTracker nt : mNetTrackers) {
815                if (nt == null) continue;
816                int netType = nt.getNetworkInfo().getType();
817                if (mNetAttributes[netType].mRadio == ConnectivityManager.TYPE_MOBILE) {
818                    if (DBG) Slog.d(TAG, "tearing down " + nt);
819                    nt.teardown();
820                }
821            }
822        }
823    }
824
825    private int getNumConnectedNetworks() {
826        int numConnectedNets = 0;
827
828        for (NetworkStateTracker nt : mNetTrackers) {
829            if (nt != null && nt.getNetworkInfo().isConnected() &&
830                    !nt.isTeardownRequested()) {
831                ++numConnectedNets;
832            }
833        }
834        return numConnectedNets;
835    }
836
837    private void enforceAccessPermission() {
838        mContext.enforceCallingOrSelfPermission(
839                android.Manifest.permission.ACCESS_NETWORK_STATE,
840                "ConnectivityService");
841    }
842
843    private void enforceChangePermission() {
844        mContext.enforceCallingOrSelfPermission(
845                android.Manifest.permission.CHANGE_NETWORK_STATE,
846                "ConnectivityService");
847    }
848
849    // TODO Make this a special check when it goes public
850    private void enforceTetherChangePermission() {
851        mContext.enforceCallingOrSelfPermission(
852                android.Manifest.permission.CHANGE_NETWORK_STATE,
853                "ConnectivityService");
854    }
855
856    private void enforceTetherAccessPermission() {
857        mContext.enforceCallingOrSelfPermission(
858                android.Manifest.permission.ACCESS_NETWORK_STATE,
859                "ConnectivityService");
860    }
861
862    /**
863     * Handle a {@code DISCONNECTED} event. If this pertains to the non-active
864     * network, we ignore it. If it is for the active network, we send out a
865     * broadcast. But first, we check whether it might be possible to connect
866     * to a different network.
867     * @param info the {@code NetworkInfo} for the network
868     */
869    private void handleDisconnect(NetworkInfo info) {
870
871        int prevNetType = info.getType();
872
873        mNetTrackers[prevNetType].setTeardownRequested(false);
874        /*
875         * If the disconnected network is not the active one, then don't report
876         * this as a loss of connectivity. What probably happened is that we're
877         * getting the disconnect for a network that we explicitly disabled
878         * in accordance with network preference policies.
879         */
880        if (!mNetAttributes[prevNetType].isDefault()) {
881            List pids = mNetRequestersPids[prevNetType];
882            for (int i = 0; i<pids.size(); i++) {
883                Integer pid = (Integer)pids.get(i);
884                // will remove them because the net's no longer connected
885                // need to do this now as only now do we know the pids and
886                // can properly null things that are no longer referenced.
887                reassessPidDns(pid.intValue(), false);
888            }
889        }
890
891        Intent intent = new Intent(ConnectivityManager.CONNECTIVITY_ACTION);
892        intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
893        intent.putExtra(ConnectivityManager.EXTRA_NETWORK_INFO, info);
894        if (info.isFailover()) {
895            intent.putExtra(ConnectivityManager.EXTRA_IS_FAILOVER, true);
896            info.setFailover(false);
897        }
898        if (info.getReason() != null) {
899            intent.putExtra(ConnectivityManager.EXTRA_REASON, info.getReason());
900        }
901        if (info.getExtraInfo() != null) {
902            intent.putExtra(ConnectivityManager.EXTRA_EXTRA_INFO,
903                    info.getExtraInfo());
904        }
905
906        NetworkStateTracker newNet = null;
907        if (mNetAttributes[prevNetType].isDefault()) {
908            newNet = tryFailover(prevNetType);
909            if (newNet != null) {
910                NetworkInfo switchTo = newNet.getNetworkInfo();
911                intent.putExtra(ConnectivityManager.EXTRA_OTHER_NETWORK_INFO, switchTo);
912            } else {
913                intent.putExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, true);
914            }
915        }
916        // do this before we broadcast the change
917        handleConnectivityChange();
918
919        sendStickyBroadcast(intent);
920        /*
921         * If the failover network is already connected, then immediately send
922         * out a followup broadcast indicating successful failover
923         */
924        if (newNet != null && newNet.getNetworkInfo().isConnected()) {
925            sendConnectedBroadcast(newNet.getNetworkInfo());
926        }
927    }
928
929    // returns null if no failover available
930    private NetworkStateTracker tryFailover(int prevNetType) {
931        /*
932         * If this is a default network, check if other defaults are available
933         * or active
934         */
935        NetworkStateTracker newNet = null;
936        if (mNetAttributes[prevNetType].isDefault()) {
937            if (mActiveDefaultNetwork == prevNetType) {
938                mActiveDefaultNetwork = -1;
939            }
940
941            int newType = -1;
942            int newPriority = -1;
943            boolean noMobileData = !getMobileDataEnabled();
944            for (int checkType=0; checkType <= ConnectivityManager.MAX_NETWORK_TYPE; checkType++) {
945                if (checkType == prevNetType) continue;
946                if (mNetAttributes[checkType] == null) continue;
947                if (mNetAttributes[checkType].mRadio == ConnectivityManager.TYPE_MOBILE &&
948                        noMobileData) {
949                    if (DBG) {
950                        Slog.d(TAG, "not failing over to mobile type " + checkType +
951                                " because Mobile Data Disabled");
952                    }
953                    continue;
954                }
955                if (mNetAttributes[checkType].isDefault()) {
956                    /* TODO - if we have multiple nets we could use
957                     * we may want to put more thought into which we choose
958                     */
959                    if (checkType == mNetworkPreference) {
960                        newType = checkType;
961                        break;
962                    }
963                    if (mNetAttributes[checkType].mPriority > newPriority) {
964                        newType = checkType;
965                        newPriority = mNetAttributes[newType].mPriority;
966                    }
967                }
968            }
969
970            if (newType != -1) {
971                newNet = mNetTrackers[newType];
972                /**
973                 * See if the other network is available to fail over to.
974                 * If is not available, we enable it anyway, so that it
975                 * will be able to connect when it does become available,
976                 * but we report a total loss of connectivity rather than
977                 * report that we are attempting to fail over.
978                 */
979                if (newNet.isAvailable()) {
980                    NetworkInfo switchTo = newNet.getNetworkInfo();
981                    switchTo.setFailover(true);
982                    if (!switchTo.isConnectedOrConnecting() ||
983                            newNet.isTeardownRequested()) {
984                        newNet.reconnect();
985                    }
986                    if (DBG) {
987                        if (switchTo.isConnected()) {
988                            Slog.v(TAG, "Switching to already connected " +
989                                    switchTo.getTypeName());
990                        } else {
991                            Slog.v(TAG, "Attempting to switch to " +
992                                    switchTo.getTypeName());
993                        }
994                    }
995                } else {
996                    newNet.reconnect();
997                    newNet = null; // not officially avail..  try anyway, but
998                                   // report no failover
999                }
1000            }
1001        }
1002
1003        return newNet;
1004    }
1005
1006    private void sendConnectedBroadcast(NetworkInfo info) {
1007        Intent intent = new Intent(ConnectivityManager.CONNECTIVITY_ACTION);
1008        intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
1009        intent.putExtra(ConnectivityManager.EXTRA_NETWORK_INFO, info);
1010        if (info.isFailover()) {
1011            intent.putExtra(ConnectivityManager.EXTRA_IS_FAILOVER, true);
1012            info.setFailover(false);
1013        }
1014        if (info.getReason() != null) {
1015            intent.putExtra(ConnectivityManager.EXTRA_REASON, info.getReason());
1016        }
1017        if (info.getExtraInfo() != null) {
1018            intent.putExtra(ConnectivityManager.EXTRA_EXTRA_INFO,
1019                    info.getExtraInfo());
1020        }
1021        sendStickyBroadcast(intent);
1022    }
1023
1024    /**
1025     * Called when an attempt to fail over to another network has failed.
1026     * @param info the {@link NetworkInfo} for the failed network
1027     */
1028    private void handleConnectionFailure(NetworkInfo info) {
1029        mNetTrackers[info.getType()].setTeardownRequested(false);
1030
1031        String reason = info.getReason();
1032        String extraInfo = info.getExtraInfo();
1033
1034        if (DBG) {
1035            String reasonText;
1036            if (reason == null) {
1037                reasonText = ".";
1038            } else {
1039                reasonText = " (" + reason + ").";
1040            }
1041            Slog.v(TAG, "Attempt to connect to " + info.getTypeName() +
1042                    " failed" + reasonText);
1043        }
1044
1045        Intent intent = new Intent(ConnectivityManager.CONNECTIVITY_ACTION);
1046        intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
1047        intent.putExtra(ConnectivityManager.EXTRA_NETWORK_INFO, info);
1048        if (getActiveNetworkInfo() == null) {
1049            intent.putExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, true);
1050        }
1051        if (reason != null) {
1052            intent.putExtra(ConnectivityManager.EXTRA_REASON, reason);
1053        }
1054        if (extraInfo != null) {
1055            intent.putExtra(ConnectivityManager.EXTRA_EXTRA_INFO, extraInfo);
1056        }
1057        if (info.isFailover()) {
1058            intent.putExtra(ConnectivityManager.EXTRA_IS_FAILOVER, true);
1059            info.setFailover(false);
1060        }
1061
1062        NetworkStateTracker newNet = null;
1063        if (mNetAttributes[info.getType()].isDefault()) {
1064            newNet = tryFailover(info.getType());
1065            if (newNet != null) {
1066                NetworkInfo switchTo = newNet.getNetworkInfo();
1067                intent.putExtra(ConnectivityManager.EXTRA_OTHER_NETWORK_INFO, switchTo);
1068            } else {
1069                intent.putExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, true);
1070            }
1071        }
1072
1073        // do this before we broadcast the change
1074        handleConnectivityChange();
1075
1076        sendStickyBroadcast(intent);
1077        /*
1078         * If the failover network is already connected, then immediately send
1079         * out a followup broadcast indicating successful failover
1080         */
1081        if (newNet != null && newNet.getNetworkInfo().isConnected()) {
1082            sendConnectedBroadcast(newNet.getNetworkInfo());
1083        }
1084    }
1085
1086    private void sendStickyBroadcast(Intent intent) {
1087        synchronized(this) {
1088            if (!mSystemReady) {
1089                mInitialBroadcast = new Intent(intent);
1090            }
1091            intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
1092            mContext.sendStickyBroadcast(intent);
1093        }
1094    }
1095
1096    void systemReady() {
1097        synchronized(this) {
1098            mSystemReady = true;
1099            if (mInitialBroadcast != null) {
1100                mContext.sendStickyBroadcast(mInitialBroadcast);
1101                mInitialBroadcast = null;
1102            }
1103        }
1104    }
1105
1106    private void handleConnect(NetworkInfo info) {
1107        int type = info.getType();
1108
1109        // snapshot isFailover, because sendConnectedBroadcast() resets it
1110        boolean isFailover = info.isFailover();
1111        NetworkStateTracker thisNet = mNetTrackers[type];
1112
1113        // if this is a default net and other default is running
1114        // kill the one not preferred
1115        if (mNetAttributes[type].isDefault()) {
1116            if (mActiveDefaultNetwork != -1 && mActiveDefaultNetwork != type) {
1117                if ((type != mNetworkPreference &&
1118                        mNetAttributes[mActiveDefaultNetwork].mPriority >
1119                        mNetAttributes[type].mPriority) ||
1120                        mNetworkPreference == mActiveDefaultNetwork) {
1121                        // don't accept this one
1122                        if (DBG) Slog.v(TAG, "Not broadcasting CONNECT_ACTION " +
1123                                "to torn down network " + info.getTypeName());
1124                        teardown(thisNet);
1125                        return;
1126                } else {
1127                    // tear down the other
1128                    NetworkStateTracker otherNet =
1129                            mNetTrackers[mActiveDefaultNetwork];
1130                    if (DBG) Slog.v(TAG, "Policy requires " +
1131                            otherNet.getNetworkInfo().getTypeName() +
1132                            " teardown");
1133                    if (!teardown(otherNet)) {
1134                        Slog.e(TAG, "Network declined teardown request");
1135                        return;
1136                    }
1137                    if (isFailover) {
1138                        otherNet.releaseWakeLock();
1139                    }
1140                }
1141            }
1142            mActiveDefaultNetwork = type;
1143        }
1144        thisNet.setTeardownRequested(false);
1145        thisNet.updateNetworkSettings();
1146        handleConnectivityChange();
1147        sendConnectedBroadcast(info);
1148    }
1149
1150    private void handleScanResultsAvailable(NetworkInfo info) {
1151        int networkType = info.getType();
1152        if (networkType != ConnectivityManager.TYPE_WIFI) {
1153            if (DBG) Slog.v(TAG, "Got ScanResultsAvailable for " +
1154                    info.getTypeName() + " network. Don't know how to handle.");
1155        }
1156
1157        mNetTrackers[networkType].interpretScanResultsAvailable();
1158    }
1159
1160    private void handleNotificationChange(boolean visible, int id,
1161            Notification notification) {
1162        NotificationManager notificationManager = (NotificationManager) mContext
1163                .getSystemService(Context.NOTIFICATION_SERVICE);
1164
1165        if (visible) {
1166            notificationManager.notify(id, notification);
1167        } else {
1168            notificationManager.cancel(id);
1169        }
1170    }
1171
1172    /**
1173     * After any kind of change in the connectivity state of any network,
1174     * make sure that anything that depends on the connectivity state of
1175     * more than one network is set up correctly. We're mainly concerned
1176     * with making sure that the list of DNS servers is set up  according
1177     * to which networks are connected, and ensuring that the right routing
1178     * table entries exist.
1179     */
1180    private void handleConnectivityChange() {
1181        /*
1182         * If a non-default network is enabled, add the host routes that
1183         * will allow it's DNS servers to be accessed.  Only
1184         * If both mobile and wifi are enabled, add the host routes that
1185         * will allow MMS traffic to pass on the mobile network. But
1186         * remove the default route for the mobile network, so that there
1187         * will be only one default route, to ensure that all traffic
1188         * except MMS will travel via Wi-Fi.
1189         */
1190        handleDnsConfigurationChange();
1191
1192        for (int netType : mPriorityList) {
1193            if (mNetTrackers[netType].getNetworkInfo().isConnected()) {
1194                if (mNetAttributes[netType].isDefault()) {
1195                    mNetTrackers[netType].addDefaultRoute();
1196                } else {
1197                    mNetTrackers[netType].addPrivateDnsRoutes();
1198                }
1199            } else {
1200                if (mNetAttributes[netType].isDefault()) {
1201                    mNetTrackers[netType].removeDefaultRoute();
1202                } else {
1203                    mNetTrackers[netType].removePrivateDnsRoutes();
1204                }
1205            }
1206        }
1207    }
1208
1209    /**
1210     * Adjust the per-process dns entries (net.dns<x>.<pid>) based
1211     * on the highest priority active net which this process requested.
1212     * If there aren't any, clear it out
1213     */
1214    private void reassessPidDns(int myPid, boolean doBump)
1215    {
1216        if (DBG) Slog.d(TAG, "reassessPidDns for pid " + myPid);
1217        for(int i : mPriorityList) {
1218            if (mNetAttributes[i].isDefault()) {
1219                continue;
1220            }
1221            NetworkStateTracker nt = mNetTrackers[i];
1222            if (nt.getNetworkInfo().isConnected() &&
1223                    !nt.isTeardownRequested()) {
1224                List pids = mNetRequestersPids[i];
1225                for (int j=0; j<pids.size(); j++) {
1226                    Integer pid = (Integer)pids.get(j);
1227                    if (pid.intValue() == myPid) {
1228                        String[] dnsList = nt.getNameServers();
1229                        writePidDns(dnsList, myPid);
1230                        if (doBump) {
1231                            bumpDns();
1232                        }
1233                        return;
1234                    }
1235                }
1236           }
1237        }
1238        // nothing found - delete
1239        for (int i = 1; ; i++) {
1240            String prop = "net.dns" + i + "." + myPid;
1241            if (SystemProperties.get(prop).length() == 0) {
1242                if (doBump) {
1243                    bumpDns();
1244                }
1245                return;
1246            }
1247            SystemProperties.set(prop, "");
1248        }
1249    }
1250
1251    private void writePidDns(String[] dnsList, int pid) {
1252        int j = 1;
1253        for (String dns : dnsList) {
1254            if (dns != null && !TextUtils.equals(dns, "0.0.0.0")) {
1255                SystemProperties.set("net.dns" + j++ + "." + pid, dns);
1256            }
1257        }
1258    }
1259
1260    private void bumpDns() {
1261        /*
1262         * Bump the property that tells the name resolver library to reread
1263         * the DNS server list from the properties.
1264         */
1265        String propVal = SystemProperties.get("net.dnschange");
1266        int n = 0;
1267        if (propVal.length() != 0) {
1268            try {
1269                n = Integer.parseInt(propVal);
1270            } catch (NumberFormatException e) {}
1271        }
1272        SystemProperties.set("net.dnschange", "" + (n+1));
1273    }
1274
1275    private void handleDnsConfigurationChange() {
1276        // add default net's dns entries
1277        for (int x = mPriorityList.length-1; x>= 0; x--) {
1278            int netType = mPriorityList[x];
1279            NetworkStateTracker nt = mNetTrackers[netType];
1280            if (nt != null && nt.getNetworkInfo().isConnected() &&
1281                    !nt.isTeardownRequested()) {
1282                String[] dnsList = nt.getNameServers();
1283                if (mNetAttributes[netType].isDefault()) {
1284                    int j = 1;
1285                    for (String dns : dnsList) {
1286                        if (dns != null && !TextUtils.equals(dns, "0.0.0.0")) {
1287                            if (DBG) {
1288                                Slog.d(TAG, "adding dns " + dns + " for " +
1289                                        nt.getNetworkInfo().getTypeName());
1290                            }
1291                            SystemProperties.set("net.dns" + j++, dns);
1292                        }
1293                    }
1294                    for (int k=j ; k<mNumDnsEntries; k++) {
1295                        if (DBG) Slog.d(TAG, "erasing net.dns" + k);
1296                        SystemProperties.set("net.dns" + k, "");
1297                    }
1298                    mNumDnsEntries = j;
1299                } else {
1300                    // set per-pid dns for attached secondary nets
1301                    List pids = mNetRequestersPids[netType];
1302                    for (int y=0; y< pids.size(); y++) {
1303                        Integer pid = (Integer)pids.get(y);
1304                        writePidDns(dnsList, pid.intValue());
1305                    }
1306                }
1307            }
1308        }
1309
1310        bumpDns();
1311    }
1312
1313    private int getRestoreDefaultNetworkDelay() {
1314        String restoreDefaultNetworkDelayStr = SystemProperties.get(
1315                NETWORK_RESTORE_DELAY_PROP_NAME);
1316        if(restoreDefaultNetworkDelayStr != null &&
1317                restoreDefaultNetworkDelayStr.length() != 0) {
1318            try {
1319                return Integer.valueOf(restoreDefaultNetworkDelayStr);
1320            } catch (NumberFormatException e) {
1321            }
1322        }
1323        return RESTORE_DEFAULT_NETWORK_DELAY;
1324    }
1325
1326    @Override
1327    protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1328        if (mContext.checkCallingOrSelfPermission(
1329                android.Manifest.permission.DUMP)
1330                != PackageManager.PERMISSION_GRANTED) {
1331            pw.println("Permission Denial: can't dump ConnectivityService " +
1332                    "from from pid=" + Binder.getCallingPid() + ", uid=" +
1333                    Binder.getCallingUid());
1334            return;
1335        }
1336        pw.println();
1337        for (NetworkStateTracker nst : mNetTrackers) {
1338            if (nst != null) {
1339                if (nst.getNetworkInfo().isConnected()) {
1340                    pw.println("Active network: " + nst.getNetworkInfo().
1341                            getTypeName());
1342                }
1343                pw.println(nst.getNetworkInfo());
1344                pw.println(nst);
1345                pw.println();
1346            }
1347        }
1348
1349        pw.println("Network Requester Pids:");
1350        for (int net : mPriorityList) {
1351            String pidString = net + ": ";
1352            for (Object pid : mNetRequestersPids[net]) {
1353                pidString = pidString + pid.toString() + ", ";
1354            }
1355            pw.println(pidString);
1356        }
1357        pw.println();
1358
1359        pw.println("FeatureUsers:");
1360        for (Object requester : mFeatureUsers) {
1361            pw.println(requester.toString());
1362        }
1363        pw.println();
1364
1365        mTethering.dump(fd, pw, args);
1366    }
1367
1368    // must be stateless - things change under us.
1369    private class MyHandler extends Handler {
1370        @Override
1371        public void handleMessage(Message msg) {
1372            NetworkInfo info;
1373            switch (msg.what) {
1374                case NetworkStateTracker.EVENT_STATE_CHANGED:
1375                    info = (NetworkInfo) msg.obj;
1376                    int type = info.getType();
1377                    NetworkInfo.State state = info.getState();
1378                    // only do this optimization for wifi.  It going into scan mode for location
1379                    // services generates alot of noise.  Meanwhile the mms apn won't send out
1380                    // subsequent notifications when on default cellular because it never
1381                    // disconnects..  so only do this to wifi notifications.  Fixed better when the
1382                    // APN notifications are standardized.
1383                    if (mNetAttributes[type].mLastState == state &&
1384                            mNetAttributes[type].mRadio == ConnectivityManager.TYPE_WIFI) {
1385                        if (DBG) {
1386                            // TODO - remove this after we validate the dropping doesn't break
1387                            // anything
1388                            Slog.d(TAG, "Dropping ConnectivityChange for " +
1389                                    info.getTypeName() + ": " +
1390                                    state + "/" + info.getDetailedState());
1391                        }
1392                        return;
1393                    }
1394                    mNetAttributes[type].mLastState = state;
1395
1396                    if (DBG) Slog.d(TAG, "ConnectivityChange for " +
1397                            info.getTypeName() + ": " +
1398                            state + "/" + info.getDetailedState());
1399
1400                    // Connectivity state changed:
1401                    // [31-13] Reserved for future use
1402                    // [12-9] Network subtype (for mobile network, as defined
1403                    //         by TelephonyManager)
1404                    // [8-3] Detailed state ordinal (as defined by
1405                    //         NetworkInfo.DetailedState)
1406                    // [2-0] Network type (as defined by ConnectivityManager)
1407                    int eventLogParam = (info.getType() & 0x7) |
1408                            ((info.getDetailedState().ordinal() & 0x3f) << 3) |
1409                            (info.getSubtype() << 9);
1410                    EventLog.writeEvent(EventLogTags.CONNECTIVITY_STATE_CHANGED,
1411                            eventLogParam);
1412
1413                    if (info.getDetailedState() ==
1414                            NetworkInfo.DetailedState.FAILED) {
1415                        handleConnectionFailure(info);
1416                    } else if (state == NetworkInfo.State.DISCONNECTED) {
1417                        handleDisconnect(info);
1418                    } else if (state == NetworkInfo.State.SUSPENDED) {
1419                        // TODO: need to think this over.
1420                        // the logic here is, handle SUSPENDED the same as
1421                        // DISCONNECTED. The only difference being we are
1422                        // broadcasting an intent with NetworkInfo that's
1423                        // suspended. This allows the applications an
1424                        // opportunity to handle DISCONNECTED and SUSPENDED
1425                        // differently, or not.
1426                        handleDisconnect(info);
1427                    } else if (state == NetworkInfo.State.CONNECTED) {
1428                        handleConnect(info);
1429                    }
1430                    break;
1431
1432                case NetworkStateTracker.EVENT_SCAN_RESULTS_AVAILABLE:
1433                    info = (NetworkInfo) msg.obj;
1434                    handleScanResultsAvailable(info);
1435                    break;
1436
1437                case NetworkStateTracker.EVENT_NOTIFICATION_CHANGED:
1438                    handleNotificationChange(msg.arg1 == 1, msg.arg2,
1439                            (Notification) msg.obj);
1440
1441                case NetworkStateTracker.EVENT_CONFIGURATION_CHANGED:
1442                    handleDnsConfigurationChange();
1443                    break;
1444
1445                case NetworkStateTracker.EVENT_ROAMING_CHANGED:
1446                    // fill me in
1447                    break;
1448
1449                case NetworkStateTracker.EVENT_NETWORK_SUBTYPE_CHANGED:
1450                    // fill me in
1451                    break;
1452                case NetworkStateTracker.EVENT_RESTORE_DEFAULT_NETWORK:
1453                    FeatureUser u = (FeatureUser)msg.obj;
1454                    u.expire();
1455                    break;
1456            }
1457        }
1458    }
1459
1460    // javadoc from interface
1461    public int tether(String iface) {
1462        enforceTetherChangePermission();
1463
1464        if (isTetheringSupported()) {
1465            return mTethering.tether(iface);
1466        } else {
1467            return ConnectivityManager.TETHER_ERROR_UNSUPPORTED;
1468        }
1469    }
1470
1471    // javadoc from interface
1472    public int untether(String iface) {
1473        enforceTetherChangePermission();
1474
1475        if (isTetheringSupported()) {
1476            return mTethering.untether(iface);
1477        } else {
1478            return ConnectivityManager.TETHER_ERROR_UNSUPPORTED;
1479        }
1480    }
1481
1482    // javadoc from interface
1483    public int getLastTetherError(String iface) {
1484        enforceTetherAccessPermission();
1485
1486        if (isTetheringSupported()) {
1487            return mTethering.getLastTetherError(iface);
1488        } else {
1489            return ConnectivityManager.TETHER_ERROR_UNSUPPORTED;
1490        }
1491    }
1492
1493    // TODO - proper iface API for selection by property, inspection, etc
1494    public String[] getTetherableUsbRegexs() {
1495        enforceTetherAccessPermission();
1496        if (isTetheringSupported()) {
1497            return mTethering.getTetherableUsbRegexs();
1498        } else {
1499            return new String[0];
1500        }
1501    }
1502
1503    public String[] getTetherableWifiRegexs() {
1504        enforceTetherAccessPermission();
1505        if (isTetheringSupported()) {
1506            return mTethering.getTetherableWifiRegexs();
1507        } else {
1508            return new String[0];
1509        }
1510    }
1511
1512    // TODO - move iface listing, queries, etc to new module
1513    // javadoc from interface
1514    public String[] getTetherableIfaces() {
1515        enforceTetherAccessPermission();
1516        return mTethering.getTetherableIfaces();
1517    }
1518
1519    public String[] getTetheredIfaces() {
1520        enforceTetherAccessPermission();
1521        return mTethering.getTetheredIfaces();
1522    }
1523
1524    public String[] getTetheringErroredIfaces() {
1525        enforceTetherAccessPermission();
1526        return mTethering.getErroredIfaces();
1527    }
1528
1529    // if ro.tether.denied = true we default to no tethering
1530    // gservices could set the secure setting to 1 though to enable it on a build where it
1531    // had previously been turned off.
1532    public boolean isTetheringSupported() {
1533        enforceTetherAccessPermission();
1534        int defaultVal = (SystemProperties.get("ro.tether.denied").equals("true") ? 0 : 1);
1535        boolean tetherEnabledInSettings = (Settings.Secure.getInt(mContext.getContentResolver(),
1536                Settings.Secure.TETHER_SUPPORTED, defaultVal) != 0);
1537        return tetherEnabledInSettings && mTetheringConfigValid;
1538    }
1539}
1540