OSDN Git Service

Merge "Import translations. DO NOT MERGE" into jb-mr2-dev
[android-x86/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 static android.Manifest.permission.MANAGE_NETWORK_POLICY;
20 import static android.Manifest.permission.RECEIVE_DATA_ACTIVITY_CHANGE;
21 import static android.net.ConnectivityManager.CONNECTIVITY_ACTION;
22 import static android.net.ConnectivityManager.CONNECTIVITY_ACTION_IMMEDIATE;
23 import static android.net.ConnectivityManager.TYPE_BLUETOOTH;
24 import static android.net.ConnectivityManager.TYPE_DUMMY;
25 import static android.net.ConnectivityManager.TYPE_ETHERNET;
26 import static android.net.ConnectivityManager.TYPE_MOBILE;
27 import static android.net.ConnectivityManager.TYPE_WIFI;
28 import static android.net.ConnectivityManager.TYPE_WIMAX;
29 import static android.net.ConnectivityManager.getNetworkTypeName;
30 import static android.net.ConnectivityManager.isNetworkTypeValid;
31 import static android.net.NetworkPolicyManager.RULE_ALLOW_ALL;
32 import static android.net.NetworkPolicyManager.RULE_REJECT_METERED;
33
34 import android.app.Notification;
35 import android.app.NotificationManager;
36 import android.app.PendingIntent;
37 import android.bluetooth.BluetoothTetheringDataTracker;
38 import android.content.BroadcastReceiver;
39 import android.content.ContentResolver;
40 import android.content.Context;
41 import android.content.ContextWrapper;
42 import android.content.Intent;
43 import android.content.IntentFilter;
44 import android.content.pm.PackageManager;
45 import android.content.res.Resources;
46 import android.database.ContentObserver;
47 import android.net.CaptivePortalTracker;
48 import android.net.ConnectivityManager;
49 import android.net.DummyDataStateTracker;
50 import android.net.EthernetDataTracker;
51 import android.net.IConnectivityManager;
52 import android.net.INetworkManagementEventObserver;
53 import android.net.INetworkPolicyListener;
54 import android.net.INetworkPolicyManager;
55 import android.net.INetworkStatsService;
56 import android.net.LinkAddress;
57 import android.net.LinkProperties;
58 import android.net.Uri;
59 import android.net.LinkProperties.CompareResult;
60 import android.net.MobileDataStateTracker;
61 import android.net.NetworkConfig;
62 import android.net.NetworkInfo;
63 import android.net.NetworkInfo.DetailedState;
64 import android.net.NetworkInfo.State;
65 import android.net.NetworkQuotaInfo;
66 import android.net.NetworkState;
67 import android.net.NetworkStateTracker;
68 import android.net.NetworkUtils;
69 import android.net.Proxy;
70 import android.net.ProxyProperties;
71 import android.net.RouteInfo;
72 import android.net.wifi.WifiStateTracker;
73 import android.net.wimax.WimaxManagerConstants;
74 import android.os.AsyncTask;
75 import android.os.Binder;
76 import android.os.FileUtils;
77 import android.os.Handler;
78 import android.os.HandlerThread;
79 import android.os.IBinder;
80 import android.os.INetworkManagementService;
81 import android.os.Looper;
82 import android.os.Message;
83 import android.os.Messenger;
84 import android.os.ParcelFileDescriptor;
85 import android.os.PowerManager;
86 import android.os.Process;
87 import android.os.RemoteException;
88 import android.os.ResultReceiver;
89 import android.os.ServiceManager;
90 import android.os.SystemClock;
91 import android.os.SystemProperties;
92 import android.os.UserHandle;
93 import android.provider.Settings;
94 import android.security.Credentials;
95 import android.security.KeyStore;
96 import android.telephony.TelephonyManager;
97 import android.text.TextUtils;
98 import android.util.Slog;
99 import android.util.SparseIntArray;
100
101 import com.android.internal.R;
102 import com.android.internal.net.LegacyVpnInfo;
103 import com.android.internal.net.VpnConfig;
104 import com.android.internal.net.VpnProfile;
105 import com.android.internal.telephony.DctConstants;
106 import com.android.internal.telephony.Phone;
107 import com.android.internal.telephony.PhoneConstants;
108 import com.android.internal.util.IndentingPrintWriter;
109 import com.android.server.am.BatteryStatsService;
110 import com.android.server.connectivity.Nat464Xlat;
111 import com.android.server.connectivity.Tethering;
112 import com.android.server.connectivity.Vpn;
113 import com.android.server.net.BaseNetworkObserver;
114 import com.android.server.net.LockdownVpnTracker;
115 import com.google.android.collect.Lists;
116 import com.google.android.collect.Sets;
117
118 import dalvik.system.DexClassLoader;
119
120 import java.io.FileDescriptor;
121 import java.io.IOException;
122 import java.io.PrintWriter;
123 import java.lang.reflect.Constructor;
124 import java.net.HttpURLConnection;
125 import java.net.Inet4Address;
126 import java.net.Inet6Address;
127 import java.net.InetAddress;
128 import java.net.URL;
129 import java.net.UnknownHostException;
130 import java.util.ArrayList;
131 import java.util.Arrays;
132 import java.util.Collection;
133 import java.util.GregorianCalendar;
134 import java.util.HashSet;
135 import java.util.List;
136 import java.util.Random;
137 import java.util.concurrent.atomic.AtomicInteger;
138
139 /**
140  * @hide
141  */
142 public class ConnectivityService extends IConnectivityManager.Stub {
143     private static final String TAG = "ConnectivityService";
144
145     private static final boolean DBG = true;
146     private static final boolean VDBG = false;
147
148     private static final boolean LOGD_RULES = false;
149
150     // TODO: create better separation between radio types and network types
151
152     // how long to wait before switching back to a radio's default network
153     private static final int RESTORE_DEFAULT_NETWORK_DELAY = 1 * 60 * 1000;
154     // system property that can override the above value
155     private static final String NETWORK_RESTORE_DELAY_PROP_NAME =
156             "android.telephony.apn-restore";
157
158     // Default value if FAIL_FAST_TIME_MS is not set
159     private static final int DEFAULT_FAIL_FAST_TIME_MS = 1 * 60 * 1000;
160     // system property that can override DEFAULT_FAIL_FAST_TIME_MS
161     private static final String FAIL_FAST_TIME_MS =
162             "persist.radio.fail_fast_time_ms";
163
164     // used in recursive route setting to add gateways for the host for which
165     // a host route was requested.
166     private static final int MAX_HOSTROUTE_CYCLE_COUNT = 10;
167
168     private Tethering mTethering;
169     private boolean mTetheringConfigValid = false;
170
171     private KeyStore mKeyStore;
172
173     private Vpn mVpn;
174     private VpnCallback mVpnCallback = new VpnCallback();
175
176     private boolean mLockdownEnabled;
177     private LockdownVpnTracker mLockdownTracker;
178
179     private Nat464Xlat mClat;
180
181     /** Lock around {@link #mUidRules} and {@link #mMeteredIfaces}. */
182     private Object mRulesLock = new Object();
183     /** Currently active network rules by UID. */
184     private SparseIntArray mUidRules = new SparseIntArray();
185     /** Set of ifaces that are costly. */
186     private HashSet<String> mMeteredIfaces = Sets.newHashSet();
187
188     /**
189      * Sometimes we want to refer to the individual network state
190      * trackers separately, and sometimes we just want to treat them
191      * abstractly.
192      */
193     private NetworkStateTracker mNetTrackers[];
194
195     /* Handles captive portal check on a network */
196     private CaptivePortalTracker mCaptivePortalTracker;
197
198     /**
199      * The link properties that define the current links
200      */
201     private LinkProperties mCurrentLinkProperties[];
202
203     /**
204      * A per Net list of the PID's that requested access to the net
205      * used both as a refcount and for per-PID DNS selection
206      */
207     private List<Integer> mNetRequestersPids[];
208
209     // priority order of the nettrackers
210     // (excluding dynamically set mNetworkPreference)
211     // TODO - move mNetworkTypePreference into this
212     private int[] mPriorityList;
213
214     private Context mContext;
215     private int mNetworkPreference;
216     private int mActiveDefaultNetwork = -1;
217     // 0 is full bad, 100 is full good
218     private int mDefaultInetCondition = 0;
219     private int mDefaultInetConditionPublished = 0;
220     private boolean mInetConditionChangeInFlight = false;
221     private int mDefaultConnectionSequence = 0;
222
223     private Object mDnsLock = new Object();
224     private int mNumDnsEntries;
225     private boolean mDnsOverridden = false;
226
227     private boolean mTestMode;
228     private static ConnectivityService sServiceInstance;
229
230     private INetworkManagementService mNetd;
231     private INetworkPolicyManager mPolicyManager;
232
233     private static final int ENABLED  = 1;
234     private static final int DISABLED = 0;
235
236     private static final boolean ADD = true;
237     private static final boolean REMOVE = false;
238
239     private static final boolean TO_DEFAULT_TABLE = true;
240     private static final boolean TO_SECONDARY_TABLE = false;
241
242     /**
243      * used internally as a delayed event to make us switch back to the
244      * default network
245      */
246     private static final int EVENT_RESTORE_DEFAULT_NETWORK = 1;
247
248     /**
249      * used internally to change our mobile data enabled flag
250      */
251     private static final int EVENT_CHANGE_MOBILE_DATA_ENABLED = 2;
252
253     /**
254      * used internally to change our network preference setting
255      * arg1 = networkType to prefer
256      */
257     private static final int EVENT_SET_NETWORK_PREFERENCE = 3;
258
259     /**
260      * used internally to synchronize inet condition reports
261      * arg1 = networkType
262      * arg2 = condition (0 bad, 100 good)
263      */
264     private static final int EVENT_INET_CONDITION_CHANGE = 4;
265
266     /**
267      * used internally to mark the end of inet condition hold periods
268      * arg1 = networkType
269      */
270     private static final int EVENT_INET_CONDITION_HOLD_END = 5;
271
272     /**
273      * used internally to set enable/disable cellular data
274      * arg1 = ENBALED or DISABLED
275      */
276     private static final int EVENT_SET_MOBILE_DATA = 7;
277
278     /**
279      * used internally to clear a wakelock when transitioning
280      * from one net to another
281      */
282     private static final int EVENT_CLEAR_NET_TRANSITION_WAKELOCK = 8;
283
284     /**
285      * used internally to reload global proxy settings
286      */
287     private static final int EVENT_APPLY_GLOBAL_HTTP_PROXY = 9;
288
289     /**
290      * used internally to set external dependency met/unmet
291      * arg1 = ENABLED (met) or DISABLED (unmet)
292      * arg2 = NetworkType
293      */
294     private static final int EVENT_SET_DEPENDENCY_MET = 10;
295
296     /**
297      * used internally to restore DNS properties back to the
298      * default network
299      */
300     private static final int EVENT_RESTORE_DNS = 11;
301
302     /**
303      * used internally to send a sticky broadcast delayed.
304      */
305     private static final int EVENT_SEND_STICKY_BROADCAST_INTENT = 12;
306
307     /**
308      * Used internally to
309      * {@link NetworkStateTracker#setPolicyDataEnable(boolean)}.
310      */
311     private static final int EVENT_SET_POLICY_DATA_ENABLE = 13;
312
313     private static final int EVENT_VPN_STATE_CHANGED = 14;
314
315     /**
316      * Used internally to disable fail fast of mobile data
317      */
318     private static final int EVENT_ENABLE_FAIL_FAST_MOBILE_DATA = 15;
319
320     /** Handler used for internal events. */
321     private InternalHandler mHandler;
322     /** Handler used for incoming {@link NetworkStateTracker} events. */
323     private NetworkStateTrackerHandler mTrackerHandler;
324
325     // list of DeathRecipients used to make sure features are turned off when
326     // a process dies
327     private List<FeatureUser> mFeatureUsers;
328
329     private boolean mSystemReady;
330     private Intent mInitialBroadcast;
331
332     private PowerManager.WakeLock mNetTransitionWakeLock;
333     private String mNetTransitionWakeLockCausedBy = "";
334     private int mNetTransitionWakeLockSerialNumber;
335     private int mNetTransitionWakeLockTimeout;
336
337     private InetAddress mDefaultDns;
338
339     // this collection is used to refcount the added routes - if there are none left
340     // it's time to remove the route from the route table
341     private Collection<RouteInfo> mAddedRoutes = new ArrayList<RouteInfo>();
342
343     // used in DBG mode to track inet condition reports
344     private static final int INET_CONDITION_LOG_MAX_SIZE = 15;
345     private ArrayList mInetLog;
346
347     // track the current default http proxy - tell the world if we get a new one (real change)
348     private ProxyProperties mDefaultProxy = null;
349     private Object mProxyLock = new Object();
350     private boolean mDefaultProxyDisabled = false;
351
352     // track the global proxy.
353     private ProxyProperties mGlobalProxy = null;
354
355     private SettingsObserver mSettingsObserver;
356
357     NetworkConfig[] mNetConfigs;
358     int mNetworksDefined;
359
360     private static class RadioAttributes {
361         public int mSimultaneity;
362         public int mType;
363         public RadioAttributes(String init) {
364             String fragments[] = init.split(",");
365             mType = Integer.parseInt(fragments[0]);
366             mSimultaneity = Integer.parseInt(fragments[1]);
367         }
368     }
369     RadioAttributes[] mRadioAttributes;
370
371     // the set of network types that can only be enabled by system/sig apps
372     List mProtectedNetworks;
373
374     private AtomicInteger mEnableFailFastMobileDataTag = new AtomicInteger(0);
375
376     TelephonyManager mTelephonyManager;
377
378     public ConnectivityService(Context context, INetworkManagementService netd,
379             INetworkStatsService statsService, INetworkPolicyManager policyManager) {
380         // Currently, omitting a NetworkFactory will create one internally
381         // TODO: create here when we have cleaner WiMAX support
382         this(context, netd, statsService, policyManager, null);
383     }
384
385     public ConnectivityService(Context context, INetworkManagementService netManager,
386             INetworkStatsService statsService, INetworkPolicyManager policyManager,
387             NetworkFactory netFactory) {
388         if (DBG) log("ConnectivityService starting up");
389
390         HandlerThread handlerThread = new HandlerThread("ConnectivityServiceThread");
391         handlerThread.start();
392         mHandler = new InternalHandler(handlerThread.getLooper());
393         mTrackerHandler = new NetworkStateTrackerHandler(handlerThread.getLooper());
394
395         if (netFactory == null) {
396             netFactory = new DefaultNetworkFactory(context, mTrackerHandler);
397         }
398
399         // setup our unique device name
400         if (TextUtils.isEmpty(SystemProperties.get("net.hostname"))) {
401             String id = Settings.Secure.getString(context.getContentResolver(),
402                     Settings.Secure.ANDROID_ID);
403             if (id != null && id.length() > 0) {
404                 String name = new String("android-").concat(id);
405                 SystemProperties.set("net.hostname", name);
406             }
407         }
408
409         // read our default dns server ip
410         String dns = Settings.Global.getString(context.getContentResolver(),
411                 Settings.Global.DEFAULT_DNS_SERVER);
412         if (dns == null || dns.length() == 0) {
413             dns = context.getResources().getString(
414                     com.android.internal.R.string.config_default_dns_server);
415         }
416         try {
417             mDefaultDns = NetworkUtils.numericToInetAddress(dns);
418         } catch (IllegalArgumentException e) {
419             loge("Error setting defaultDns using " + dns);
420         }
421
422         mContext = checkNotNull(context, "missing Context");
423         mNetd = checkNotNull(netManager, "missing INetworkManagementService");
424         mPolicyManager = checkNotNull(policyManager, "missing INetworkPolicyManager");
425         mKeyStore = KeyStore.getInstance();
426         mTelephonyManager = (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
427
428         try {
429             mPolicyManager.registerListener(mPolicyListener);
430         } catch (RemoteException e) {
431             // ouch, no rules updates means some processes may never get network
432             loge("unable to register INetworkPolicyListener" + e.toString());
433         }
434
435         final PowerManager powerManager = (PowerManager) context.getSystemService(
436                 Context.POWER_SERVICE);
437         mNetTransitionWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
438         mNetTransitionWakeLockTimeout = mContext.getResources().getInteger(
439                 com.android.internal.R.integer.config_networkTransitionTimeout);
440
441         mNetTrackers = new NetworkStateTracker[
442                 ConnectivityManager.MAX_NETWORK_TYPE+1];
443         mCurrentLinkProperties = new LinkProperties[ConnectivityManager.MAX_NETWORK_TYPE+1];
444
445         mRadioAttributes = new RadioAttributes[ConnectivityManager.MAX_RADIO_TYPE+1];
446         mNetConfigs = new NetworkConfig[ConnectivityManager.MAX_NETWORK_TYPE+1];
447
448         // Load device network attributes from resources
449         String[] raStrings = context.getResources().getStringArray(
450                 com.android.internal.R.array.radioAttributes);
451         for (String raString : raStrings) {
452             RadioAttributes r = new RadioAttributes(raString);
453             if (r.mType > ConnectivityManager.MAX_RADIO_TYPE) {
454                 loge("Error in radioAttributes - ignoring attempt to define type " + r.mType);
455                 continue;
456             }
457             if (mRadioAttributes[r.mType] != null) {
458                 loge("Error in radioAttributes - ignoring attempt to redefine type " +
459                         r.mType);
460                 continue;
461             }
462             mRadioAttributes[r.mType] = r;
463         }
464
465         // TODO: What is the "correct" way to do determine if this is a wifi only device?
466         boolean wifiOnly = SystemProperties.getBoolean("ro.radio.noril", false);
467         log("wifiOnly=" + wifiOnly);
468         String[] naStrings = context.getResources().getStringArray(
469                 com.android.internal.R.array.networkAttributes);
470         for (String naString : naStrings) {
471             try {
472                 NetworkConfig n = new NetworkConfig(naString);
473                 if (n.type > ConnectivityManager.MAX_NETWORK_TYPE) {
474                     loge("Error in networkAttributes - ignoring attempt to define type " +
475                             n.type);
476                     continue;
477                 }
478                 if (wifiOnly && ConnectivityManager.isNetworkTypeMobile(n.type)) {
479                     log("networkAttributes - ignoring mobile as this dev is wifiOnly " +
480                             n.type);
481                     continue;
482                 }
483                 if (mNetConfigs[n.type] != null) {
484                     loge("Error in networkAttributes - ignoring attempt to redefine type " +
485                             n.type);
486                     continue;
487                 }
488                 if (mRadioAttributes[n.radio] == null) {
489                     loge("Error in networkAttributes - ignoring attempt to use undefined " +
490                             "radio " + n.radio + " in network type " + n.type);
491                     continue;
492                 }
493                 mNetConfigs[n.type] = n;
494                 mNetworksDefined++;
495             } catch(Exception e) {
496                 // ignore it - leave the entry null
497             }
498         }
499
500         mProtectedNetworks = new ArrayList<Integer>();
501         int[] protectedNetworks = context.getResources().getIntArray(
502                 com.android.internal.R.array.config_protectedNetworks);
503         for (int p : protectedNetworks) {
504             if ((mNetConfigs[p] != null) && (mProtectedNetworks.contains(p) == false)) {
505                 mProtectedNetworks.add(p);
506             } else {
507                 if (DBG) loge("Ignoring protectedNetwork " + p);
508             }
509         }
510
511         // high priority first
512         mPriorityList = new int[mNetworksDefined];
513         {
514             int insertionPoint = mNetworksDefined-1;
515             int currentLowest = 0;
516             int nextLowest = 0;
517             while (insertionPoint > -1) {
518                 for (NetworkConfig na : mNetConfigs) {
519                     if (na == null) continue;
520                     if (na.priority < currentLowest) continue;
521                     if (na.priority > currentLowest) {
522                         if (na.priority < nextLowest || nextLowest == 0) {
523                             nextLowest = na.priority;
524                         }
525                         continue;
526                     }
527                     mPriorityList[insertionPoint--] = na.type;
528                 }
529                 currentLowest = nextLowest;
530                 nextLowest = 0;
531             }
532         }
533
534         // Update mNetworkPreference according to user mannually first then overlay config.xml
535         mNetworkPreference = getPersistedNetworkPreference();
536         if (mNetworkPreference == -1) {
537             for (int n : mPriorityList) {
538                 if (mNetConfigs[n].isDefault() && ConnectivityManager.isNetworkTypeValid(n)) {
539                     mNetworkPreference = n;
540                     break;
541                 }
542             }
543             if (mNetworkPreference == -1) {
544                 throw new IllegalStateException(
545                         "You should set at least one default Network in config.xml!");
546             }
547         }
548
549         mNetRequestersPids =
550                 (List<Integer> [])new ArrayList[ConnectivityManager.MAX_NETWORK_TYPE+1];
551         for (int i : mPriorityList) {
552             mNetRequestersPids[i] = new ArrayList<Integer>();
553         }
554
555         mFeatureUsers = new ArrayList<FeatureUser>();
556
557         mTestMode = SystemProperties.get("cm.test.mode").equals("true")
558                 && SystemProperties.get("ro.build.type").equals("eng");
559
560         // Create and start trackers for hard-coded networks
561         for (int targetNetworkType : mPriorityList) {
562             final NetworkConfig config = mNetConfigs[targetNetworkType];
563             final NetworkStateTracker tracker;
564             try {
565                 tracker = netFactory.createTracker(targetNetworkType, config);
566                 mNetTrackers[targetNetworkType] = tracker;
567             } catch (IllegalArgumentException e) {
568                 Slog.e(TAG, "Problem creating " + getNetworkTypeName(targetNetworkType)
569                         + " tracker: " + e);
570                 continue;
571             }
572
573             tracker.startMonitoring(context, mTrackerHandler);
574             if (config.isDefault()) {
575                 tracker.reconnect();
576             }
577         }
578
579         mTethering = new Tethering(mContext, mNetd, statsService, this, mHandler.getLooper());
580         mTetheringConfigValid = ((mTethering.getTetherableUsbRegexs().length != 0 ||
581                                   mTethering.getTetherableWifiRegexs().length != 0 ||
582                                   mTethering.getTetherableBluetoothRegexs().length != 0) &&
583                                  mTethering.getUpstreamIfaceTypes().length != 0);
584
585         mVpn = new Vpn(mContext, mVpnCallback, mNetd, this);
586         mVpn.startMonitoring(mContext, mTrackerHandler);
587
588         mClat = new Nat464Xlat(mContext, mNetd, this, mTrackerHandler);
589
590         try {
591             mNetd.registerObserver(mTethering);
592             mNetd.registerObserver(mDataActivityObserver);
593             mNetd.registerObserver(mClat);
594         } catch (RemoteException e) {
595             loge("Error registering observer :" + e);
596         }
597
598         if (DBG) {
599             mInetLog = new ArrayList();
600         }
601
602         mSettingsObserver = new SettingsObserver(mHandler, EVENT_APPLY_GLOBAL_HTTP_PROXY);
603         mSettingsObserver.observe(mContext);
604
605         mCaptivePortalTracker = CaptivePortalTracker.makeCaptivePortalTracker(mContext, this);
606         loadGlobalProxy();
607     }
608
609     /**
610      * Factory that creates {@link NetworkStateTracker} instances using given
611      * {@link NetworkConfig}.
612      */
613     public interface NetworkFactory {
614         public NetworkStateTracker createTracker(int targetNetworkType, NetworkConfig config);
615     }
616
617     private static class DefaultNetworkFactory implements NetworkFactory {
618         private final Context mContext;
619         private final Handler mTrackerHandler;
620
621         public DefaultNetworkFactory(Context context, Handler trackerHandler) {
622             mContext = context;
623             mTrackerHandler = trackerHandler;
624         }
625
626         @Override
627         public NetworkStateTracker createTracker(int targetNetworkType, NetworkConfig config) {
628             switch (config.radio) {
629                 case TYPE_WIFI:
630                     return new WifiStateTracker(targetNetworkType, config.name);
631                 case TYPE_MOBILE:
632                     return new MobileDataStateTracker(targetNetworkType, config.name);
633                 case TYPE_DUMMY:
634                     return new DummyDataStateTracker(targetNetworkType, config.name);
635                 case TYPE_BLUETOOTH:
636                     return BluetoothTetheringDataTracker.getInstance();
637                 case TYPE_WIMAX:
638                     return makeWimaxStateTracker(mContext, mTrackerHandler);
639                 case TYPE_ETHERNET:
640                     return EthernetDataTracker.getInstance();
641                 default:
642                     throw new IllegalArgumentException(
643                             "Trying to create a NetworkStateTracker for an unknown radio type: "
644                             + config.radio);
645             }
646         }
647     }
648
649     /**
650      * Loads external WiMAX library and registers as system service, returning a
651      * {@link NetworkStateTracker} for WiMAX. Caller is still responsible for
652      * invoking {@link NetworkStateTracker#startMonitoring(Context, Handler)}.
653      */
654     private static NetworkStateTracker makeWimaxStateTracker(
655             Context context, Handler trackerHandler) {
656         // Initialize Wimax
657         DexClassLoader wimaxClassLoader;
658         Class wimaxStateTrackerClass = null;
659         Class wimaxServiceClass = null;
660         Class wimaxManagerClass;
661         String wimaxJarLocation;
662         String wimaxLibLocation;
663         String wimaxManagerClassName;
664         String wimaxServiceClassName;
665         String wimaxStateTrackerClassName;
666
667         NetworkStateTracker wimaxStateTracker = null;
668
669         boolean isWimaxEnabled = context.getResources().getBoolean(
670                 com.android.internal.R.bool.config_wimaxEnabled);
671
672         if (isWimaxEnabled) {
673             try {
674                 wimaxJarLocation = context.getResources().getString(
675                         com.android.internal.R.string.config_wimaxServiceJarLocation);
676                 wimaxLibLocation = context.getResources().getString(
677                         com.android.internal.R.string.config_wimaxNativeLibLocation);
678                 wimaxManagerClassName = context.getResources().getString(
679                         com.android.internal.R.string.config_wimaxManagerClassname);
680                 wimaxServiceClassName = context.getResources().getString(
681                         com.android.internal.R.string.config_wimaxServiceClassname);
682                 wimaxStateTrackerClassName = context.getResources().getString(
683                         com.android.internal.R.string.config_wimaxStateTrackerClassname);
684
685                 if (DBG) log("wimaxJarLocation: " + wimaxJarLocation);
686                 wimaxClassLoader =  new DexClassLoader(wimaxJarLocation,
687                         new ContextWrapper(context).getCacheDir().getAbsolutePath(),
688                         wimaxLibLocation, ClassLoader.getSystemClassLoader());
689
690                 try {
691                     wimaxManagerClass = wimaxClassLoader.loadClass(wimaxManagerClassName);
692                     wimaxStateTrackerClass = wimaxClassLoader.loadClass(wimaxStateTrackerClassName);
693                     wimaxServiceClass = wimaxClassLoader.loadClass(wimaxServiceClassName);
694                 } catch (ClassNotFoundException ex) {
695                     loge("Exception finding Wimax classes: " + ex.toString());
696                     return null;
697                 }
698             } catch(Resources.NotFoundException ex) {
699                 loge("Wimax Resources does not exist!!! ");
700                 return null;
701             }
702
703             try {
704                 if (DBG) log("Starting Wimax Service... ");
705
706                 Constructor wmxStTrkrConst = wimaxStateTrackerClass.getConstructor
707                         (new Class[] {Context.class, Handler.class});
708                 wimaxStateTracker = (NetworkStateTracker) wmxStTrkrConst.newInstance(
709                         context, trackerHandler);
710
711                 Constructor wmxSrvConst = wimaxServiceClass.getDeclaredConstructor
712                         (new Class[] {Context.class, wimaxStateTrackerClass});
713                 wmxSrvConst.setAccessible(true);
714                 IBinder svcInvoker = (IBinder)wmxSrvConst.newInstance(context, wimaxStateTracker);
715                 wmxSrvConst.setAccessible(false);
716
717                 ServiceManager.addService(WimaxManagerConstants.WIMAX_SERVICE, svcInvoker);
718
719             } catch(Exception ex) {
720                 loge("Exception creating Wimax classes: " + ex.toString());
721                 return null;
722             }
723         } else {
724             loge("Wimax is not enabled or not added to the network attributes!!! ");
725             return null;
726         }
727
728         return wimaxStateTracker;
729     }
730
731     /**
732      * Sets the preferred network.
733      * @param preference the new preference
734      */
735     public void setNetworkPreference(int preference) {
736         enforceChangePermission();
737
738         mHandler.sendMessage(
739                 mHandler.obtainMessage(EVENT_SET_NETWORK_PREFERENCE, preference, 0));
740     }
741
742     public int getNetworkPreference() {
743         enforceAccessPermission();
744         int preference;
745         synchronized(this) {
746             preference = mNetworkPreference;
747         }
748         return preference;
749     }
750
751     private void handleSetNetworkPreference(int preference) {
752         if (ConnectivityManager.isNetworkTypeValid(preference) &&
753                 mNetConfigs[preference] != null &&
754                 mNetConfigs[preference].isDefault()) {
755             if (mNetworkPreference != preference) {
756                 final ContentResolver cr = mContext.getContentResolver();
757                 Settings.Global.putInt(cr, Settings.Global.NETWORK_PREFERENCE, preference);
758                 synchronized(this) {
759                     mNetworkPreference = preference;
760                 }
761                 enforcePreference();
762             }
763         }
764     }
765
766     private int getConnectivityChangeDelay() {
767         final ContentResolver cr = mContext.getContentResolver();
768
769         /** Check system properties for the default value then use secure settings value, if any. */
770         int defaultDelay = SystemProperties.getInt(
771                 "conn." + Settings.Global.CONNECTIVITY_CHANGE_DELAY,
772                 ConnectivityManager.CONNECTIVITY_CHANGE_DELAY_DEFAULT);
773         return Settings.Global.getInt(cr, Settings.Global.CONNECTIVITY_CHANGE_DELAY,
774                 defaultDelay);
775     }
776
777     private int getPersistedNetworkPreference() {
778         final ContentResolver cr = mContext.getContentResolver();
779
780         final int networkPrefSetting = Settings.Global
781                 .getInt(cr, Settings.Global.NETWORK_PREFERENCE, -1);
782
783         return networkPrefSetting;
784     }
785
786     /**
787      * Make the state of network connectivity conform to the preference settings
788      * In this method, we only tear down a non-preferred network. Establishing
789      * a connection to the preferred network is taken care of when we handle
790      * the disconnect event from the non-preferred network
791      * (see {@link #handleDisconnect(NetworkInfo)}).
792      */
793     private void enforcePreference() {
794         if (mNetTrackers[mNetworkPreference].getNetworkInfo().isConnected())
795             return;
796
797         if (!mNetTrackers[mNetworkPreference].isAvailable())
798             return;
799
800         for (int t=0; t <= ConnectivityManager.MAX_RADIO_TYPE; t++) {
801             if (t != mNetworkPreference && mNetTrackers[t] != null &&
802                     mNetTrackers[t].getNetworkInfo().isConnected()) {
803                 if (DBG) {
804                     log("tearing down " + mNetTrackers[t].getNetworkInfo() +
805                             " in enforcePreference");
806                 }
807                 teardown(mNetTrackers[t]);
808             }
809         }
810     }
811
812     private boolean teardown(NetworkStateTracker netTracker) {
813         if (netTracker.teardown()) {
814             netTracker.setTeardownRequested(true);
815             return true;
816         } else {
817             return false;
818         }
819     }
820
821     /**
822      * Check if UID should be blocked from using the network represented by the
823      * given {@link NetworkStateTracker}.
824      */
825     private boolean isNetworkBlocked(NetworkStateTracker tracker, int uid) {
826         final String iface = tracker.getLinkProperties().getInterfaceName();
827
828         final boolean networkCostly;
829         final int uidRules;
830         synchronized (mRulesLock) {
831             networkCostly = mMeteredIfaces.contains(iface);
832             uidRules = mUidRules.get(uid, RULE_ALLOW_ALL);
833         }
834
835         if (networkCostly && (uidRules & RULE_REJECT_METERED) != 0) {
836             return true;
837         }
838
839         // no restrictive rules; network is visible
840         return false;
841     }
842
843     /**
844      * Return a filtered {@link NetworkInfo}, potentially marked
845      * {@link DetailedState#BLOCKED} based on
846      * {@link #isNetworkBlocked(NetworkStateTracker, int)}.
847      */
848     private NetworkInfo getFilteredNetworkInfo(NetworkStateTracker tracker, int uid) {
849         NetworkInfo info = tracker.getNetworkInfo();
850         if (isNetworkBlocked(tracker, uid)) {
851             // network is blocked; clone and override state
852             info = new NetworkInfo(info);
853             info.setDetailedState(DetailedState.BLOCKED, null, null);
854         }
855         if (mLockdownTracker != null) {
856             info = mLockdownTracker.augmentNetworkInfo(info);
857         }
858         return info;
859     }
860
861     /**
862      * Return NetworkInfo for the active (i.e., connected) network interface.
863      * It is assumed that at most one network is active at a time. If more
864      * than one is active, it is indeterminate which will be returned.
865      * @return the info for the active network, or {@code null} if none is
866      * active
867      */
868     @Override
869     public NetworkInfo getActiveNetworkInfo() {
870         enforceAccessPermission();
871         final int uid = Binder.getCallingUid();
872         return getNetworkInfo(mActiveDefaultNetwork, uid);
873     }
874
875     public NetworkInfo getActiveNetworkInfoUnfiltered() {
876         enforceAccessPermission();
877         if (isNetworkTypeValid(mActiveDefaultNetwork)) {
878             final NetworkStateTracker tracker = mNetTrackers[mActiveDefaultNetwork];
879             if (tracker != null) {
880                 return tracker.getNetworkInfo();
881             }
882         }
883         return null;
884     }
885
886     @Override
887     public NetworkInfo getActiveNetworkInfoForUid(int uid) {
888         enforceConnectivityInternalPermission();
889         return getNetworkInfo(mActiveDefaultNetwork, uid);
890     }
891
892     @Override
893     public NetworkInfo getNetworkInfo(int networkType) {
894         enforceAccessPermission();
895         final int uid = Binder.getCallingUid();
896         return getNetworkInfo(networkType, uid);
897     }
898
899     private NetworkInfo getNetworkInfo(int networkType, int uid) {
900         NetworkInfo info = null;
901         if (isNetworkTypeValid(networkType)) {
902             final NetworkStateTracker tracker = mNetTrackers[networkType];
903             if (tracker != null) {
904                 info = getFilteredNetworkInfo(tracker, uid);
905             }
906         }
907         return info;
908     }
909
910     @Override
911     public NetworkInfo[] getAllNetworkInfo() {
912         enforceAccessPermission();
913         final int uid = Binder.getCallingUid();
914         final ArrayList<NetworkInfo> result = Lists.newArrayList();
915         synchronized (mRulesLock) {
916             for (NetworkStateTracker tracker : mNetTrackers) {
917                 if (tracker != null) {
918                     result.add(getFilteredNetworkInfo(tracker, uid));
919                 }
920             }
921         }
922         return result.toArray(new NetworkInfo[result.size()]);
923     }
924
925     @Override
926     public boolean isNetworkSupported(int networkType) {
927         enforceAccessPermission();
928         return (isNetworkTypeValid(networkType) && (mNetTrackers[networkType] != null));
929     }
930
931     /**
932      * Return LinkProperties for the active (i.e., connected) default
933      * network interface.  It is assumed that at most one default network
934      * is active at a time. If more than one is active, it is indeterminate
935      * which will be returned.
936      * @return the ip properties for the active network, or {@code null} if
937      * none is active
938      */
939     @Override
940     public LinkProperties getActiveLinkProperties() {
941         return getLinkProperties(mActiveDefaultNetwork);
942     }
943
944     @Override
945     public LinkProperties getLinkProperties(int networkType) {
946         enforceAccessPermission();
947         if (isNetworkTypeValid(networkType)) {
948             final NetworkStateTracker tracker = mNetTrackers[networkType];
949             if (tracker != null) {
950                 return tracker.getLinkProperties();
951             }
952         }
953         return null;
954     }
955
956     @Override
957     public NetworkState[] getAllNetworkState() {
958         enforceAccessPermission();
959         final int uid = Binder.getCallingUid();
960         final ArrayList<NetworkState> result = Lists.newArrayList();
961         synchronized (mRulesLock) {
962             for (NetworkStateTracker tracker : mNetTrackers) {
963                 if (tracker != null) {
964                     final NetworkInfo info = getFilteredNetworkInfo(tracker, uid);
965                     result.add(new NetworkState(
966                             info, tracker.getLinkProperties(), tracker.getLinkCapabilities()));
967                 }
968             }
969         }
970         return result.toArray(new NetworkState[result.size()]);
971     }
972
973     private NetworkState getNetworkStateUnchecked(int networkType) {
974         if (isNetworkTypeValid(networkType)) {
975             final NetworkStateTracker tracker = mNetTrackers[networkType];
976             if (tracker != null) {
977                 return new NetworkState(tracker.getNetworkInfo(), tracker.getLinkProperties(),
978                         tracker.getLinkCapabilities());
979             }
980         }
981         return null;
982     }
983
984     @Override
985     public NetworkQuotaInfo getActiveNetworkQuotaInfo() {
986         enforceAccessPermission();
987
988         final long token = Binder.clearCallingIdentity();
989         try {
990             final NetworkState state = getNetworkStateUnchecked(mActiveDefaultNetwork);
991             if (state != null) {
992                 try {
993                     return mPolicyManager.getNetworkQuotaInfo(state);
994                 } catch (RemoteException e) {
995                 }
996             }
997             return null;
998         } finally {
999             Binder.restoreCallingIdentity(token);
1000         }
1001     }
1002
1003     @Override
1004     public boolean isActiveNetworkMetered() {
1005         enforceAccessPermission();
1006         final long token = Binder.clearCallingIdentity();
1007         try {
1008             return isNetworkMeteredUnchecked(mActiveDefaultNetwork);
1009         } finally {
1010             Binder.restoreCallingIdentity(token);
1011         }
1012     }
1013
1014     private boolean isNetworkMeteredUnchecked(int networkType) {
1015         final NetworkState state = getNetworkStateUnchecked(networkType);
1016         if (state != null) {
1017             try {
1018                 return mPolicyManager.isNetworkMetered(state);
1019             } catch (RemoteException e) {
1020             }
1021         }
1022         return false;
1023     }
1024
1025     public boolean setRadios(boolean turnOn) {
1026         boolean result = true;
1027         enforceChangePermission();
1028         for (NetworkStateTracker t : mNetTrackers) {
1029             if (t != null) result = t.setRadio(turnOn) && result;
1030         }
1031         return result;
1032     }
1033
1034     public boolean setRadio(int netType, boolean turnOn) {
1035         enforceChangePermission();
1036         if (!ConnectivityManager.isNetworkTypeValid(netType)) {
1037             return false;
1038         }
1039         NetworkStateTracker tracker = mNetTrackers[netType];
1040         return tracker != null && tracker.setRadio(turnOn);
1041     }
1042
1043     private INetworkManagementEventObserver mDataActivityObserver = new BaseNetworkObserver() {
1044         @Override
1045         public void interfaceClassDataActivityChanged(String label, boolean active) {
1046             int deviceType = Integer.parseInt(label);
1047             sendDataActivityBroadcast(deviceType, active);
1048         }
1049     };
1050
1051     /**
1052      * Used to notice when the calling process dies so we can self-expire
1053      *
1054      * Also used to know if the process has cleaned up after itself when
1055      * our auto-expire timer goes off.  The timer has a link to an object.
1056      *
1057      */
1058     private class FeatureUser implements IBinder.DeathRecipient {
1059         int mNetworkType;
1060         String mFeature;
1061         IBinder mBinder;
1062         int mPid;
1063         int mUid;
1064         long mCreateTime;
1065
1066         FeatureUser(int type, String feature, IBinder binder) {
1067             super();
1068             mNetworkType = type;
1069             mFeature = feature;
1070             mBinder = binder;
1071             mPid = getCallingPid();
1072             mUid = getCallingUid();
1073             mCreateTime = System.currentTimeMillis();
1074
1075             try {
1076                 mBinder.linkToDeath(this, 0);
1077             } catch (RemoteException e) {
1078                 binderDied();
1079             }
1080         }
1081
1082         void unlinkDeathRecipient() {
1083             mBinder.unlinkToDeath(this, 0);
1084         }
1085
1086         public void binderDied() {
1087             log("ConnectivityService FeatureUser binderDied(" +
1088                     mNetworkType + ", " + mFeature + ", " + mBinder + "), created " +
1089                     (System.currentTimeMillis() - mCreateTime) + " mSec ago");
1090             stopUsingNetworkFeature(this, false);
1091         }
1092
1093         public void expire() {
1094             if (VDBG) {
1095                 log("ConnectivityService FeatureUser expire(" +
1096                         mNetworkType + ", " + mFeature + ", " + mBinder +"), created " +
1097                         (System.currentTimeMillis() - mCreateTime) + " mSec ago");
1098             }
1099             stopUsingNetworkFeature(this, false);
1100         }
1101
1102         public boolean isSameUser(FeatureUser u) {
1103             if (u == null) return false;
1104
1105             return isSameUser(u.mPid, u.mUid, u.mNetworkType, u.mFeature);
1106         }
1107
1108         public boolean isSameUser(int pid, int uid, int networkType, String feature) {
1109             if ((mPid == pid) && (mUid == uid) && (mNetworkType == networkType) &&
1110                 TextUtils.equals(mFeature, feature)) {
1111                 return true;
1112             }
1113             return false;
1114         }
1115
1116         public String toString() {
1117             return "FeatureUser("+mNetworkType+","+mFeature+","+mPid+","+mUid+"), created " +
1118                     (System.currentTimeMillis() - mCreateTime) + " mSec ago";
1119         }
1120     }
1121
1122     // javadoc from interface
1123     public int startUsingNetworkFeature(int networkType, String feature,
1124             IBinder binder) {
1125         long startTime = 0;
1126         if (DBG) {
1127             startTime = SystemClock.elapsedRealtime();
1128         }
1129         if (VDBG) {
1130             log("startUsingNetworkFeature for net " + networkType + ": " + feature + ", uid="
1131                     + Binder.getCallingUid());
1132         }
1133         enforceChangePermission();
1134         try {
1135             if (!ConnectivityManager.isNetworkTypeValid(networkType) ||
1136                     mNetConfigs[networkType] == null) {
1137                 return PhoneConstants.APN_REQUEST_FAILED;
1138             }
1139
1140             FeatureUser f = new FeatureUser(networkType, feature, binder);
1141
1142             // TODO - move this into individual networktrackers
1143             int usedNetworkType = convertFeatureToNetworkType(networkType, feature);
1144
1145             if (mLockdownEnabled) {
1146                 // Since carrier APNs usually aren't available from VPN
1147                 // endpoint, mark them as unavailable.
1148                 return PhoneConstants.APN_TYPE_NOT_AVAILABLE;
1149             }
1150
1151             if (mProtectedNetworks.contains(usedNetworkType)) {
1152                 enforceConnectivityInternalPermission();
1153             }
1154
1155             // if UID is restricted, don't allow them to bring up metered APNs
1156             final boolean networkMetered = isNetworkMeteredUnchecked(usedNetworkType);
1157             final int uidRules;
1158             synchronized (mRulesLock) {
1159                 uidRules = mUidRules.get(Binder.getCallingUid(), RULE_ALLOW_ALL);
1160             }
1161             if (networkMetered && (uidRules & RULE_REJECT_METERED) != 0) {
1162                 return PhoneConstants.APN_REQUEST_FAILED;
1163             }
1164
1165             NetworkStateTracker network = mNetTrackers[usedNetworkType];
1166             if (network != null) {
1167                 Integer currentPid = new Integer(getCallingPid());
1168                 if (usedNetworkType != networkType) {
1169                     NetworkInfo ni = network.getNetworkInfo();
1170
1171                     if (ni.isAvailable() == false) {
1172                         if (!TextUtils.equals(feature,Phone.FEATURE_ENABLE_DUN_ALWAYS)) {
1173                             if (DBG) log("special network not available ni=" + ni.getTypeName());
1174                             return PhoneConstants.APN_TYPE_NOT_AVAILABLE;
1175                         } else {
1176                             // else make the attempt anyway - probably giving REQUEST_STARTED below
1177                             if (DBG) {
1178                                 log("special network not available, but try anyway ni=" +
1179                                         ni.getTypeName());
1180                             }
1181                         }
1182                     }
1183
1184                     int restoreTimer = getRestoreDefaultNetworkDelay(usedNetworkType);
1185
1186                     synchronized(this) {
1187                         boolean addToList = true;
1188                         if (restoreTimer < 0) {
1189                             // In case there is no timer is specified for the feature,
1190                             // make sure we don't add duplicate entry with the same request.
1191                             for (FeatureUser u : mFeatureUsers) {
1192                                 if (u.isSameUser(f)) {
1193                                     // Duplicate user is found. Do not add.
1194                                     addToList = false;
1195                                     break;
1196                                 }
1197                             }
1198                         }
1199
1200                         if (addToList) mFeatureUsers.add(f);
1201                         if (!mNetRequestersPids[usedNetworkType].contains(currentPid)) {
1202                             // this gets used for per-pid dns when connected
1203                             mNetRequestersPids[usedNetworkType].add(currentPid);
1204                         }
1205                     }
1206
1207                     if (restoreTimer >= 0) {
1208                         mHandler.sendMessageDelayed(mHandler.obtainMessage(
1209                                 EVENT_RESTORE_DEFAULT_NETWORK, f), restoreTimer);
1210                     }
1211
1212                     if ((ni.isConnectedOrConnecting() == true) &&
1213                             !network.isTeardownRequested()) {
1214                         if (ni.isConnected() == true) {
1215                             final long token = Binder.clearCallingIdentity();
1216                             try {
1217                                 // add the pid-specific dns
1218                                 handleDnsConfigurationChange(usedNetworkType);
1219                                 if (VDBG) log("special network already active");
1220                             } finally {
1221                                 Binder.restoreCallingIdentity(token);
1222                             }
1223                             return PhoneConstants.APN_ALREADY_ACTIVE;
1224                         }
1225                         if (VDBG) log("special network already connecting");
1226                         return PhoneConstants.APN_REQUEST_STARTED;
1227                     }
1228
1229                     // check if the radio in play can make another contact
1230                     // assume if cannot for now
1231
1232                     if (DBG) {
1233                         log("startUsingNetworkFeature reconnecting to " + networkType + ": " +
1234                                 feature);
1235                     }
1236                     if (network.reconnect()) {
1237                         return PhoneConstants.APN_REQUEST_STARTED;
1238                     } else {
1239                         return PhoneConstants.APN_REQUEST_FAILED;
1240                     }
1241                 } else {
1242                     // need to remember this unsupported request so we respond appropriately on stop
1243                     synchronized(this) {
1244                         mFeatureUsers.add(f);
1245                         if (!mNetRequestersPids[usedNetworkType].contains(currentPid)) {
1246                             // this gets used for per-pid dns when connected
1247                             mNetRequestersPids[usedNetworkType].add(currentPid);
1248                         }
1249                     }
1250                     return -1;
1251                 }
1252             }
1253             return PhoneConstants.APN_TYPE_NOT_AVAILABLE;
1254          } finally {
1255             if (DBG) {
1256                 final long execTime = SystemClock.elapsedRealtime() - startTime;
1257                 if (execTime > 250) {
1258                     loge("startUsingNetworkFeature took too long: " + execTime + "ms");
1259                 } else {
1260                     if (VDBG) log("startUsingNetworkFeature took " + execTime + "ms");
1261                 }
1262             }
1263          }
1264     }
1265
1266     // javadoc from interface
1267     public int stopUsingNetworkFeature(int networkType, String feature) {
1268         enforceChangePermission();
1269
1270         int pid = getCallingPid();
1271         int uid = getCallingUid();
1272
1273         FeatureUser u = null;
1274         boolean found = false;
1275
1276         synchronized(this) {
1277             for (FeatureUser x : mFeatureUsers) {
1278                 if (x.isSameUser(pid, uid, networkType, feature)) {
1279                     u = x;
1280                     found = true;
1281                     break;
1282                 }
1283             }
1284         }
1285         if (found && u != null) {
1286             // stop regardless of how many other time this proc had called start
1287             return stopUsingNetworkFeature(u, true);
1288         } else {
1289             // none found!
1290             if (VDBG) log("stopUsingNetworkFeature - not a live request, ignoring");
1291             return 1;
1292         }
1293     }
1294
1295     private int stopUsingNetworkFeature(FeatureUser u, boolean ignoreDups) {
1296         int networkType = u.mNetworkType;
1297         String feature = u.mFeature;
1298         int pid = u.mPid;
1299         int uid = u.mUid;
1300
1301         NetworkStateTracker tracker = null;
1302         boolean callTeardown = false;  // used to carry our decision outside of sync block
1303
1304         if (VDBG) {
1305             log("stopUsingNetworkFeature: net " + networkType + ": " + feature);
1306         }
1307
1308         if (!ConnectivityManager.isNetworkTypeValid(networkType)) {
1309             if (DBG) {
1310                 log("stopUsingNetworkFeature: net " + networkType + ": " + feature +
1311                         ", net is invalid");
1312             }
1313             return -1;
1314         }
1315
1316         // need to link the mFeatureUsers list with the mNetRequestersPids state in this
1317         // sync block
1318         synchronized(this) {
1319             // check if this process still has an outstanding start request
1320             if (!mFeatureUsers.contains(u)) {
1321                 if (VDBG) {
1322                     log("stopUsingNetworkFeature: this process has no outstanding requests" +
1323                         ", ignoring");
1324                 }
1325                 return 1;
1326             }
1327             u.unlinkDeathRecipient();
1328             mFeatureUsers.remove(mFeatureUsers.indexOf(u));
1329             // If we care about duplicate requests, check for that here.
1330             //
1331             // This is done to support the extension of a request - the app
1332             // can request we start the network feature again and renew the
1333             // auto-shutoff delay.  Normal "stop" calls from the app though
1334             // do not pay attention to duplicate requests - in effect the
1335             // API does not refcount and a single stop will counter multiple starts.
1336             if (ignoreDups == false) {
1337                 for (FeatureUser x : mFeatureUsers) {
1338                     if (x.isSameUser(u)) {
1339                         if (VDBG) log("stopUsingNetworkFeature: dup is found, ignoring");
1340                         return 1;
1341                     }
1342                 }
1343             }
1344
1345             // TODO - move to individual network trackers
1346             int usedNetworkType = convertFeatureToNetworkType(networkType, feature);
1347
1348             tracker =  mNetTrackers[usedNetworkType];
1349             if (tracker == null) {
1350                 if (DBG) {
1351                     log("stopUsingNetworkFeature: net " + networkType + ": " + feature +
1352                             " no known tracker for used net type " + usedNetworkType);
1353                 }
1354                 return -1;
1355             }
1356             if (usedNetworkType != networkType) {
1357                 Integer currentPid = new Integer(pid);
1358                 mNetRequestersPids[usedNetworkType].remove(currentPid);
1359
1360                 final long token = Binder.clearCallingIdentity();
1361                 try {
1362                     reassessPidDns(pid, true);
1363                 } finally {
1364                     Binder.restoreCallingIdentity(token);
1365                 }
1366                 flushVmDnsCache();
1367                 if (mNetRequestersPids[usedNetworkType].size() != 0) {
1368                     if (VDBG) {
1369                         log("stopUsingNetworkFeature: net " + networkType + ": " + feature +
1370                                 " others still using it");
1371                     }
1372                     return 1;
1373                 }
1374                 callTeardown = true;
1375             } else {
1376                 if (DBG) {
1377                     log("stopUsingNetworkFeature: net " + networkType + ": " + feature +
1378                             " not a known feature - dropping");
1379                 }
1380             }
1381         }
1382
1383         if (callTeardown) {
1384             if (DBG) {
1385                 log("stopUsingNetworkFeature: teardown net " + networkType + ": " + feature);
1386             }
1387             tracker.teardown();
1388             return 1;
1389         } else {
1390             return -1;
1391         }
1392     }
1393
1394     /**
1395      * @deprecated use requestRouteToHostAddress instead
1396      *
1397      * Ensure that a network route exists to deliver traffic to the specified
1398      * host via the specified network interface.
1399      * @param networkType the type of the network over which traffic to the
1400      * specified host is to be routed
1401      * @param hostAddress the IP address of the host to which the route is
1402      * desired
1403      * @return {@code true} on success, {@code false} on failure
1404      */
1405     public boolean requestRouteToHost(int networkType, int hostAddress) {
1406         InetAddress inetAddress = NetworkUtils.intToInetAddress(hostAddress);
1407
1408         if (inetAddress == null) {
1409             return false;
1410         }
1411
1412         return requestRouteToHostAddress(networkType, inetAddress.getAddress());
1413     }
1414
1415     /**
1416      * Ensure that a network route exists to deliver traffic to the specified
1417      * host via the specified network interface.
1418      * @param networkType the type of the network over which traffic to the
1419      * specified host is to be routed
1420      * @param hostAddress the IP address of the host to which the route is
1421      * desired
1422      * @return {@code true} on success, {@code false} on failure
1423      */
1424     public boolean requestRouteToHostAddress(int networkType, byte[] hostAddress) {
1425         enforceChangePermission();
1426         if (mProtectedNetworks.contains(networkType)) {
1427             enforceConnectivityInternalPermission();
1428         }
1429
1430         if (!ConnectivityManager.isNetworkTypeValid(networkType)) {
1431             if (DBG) log("requestRouteToHostAddress on invalid network: " + networkType);
1432             return false;
1433         }
1434         NetworkStateTracker tracker = mNetTrackers[networkType];
1435         DetailedState netState = tracker.getNetworkInfo().getDetailedState();
1436
1437         if (tracker == null || (netState != DetailedState.CONNECTED &&
1438                 netState != DetailedState.CAPTIVE_PORTAL_CHECK) ||
1439                 tracker.isTeardownRequested()) {
1440             if (VDBG) {
1441                 log("requestRouteToHostAddress on down network "
1442                         + "(" + networkType + ") - dropped"
1443                         + " tracker=" + tracker
1444                         + " netState=" + netState
1445                         + " isTeardownRequested="
1446                             + ((tracker != null) ? tracker.isTeardownRequested() : "tracker:null"));
1447             }
1448             return false;
1449         }
1450         final long token = Binder.clearCallingIdentity();
1451         try {
1452             InetAddress addr = InetAddress.getByAddress(hostAddress);
1453             LinkProperties lp = tracker.getLinkProperties();
1454             boolean ok = addRouteToAddress(lp, addr);
1455             if (DBG) log("requestRouteToHostAddress ok=" + ok);
1456             return ok;
1457         } catch (UnknownHostException e) {
1458             if (DBG) log("requestRouteToHostAddress got " + e.toString());
1459         } finally {
1460             Binder.restoreCallingIdentity(token);
1461         }
1462         if (DBG) log("requestRouteToHostAddress X bottom return false");
1463         return false;
1464     }
1465
1466     private boolean addRoute(LinkProperties p, RouteInfo r, boolean toDefaultTable) {
1467         return modifyRoute(p, r, 0, ADD, toDefaultTable);
1468     }
1469
1470     private boolean removeRoute(LinkProperties p, RouteInfo r, boolean toDefaultTable) {
1471         return modifyRoute(p, r, 0, REMOVE, toDefaultTable);
1472     }
1473
1474     private boolean addRouteToAddress(LinkProperties lp, InetAddress addr) {
1475         return modifyRouteToAddress(lp, addr, ADD, TO_DEFAULT_TABLE);
1476     }
1477
1478     private boolean removeRouteToAddress(LinkProperties lp, InetAddress addr) {
1479         return modifyRouteToAddress(lp, addr, REMOVE, TO_DEFAULT_TABLE);
1480     }
1481
1482     private boolean modifyRouteToAddress(LinkProperties lp, InetAddress addr, boolean doAdd,
1483             boolean toDefaultTable) {
1484         RouteInfo bestRoute = RouteInfo.selectBestRoute(lp.getAllRoutes(), addr);
1485         if (bestRoute == null) {
1486             bestRoute = RouteInfo.makeHostRoute(addr, lp.getInterfaceName());
1487         } else {
1488             String iface = bestRoute.getInterface();
1489             if (bestRoute.getGateway().equals(addr)) {
1490                 // if there is no better route, add the implied hostroute for our gateway
1491                 bestRoute = RouteInfo.makeHostRoute(addr, iface);
1492             } else {
1493                 // if we will connect to this through another route, add a direct route
1494                 // to it's gateway
1495                 bestRoute = RouteInfo.makeHostRoute(addr, bestRoute.getGateway(), iface);
1496             }
1497         }
1498         return modifyRoute(lp, bestRoute, 0, doAdd, toDefaultTable);
1499     }
1500
1501     private boolean modifyRoute(LinkProperties lp, RouteInfo r, int cycleCount, boolean doAdd,
1502             boolean toDefaultTable) {
1503         if ((lp == null) || (r == null)) {
1504             if (DBG) log("modifyRoute got unexpected null: " + lp + ", " + r);
1505             return false;
1506         }
1507
1508         if (cycleCount > MAX_HOSTROUTE_CYCLE_COUNT) {
1509             loge("Error modifying route - too much recursion");
1510             return false;
1511         }
1512
1513         String ifaceName = r.getInterface();
1514         if(ifaceName == null) {
1515             loge("Error modifying route - no interface name");
1516             return false;
1517         }
1518         if (r.hasGateway()) {
1519             RouteInfo bestRoute = RouteInfo.selectBestRoute(lp.getAllRoutes(), r.getGateway());
1520             if (bestRoute != null) {
1521                 if (bestRoute.getGateway().equals(r.getGateway())) {
1522                     // if there is no better route, add the implied hostroute for our gateway
1523                     bestRoute = RouteInfo.makeHostRoute(r.getGateway(), ifaceName);
1524                 } else {
1525                     // if we will connect to our gateway through another route, add a direct
1526                     // route to it's gateway
1527                     bestRoute = RouteInfo.makeHostRoute(r.getGateway(),
1528                                                         bestRoute.getGateway(),
1529                                                         ifaceName);
1530                 }
1531                 modifyRoute(lp, bestRoute, cycleCount+1, doAdd, toDefaultTable);
1532             }
1533         }
1534         if (doAdd) {
1535             if (VDBG) log("Adding " + r + " for interface " + ifaceName);
1536             try {
1537                 if (toDefaultTable) {
1538                     mAddedRoutes.add(r);  // only track default table - only one apps can effect
1539                     mNetd.addRoute(ifaceName, r);
1540                 } else {
1541                     mNetd.addSecondaryRoute(ifaceName, r);
1542                 }
1543             } catch (Exception e) {
1544                 // never crash - catch them all
1545                 if (DBG) loge("Exception trying to add a route: " + e);
1546                 return false;
1547             }
1548         } else {
1549             // if we remove this one and there are no more like it, then refcount==0 and
1550             // we can remove it from the table
1551             if (toDefaultTable) {
1552                 mAddedRoutes.remove(r);
1553                 if (mAddedRoutes.contains(r) == false) {
1554                     if (VDBG) log("Removing " + r + " for interface " + ifaceName);
1555                     try {
1556                         mNetd.removeRoute(ifaceName, r);
1557                     } catch (Exception e) {
1558                         // never crash - catch them all
1559                         if (VDBG) loge("Exception trying to remove a route: " + e);
1560                         return false;
1561                     }
1562                 } else {
1563                     if (VDBG) log("not removing " + r + " as it's still in use");
1564                 }
1565             } else {
1566                 if (VDBG) log("Removing " + r + " for interface " + ifaceName);
1567                 try {
1568                     mNetd.removeSecondaryRoute(ifaceName, r);
1569                 } catch (Exception e) {
1570                     // never crash - catch them all
1571                     if (VDBG) loge("Exception trying to remove a route: " + e);
1572                     return false;
1573                 }
1574             }
1575         }
1576         return true;
1577     }
1578
1579     /**
1580      * @see ConnectivityManager#getMobileDataEnabled()
1581      */
1582     public boolean getMobileDataEnabled() {
1583         // TODO: This detail should probably be in DataConnectionTracker's
1584         //       which is where we store the value and maybe make this
1585         //       asynchronous.
1586         enforceAccessPermission();
1587         boolean retVal = Settings.Global.getInt(mContext.getContentResolver(),
1588                 Settings.Global.MOBILE_DATA, 1) == 1;
1589         if (VDBG) log("getMobileDataEnabled returning " + retVal);
1590         return retVal;
1591     }
1592
1593     public void setDataDependency(int networkType, boolean met) {
1594         enforceConnectivityInternalPermission();
1595
1596         mHandler.sendMessage(mHandler.obtainMessage(EVENT_SET_DEPENDENCY_MET,
1597                 (met ? ENABLED : DISABLED), networkType));
1598     }
1599
1600     private void handleSetDependencyMet(int networkType, boolean met) {
1601         if (mNetTrackers[networkType] != null) {
1602             if (DBG) {
1603                 log("handleSetDependencyMet(" + networkType + ", " + met + ")");
1604             }
1605             mNetTrackers[networkType].setDependencyMet(met);
1606         }
1607     }
1608
1609     private INetworkPolicyListener mPolicyListener = new INetworkPolicyListener.Stub() {
1610         @Override
1611         public void onUidRulesChanged(int uid, int uidRules) {
1612             // caller is NPMS, since we only register with them
1613             if (LOGD_RULES) {
1614                 log("onUidRulesChanged(uid=" + uid + ", uidRules=" + uidRules + ")");
1615             }
1616
1617             synchronized (mRulesLock) {
1618                 // skip update when we've already applied rules
1619                 final int oldRules = mUidRules.get(uid, RULE_ALLOW_ALL);
1620                 if (oldRules == uidRules) return;
1621
1622                 mUidRules.put(uid, uidRules);
1623             }
1624
1625             // TODO: notify UID when it has requested targeted updates
1626         }
1627
1628         @Override
1629         public void onMeteredIfacesChanged(String[] meteredIfaces) {
1630             // caller is NPMS, since we only register with them
1631             if (LOGD_RULES) {
1632                 log("onMeteredIfacesChanged(ifaces=" + Arrays.toString(meteredIfaces) + ")");
1633             }
1634
1635             synchronized (mRulesLock) {
1636                 mMeteredIfaces.clear();
1637                 for (String iface : meteredIfaces) {
1638                     mMeteredIfaces.add(iface);
1639                 }
1640             }
1641         }
1642
1643         @Override
1644         public void onRestrictBackgroundChanged(boolean restrictBackground) {
1645             // caller is NPMS, since we only register with them
1646             if (LOGD_RULES) {
1647                 log("onRestrictBackgroundChanged(restrictBackground=" + restrictBackground + ")");
1648             }
1649
1650             // kick off connectivity change broadcast for active network, since
1651             // global background policy change is radical.
1652             final int networkType = mActiveDefaultNetwork;
1653             if (isNetworkTypeValid(networkType)) {
1654                 final NetworkStateTracker tracker = mNetTrackers[networkType];
1655                 if (tracker != null) {
1656                     final NetworkInfo info = tracker.getNetworkInfo();
1657                     if (info != null && info.isConnected()) {
1658                         sendConnectedBroadcast(info);
1659                     }
1660                 }
1661             }
1662         }
1663     };
1664
1665     /**
1666      * @see ConnectivityManager#setMobileDataEnabled(boolean)
1667      */
1668     public void setMobileDataEnabled(boolean enabled) {
1669         enforceChangePermission();
1670         if (DBG) log("setMobileDataEnabled(" + enabled + ")");
1671
1672         mHandler.sendMessage(mHandler.obtainMessage(EVENT_SET_MOBILE_DATA,
1673                 (enabled ? ENABLED : DISABLED), 0));
1674     }
1675
1676     private void handleSetMobileData(boolean enabled) {
1677         if (mNetTrackers[ConnectivityManager.TYPE_MOBILE] != null) {
1678             if (VDBG) {
1679                 log(mNetTrackers[ConnectivityManager.TYPE_MOBILE].toString() + enabled);
1680             }
1681             mNetTrackers[ConnectivityManager.TYPE_MOBILE].setUserDataEnable(enabled);
1682         }
1683         if (mNetTrackers[ConnectivityManager.TYPE_WIMAX] != null) {
1684             if (VDBG) {
1685                 log(mNetTrackers[ConnectivityManager.TYPE_WIMAX].toString() + enabled);
1686             }
1687             mNetTrackers[ConnectivityManager.TYPE_WIMAX].setUserDataEnable(enabled);
1688         }
1689     }
1690
1691     @Override
1692     public void setPolicyDataEnable(int networkType, boolean enabled) {
1693         // only someone like NPMS should only be calling us
1694         mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
1695
1696         mHandler.sendMessage(mHandler.obtainMessage(
1697                 EVENT_SET_POLICY_DATA_ENABLE, networkType, (enabled ? ENABLED : DISABLED)));
1698     }
1699
1700     private void handleSetPolicyDataEnable(int networkType, boolean enabled) {
1701         if (isNetworkTypeValid(networkType)) {
1702             final NetworkStateTracker tracker = mNetTrackers[networkType];
1703             if (tracker != null) {
1704                 tracker.setPolicyDataEnable(enabled);
1705             }
1706         }
1707     }
1708
1709     private void enforceAccessPermission() {
1710         mContext.enforceCallingOrSelfPermission(
1711                 android.Manifest.permission.ACCESS_NETWORK_STATE,
1712                 "ConnectivityService");
1713     }
1714
1715     private void enforceChangePermission() {
1716         mContext.enforceCallingOrSelfPermission(
1717                 android.Manifest.permission.CHANGE_NETWORK_STATE,
1718                 "ConnectivityService");
1719     }
1720
1721     // TODO Make this a special check when it goes public
1722     private void enforceTetherChangePermission() {
1723         mContext.enforceCallingOrSelfPermission(
1724                 android.Manifest.permission.CHANGE_NETWORK_STATE,
1725                 "ConnectivityService");
1726     }
1727
1728     private void enforceTetherAccessPermission() {
1729         mContext.enforceCallingOrSelfPermission(
1730                 android.Manifest.permission.ACCESS_NETWORK_STATE,
1731                 "ConnectivityService");
1732     }
1733
1734     private void enforceConnectivityInternalPermission() {
1735         mContext.enforceCallingOrSelfPermission(
1736                 android.Manifest.permission.CONNECTIVITY_INTERNAL,
1737                 "ConnectivityService");
1738     }
1739
1740     /**
1741      * Handle a {@code DISCONNECTED} event. If this pertains to the non-active
1742      * network, we ignore it. If it is for the active network, we send out a
1743      * broadcast. But first, we check whether it might be possible to connect
1744      * to a different network.
1745      * @param info the {@code NetworkInfo} for the network
1746      */
1747     private void handleDisconnect(NetworkInfo info) {
1748
1749         int prevNetType = info.getType();
1750
1751         mNetTrackers[prevNetType].setTeardownRequested(false);
1752
1753         // Remove idletimer previously setup in {@code handleConnect}
1754         removeDataActivityTracking(prevNetType);
1755
1756         /*
1757          * If the disconnected network is not the active one, then don't report
1758          * this as a loss of connectivity. What probably happened is that we're
1759          * getting the disconnect for a network that we explicitly disabled
1760          * in accordance with network preference policies.
1761          */
1762         if (!mNetConfigs[prevNetType].isDefault()) {
1763             List<Integer> pids = mNetRequestersPids[prevNetType];
1764             for (Integer pid : pids) {
1765                 // will remove them because the net's no longer connected
1766                 // need to do this now as only now do we know the pids and
1767                 // can properly null things that are no longer referenced.
1768                 reassessPidDns(pid.intValue(), false);
1769             }
1770         }
1771
1772         Intent intent = new Intent(ConnectivityManager.CONNECTIVITY_ACTION);
1773         intent.putExtra(ConnectivityManager.EXTRA_NETWORK_INFO, new NetworkInfo(info));
1774         intent.putExtra(ConnectivityManager.EXTRA_NETWORK_TYPE, info.getType());
1775         if (info.isFailover()) {
1776             intent.putExtra(ConnectivityManager.EXTRA_IS_FAILOVER, true);
1777             info.setFailover(false);
1778         }
1779         if (info.getReason() != null) {
1780             intent.putExtra(ConnectivityManager.EXTRA_REASON, info.getReason());
1781         }
1782         if (info.getExtraInfo() != null) {
1783             intent.putExtra(ConnectivityManager.EXTRA_EXTRA_INFO,
1784                     info.getExtraInfo());
1785         }
1786
1787         if (mNetConfigs[prevNetType].isDefault()) {
1788             tryFailover(prevNetType);
1789             if (mActiveDefaultNetwork != -1) {
1790                 NetworkInfo switchTo = mNetTrackers[mActiveDefaultNetwork].getNetworkInfo();
1791                 intent.putExtra(ConnectivityManager.EXTRA_OTHER_NETWORK_INFO, switchTo);
1792             } else {
1793                 mDefaultInetConditionPublished = 0; // we're not connected anymore
1794                 intent.putExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, true);
1795             }
1796         }
1797         intent.putExtra(ConnectivityManager.EXTRA_INET_CONDITION, mDefaultInetConditionPublished);
1798
1799         // Reset interface if no other connections are using the same interface
1800         boolean doReset = true;
1801         LinkProperties linkProperties = mNetTrackers[prevNetType].getLinkProperties();
1802         if (linkProperties != null) {
1803             String oldIface = linkProperties.getInterfaceName();
1804             if (TextUtils.isEmpty(oldIface) == false) {
1805                 for (NetworkStateTracker networkStateTracker : mNetTrackers) {
1806                     if (networkStateTracker == null) continue;
1807                     NetworkInfo networkInfo = networkStateTracker.getNetworkInfo();
1808                     if (networkInfo.isConnected() && networkInfo.getType() != prevNetType) {
1809                         LinkProperties l = networkStateTracker.getLinkProperties();
1810                         if (l == null) continue;
1811                         if (oldIface.equals(l.getInterfaceName())) {
1812                             doReset = false;
1813                             break;
1814                         }
1815                     }
1816                 }
1817             }
1818         }
1819
1820         // do this before we broadcast the change
1821         handleConnectivityChange(prevNetType, doReset);
1822
1823         final Intent immediateIntent = new Intent(intent);
1824         immediateIntent.setAction(CONNECTIVITY_ACTION_IMMEDIATE);
1825         sendStickyBroadcast(immediateIntent);
1826         sendStickyBroadcastDelayed(intent, getConnectivityChangeDelay());
1827         /*
1828          * If the failover network is already connected, then immediately send
1829          * out a followup broadcast indicating successful failover
1830          */
1831         if (mActiveDefaultNetwork != -1) {
1832             sendConnectedBroadcastDelayed(mNetTrackers[mActiveDefaultNetwork].getNetworkInfo(),
1833                     getConnectivityChangeDelay());
1834         }
1835     }
1836
1837     private void tryFailover(int prevNetType) {
1838         /*
1839          * If this is a default network, check if other defaults are available.
1840          * Try to reconnect on all available and let them hash it out when
1841          * more than one connects.
1842          */
1843         if (mNetConfigs[prevNetType].isDefault()) {
1844             if (mActiveDefaultNetwork == prevNetType) {
1845                 mActiveDefaultNetwork = -1;
1846             }
1847
1848             // don't signal a reconnect for anything lower or equal priority than our
1849             // current connected default
1850             // TODO - don't filter by priority now - nice optimization but risky
1851 //            int currentPriority = -1;
1852 //            if (mActiveDefaultNetwork != -1) {
1853 //                currentPriority = mNetConfigs[mActiveDefaultNetwork].mPriority;
1854 //            }
1855             for (int checkType=0; checkType <= ConnectivityManager.MAX_NETWORK_TYPE; checkType++) {
1856                 if (checkType == prevNetType) continue;
1857                 if (mNetConfigs[checkType] == null) continue;
1858                 if (!mNetConfigs[checkType].isDefault()) continue;
1859                 if (mNetTrackers[checkType] == null) continue;
1860
1861 // Enabling the isAvailable() optimization caused mobile to not get
1862 // selected if it was in the middle of error handling. Specifically
1863 // a moble connection that took 30 seconds to complete the DEACTIVATE_DATA_CALL
1864 // would not be available and we wouldn't get connected to anything.
1865 // So removing the isAvailable() optimization below for now. TODO: This
1866 // optimization should work and we need to investigate why it doesn't work.
1867 // This could be related to how DEACTIVATE_DATA_CALL is reporting its
1868 // complete before it is really complete.
1869 //                if (!mNetTrackers[checkType].isAvailable()) continue;
1870
1871 //                if (currentPriority >= mNetConfigs[checkType].mPriority) continue;
1872
1873                 NetworkStateTracker checkTracker = mNetTrackers[checkType];
1874                 NetworkInfo checkInfo = checkTracker.getNetworkInfo();
1875                 if (!checkInfo.isConnectedOrConnecting() || checkTracker.isTeardownRequested()) {
1876                     checkInfo.setFailover(true);
1877                     checkTracker.reconnect();
1878                 }
1879                 if (DBG) log("Attempting to switch to " + checkInfo.getTypeName());
1880             }
1881         }
1882     }
1883
1884     public void sendConnectedBroadcast(NetworkInfo info) {
1885         enforceConnectivityInternalPermission();
1886         sendGeneralBroadcast(info, CONNECTIVITY_ACTION_IMMEDIATE);
1887         sendGeneralBroadcast(info, CONNECTIVITY_ACTION);
1888     }
1889
1890     private void sendConnectedBroadcastDelayed(NetworkInfo info, int delayMs) {
1891         sendGeneralBroadcast(info, CONNECTIVITY_ACTION_IMMEDIATE);
1892         sendGeneralBroadcastDelayed(info, CONNECTIVITY_ACTION, delayMs);
1893     }
1894
1895     private void sendInetConditionBroadcast(NetworkInfo info) {
1896         sendGeneralBroadcast(info, ConnectivityManager.INET_CONDITION_ACTION);
1897     }
1898
1899     private Intent makeGeneralIntent(NetworkInfo info, String bcastType) {
1900         if (mLockdownTracker != null) {
1901             info = mLockdownTracker.augmentNetworkInfo(info);
1902         }
1903
1904         Intent intent = new Intent(bcastType);
1905         intent.putExtra(ConnectivityManager.EXTRA_NETWORK_INFO, new NetworkInfo(info));
1906         intent.putExtra(ConnectivityManager.EXTRA_NETWORK_TYPE, info.getType());
1907         if (info.isFailover()) {
1908             intent.putExtra(ConnectivityManager.EXTRA_IS_FAILOVER, true);
1909             info.setFailover(false);
1910         }
1911         if (info.getReason() != null) {
1912             intent.putExtra(ConnectivityManager.EXTRA_REASON, info.getReason());
1913         }
1914         if (info.getExtraInfo() != null) {
1915             intent.putExtra(ConnectivityManager.EXTRA_EXTRA_INFO,
1916                     info.getExtraInfo());
1917         }
1918         intent.putExtra(ConnectivityManager.EXTRA_INET_CONDITION, mDefaultInetConditionPublished);
1919         return intent;
1920     }
1921
1922     private void sendGeneralBroadcast(NetworkInfo info, String bcastType) {
1923         sendStickyBroadcast(makeGeneralIntent(info, bcastType));
1924     }
1925
1926     private void sendGeneralBroadcastDelayed(NetworkInfo info, String bcastType, int delayMs) {
1927         sendStickyBroadcastDelayed(makeGeneralIntent(info, bcastType), delayMs);
1928     }
1929
1930     private void sendDataActivityBroadcast(int deviceType, boolean active) {
1931         Intent intent = new Intent(ConnectivityManager.ACTION_DATA_ACTIVITY_CHANGE);
1932         intent.putExtra(ConnectivityManager.EXTRA_DEVICE_TYPE, deviceType);
1933         intent.putExtra(ConnectivityManager.EXTRA_IS_ACTIVE, active);
1934         final long ident = Binder.clearCallingIdentity();
1935         try {
1936             mContext.sendOrderedBroadcastAsUser(intent, UserHandle.ALL,
1937                     RECEIVE_DATA_ACTIVITY_CHANGE, null, null, 0, null, null);
1938         } finally {
1939             Binder.restoreCallingIdentity(ident);
1940         }
1941     }
1942
1943     /**
1944      * Called when an attempt to fail over to another network has failed.
1945      * @param info the {@link NetworkInfo} for the failed network
1946      */
1947     private void handleConnectionFailure(NetworkInfo info) {
1948         mNetTrackers[info.getType()].setTeardownRequested(false);
1949
1950         String reason = info.getReason();
1951         String extraInfo = info.getExtraInfo();
1952
1953         String reasonText;
1954         if (reason == null) {
1955             reasonText = ".";
1956         } else {
1957             reasonText = " (" + reason + ").";
1958         }
1959         loge("Attempt to connect to " + info.getTypeName() + " failed" + reasonText);
1960
1961         Intent intent = new Intent(ConnectivityManager.CONNECTIVITY_ACTION);
1962         intent.putExtra(ConnectivityManager.EXTRA_NETWORK_INFO, new NetworkInfo(info));
1963         intent.putExtra(ConnectivityManager.EXTRA_NETWORK_TYPE, info.getType());
1964         if (getActiveNetworkInfo() == null) {
1965             intent.putExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, true);
1966         }
1967         if (reason != null) {
1968             intent.putExtra(ConnectivityManager.EXTRA_REASON, reason);
1969         }
1970         if (extraInfo != null) {
1971             intent.putExtra(ConnectivityManager.EXTRA_EXTRA_INFO, extraInfo);
1972         }
1973         if (info.isFailover()) {
1974             intent.putExtra(ConnectivityManager.EXTRA_IS_FAILOVER, true);
1975             info.setFailover(false);
1976         }
1977
1978         if (mNetConfigs[info.getType()].isDefault()) {
1979             tryFailover(info.getType());
1980             if (mActiveDefaultNetwork != -1) {
1981                 NetworkInfo switchTo = mNetTrackers[mActiveDefaultNetwork].getNetworkInfo();
1982                 intent.putExtra(ConnectivityManager.EXTRA_OTHER_NETWORK_INFO, switchTo);
1983             } else {
1984                 mDefaultInetConditionPublished = 0;
1985                 intent.putExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, true);
1986             }
1987         }
1988
1989         intent.putExtra(ConnectivityManager.EXTRA_INET_CONDITION, mDefaultInetConditionPublished);
1990
1991         final Intent immediateIntent = new Intent(intent);
1992         immediateIntent.setAction(CONNECTIVITY_ACTION_IMMEDIATE);
1993         sendStickyBroadcast(immediateIntent);
1994         sendStickyBroadcast(intent);
1995         /*
1996          * If the failover network is already connected, then immediately send
1997          * out a followup broadcast indicating successful failover
1998          */
1999         if (mActiveDefaultNetwork != -1) {
2000             sendConnectedBroadcast(mNetTrackers[mActiveDefaultNetwork].getNetworkInfo());
2001         }
2002     }
2003
2004     private void sendStickyBroadcast(Intent intent) {
2005         synchronized(this) {
2006             if (!mSystemReady) {
2007                 mInitialBroadcast = new Intent(intent);
2008             }
2009             intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
2010             if (VDBG) {
2011                 log("sendStickyBroadcast: action=" + intent.getAction());
2012             }
2013
2014             final long ident = Binder.clearCallingIdentity();
2015             try {
2016                 mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
2017             } finally {
2018                 Binder.restoreCallingIdentity(ident);
2019             }
2020         }
2021     }
2022
2023     private void sendStickyBroadcastDelayed(Intent intent, int delayMs) {
2024         if (delayMs <= 0) {
2025             sendStickyBroadcast(intent);
2026         } else {
2027             if (VDBG) {
2028                 log("sendStickyBroadcastDelayed: delayMs=" + delayMs + ", action="
2029                         + intent.getAction());
2030             }
2031             mHandler.sendMessageDelayed(mHandler.obtainMessage(
2032                     EVENT_SEND_STICKY_BROADCAST_INTENT, intent), delayMs);
2033         }
2034     }
2035
2036     void systemReady() {
2037         synchronized(this) {
2038             mSystemReady = true;
2039             if (mInitialBroadcast != null) {
2040                 mContext.sendStickyBroadcastAsUser(mInitialBroadcast, UserHandle.ALL);
2041                 mInitialBroadcast = null;
2042             }
2043         }
2044         // load the global proxy at startup
2045         mHandler.sendMessage(mHandler.obtainMessage(EVENT_APPLY_GLOBAL_HTTP_PROXY));
2046
2047         // Try bringing up tracker, but if KeyStore isn't ready yet, wait
2048         // for user to unlock device.
2049         if (!updateLockdownVpn()) {
2050             final IntentFilter filter = new IntentFilter(Intent.ACTION_USER_PRESENT);
2051             mContext.registerReceiver(mUserPresentReceiver, filter);
2052         }
2053     }
2054
2055     private BroadcastReceiver mUserPresentReceiver = new BroadcastReceiver() {
2056         @Override
2057         public void onReceive(Context context, Intent intent) {
2058             // Try creating lockdown tracker, since user present usually means
2059             // unlocked keystore.
2060             if (updateLockdownVpn()) {
2061                 mContext.unregisterReceiver(this);
2062             }
2063         }
2064     };
2065
2066     private boolean isNewNetTypePreferredOverCurrentNetType(int type) {
2067         if ((type != mNetworkPreference &&
2068                     mNetConfigs[mActiveDefaultNetwork].priority >
2069                     mNetConfigs[type].priority) ||
2070                 mNetworkPreference == mActiveDefaultNetwork) return false;
2071         return true;
2072     }
2073
2074     private void handleConnect(NetworkInfo info) {
2075         final int newNetType = info.getType();
2076
2077         setupDataActivityTracking(newNetType);
2078
2079         // snapshot isFailover, because sendConnectedBroadcast() resets it
2080         boolean isFailover = info.isFailover();
2081         final NetworkStateTracker thisNet = mNetTrackers[newNetType];
2082         final String thisIface = thisNet.getLinkProperties().getInterfaceName();
2083
2084         // if this is a default net and other default is running
2085         // kill the one not preferred
2086         if (mNetConfigs[newNetType].isDefault()) {
2087             if (mActiveDefaultNetwork != -1 && mActiveDefaultNetwork != newNetType) {
2088                 if (isNewNetTypePreferredOverCurrentNetType(newNetType)) {
2089                     // tear down the other
2090                     NetworkStateTracker otherNet =
2091                             mNetTrackers[mActiveDefaultNetwork];
2092                     if (DBG) {
2093                         log("Policy requires " + otherNet.getNetworkInfo().getTypeName() +
2094                             " teardown");
2095                     }
2096                     if (!teardown(otherNet)) {
2097                         loge("Network declined teardown request");
2098                         teardown(thisNet);
2099                         return;
2100                     }
2101                 } else {
2102                        // don't accept this one
2103                         if (VDBG) {
2104                             log("Not broadcasting CONNECT_ACTION " +
2105                                 "to torn down network " + info.getTypeName());
2106                         }
2107                         teardown(thisNet);
2108                         return;
2109                 }
2110             }
2111             synchronized (ConnectivityService.this) {
2112                 // have a new default network, release the transition wakelock in a second
2113                 // if it's held.  The second pause is to allow apps to reconnect over the
2114                 // new network
2115                 if (mNetTransitionWakeLock.isHeld()) {
2116                     mHandler.sendMessageDelayed(mHandler.obtainMessage(
2117                             EVENT_CLEAR_NET_TRANSITION_WAKELOCK,
2118                             mNetTransitionWakeLockSerialNumber, 0),
2119                             1000);
2120                 }
2121             }
2122             mActiveDefaultNetwork = newNetType;
2123             // this will cause us to come up initially as unconnected and switching
2124             // to connected after our normal pause unless somebody reports us as reall
2125             // disconnected
2126             mDefaultInetConditionPublished = 0;
2127             mDefaultConnectionSequence++;
2128             mInetConditionChangeInFlight = false;
2129             // Don't do this - if we never sign in stay, grey
2130             //reportNetworkCondition(mActiveDefaultNetwork, 100);
2131         }
2132         thisNet.setTeardownRequested(false);
2133         updateNetworkSettings(thisNet);
2134         handleConnectivityChange(newNetType, false);
2135         sendConnectedBroadcastDelayed(info, getConnectivityChangeDelay());
2136
2137         // notify battery stats service about this network
2138         if (thisIface != null) {
2139             try {
2140                 BatteryStatsService.getService().noteNetworkInterfaceType(thisIface, newNetType);
2141             } catch (RemoteException e) {
2142                 // ignored; service lives in system_server
2143             }
2144         }
2145     }
2146
2147     private void handleCaptivePortalTrackerCheck(NetworkInfo info) {
2148         if (DBG) log("Captive portal check " + info);
2149         int type = info.getType();
2150         final NetworkStateTracker thisNet = mNetTrackers[type];
2151         if (mNetConfigs[type].isDefault()) {
2152             if (mActiveDefaultNetwork != -1 && mActiveDefaultNetwork != type) {
2153                 if (isNewNetTypePreferredOverCurrentNetType(type)) {
2154                     if (DBG) log("Captive check on " + info.getTypeName());
2155                     mCaptivePortalTracker.detectCaptivePortal(new NetworkInfo(info));
2156                     return;
2157                 } else {
2158                     if (DBG) log("Tear down low priority net " + info.getTypeName());
2159                     teardown(thisNet);
2160                     return;
2161                 }
2162             }
2163         }
2164
2165         thisNet.captivePortalCheckComplete();
2166     }
2167
2168     /** @hide */
2169     public void captivePortalCheckComplete(NetworkInfo info) {
2170         enforceConnectivityInternalPermission();
2171         mNetTrackers[info.getType()].captivePortalCheckComplete();
2172     }
2173
2174     /**
2175      * Setup data activity tracking for the given network interface.
2176      *
2177      * Every {@code setupDataActivityTracking} should be paired with a
2178      * {@link removeDataActivityTracking} for cleanup.
2179      */
2180     private void setupDataActivityTracking(int type) {
2181         final NetworkStateTracker thisNet = mNetTrackers[type];
2182         final String iface = thisNet.getLinkProperties().getInterfaceName();
2183
2184         final int timeout;
2185
2186         if (ConnectivityManager.isNetworkTypeMobile(type)) {
2187             timeout = Settings.Global.getInt(mContext.getContentResolver(),
2188                                              Settings.Global.DATA_ACTIVITY_TIMEOUT_MOBILE,
2189                                              0);
2190             // Canonicalize mobile network type
2191             type = ConnectivityManager.TYPE_MOBILE;
2192         } else if (ConnectivityManager.TYPE_WIFI == type) {
2193             timeout = Settings.Global.getInt(mContext.getContentResolver(),
2194                                              Settings.Global.DATA_ACTIVITY_TIMEOUT_WIFI,
2195                                              0);
2196         } else {
2197             // do not track any other networks
2198             timeout = 0;
2199         }
2200
2201         if (timeout > 0 && iface != null) {
2202             try {
2203                 mNetd.addIdleTimer(iface, timeout, Integer.toString(type));
2204             } catch (RemoteException e) {
2205             }
2206         }
2207     }
2208
2209     /**
2210      * Remove data activity tracking when network disconnects.
2211      */
2212     private void removeDataActivityTracking(int type) {
2213         final NetworkStateTracker net = mNetTrackers[type];
2214         final String iface = net.getLinkProperties().getInterfaceName();
2215
2216         if (iface != null && (ConnectivityManager.isNetworkTypeMobile(type) ||
2217                               ConnectivityManager.TYPE_WIFI == type)) {
2218             try {
2219                 // the call fails silently if no idletimer setup for this interface
2220                 mNetd.removeIdleTimer(iface);
2221             } catch (RemoteException e) {
2222             }
2223         }
2224     }
2225
2226     /**
2227      * After a change in the connectivity state of a network. We're mainly
2228      * concerned with making sure that the list of DNS servers is set up
2229      * according to which networks are connected, and ensuring that the
2230      * right routing table entries exist.
2231      */
2232     private void handleConnectivityChange(int netType, boolean doReset) {
2233         int resetMask = doReset ? NetworkUtils.RESET_ALL_ADDRESSES : 0;
2234
2235         /*
2236          * If a non-default network is enabled, add the host routes that
2237          * will allow it's DNS servers to be accessed.
2238          */
2239         handleDnsConfigurationChange(netType);
2240
2241         LinkProperties curLp = mCurrentLinkProperties[netType];
2242         LinkProperties newLp = null;
2243
2244         if (mNetTrackers[netType].getNetworkInfo().isConnected()) {
2245             newLp = mNetTrackers[netType].getLinkProperties();
2246             if (VDBG) {
2247                 log("handleConnectivityChange: changed linkProperty[" + netType + "]:" +
2248                         " doReset=" + doReset + " resetMask=" + resetMask +
2249                         "\n   curLp=" + curLp +
2250                         "\n   newLp=" + newLp);
2251             }
2252
2253             if (curLp != null) {
2254                 if (curLp.isIdenticalInterfaceName(newLp)) {
2255                     CompareResult<LinkAddress> car = curLp.compareAddresses(newLp);
2256                     if ((car.removed.size() != 0) || (car.added.size() != 0)) {
2257                         for (LinkAddress linkAddr : car.removed) {
2258                             if (linkAddr.getAddress() instanceof Inet4Address) {
2259                                 resetMask |= NetworkUtils.RESET_IPV4_ADDRESSES;
2260                             }
2261                             if (linkAddr.getAddress() instanceof Inet6Address) {
2262                                 resetMask |= NetworkUtils.RESET_IPV6_ADDRESSES;
2263                             }
2264                         }
2265                         if (DBG) {
2266                             log("handleConnectivityChange: addresses changed" +
2267                                     " linkProperty[" + netType + "]:" + " resetMask=" + resetMask +
2268                                     "\n   car=" + car);
2269                         }
2270                     } else {
2271                         if (DBG) {
2272                             log("handleConnectivityChange: address are the same reset per doReset" +
2273                                    " linkProperty[" + netType + "]:" +
2274                                    " resetMask=" + resetMask);
2275                         }
2276                     }
2277                 } else {
2278                     resetMask = NetworkUtils.RESET_ALL_ADDRESSES;
2279                     if (DBG) {
2280                         log("handleConnectivityChange: interface not not equivalent reset both" +
2281                                 " linkProperty[" + netType + "]:" +
2282                                 " resetMask=" + resetMask);
2283                     }
2284                 }
2285             }
2286             if (mNetConfigs[netType].isDefault()) {
2287                 handleApplyDefaultProxy(newLp.getHttpProxy());
2288             }
2289         } else {
2290             if (VDBG) {
2291                 log("handleConnectivityChange: changed linkProperty[" + netType + "]:" +
2292                         " doReset=" + doReset + " resetMask=" + resetMask +
2293                         "\n  curLp=" + curLp +
2294                         "\n  newLp= null");
2295             }
2296         }
2297         mCurrentLinkProperties[netType] = newLp;
2298         boolean resetDns = updateRoutes(newLp, curLp, mNetConfigs[netType].isDefault());
2299
2300         if (resetMask != 0 || resetDns) {
2301             if (curLp != null) {
2302                 for (String iface : curLp.getAllInterfaceNames()) {
2303                     if (TextUtils.isEmpty(iface) == false) {
2304                         if (resetMask != 0) {
2305                             if (DBG) log("resetConnections(" + iface + ", " + resetMask + ")");
2306                             NetworkUtils.resetConnections(iface, resetMask);
2307
2308                             // Tell VPN the interface is down. It is a temporary
2309                             // but effective fix to make VPN aware of the change.
2310                             if ((resetMask & NetworkUtils.RESET_IPV4_ADDRESSES) != 0) {
2311                                 mVpn.interfaceStatusChanged(iface, false);
2312                             }
2313                         }
2314                         if (resetDns) {
2315                             flushVmDnsCache();
2316                             if (VDBG) log("resetting DNS cache for " + iface);
2317                             try {
2318                                 mNetd.flushInterfaceDnsCache(iface);
2319                             } catch (Exception e) {
2320                                 // never crash - catch them all
2321                                 if (DBG) loge("Exception resetting dns cache: " + e);
2322                             }
2323                         }
2324                     } else {
2325                         loge("Can't reset connection for type "+netType);
2326                     }
2327                 }
2328             }
2329         }
2330
2331         // Update 464xlat state.
2332         NetworkStateTracker tracker = mNetTrackers[netType];
2333         if (mClat.requiresClat(netType, tracker)) {
2334             // If the connection was previously using clat, but is not using it now, stop the clat
2335             // daemon. Normally, this happens automatically when the connection disconnects, but if
2336             // the disconnect is not reported, or if the connection's LinkProperties changed for
2337             // some other reason (e.g., handoff changes the IP addresses on the link), it would
2338             // still be running. If it's not running, then stopping it is a no-op.
2339             if (Nat464Xlat.isRunningClat(curLp) && !Nat464Xlat.isRunningClat(newLp)) {
2340                 mClat.stopClat();
2341             }
2342             // If the link requires clat to be running, then start the daemon now.
2343             if (mNetTrackers[netType].getNetworkInfo().isConnected()) {
2344                 mClat.startClat(tracker);
2345             } else {
2346                 mClat.stopClat();
2347             }
2348         }
2349
2350         // TODO: Temporary notifying upstread change to Tethering.
2351         //       @see bug/4455071
2352         /** Notify TetheringService if interface name has been changed. */
2353         if (TextUtils.equals(mNetTrackers[netType].getNetworkInfo().getReason(),
2354                              PhoneConstants.REASON_LINK_PROPERTIES_CHANGED)) {
2355             if (isTetheringSupported()) {
2356                 mTethering.handleTetherIfaceChange();
2357             }
2358         }
2359     }
2360
2361     /**
2362      * Add and remove routes using the old properties (null if not previously connected),
2363      * new properties (null if becoming disconnected).  May even be double null, which
2364      * is a noop.
2365      * Uses isLinkDefault to determine if default routes should be set or conversely if
2366      * host routes should be set to the dns servers
2367      * returns a boolean indicating the routes changed
2368      */
2369     private boolean updateRoutes(LinkProperties newLp, LinkProperties curLp,
2370             boolean isLinkDefault) {
2371         Collection<RouteInfo> routesToAdd = null;
2372         CompareResult<InetAddress> dnsDiff = new CompareResult<InetAddress>();
2373         CompareResult<RouteInfo> routeDiff = new CompareResult<RouteInfo>();
2374         if (curLp != null) {
2375             // check for the delta between the current set and the new
2376             routeDiff = curLp.compareRoutes(newLp);
2377             dnsDiff = curLp.compareDnses(newLp);
2378         } else if (newLp != null) {
2379             routeDiff.added = newLp.getAllRoutes();
2380             dnsDiff.added = newLp.getDnses();
2381         }
2382
2383         boolean routesChanged = (routeDiff.removed.size() != 0 || routeDiff.added.size() != 0);
2384
2385         for (RouteInfo r : routeDiff.removed) {
2386             if (isLinkDefault || ! r.isDefaultRoute()) {
2387                 removeRoute(curLp, r, TO_DEFAULT_TABLE);
2388             }
2389             if (isLinkDefault == false) {
2390                 // remove from a secondary route table
2391                 removeRoute(curLp, r, TO_SECONDARY_TABLE);
2392             }
2393         }
2394
2395         if (!isLinkDefault) {
2396             // handle DNS routes
2397             if (routesChanged) {
2398                 // routes changed - remove all old dns entries and add new
2399                 if (curLp != null) {
2400                     for (InetAddress oldDns : curLp.getDnses()) {
2401                         removeRouteToAddress(curLp, oldDns);
2402                     }
2403                 }
2404                 if (newLp != null) {
2405                     for (InetAddress newDns : newLp.getDnses()) {
2406                         addRouteToAddress(newLp, newDns);
2407                     }
2408                 }
2409             } else {
2410                 // no change in routes, check for change in dns themselves
2411                 for (InetAddress oldDns : dnsDiff.removed) {
2412                     removeRouteToAddress(curLp, oldDns);
2413                 }
2414                 for (InetAddress newDns : dnsDiff.added) {
2415                     addRouteToAddress(newLp, newDns);
2416                 }
2417             }
2418         }
2419
2420         for (RouteInfo r :  routeDiff.added) {
2421             if (isLinkDefault || ! r.isDefaultRoute()) {
2422                 addRoute(newLp, r, TO_DEFAULT_TABLE);
2423             } else {
2424                 // add to a secondary route table
2425                 addRoute(newLp, r, TO_SECONDARY_TABLE);
2426
2427                 // many radios add a default route even when we don't want one.
2428                 // remove the default route unless somebody else has asked for it
2429                 String ifaceName = newLp.getInterfaceName();
2430                 if (TextUtils.isEmpty(ifaceName) == false && mAddedRoutes.contains(r) == false) {
2431                     if (VDBG) log("Removing " + r + " for interface " + ifaceName);
2432                     try {
2433                         mNetd.removeRoute(ifaceName, r);
2434                     } catch (Exception e) {
2435                         // never crash - catch them all
2436                         if (DBG) loge("Exception trying to remove a route: " + e);
2437                     }
2438                 }
2439             }
2440         }
2441
2442         return routesChanged;
2443     }
2444
2445
2446    /**
2447      * Reads the network specific TCP buffer sizes from SystemProperties
2448      * net.tcp.buffersize.[default|wifi|umts|edge|gprs] and set them for system
2449      * wide use
2450      */
2451    private void updateNetworkSettings(NetworkStateTracker nt) {
2452         String key = nt.getTcpBufferSizesPropName();
2453         String bufferSizes = key == null ? null : SystemProperties.get(key);
2454
2455         if (TextUtils.isEmpty(bufferSizes)) {
2456             if (VDBG) log(key + " not found in system properties. Using defaults");
2457
2458             // Setting to default values so we won't be stuck to previous values
2459             key = "net.tcp.buffersize.default";
2460             bufferSizes = SystemProperties.get(key);
2461         }
2462
2463         // Set values in kernel
2464         if (bufferSizes.length() != 0) {
2465             if (VDBG) {
2466                 log("Setting TCP values: [" + bufferSizes
2467                         + "] which comes from [" + key + "]");
2468             }
2469             setBufferSize(bufferSizes);
2470         }
2471     }
2472
2473    /**
2474      * Writes TCP buffer sizes to /sys/kernel/ipv4/tcp_[r/w]mem_[min/def/max]
2475      * which maps to /proc/sys/net/ipv4/tcp_rmem and tcpwmem
2476      *
2477      * @param bufferSizes in the format of "readMin, readInitial, readMax,
2478      *        writeMin, writeInitial, writeMax"
2479      */
2480     private void setBufferSize(String bufferSizes) {
2481         try {
2482             String[] values = bufferSizes.split(",");
2483
2484             if (values.length == 6) {
2485               final String prefix = "/sys/kernel/ipv4/tcp_";
2486                 FileUtils.stringToFile(prefix + "rmem_min", values[0]);
2487                 FileUtils.stringToFile(prefix + "rmem_def", values[1]);
2488                 FileUtils.stringToFile(prefix + "rmem_max", values[2]);
2489                 FileUtils.stringToFile(prefix + "wmem_min", values[3]);
2490                 FileUtils.stringToFile(prefix + "wmem_def", values[4]);
2491                 FileUtils.stringToFile(prefix + "wmem_max", values[5]);
2492             } else {
2493                 loge("Invalid buffersize string: " + bufferSizes);
2494             }
2495         } catch (IOException e) {
2496             loge("Can't set tcp buffer sizes:" + e);
2497         }
2498     }
2499
2500     /**
2501      * Adjust the per-process dns entries (net.dns<x>.<pid>) based
2502      * on the highest priority active net which this process requested.
2503      * If there aren't any, clear it out
2504      */
2505     private void reassessPidDns(int pid, boolean doBump)
2506     {
2507         if (VDBG) log("reassessPidDns for pid " + pid);
2508         Integer myPid = new Integer(pid);
2509         for(int i : mPriorityList) {
2510             if (mNetConfigs[i].isDefault()) {
2511                 continue;
2512             }
2513             NetworkStateTracker nt = mNetTrackers[i];
2514             if (nt.getNetworkInfo().isConnected() &&
2515                     !nt.isTeardownRequested()) {
2516                 LinkProperties p = nt.getLinkProperties();
2517                 if (p == null) continue;
2518                 if (mNetRequestersPids[i].contains(myPid)) {
2519                     try {
2520                         mNetd.setDnsInterfaceForPid(p.getInterfaceName(), pid);
2521                     } catch (Exception e) {
2522                         Slog.e(TAG, "exception reasseses pid dns: " + e);
2523                     }
2524                     return;
2525                 }
2526            }
2527         }
2528         // nothing found - delete
2529         try {
2530             mNetd.clearDnsInterfaceForPid(pid);
2531         } catch (Exception e) {
2532             Slog.e(TAG, "exception clear interface from pid: " + e);
2533         }
2534     }
2535
2536     private void flushVmDnsCache() {
2537         /*
2538          * Tell the VMs to toss their DNS caches
2539          */
2540         Intent intent = new Intent(Intent.ACTION_CLEAR_DNS_CACHE);
2541         intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
2542         /*
2543          * Connectivity events can happen before boot has completed ...
2544          */
2545         intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
2546         final long ident = Binder.clearCallingIdentity();
2547         try {
2548             mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
2549         } finally {
2550             Binder.restoreCallingIdentity(ident);
2551         }
2552     }
2553
2554     // Caller must grab mDnsLock.
2555     private void updateDnsLocked(String network, String iface,
2556             Collection<InetAddress> dnses, String domains) {
2557         int last = 0;
2558         if (dnses.size() == 0 && mDefaultDns != null) {
2559             dnses = new ArrayList();
2560             dnses.add(mDefaultDns);
2561             if (DBG) {
2562                 loge("no dns provided for " + network + " - using " + mDefaultDns.getHostAddress());
2563             }
2564         }
2565
2566         try {
2567             mNetd.setDnsServersForInterface(iface, NetworkUtils.makeStrings(dnses), domains);
2568             mNetd.setDefaultInterfaceForDns(iface);
2569             for (InetAddress dns : dnses) {
2570                 ++last;
2571                 String key = "net.dns" + last;
2572                 String value = dns.getHostAddress();
2573                 SystemProperties.set(key, value);
2574             }
2575             for (int i = last + 1; i <= mNumDnsEntries; ++i) {
2576                 String key = "net.dns" + i;
2577                 SystemProperties.set(key, "");
2578             }
2579             mNumDnsEntries = last;
2580         } catch (Exception e) {
2581             if (DBG) loge("exception setting default dns interface: " + e);
2582         }
2583     }
2584
2585     private void handleDnsConfigurationChange(int netType) {
2586         // add default net's dns entries
2587         NetworkStateTracker nt = mNetTrackers[netType];
2588         if (nt != null && nt.getNetworkInfo().isConnected() && !nt.isTeardownRequested()) {
2589             LinkProperties p = nt.getLinkProperties();
2590             if (p == null) return;
2591             Collection<InetAddress> dnses = p.getDnses();
2592             if (mNetConfigs[netType].isDefault()) {
2593                 String network = nt.getNetworkInfo().getTypeName();
2594                 synchronized (mDnsLock) {
2595                     if (!mDnsOverridden) {
2596                         updateDnsLocked(network, p.getInterfaceName(), dnses, p.getDomains());
2597                     }
2598                 }
2599             } else {
2600                 try {
2601                     mNetd.setDnsServersForInterface(p.getInterfaceName(),
2602                             NetworkUtils.makeStrings(dnses), p.getDomains());
2603                 } catch (Exception e) {
2604                     if (DBG) loge("exception setting dns servers: " + e);
2605                 }
2606                 // set per-pid dns for attached secondary nets
2607                 List<Integer> pids = mNetRequestersPids[netType];
2608                 for (Integer pid : pids) {
2609                     try {
2610                         mNetd.setDnsInterfaceForPid(p.getInterfaceName(), pid);
2611                     } catch (Exception e) {
2612                         Slog.e(TAG, "exception setting interface for pid: " + e);
2613                     }
2614                 }
2615             }
2616             flushVmDnsCache();
2617         }
2618     }
2619
2620     private int getRestoreDefaultNetworkDelay(int networkType) {
2621         String restoreDefaultNetworkDelayStr = SystemProperties.get(
2622                 NETWORK_RESTORE_DELAY_PROP_NAME);
2623         if(restoreDefaultNetworkDelayStr != null &&
2624                 restoreDefaultNetworkDelayStr.length() != 0) {
2625             try {
2626                 return Integer.valueOf(restoreDefaultNetworkDelayStr);
2627             } catch (NumberFormatException e) {
2628             }
2629         }
2630         // if the system property isn't set, use the value for the apn type
2631         int ret = RESTORE_DEFAULT_NETWORK_DELAY;
2632
2633         if ((networkType <= ConnectivityManager.MAX_NETWORK_TYPE) &&
2634                 (mNetConfigs[networkType] != null)) {
2635             ret = mNetConfigs[networkType].restoreTime;
2636         }
2637         return ret;
2638     }
2639
2640     @Override
2641     protected void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
2642         final IndentingPrintWriter pw = new IndentingPrintWriter(writer, "  ");
2643         if (mContext.checkCallingOrSelfPermission(
2644                 android.Manifest.permission.DUMP)
2645                 != PackageManager.PERMISSION_GRANTED) {
2646             pw.println("Permission Denial: can't dump ConnectivityService " +
2647                     "from from pid=" + Binder.getCallingPid() + ", uid=" +
2648                     Binder.getCallingUid());
2649             return;
2650         }
2651
2652         // TODO: add locking to get atomic snapshot
2653         pw.println();
2654         for (int i = 0; i < mNetTrackers.length; i++) {
2655             final NetworkStateTracker nst = mNetTrackers[i];
2656             if (nst != null) {
2657                 pw.println("NetworkStateTracker for " + getNetworkTypeName(i) + ":");
2658                 pw.increaseIndent();
2659                 if (nst.getNetworkInfo().isConnected()) {
2660                     pw.println("Active network: " + nst.getNetworkInfo().
2661                             getTypeName());
2662                 }
2663                 pw.println(nst.getNetworkInfo());
2664                 pw.println(nst.getLinkProperties());
2665                 pw.println(nst);
2666                 pw.println();
2667                 pw.decreaseIndent();
2668             }
2669         }
2670
2671         pw.println("Network Requester Pids:");
2672         pw.increaseIndent();
2673         for (int net : mPriorityList) {
2674             String pidString = net + ": ";
2675             for (Integer pid : mNetRequestersPids[net]) {
2676                 pidString = pidString + pid.toString() + ", ";
2677             }
2678             pw.println(pidString);
2679         }
2680         pw.println();
2681         pw.decreaseIndent();
2682
2683         pw.println("FeatureUsers:");
2684         pw.increaseIndent();
2685         for (Object requester : mFeatureUsers) {
2686             pw.println(requester.toString());
2687         }
2688         pw.println();
2689         pw.decreaseIndent();
2690
2691         synchronized (this) {
2692             pw.println("NetworkTranstionWakeLock is currently " +
2693                     (mNetTransitionWakeLock.isHeld() ? "" : "not ") + "held.");
2694             pw.println("It was last requested for "+mNetTransitionWakeLockCausedBy);
2695         }
2696         pw.println();
2697
2698         mTethering.dump(fd, pw, args);
2699
2700         if (mInetLog != null) {
2701             pw.println();
2702             pw.println("Inet condition reports:");
2703             pw.increaseIndent();
2704             for(int i = 0; i < mInetLog.size(); i++) {
2705                 pw.println(mInetLog.get(i));
2706             }
2707             pw.decreaseIndent();
2708         }
2709     }
2710
2711     // must be stateless - things change under us.
2712     private class NetworkStateTrackerHandler extends Handler {
2713         public NetworkStateTrackerHandler(Looper looper) {
2714             super(looper);
2715         }
2716
2717         @Override
2718         public void handleMessage(Message msg) {
2719             NetworkInfo info;
2720             switch (msg.what) {
2721                 case NetworkStateTracker.EVENT_STATE_CHANGED:
2722                     info = (NetworkInfo) msg.obj;
2723                     int type = info.getType();
2724                     NetworkInfo.State state = info.getState();
2725
2726                     if (VDBG || (state == NetworkInfo.State.CONNECTED) ||
2727                             (state == NetworkInfo.State.DISCONNECTED)) {
2728                         log("ConnectivityChange for " +
2729                             info.getTypeName() + ": " +
2730                             state + "/" + info.getDetailedState());
2731                     }
2732
2733                     EventLogTags.writeConnectivityStateChanged(
2734                             info.getType(), info.getSubtype(), info.getDetailedState().ordinal());
2735
2736                     if (info.getDetailedState() ==
2737                             NetworkInfo.DetailedState.FAILED) {
2738                         handleConnectionFailure(info);
2739                     } else if (info.getDetailedState() ==
2740                             DetailedState.CAPTIVE_PORTAL_CHECK) {
2741                         handleCaptivePortalTrackerCheck(info);
2742                     } else if (state == NetworkInfo.State.DISCONNECTED) {
2743                         handleDisconnect(info);
2744                     } else if (state == NetworkInfo.State.SUSPENDED) {
2745                         // TODO: need to think this over.
2746                         // the logic here is, handle SUSPENDED the same as
2747                         // DISCONNECTED. The only difference being we are
2748                         // broadcasting an intent with NetworkInfo that's
2749                         // suspended. This allows the applications an
2750                         // opportunity to handle DISCONNECTED and SUSPENDED
2751                         // differently, or not.
2752                         handleDisconnect(info);
2753                     } else if (state == NetworkInfo.State.CONNECTED) {
2754                         handleConnect(info);
2755                     }
2756                     if (mLockdownTracker != null) {
2757                         mLockdownTracker.onNetworkInfoChanged(info);
2758                     }
2759                     break;
2760                 case NetworkStateTracker.EVENT_CONFIGURATION_CHANGED:
2761                     info = (NetworkInfo) msg.obj;
2762                     // TODO: Temporary allowing network configuration
2763                     //       change not resetting sockets.
2764                     //       @see bug/4455071
2765                     handleConnectivityChange(info.getType(), false);
2766                     break;
2767                 case NetworkStateTracker.EVENT_NETWORK_SUBTYPE_CHANGED:
2768                     info = (NetworkInfo) msg.obj;
2769                     type = info.getType();
2770                     updateNetworkSettings(mNetTrackers[type]);
2771                     break;
2772             }
2773         }
2774     }
2775
2776     private class InternalHandler extends Handler {
2777         public InternalHandler(Looper looper) {
2778             super(looper);
2779         }
2780
2781         @Override
2782         public void handleMessage(Message msg) {
2783             NetworkInfo info;
2784             switch (msg.what) {
2785                 case EVENT_CLEAR_NET_TRANSITION_WAKELOCK:
2786                     String causedBy = null;
2787                     synchronized (ConnectivityService.this) {
2788                         if (msg.arg1 == mNetTransitionWakeLockSerialNumber &&
2789                                 mNetTransitionWakeLock.isHeld()) {
2790                             mNetTransitionWakeLock.release();
2791                             causedBy = mNetTransitionWakeLockCausedBy;
2792                         }
2793                     }
2794                     if (causedBy != null) {
2795                         log("NetTransition Wakelock for " + causedBy + " released by timeout");
2796                     }
2797                     break;
2798                 case EVENT_RESTORE_DEFAULT_NETWORK:
2799                     FeatureUser u = (FeatureUser)msg.obj;
2800                     u.expire();
2801                     break;
2802                 case EVENT_INET_CONDITION_CHANGE:
2803                 {
2804                     int netType = msg.arg1;
2805                     int condition = msg.arg2;
2806                     handleInetConditionChange(netType, condition);
2807                     break;
2808                 }
2809                 case EVENT_INET_CONDITION_HOLD_END:
2810                 {
2811                     int netType = msg.arg1;
2812                     int sequence = msg.arg2;
2813                     handleInetConditionHoldEnd(netType, sequence);
2814                     break;
2815                 }
2816                 case EVENT_SET_NETWORK_PREFERENCE:
2817                 {
2818                     int preference = msg.arg1;
2819                     handleSetNetworkPreference(preference);
2820                     break;
2821                 }
2822                 case EVENT_SET_MOBILE_DATA:
2823                 {
2824                     boolean enabled = (msg.arg1 == ENABLED);
2825                     handleSetMobileData(enabled);
2826                     break;
2827                 }
2828                 case EVENT_APPLY_GLOBAL_HTTP_PROXY:
2829                 {
2830                     handleDeprecatedGlobalHttpProxy();
2831                     break;
2832                 }
2833                 case EVENT_SET_DEPENDENCY_MET:
2834                 {
2835                     boolean met = (msg.arg1 == ENABLED);
2836                     handleSetDependencyMet(msg.arg2, met);
2837                     break;
2838                 }
2839                 case EVENT_RESTORE_DNS:
2840                 {
2841                     if (mActiveDefaultNetwork != -1) {
2842                         handleDnsConfigurationChange(mActiveDefaultNetwork);
2843                     }
2844                     break;
2845                 }
2846                 case EVENT_SEND_STICKY_BROADCAST_INTENT:
2847                 {
2848                     Intent intent = (Intent)msg.obj;
2849                     sendStickyBroadcast(intent);
2850                     break;
2851                 }
2852                 case EVENT_SET_POLICY_DATA_ENABLE: {
2853                     final int networkType = msg.arg1;
2854                     final boolean enabled = msg.arg2 == ENABLED;
2855                     handleSetPolicyDataEnable(networkType, enabled);
2856                     break;
2857                 }
2858                 case EVENT_VPN_STATE_CHANGED: {
2859                     if (mLockdownTracker != null) {
2860                         mLockdownTracker.onVpnStateChanged((NetworkInfo) msg.obj);
2861                     }
2862                     break;
2863                 }
2864                 case EVENT_ENABLE_FAIL_FAST_MOBILE_DATA: {
2865                     int tag = mEnableFailFastMobileDataTag.get();
2866                     if (msg.arg1 == tag) {
2867                         MobileDataStateTracker mobileDst =
2868                             (MobileDataStateTracker) mNetTrackers[ConnectivityManager.TYPE_MOBILE];
2869                         if (mobileDst != null) {
2870                             mobileDst.setEnableFailFastMobileData(msg.arg2);
2871                         }
2872                     } else {
2873                         log("EVENT_ENABLE_FAIL_FAST_MOBILE_DATA: stale arg1:" + msg.arg1
2874                                 + " != tag:" + tag);
2875                     }
2876                 }
2877             }
2878         }
2879     }
2880
2881     // javadoc from interface
2882     public int tether(String iface) {
2883         enforceTetherChangePermission();
2884
2885         if (isTetheringSupported()) {
2886             return mTethering.tether(iface);
2887         } else {
2888             return ConnectivityManager.TETHER_ERROR_UNSUPPORTED;
2889         }
2890     }
2891
2892     // javadoc from interface
2893     public int untether(String iface) {
2894         enforceTetherChangePermission();
2895
2896         if (isTetheringSupported()) {
2897             return mTethering.untether(iface);
2898         } else {
2899             return ConnectivityManager.TETHER_ERROR_UNSUPPORTED;
2900         }
2901     }
2902
2903     // javadoc from interface
2904     public int getLastTetherError(String iface) {
2905         enforceTetherAccessPermission();
2906
2907         if (isTetheringSupported()) {
2908             return mTethering.getLastTetherError(iface);
2909         } else {
2910             return ConnectivityManager.TETHER_ERROR_UNSUPPORTED;
2911         }
2912     }
2913
2914     // TODO - proper iface API for selection by property, inspection, etc
2915     public String[] getTetherableUsbRegexs() {
2916         enforceTetherAccessPermission();
2917         if (isTetheringSupported()) {
2918             return mTethering.getTetherableUsbRegexs();
2919         } else {
2920             return new String[0];
2921         }
2922     }
2923
2924     public String[] getTetherableWifiRegexs() {
2925         enforceTetherAccessPermission();
2926         if (isTetheringSupported()) {
2927             return mTethering.getTetherableWifiRegexs();
2928         } else {
2929             return new String[0];
2930         }
2931     }
2932
2933     public String[] getTetherableBluetoothRegexs() {
2934         enforceTetherAccessPermission();
2935         if (isTetheringSupported()) {
2936             return mTethering.getTetherableBluetoothRegexs();
2937         } else {
2938             return new String[0];
2939         }
2940     }
2941
2942     public int setUsbTethering(boolean enable) {
2943         enforceTetherChangePermission();
2944         if (isTetheringSupported()) {
2945             return mTethering.setUsbTethering(enable);
2946         } else {
2947             return ConnectivityManager.TETHER_ERROR_UNSUPPORTED;
2948         }
2949     }
2950
2951     // TODO - move iface listing, queries, etc to new module
2952     // javadoc from interface
2953     public String[] getTetherableIfaces() {
2954         enforceTetherAccessPermission();
2955         return mTethering.getTetherableIfaces();
2956     }
2957
2958     public String[] getTetheredIfaces() {
2959         enforceTetherAccessPermission();
2960         return mTethering.getTetheredIfaces();
2961     }
2962
2963     @Override
2964     public String[] getTetheredIfacePairs() {
2965         enforceTetherAccessPermission();
2966         return mTethering.getTetheredIfacePairs();
2967     }
2968
2969     public String[] getTetheringErroredIfaces() {
2970         enforceTetherAccessPermission();
2971         return mTethering.getErroredIfaces();
2972     }
2973
2974     // if ro.tether.denied = true we default to no tethering
2975     // gservices could set the secure setting to 1 though to enable it on a build where it
2976     // had previously been turned off.
2977     public boolean isTetheringSupported() {
2978         enforceTetherAccessPermission();
2979         int defaultVal = (SystemProperties.get("ro.tether.denied").equals("true") ? 0 : 1);
2980         boolean tetherEnabledInSettings = (Settings.Global.getInt(mContext.getContentResolver(),
2981                 Settings.Global.TETHER_SUPPORTED, defaultVal) != 0);
2982         return tetherEnabledInSettings && mTetheringConfigValid;
2983     }
2984
2985     // An API NetworkStateTrackers can call when they lose their network.
2986     // This will automatically be cleared after X seconds or a network becomes CONNECTED,
2987     // whichever happens first.  The timer is started by the first caller and not
2988     // restarted by subsequent callers.
2989     public void requestNetworkTransitionWakelock(String forWhom) {
2990         enforceConnectivityInternalPermission();
2991         synchronized (this) {
2992             if (mNetTransitionWakeLock.isHeld()) return;
2993             mNetTransitionWakeLockSerialNumber++;
2994             mNetTransitionWakeLock.acquire();
2995             mNetTransitionWakeLockCausedBy = forWhom;
2996         }
2997         mHandler.sendMessageDelayed(mHandler.obtainMessage(
2998                 EVENT_CLEAR_NET_TRANSITION_WAKELOCK,
2999                 mNetTransitionWakeLockSerialNumber, 0),
3000                 mNetTransitionWakeLockTimeout);
3001         return;
3002     }
3003
3004     // 100 percent is full good, 0 is full bad.
3005     public void reportInetCondition(int networkType, int percentage) {
3006         if (VDBG) log("reportNetworkCondition(" + networkType + ", " + percentage + ")");
3007         mContext.enforceCallingOrSelfPermission(
3008                 android.Manifest.permission.STATUS_BAR,
3009                 "ConnectivityService");
3010
3011         if (DBG) {
3012             int pid = getCallingPid();
3013             int uid = getCallingUid();
3014             String s = pid + "(" + uid + ") reports inet is " +
3015                 (percentage > 50 ? "connected" : "disconnected") + " (" + percentage + ") on " +
3016                 "network Type " + networkType + " at " + GregorianCalendar.getInstance().getTime();
3017             mInetLog.add(s);
3018             while(mInetLog.size() > INET_CONDITION_LOG_MAX_SIZE) {
3019                 mInetLog.remove(0);
3020             }
3021         }
3022         mHandler.sendMessage(mHandler.obtainMessage(
3023             EVENT_INET_CONDITION_CHANGE, networkType, percentage));
3024     }
3025
3026     private void handleInetConditionChange(int netType, int condition) {
3027         if (mActiveDefaultNetwork == -1) {
3028             if (DBG) log("handleInetConditionChange: no active default network - ignore");
3029             return;
3030         }
3031         if (mActiveDefaultNetwork != netType) {
3032             if (DBG) log("handleInetConditionChange: net=" + netType +
3033                             " != default=" + mActiveDefaultNetwork + " - ignore");
3034             return;
3035         }
3036         if (VDBG) {
3037             log("handleInetConditionChange: net=" +
3038                     netType + ", condition=" + condition +
3039                     ",mActiveDefaultNetwork=" + mActiveDefaultNetwork);
3040         }
3041         mDefaultInetCondition = condition;
3042         int delay;
3043         if (mInetConditionChangeInFlight == false) {
3044             if (VDBG) log("handleInetConditionChange: starting a change hold");
3045             // setup a new hold to debounce this
3046             if (mDefaultInetCondition > 50) {
3047                 delay = Settings.Global.getInt(mContext.getContentResolver(),
3048                         Settings.Global.INET_CONDITION_DEBOUNCE_UP_DELAY, 500);
3049             } else {
3050                 delay = Settings.Global.getInt(mContext.getContentResolver(),
3051                         Settings.Global.INET_CONDITION_DEBOUNCE_DOWN_DELAY, 3000);
3052             }
3053             mInetConditionChangeInFlight = true;
3054             mHandler.sendMessageDelayed(mHandler.obtainMessage(EVENT_INET_CONDITION_HOLD_END,
3055                     mActiveDefaultNetwork, mDefaultConnectionSequence), delay);
3056         } else {
3057             // we've set the new condition, when this hold ends that will get picked up
3058             if (VDBG) log("handleInetConditionChange: currently in hold - not setting new end evt");
3059         }
3060     }
3061
3062     private void handleInetConditionHoldEnd(int netType, int sequence) {
3063         if (DBG) {
3064             log("handleInetConditionHoldEnd: net=" + netType +
3065                     ", condition=" + mDefaultInetCondition +
3066                     ", published condition=" + mDefaultInetConditionPublished);
3067         }
3068         mInetConditionChangeInFlight = false;
3069
3070         if (mActiveDefaultNetwork == -1) {
3071             if (DBG) log("handleInetConditionHoldEnd: no active default network - ignoring");
3072             return;
3073         }
3074         if (mDefaultConnectionSequence != sequence) {
3075             if (DBG) log("handleInetConditionHoldEnd: event hold for obsolete network - ignoring");
3076             return;
3077         }
3078         // TODO: Figure out why this optimization sometimes causes a
3079         //       change in mDefaultInetCondition to be missed and the
3080         //       UI to not be updated.
3081         //if (mDefaultInetConditionPublished == mDefaultInetCondition) {
3082         //    if (DBG) log("no change in condition - aborting");
3083         //    return;
3084         //}
3085         NetworkInfo networkInfo = mNetTrackers[mActiveDefaultNetwork].getNetworkInfo();
3086         if (networkInfo.isConnected() == false) {
3087             if (DBG) log("handleInetConditionHoldEnd: default network not connected - ignoring");
3088             return;
3089         }
3090         mDefaultInetConditionPublished = mDefaultInetCondition;
3091         sendInetConditionBroadcast(networkInfo);
3092         return;
3093     }
3094
3095     public ProxyProperties getProxy() {
3096         // this information is already available as a world read/writable jvm property
3097         // so this API change wouldn't have a benifit.  It also breaks the passing
3098         // of proxy info to all the JVMs.
3099         // enforceAccessPermission();
3100         synchronized (mProxyLock) {
3101             if (mGlobalProxy != null) return mGlobalProxy;
3102             return (mDefaultProxyDisabled ? null : mDefaultProxy);
3103         }
3104     }
3105
3106     public void setGlobalProxy(ProxyProperties proxyProperties) {
3107         enforceConnectivityInternalPermission();
3108         synchronized (mProxyLock) {
3109             if (proxyProperties == mGlobalProxy) return;
3110             if (proxyProperties != null && proxyProperties.equals(mGlobalProxy)) return;
3111             if (mGlobalProxy != null && mGlobalProxy.equals(proxyProperties)) return;
3112
3113             String host = "";
3114             int port = 0;
3115             String exclList = "";
3116             if (proxyProperties != null && !TextUtils.isEmpty(proxyProperties.getHost())) {
3117                 mGlobalProxy = new ProxyProperties(proxyProperties);
3118                 host = mGlobalProxy.getHost();
3119                 port = mGlobalProxy.getPort();
3120                 exclList = mGlobalProxy.getExclusionList();
3121             } else {
3122                 mGlobalProxy = null;
3123             }
3124             ContentResolver res = mContext.getContentResolver();
3125             final long token = Binder.clearCallingIdentity();
3126             try {
3127                 Settings.Global.putString(res, Settings.Global.GLOBAL_HTTP_PROXY_HOST, host);
3128                 Settings.Global.putInt(res, Settings.Global.GLOBAL_HTTP_PROXY_PORT, port);
3129                 Settings.Global.putString(res, Settings.Global.GLOBAL_HTTP_PROXY_EXCLUSION_LIST,
3130                         exclList);
3131             } finally {
3132                 Binder.restoreCallingIdentity(token);
3133             }
3134         }
3135
3136         if (mGlobalProxy == null) {
3137             proxyProperties = mDefaultProxy;
3138         }
3139         sendProxyBroadcast(proxyProperties);
3140     }
3141
3142     private void loadGlobalProxy() {
3143         ContentResolver res = mContext.getContentResolver();
3144         String host = Settings.Global.getString(res, Settings.Global.GLOBAL_HTTP_PROXY_HOST);
3145         int port = Settings.Global.getInt(res, Settings.Global.GLOBAL_HTTP_PROXY_PORT, 0);
3146         String exclList = Settings.Global.getString(res,
3147                 Settings.Global.GLOBAL_HTTP_PROXY_EXCLUSION_LIST);
3148         if (!TextUtils.isEmpty(host)) {
3149             ProxyProperties proxyProperties = new ProxyProperties(host, port, exclList);
3150             synchronized (mProxyLock) {
3151                 mGlobalProxy = proxyProperties;
3152             }
3153         }
3154     }
3155
3156     public ProxyProperties getGlobalProxy() {
3157         // this information is already available as a world read/writable jvm property
3158         // so this API change wouldn't have a benifit.  It also breaks the passing
3159         // of proxy info to all the JVMs.
3160         // enforceAccessPermission();
3161         synchronized (mProxyLock) {
3162             return mGlobalProxy;
3163         }
3164     }
3165
3166     private void handleApplyDefaultProxy(ProxyProperties proxy) {
3167         if (proxy != null && TextUtils.isEmpty(proxy.getHost())) {
3168             proxy = null;
3169         }
3170         synchronized (mProxyLock) {
3171             if (mDefaultProxy != null && mDefaultProxy.equals(proxy)) return;
3172             if (mDefaultProxy == proxy) return; // catches repeated nulls
3173             mDefaultProxy = proxy;
3174
3175             if (mGlobalProxy != null) return;
3176             if (!mDefaultProxyDisabled) {
3177                 sendProxyBroadcast(proxy);
3178             }
3179         }
3180     }
3181
3182     private void handleDeprecatedGlobalHttpProxy() {
3183         String proxy = Settings.Global.getString(mContext.getContentResolver(),
3184                 Settings.Global.HTTP_PROXY);
3185         if (!TextUtils.isEmpty(proxy)) {
3186             String data[] = proxy.split(":");
3187             String proxyHost =  data[0];
3188             int proxyPort = 8080;
3189             if (data.length > 1) {
3190                 try {
3191                     proxyPort = Integer.parseInt(data[1]);
3192                 } catch (NumberFormatException e) {
3193                     return;
3194                 }
3195             }
3196             ProxyProperties p = new ProxyProperties(data[0], proxyPort, "");
3197             setGlobalProxy(p);
3198         }
3199     }
3200
3201     private void sendProxyBroadcast(ProxyProperties proxy) {
3202         if (proxy == null) proxy = new ProxyProperties("", 0, "");
3203         if (DBG) log("sending Proxy Broadcast for " + proxy);
3204         Intent intent = new Intent(Proxy.PROXY_CHANGE_ACTION);
3205         intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING |
3206             Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
3207         intent.putExtra(Proxy.EXTRA_PROXY_INFO, proxy);
3208         final long ident = Binder.clearCallingIdentity();
3209         try {
3210             mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
3211         } finally {
3212             Binder.restoreCallingIdentity(ident);
3213         }
3214     }
3215
3216     private static class SettingsObserver extends ContentObserver {
3217         private int mWhat;
3218         private Handler mHandler;
3219         SettingsObserver(Handler handler, int what) {
3220             super(handler);
3221             mHandler = handler;
3222             mWhat = what;
3223         }
3224
3225         void observe(Context context) {
3226             ContentResolver resolver = context.getContentResolver();
3227             resolver.registerContentObserver(Settings.Global.getUriFor(
3228                     Settings.Global.HTTP_PROXY), false, this);
3229         }
3230
3231         @Override
3232         public void onChange(boolean selfChange) {
3233             mHandler.obtainMessage(mWhat).sendToTarget();
3234         }
3235     }
3236
3237     private static void log(String s) {
3238         Slog.d(TAG, s);
3239     }
3240
3241     private static void loge(String s) {
3242         Slog.e(TAG, s);
3243     }
3244
3245     int convertFeatureToNetworkType(int networkType, String feature) {
3246         int usedNetworkType = networkType;
3247
3248         if(networkType == ConnectivityManager.TYPE_MOBILE) {
3249             if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_MMS)) {
3250                 usedNetworkType = ConnectivityManager.TYPE_MOBILE_MMS;
3251             } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_SUPL)) {
3252                 usedNetworkType = ConnectivityManager.TYPE_MOBILE_SUPL;
3253             } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_DUN) ||
3254                     TextUtils.equals(feature, Phone.FEATURE_ENABLE_DUN_ALWAYS)) {
3255                 usedNetworkType = ConnectivityManager.TYPE_MOBILE_DUN;
3256             } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_HIPRI)) {
3257                 usedNetworkType = ConnectivityManager.TYPE_MOBILE_HIPRI;
3258             } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_FOTA)) {
3259                 usedNetworkType = ConnectivityManager.TYPE_MOBILE_FOTA;
3260             } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_IMS)) {
3261                 usedNetworkType = ConnectivityManager.TYPE_MOBILE_IMS;
3262             } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_CBS)) {
3263                 usedNetworkType = ConnectivityManager.TYPE_MOBILE_CBS;
3264             } else {
3265                 Slog.e(TAG, "Can't match any mobile netTracker!");
3266             }
3267         } else if (networkType == ConnectivityManager.TYPE_WIFI) {
3268             if (TextUtils.equals(feature, "p2p")) {
3269                 usedNetworkType = ConnectivityManager.TYPE_WIFI_P2P;
3270             } else {
3271                 Slog.e(TAG, "Can't match any wifi netTracker!");
3272             }
3273         } else {
3274             Slog.e(TAG, "Unexpected network type");
3275         }
3276         return usedNetworkType;
3277     }
3278
3279     private static <T> T checkNotNull(T value, String message) {
3280         if (value == null) {
3281             throw new NullPointerException(message);
3282         }
3283         return value;
3284     }
3285
3286     /**
3287      * Protect a socket from VPN routing rules. This method is used by
3288      * VpnBuilder and not available in ConnectivityManager. Permissions
3289      * are checked in Vpn class.
3290      * @hide
3291      */
3292     @Override
3293     public boolean protectVpn(ParcelFileDescriptor socket) {
3294         throwIfLockdownEnabled();
3295         try {
3296             int type = mActiveDefaultNetwork;
3297             if (ConnectivityManager.isNetworkTypeValid(type) && mNetTrackers[type] != null) {
3298                 mVpn.protect(socket, mNetTrackers[type].getLinkProperties().getInterfaceName());
3299                 return true;
3300             }
3301         } catch (Exception e) {
3302             // ignore
3303         } finally {
3304             try {
3305                 socket.close();
3306             } catch (Exception e) {
3307                 // ignore
3308             }
3309         }
3310         return false;
3311     }
3312
3313     /**
3314      * Prepare for a VPN application. This method is used by VpnDialogs
3315      * and not available in ConnectivityManager. Permissions are checked
3316      * in Vpn class.
3317      * @hide
3318      */
3319     @Override
3320     public boolean prepareVpn(String oldPackage, String newPackage) {
3321         throwIfLockdownEnabled();
3322         return mVpn.prepare(oldPackage, newPackage);
3323     }
3324
3325     /**
3326      * Configure a TUN interface and return its file descriptor. Parameters
3327      * are encoded and opaque to this class. This method is used by VpnBuilder
3328      * and not available in ConnectivityManager. Permissions are checked in
3329      * Vpn class.
3330      * @hide
3331      */
3332     @Override
3333     public ParcelFileDescriptor establishVpn(VpnConfig config) {
3334         throwIfLockdownEnabled();
3335         return mVpn.establish(config);
3336     }
3337
3338     /**
3339      * Start legacy VPN, controlling native daemons as needed. Creates a
3340      * secondary thread to perform connection work, returning quickly.
3341      */
3342     @Override
3343     public void startLegacyVpn(VpnProfile profile) {
3344         throwIfLockdownEnabled();
3345         final LinkProperties egress = getActiveLinkProperties();
3346         if (egress == null) {
3347             throw new IllegalStateException("Missing active network connection");
3348         }
3349         mVpn.startLegacyVpn(profile, mKeyStore, egress);
3350     }
3351
3352     /**
3353      * Return the information of the ongoing legacy VPN. This method is used
3354      * by VpnSettings and not available in ConnectivityManager. Permissions
3355      * are checked in Vpn class.
3356      * @hide
3357      */
3358     @Override
3359     public LegacyVpnInfo getLegacyVpnInfo() {
3360         throwIfLockdownEnabled();
3361         return mVpn.getLegacyVpnInfo();
3362     }
3363
3364     /**
3365      * Callback for VPN subsystem. Currently VPN is not adapted to the service
3366      * through NetworkStateTracker since it works differently. For example, it
3367      * needs to override DNS servers but never takes the default routes. It
3368      * relies on another data network, and it could keep existing connections
3369      * alive after reconnecting, switching between networks, or even resuming
3370      * from deep sleep. Calls from applications should be done synchronously
3371      * to avoid race conditions. As these are all hidden APIs, refactoring can
3372      * be done whenever a better abstraction is developed.
3373      */
3374     public class VpnCallback {
3375         private VpnCallback() {
3376         }
3377
3378         public void onStateChanged(NetworkInfo info) {
3379             mHandler.obtainMessage(EVENT_VPN_STATE_CHANGED, info).sendToTarget();
3380         }
3381
3382         public void override(List<String> dnsServers, List<String> searchDomains) {
3383             if (dnsServers == null) {
3384                 restore();
3385                 return;
3386             }
3387
3388             // Convert DNS servers into addresses.
3389             List<InetAddress> addresses = new ArrayList<InetAddress>();
3390             for (String address : dnsServers) {
3391                 // Double check the addresses and remove invalid ones.
3392                 try {
3393                     addresses.add(InetAddress.parseNumericAddress(address));
3394                 } catch (Exception e) {
3395                     // ignore
3396                 }
3397             }
3398             if (addresses.isEmpty()) {
3399                 restore();
3400                 return;
3401             }
3402
3403             // Concatenate search domains into a string.
3404             StringBuilder buffer = new StringBuilder();
3405             if (searchDomains != null) {
3406                 for (String domain : searchDomains) {
3407                     buffer.append(domain).append(' ');
3408                 }
3409             }
3410             String domains = buffer.toString().trim();
3411
3412             // Apply DNS changes.
3413             synchronized (mDnsLock) {
3414                 updateDnsLocked("VPN", "VPN", addresses, domains);
3415                 mDnsOverridden = true;
3416             }
3417
3418             // Temporarily disable the default proxy (not global).
3419             synchronized (mProxyLock) {
3420                 mDefaultProxyDisabled = true;
3421                 if (mGlobalProxy == null && mDefaultProxy != null) {
3422                     sendProxyBroadcast(null);
3423                 }
3424             }
3425
3426             // TODO: support proxy per network.
3427         }
3428
3429         public void restore() {
3430             synchronized (mDnsLock) {
3431                 if (mDnsOverridden) {
3432                     mDnsOverridden = false;
3433                     mHandler.sendEmptyMessage(EVENT_RESTORE_DNS);
3434                 }
3435             }
3436             synchronized (mProxyLock) {
3437                 mDefaultProxyDisabled = false;
3438                 if (mGlobalProxy == null && mDefaultProxy != null) {
3439                     sendProxyBroadcast(mDefaultProxy);
3440                 }
3441             }
3442         }
3443     }
3444
3445     @Override
3446     public boolean updateLockdownVpn() {
3447         if (Binder.getCallingUid() != Process.SYSTEM_UID) {
3448             Slog.w(TAG, "Lockdown VPN only available to AID_SYSTEM");
3449             return false;
3450         }
3451
3452         // Tear down existing lockdown if profile was removed
3453         mLockdownEnabled = LockdownVpnTracker.isEnabled();
3454         if (mLockdownEnabled) {
3455             if (!mKeyStore.isUnlocked()) {
3456                 Slog.w(TAG, "KeyStore locked; unable to create LockdownTracker");
3457                 return false;
3458             }
3459
3460             final String profileName = new String(mKeyStore.get(Credentials.LOCKDOWN_VPN));
3461             final VpnProfile profile = VpnProfile.decode(
3462                     profileName, mKeyStore.get(Credentials.VPN + profileName));
3463             setLockdownTracker(new LockdownVpnTracker(mContext, mNetd, this, mVpn, profile));
3464         } else {
3465             setLockdownTracker(null);
3466         }
3467
3468         return true;
3469     }
3470
3471     /**
3472      * Internally set new {@link LockdownVpnTracker}, shutting down any existing
3473      * {@link LockdownVpnTracker}. Can be {@code null} to disable lockdown.
3474      */
3475     private void setLockdownTracker(LockdownVpnTracker tracker) {
3476         // Shutdown any existing tracker
3477         final LockdownVpnTracker existing = mLockdownTracker;
3478         mLockdownTracker = null;
3479         if (existing != null) {
3480             existing.shutdown();
3481         }
3482
3483         try {
3484             if (tracker != null) {
3485                 mNetd.setFirewallEnabled(true);
3486                 mNetd.setFirewallInterfaceRule("lo", true);
3487                 mLockdownTracker = tracker;
3488                 mLockdownTracker.init();
3489             } else {
3490                 mNetd.setFirewallEnabled(false);
3491             }
3492         } catch (RemoteException e) {
3493             // ignored; NMS lives inside system_server
3494         }
3495     }
3496
3497     private void throwIfLockdownEnabled() {
3498         if (mLockdownEnabled) {
3499             throw new IllegalStateException("Unavailable in lockdown mode");
3500         }
3501     }
3502
3503     public void supplyMessenger(int networkType, Messenger messenger) {
3504         enforceConnectivityInternalPermission();
3505
3506         if (isNetworkTypeValid(networkType) && mNetTrackers[networkType] != null) {
3507             mNetTrackers[networkType].supplyMessenger(messenger);
3508         }
3509     }
3510
3511     public int findConnectionTypeForIface(String iface) {
3512         enforceConnectivityInternalPermission();
3513
3514         if (TextUtils.isEmpty(iface)) return ConnectivityManager.TYPE_NONE;
3515         for (NetworkStateTracker tracker : mNetTrackers) {
3516             if (tracker != null) {
3517                 LinkProperties lp = tracker.getLinkProperties();
3518                 if (lp != null && iface.equals(lp.getInterfaceName())) {
3519                     return tracker.getNetworkInfo().getType();
3520                 }
3521             }
3522         }
3523         return ConnectivityManager.TYPE_NONE;
3524     }
3525
3526     /**
3527      * Have mobile data fail fast if enabled.
3528      *
3529      * @param enabled DctConstants.ENABLED/DISABLED
3530      */
3531     private void setEnableFailFastMobileData(int enabled) {
3532         int tag;
3533
3534         if (enabled == DctConstants.ENABLED) {
3535             tag = mEnableFailFastMobileDataTag.incrementAndGet();
3536         } else {
3537             tag = mEnableFailFastMobileDataTag.get();
3538         }
3539         mHandler.sendMessage(mHandler.obtainMessage(EVENT_ENABLE_FAIL_FAST_MOBILE_DATA, tag,
3540                          enabled));
3541     }
3542
3543     @Override
3544     public int checkMobileProvisioning(boolean sendNotification, int suggestedTimeOutMs,
3545             final ResultReceiver resultReceiver) {
3546         log("checkMobileProvisioning: E sendNotification=" + sendNotification
3547                 + " suggestedTimeOutMs=" + suggestedTimeOutMs
3548                 + " resultReceiver=" + resultReceiver);
3549         enforceChangePermission();
3550
3551         int timeOutMs = suggestedTimeOutMs;
3552         if (suggestedTimeOutMs > CheckMp.MAX_TIMEOUT_MS) {
3553             timeOutMs = CheckMp.MAX_TIMEOUT_MS;
3554         }
3555
3556         final long token = Binder.clearCallingIdentity();
3557         try {
3558             CheckMp checkMp = new CheckMp(mContext, this);
3559             CheckMp.CallBack cb = new CheckMp.CallBack() {
3560                 @Override
3561                 void onComplete(Integer result) {
3562                     log("CheckMp.onComplete: result=" + result);
3563                     if (resultReceiver != null) {
3564                         log("CheckMp.onComplete: send result");
3565                         resultReceiver.send(result, null);
3566                     }
3567                     NetworkInfo ni =
3568                             mNetTrackers[ConnectivityManager.TYPE_MOBILE_HIPRI].getNetworkInfo();
3569                     switch(result) {
3570                         case ConnectivityManager.CMP_RESULT_CODE_CONNECTABLE:
3571                         case ConnectivityManager.CMP_RESULT_CODE_NO_CONNECTION: {
3572                             log("CheckMp.onComplete: ignore, connected or no connection");
3573                             break;
3574                         }
3575                         case ConnectivityManager.CMP_RESULT_CODE_REDIRECTED: {
3576                             log("CheckMp.onComplete: warm sim");
3577                             String url = getProvisioningUrl();
3578                             if (TextUtils.isEmpty(url)) {
3579                                 url = mContext.getResources()
3580                                         .getString(R.string.mobile_redirected_provisioning_url);
3581                             }
3582                             if (TextUtils.isEmpty(url) == false) {
3583                                 log("CheckMp.onComplete: warm sim (redirected), url=" + url);
3584                                 setNotificationVisible(true, ni, url);
3585                             } else {
3586                                 log("CheckMp.onComplete: warm sim (redirected), no url");
3587                             }
3588                             break;
3589                         }
3590                         case ConnectivityManager.CMP_RESULT_CODE_NO_DNS:
3591                         case ConnectivityManager.CMP_RESULT_CODE_NO_TCP_CONNECTION: {
3592                             String url = getProvisioningUrl();
3593                             if (TextUtils.isEmpty(url) == false) {
3594                                 log("CheckMp.onComplete: warm sim (no dns/tcp), url=" + url);
3595                                 setNotificationVisible(true, ni, url);
3596                             } else {
3597                                 log("CheckMp.onComplete: warm sim (no dns/tcp), no url");
3598                             }
3599                             break;
3600                         }
3601                         default: {
3602                             loge("CheckMp.onComplete: ignore unexpected result=" + result);
3603                             break;
3604                         }
3605                     }
3606                 }
3607             };
3608             CheckMp.Params params =
3609                     new CheckMp.Params(checkMp.getDefaultUrl(), timeOutMs, cb);
3610             log("checkMobileProvisioning: params=" + params);
3611             setNotificationVisible(false, null, null);
3612             checkMp.execute(params);
3613         } finally {
3614             Binder.restoreCallingIdentity(token);
3615             log("checkMobileProvisioning: X");
3616         }
3617         return timeOutMs;
3618     }
3619
3620     static class CheckMp extends
3621             AsyncTask<CheckMp.Params, Void, Integer> {
3622         private static final String CHECKMP_TAG = "CheckMp";
3623         public static final int MAX_TIMEOUT_MS =  60000;
3624         private static final int SOCKET_TIMEOUT_MS = 5000;
3625         private Context mContext;
3626         private ConnectivityService mCs;
3627         private TelephonyManager mTm;
3628         private Params mParams;
3629
3630         /**
3631          * Parameters for AsyncTask.execute
3632          */
3633         static class Params {
3634             private String mUrl;
3635             private long mTimeOutMs;
3636             private CallBack mCb;
3637
3638             Params(String url, long timeOutMs, CallBack cb) {
3639                 mUrl = url;
3640                 mTimeOutMs = timeOutMs;
3641                 mCb = cb;
3642             }
3643
3644             @Override
3645             public String toString() {
3646                 return "{" + " url=" + mUrl + " mTimeOutMs=" + mTimeOutMs + " mCb=" + mCb + "}";
3647             }
3648         }
3649
3650         /**
3651          * The call back object passed in Params. onComplete will be called
3652          * on the main thread.
3653          */
3654         abstract static class CallBack {
3655             // Called on the main thread.
3656             abstract void onComplete(Integer result);
3657         }
3658
3659         public CheckMp(Context context, ConnectivityService cs) {
3660             mContext = context;
3661             mCs = cs;
3662
3663             // Setup access to TelephonyService we'll be using.
3664             mTm = (TelephonyManager) mContext.getSystemService(
3665                     Context.TELEPHONY_SERVICE);
3666         }
3667
3668         /**
3669          * Get the default url to use for the test.
3670          */
3671         public String getDefaultUrl() {
3672             // See http://go/clientsdns for usage approval
3673             String server = Settings.Global.getString(mContext.getContentResolver(),
3674                     Settings.Global.CAPTIVE_PORTAL_SERVER);
3675             if (server == null) {
3676                 server = "clients3.google.com";
3677             }
3678             return "http://" + server + "/generate_204";
3679         }
3680
3681         /**
3682          * Detect if its possible to connect to the http url. DNS based detection techniques
3683          * do not work at all hotspots. The best way to check is to perform a request to
3684          * a known address that fetches the data we expect.
3685          */
3686         private synchronized Integer isMobileOk(Params params) {
3687             Integer result = ConnectivityManager.CMP_RESULT_CODE_NO_CONNECTION;
3688             Uri orgUri = Uri.parse(params.mUrl);
3689             Random rand = new Random();
3690             mParams = params;
3691
3692             try {
3693                 if (mCs.isNetworkSupported(ConnectivityManager.TYPE_MOBILE) == false) {
3694                     log("isMobileOk: not mobile capable");
3695                     result = ConnectivityManager.CMP_RESULT_CODE_NO_CONNECTION;
3696                     return result;
3697                 }
3698
3699                 // Enable fail fast as we'll do retries here and use a
3700                 // hipri connection so the default connection stays active.
3701                 log("isMobileOk: start hipri url=" + params.mUrl);
3702                 mCs.setEnableFailFastMobileData(DctConstants.ENABLED);
3703                 mCs.startUsingNetworkFeature(ConnectivityManager.TYPE_MOBILE,
3704                         Phone.FEATURE_ENABLE_HIPRI, new Binder());
3705
3706                 // Continue trying to connect until time has run out
3707                 long endTime = SystemClock.elapsedRealtime() + params.mTimeOutMs;
3708                 while(SystemClock.elapsedRealtime() < endTime) {
3709                     try {
3710                         // Wait for hipri to connect.
3711                         // TODO: Don't poll and handle situation where hipri fails
3712                         // because default is retrying. See b/9569540
3713                         NetworkInfo.State state = mCs
3714                                 .getNetworkInfo(ConnectivityManager.TYPE_MOBILE_HIPRI).getState();
3715                         if (state != NetworkInfo.State.CONNECTED) {
3716                             log("isMobileOk: not connected ni=" +
3717                                     mCs.getNetworkInfo(ConnectivityManager.TYPE_MOBILE_HIPRI));
3718                             sleep(1);
3719                             result = ConnectivityManager.CMP_RESULT_CODE_NO_CONNECTION;
3720                             continue;
3721                         }
3722
3723                         // Get of the addresses associated with the url host. We need to use the
3724                         // address otherwise HttpURLConnection object will use the name to get
3725                         // the addresses and is will try every address but that will bypass the
3726                         // route to host we setup and the connection could succeed as the default
3727                         // interface might be connected to the internet via wifi or other interface.
3728                         InetAddress[] addresses;
3729                         try {
3730                             addresses = InetAddress.getAllByName(orgUri.getHost());
3731                         } catch (UnknownHostException e) {
3732                             log("isMobileOk: UnknownHostException");
3733                             result = ConnectivityManager.CMP_RESULT_CODE_NO_DNS;
3734                             return result;
3735                         }
3736                         log("isMobileOk: addresses=" + inetAddressesToString(addresses));
3737
3738                         // Get the type of addresses supported by this link
3739                         LinkProperties lp = mCs.getLinkProperties(
3740                                 ConnectivityManager.TYPE_MOBILE_HIPRI);
3741                         boolean linkHasIpv4 = hasIPv4Address(lp);
3742                         boolean linkHasIpv6 = hasIPv6Address(lp);
3743                         log("isMobileOk: linkHasIpv4=" + linkHasIpv4
3744                                 + " linkHasIpv6=" + linkHasIpv6);
3745
3746                         // Loop through at most 3 valid addresses or all of the address or until
3747                         // we run out of time
3748                         int loops = Math.min(3, addresses.length);
3749                         for(int validAddr=0, addrTried=0;
3750                                     (validAddr < loops) && (addrTried < addresses.length)
3751                                       && (SystemClock.elapsedRealtime() < endTime);
3752                                 addrTried ++) {
3753
3754                             // Choose the address at random but make sure its type is supported
3755                             InetAddress hostAddr = addresses[rand.nextInt(addresses.length)];
3756                             if (((hostAddr instanceof Inet4Address) && linkHasIpv4)
3757                                     || ((hostAddr instanceof Inet6Address) && linkHasIpv6)) {
3758                                 // Valid address, so use it
3759                                 validAddr += 1;
3760                             } else {
3761                                 // Invalid address so try next address
3762                                 continue;
3763                             }
3764
3765                             // Make a route to host so we check the specific interface.
3766                             if (mCs.requestRouteToHostAddress(ConnectivityManager.TYPE_MOBILE_HIPRI,
3767                                     hostAddr.getAddress())) {
3768                                 // Wait a short time to be sure the route is established ??
3769                                 log("isMobileOk:"
3770                                         + " wait to establish route to hostAddr=" + hostAddr);
3771                                 sleep(3);
3772                             } else {
3773                                 log("isMobileOk:"
3774                                         + " could not establish route to hostAddr=" + hostAddr);
3775                                 continue;
3776                             }
3777
3778                             // Rewrite the url to have numeric address to use the specific route.
3779                             // I also set the "Connection" to "Close" as by default "Keep-Alive"
3780                             // is used which is useless in this case.
3781                             URL newUrl = new URL(orgUri.getScheme() + "://"
3782                                     + hostAddr.getHostAddress() + orgUri.getPath());
3783                             log("isMobileOk: newUrl=" + newUrl);
3784
3785                             HttpURLConnection urlConn = null;
3786                             try {
3787                                 // Open the connection set the request header and get the response
3788                                 urlConn = (HttpURLConnection) newUrl.openConnection(
3789                                         java.net.Proxy.NO_PROXY);
3790                                 urlConn.setInstanceFollowRedirects(false);
3791                                 urlConn.setConnectTimeout(SOCKET_TIMEOUT_MS);
3792                                 urlConn.setReadTimeout(SOCKET_TIMEOUT_MS);
3793                                 urlConn.setUseCaches(false);
3794                                 urlConn.setAllowUserInteraction(false);
3795                                 urlConn.setRequestProperty("Connection", "close");
3796                                 int responseCode = urlConn.getResponseCode();
3797                                 if (responseCode == 204) {
3798                                     result = ConnectivityManager.CMP_RESULT_CODE_CONNECTABLE;
3799                                 } else {
3800                                     result = ConnectivityManager.CMP_RESULT_CODE_REDIRECTED;
3801                                 }
3802                                 log("isMobileOk: connected responseCode=" + responseCode);
3803                                 urlConn.disconnect();
3804                                 urlConn = null;
3805                                 return result;
3806                             } catch (Exception e) {
3807                                 log("isMobileOk: HttpURLConnection Exception e=" + e);
3808                                 if (urlConn != null) {
3809                                     urlConn.disconnect();
3810                                     urlConn = null;
3811                                 }
3812                             }
3813                         }
3814                         result = ConnectivityManager.CMP_RESULT_CODE_NO_TCP_CONNECTION;
3815                         log("isMobileOk: loops|timed out");
3816                         return result;
3817                     } catch (Exception e) {
3818                         log("isMobileOk: Exception e=" + e);
3819                         continue;
3820                     }
3821                 }
3822                 log("isMobileOk: timed out");
3823             } finally {
3824                 log("isMobileOk: F stop hipri");
3825                 mCs.setEnableFailFastMobileData(DctConstants.DISABLED);
3826                 mCs.stopUsingNetworkFeature(ConnectivityManager.TYPE_MOBILE,
3827                         Phone.FEATURE_ENABLE_HIPRI);
3828                 log("isMobileOk: X result=" + result);
3829             }
3830             return result;
3831         }
3832
3833         @Override
3834         protected Integer doInBackground(Params... params) {
3835             return isMobileOk(params[0]);
3836         }
3837
3838         @Override
3839         protected void onPostExecute(Integer result) {
3840             log("onPostExecute: result=" + result);
3841             if ((mParams != null) && (mParams.mCb != null)) {
3842                 mParams.mCb.onComplete(result);
3843             }
3844         }
3845
3846         private String inetAddressesToString(InetAddress[] addresses) {
3847             StringBuffer sb = new StringBuffer();
3848             boolean firstTime = true;
3849             for(InetAddress addr : addresses) {
3850                 if (firstTime) {
3851                     firstTime = false;
3852                 } else {
3853                     sb.append(",");
3854                 }
3855                 sb.append(addr);
3856             }
3857             return sb.toString();
3858         }
3859
3860         private void printNetworkInfo() {
3861             boolean hasIccCard = mTm.hasIccCard();
3862             int simState = mTm.getSimState();
3863             log("hasIccCard=" + hasIccCard
3864                     + " simState=" + simState);
3865             NetworkInfo[] ni = mCs.getAllNetworkInfo();
3866             if (ni != null) {
3867                 log("ni.length=" + ni.length);
3868                 for (NetworkInfo netInfo: ni) {
3869                     log("netInfo=" + netInfo.toString());
3870                 }
3871             } else {
3872                 log("no network info ni=null");
3873             }
3874         }
3875
3876         /**
3877          * Sleep for a few seconds then return.
3878          * @param seconds
3879          */
3880         private static void sleep(int seconds) {
3881             try {
3882                 Thread.sleep(seconds * 1000);
3883             } catch (InterruptedException e) {
3884                 e.printStackTrace();
3885             }
3886         }
3887
3888         public boolean hasIPv4Address(LinkProperties lp) {
3889             return lp.hasIPv4Address();
3890         }
3891
3892         // Not implemented in LinkProperties, do it here.
3893         public boolean hasIPv6Address(LinkProperties lp) {
3894             for (LinkAddress address : lp.getLinkAddresses()) {
3895               if (address.getAddress() instanceof Inet6Address) {
3896                 return true;
3897               }
3898             }
3899             return false;
3900         }
3901
3902         private void log(String s) {
3903             Slog.d(ConnectivityService.TAG, "[" + CHECKMP_TAG + "] " + s);
3904         }
3905     }
3906
3907     private static final String NOTIFICATION_ID = "CaptivePortal.Notification";
3908
3909     private void setNotificationVisible(boolean visible, NetworkInfo networkInfo, String url) {
3910         log("setNotificationVisible: E visible=" + visible + " ni=" + networkInfo + " url=" + url);
3911
3912         Resources r = Resources.getSystem();
3913         NotificationManager notificationManager = (NotificationManager) mContext
3914             .getSystemService(Context.NOTIFICATION_SERVICE);
3915
3916         if (visible) {
3917             CharSequence title;
3918             CharSequence details;
3919             int icon;
3920             switch (networkInfo.getType()) {
3921                 case ConnectivityManager.TYPE_WIFI:
3922                     log("setNotificationVisible: TYPE_WIFI");
3923                     title = r.getString(R.string.wifi_available_sign_in, 0);
3924                     details = r.getString(R.string.network_available_sign_in_detailed,
3925                             networkInfo.getExtraInfo());
3926                     icon = R.drawable.stat_notify_wifi_in_range;
3927                     break;
3928                 case ConnectivityManager.TYPE_MOBILE:
3929                 case ConnectivityManager.TYPE_MOBILE_HIPRI:
3930                     log("setNotificationVisible: TYPE_MOBILE|HIPRI");
3931                     title = r.getString(R.string.network_available_sign_in, 0);
3932                     // TODO: Change this to pull from NetworkInfo once a printable
3933                     // name has been added to it
3934                     details = mTelephonyManager.getNetworkOperatorName();
3935                     icon = R.drawable.stat_notify_rssi_in_range;
3936                     break;
3937                 default:
3938                     log("setNotificationVisible: other type=" + networkInfo.getType());
3939                     title = r.getString(R.string.network_available_sign_in, 0);
3940                     details = r.getString(R.string.network_available_sign_in_detailed,
3941                             networkInfo.getExtraInfo());
3942                     icon = R.drawable.stat_notify_rssi_in_range;
3943                     break;
3944             }
3945
3946             Notification notification = new Notification();
3947             notification.when = 0;
3948             notification.icon = icon;
3949             notification.flags = Notification.FLAG_AUTO_CANCEL;
3950             Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
3951             intent.setFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT |
3952                     Intent.FLAG_ACTIVITY_NEW_TASK);
3953             notification.contentIntent = PendingIntent.getActivity(mContext, 0, intent, 0);
3954             notification.tickerText = title;
3955             notification.setLatestEventInfo(mContext, title, details, notification.contentIntent);
3956
3957             log("setNotificaitionVisible: notify notificaiton=" + notification);
3958             notificationManager.notify(NOTIFICATION_ID, 1, notification);
3959         } else {
3960             log("setNotificaitionVisible: cancel");
3961             notificationManager.cancel(NOTIFICATION_ID, 1);
3962         }
3963         log("setNotificationVisible: X visible=" + visible + " ni=" + networkInfo + " url=" + url);
3964     }
3965
3966     private String getProvisioningUrl() {
3967         String url = mContext.getResources().getString(R.string.mobile_provisioning_url);
3968         log("getProvisioningUrl: resource url=" + url);
3969
3970         // populate the iccid and imei in the provisioning url.
3971         if (!TextUtils.isEmpty(url)) {
3972             url = String.format(url,
3973                     mTelephonyManager.getSimSerialNumber() /* ICCID */,
3974                     mTelephonyManager.getDeviceId() /* IMEI */,
3975                     mTelephonyManager.getLine1Number() /* Phone numer */);
3976         }
3977
3978         log("getProvisioningUrl: url=" + url);
3979         return url;
3980     }
3981 }