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