blob: aee2a9a17de95f4b18b6e3495025b7064197d133 [file] [log] [blame]
The Android Open Source Project28527d22009-03-03 19:31:44 -08001/*
2 * Copyright (C) 2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.server;
18
Jaikumar Ganesh0db51a02010-12-21 22:31:44 -080019import android.bluetooth.BluetoothTetheringDataTracker;
The Android Open Source Project28527d22009-03-03 19:31:44 -080020import android.content.ContentResolver;
21import android.content.Context;
22import android.content.Intent;
23import android.content.pm.PackageManager;
Robert Greenwaltc3c5f862010-10-11 16:00:27 -070024import android.database.ContentObserver;
The Android Open Source Project28527d22009-03-03 19:31:44 -080025import android.net.ConnectivityManager;
Robert Greenwalteb123ac2010-12-06 13:56:24 -080026import android.net.DummyDataStateTracker;
Benoit Goby6cec7f32010-12-22 14:29:40 -080027import android.net.EthernetDataTracker;
The Android Open Source Project28527d22009-03-03 19:31:44 -080028import android.net.IConnectivityManager;
Robert Greenwalt355205c2011-05-10 15:05:02 -070029import android.net.LinkAddress;
Jaikumar Ganesh0db51a02010-12-21 22:31:44 -080030import android.net.LinkProperties;
The Android Open Source Project28527d22009-03-03 19:31:44 -080031import android.net.MobileDataStateTracker;
Robert Greenwalt34848c02011-03-25 13:09:25 -070032import android.net.NetworkConfig;
The Android Open Source Project28527d22009-03-03 19:31:44 -080033import android.net.NetworkInfo;
34import android.net.NetworkStateTracker;
Robert Greenwalt7fe44cb2010-08-27 09:24:29 -070035import android.net.NetworkUtils;
Robert Greenwaltc3c5f862010-10-11 16:00:27 -070036import android.net.Proxy;
37import android.net.ProxyProperties;
Robert Greenwalt5a901292011-04-28 14:28:50 -070038import android.net.RouteInfo;
Hung-ying Tyan4e723422011-01-19 16:48:38 +080039import android.net.vpn.VpnManager;
The Android Open Source Project28527d22009-03-03 19:31:44 -080040import android.net.wifi.WifiStateTracker;
41import android.os.Binder;
42import android.os.Handler;
Wink Saville775aad62010-09-02 19:23:52 -070043import android.os.HandlerThread;
Robert Greenwalt2034b912009-08-12 16:08:25 -070044import android.os.IBinder;
Robert Greenwalt355205c2011-05-10 15:05:02 -070045import android.os.INetworkManagementService;
The Android Open Source Project28527d22009-03-03 19:31:44 -080046import android.os.Looper;
47import android.os.Message;
Robert Greenwalt93dc1042010-06-15 12:19:37 -070048import android.os.PowerManager;
Robert Greenwalt2034b912009-08-12 16:08:25 -070049import android.os.RemoteException;
The Android Open Source Project28527d22009-03-03 19:31:44 -080050import android.os.ServiceManager;
51import android.os.SystemProperties;
52import android.provider.Settings;
Robert Greenwalt2034b912009-08-12 16:08:25 -070053import android.text.TextUtils;
The Android Open Source Project28527d22009-03-03 19:31:44 -080054import android.util.EventLog;
Joe Onoratoc2386bb2010-02-26 18:56:32 -080055import android.util.Slog;
The Android Open Source Project28527d22009-03-03 19:31:44 -080056
Robert Greenwalt2034b912009-08-12 16:08:25 -070057import com.android.internal.telephony.Phone;
Robert Greenwalt0c4828c2010-01-26 11:40:34 -080058import com.android.server.connectivity.Tethering;
59
The Android Open Source Project28527d22009-03-03 19:31:44 -080060import java.io.FileDescriptor;
Irfan Sheriff7f132d92010-06-09 15:39:36 -070061import java.io.FileWriter;
62import java.io.IOException;
The Android Open Source Project28527d22009-03-03 19:31:44 -080063import java.io.PrintWriter;
Robert Greenwalta7dfbd32010-06-15 15:43:39 -070064import java.net.InetAddress;
Robert Greenwalt355205c2011-05-10 15:05:02 -070065import java.net.Inet4Address;
Robert Greenwalta7dfbd32010-06-15 15:43:39 -070066import java.net.UnknownHostException;
Robert Greenwalt2034b912009-08-12 16:08:25 -070067import java.util.ArrayList;
Robert Greenwalta7dfbd32010-06-15 15:43:39 -070068import java.util.Collection;
Robert Greenwaltd62c7002010-12-29 16:15:02 -080069import java.util.concurrent.atomic.AtomicBoolean;
Robert Greenwalt0e80be12010-09-20 14:35:25 -070070import java.util.GregorianCalendar;
Robert Greenwalt2034b912009-08-12 16:08:25 -070071import java.util.List;
The Android Open Source Project28527d22009-03-03 19:31:44 -080072
73/**
74 * @hide
75 */
76public class ConnectivityService extends IConnectivityManager.Stub {
77
Robert Greenwalt063dc7d2010-10-05 19:12:26 -070078 private static final boolean DBG = true;
The Android Open Source Project28527d22009-03-03 19:31:44 -080079 private static final String TAG = "ConnectivityService";
80
Robert Greenwalt2034b912009-08-12 16:08:25 -070081 // how long to wait before switching back to a radio's default network
82 private static final int RESTORE_DEFAULT_NETWORK_DELAY = 1 * 60 * 1000;
83 // system property that can override the above value
84 private static final String NETWORK_RESTORE_DELAY_PROP_NAME =
85 "android.telephony.apn-restore";
86
Robert Greenwaltbd492212011-05-06 17:10:53 -070087 // used in recursive route setting to add gateways for the host for which
88 // a host route was requested.
89 private static final int MAX_HOSTROUTE_CYCLE_COUNT = 10;
90
Robert Greenwalt0c4828c2010-01-26 11:40:34 -080091 private Tethering mTethering;
Robert Greenwaltf1b66e12010-02-25 12:29:30 -080092 private boolean mTetheringConfigValid = false;
Robert Greenwalt0c4828c2010-01-26 11:40:34 -080093
The Android Open Source Project28527d22009-03-03 19:31:44 -080094 /**
95 * Sometimes we want to refer to the individual network state
96 * trackers separately, and sometimes we just want to treat them
97 * abstractly.
98 */
99 private NetworkStateTracker mNetTrackers[];
Robert Greenwalt2034b912009-08-12 16:08:25 -0700100
101 /**
102 * A per Net list of the PID's that requested access to the net
103 * used both as a refcount and for per-PID DNS selection
104 */
105 private List mNetRequestersPids[];
106
Irfan Sheriff653e2a22010-06-07 09:03:04 -0700107 private WifiWatchdogService mWifiWatchdogService;
108
Robert Greenwalt2034b912009-08-12 16:08:25 -0700109 // priority order of the nettrackers
110 // (excluding dynamically set mNetworkPreference)
111 // TODO - move mNetworkTypePreference into this
112 private int[] mPriorityList;
113
The Android Open Source Project28527d22009-03-03 19:31:44 -0800114 private Context mContext;
115 private int mNetworkPreference;
Robert Greenwalt2034b912009-08-12 16:08:25 -0700116 private int mActiveDefaultNetwork = -1;
Robert Greenwalt986c7412010-09-08 15:24:47 -0700117 // 0 is full bad, 100 is full good
118 private int mDefaultInetCondition = 0;
119 private int mDefaultInetConditionPublished = 0;
120 private boolean mInetConditionChangeInFlight = false;
121 private int mDefaultConnectionSequence = 0;
The Android Open Source Project28527d22009-03-03 19:31:44 -0800122
123 private int mNumDnsEntries;
The Android Open Source Project28527d22009-03-03 19:31:44 -0800124
125 private boolean mTestMode;
Joe Onorato56023ad2010-09-01 21:18:22 -0700126 private static ConnectivityService sServiceInstance;
The Android Open Source Project28527d22009-03-03 19:31:44 -0800127
Robert Greenwaltd62c7002010-12-29 16:15:02 -0800128 private AtomicBoolean mBackgroundDataEnabled = new AtomicBoolean(true);
129
Robert Greenwalt355205c2011-05-10 15:05:02 -0700130 private INetworkManagementService mNetd;
131
Robert Greenwalt6a2db8a2010-09-23 10:05:56 -0700132 private static final int ENABLED = 1;
133 private static final int DISABLED = 0;
134
135 // Share the event space with NetworkStateTracker (which can't see this
136 // internal class but sends us events). If you change these, change
137 // NetworkStateTracker.java too.
138 private static final int MIN_NETWORK_STATE_TRACKER_EVENT = 1;
139 private static final int MAX_NETWORK_STATE_TRACKER_EVENT = 100;
140
141 /**
142 * used internally as a delayed event to make us switch back to the
143 * default network
144 */
145 private static final int EVENT_RESTORE_DEFAULT_NETWORK =
146 MAX_NETWORK_STATE_TRACKER_EVENT + 1;
147
148 /**
149 * used internally to change our mobile data enabled flag
150 */
151 private static final int EVENT_CHANGE_MOBILE_DATA_ENABLED =
152 MAX_NETWORK_STATE_TRACKER_EVENT + 2;
153
154 /**
155 * used internally to change our network preference setting
156 * arg1 = networkType to prefer
157 */
158 private static final int EVENT_SET_NETWORK_PREFERENCE =
159 MAX_NETWORK_STATE_TRACKER_EVENT + 3;
160
161 /**
162 * used internally to synchronize inet condition reports
163 * arg1 = networkType
164 * arg2 = condition (0 bad, 100 good)
165 */
166 private static final int EVENT_INET_CONDITION_CHANGE =
167 MAX_NETWORK_STATE_TRACKER_EVENT + 4;
168
169 /**
170 * used internally to mark the end of inet condition hold periods
171 * arg1 = networkType
172 */
173 private static final int EVENT_INET_CONDITION_HOLD_END =
174 MAX_NETWORK_STATE_TRACKER_EVENT + 5;
175
176 /**
177 * used internally to set the background data preference
178 * arg1 = TRUE for enabled, FALSE for disabled
179 */
180 private static final int EVENT_SET_BACKGROUND_DATA =
181 MAX_NETWORK_STATE_TRACKER_EVENT + 6;
182
183 /**
184 * used internally to set enable/disable cellular data
185 * arg1 = ENBALED or DISABLED
186 */
187 private static final int EVENT_SET_MOBILE_DATA =
188 MAX_NETWORK_STATE_TRACKER_EVENT + 7;
189
Robert Greenwaltccb36f92010-09-24 14:32:21 -0700190 /**
191 * used internally to clear a wakelock when transitioning
192 * from one net to another
193 */
194 private static final int EVENT_CLEAR_NET_TRANSITION_WAKELOCK =
195 MAX_NETWORK_STATE_TRACKER_EVENT + 8;
196
Robert Greenwaltc3c5f862010-10-11 16:00:27 -0700197 /**
198 * used internally to reload global proxy settings
199 */
200 private static final int EVENT_APPLY_GLOBAL_HTTP_PROXY =
201 MAX_NETWORK_STATE_TRACKER_EVENT + 9;
202
Robert Greenwalt34848c02011-03-25 13:09:25 -0700203 /**
204 * used internally to set external dependency met/unmet
205 * arg1 = ENABLED (met) or DISABLED (unmet)
206 * arg2 = NetworkType
207 */
208 private static final int EVENT_SET_DEPENDENCY_MET =
209 MAX_NETWORK_STATE_TRACKER_EVENT + 10;
210
Robert Greenwalt2034b912009-08-12 16:08:25 -0700211 private Handler mHandler;
212
213 // list of DeathRecipients used to make sure features are turned off when
214 // a process dies
215 private List mFeatureUsers;
216
Mike Lockwoodfde2b762009-08-14 14:18:49 -0400217 private boolean mSystemReady;
Dianne Hackborna417ff82009-12-08 19:45:14 -0800218 private Intent mInitialBroadcast;
Mike Lockwoodfde2b762009-08-14 14:18:49 -0400219
Robert Greenwalt93dc1042010-06-15 12:19:37 -0700220 private PowerManager.WakeLock mNetTransitionWakeLock;
221 private String mNetTransitionWakeLockCausedBy = "";
222 private int mNetTransitionWakeLockSerialNumber;
223 private int mNetTransitionWakeLockTimeout;
224
Robert Greenwalt94daa182010-09-01 11:34:05 -0700225 private InetAddress mDefaultDns;
226
Robert Greenwalt0e80be12010-09-20 14:35:25 -0700227 // used in DBG mode to track inet condition reports
228 private static final int INET_CONDITION_LOG_MAX_SIZE = 15;
229 private ArrayList mInetLog;
230
Robert Greenwaltc3c5f862010-10-11 16:00:27 -0700231 // track the current default http proxy - tell the world if we get a new one (real change)
232 private ProxyProperties mDefaultProxy = null;
233 // track the global proxy.
234 private ProxyProperties mGlobalProxy = null;
235 private final Object mGlobalProxyLock = new Object();
236
237 private SettingsObserver mSettingsObserver;
238
Robert Greenwalt34848c02011-03-25 13:09:25 -0700239 NetworkConfig[] mNetConfigs;
Robert Greenwaltec05b3c2009-10-30 14:17:42 -0700240 int mNetworksDefined;
Robert Greenwalt2034b912009-08-12 16:08:25 -0700241
Robert Greenwalt12c44552009-12-07 11:33:18 -0800242 private static class RadioAttributes {
Robert Greenwalt2034b912009-08-12 16:08:25 -0700243 public int mSimultaneity;
244 public int mType;
245 public RadioAttributes(String init) {
246 String fragments[] = init.split(",");
Robert Greenwaltec05b3c2009-10-30 14:17:42 -0700247 mType = Integer.parseInt(fragments[0]);
248 mSimultaneity = Integer.parseInt(fragments[1]);
Robert Greenwalt2034b912009-08-12 16:08:25 -0700249 }
250 }
251 RadioAttributes[] mRadioAttributes;
252
Wink Saville775aad62010-09-02 19:23:52 -0700253 public static synchronized ConnectivityService getInstance(Context context) {
254 if (sServiceInstance == null) {
255 sServiceInstance = new ConnectivityService(context);
The Android Open Source Project28527d22009-03-03 19:31:44 -0800256 }
Wink Saville775aad62010-09-02 19:23:52 -0700257 return sServiceInstance;
The Android Open Source Project28527d22009-03-03 19:31:44 -0800258 }
Robert Greenwalt0659da32009-07-16 17:21:39 -0700259
The Android Open Source Project28527d22009-03-03 19:31:44 -0800260 private ConnectivityService(Context context) {
Wink Savillee70c6f52010-12-03 12:01:38 -0800261 if (DBG) log("ConnectivityService starting up");
Robert Greenwaltd48f8ee2010-01-14 17:47:58 -0800262
Wink Saville775aad62010-09-02 19:23:52 -0700263 HandlerThread handlerThread = new HandlerThread("ConnectivityServiceThread");
264 handlerThread.start();
265 mHandler = new MyHandler(handlerThread.getLooper());
266
Robert Greenwaltd62c7002010-12-29 16:15:02 -0800267 mBackgroundDataEnabled.set(Settings.Secure.getInt(context.getContentResolver(),
268 Settings.Secure.BACKGROUND_DATA, 1) == 1);
269
Robert Greenwaltd48f8ee2010-01-14 17:47:58 -0800270 // setup our unique device name
Robert Greenwalt82cde132010-12-06 09:30:17 -0800271 if (TextUtils.isEmpty(SystemProperties.get("net.hostname"))) {
272 String id = Settings.Secure.getString(context.getContentResolver(),
273 Settings.Secure.ANDROID_ID);
274 if (id != null && id.length() > 0) {
275 String name = new String("android_").concat(id);
276 SystemProperties.set("net.hostname", name);
277 }
Robert Greenwaltd48f8ee2010-01-14 17:47:58 -0800278 }
279
Robert Greenwalt94daa182010-09-01 11:34:05 -0700280 // read our default dns server ip
281 String dns = Settings.Secure.getString(context.getContentResolver(),
282 Settings.Secure.DEFAULT_DNS_SERVER);
283 if (dns == null || dns.length() == 0) {
284 dns = context.getResources().getString(
285 com.android.internal.R.string.config_default_dns_server);
286 }
287 try {
Robert Greenwalt35e34d12011-02-22 16:00:42 -0800288 mDefaultDns = NetworkUtils.numericToInetAddress(dns);
289 } catch (IllegalArgumentException e) {
Wink Savillee70c6f52010-12-03 12:01:38 -0800290 loge("Error setting defaultDns using " + dns);
Robert Greenwalt94daa182010-09-01 11:34:05 -0700291 }
292
The Android Open Source Project28527d22009-03-03 19:31:44 -0800293 mContext = context;
Robert Greenwalt93dc1042010-06-15 12:19:37 -0700294
295 PowerManager powerManager = (PowerManager)mContext.getSystemService(Context.POWER_SERVICE);
296 mNetTransitionWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
297 mNetTransitionWakeLockTimeout = mContext.getResources().getInteger(
298 com.android.internal.R.integer.config_networkTransitionTimeout);
299
Robert Greenwalt2034b912009-08-12 16:08:25 -0700300 mNetTrackers = new NetworkStateTracker[
301 ConnectivityManager.MAX_NETWORK_TYPE+1];
Robert Greenwalt0659da32009-07-16 17:21:39 -0700302
The Android Open Source Project28527d22009-03-03 19:31:44 -0800303 mNetworkPreference = getPersistedNetworkPreference();
Robert Greenwalt0659da32009-07-16 17:21:39 -0700304
Robert Greenwaltec05b3c2009-10-30 14:17:42 -0700305 mRadioAttributes = new RadioAttributes[ConnectivityManager.MAX_RADIO_TYPE+1];
Robert Greenwalt34848c02011-03-25 13:09:25 -0700306 mNetConfigs = new NetworkConfig[ConnectivityManager.MAX_NETWORK_TYPE+1];
Robert Greenwaltec05b3c2009-10-30 14:17:42 -0700307
Robert Greenwalt2034b912009-08-12 16:08:25 -0700308 // Load device network attributes from resources
Robert Greenwalt2034b912009-08-12 16:08:25 -0700309 String[] raStrings = context.getResources().getStringArray(
310 com.android.internal.R.array.radioAttributes);
Robert Greenwaltec05b3c2009-10-30 14:17:42 -0700311 for (String raString : raStrings) {
312 RadioAttributes r = new RadioAttributes(raString);
313 if (r.mType > ConnectivityManager.MAX_RADIO_TYPE) {
Wink Savillee70c6f52010-12-03 12:01:38 -0800314 loge("Error in radioAttributes - ignoring attempt to define type " + r.mType);
Robert Greenwaltec05b3c2009-10-30 14:17:42 -0700315 continue;
316 }
317 if (mRadioAttributes[r.mType] != null) {
Wink Savillee70c6f52010-12-03 12:01:38 -0800318 loge("Error in radioAttributes - ignoring attempt to redefine type " +
Robert Greenwaltec05b3c2009-10-30 14:17:42 -0700319 r.mType);
320 continue;
321 }
Robert Greenwalt2034b912009-08-12 16:08:25 -0700322 mRadioAttributes[r.mType] = r;
323 }
324
Robert Greenwaltec05b3c2009-10-30 14:17:42 -0700325 String[] naStrings = context.getResources().getStringArray(
326 com.android.internal.R.array.networkAttributes);
327 for (String naString : naStrings) {
328 try {
Robert Greenwalt34848c02011-03-25 13:09:25 -0700329 NetworkConfig n = new NetworkConfig(naString);
Wink Savillef2a62832011-04-07 14:23:45 -0700330 if (n.type > ConnectivityManager.MAX_NETWORK_TYPE) {
Wink Savillee70c6f52010-12-03 12:01:38 -0800331 loge("Error in networkAttributes - ignoring attempt to define type " +
Wink Savillef2a62832011-04-07 14:23:45 -0700332 n.type);
Robert Greenwaltec05b3c2009-10-30 14:17:42 -0700333 continue;
Robert Greenwalt2034b912009-08-12 16:08:25 -0700334 }
Wink Savillef2a62832011-04-07 14:23:45 -0700335 if (mNetConfigs[n.type] != null) {
Wink Savillee70c6f52010-12-03 12:01:38 -0800336 loge("Error in networkAttributes - ignoring attempt to redefine type " +
Wink Savillef2a62832011-04-07 14:23:45 -0700337 n.type);
Robert Greenwaltec05b3c2009-10-30 14:17:42 -0700338 continue;
339 }
Wink Savillef2a62832011-04-07 14:23:45 -0700340 if (mRadioAttributes[n.radio] == null) {
Wink Savillee70c6f52010-12-03 12:01:38 -0800341 loge("Error in networkAttributes - ignoring attempt to use undefined " +
Wink Savillef2a62832011-04-07 14:23:45 -0700342 "radio " + n.radio + " in network type " + n.type);
Robert Greenwaltec05b3c2009-10-30 14:17:42 -0700343 continue;
344 }
Wink Savillef2a62832011-04-07 14:23:45 -0700345 mNetConfigs[n.type] = n;
Robert Greenwaltec05b3c2009-10-30 14:17:42 -0700346 mNetworksDefined++;
347 } catch(Exception e) {
348 // ignore it - leave the entry null
Robert Greenwalt2034b912009-08-12 16:08:25 -0700349 }
350 }
351
Robert Greenwaltec05b3c2009-10-30 14:17:42 -0700352 // high priority first
353 mPriorityList = new int[mNetworksDefined];
354 {
355 int insertionPoint = mNetworksDefined-1;
356 int currentLowest = 0;
357 int nextLowest = 0;
358 while (insertionPoint > -1) {
Robert Greenwalt34848c02011-03-25 13:09:25 -0700359 for (NetworkConfig na : mNetConfigs) {
Robert Greenwaltec05b3c2009-10-30 14:17:42 -0700360 if (na == null) continue;
Wink Savillef2a62832011-04-07 14:23:45 -0700361 if (na.priority < currentLowest) continue;
362 if (na.priority > currentLowest) {
363 if (na.priority < nextLowest || nextLowest == 0) {
364 nextLowest = na.priority;
Robert Greenwaltec05b3c2009-10-30 14:17:42 -0700365 }
366 continue;
367 }
Wink Savillef2a62832011-04-07 14:23:45 -0700368 mPriorityList[insertionPoint--] = na.type;
Robert Greenwaltec05b3c2009-10-30 14:17:42 -0700369 }
370 currentLowest = nextLowest;
371 nextLowest = 0;
372 }
373 }
374
375 mNetRequestersPids = new ArrayList[ConnectivityManager.MAX_NETWORK_TYPE+1];
376 for (int i : mPriorityList) {
Robert Greenwalt2034b912009-08-12 16:08:25 -0700377 mNetRequestersPids[i] = new ArrayList();
378 }
379
380 mFeatureUsers = new ArrayList();
381
Robert Greenwaltec05b3c2009-10-30 14:17:42 -0700382 mNumDnsEntries = 0;
383
384 mTestMode = SystemProperties.get("cm.test.mode").equals("true")
385 && SystemProperties.get("ro.build.type").equals("eng");
The Android Open Source Project28527d22009-03-03 19:31:44 -0800386 /*
387 * Create the network state trackers for Wi-Fi and mobile
388 * data. Maybe this could be done with a factory class,
389 * but it's not clear that it's worth it, given that
390 * the number of different network types is not going
391 * to change very often.
392 */
Robert Greenwaltec05b3c2009-10-30 14:17:42 -0700393 for (int netType : mPriorityList) {
Wink Savillef2a62832011-04-07 14:23:45 -0700394 switch (mNetConfigs[netType].radio) {
Robert Greenwaltec05b3c2009-10-30 14:17:42 -0700395 case ConnectivityManager.TYPE_WIFI:
Wink Savillee70c6f52010-12-03 12:01:38 -0800396 if (DBG) log("Starting Wifi Service.");
Wink Saville7fabfa22010-08-13 16:11:42 -0700397 WifiStateTracker wst = new WifiStateTracker();
Irfan Sheriff25be0762010-07-28 09:35:20 -0700398 WifiService wifiService = new WifiService(context);
Robert Greenwaltec05b3c2009-10-30 14:17:42 -0700399 ServiceManager.addService(Context.WIFI_SERVICE, wifiService);
Irfan Sheriff25be0762010-07-28 09:35:20 -0700400 wifiService.checkAndStartWifi();
Robert Greenwaltec05b3c2009-10-30 14:17:42 -0700401 mNetTrackers[ConnectivityManager.TYPE_WIFI] = wst;
Wink Saville7fabfa22010-08-13 16:11:42 -0700402 wst.startMonitoring(context, mHandler);
The Android Open Source Project28527d22009-03-03 19:31:44 -0800403
Irfan Sheriff653e2a22010-06-07 09:03:04 -0700404 //TODO: as part of WWS refactor, create only when needed
Irfan Sheriff25be0762010-07-28 09:35:20 -0700405 mWifiWatchdogService = new WifiWatchdogService(context);
Irfan Sheriff653e2a22010-06-07 09:03:04 -0700406
Robert Greenwaltec05b3c2009-10-30 14:17:42 -0700407 break;
408 case ConnectivityManager.TYPE_MOBILE:
Wink Saville7fabfa22010-08-13 16:11:42 -0700409 mNetTrackers[netType] = new MobileDataStateTracker(netType,
Wink Savillef2a62832011-04-07 14:23:45 -0700410 mNetConfigs[netType].name);
Wink Saville7fabfa22010-08-13 16:11:42 -0700411 mNetTrackers[netType].startMonitoring(context, mHandler);
Robert Greenwaltec05b3c2009-10-30 14:17:42 -0700412 break;
Robert Greenwalteb123ac2010-12-06 13:56:24 -0800413 case ConnectivityManager.TYPE_DUMMY:
414 mNetTrackers[netType] = new DummyDataStateTracker(netType,
Wink Savillef2a62832011-04-07 14:23:45 -0700415 mNetConfigs[netType].name);
Robert Greenwalteb123ac2010-12-06 13:56:24 -0800416 mNetTrackers[netType].startMonitoring(context, mHandler);
417 break;
Jaikumar Ganesh0db51a02010-12-21 22:31:44 -0800418 case ConnectivityManager.TYPE_BLUETOOTH:
419 mNetTrackers[netType] = BluetoothTetheringDataTracker.getInstance();
420 mNetTrackers[netType].startMonitoring(context, mHandler);
421 break;
Benoit Goby6cec7f32010-12-22 14:29:40 -0800422 case ConnectivityManager.TYPE_ETHERNET:
423 mNetTrackers[netType] = EthernetDataTracker.getInstance();
424 mNetTrackers[netType].startMonitoring(context, mHandler);
425 break;
Robert Greenwaltec05b3c2009-10-30 14:17:42 -0700426 default:
Wink Savillee70c6f52010-12-03 12:01:38 -0800427 loge("Trying to create a DataStateTracker for an unknown radio type " +
Wink Savillef2a62832011-04-07 14:23:45 -0700428 mNetConfigs[netType].radio);
Robert Greenwaltec05b3c2009-10-30 14:17:42 -0700429 continue;
430 }
431 }
Robert Greenwalt0c4828c2010-01-26 11:40:34 -0800432
Robert Greenwaltc0b6c602010-03-11 15:03:08 -0800433 mTethering = new Tethering(mContext, mHandler.getLooper());
Robert Greenwalt33cdcdf2011-06-02 17:30:47 -0700434 mTetheringConfigValid = ((mTethering.getTetherableUsbRegexs().length != 0 ||
Danica Chang96567052010-08-11 14:54:43 -0700435 mTethering.getTetherableWifiRegexs().length != 0 ||
436 mTethering.getTetherableBluetoothRegexs().length != 0) &&
Robert Greenwalt33cdcdf2011-06-02 17:30:47 -0700437 mTethering.getUpstreamIfaceTypes().length != 0);
Robert Greenwaltf1b66e12010-02-25 12:29:30 -0800438
Robert Greenwalt0e80be12010-09-20 14:35:25 -0700439 if (DBG) {
440 mInetLog = new ArrayList();
441 }
Robert Greenwaltc3c5f862010-10-11 16:00:27 -0700442
443 mSettingsObserver = new SettingsObserver(mHandler, EVENT_APPLY_GLOBAL_HTTP_PROXY);
444 mSettingsObserver.observe(mContext);
Robert Greenwalt6f7c6092010-12-02 11:31:00 -0800445
446 loadGlobalProxy();
Hung-ying Tyan4e723422011-01-19 16:48:38 +0800447
448 VpnManager.startVpnService(context);
The Android Open Source Project28527d22009-03-03 19:31:44 -0800449 }
450
Robert Greenwaltec05b3c2009-10-30 14:17:42 -0700451
The Android Open Source Project28527d22009-03-03 19:31:44 -0800452 /**
Robert Greenwalt0659da32009-07-16 17:21:39 -0700453 * Sets the preferred network.
The Android Open Source Project28527d22009-03-03 19:31:44 -0800454 * @param preference the new preference
455 */
Robert Greenwalt6a2db8a2010-09-23 10:05:56 -0700456 public void setNetworkPreference(int preference) {
The Android Open Source Project28527d22009-03-03 19:31:44 -0800457 enforceChangePermission();
Robert Greenwalt6a2db8a2010-09-23 10:05:56 -0700458
459 mHandler.sendMessage(mHandler.obtainMessage(EVENT_SET_NETWORK_PREFERENCE, preference, 0));
The Android Open Source Project28527d22009-03-03 19:31:44 -0800460 }
461
462 public int getNetworkPreference() {
463 enforceAccessPermission();
Robert Greenwalt6a2db8a2010-09-23 10:05:56 -0700464 int preference;
465 synchronized(this) {
466 preference = mNetworkPreference;
467 }
468 return preference;
The Android Open Source Project28527d22009-03-03 19:31:44 -0800469 }
470
Robert Greenwalt6a2db8a2010-09-23 10:05:56 -0700471 private void handleSetNetworkPreference(int preference) {
472 if (ConnectivityManager.isNetworkTypeValid(preference) &&
Robert Greenwalt34848c02011-03-25 13:09:25 -0700473 mNetConfigs[preference] != null &&
474 mNetConfigs[preference].isDefault()) {
Robert Greenwalt6a2db8a2010-09-23 10:05:56 -0700475 if (mNetworkPreference != preference) {
476 final ContentResolver cr = mContext.getContentResolver();
477 Settings.Secure.putInt(cr, Settings.Secure.NETWORK_PREFERENCE, preference);
478 synchronized(this) {
479 mNetworkPreference = preference;
480 }
481 enforcePreference();
482 }
483 }
The Android Open Source Project28527d22009-03-03 19:31:44 -0800484 }
Robert Greenwalt0659da32009-07-16 17:21:39 -0700485
The Android Open Source Project28527d22009-03-03 19:31:44 -0800486 private int getPersistedNetworkPreference() {
487 final ContentResolver cr = mContext.getContentResolver();
488
489 final int networkPrefSetting = Settings.Secure
490 .getInt(cr, Settings.Secure.NETWORK_PREFERENCE, -1);
491 if (networkPrefSetting != -1) {
492 return networkPrefSetting;
493 }
494
495 return ConnectivityManager.DEFAULT_NETWORK_PREFERENCE;
496 }
Robert Greenwalt0659da32009-07-16 17:21:39 -0700497
The Android Open Source Project28527d22009-03-03 19:31:44 -0800498 /**
Robert Greenwalt0659da32009-07-16 17:21:39 -0700499 * Make the state of network connectivity conform to the preference settings
The Android Open Source Project28527d22009-03-03 19:31:44 -0800500 * In this method, we only tear down a non-preferred network. Establishing
501 * a connection to the preferred network is taken care of when we handle
502 * the disconnect event from the non-preferred network
503 * (see {@link #handleDisconnect(NetworkInfo)}).
504 */
505 private void enforcePreference() {
Robert Greenwalt2034b912009-08-12 16:08:25 -0700506 if (mNetTrackers[mNetworkPreference].getNetworkInfo().isConnected())
The Android Open Source Project28527d22009-03-03 19:31:44 -0800507 return;
508
Robert Greenwalt2034b912009-08-12 16:08:25 -0700509 if (!mNetTrackers[mNetworkPreference].isAvailable())
510 return;
The Android Open Source Project28527d22009-03-03 19:31:44 -0800511
Robert Greenwalt2034b912009-08-12 16:08:25 -0700512 for (int t=0; t <= ConnectivityManager.MAX_RADIO_TYPE; t++) {
Robert Greenwaltec05b3c2009-10-30 14:17:42 -0700513 if (t != mNetworkPreference && mNetTrackers[t] != null &&
Robert Greenwalt2034b912009-08-12 16:08:25 -0700514 mNetTrackers[t].getNetworkInfo().isConnected()) {
Robert Greenwaltf3f045b2009-08-20 15:25:14 -0700515 if (DBG) {
Wink Savillee70c6f52010-12-03 12:01:38 -0800516 log("tearing down " + mNetTrackers[t].getNetworkInfo() +
Robert Greenwaltf3f045b2009-08-20 15:25:14 -0700517 " in enforcePreference");
518 }
Robert Greenwalt2034b912009-08-12 16:08:25 -0700519 teardown(mNetTrackers[t]);
The Android Open Source Project28527d22009-03-03 19:31:44 -0800520 }
521 }
522 }
523
524 private boolean teardown(NetworkStateTracker netTracker) {
525 if (netTracker.teardown()) {
526 netTracker.setTeardownRequested(true);
527 return true;
528 } else {
529 return false;
530 }
531 }
532
533 /**
534 * Return NetworkInfo for the active (i.e., connected) network interface.
535 * It is assumed that at most one network is active at a time. If more
536 * than one is active, it is indeterminate which will be returned.
Robert Greenwalt0659da32009-07-16 17:21:39 -0700537 * @return the info for the active network, or {@code null} if none is
538 * active
The Android Open Source Project28527d22009-03-03 19:31:44 -0800539 */
540 public NetworkInfo getActiveNetworkInfo() {
Robert Greenwalte1544bb2011-05-20 12:23:41 -0700541 return getNetworkInfo(mActiveDefaultNetwork);
The Android Open Source Project28527d22009-03-03 19:31:44 -0800542 }
543
544 public NetworkInfo getNetworkInfo(int networkType) {
545 enforceAccessPermission();
546 if (ConnectivityManager.isNetworkTypeValid(networkType)) {
547 NetworkStateTracker t = mNetTrackers[networkType];
548 if (t != null)
549 return t.getNetworkInfo();
550 }
551 return null;
552 }
553
554 public NetworkInfo[] getAllNetworkInfo() {
555 enforceAccessPermission();
Robert Greenwaltec05b3c2009-10-30 14:17:42 -0700556 NetworkInfo[] result = new NetworkInfo[mNetworksDefined];
The Android Open Source Project28527d22009-03-03 19:31:44 -0800557 int i = 0;
558 for (NetworkStateTracker t : mNetTrackers) {
Robert Greenwaltec05b3c2009-10-30 14:17:42 -0700559 if(t != null) result[i++] = t.getNetworkInfo();
The Android Open Source Project28527d22009-03-03 19:31:44 -0800560 }
561 return result;
562 }
563
Robert Greenwalt9f0ee4f2010-09-14 09:18:02 -0700564 /**
565 * Return LinkProperties for the active (i.e., connected) default
566 * network interface. It is assumed that at most one default network
567 * is active at a time. If more than one is active, it is indeterminate
568 * which will be returned.
569 * @return the ip properties for the active network, or {@code null} if
570 * none is active
571 */
572 public LinkProperties getActiveLinkProperties() {
Robert Greenwalte1544bb2011-05-20 12:23:41 -0700573 return getLinkProperties(mActiveDefaultNetwork);
Robert Greenwalt9f0ee4f2010-09-14 09:18:02 -0700574 }
575
576 public LinkProperties getLinkProperties(int networkType) {
577 enforceAccessPermission();
578 if (ConnectivityManager.isNetworkTypeValid(networkType)) {
579 NetworkStateTracker t = mNetTrackers[networkType];
580 if (t != null) return t.getLinkProperties();
581 }
582 return null;
583 }
584
The Android Open Source Project28527d22009-03-03 19:31:44 -0800585 public boolean setRadios(boolean turnOn) {
586 boolean result = true;
587 enforceChangePermission();
588 for (NetworkStateTracker t : mNetTrackers) {
Robert Greenwaltec05b3c2009-10-30 14:17:42 -0700589 if (t != null) result = t.setRadio(turnOn) && result;
The Android Open Source Project28527d22009-03-03 19:31:44 -0800590 }
591 return result;
592 }
593
594 public boolean setRadio(int netType, boolean turnOn) {
595 enforceChangePermission();
596 if (!ConnectivityManager.isNetworkTypeValid(netType)) {
597 return false;
598 }
599 NetworkStateTracker tracker = mNetTrackers[netType];
600 return tracker != null && tracker.setRadio(turnOn);
601 }
602
Robert Greenwaltaffc3a12009-09-27 17:27:04 -0700603 /**
604 * Used to notice when the calling process dies so we can self-expire
605 *
606 * Also used to know if the process has cleaned up after itself when
607 * our auto-expire timer goes off. The timer has a link to an object.
608 *
609 */
Robert Greenwalt2034b912009-08-12 16:08:25 -0700610 private class FeatureUser implements IBinder.DeathRecipient {
611 int mNetworkType;
612 String mFeature;
613 IBinder mBinder;
614 int mPid;
615 int mUid;
Robert Greenwalt3eeb6032009-12-21 18:24:07 -0800616 long mCreateTime;
Robert Greenwalt2034b912009-08-12 16:08:25 -0700617
618 FeatureUser(int type, String feature, IBinder binder) {
619 super();
620 mNetworkType = type;
621 mFeature = feature;
622 mBinder = binder;
623 mPid = getCallingPid();
624 mUid = getCallingUid();
Robert Greenwalt3eeb6032009-12-21 18:24:07 -0800625 mCreateTime = System.currentTimeMillis();
Robert Greenwaltaffc3a12009-09-27 17:27:04 -0700626
Robert Greenwalt2034b912009-08-12 16:08:25 -0700627 try {
628 mBinder.linkToDeath(this, 0);
629 } catch (RemoteException e) {
630 binderDied();
631 }
632 }
633
634 void unlinkDeathRecipient() {
635 mBinder.unlinkToDeath(this, 0);
636 }
637
638 public void binderDied() {
Wink Savillee70c6f52010-12-03 12:01:38 -0800639 log("ConnectivityService FeatureUser binderDied(" +
Robert Greenwalt3eeb6032009-12-21 18:24:07 -0800640 mNetworkType + ", " + mFeature + ", " + mBinder + "), created " +
641 (System.currentTimeMillis() - mCreateTime) + " mSec ago");
Robert Greenwaltaffc3a12009-09-27 17:27:04 -0700642 stopUsingNetworkFeature(this, false);
Robert Greenwalt2034b912009-08-12 16:08:25 -0700643 }
644
Robert Greenwaltaffc3a12009-09-27 17:27:04 -0700645 public void expire() {
Wink Savillee70c6f52010-12-03 12:01:38 -0800646 log("ConnectivityService FeatureUser expire(" +
Robert Greenwalt3eeb6032009-12-21 18:24:07 -0800647 mNetworkType + ", " + mFeature + ", " + mBinder +"), created " +
648 (System.currentTimeMillis() - mCreateTime) + " mSec ago");
Robert Greenwaltaffc3a12009-09-27 17:27:04 -0700649 stopUsingNetworkFeature(this, false);
650 }
Robert Greenwalt3eeb6032009-12-21 18:24:07 -0800651
652 public String toString() {
653 return "FeatureUser("+mNetworkType+","+mFeature+","+mPid+","+mUid+"), created " +
654 (System.currentTimeMillis() - mCreateTime) + " mSec ago";
655 }
Robert Greenwalt2034b912009-08-12 16:08:25 -0700656 }
657
Robert Greenwaltaffc3a12009-09-27 17:27:04 -0700658 // javadoc from interface
Robert Greenwalt2034b912009-08-12 16:08:25 -0700659 public int startUsingNetworkFeature(int networkType, String feature,
660 IBinder binder) {
661 if (DBG) {
Wink Savillee70c6f52010-12-03 12:01:38 -0800662 log("startUsingNetworkFeature for net " + networkType + ": " + feature);
Robert Greenwalt2034b912009-08-12 16:08:25 -0700663 }
The Android Open Source Project28527d22009-03-03 19:31:44 -0800664 enforceChangePermission();
Robert Greenwaltec05b3c2009-10-30 14:17:42 -0700665 if (!ConnectivityManager.isNetworkTypeValid(networkType) ||
Robert Greenwalt34848c02011-03-25 13:09:25 -0700666 mNetConfigs[networkType] == null) {
Robert Greenwalt2034b912009-08-12 16:08:25 -0700667 return Phone.APN_REQUEST_FAILED;
The Android Open Source Project28527d22009-03-03 19:31:44 -0800668 }
Robert Greenwalt2034b912009-08-12 16:08:25 -0700669
Robert Greenwaltaffc3a12009-09-27 17:27:04 -0700670 FeatureUser f = new FeatureUser(networkType, feature, binder);
Robert Greenwalt2034b912009-08-12 16:08:25 -0700671
672 // TODO - move this into the MobileDataStateTracker
673 int usedNetworkType = networkType;
674 if(networkType == ConnectivityManager.TYPE_MOBILE) {
Wink Savilleb7c92c72011-03-12 14:52:01 -0800675 usedNetworkType = convertFeatureToNetworkType(feature);
676 if (usedNetworkType < 0) {
677 Slog.e(TAG, "Can't match any netTracker!");
678 usedNetworkType = networkType;
Robert Greenwalt2034b912009-08-12 16:08:25 -0700679 }
680 }
681 NetworkStateTracker network = mNetTrackers[usedNetworkType];
682 if (network != null) {
Robert Greenwalt5364d752010-12-15 13:26:33 -0800683 Integer currentPid = new Integer(getCallingPid());
Robert Greenwalt2034b912009-08-12 16:08:25 -0700684 if (usedNetworkType != networkType) {
Robert Greenwalt2034b912009-08-12 16:08:25 -0700685 NetworkStateTracker radio = mNetTrackers[networkType];
686 NetworkInfo ni = network.getNetworkInfo();
687
688 if (ni.isAvailable() == false) {
Wink Savillee70c6f52010-12-03 12:01:38 -0800689 if (DBG) log("special network not available");
Robert Greenwalt2cc87442010-12-29 14:35:21 -0800690 if (!TextUtils.equals(feature,Phone.FEATURE_ENABLE_DUN_ALWAYS)) {
691 return Phone.APN_TYPE_NOT_AVAILABLE;
692 } else {
693 // else make the attempt anyway - probably giving REQUEST_STARTED below
694 }
Robert Greenwalt2034b912009-08-12 16:08:25 -0700695 }
696
Robert Greenwaltaffc3a12009-09-27 17:27:04 -0700697 synchronized(this) {
698 mFeatureUsers.add(f);
699 if (!mNetRequestersPids[usedNetworkType].contains(currentPid)) {
700 // this gets used for per-pid dns when connected
701 mNetRequestersPids[usedNetworkType].add(currentPid);
702 }
Robert Greenwalt2034b912009-08-12 16:08:25 -0700703 }
Robert Greenwaltaffc3a12009-09-27 17:27:04 -0700704
Robert Greenwalt20f819c2011-05-03 19:02:44 -0700705 int restoreTimer = getRestoreDefaultNetworkDelay(usedNetworkType);
706
707 if (restoreTimer >= 0) {
708 mHandler.sendMessageDelayed(
709 mHandler.obtainMessage(EVENT_RESTORE_DEFAULT_NETWORK, f), restoreTimer);
710 }
Robert Greenwalt2034b912009-08-12 16:08:25 -0700711
Robert Greenwalta52c75a2009-08-19 20:19:33 -0700712 if ((ni.isConnectedOrConnecting() == true) &&
713 !network.isTeardownRequested()) {
Robert Greenwalt2034b912009-08-12 16:08:25 -0700714 if (ni.isConnected() == true) {
715 // add the pid-specific dns
Robert Greenwalt3afbead2010-07-23 15:46:26 -0700716 handleDnsConfigurationChange(networkType);
Wink Savillee70c6f52010-12-03 12:01:38 -0800717 if (DBG) log("special network already active");
Robert Greenwalt2034b912009-08-12 16:08:25 -0700718 return Phone.APN_ALREADY_ACTIVE;
719 }
Wink Savillee70c6f52010-12-03 12:01:38 -0800720 if (DBG) log("special network already connecting");
Robert Greenwalt2034b912009-08-12 16:08:25 -0700721 return Phone.APN_REQUEST_STARTED;
722 }
723
724 // check if the radio in play can make another contact
725 // assume if cannot for now
726
Wink Savillee70c6f52010-12-03 12:01:38 -0800727 if (DBG) log("reconnecting to special network");
Robert Greenwalt2034b912009-08-12 16:08:25 -0700728 network.reconnect();
729 return Phone.APN_REQUEST_STARTED;
730 } else {
Robert Greenwalt5364d752010-12-15 13:26:33 -0800731 // need to remember this unsupported request so we respond appropriately on stop
732 synchronized(this) {
733 mFeatureUsers.add(f);
734 if (!mNetRequestersPids[usedNetworkType].contains(currentPid)) {
735 // this gets used for per-pid dns when connected
736 mNetRequestersPids[usedNetworkType].add(currentPid);
737 }
738 }
Robert Greenwaltd391e892010-05-18 10:52:51 -0700739 return -1;
Robert Greenwalt2034b912009-08-12 16:08:25 -0700740 }
741 }
742 return Phone.APN_TYPE_NOT_AVAILABLE;
The Android Open Source Project28527d22009-03-03 19:31:44 -0800743 }
744
Robert Greenwaltaffc3a12009-09-27 17:27:04 -0700745 // javadoc from interface
The Android Open Source Project28527d22009-03-03 19:31:44 -0800746 public int stopUsingNetworkFeature(int networkType, String feature) {
Robert Greenwalt28f43012009-10-06 17:52:40 -0700747 enforceChangePermission();
748
Robert Greenwaltaffc3a12009-09-27 17:27:04 -0700749 int pid = getCallingPid();
750 int uid = getCallingUid();
751
752 FeatureUser u = null;
753 boolean found = false;
754
755 synchronized(this) {
756 for (int i = 0; i < mFeatureUsers.size() ; i++) {
757 u = (FeatureUser)mFeatureUsers.get(i);
758 if (uid == u.mUid && pid == u.mPid &&
759 networkType == u.mNetworkType &&
760 TextUtils.equals(feature, u.mFeature)) {
761 found = true;
762 break;
763 }
764 }
765 }
766 if (found && u != null) {
767 // stop regardless of how many other time this proc had called start
768 return stopUsingNetworkFeature(u, true);
769 } else {
770 // none found!
Wink Savillee70c6f52010-12-03 12:01:38 -0800771 if (DBG) log("ignoring stopUsingNetworkFeature - not a live request");
Robert Greenwaltaffc3a12009-09-27 17:27:04 -0700772 return 1;
773 }
Robert Greenwalt2034b912009-08-12 16:08:25 -0700774 }
775
Robert Greenwaltaffc3a12009-09-27 17:27:04 -0700776 private int stopUsingNetworkFeature(FeatureUser u, boolean ignoreDups) {
777 int networkType = u.mNetworkType;
778 String feature = u.mFeature;
779 int pid = u.mPid;
780 int uid = u.mUid;
781
782 NetworkStateTracker tracker = null;
783 boolean callTeardown = false; // used to carry our decision outside of sync block
784
Robert Greenwalt2034b912009-08-12 16:08:25 -0700785 if (DBG) {
Wink Savillee70c6f52010-12-03 12:01:38 -0800786 log("stopUsingNetworkFeature for net " + networkType +
Robert Greenwalt2034b912009-08-12 16:08:25 -0700787 ": " + feature);
788 }
Robert Greenwalt28f43012009-10-06 17:52:40 -0700789
The Android Open Source Project28527d22009-03-03 19:31:44 -0800790 if (!ConnectivityManager.isNetworkTypeValid(networkType)) {
791 return -1;
792 }
Robert Greenwalt2034b912009-08-12 16:08:25 -0700793
Robert Greenwaltaffc3a12009-09-27 17:27:04 -0700794 // need to link the mFeatureUsers list with the mNetRequestersPids state in this
795 // sync block
796 synchronized(this) {
797 // check if this process still has an outstanding start request
798 if (!mFeatureUsers.contains(u)) {
Wink Savillee70c6f52010-12-03 12:01:38 -0800799 if (DBG) log("ignoring - this process has no outstanding requests");
Robert Greenwalt2034b912009-08-12 16:08:25 -0700800 return 1;
801 }
Robert Greenwaltaffc3a12009-09-27 17:27:04 -0700802 u.unlinkDeathRecipient();
803 mFeatureUsers.remove(mFeatureUsers.indexOf(u));
804 // If we care about duplicate requests, check for that here.
805 //
806 // This is done to support the extension of a request - the app
807 // can request we start the network feature again and renew the
808 // auto-shutoff delay. Normal "stop" calls from the app though
809 // do not pay attention to duplicate requests - in effect the
810 // API does not refcount and a single stop will counter multiple starts.
811 if (ignoreDups == false) {
812 for (int i = 0; i < mFeatureUsers.size() ; i++) {
813 FeatureUser x = (FeatureUser)mFeatureUsers.get(i);
814 if (x.mUid == u.mUid && x.mPid == u.mPid &&
815 x.mNetworkType == u.mNetworkType &&
816 TextUtils.equals(x.mFeature, u.mFeature)) {
Wink Savillee70c6f52010-12-03 12:01:38 -0800817 if (DBG) log("ignoring stopUsingNetworkFeature as dup is found");
Robert Greenwaltaffc3a12009-09-27 17:27:04 -0700818 return 1;
819 }
820 }
Robert Greenwalt2034b912009-08-12 16:08:25 -0700821 }
Robert Greenwaltaffc3a12009-09-27 17:27:04 -0700822
823 // TODO - move to MobileDataStateTracker
824 int usedNetworkType = networkType;
825 if (networkType == ConnectivityManager.TYPE_MOBILE) {
Wink Savilleb7c92c72011-03-12 14:52:01 -0800826 usedNetworkType = convertFeatureToNetworkType(feature);
827 if (usedNetworkType < 0) {
828 usedNetworkType = networkType;
Robert Greenwaltaffc3a12009-09-27 17:27:04 -0700829 }
830 }
831 tracker = mNetTrackers[usedNetworkType];
Robert Greenwaltec05b3c2009-10-30 14:17:42 -0700832 if (tracker == null) {
Wink Savillee70c6f52010-12-03 12:01:38 -0800833 if (DBG) log("ignoring - no known tracker for net type " + usedNetworkType);
Robert Greenwaltec05b3c2009-10-30 14:17:42 -0700834 return -1;
835 }
836 if (usedNetworkType != networkType) {
Robert Greenwaltaffc3a12009-09-27 17:27:04 -0700837 Integer currentPid = new Integer(pid);
Robert Greenwaltaffc3a12009-09-27 17:27:04 -0700838 mNetRequestersPids[usedNetworkType].remove(currentPid);
Robert Greenwalt0ca68a02009-12-17 14:54:59 -0800839 reassessPidDns(pid, true);
Robert Greenwaltaffc3a12009-09-27 17:27:04 -0700840 if (mNetRequestersPids[usedNetworkType].size() != 0) {
Wink Savillee70c6f52010-12-03 12:01:38 -0800841 if (DBG) log("not tearing down special network - " +
Robert Greenwaltaffc3a12009-09-27 17:27:04 -0700842 "others still using it");
843 return 1;
844 }
845 callTeardown = true;
Robert Greenwalt9f3be4c2011-01-10 11:58:31 -0800846 } else {
847 if (DBG) log("not a known feature - dropping");
Robert Greenwaltaffc3a12009-09-27 17:27:04 -0700848 }
849 }
Wink Savillee70c6f52010-12-03 12:01:38 -0800850 if (DBG) log("Doing network teardown");
Robert Greenwaltaffc3a12009-09-27 17:27:04 -0700851 if (callTeardown) {
852 tracker.teardown();
Robert Greenwalt2034b912009-08-12 16:08:25 -0700853 return 1;
854 } else {
Robert Greenwaltd391e892010-05-18 10:52:51 -0700855 return -1;
Robert Greenwalt2034b912009-08-12 16:08:25 -0700856 }
The Android Open Source Project28527d22009-03-03 19:31:44 -0800857 }
858
859 /**
Robert Greenwalt7fe44cb2010-08-27 09:24:29 -0700860 * @deprecated use requestRouteToHostAddress instead
861 *
The Android Open Source Project28527d22009-03-03 19:31:44 -0800862 * Ensure that a network route exists to deliver traffic to the specified
863 * host via the specified network interface.
Robert Greenwalt0659da32009-07-16 17:21:39 -0700864 * @param networkType the type of the network over which traffic to the
865 * specified host is to be routed
866 * @param hostAddress the IP address of the host to which the route is
867 * desired
The Android Open Source Project28527d22009-03-03 19:31:44 -0800868 * @return {@code true} on success, {@code false} on failure
869 */
870 public boolean requestRouteToHost(int networkType, int hostAddress) {
Robert Greenwalt7fe44cb2010-08-27 09:24:29 -0700871 InetAddress inetAddress = NetworkUtils.intToInetAddress(hostAddress);
872
873 if (inetAddress == null) {
874 return false;
875 }
876
877 return requestRouteToHostAddress(networkType, inetAddress.getAddress());
878 }
879
880 /**
881 * Ensure that a network route exists to deliver traffic to the specified
882 * host via the specified network interface.
883 * @param networkType the type of the network over which traffic to the
884 * specified host is to be routed
885 * @param hostAddress the IP address of the host to which the route is
886 * desired
887 * @return {@code true} on success, {@code false} on failure
888 */
889 public boolean requestRouteToHostAddress(int networkType, byte[] hostAddress) {
The Android Open Source Project28527d22009-03-03 19:31:44 -0800890 enforceChangePermission();
891 if (!ConnectivityManager.isNetworkTypeValid(networkType)) {
892 return false;
893 }
894 NetworkStateTracker tracker = mNetTrackers[networkType];
Robert Greenwalt4666ed02009-09-10 15:06:20 -0700895
Robert Greenwaltec05b3c2009-10-30 14:17:42 -0700896 if (tracker == null || !tracker.getNetworkInfo().isConnected() ||
897 tracker.isTeardownRequested()) {
Robert Greenwalt4666ed02009-09-10 15:06:20 -0700898 if (DBG) {
Wink Savillee70c6f52010-12-03 12:01:38 -0800899 log("requestRouteToHostAddress on down network " +
Robert Greenwalt7fe44cb2010-08-27 09:24:29 -0700900 "(" + networkType + ") - dropped");
Robert Greenwalt4666ed02009-09-10 15:06:20 -0700901 }
902 return false;
The Android Open Source Project28527d22009-03-03 19:31:44 -0800903 }
Robert Greenwalta7dfbd32010-06-15 15:43:39 -0700904 try {
Robert Greenwalt7fe44cb2010-08-27 09:24:29 -0700905 InetAddress addr = InetAddress.getByAddress(hostAddress);
Robert Greenwaltbd492212011-05-06 17:10:53 -0700906 return addHostRoute(tracker, addr, 0);
Robert Greenwalta7dfbd32010-06-15 15:43:39 -0700907 } catch (UnknownHostException e) {}
908 return false;
Irfan Sheriff7f132d92010-06-09 15:39:36 -0700909 }
910
911 /**
912 * Ensure that a network route exists to deliver traffic to the specified
913 * host via the mobile data network.
914 * @param hostAddress the IP address of the host to which the route is desired,
915 * in network byte order.
Robert Greenwalta7dfbd32010-06-15 15:43:39 -0700916 * TODO - deprecate
Irfan Sheriff7f132d92010-06-09 15:39:36 -0700917 * @return {@code true} on success, {@code false} on failure
918 */
Robert Greenwaltbd492212011-05-06 17:10:53 -0700919 private boolean addHostRoute(NetworkStateTracker nt, InetAddress hostAddress, int cycleCount) {
Robert Greenwaltbd492212011-05-06 17:10:53 -0700920 LinkProperties lp = nt.getLinkProperties();
921 if ((lp == null) || (hostAddress == null)) return false;
Irfan Sheriff7f132d92010-06-09 15:39:36 -0700922
Robert Greenwaltbd492212011-05-06 17:10:53 -0700923 String interfaceName = lp.getInterfaceName();
Irfan Sheriff7f132d92010-06-09 15:39:36 -0700924 if (DBG) {
Robert Greenwaltbd492212011-05-06 17:10:53 -0700925 log("Requested host route to " + hostAddress + "(" + interfaceName + "), cycleCount=" +
926 cycleCount);
Irfan Sheriff7f132d92010-06-09 15:39:36 -0700927 }
Robert Greenwaltbd492212011-05-06 17:10:53 -0700928 if (interfaceName == null) {
Wink Savillee70c6f52010-12-03 12:01:38 -0800929 if (DBG) loge("addHostRoute failed due to null interface name");
Irfan Sheriff7f132d92010-06-09 15:39:36 -0700930 return false;
931 }
Robert Greenwaltbd492212011-05-06 17:10:53 -0700932
933 RouteInfo bestRoute = RouteInfo.selectBestRoute(lp.getRoutes(), hostAddress);
Robert Greenwalt355205c2011-05-10 15:05:02 -0700934 InetAddress gatewayAddress = null;
Robert Greenwaltbd492212011-05-06 17:10:53 -0700935 if (bestRoute != null) {
Robert Greenwalt355205c2011-05-10 15:05:02 -0700936 gatewayAddress = bestRoute.getGateway();
Robert Greenwaltbd492212011-05-06 17:10:53 -0700937 // if the best route is ourself, don't relf-reference, just add the host route
Robert Greenwalt355205c2011-05-10 15:05:02 -0700938 if (hostAddress.equals(gatewayAddress)) gatewayAddress = null;
Robert Greenwaltbd492212011-05-06 17:10:53 -0700939 }
Robert Greenwalt355205c2011-05-10 15:05:02 -0700940 if (gatewayAddress != null) {
Robert Greenwaltbd492212011-05-06 17:10:53 -0700941 if (cycleCount > MAX_HOSTROUTE_CYCLE_COUNT) {
942 loge("Error adding hostroute - too much recursion");
943 return false;
944 }
Robert Greenwalt355205c2011-05-10 15:05:02 -0700945 if (!addHostRoute(nt, gatewayAddress, cycleCount+1)) return false;
Robert Greenwaltbd492212011-05-06 17:10:53 -0700946 }
Robert Greenwalt355205c2011-05-10 15:05:02 -0700947
948 RouteInfo route = RouteInfo.makeHostRoute(hostAddress, gatewayAddress);
949
950 try {
951 mNetd.addRoute(interfaceName, route);
952 return true;
953 } catch (Exception ex) {
954 return false;
955 }
Robert Greenwaltbd492212011-05-06 17:10:53 -0700956 }
957
958 // TODO support the removal of single host routes. Keep a ref count of them so we
959 // aren't over-zealous
960 private boolean removeHostRoute(NetworkStateTracker nt, InetAddress hostAddress) {
961 return false;
The Android Open Source Project28527d22009-03-03 19:31:44 -0800962 }
963
964 /**
965 * @see ConnectivityManager#getBackgroundDataSetting()
966 */
967 public boolean getBackgroundDataSetting() {
Robert Greenwaltd62c7002010-12-29 16:15:02 -0800968 return mBackgroundDataEnabled.get();
The Android Open Source Project28527d22009-03-03 19:31:44 -0800969 }
Robert Greenwalt0659da32009-07-16 17:21:39 -0700970
The Android Open Source Project28527d22009-03-03 19:31:44 -0800971 /**
972 * @see ConnectivityManager#setBackgroundDataSetting(boolean)
973 */
974 public void setBackgroundDataSetting(boolean allowBackgroundDataUsage) {
975 mContext.enforceCallingOrSelfPermission(
976 android.Manifest.permission.CHANGE_BACKGROUND_DATA_SETTING,
977 "ConnectivityService");
Robert Greenwalt0659da32009-07-16 17:21:39 -0700978
Robert Greenwaltd62c7002010-12-29 16:15:02 -0800979 mBackgroundDataEnabled.set(allowBackgroundDataUsage);
980
Robert Greenwalt6a2db8a2010-09-23 10:05:56 -0700981 mHandler.sendMessage(mHandler.obtainMessage(EVENT_SET_BACKGROUND_DATA,
982 (allowBackgroundDataUsage ? ENABLED : DISABLED), 0));
983 }
The Android Open Source Project28527d22009-03-03 19:31:44 -0800984
Robert Greenwalt6a2db8a2010-09-23 10:05:56 -0700985 private void handleSetBackgroundData(boolean enabled) {
Robert Greenwalt0ffdef12011-02-25 13:44:09 -0800986 Settings.Secure.putInt(mContext.getContentResolver(),
987 Settings.Secure.BACKGROUND_DATA, enabled ? 1 : 0);
988 Intent broadcast = new Intent(
989 ConnectivityManager.ACTION_BACKGROUND_DATA_SETTING_CHANGED);
990 mContext.sendBroadcast(broadcast);
Robert Greenwalt0659da32009-07-16 17:21:39 -0700991 }
992
Robert Greenwalt1b21f6c2010-02-23 18:58:05 -0800993 /**
994 * @see ConnectivityManager#getMobileDataEnabled()
995 */
996 public boolean getMobileDataEnabled() {
Wink Savilleb9024c62010-12-07 10:31:02 -0800997 // TODO: This detail should probably be in DataConnectionTracker's
998 // which is where we store the value and maybe make this
999 // asynchronous.
Robert Greenwalt1b21f6c2010-02-23 18:58:05 -08001000 enforceAccessPermission();
1001 boolean retVal = Settings.Secure.getInt(mContext.getContentResolver(),
1002 Settings.Secure.MOBILE_DATA, 1) == 1;
Wink Savillee70c6f52010-12-03 12:01:38 -08001003 if (DBG) log("getMobileDataEnabled returning " + retVal);
Robert Greenwalt1b21f6c2010-02-23 18:58:05 -08001004 return retVal;
1005 }
1006
Robert Greenwalt34848c02011-03-25 13:09:25 -07001007 public void setDataDependency(int networkType, boolean met) {
1008 enforceChangePermission();
1009 if (DBG) {
1010 log("setDataDependency(" + networkType + ", " + met + ")");
1011 }
1012 mHandler.sendMessage(mHandler.obtainMessage(EVENT_SET_DEPENDENCY_MET,
1013 (met ? ENABLED : DISABLED), networkType));
1014 }
1015
1016 private void handleSetDependencyMet(int networkType, boolean met) {
1017 if (mNetTrackers[networkType] != null) {
1018 if (DBG) {
1019 log("handleSetDependencyMet(" + networkType + ", " + met + ")");
1020 }
1021 mNetTrackers[networkType].setDependencyMet(met);
1022 }
1023 }
1024
Robert Greenwalt1b21f6c2010-02-23 18:58:05 -08001025 /**
1026 * @see ConnectivityManager#setMobileDataEnabled(boolean)
1027 */
Robert Greenwalt6a2db8a2010-09-23 10:05:56 -07001028 public void setMobileDataEnabled(boolean enabled) {
Robert Greenwalt1b21f6c2010-02-23 18:58:05 -08001029 enforceChangePermission();
Wink Savillee70c6f52010-12-03 12:01:38 -08001030 if (DBG) log("setMobileDataEnabled(" + enabled + ")");
Robert Greenwalt1b21f6c2010-02-23 18:58:05 -08001031
Robert Greenwalt6a2db8a2010-09-23 10:05:56 -07001032 mHandler.sendMessage(mHandler.obtainMessage(EVENT_SET_MOBILE_DATA,
Robert Greenwalt34848c02011-03-25 13:09:25 -07001033 (enabled ? ENABLED : DISABLED), 0));
Robert Greenwalt6a2db8a2010-09-23 10:05:56 -07001034 }
1035
1036 private void handleSetMobileData(boolean enabled) {
Wink Savilleb9024c62010-12-07 10:31:02 -08001037 if (mNetTrackers[ConnectivityManager.TYPE_MOBILE] != null) {
1038 if (DBG) {
1039 Slog.d(TAG, mNetTrackers[ConnectivityManager.TYPE_MOBILE].toString() + enabled);
Robert Greenwalt1b21f6c2010-02-23 18:58:05 -08001040 }
Wink Savilleb9024c62010-12-07 10:31:02 -08001041 mNetTrackers[ConnectivityManager.TYPE_MOBILE].setDataEnable(enabled);
Robert Greenwalt1b21f6c2010-02-23 18:58:05 -08001042 }
1043 }
1044
The Android Open Source Project28527d22009-03-03 19:31:44 -08001045 private void enforceAccessPermission() {
Robert Greenwalt0659da32009-07-16 17:21:39 -07001046 mContext.enforceCallingOrSelfPermission(
1047 android.Manifest.permission.ACCESS_NETWORK_STATE,
1048 "ConnectivityService");
The Android Open Source Project28527d22009-03-03 19:31:44 -08001049 }
1050
1051 private void enforceChangePermission() {
Robert Greenwalt0659da32009-07-16 17:21:39 -07001052 mContext.enforceCallingOrSelfPermission(
1053 android.Manifest.permission.CHANGE_NETWORK_STATE,
1054 "ConnectivityService");
The Android Open Source Project28527d22009-03-03 19:31:44 -08001055 }
1056
Robert Greenwalt0c4828c2010-01-26 11:40:34 -08001057 // TODO Make this a special check when it goes public
1058 private void enforceTetherChangePermission() {
1059 mContext.enforceCallingOrSelfPermission(
1060 android.Manifest.permission.CHANGE_NETWORK_STATE,
1061 "ConnectivityService");
1062 }
1063
Robert Greenwalt8e87f122010-02-11 18:18:40 -08001064 private void enforceTetherAccessPermission() {
1065 mContext.enforceCallingOrSelfPermission(
1066 android.Manifest.permission.ACCESS_NETWORK_STATE,
1067 "ConnectivityService");
1068 }
1069
Robert Greenwalt93dc1042010-06-15 12:19:37 -07001070 private void enforceConnectivityInternalPermission() {
1071 mContext.enforceCallingOrSelfPermission(
1072 android.Manifest.permission.CONNECTIVITY_INTERNAL,
1073 "ConnectivityService");
1074 }
1075
The Android Open Source Project28527d22009-03-03 19:31:44 -08001076 /**
Robert Greenwalt0659da32009-07-16 17:21:39 -07001077 * Handle a {@code DISCONNECTED} event. If this pertains to the non-active
1078 * network, we ignore it. If it is for the active network, we send out a
1079 * broadcast. But first, we check whether it might be possible to connect
1080 * to a different network.
The Android Open Source Project28527d22009-03-03 19:31:44 -08001081 * @param info the {@code NetworkInfo} for the network
1082 */
1083 private void handleDisconnect(NetworkInfo info) {
1084
Robert Greenwalt2034b912009-08-12 16:08:25 -07001085 int prevNetType = info.getType();
The Android Open Source Project28527d22009-03-03 19:31:44 -08001086
Robert Greenwalt2034b912009-08-12 16:08:25 -07001087 mNetTrackers[prevNetType].setTeardownRequested(false);
The Android Open Source Project28527d22009-03-03 19:31:44 -08001088 /*
1089 * If the disconnected network is not the active one, then don't report
1090 * this as a loss of connectivity. What probably happened is that we're
1091 * getting the disconnect for a network that we explicitly disabled
1092 * in accordance with network preference policies.
1093 */
Robert Greenwalt34848c02011-03-25 13:09:25 -07001094 if (!mNetConfigs[prevNetType].isDefault()) {
Robert Greenwalt2034b912009-08-12 16:08:25 -07001095 List pids = mNetRequestersPids[prevNetType];
1096 for (int i = 0; i<pids.size(); i++) {
1097 Integer pid = (Integer)pids.get(i);
1098 // will remove them because the net's no longer connected
1099 // need to do this now as only now do we know the pids and
1100 // can properly null things that are no longer referenced.
1101 reassessPidDns(pid.intValue(), false);
The Android Open Source Project28527d22009-03-03 19:31:44 -08001102 }
The Android Open Source Project28527d22009-03-03 19:31:44 -08001103 }
1104
The Android Open Source Project28527d22009-03-03 19:31:44 -08001105 Intent intent = new Intent(ConnectivityManager.CONNECTIVITY_ACTION);
1106 intent.putExtra(ConnectivityManager.EXTRA_NETWORK_INFO, info);
1107 if (info.isFailover()) {
1108 intent.putExtra(ConnectivityManager.EXTRA_IS_FAILOVER, true);
1109 info.setFailover(false);
1110 }
1111 if (info.getReason() != null) {
1112 intent.putExtra(ConnectivityManager.EXTRA_REASON, info.getReason());
1113 }
1114 if (info.getExtraInfo() != null) {
Robert Greenwalt0659da32009-07-16 17:21:39 -07001115 intent.putExtra(ConnectivityManager.EXTRA_EXTRA_INFO,
1116 info.getExtraInfo());
The Android Open Source Project28527d22009-03-03 19:31:44 -08001117 }
Robert Greenwalt2034b912009-08-12 16:08:25 -07001118
Robert Greenwalt34848c02011-03-25 13:09:25 -07001119 if (mNetConfigs[prevNetType].isDefault()) {
Robert Greenwalt4b7c55e2011-01-11 13:56:33 -08001120 tryFailover(prevNetType);
1121 if (mActiveDefaultNetwork != -1) {
1122 NetworkInfo switchTo = mNetTrackers[mActiveDefaultNetwork].getNetworkInfo();
Robert Greenwalt3cc68d32010-01-25 17:54:29 -08001123 intent.putExtra(ConnectivityManager.EXTRA_OTHER_NETWORK_INFO, switchTo);
1124 } else {
Robert Greenwaltb2a9e492010-09-20 18:01:43 -07001125 mDefaultInetConditionPublished = 0; // we're not connected anymore
Robert Greenwalt3cc68d32010-01-25 17:54:29 -08001126 intent.putExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, true);
1127 }
Robert Greenwaltf55ced92010-01-20 19:29:41 -08001128 }
Robert Greenwaltb2a9e492010-09-20 18:01:43 -07001129 intent.putExtra(ConnectivityManager.EXTRA_INET_CONDITION, mDefaultInetConditionPublished);
Robert Greenwalt36ea8692011-06-15 12:22:07 -07001130
1131 // Reset interface if no other connections are using the same interface
1132 boolean doReset = true;
1133 LinkProperties linkProperties = mNetTrackers[prevNetType].getLinkProperties();
1134 if (linkProperties != null) {
1135 String oldIface = linkProperties.getInterfaceName();
1136 if (TextUtils.isEmpty(oldIface) == false) {
1137 for (NetworkStateTracker networkStateTracker : mNetTrackers) {
1138 if (networkStateTracker == null) continue;
1139 NetworkInfo networkInfo = networkStateTracker.getNetworkInfo();
1140 if (networkInfo.isConnected() && networkInfo.getType() != prevNetType) {
1141 LinkProperties l = networkStateTracker.getLinkProperties();
1142 if (l == null) continue;
1143 if (oldIface.equals(l.getInterfaceName())) {
1144 doReset = false;
1145 break;
1146 }
1147 }
1148 }
1149 }
1150 }
1151
Robert Greenwaltf55ced92010-01-20 19:29:41 -08001152 // do this before we broadcast the change
Robert Greenwalt36ea8692011-06-15 12:22:07 -07001153 handleConnectivityChange(prevNetType, doReset);
Robert Greenwaltf55ced92010-01-20 19:29:41 -08001154
1155 sendStickyBroadcast(intent);
1156 /*
1157 * If the failover network is already connected, then immediately send
1158 * out a followup broadcast indicating successful failover
1159 */
Robert Greenwalt4b7c55e2011-01-11 13:56:33 -08001160 if (mActiveDefaultNetwork != -1) {
1161 sendConnectedBroadcast(mNetTrackers[mActiveDefaultNetwork].getNetworkInfo());
Robert Greenwaltf55ced92010-01-20 19:29:41 -08001162 }
1163 }
1164
Robert Greenwalt4b7c55e2011-01-11 13:56:33 -08001165 private void tryFailover(int prevNetType) {
Robert Greenwalt2034b912009-08-12 16:08:25 -07001166 /*
Robert Greenwalt92564852011-01-06 15:41:07 -08001167 * If this is a default network, check if other defaults are available.
1168 * Try to reconnect on all available and let them hash it out when
1169 * more than one connects.
Robert Greenwalt2034b912009-08-12 16:08:25 -07001170 */
Robert Greenwalt34848c02011-03-25 13:09:25 -07001171 if (mNetConfigs[prevNetType].isDefault()) {
Robert Greenwalt2034b912009-08-12 16:08:25 -07001172 if (mActiveDefaultNetwork == prevNetType) {
1173 mActiveDefaultNetwork = -1;
1174 }
1175
Robert Greenwalt4b7c55e2011-01-11 13:56:33 -08001176 // don't signal a reconnect for anything lower or equal priority than our
1177 // current connected default
1178 // TODO - don't filter by priority now - nice optimization but risky
1179// int currentPriority = -1;
1180// if (mActiveDefaultNetwork != -1) {
Robert Greenwalt34848c02011-03-25 13:09:25 -07001181// currentPriority = mNetConfigs[mActiveDefaultNetwork].mPriority;
Robert Greenwalt4b7c55e2011-01-11 13:56:33 -08001182// }
Robert Greenwaltf55ced92010-01-20 19:29:41 -08001183 for (int checkType=0; checkType <= ConnectivityManager.MAX_NETWORK_TYPE; checkType++) {
Robert Greenwaltec05b3c2009-10-30 14:17:42 -07001184 if (checkType == prevNetType) continue;
Robert Greenwalt34848c02011-03-25 13:09:25 -07001185 if (mNetConfigs[checkType] == null) continue;
1186 if (!mNetConfigs[checkType].isDefault()) continue;
Wink Saville72a95b92011-01-26 15:43:49 -08001187
1188// Enabling the isAvailable() optimization caused mobile to not get
1189// selected if it was in the middle of error handling. Specifically
1190// a moble connection that took 30 seconds to complete the DEACTIVATE_DATA_CALL
1191// would not be available and we wouldn't get connected to anything.
1192// So removing the isAvailable() optimization below for now. TODO: This
1193// optimization should work and we need to investigate why it doesn't work.
1194// This could be related to how DEACTIVATE_DATA_CALL is reporting its
1195// complete before it is really complete.
1196// if (!mNetTrackers[checkType].isAvailable()) continue;
1197
Robert Greenwalt34848c02011-03-25 13:09:25 -07001198// if (currentPriority >= mNetConfigs[checkType].mPriority) continue;
Robert Greenwalt2034b912009-08-12 16:08:25 -07001199
Robert Greenwalt4b7c55e2011-01-11 13:56:33 -08001200 NetworkStateTracker checkTracker = mNetTrackers[checkType];
1201 NetworkInfo checkInfo = checkTracker.getNetworkInfo();
1202 if (!checkInfo.isConnectedOrConnecting() || checkTracker.isTeardownRequested()) {
1203 checkInfo.setFailover(true);
1204 checkTracker.reconnect();
Robert Greenwalt2034b912009-08-12 16:08:25 -07001205 }
Robert Greenwalt4b7c55e2011-01-11 13:56:33 -08001206 if (DBG) log("Attempting to switch to " + checkInfo.getTypeName());
Robert Greenwalt2034b912009-08-12 16:08:25 -07001207 }
The Android Open Source Project28527d22009-03-03 19:31:44 -08001208 }
The Android Open Source Project28527d22009-03-03 19:31:44 -08001209 }
1210
1211 private void sendConnectedBroadcast(NetworkInfo info) {
Robert Greenwaltd3401f92010-09-15 17:36:33 -07001212 sendGeneralBroadcast(info, ConnectivityManager.CONNECTIVITY_ACTION);
1213 }
1214
1215 private void sendInetConditionBroadcast(NetworkInfo info) {
1216 sendGeneralBroadcast(info, ConnectivityManager.INET_CONDITION_ACTION);
1217 }
1218
1219 private void sendGeneralBroadcast(NetworkInfo info, String bcastType) {
1220 Intent intent = new Intent(bcastType);
The Android Open Source Project28527d22009-03-03 19:31:44 -08001221 intent.putExtra(ConnectivityManager.EXTRA_NETWORK_INFO, info);
1222 if (info.isFailover()) {
1223 intent.putExtra(ConnectivityManager.EXTRA_IS_FAILOVER, true);
1224 info.setFailover(false);
1225 }
1226 if (info.getReason() != null) {
1227 intent.putExtra(ConnectivityManager.EXTRA_REASON, info.getReason());
1228 }
1229 if (info.getExtraInfo() != null) {
Robert Greenwalt0659da32009-07-16 17:21:39 -07001230 intent.putExtra(ConnectivityManager.EXTRA_EXTRA_INFO,
1231 info.getExtraInfo());
The Android Open Source Project28527d22009-03-03 19:31:44 -08001232 }
Robert Greenwalt986c7412010-09-08 15:24:47 -07001233 intent.putExtra(ConnectivityManager.EXTRA_INET_CONDITION, mDefaultInetConditionPublished);
Mike Lockwoodfde2b762009-08-14 14:18:49 -04001234 sendStickyBroadcast(intent);
The Android Open Source Project28527d22009-03-03 19:31:44 -08001235 }
1236
1237 /**
1238 * Called when an attempt to fail over to another network has failed.
1239 * @param info the {@link NetworkInfo} for the failed network
1240 */
1241 private void handleConnectionFailure(NetworkInfo info) {
1242 mNetTrackers[info.getType()].setTeardownRequested(false);
The Android Open Source Project28527d22009-03-03 19:31:44 -08001243
Robert Greenwalt2034b912009-08-12 16:08:25 -07001244 String reason = info.getReason();
1245 String extraInfo = info.getExtraInfo();
Robert Greenwalt0659da32009-07-16 17:21:39 -07001246
Robert Greenwalte981bc52010-10-08 16:35:52 -07001247 String reasonText;
1248 if (reason == null) {
1249 reasonText = ".";
1250 } else {
1251 reasonText = " (" + reason + ").";
The Android Open Source Project28527d22009-03-03 19:31:44 -08001252 }
Wink Savillee70c6f52010-12-03 12:01:38 -08001253 loge("Attempt to connect to " + info.getTypeName() + " failed" + reasonText);
Robert Greenwalt2034b912009-08-12 16:08:25 -07001254
1255 Intent intent = new Intent(ConnectivityManager.CONNECTIVITY_ACTION);
1256 intent.putExtra(ConnectivityManager.EXTRA_NETWORK_INFO, info);
1257 if (getActiveNetworkInfo() == null) {
1258 intent.putExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, true);
1259 }
1260 if (reason != null) {
1261 intent.putExtra(ConnectivityManager.EXTRA_REASON, reason);
1262 }
1263 if (extraInfo != null) {
1264 intent.putExtra(ConnectivityManager.EXTRA_EXTRA_INFO, extraInfo);
1265 }
1266 if (info.isFailover()) {
1267 intent.putExtra(ConnectivityManager.EXTRA_IS_FAILOVER, true);
1268 info.setFailover(false);
1269 }
Robert Greenwaltf55ced92010-01-20 19:29:41 -08001270
Robert Greenwalt34848c02011-03-25 13:09:25 -07001271 if (mNetConfigs[info.getType()].isDefault()) {
Robert Greenwalt4b7c55e2011-01-11 13:56:33 -08001272 tryFailover(info.getType());
1273 if (mActiveDefaultNetwork != -1) {
1274 NetworkInfo switchTo = mNetTrackers[mActiveDefaultNetwork].getNetworkInfo();
Robert Greenwalt3cc68d32010-01-25 17:54:29 -08001275 intent.putExtra(ConnectivityManager.EXTRA_OTHER_NETWORK_INFO, switchTo);
1276 } else {
Robert Greenwaltb2a9e492010-09-20 18:01:43 -07001277 mDefaultInetConditionPublished = 0;
Robert Greenwalt3cc68d32010-01-25 17:54:29 -08001278 intent.putExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, true);
1279 }
Robert Greenwaltf55ced92010-01-20 19:29:41 -08001280 }
Robert Greenwalt3cc68d32010-01-25 17:54:29 -08001281
Robert Greenwaltb2a9e492010-09-20 18:01:43 -07001282 intent.putExtra(ConnectivityManager.EXTRA_INET_CONDITION, mDefaultInetConditionPublished);
Mike Lockwoodfde2b762009-08-14 14:18:49 -04001283 sendStickyBroadcast(intent);
Robert Greenwaltf55ced92010-01-20 19:29:41 -08001284 /*
1285 * If the failover network is already connected, then immediately send
1286 * out a followup broadcast indicating successful failover
1287 */
Robert Greenwalt4b7c55e2011-01-11 13:56:33 -08001288 if (mActiveDefaultNetwork != -1) {
1289 sendConnectedBroadcast(mNetTrackers[mActiveDefaultNetwork].getNetworkInfo());
Robert Greenwaltf55ced92010-01-20 19:29:41 -08001290 }
Mike Lockwoodfde2b762009-08-14 14:18:49 -04001291 }
1292
1293 private void sendStickyBroadcast(Intent intent) {
1294 synchronized(this) {
Dianne Hackborna417ff82009-12-08 19:45:14 -08001295 if (!mSystemReady) {
1296 mInitialBroadcast = new Intent(intent);
Mike Lockwoodfde2b762009-08-14 14:18:49 -04001297 }
Dianne Hackborna417ff82009-12-08 19:45:14 -08001298 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
1299 mContext.sendStickyBroadcast(intent);
Mike Lockwoodfde2b762009-08-14 14:18:49 -04001300 }
1301 }
1302
1303 void systemReady() {
Robert Greenwalt355205c2011-05-10 15:05:02 -07001304 IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
1305 mNetd = INetworkManagementService.Stub.asInterface(b);
1306
Mike Lockwoodfde2b762009-08-14 14:18:49 -04001307 synchronized(this) {
1308 mSystemReady = true;
Dianne Hackborna417ff82009-12-08 19:45:14 -08001309 if (mInitialBroadcast != null) {
1310 mContext.sendStickyBroadcast(mInitialBroadcast);
1311 mInitialBroadcast = null;
Mike Lockwoodfde2b762009-08-14 14:18:49 -04001312 }
1313 }
Robert Greenwaltc3c5f862010-10-11 16:00:27 -07001314 // load the global proxy at startup
1315 mHandler.sendMessage(mHandler.obtainMessage(EVENT_APPLY_GLOBAL_HTTP_PROXY));
The Android Open Source Project28527d22009-03-03 19:31:44 -08001316 }
1317
1318 private void handleConnect(NetworkInfo info) {
Robert Greenwalt2034b912009-08-12 16:08:25 -07001319 int type = info.getType();
The Android Open Source Project28527d22009-03-03 19:31:44 -08001320
1321 // snapshot isFailover, because sendConnectedBroadcast() resets it
1322 boolean isFailover = info.isFailover();
Robert Greenwalt2034b912009-08-12 16:08:25 -07001323 NetworkStateTracker thisNet = mNetTrackers[type];
The Android Open Source Project28527d22009-03-03 19:31:44 -08001324
Robert Greenwalt2034b912009-08-12 16:08:25 -07001325 // if this is a default net and other default is running
1326 // kill the one not preferred
Robert Greenwalt34848c02011-03-25 13:09:25 -07001327 if (mNetConfigs[type].isDefault()) {
Robert Greenwalt2034b912009-08-12 16:08:25 -07001328 if (mActiveDefaultNetwork != -1 && mActiveDefaultNetwork != type) {
1329 if ((type != mNetworkPreference &&
Wink Savillef2a62832011-04-07 14:23:45 -07001330 mNetConfigs[mActiveDefaultNetwork].priority >
1331 mNetConfigs[type].priority) ||
Robert Greenwalt2034b912009-08-12 16:08:25 -07001332 mNetworkPreference == mActiveDefaultNetwork) {
1333 // don't accept this one
Wink Savillee70c6f52010-12-03 12:01:38 -08001334 if (DBG) {
1335 log("Not broadcasting CONNECT_ACTION " +
Robert Greenwalt2034b912009-08-12 16:08:25 -07001336 "to torn down network " + info.getTypeName());
Wink Savillee70c6f52010-12-03 12:01:38 -08001337 }
Robert Greenwalt2034b912009-08-12 16:08:25 -07001338 teardown(thisNet);
1339 return;
1340 } else {
1341 // tear down the other
1342 NetworkStateTracker otherNet =
1343 mNetTrackers[mActiveDefaultNetwork];
Wink Savillee70c6f52010-12-03 12:01:38 -08001344 if (DBG) {
1345 log("Policy requires " + otherNet.getNetworkInfo().getTypeName() +
Robert Greenwalt2034b912009-08-12 16:08:25 -07001346 " teardown");
Wink Savillee70c6f52010-12-03 12:01:38 -08001347 }
Robert Greenwalt2034b912009-08-12 16:08:25 -07001348 if (!teardown(otherNet)) {
Wink Savillee70c6f52010-12-03 12:01:38 -08001349 loge("Network declined teardown request");
Robert Greenwalt99910172011-03-29 11:36:28 -07001350 teardown(thisNet);
Robert Greenwalt2034b912009-08-12 16:08:25 -07001351 return;
1352 }
Robert Greenwalt93dc1042010-06-15 12:19:37 -07001353 }
1354 }
1355 synchronized (ConnectivityService.this) {
1356 // have a new default network, release the transition wakelock in a second
1357 // if it's held. The second pause is to allow apps to reconnect over the
1358 // new network
1359 if (mNetTransitionWakeLock.isHeld()) {
1360 mHandler.sendMessageDelayed(mHandler.obtainMessage(
Robert Greenwaltccb36f92010-09-24 14:32:21 -07001361 EVENT_CLEAR_NET_TRANSITION_WAKELOCK,
Robert Greenwalt93dc1042010-06-15 12:19:37 -07001362 mNetTransitionWakeLockSerialNumber, 0),
1363 1000);
Robert Greenwalt2034b912009-08-12 16:08:25 -07001364 }
1365 }
1366 mActiveDefaultNetwork = type;
Robert Greenwalt986c7412010-09-08 15:24:47 -07001367 // this will cause us to come up initially as unconnected and switching
1368 // to connected after our normal pause unless somebody reports us as reall
1369 // disconnected
1370 mDefaultInetConditionPublished = 0;
1371 mDefaultConnectionSequence++;
1372 mInetConditionChangeInFlight = false;
1373 // Don't do this - if we never sign in stay, grey
1374 //reportNetworkCondition(mActiveDefaultNetwork, 100);
Robert Greenwalt2034b912009-08-12 16:08:25 -07001375 }
The Android Open Source Project28527d22009-03-03 19:31:44 -08001376 thisNet.setTeardownRequested(false);
Irfan Sheriff7f132d92010-06-09 15:39:36 -07001377 updateNetworkSettings(thisNet);
Robert Greenwalt36ea8692011-06-15 12:22:07 -07001378 handleConnectivityChange(type, false);
Robert Greenwalt2034b912009-08-12 16:08:25 -07001379 sendConnectedBroadcast(info);
The Android Open Source Project28527d22009-03-03 19:31:44 -08001380 }
1381
The Android Open Source Project28527d22009-03-03 19:31:44 -08001382 /**
Robert Greenwalt3afbead2010-07-23 15:46:26 -07001383 * After a change in the connectivity state of a network. We're mainly
1384 * concerned with making sure that the list of DNS servers is set up
1385 * according to which networks are connected, and ensuring that the
1386 * right routing table entries exist.
The Android Open Source Project28527d22009-03-03 19:31:44 -08001387 */
Robert Greenwalt36ea8692011-06-15 12:22:07 -07001388 private void handleConnectivityChange(int netType, boolean doReset) {
The Android Open Source Project28527d22009-03-03 19:31:44 -08001389 /*
Robert Greenwalt2034b912009-08-12 16:08:25 -07001390 * If a non-default network is enabled, add the host routes that
Robert Greenwalt3afbead2010-07-23 15:46:26 -07001391 * will allow it's DNS servers to be accessed.
The Android Open Source Project28527d22009-03-03 19:31:44 -08001392 */
Robert Greenwalt3afbead2010-07-23 15:46:26 -07001393 handleDnsConfigurationChange(netType);
Robert Greenwalt2034b912009-08-12 16:08:25 -07001394
Robert Greenwalt3afbead2010-07-23 15:46:26 -07001395 if (mNetTrackers[netType].getNetworkInfo().isConnected()) {
Robert Greenwalt34848c02011-03-25 13:09:25 -07001396 if (mNetConfigs[netType].isDefault()) {
Robert Greenwaltc3c5f862010-10-11 16:00:27 -07001397 handleApplyDefaultProxy(netType);
Robert Greenwalt3afbead2010-07-23 15:46:26 -07001398 addDefaultRoute(mNetTrackers[netType]);
Robert Greenwalt2034b912009-08-12 16:08:25 -07001399 } else {
Robert Greenwalta71471b2011-03-24 21:41:41 -07001400 // many radios add a default route even when we don't want one.
1401 // remove the default interface unless we need it for our active network
1402 if (mActiveDefaultNetwork != -1) {
Robert Greenwalt3a378b92011-03-30 15:03:13 -07001403 LinkProperties linkProperties =
1404 mNetTrackers[mActiveDefaultNetwork].getLinkProperties();
1405 LinkProperties newLinkProperties =
1406 mNetTrackers[netType].getLinkProperties();
1407 String defaultIface = linkProperties.getInterfaceName();
Robert Greenwalta71471b2011-03-24 21:41:41 -07001408 if (defaultIface != null &&
Robert Greenwalt3a378b92011-03-30 15:03:13 -07001409 !defaultIface.equals(newLinkProperties.getInterfaceName())) {
Robert Greenwaltf7dae302011-03-31 10:44:47 -07001410 removeDefaultRoute(mNetTrackers[netType]);
Robert Greenwalta71471b2011-03-24 21:41:41 -07001411 }
1412 }
Robert Greenwaltf7dae302011-03-31 10:44:47 -07001413 addPrivateDnsRoutes(mNetTrackers[netType]);
Robert Greenwalt3afbead2010-07-23 15:46:26 -07001414 }
1415 } else {
Robert Greenwalt34848c02011-03-25 13:09:25 -07001416 if (mNetConfigs[netType].isDefault()) {
Robert Greenwalt3afbead2010-07-23 15:46:26 -07001417 removeDefaultRoute(mNetTrackers[netType]);
1418 } else {
1419 removePrivateDnsRoutes(mNetTrackers[netType]);
Robert Greenwalt2034b912009-08-12 16:08:25 -07001420 }
The Android Open Source Project28527d22009-03-03 19:31:44 -08001421 }
Robert Greenwalt36ea8692011-06-15 12:22:07 -07001422
1423 if (doReset) {
1424 LinkProperties linkProperties = mNetTrackers[netType].getLinkProperties();
1425 if (linkProperties != null) {
1426 String iface = linkProperties.getInterfaceName();
1427 if (TextUtils.isEmpty(iface) == false) {
1428 if (DBG) log("resetConnections(" + iface + ")");
1429 NetworkUtils.resetConnections(iface);
1430 }
1431 }
1432 }
The Android Open Source Project28527d22009-03-03 19:31:44 -08001433 }
1434
Irfan Sheriff7f132d92010-06-09 15:39:36 -07001435 private void addPrivateDnsRoutes(NetworkStateTracker nt) {
Irfan Sheriff7f132d92010-06-09 15:39:36 -07001436 boolean privateDnsRouteSet = nt.isPrivateDnsRouteSet();
Robert Greenwalt1f1bcfe2010-08-30 10:56:47 -07001437 LinkProperties p = nt.getLinkProperties();
Robert Greenwalta7dfbd32010-06-15 15:43:39 -07001438 if (p == null) return;
1439 String interfaceName = p.getInterfaceName();
Irfan Sheriff7f132d92010-06-09 15:39:36 -07001440
1441 if (DBG) {
Wink Savillee70c6f52010-12-03 12:01:38 -08001442 log("addPrivateDnsRoutes for " + nt +
Irfan Sheriff7f132d92010-06-09 15:39:36 -07001443 "(" + interfaceName + ") - mPrivateDnsRouteSet = " + privateDnsRouteSet);
1444 }
Irfan Sheriff7f132d92010-06-09 15:39:36 -07001445 if (interfaceName != null && !privateDnsRouteSet) {
Robert Greenwalta7dfbd32010-06-15 15:43:39 -07001446 Collection<InetAddress> dnsList = p.getDnses();
1447 for (InetAddress dns : dnsList) {
Robert Greenwaltbd492212011-05-06 17:10:53 -07001448 addHostRoute(nt, dns, 0);
Irfan Sheriff7f132d92010-06-09 15:39:36 -07001449 }
1450 nt.privateDnsRouteSet(true);
1451 }
1452 }
1453
1454 private void removePrivateDnsRoutes(NetworkStateTracker nt) {
Robert Greenwalt1f1bcfe2010-08-30 10:56:47 -07001455 LinkProperties p = nt.getLinkProperties();
Robert Greenwalta7dfbd32010-06-15 15:43:39 -07001456 if (p == null) return;
1457 String interfaceName = p.getInterfaceName();
Irfan Sheriff7f132d92010-06-09 15:39:36 -07001458 boolean privateDnsRouteSet = nt.isPrivateDnsRouteSet();
1459 if (interfaceName != null && privateDnsRouteSet) {
1460 if (DBG) {
Wink Savillee70c6f52010-12-03 12:01:38 -08001461 log("removePrivateDnsRoutes for " + nt.getNetworkInfo().getTypeName() +
Irfan Sheriff7f132d92010-06-09 15:39:36 -07001462 " (" + interfaceName + ")");
1463 }
Robert Greenwalt355205c2011-05-10 15:05:02 -07001464
1465 Collection<InetAddress> dnsList = p.getDnses();
1466 for (InetAddress dns : dnsList) {
1467 if (DBG) log(" removing " + dns);
1468 RouteInfo route = RouteInfo.makeHostRoute(dns);
1469 try {
1470 mNetd.removeRoute(interfaceName, route);
1471 } catch (Exception ex) {
1472 loge("error (" + ex + ") removing dns route " + route);
1473 }
1474 }
Irfan Sheriff7f132d92010-06-09 15:39:36 -07001475 nt.privateDnsRouteSet(false);
1476 }
1477 }
1478
Irfan Sheriff7f132d92010-06-09 15:39:36 -07001479
1480 private void addDefaultRoute(NetworkStateTracker nt) {
Robert Greenwalt1f1bcfe2010-08-30 10:56:47 -07001481 LinkProperties p = nt.getLinkProperties();
Robert Greenwalta7dfbd32010-06-15 15:43:39 -07001482 if (p == null) return;
1483 String interfaceName = p.getInterfaceName();
Robert Greenwalt5c733972011-02-09 13:56:06 -08001484 if (TextUtils.isEmpty(interfaceName)) return;
Irfan Sheriff7f132d92010-06-09 15:39:36 -07001485
Robert Greenwalt355205c2011-05-10 15:05:02 -07001486 for (RouteInfo route : p.getRoutes()) {
Robert Greenwalt5a901292011-04-28 14:28:50 -07001487 //TODO - handle non-default routes
1488 if (route.isDefaultRoute()) {
Robert Greenwalt355205c2011-05-10 15:05:02 -07001489 if (DBG) log("adding default route " + route);
Robert Greenwalt5a901292011-04-28 14:28:50 -07001490 InetAddress gateway = route.getGateway();
Robert Greenwalt355205c2011-05-10 15:05:02 -07001491 if (addHostRoute(nt, gateway, 0)) {
1492 try {
1493 mNetd.addRoute(interfaceName, route);
1494 } catch (Exception e) {
1495 loge("error adding default route " + route);
1496 continue;
1497 }
Robert Greenwalt5a901292011-04-28 14:28:50 -07001498 if (DBG) {
1499 NetworkInfo networkInfo = nt.getNetworkInfo();
1500 log("addDefaultRoute for " + networkInfo.getTypeName() +
1501 " (" + interfaceName + "), GatewayAddr=" +
1502 gateway.getHostAddress());
1503 }
Robert Greenwalt355205c2011-05-10 15:05:02 -07001504 } else {
1505 loge("error adding host route for default route " + route);
Robert Greenwalt03d53da2011-03-22 18:47:42 -07001506 }
Irfan Sheriff7f132d92010-06-09 15:39:36 -07001507 }
Irfan Sheriff7f132d92010-06-09 15:39:36 -07001508 }
1509 }
1510
1511
1512 public void removeDefaultRoute(NetworkStateTracker nt) {
Robert Greenwalt1f1bcfe2010-08-30 10:56:47 -07001513 LinkProperties p = nt.getLinkProperties();
Robert Greenwalta7dfbd32010-06-15 15:43:39 -07001514 if (p == null) return;
1515 String interfaceName = p.getInterfaceName();
Irfan Sheriff7f132d92010-06-09 15:39:36 -07001516
Robert Greenwalt355205c2011-05-10 15:05:02 -07001517 if (interfaceName == null) return;
1518
1519 for (RouteInfo route : p.getRoutes()) {
1520 //TODO - handle non-default routes
1521 if (route.isDefaultRoute()) {
1522 try {
1523 mNetd.removeRoute(interfaceName, route);
1524 } catch (Exception ex) {
1525 loge("error (" + ex + ") removing default route " + route);
1526 continue;
1527 }
Robert Greenwalt03d53da2011-03-22 18:47:42 -07001528 if (DBG) {
1529 NetworkInfo networkInfo = nt.getNetworkInfo();
1530 log("removeDefaultRoute for " + networkInfo.getTypeName() + " (" +
1531 interfaceName + ")");
1532 }
Irfan Sheriff7f132d92010-06-09 15:39:36 -07001533 }
Irfan Sheriff7f132d92010-06-09 15:39:36 -07001534 }
1535 }
1536
1537 /**
1538 * Reads the network specific TCP buffer sizes from SystemProperties
1539 * net.tcp.buffersize.[default|wifi|umts|edge|gprs] and set them for system
1540 * wide use
1541 */
1542 public void updateNetworkSettings(NetworkStateTracker nt) {
1543 String key = nt.getTcpBufferSizesPropName();
1544 String bufferSizes = SystemProperties.get(key);
1545
1546 if (bufferSizes.length() == 0) {
Wink Savillee70c6f52010-12-03 12:01:38 -08001547 loge(key + " not found in system properties. Using defaults");
Irfan Sheriff7f132d92010-06-09 15:39:36 -07001548
1549 // Setting to default values so we won't be stuck to previous values
1550 key = "net.tcp.buffersize.default";
1551 bufferSizes = SystemProperties.get(key);
1552 }
1553
1554 // Set values in kernel
1555 if (bufferSizes.length() != 0) {
1556 if (DBG) {
Wink Savillee70c6f52010-12-03 12:01:38 -08001557 log("Setting TCP values: [" + bufferSizes
Irfan Sheriff7f132d92010-06-09 15:39:36 -07001558 + "] which comes from [" + key + "]");
1559 }
1560 setBufferSize(bufferSizes);
1561 }
1562 }
1563
1564 /**
1565 * Writes TCP buffer sizes to /sys/kernel/ipv4/tcp_[r/w]mem_[min/def/max]
1566 * which maps to /proc/sys/net/ipv4/tcp_rmem and tcpwmem
1567 *
1568 * @param bufferSizes in the format of "readMin, readInitial, readMax,
1569 * writeMin, writeInitial, writeMax"
1570 */
1571 private void setBufferSize(String bufferSizes) {
1572 try {
1573 String[] values = bufferSizes.split(",");
1574
1575 if (values.length == 6) {
1576 final String prefix = "/sys/kernel/ipv4/tcp_";
1577 stringToFile(prefix + "rmem_min", values[0]);
1578 stringToFile(prefix + "rmem_def", values[1]);
1579 stringToFile(prefix + "rmem_max", values[2]);
1580 stringToFile(prefix + "wmem_min", values[3]);
1581 stringToFile(prefix + "wmem_def", values[4]);
1582 stringToFile(prefix + "wmem_max", values[5]);
1583 } else {
Wink Savillee70c6f52010-12-03 12:01:38 -08001584 loge("Invalid buffersize string: " + bufferSizes);
Irfan Sheriff7f132d92010-06-09 15:39:36 -07001585 }
1586 } catch (IOException e) {
Wink Savillee70c6f52010-12-03 12:01:38 -08001587 loge("Can't set tcp buffer sizes:" + e);
Irfan Sheriff7f132d92010-06-09 15:39:36 -07001588 }
1589 }
1590
1591 /**
1592 * Writes string to file. Basically same as "echo -n $string > $filename"
1593 *
1594 * @param filename
1595 * @param string
1596 * @throws IOException
1597 */
1598 private void stringToFile(String filename, String string) throws IOException {
1599 FileWriter out = new FileWriter(filename);
1600 try {
1601 out.write(string);
1602 } finally {
1603 out.close();
1604 }
1605 }
1606
1607
Robert Greenwalt2034b912009-08-12 16:08:25 -07001608 /**
1609 * Adjust the per-process dns entries (net.dns<x>.<pid>) based
1610 * on the highest priority active net which this process requested.
1611 * If there aren't any, clear it out
1612 */
1613 private void reassessPidDns(int myPid, boolean doBump)
1614 {
Wink Savillee70c6f52010-12-03 12:01:38 -08001615 if (DBG) log("reassessPidDns for pid " + myPid);
Robert Greenwalt2034b912009-08-12 16:08:25 -07001616 for(int i : mPriorityList) {
Robert Greenwalt34848c02011-03-25 13:09:25 -07001617 if (mNetConfigs[i].isDefault()) {
Robert Greenwalt2034b912009-08-12 16:08:25 -07001618 continue;
1619 }
1620 NetworkStateTracker nt = mNetTrackers[i];
Robert Greenwalt0659da32009-07-16 17:21:39 -07001621 if (nt.getNetworkInfo().isConnected() &&
1622 !nt.isTeardownRequested()) {
Robert Greenwalt1f1bcfe2010-08-30 10:56:47 -07001623 LinkProperties p = nt.getLinkProperties();
Robert Greenwalta7dfbd32010-06-15 15:43:39 -07001624 if (p == null) continue;
Robert Greenwalt2034b912009-08-12 16:08:25 -07001625 List pids = mNetRequestersPids[i];
1626 for (int j=0; j<pids.size(); j++) {
1627 Integer pid = (Integer)pids.get(j);
1628 if (pid.intValue() == myPid) {
Robert Greenwalta7dfbd32010-06-15 15:43:39 -07001629 Collection<InetAddress> dnses = p.getDnses();
1630 writePidDns(dnses, myPid);
Robert Greenwalt2034b912009-08-12 16:08:25 -07001631 if (doBump) {
1632 bumpDns();
1633 }
1634 return;
1635 }
1636 }
1637 }
1638 }
1639 // nothing found - delete
1640 for (int i = 1; ; i++) {
1641 String prop = "net.dns" + i + "." + myPid;
1642 if (SystemProperties.get(prop).length() == 0) {
1643 if (doBump) {
1644 bumpDns();
1645 }
1646 return;
1647 }
1648 SystemProperties.set(prop, "");
1649 }
1650 }
1651
Robert Greenwalt8ca88762010-12-17 15:20:36 -08001652 // return true if results in a change
1653 private boolean writePidDns(Collection <InetAddress> dnses, int pid) {
Robert Greenwalt2034b912009-08-12 16:08:25 -07001654 int j = 1;
Robert Greenwalt8ca88762010-12-17 15:20:36 -08001655 boolean changed = false;
Robert Greenwalta7dfbd32010-06-15 15:43:39 -07001656 for (InetAddress dns : dnses) {
Robert Greenwalt8ca88762010-12-17 15:20:36 -08001657 String dnsString = dns.getHostAddress();
1658 if (changed || !dnsString.equals(SystemProperties.get("net.dns" + j + "." + pid))) {
1659 changed = true;
1660 SystemProperties.set("net.dns" + j++ + "." + pid, dns.getHostAddress());
1661 }
Robert Greenwalt2034b912009-08-12 16:08:25 -07001662 }
Robert Greenwalt8ca88762010-12-17 15:20:36 -08001663 return changed;
Robert Greenwalt2034b912009-08-12 16:08:25 -07001664 }
1665
1666 private void bumpDns() {
1667 /*
1668 * Bump the property that tells the name resolver library to reread
1669 * the DNS server list from the properties.
1670 */
1671 String propVal = SystemProperties.get("net.dnschange");
1672 int n = 0;
1673 if (propVal.length() != 0) {
1674 try {
1675 n = Integer.parseInt(propVal);
1676 } catch (NumberFormatException e) {}
1677 }
1678 SystemProperties.set("net.dnschange", "" + (n+1));
Robert Greenwalt051642b2010-11-02 14:08:23 -07001679 /*
1680 * Tell the VMs to toss their DNS caches
1681 */
1682 Intent intent = new Intent(Intent.ACTION_CLEAR_DNS_CACHE);
1683 intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
Stan Chesnuttf444f502011-01-05 17:14:03 -08001684 /*
1685 * Connectivity events can happen before boot has completed ...
1686 */
1687 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
Robert Greenwalt051642b2010-11-02 14:08:23 -07001688 mContext.sendBroadcast(intent);
Robert Greenwalt2034b912009-08-12 16:08:25 -07001689 }
1690
Robert Greenwalt3afbead2010-07-23 15:46:26 -07001691 private void handleDnsConfigurationChange(int netType) {
Robert Greenwalt2034b912009-08-12 16:08:25 -07001692 // add default net's dns entries
Robert Greenwalt3afbead2010-07-23 15:46:26 -07001693 NetworkStateTracker nt = mNetTrackers[netType];
1694 if (nt != null && nt.getNetworkInfo().isConnected() && !nt.isTeardownRequested()) {
Robert Greenwalt1f1bcfe2010-08-30 10:56:47 -07001695 LinkProperties p = nt.getLinkProperties();
Robert Greenwalt3afbead2010-07-23 15:46:26 -07001696 if (p == null) return;
1697 Collection<InetAddress> dnses = p.getDnses();
Robert Greenwalt8ca88762010-12-17 15:20:36 -08001698 boolean changed = false;
Robert Greenwalt34848c02011-03-25 13:09:25 -07001699 if (mNetConfigs[netType].isDefault()) {
Robert Greenwalt3afbead2010-07-23 15:46:26 -07001700 int j = 1;
Robert Greenwalt94daa182010-09-01 11:34:05 -07001701 if (dnses.size() == 0 && mDefaultDns != null) {
Robert Greenwalt8ca88762010-12-17 15:20:36 -08001702 String dnsString = mDefaultDns.getHostAddress();
1703 if (!dnsString.equals(SystemProperties.get("net.dns1"))) {
1704 if (DBG) {
1705 log("no dns provided - using " + dnsString);
1706 }
1707 changed = true;
1708 SystemProperties.set("net.dns1", dnsString);
Robert Greenwalt2034b912009-08-12 16:08:25 -07001709 }
Robert Greenwalt94daa182010-09-01 11:34:05 -07001710 j++;
1711 } else {
1712 for (InetAddress dns : dnses) {
Robert Greenwalt8ca88762010-12-17 15:20:36 -08001713 String dnsString = dns.getHostAddress();
1714 if (!changed && dnsString.equals(SystemProperties.get("net.dns" + j))) {
1715 j++;
1716 continue;
1717 }
Robert Greenwalt94daa182010-09-01 11:34:05 -07001718 if (DBG) {
Wink Savillee70c6f52010-12-03 12:01:38 -08001719 log("adding dns " + dns + " for " +
Robert Greenwalt94daa182010-09-01 11:34:05 -07001720 nt.getNetworkInfo().getTypeName());
1721 }
Robert Greenwalt8ca88762010-12-17 15:20:36 -08001722 changed = true;
1723 SystemProperties.set("net.dns" + j++, dnsString);
Robert Greenwalt94daa182010-09-01 11:34:05 -07001724 }
Robert Greenwalt3afbead2010-07-23 15:46:26 -07001725 }
1726 for (int k=j ; k<mNumDnsEntries; k++) {
Robert Greenwalt8ca88762010-12-17 15:20:36 -08001727 if (changed || !TextUtils.isEmpty(SystemProperties.get("net.dns" + k))) {
1728 if (DBG) log("erasing net.dns" + k);
1729 changed = true;
1730 SystemProperties.set("net.dns" + k, "");
1731 }
Robert Greenwalt3afbead2010-07-23 15:46:26 -07001732 }
1733 mNumDnsEntries = j;
1734 } else {
1735 // set per-pid dns for attached secondary nets
1736 List pids = mNetRequestersPids[netType];
1737 for (int y=0; y< pids.size(); y++) {
1738 Integer pid = (Integer)pids.get(y);
Robert Greenwalt8ca88762010-12-17 15:20:36 -08001739 changed = writePidDns(dnses, pid.intValue());
The Android Open Source Project28527d22009-03-03 19:31:44 -08001740 }
1741 }
Robert Greenwalt8ca88762010-12-17 15:20:36 -08001742 if (changed) bumpDns();
The Android Open Source Project28527d22009-03-03 19:31:44 -08001743 }
Robert Greenwalt2034b912009-08-12 16:08:25 -07001744 }
1745
Robert Greenwalt20f819c2011-05-03 19:02:44 -07001746 private int getRestoreDefaultNetworkDelay(int networkType) {
Robert Greenwalt2034b912009-08-12 16:08:25 -07001747 String restoreDefaultNetworkDelayStr = SystemProperties.get(
1748 NETWORK_RESTORE_DELAY_PROP_NAME);
1749 if(restoreDefaultNetworkDelayStr != null &&
1750 restoreDefaultNetworkDelayStr.length() != 0) {
1751 try {
1752 return Integer.valueOf(restoreDefaultNetworkDelayStr);
1753 } catch (NumberFormatException e) {
1754 }
The Android Open Source Project28527d22009-03-03 19:31:44 -08001755 }
Robert Greenwalt20f819c2011-05-03 19:02:44 -07001756 // if the system property isn't set, use the value for the apn type
1757 int ret = RESTORE_DEFAULT_NETWORK_DELAY;
1758
1759 if ((networkType <= ConnectivityManager.MAX_NETWORK_TYPE) &&
1760 (mNetConfigs[networkType] != null)) {
1761 ret = mNetConfigs[networkType].restoreTime;
1762 }
1763 return ret;
The Android Open Source Project28527d22009-03-03 19:31:44 -08001764 }
1765
1766 @Override
1767 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
Robert Greenwalt0659da32009-07-16 17:21:39 -07001768 if (mContext.checkCallingOrSelfPermission(
1769 android.Manifest.permission.DUMP)
The Android Open Source Project28527d22009-03-03 19:31:44 -08001770 != PackageManager.PERMISSION_GRANTED) {
Robert Greenwalt0659da32009-07-16 17:21:39 -07001771 pw.println("Permission Denial: can't dump ConnectivityService " +
1772 "from from pid=" + Binder.getCallingPid() + ", uid=" +
1773 Binder.getCallingUid());
The Android Open Source Project28527d22009-03-03 19:31:44 -08001774 return;
1775 }
The Android Open Source Project28527d22009-03-03 19:31:44 -08001776 pw.println();
1777 for (NetworkStateTracker nst : mNetTrackers) {
Robert Greenwalt3eeb6032009-12-21 18:24:07 -08001778 if (nst != null) {
1779 if (nst.getNetworkInfo().isConnected()) {
1780 pw.println("Active network: " + nst.getNetworkInfo().
1781 getTypeName());
1782 }
1783 pw.println(nst.getNetworkInfo());
1784 pw.println(nst);
1785 pw.println();
Robert Greenwalt2034b912009-08-12 16:08:25 -07001786 }
The Android Open Source Project28527d22009-03-03 19:31:44 -08001787 }
Robert Greenwalt3eeb6032009-12-21 18:24:07 -08001788
1789 pw.println("Network Requester Pids:");
1790 for (int net : mPriorityList) {
1791 String pidString = net + ": ";
1792 for (Object pid : mNetRequestersPids[net]) {
1793 pidString = pidString + pid.toString() + ", ";
1794 }
1795 pw.println(pidString);
1796 }
1797 pw.println();
1798
1799 pw.println("FeatureUsers:");
1800 for (Object requester : mFeatureUsers) {
1801 pw.println(requester.toString());
1802 }
1803 pw.println();
Robert Greenwalt8e87f122010-02-11 18:18:40 -08001804
Robert Greenwalt93dc1042010-06-15 12:19:37 -07001805 synchronized (this) {
1806 pw.println("NetworkTranstionWakeLock is currently " +
1807 (mNetTransitionWakeLock.isHeld() ? "" : "not ") + "held.");
1808 pw.println("It was last requested for "+mNetTransitionWakeLockCausedBy);
1809 }
1810 pw.println();
1811
Robert Greenwalt8e87f122010-02-11 18:18:40 -08001812 mTethering.dump(fd, pw, args);
Robert Greenwalt0e80be12010-09-20 14:35:25 -07001813
1814 if (mInetLog != null) {
1815 pw.println();
1816 pw.println("Inet condition reports:");
1817 for(int i = 0; i < mInetLog.size(); i++) {
1818 pw.println(mInetLog.get(i));
1819 }
1820 }
The Android Open Source Project28527d22009-03-03 19:31:44 -08001821 }
1822
Robert Greenwalt2034b912009-08-12 16:08:25 -07001823 // must be stateless - things change under us.
The Android Open Source Project28527d22009-03-03 19:31:44 -08001824 private class MyHandler extends Handler {
Wink Saville775aad62010-09-02 19:23:52 -07001825 public MyHandler(Looper looper) {
1826 super(looper);
1827 }
1828
The Android Open Source Project28527d22009-03-03 19:31:44 -08001829 @Override
1830 public void handleMessage(Message msg) {
1831 NetworkInfo info;
1832 switch (msg.what) {
1833 case NetworkStateTracker.EVENT_STATE_CHANGED:
1834 info = (NetworkInfo) msg.obj;
Robert Greenwalt12c44552009-12-07 11:33:18 -08001835 int type = info.getType();
1836 NetworkInfo.State state = info.getState();
Robert Greenwalt12c44552009-12-07 11:33:18 -08001837
Wink Savillee70c6f52010-12-03 12:01:38 -08001838 if (DBG) log("ConnectivityChange for " +
Robert Greenwalt0659da32009-07-16 17:21:39 -07001839 info.getTypeName() + ": " +
Robert Greenwalt12c44552009-12-07 11:33:18 -08001840 state + "/" + info.getDetailedState());
The Android Open Source Project28527d22009-03-03 19:31:44 -08001841
1842 // Connectivity state changed:
1843 // [31-13] Reserved for future use
Robert Greenwalt0659da32009-07-16 17:21:39 -07001844 // [12-9] Network subtype (for mobile network, as defined
1845 // by TelephonyManager)
1846 // [8-3] Detailed state ordinal (as defined by
1847 // NetworkInfo.DetailedState)
The Android Open Source Project28527d22009-03-03 19:31:44 -08001848 // [2-0] Network type (as defined by ConnectivityManager)
1849 int eventLogParam = (info.getType() & 0x7) |
1850 ((info.getDetailedState().ordinal() & 0x3f) << 3) |
1851 (info.getSubtype() << 9);
Doug Zongker2fc96232009-12-04 10:31:43 -08001852 EventLog.writeEvent(EventLogTags.CONNECTIVITY_STATE_CHANGED,
Robert Greenwalt0659da32009-07-16 17:21:39 -07001853 eventLogParam);
1854
1855 if (info.getDetailedState() ==
1856 NetworkInfo.DetailedState.FAILED) {
The Android Open Source Project28527d22009-03-03 19:31:44 -08001857 handleConnectionFailure(info);
Robert Greenwalt12c44552009-12-07 11:33:18 -08001858 } else if (state == NetworkInfo.State.DISCONNECTED) {
The Android Open Source Project28527d22009-03-03 19:31:44 -08001859 handleDisconnect(info);
Robert Greenwalt12c44552009-12-07 11:33:18 -08001860 } else if (state == NetworkInfo.State.SUSPENDED) {
The Android Open Source Project28527d22009-03-03 19:31:44 -08001861 // TODO: need to think this over.
Robert Greenwalt0659da32009-07-16 17:21:39 -07001862 // the logic here is, handle SUSPENDED the same as
1863 // DISCONNECTED. The only difference being we are
1864 // broadcasting an intent with NetworkInfo that's
1865 // suspended. This allows the applications an
1866 // opportunity to handle DISCONNECTED and SUSPENDED
1867 // differently, or not.
The Android Open Source Project28527d22009-03-03 19:31:44 -08001868 handleDisconnect(info);
Robert Greenwalt12c44552009-12-07 11:33:18 -08001869 } else if (state == NetworkInfo.State.CONNECTED) {
The Android Open Source Project28527d22009-03-03 19:31:44 -08001870 handleConnect(info);
1871 }
The Android Open Source Project28527d22009-03-03 19:31:44 -08001872 break;
The Android Open Source Project28527d22009-03-03 19:31:44 -08001873 case NetworkStateTracker.EVENT_CONFIGURATION_CHANGED:
Robert Greenwalt3afbead2010-07-23 15:46:26 -07001874 info = (NetworkInfo) msg.obj;
Robert Greenwalt36ea8692011-06-15 12:22:07 -07001875 handleConnectivityChange(info.getType(), true);
The Android Open Source Project28527d22009-03-03 19:31:44 -08001876 break;
Robert Greenwaltccb36f92010-09-24 14:32:21 -07001877 case EVENT_CLEAR_NET_TRANSITION_WAKELOCK:
Robert Greenwalt93dc1042010-06-15 12:19:37 -07001878 String causedBy = null;
1879 synchronized (ConnectivityService.this) {
1880 if (msg.arg1 == mNetTransitionWakeLockSerialNumber &&
1881 mNetTransitionWakeLock.isHeld()) {
1882 mNetTransitionWakeLock.release();
1883 causedBy = mNetTransitionWakeLockCausedBy;
1884 }
1885 }
1886 if (causedBy != null) {
Wink Savillee70c6f52010-12-03 12:01:38 -08001887 log("NetTransition Wakelock for " + causedBy + " released by timeout");
Robert Greenwalt93dc1042010-06-15 12:19:37 -07001888 }
Robert Greenwaltcf1a56c2010-09-09 14:05:10 -07001889 break;
Robert Greenwalt6a2db8a2010-09-23 10:05:56 -07001890 case EVENT_RESTORE_DEFAULT_NETWORK:
Robert Greenwaltaffc3a12009-09-27 17:27:04 -07001891 FeatureUser u = (FeatureUser)msg.obj;
1892 u.expire();
Robert Greenwalt986c7412010-09-08 15:24:47 -07001893 break;
Robert Greenwalt6a2db8a2010-09-23 10:05:56 -07001894 case EVENT_INET_CONDITION_CHANGE:
1895 {
1896 int netType = msg.arg1;
1897 int condition = msg.arg2;
1898 handleInetConditionChange(netType, condition);
Robert Greenwalt93dc1042010-06-15 12:19:37 -07001899 break;
Robert Greenwalt6a2db8a2010-09-23 10:05:56 -07001900 }
1901 case EVENT_INET_CONDITION_HOLD_END:
1902 {
1903 int netType = msg.arg1;
1904 int sequence = msg.arg2;
1905 handleInetConditionHoldEnd(netType, sequence);
Robert Greenwalt986c7412010-09-08 15:24:47 -07001906 break;
Robert Greenwalt6a2db8a2010-09-23 10:05:56 -07001907 }
1908 case EVENT_SET_NETWORK_PREFERENCE:
1909 {
1910 int preference = msg.arg1;
1911 handleSetNetworkPreference(preference);
1912 break;
1913 }
1914 case EVENT_SET_BACKGROUND_DATA:
1915 {
1916 boolean enabled = (msg.arg1 == ENABLED);
1917 handleSetBackgroundData(enabled);
1918 break;
1919 }
1920 case EVENT_SET_MOBILE_DATA:
1921 {
1922 boolean enabled = (msg.arg1 == ENABLED);
1923 handleSetMobileData(enabled);
1924 break;
1925 }
Robert Greenwaltc3c5f862010-10-11 16:00:27 -07001926 case EVENT_APPLY_GLOBAL_HTTP_PROXY:
1927 {
1928 handleDeprecatedGlobalHttpProxy();
Robert Greenwalt34848c02011-03-25 13:09:25 -07001929 break;
1930 }
1931 case EVENT_SET_DEPENDENCY_MET:
1932 {
1933 boolean met = (msg.arg1 == ENABLED);
1934 handleSetDependencyMet(msg.arg2, met);
1935 break;
Robert Greenwaltc3c5f862010-10-11 16:00:27 -07001936 }
The Android Open Source Project28527d22009-03-03 19:31:44 -08001937 }
1938 }
1939 }
Robert Greenwalt0c4828c2010-01-26 11:40:34 -08001940
1941 // javadoc from interface
Robert Greenwalt4283ded2010-03-02 17:25:02 -08001942 public int tether(String iface) {
Robert Greenwalt0c4828c2010-01-26 11:40:34 -08001943 enforceTetherChangePermission();
Robert Greenwalt4283ded2010-03-02 17:25:02 -08001944
1945 if (isTetheringSupported()) {
1946 return mTethering.tether(iface);
1947 } else {
1948 return ConnectivityManager.TETHER_ERROR_UNSUPPORTED;
1949 }
Robert Greenwalt0c4828c2010-01-26 11:40:34 -08001950 }
1951
1952 // javadoc from interface
Robert Greenwalt4283ded2010-03-02 17:25:02 -08001953 public int untether(String iface) {
Robert Greenwalt0c4828c2010-01-26 11:40:34 -08001954 enforceTetherChangePermission();
Robert Greenwalt4283ded2010-03-02 17:25:02 -08001955
1956 if (isTetheringSupported()) {
1957 return mTethering.untether(iface);
1958 } else {
1959 return ConnectivityManager.TETHER_ERROR_UNSUPPORTED;
1960 }
1961 }
1962
1963 // javadoc from interface
1964 public int getLastTetherError(String iface) {
1965 enforceTetherAccessPermission();
1966
1967 if (isTetheringSupported()) {
1968 return mTethering.getLastTetherError(iface);
1969 } else {
1970 return ConnectivityManager.TETHER_ERROR_UNSUPPORTED;
1971 }
Robert Greenwalt8e87f122010-02-11 18:18:40 -08001972 }
1973
1974 // TODO - proper iface API for selection by property, inspection, etc
1975 public String[] getTetherableUsbRegexs() {
1976 enforceTetherAccessPermission();
1977 if (isTetheringSupported()) {
1978 return mTethering.getTetherableUsbRegexs();
1979 } else {
1980 return new String[0];
1981 }
1982 }
1983
1984 public String[] getTetherableWifiRegexs() {
1985 enforceTetherAccessPermission();
1986 if (isTetheringSupported()) {
1987 return mTethering.getTetherableWifiRegexs();
1988 } else {
1989 return new String[0];
1990 }
Robert Greenwalt0c4828c2010-01-26 11:40:34 -08001991 }
1992
Danica Chang96567052010-08-11 14:54:43 -07001993 public String[] getTetherableBluetoothRegexs() {
1994 enforceTetherAccessPermission();
1995 if (isTetheringSupported()) {
1996 return mTethering.getTetherableBluetoothRegexs();
1997 } else {
1998 return new String[0];
1999 }
2000 }
2001
Robert Greenwalt0c4828c2010-01-26 11:40:34 -08002002 // TODO - move iface listing, queries, etc to new module
2003 // javadoc from interface
2004 public String[] getTetherableIfaces() {
Robert Greenwalt8e87f122010-02-11 18:18:40 -08002005 enforceTetherAccessPermission();
Robert Greenwalt0c4828c2010-01-26 11:40:34 -08002006 return mTethering.getTetherableIfaces();
2007 }
2008
2009 public String[] getTetheredIfaces() {
Robert Greenwalt8e87f122010-02-11 18:18:40 -08002010 enforceTetherAccessPermission();
Robert Greenwalt0c4828c2010-01-26 11:40:34 -08002011 return mTethering.getTetheredIfaces();
2012 }
Robert Greenwalt8e87f122010-02-11 18:18:40 -08002013
Robert Greenwalt4283ded2010-03-02 17:25:02 -08002014 public String[] getTetheringErroredIfaces() {
2015 enforceTetherAccessPermission();
2016 return mTethering.getErroredIfaces();
2017 }
2018
Robert Greenwalt8e87f122010-02-11 18:18:40 -08002019 // if ro.tether.denied = true we default to no tethering
2020 // gservices could set the secure setting to 1 though to enable it on a build where it
2021 // had previously been turned off.
2022 public boolean isTetheringSupported() {
2023 enforceTetherAccessPermission();
2024 int defaultVal = (SystemProperties.get("ro.tether.denied").equals("true") ? 0 : 1);
Robert Greenwaltf1b66e12010-02-25 12:29:30 -08002025 boolean tetherEnabledInSettings = (Settings.Secure.getInt(mContext.getContentResolver(),
2026 Settings.Secure.TETHER_SUPPORTED, defaultVal) != 0);
2027 return tetherEnabledInSettings && mTetheringConfigValid;
Robert Greenwalt8e87f122010-02-11 18:18:40 -08002028 }
Robert Greenwalt93dc1042010-06-15 12:19:37 -07002029
2030 // An API NetworkStateTrackers can call when they lose their network.
2031 // This will automatically be cleared after X seconds or a network becomes CONNECTED,
2032 // whichever happens first. The timer is started by the first caller and not
2033 // restarted by subsequent callers.
2034 public void requestNetworkTransitionWakelock(String forWhom) {
2035 enforceConnectivityInternalPermission();
2036 synchronized (this) {
2037 if (mNetTransitionWakeLock.isHeld()) return;
2038 mNetTransitionWakeLockSerialNumber++;
2039 mNetTransitionWakeLock.acquire();
2040 mNetTransitionWakeLockCausedBy = forWhom;
2041 }
2042 mHandler.sendMessageDelayed(mHandler.obtainMessage(
Robert Greenwaltccb36f92010-09-24 14:32:21 -07002043 EVENT_CLEAR_NET_TRANSITION_WAKELOCK,
Robert Greenwalt93dc1042010-06-15 12:19:37 -07002044 mNetTransitionWakeLockSerialNumber, 0),
2045 mNetTransitionWakeLockTimeout);
2046 return;
2047 }
Robert Greenwalt24118e82010-09-09 13:15:32 -07002048
Robert Greenwalt986c7412010-09-08 15:24:47 -07002049 // 100 percent is full good, 0 is full bad.
2050 public void reportInetCondition(int networkType, int percentage) {
Wink Savillee70c6f52010-12-03 12:01:38 -08002051 if (DBG) log("reportNetworkCondition(" + networkType + ", " + percentage + ")");
Robert Greenwalt986c7412010-09-08 15:24:47 -07002052 mContext.enforceCallingOrSelfPermission(
2053 android.Manifest.permission.STATUS_BAR,
2054 "ConnectivityService");
2055
Robert Greenwalt0e80be12010-09-20 14:35:25 -07002056 if (DBG) {
2057 int pid = getCallingPid();
2058 int uid = getCallingUid();
2059 String s = pid + "(" + uid + ") reports inet is " +
2060 (percentage > 50 ? "connected" : "disconnected") + " (" + percentage + ") on " +
2061 "network Type " + networkType + " at " + GregorianCalendar.getInstance().getTime();
2062 mInetLog.add(s);
2063 while(mInetLog.size() > INET_CONDITION_LOG_MAX_SIZE) {
2064 mInetLog.remove(0);
2065 }
2066 }
Robert Greenwalt986c7412010-09-08 15:24:47 -07002067 mHandler.sendMessage(mHandler.obtainMessage(
Robert Greenwalt6a2db8a2010-09-23 10:05:56 -07002068 EVENT_INET_CONDITION_CHANGE, networkType, percentage));
2069 }
2070
2071 private void handleInetConditionChange(int netType, int condition) {
2072 if (DBG) {
Wink Savillee70c6f52010-12-03 12:01:38 -08002073 log("Inet connectivity change, net=" +
Robert Greenwalt6a2db8a2010-09-23 10:05:56 -07002074 netType + ", condition=" + condition +
2075 ",mActiveDefaultNetwork=" + mActiveDefaultNetwork);
2076 }
2077 if (mActiveDefaultNetwork == -1) {
Wink Savillee70c6f52010-12-03 12:01:38 -08002078 if (DBG) log("no active default network - aborting");
Robert Greenwalt6a2db8a2010-09-23 10:05:56 -07002079 return;
2080 }
2081 if (mActiveDefaultNetwork != netType) {
Wink Savillee70c6f52010-12-03 12:01:38 -08002082 if (DBG) log("given net not default - aborting");
Robert Greenwalt6a2db8a2010-09-23 10:05:56 -07002083 return;
2084 }
2085 mDefaultInetCondition = condition;
2086 int delay;
2087 if (mInetConditionChangeInFlight == false) {
Wink Savillee70c6f52010-12-03 12:01:38 -08002088 if (DBG) log("starting a change hold");
Robert Greenwalt6a2db8a2010-09-23 10:05:56 -07002089 // setup a new hold to debounce this
2090 if (mDefaultInetCondition > 50) {
2091 delay = Settings.Secure.getInt(mContext.getContentResolver(),
2092 Settings.Secure.INET_CONDITION_DEBOUNCE_UP_DELAY, 500);
2093 } else {
2094 delay = Settings.Secure.getInt(mContext.getContentResolver(),
2095 Settings.Secure.INET_CONDITION_DEBOUNCE_DOWN_DELAY, 3000);
2096 }
2097 mInetConditionChangeInFlight = true;
2098 mHandler.sendMessageDelayed(mHandler.obtainMessage(EVENT_INET_CONDITION_HOLD_END,
2099 mActiveDefaultNetwork, mDefaultConnectionSequence), delay);
2100 } else {
2101 // we've set the new condition, when this hold ends that will get
2102 // picked up
Wink Savillee70c6f52010-12-03 12:01:38 -08002103 if (DBG) log("currently in hold - not setting new end evt");
Robert Greenwalt6a2db8a2010-09-23 10:05:56 -07002104 }
2105 }
2106
2107 private void handleInetConditionHoldEnd(int netType, int sequence) {
2108 if (DBG) {
Wink Savillee70c6f52010-12-03 12:01:38 -08002109 log("Inet hold end, net=" + netType +
Robert Greenwalt6a2db8a2010-09-23 10:05:56 -07002110 ", condition =" + mDefaultInetCondition +
2111 ", published condition =" + mDefaultInetConditionPublished);
2112 }
2113 mInetConditionChangeInFlight = false;
2114
2115 if (mActiveDefaultNetwork == -1) {
Wink Savillee70c6f52010-12-03 12:01:38 -08002116 if (DBG) log("no active default network - aborting");
Robert Greenwalt6a2db8a2010-09-23 10:05:56 -07002117 return;
2118 }
2119 if (mDefaultConnectionSequence != sequence) {
Wink Savillee70c6f52010-12-03 12:01:38 -08002120 if (DBG) log("event hold for obsolete network - aborting");
Robert Greenwalt6a2db8a2010-09-23 10:05:56 -07002121 return;
2122 }
2123 if (mDefaultInetConditionPublished == mDefaultInetCondition) {
Wink Savillee70c6f52010-12-03 12:01:38 -08002124 if (DBG) log("no change in condition - aborting");
Robert Greenwalt6a2db8a2010-09-23 10:05:56 -07002125 return;
2126 }
2127 NetworkInfo networkInfo = mNetTrackers[mActiveDefaultNetwork].getNetworkInfo();
2128 if (networkInfo.isConnected() == false) {
Wink Savillee70c6f52010-12-03 12:01:38 -08002129 if (DBG) log("default network not connected - aborting");
Robert Greenwalt6a2db8a2010-09-23 10:05:56 -07002130 return;
2131 }
2132 mDefaultInetConditionPublished = mDefaultInetCondition;
2133 sendInetConditionBroadcast(networkInfo);
2134 return;
Robert Greenwalt986c7412010-09-08 15:24:47 -07002135 }
Robert Greenwaltc3c5f862010-10-11 16:00:27 -07002136
2137 public synchronized ProxyProperties getProxy() {
2138 if (mGlobalProxy != null) return mGlobalProxy;
2139 if (mDefaultProxy != null) return mDefaultProxy;
2140 return null;
2141 }
2142
2143 public void setGlobalProxy(ProxyProperties proxyProperties) {
2144 enforceChangePermission();
2145 synchronized (mGlobalProxyLock) {
2146 if (proxyProperties == mGlobalProxy) return;
2147 if (proxyProperties != null && proxyProperties.equals(mGlobalProxy)) return;
2148 if (mGlobalProxy != null && mGlobalProxy.equals(proxyProperties)) return;
2149
2150 String host = "";
2151 int port = 0;
2152 String exclList = "";
2153 if (proxyProperties != null && !TextUtils.isEmpty(proxyProperties.getHost())) {
2154 mGlobalProxy = new ProxyProperties(proxyProperties);
2155 host = mGlobalProxy.getHost();
2156 port = mGlobalProxy.getPort();
2157 exclList = mGlobalProxy.getExclusionList();
2158 } else {
2159 mGlobalProxy = null;
2160 }
2161 ContentResolver res = mContext.getContentResolver();
2162 Settings.Secure.putString(res, Settings.Secure.GLOBAL_HTTP_PROXY_HOST, host);
2163 Settings.Secure.putInt(res, Settings.Secure.GLOBAL_HTTP_PROXY_PORT, port);
Robert Greenwalt6f7c6092010-12-02 11:31:00 -08002164 Settings.Secure.putString(res, Settings.Secure.GLOBAL_HTTP_PROXY_EXCLUSION_LIST,
Robert Greenwaltc3c5f862010-10-11 16:00:27 -07002165 exclList);
2166 }
2167
2168 if (mGlobalProxy == null) {
2169 proxyProperties = mDefaultProxy;
2170 }
2171 sendProxyBroadcast(proxyProperties);
2172 }
2173
Robert Greenwalt6f7c6092010-12-02 11:31:00 -08002174 private void loadGlobalProxy() {
2175 ContentResolver res = mContext.getContentResolver();
2176 String host = Settings.Secure.getString(res, Settings.Secure.GLOBAL_HTTP_PROXY_HOST);
2177 int port = Settings.Secure.getInt(res, Settings.Secure.GLOBAL_HTTP_PROXY_PORT, 0);
2178 String exclList = Settings.Secure.getString(res,
2179 Settings.Secure.GLOBAL_HTTP_PROXY_EXCLUSION_LIST);
2180 if (!TextUtils.isEmpty(host)) {
2181 ProxyProperties proxyProperties = new ProxyProperties(host, port, exclList);
2182 synchronized (mGlobalProxyLock) {
2183 mGlobalProxy = proxyProperties;
2184 }
2185 }
2186 }
2187
Robert Greenwaltc3c5f862010-10-11 16:00:27 -07002188 public ProxyProperties getGlobalProxy() {
2189 synchronized (mGlobalProxyLock) {
2190 return mGlobalProxy;
2191 }
2192 }
2193
2194 private void handleApplyDefaultProxy(int type) {
2195 // check if new default - push it out to all VM if so
2196 ProxyProperties proxy = mNetTrackers[type].getLinkProperties().getHttpProxy();
2197 synchronized (this) {
2198 if (mDefaultProxy != null && mDefaultProxy.equals(proxy)) return;
2199 if (mDefaultProxy == proxy) return;
2200 if (!TextUtils.isEmpty(proxy.getHost())) {
2201 mDefaultProxy = proxy;
2202 } else {
2203 mDefaultProxy = null;
2204 }
2205 }
Wink Savillee70c6f52010-12-03 12:01:38 -08002206 if (DBG) log("changing default proxy to " + proxy);
Robert Greenwaltc3c5f862010-10-11 16:00:27 -07002207 if ((proxy == null && mGlobalProxy == null) || proxy.equals(mGlobalProxy)) return;
2208 if (mGlobalProxy != null) return;
2209 sendProxyBroadcast(proxy);
2210 }
2211
2212 private void handleDeprecatedGlobalHttpProxy() {
2213 String proxy = Settings.Secure.getString(mContext.getContentResolver(),
2214 Settings.Secure.HTTP_PROXY);
2215 if (!TextUtils.isEmpty(proxy)) {
2216 String data[] = proxy.split(":");
2217 String proxyHost = data[0];
2218 int proxyPort = 8080;
2219 if (data.length > 1) {
2220 try {
2221 proxyPort = Integer.parseInt(data[1]);
2222 } catch (NumberFormatException e) {
2223 return;
2224 }
2225 }
2226 ProxyProperties p = new ProxyProperties(data[0], proxyPort, "");
2227 setGlobalProxy(p);
2228 }
2229 }
2230
2231 private void sendProxyBroadcast(ProxyProperties proxy) {
Robert Greenwalt611291c2010-12-23 15:51:10 -08002232 if (proxy == null) proxy = new ProxyProperties("", 0, "");
Wink Savillee70c6f52010-12-03 12:01:38 -08002233 log("sending Proxy Broadcast for " + proxy);
Robert Greenwaltc3c5f862010-10-11 16:00:27 -07002234 Intent intent = new Intent(Proxy.PROXY_CHANGE_ACTION);
Stan Chesnutt1f2a2ac2011-01-06 11:00:19 -08002235 intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING |
2236 Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
Robert Greenwaltc3c5f862010-10-11 16:00:27 -07002237 intent.putExtra(Proxy.EXTRA_PROXY_INFO, proxy);
Robert Greenwaltd93dc8f2010-12-06 11:29:17 -08002238 mContext.sendStickyBroadcast(intent);
Robert Greenwaltc3c5f862010-10-11 16:00:27 -07002239 }
2240
2241 private static class SettingsObserver extends ContentObserver {
2242 private int mWhat;
2243 private Handler mHandler;
2244 SettingsObserver(Handler handler, int what) {
2245 super(handler);
2246 mHandler = handler;
2247 mWhat = what;
2248 }
2249
2250 void observe(Context context) {
2251 ContentResolver resolver = context.getContentResolver();
2252 resolver.registerContentObserver(Settings.Secure.getUriFor(
2253 Settings.Secure.HTTP_PROXY), false, this);
2254 }
2255
2256 @Override
2257 public void onChange(boolean selfChange) {
2258 mHandler.obtainMessage(mWhat).sendToTarget();
2259 }
2260 }
Wink Savillee70c6f52010-12-03 12:01:38 -08002261
2262 private void log(String s) {
2263 Slog.d(TAG, s);
2264 }
2265
2266 private void loge(String s) {
2267 Slog.e(TAG, s);
2268 }
Wink Savilleb7c92c72011-03-12 14:52:01 -08002269 int convertFeatureToNetworkType(String feature){
2270 int networkType = -1;
2271 if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_MMS)) {
2272 networkType = ConnectivityManager.TYPE_MOBILE_MMS;
2273 } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_SUPL)) {
2274 networkType = ConnectivityManager.TYPE_MOBILE_SUPL;
2275 } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_DUN) ||
2276 TextUtils.equals(feature, Phone.FEATURE_ENABLE_DUN_ALWAYS)) {
2277 networkType = ConnectivityManager.TYPE_MOBILE_DUN;
2278 } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_HIPRI)) {
2279 networkType = ConnectivityManager.TYPE_MOBILE_HIPRI;
2280 } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_FOTA)) {
2281 networkType = ConnectivityManager.TYPE_MOBILE_FOTA;
2282 } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_IMS)) {
2283 networkType = ConnectivityManager.TYPE_MOBILE_IMS;
2284 } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_CBS)) {
2285 networkType = ConnectivityManager.TYPE_MOBILE_CBS;
2286 }
2287 return networkType;
2288 }
The Android Open Source Project28527d22009-03-03 19:31:44 -08002289}