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