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