blob: c28a3733edb9da180ee3c38c08219782f4e22c96 [file] [log] [blame]
The Android Open Source Project9066cfe2009-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
19import android.app.Notification;
20import android.app.NotificationManager;
21import android.content.ContentResolver;
22import android.content.Context;
23import android.content.Intent;
24import android.content.pm.PackageManager;
25import android.net.ConnectivityManager;
26import android.net.IConnectivityManager;
27import android.net.MobileDataStateTracker;
28import android.net.NetworkInfo;
Robert Greenwalt37e65eb2010-08-30 10:56:47 -070029import android.net.LinkProperties;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080030import android.net.NetworkStateTracker;
Robert Greenwalt585ac0f2010-08-27 09:24:29 -070031import android.net.NetworkUtils;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080032import android.net.wifi.WifiStateTracker;
Irfan Sheriffd649c122010-06-09 15:39:36 -070033import android.net.NetworkUtils;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080034import android.os.Binder;
35import android.os.Handler;
Robert Greenwalt42acef32009-08-12 16:08:25 -070036import android.os.IBinder;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080037import android.os.Looper;
38import android.os.Message;
Robert Greenwalt14f2ef42010-06-15 12:19:37 -070039import android.os.PowerManager;
Robert Greenwalt42acef32009-08-12 16:08:25 -070040import android.os.RemoteException;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080041import android.os.ServiceManager;
42import android.os.SystemProperties;
43import android.provider.Settings;
Robert Greenwalt42acef32009-08-12 16:08:25 -070044import android.text.TextUtils;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080045import android.util.EventLog;
Joe Onorato8a9b2202010-02-26 18:56:32 -080046import android.util.Slog;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080047
Robert Greenwalt42acef32009-08-12 16:08:25 -070048import com.android.internal.telephony.Phone;
49
Robert Greenwaltd0e18ff2010-01-26 11:40:34 -080050import com.android.server.connectivity.Tethering;
51
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080052import java.io.FileDescriptor;
Irfan Sheriffd649c122010-06-09 15:39:36 -070053import java.io.FileWriter;
54import java.io.IOException;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080055import java.io.PrintWriter;
Robert Greenwalt47f69fe2010-06-15 15:43:39 -070056import java.net.InetAddress;
57import java.net.UnknownHostException;
Robert Greenwalt42acef32009-08-12 16:08:25 -070058import java.util.ArrayList;
Robert Greenwalt47f69fe2010-06-15 15:43:39 -070059import java.util.Collection;
Robert Greenwalt42acef32009-08-12 16:08:25 -070060import java.util.List;
Robert Greenwalt585ac0f2010-08-27 09:24:29 -070061import java.net.InetAddress;
62import java.net.UnknownHostException;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080063
64/**
65 * @hide
66 */
67public class ConnectivityService extends IConnectivityManager.Stub {
68
Robert Greenwaltd8df1492009-10-06 14:12:53 -070069 private static final boolean DBG = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080070 private static final String TAG = "ConnectivityService";
71
Robert Greenwalt42acef32009-08-12 16:08:25 -070072 // how long to wait before switching back to a radio's default network
73 private static final int RESTORE_DEFAULT_NETWORK_DELAY = 1 * 60 * 1000;
74 // system property that can override the above value
75 private static final String NETWORK_RESTORE_DELAY_PROP_NAME =
76 "android.telephony.apn-restore";
77
Robert Greenwaltd0e18ff2010-01-26 11:40:34 -080078 private Tethering mTethering;
Robert Greenwaltc9d5fb72010-02-25 12:29:30 -080079 private boolean mTetheringConfigValid = false;
Robert Greenwaltd0e18ff2010-01-26 11:40:34 -080080
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080081 /**
82 * Sometimes we want to refer to the individual network state
83 * trackers separately, and sometimes we just want to treat them
84 * abstractly.
85 */
86 private NetworkStateTracker mNetTrackers[];
Robert Greenwalt42acef32009-08-12 16:08:25 -070087
88 /**
89 * A per Net list of the PID's that requested access to the net
90 * used both as a refcount and for per-PID DNS selection
91 */
92 private List mNetRequestersPids[];
93
Irfan Sheriffa2a1b912010-06-07 09:03:04 -070094 private WifiWatchdogService mWifiWatchdogService;
95
Robert Greenwalt42acef32009-08-12 16:08:25 -070096 // priority order of the nettrackers
97 // (excluding dynamically set mNetworkPreference)
98 // TODO - move mNetworkTypePreference into this
99 private int[] mPriorityList;
100
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800101 private Context mContext;
102 private int mNetworkPreference;
Robert Greenwalt42acef32009-08-12 16:08:25 -0700103 private int mActiveDefaultNetwork = -1;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800104
105 private int mNumDnsEntries;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800106
107 private boolean mTestMode;
Joe Onorato00092872010-09-01 21:18:22 -0700108 private static ConnectivityService sServiceInstance;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800109
Robert Greenwalt42acef32009-08-12 16:08:25 -0700110 private Handler mHandler;
111
112 // list of DeathRecipients used to make sure features are turned off when
113 // a process dies
114 private List mFeatureUsers;
115
Mike Lockwood0f79b542009-08-14 14:18:49 -0400116 private boolean mSystemReady;
Dianne Hackborn1c633fc2009-12-08 19:45:14 -0800117 private Intent mInitialBroadcast;
Mike Lockwood0f79b542009-08-14 14:18:49 -0400118
Robert Greenwalt14f2ef42010-06-15 12:19:37 -0700119 private PowerManager.WakeLock mNetTransitionWakeLock;
120 private String mNetTransitionWakeLockCausedBy = "";
121 private int mNetTransitionWakeLockSerialNumber;
122 private int mNetTransitionWakeLockTimeout;
123
Robert Greenwalte90aa5e2010-09-01 11:34:05 -0700124 private InetAddress mDefaultDns;
125
Robert Greenwalt511288a2009-12-07 11:33:18 -0800126 private static class NetworkAttributes {
Robert Greenwalt42acef32009-08-12 16:08:25 -0700127 /**
128 * Class for holding settings read from resources.
129 */
130 public String mName;
131 public int mType;
132 public int mRadio;
133 public int mPriority;
Robert Greenwalt511288a2009-12-07 11:33:18 -0800134 public NetworkInfo.State mLastState;
Robert Greenwalt42acef32009-08-12 16:08:25 -0700135 public NetworkAttributes(String init) {
136 String fragments[] = init.split(",");
137 mName = fragments[0].toLowerCase();
Robert Greenwalt5154ae762009-10-30 14:17:42 -0700138 mType = Integer.parseInt(fragments[1]);
139 mRadio = Integer.parseInt(fragments[2]);
140 mPriority = Integer.parseInt(fragments[3]);
Robert Greenwalt511288a2009-12-07 11:33:18 -0800141 mLastState = NetworkInfo.State.UNKNOWN;
Robert Greenwalt42acef32009-08-12 16:08:25 -0700142 }
143 public boolean isDefault() {
144 return (mType == mRadio);
145 }
146 }
147 NetworkAttributes[] mNetAttributes;
Robert Greenwalt5154ae762009-10-30 14:17:42 -0700148 int mNetworksDefined;
Robert Greenwalt42acef32009-08-12 16:08:25 -0700149
Robert Greenwalt511288a2009-12-07 11:33:18 -0800150 private static class RadioAttributes {
Robert Greenwalt42acef32009-08-12 16:08:25 -0700151 public int mSimultaneity;
152 public int mType;
153 public RadioAttributes(String init) {
154 String fragments[] = init.split(",");
Robert Greenwalt5154ae762009-10-30 14:17:42 -0700155 mType = Integer.parseInt(fragments[0]);
156 mSimultaneity = Integer.parseInt(fragments[1]);
Robert Greenwalt42acef32009-08-12 16:08:25 -0700157 }
158 }
159 RadioAttributes[] mRadioAttributes;
160
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800161 private static class ConnectivityThread extends Thread {
162 private Context mContext;
Robert Greenwalt86e9e552009-07-16 17:21:39 -0700163
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800164 private ConnectivityThread(Context context) {
165 super("ConnectivityThread");
166 mContext = context;
167 }
168
169 @Override
170 public void run() {
171 Looper.prepare();
172 synchronized (this) {
173 sServiceInstance = new ConnectivityService(mContext);
174 notifyAll();
175 }
176 Looper.loop();
177 }
Robert Greenwalt86e9e552009-07-16 17:21:39 -0700178
Joe Onorato00092872010-09-01 21:18:22 -0700179 public static ConnectivityService getServiceInstance(Context context) {
180 ConnectivityThread thread = new ConnectivityThread(context);
181 thread.start();
182
183 synchronized (thread) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800184 while (sServiceInstance == null) {
185 try {
186 // Wait until sServiceInstance has been initialized.
187 thread.wait();
188 } catch (InterruptedException ignore) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800189 Slog.e(TAG,
Robert Greenwalt86e9e552009-07-16 17:21:39 -0700190 "Unexpected InterruptedException while waiting"+
191 " for ConnectivityService thread");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800192 }
193 }
194 }
Robert Greenwalt86e9e552009-07-16 17:21:39 -0700195
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800196 return sServiceInstance;
197 }
198 }
Robert Greenwalt86e9e552009-07-16 17:21:39 -0700199
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800200 public static ConnectivityService getInstance(Context context) {
201 return ConnectivityThread.getServiceInstance(context);
202 }
Robert Greenwalt86e9e552009-07-16 17:21:39 -0700203
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800204 private ConnectivityService(Context context) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800205 if (DBG) Slog.v(TAG, "ConnectivityService starting up");
Robert Greenwaltde8383c2010-01-14 17:47:58 -0800206
207 // setup our unique device name
208 String id = Settings.Secure.getString(context.getContentResolver(),
209 Settings.Secure.ANDROID_ID);
210 if (id != null && id.length() > 0) {
211 String name = new String("android_").concat(id);
212 SystemProperties.set("net.hostname", name);
213 }
214
Robert Greenwalte90aa5e2010-09-01 11:34:05 -0700215 // read our default dns server ip
216 String dns = Settings.Secure.getString(context.getContentResolver(),
217 Settings.Secure.DEFAULT_DNS_SERVER);
218 if (dns == null || dns.length() == 0) {
219 dns = context.getResources().getString(
220 com.android.internal.R.string.config_default_dns_server);
221 }
222 try {
223 mDefaultDns = InetAddress.getByName(dns);
224 } catch (UnknownHostException e) {
225 Slog.e(TAG, "Error setting defaultDns using " + dns);
226 }
227
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800228 mContext = context;
Robert Greenwalt14f2ef42010-06-15 12:19:37 -0700229
230 PowerManager powerManager = (PowerManager)mContext.getSystemService(Context.POWER_SERVICE);
231 mNetTransitionWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
232 mNetTransitionWakeLockTimeout = mContext.getResources().getInteger(
233 com.android.internal.R.integer.config_networkTransitionTimeout);
234
Robert Greenwalt42acef32009-08-12 16:08:25 -0700235 mNetTrackers = new NetworkStateTracker[
236 ConnectivityManager.MAX_NETWORK_TYPE+1];
237 mHandler = new MyHandler();
Robert Greenwalt86e9e552009-07-16 17:21:39 -0700238
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800239 mNetworkPreference = getPersistedNetworkPreference();
Robert Greenwalt86e9e552009-07-16 17:21:39 -0700240
Robert Greenwalt5154ae762009-10-30 14:17:42 -0700241 mRadioAttributes = new RadioAttributes[ConnectivityManager.MAX_RADIO_TYPE+1];
242 mNetAttributes = new NetworkAttributes[ConnectivityManager.MAX_NETWORK_TYPE+1];
243
Robert Greenwalt42acef32009-08-12 16:08:25 -0700244 // Load device network attributes from resources
Robert Greenwalt42acef32009-08-12 16:08:25 -0700245 String[] raStrings = context.getResources().getStringArray(
246 com.android.internal.R.array.radioAttributes);
Robert Greenwalt5154ae762009-10-30 14:17:42 -0700247 for (String raString : raStrings) {
248 RadioAttributes r = new RadioAttributes(raString);
249 if (r.mType > ConnectivityManager.MAX_RADIO_TYPE) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800250 Slog.e(TAG, "Error in radioAttributes - ignoring attempt to define type " + r.mType);
Robert Greenwalt5154ae762009-10-30 14:17:42 -0700251 continue;
252 }
253 if (mRadioAttributes[r.mType] != null) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800254 Slog.e(TAG, "Error in radioAttributes - ignoring attempt to redefine type " +
Robert Greenwalt5154ae762009-10-30 14:17:42 -0700255 r.mType);
256 continue;
257 }
Robert Greenwalt42acef32009-08-12 16:08:25 -0700258 mRadioAttributes[r.mType] = r;
259 }
260
Robert Greenwalt5154ae762009-10-30 14:17:42 -0700261 String[] naStrings = context.getResources().getStringArray(
262 com.android.internal.R.array.networkAttributes);
263 for (String naString : naStrings) {
264 try {
265 NetworkAttributes n = new NetworkAttributes(naString);
266 if (n.mType > ConnectivityManager.MAX_NETWORK_TYPE) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800267 Slog.e(TAG, "Error in networkAttributes - ignoring attempt to define type " +
Robert Greenwalt5154ae762009-10-30 14:17:42 -0700268 n.mType);
269 continue;
Robert Greenwalt42acef32009-08-12 16:08:25 -0700270 }
Robert Greenwalt5154ae762009-10-30 14:17:42 -0700271 if (mNetAttributes[n.mType] != null) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800272 Slog.e(TAG, "Error in networkAttributes - ignoring attempt to redefine type " +
Robert Greenwalt5154ae762009-10-30 14:17:42 -0700273 n.mType);
274 continue;
275 }
276 if (mRadioAttributes[n.mRadio] == null) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800277 Slog.e(TAG, "Error in networkAttributes - ignoring attempt to use undefined " +
Robert Greenwalt5154ae762009-10-30 14:17:42 -0700278 "radio " + n.mRadio + " in network type " + n.mType);
279 continue;
280 }
281 mNetAttributes[n.mType] = n;
282 mNetworksDefined++;
283 } catch(Exception e) {
284 // ignore it - leave the entry null
Robert Greenwalt42acef32009-08-12 16:08:25 -0700285 }
286 }
287
Robert Greenwalt5154ae762009-10-30 14:17:42 -0700288 // high priority first
289 mPriorityList = new int[mNetworksDefined];
290 {
291 int insertionPoint = mNetworksDefined-1;
292 int currentLowest = 0;
293 int nextLowest = 0;
294 while (insertionPoint > -1) {
295 for (NetworkAttributes na : mNetAttributes) {
296 if (na == null) continue;
297 if (na.mPriority < currentLowest) continue;
298 if (na.mPriority > currentLowest) {
299 if (na.mPriority < nextLowest || nextLowest == 0) {
300 nextLowest = na.mPriority;
301 }
302 continue;
303 }
304 mPriorityList[insertionPoint--] = na.mType;
305 }
306 currentLowest = nextLowest;
307 nextLowest = 0;
308 }
309 }
310
311 mNetRequestersPids = new ArrayList[ConnectivityManager.MAX_NETWORK_TYPE+1];
312 for (int i : mPriorityList) {
Robert Greenwalt42acef32009-08-12 16:08:25 -0700313 mNetRequestersPids[i] = new ArrayList();
314 }
315
316 mFeatureUsers = new ArrayList();
317
Robert Greenwalt5154ae762009-10-30 14:17:42 -0700318 mNumDnsEntries = 0;
319
320 mTestMode = SystemProperties.get("cm.test.mode").equals("true")
321 && SystemProperties.get("ro.build.type").equals("eng");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800322 /*
323 * Create the network state trackers for Wi-Fi and mobile
324 * data. Maybe this could be done with a factory class,
325 * but it's not clear that it's worth it, given that
326 * the number of different network types is not going
327 * to change very often.
328 */
Robert Greenwaltc03fa502010-02-23 18:58:05 -0800329 boolean noMobileData = !getMobileDataEnabled();
Robert Greenwalt5154ae762009-10-30 14:17:42 -0700330 for (int netType : mPriorityList) {
331 switch (mNetAttributes[netType].mRadio) {
332 case ConnectivityManager.TYPE_WIFI:
Joe Onorato8a9b2202010-02-26 18:56:32 -0800333 if (DBG) Slog.v(TAG, "Starting Wifi Service.");
Wink Savillec7a98342010-08-13 16:11:42 -0700334 WifiStateTracker wst = new WifiStateTracker();
Irfan Sheriff0d255342010-07-28 09:35:20 -0700335 WifiService wifiService = new WifiService(context);
Robert Greenwalt5154ae762009-10-30 14:17:42 -0700336 ServiceManager.addService(Context.WIFI_SERVICE, wifiService);
Irfan Sheriff0d255342010-07-28 09:35:20 -0700337 wifiService.checkAndStartWifi();
Robert Greenwalt5154ae762009-10-30 14:17:42 -0700338 mNetTrackers[ConnectivityManager.TYPE_WIFI] = wst;
Wink Savillec7a98342010-08-13 16:11:42 -0700339 wst.startMonitoring(context, mHandler);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800340
Irfan Sheriffa2a1b912010-06-07 09:03:04 -0700341 //TODO: as part of WWS refactor, create only when needed
Irfan Sheriff0d255342010-07-28 09:35:20 -0700342 mWifiWatchdogService = new WifiWatchdogService(context);
Irfan Sheriffa2a1b912010-06-07 09:03:04 -0700343
Robert Greenwalt5154ae762009-10-30 14:17:42 -0700344 break;
345 case ConnectivityManager.TYPE_MOBILE:
Wink Savillec7a98342010-08-13 16:11:42 -0700346 mNetTrackers[netType] = new MobileDataStateTracker(netType,
347 mNetAttributes[netType].mName);
348 mNetTrackers[netType].startMonitoring(context, mHandler);
Robert Greenwaltc03fa502010-02-23 18:58:05 -0800349 if (noMobileData) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800350 if (DBG) Slog.d(TAG, "tearing down Mobile networks due to setting");
Robert Greenwaltc03fa502010-02-23 18:58:05 -0800351 mNetTrackers[netType].teardown();
352 }
Robert Greenwalt5154ae762009-10-30 14:17:42 -0700353 break;
354 default:
Joe Onorato8a9b2202010-02-26 18:56:32 -0800355 Slog.e(TAG, "Trying to create a DataStateTracker for an unknown radio type " +
Robert Greenwalt5154ae762009-10-30 14:17:42 -0700356 mNetAttributes[netType].mRadio);
357 continue;
358 }
359 }
Robert Greenwaltd0e18ff2010-01-26 11:40:34 -0800360
Robert Greenwaltdfadaea2010-03-11 15:03:08 -0800361 mTethering = new Tethering(mContext, mHandler.getLooper());
Robert Greenwaltc9d5fb72010-02-25 12:29:30 -0800362 mTetheringConfigValid = (((mNetTrackers[ConnectivityManager.TYPE_MOBILE_DUN] != null) ||
363 !mTethering.isDunRequired()) &&
364 (mTethering.getTetherableUsbRegexs().length != 0 ||
Danica Chang6fdd0c62010-08-11 14:54:43 -0700365 mTethering.getTetherableWifiRegexs().length != 0 ||
366 mTethering.getTetherableBluetoothRegexs().length != 0) &&
Robert Greenwaltc9d5fb72010-02-25 12:29:30 -0800367 mTethering.getUpstreamIfaceRegexs().length != 0);
368
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800369 }
370
Robert Greenwalt5154ae762009-10-30 14:17:42 -0700371
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800372 /**
Robert Greenwalt86e9e552009-07-16 17:21:39 -0700373 * Sets the preferred network.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800374 * @param preference the new preference
375 */
376 public synchronized void setNetworkPreference(int preference) {
377 enforceChangePermission();
Robert Greenwalt42acef32009-08-12 16:08:25 -0700378 if (ConnectivityManager.isNetworkTypeValid(preference) &&
Robert Greenwalt5154ae762009-10-30 14:17:42 -0700379 mNetAttributes[preference] != null &&
Robert Greenwalt42acef32009-08-12 16:08:25 -0700380 mNetAttributes[preference].isDefault()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800381 if (mNetworkPreference != preference) {
382 persistNetworkPreference(preference);
383 mNetworkPreference = preference;
384 enforcePreference();
385 }
386 }
387 }
388
389 public int getNetworkPreference() {
390 enforceAccessPermission();
391 return mNetworkPreference;
392 }
393
394 private void persistNetworkPreference(int networkPreference) {
395 final ContentResolver cr = mContext.getContentResolver();
Robert Greenwalt86e9e552009-07-16 17:21:39 -0700396 Settings.Secure.putInt(cr, Settings.Secure.NETWORK_PREFERENCE,
397 networkPreference);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800398 }
Robert Greenwalt86e9e552009-07-16 17:21:39 -0700399
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800400 private int getPersistedNetworkPreference() {
401 final ContentResolver cr = mContext.getContentResolver();
402
403 final int networkPrefSetting = Settings.Secure
404 .getInt(cr, Settings.Secure.NETWORK_PREFERENCE, -1);
405 if (networkPrefSetting != -1) {
406 return networkPrefSetting;
407 }
408
409 return ConnectivityManager.DEFAULT_NETWORK_PREFERENCE;
410 }
Robert Greenwalt86e9e552009-07-16 17:21:39 -0700411
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800412 /**
Robert Greenwalt86e9e552009-07-16 17:21:39 -0700413 * Make the state of network connectivity conform to the preference settings
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800414 * In this method, we only tear down a non-preferred network. Establishing
415 * a connection to the preferred network is taken care of when we handle
416 * the disconnect event from the non-preferred network
417 * (see {@link #handleDisconnect(NetworkInfo)}).
418 */
419 private void enforcePreference() {
Robert Greenwalt42acef32009-08-12 16:08:25 -0700420 if (mNetTrackers[mNetworkPreference].getNetworkInfo().isConnected())
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800421 return;
422
Robert Greenwalt42acef32009-08-12 16:08:25 -0700423 if (!mNetTrackers[mNetworkPreference].isAvailable())
424 return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800425
Robert Greenwalt42acef32009-08-12 16:08:25 -0700426 for (int t=0; t <= ConnectivityManager.MAX_RADIO_TYPE; t++) {
Robert Greenwalt5154ae762009-10-30 14:17:42 -0700427 if (t != mNetworkPreference && mNetTrackers[t] != null &&
Robert Greenwalt42acef32009-08-12 16:08:25 -0700428 mNetTrackers[t].getNetworkInfo().isConnected()) {
Robert Greenwaltec9fe462009-08-20 15:25:14 -0700429 if (DBG) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800430 Slog.d(TAG, "tearing down " +
Robert Greenwaltec9fe462009-08-20 15:25:14 -0700431 mNetTrackers[t].getNetworkInfo() +
432 " in enforcePreference");
433 }
Robert Greenwalt42acef32009-08-12 16:08:25 -0700434 teardown(mNetTrackers[t]);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800435 }
436 }
437 }
438
439 private boolean teardown(NetworkStateTracker netTracker) {
440 if (netTracker.teardown()) {
441 netTracker.setTeardownRequested(true);
442 return true;
443 } else {
444 return false;
445 }
446 }
447
448 /**
449 * Return NetworkInfo for the active (i.e., connected) network interface.
450 * It is assumed that at most one network is active at a time. If more
451 * than one is active, it is indeterminate which will be returned.
Robert Greenwalt86e9e552009-07-16 17:21:39 -0700452 * @return the info for the active network, or {@code null} if none is
453 * active
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800454 */
455 public NetworkInfo getActiveNetworkInfo() {
456 enforceAccessPermission();
Robert Greenwalt42acef32009-08-12 16:08:25 -0700457 for (int type=0; type <= ConnectivityManager.MAX_NETWORK_TYPE; type++) {
Robert Greenwalt5154ae762009-10-30 14:17:42 -0700458 if (mNetAttributes[type] == null || !mNetAttributes[type].isDefault()) {
Robert Greenwalt42acef32009-08-12 16:08:25 -0700459 continue;
460 }
461 NetworkStateTracker t = mNetTrackers[type];
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800462 NetworkInfo info = t.getNetworkInfo();
463 if (info.isConnected()) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800464 if (DBG && type != mActiveDefaultNetwork) Slog.e(TAG,
Robert Greenwalt42acef32009-08-12 16:08:25 -0700465 "connected default network is not " +
466 "mActiveDefaultNetwork!");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800467 return info;
468 }
469 }
470 return null;
471 }
472
473 public NetworkInfo getNetworkInfo(int networkType) {
474 enforceAccessPermission();
475 if (ConnectivityManager.isNetworkTypeValid(networkType)) {
476 NetworkStateTracker t = mNetTrackers[networkType];
477 if (t != null)
478 return t.getNetworkInfo();
479 }
480 return null;
481 }
482
483 public NetworkInfo[] getAllNetworkInfo() {
484 enforceAccessPermission();
Robert Greenwalt5154ae762009-10-30 14:17:42 -0700485 NetworkInfo[] result = new NetworkInfo[mNetworksDefined];
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800486 int i = 0;
487 for (NetworkStateTracker t : mNetTrackers) {
Robert Greenwalt5154ae762009-10-30 14:17:42 -0700488 if(t != null) result[i++] = t.getNetworkInfo();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800489 }
490 return result;
491 }
492
493 public boolean setRadios(boolean turnOn) {
494 boolean result = true;
495 enforceChangePermission();
496 for (NetworkStateTracker t : mNetTrackers) {
Robert Greenwalt5154ae762009-10-30 14:17:42 -0700497 if (t != null) result = t.setRadio(turnOn) && result;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800498 }
499 return result;
500 }
501
502 public boolean setRadio(int netType, boolean turnOn) {
503 enforceChangePermission();
504 if (!ConnectivityManager.isNetworkTypeValid(netType)) {
505 return false;
506 }
507 NetworkStateTracker tracker = mNetTrackers[netType];
508 return tracker != null && tracker.setRadio(turnOn);
509 }
510
Robert Greenwalt9c75d4a2009-09-27 17:27:04 -0700511 /**
512 * Used to notice when the calling process dies so we can self-expire
513 *
514 * Also used to know if the process has cleaned up after itself when
515 * our auto-expire timer goes off. The timer has a link to an object.
516 *
517 */
Robert Greenwalt42acef32009-08-12 16:08:25 -0700518 private class FeatureUser implements IBinder.DeathRecipient {
519 int mNetworkType;
520 String mFeature;
521 IBinder mBinder;
522 int mPid;
523 int mUid;
Robert Greenwaltb9285352009-12-21 18:24:07 -0800524 long mCreateTime;
Robert Greenwalt42acef32009-08-12 16:08:25 -0700525
526 FeatureUser(int type, String feature, IBinder binder) {
527 super();
528 mNetworkType = type;
529 mFeature = feature;
530 mBinder = binder;
531 mPid = getCallingPid();
532 mUid = getCallingUid();
Robert Greenwaltb9285352009-12-21 18:24:07 -0800533 mCreateTime = System.currentTimeMillis();
Robert Greenwalt9c75d4a2009-09-27 17:27:04 -0700534
Robert Greenwalt42acef32009-08-12 16:08:25 -0700535 try {
536 mBinder.linkToDeath(this, 0);
537 } catch (RemoteException e) {
538 binderDied();
539 }
540 }
541
542 void unlinkDeathRecipient() {
543 mBinder.unlinkToDeath(this, 0);
544 }
545
546 public void binderDied() {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800547 Slog.d(TAG, "ConnectivityService FeatureUser binderDied(" +
Robert Greenwaltb9285352009-12-21 18:24:07 -0800548 mNetworkType + ", " + mFeature + ", " + mBinder + "), created " +
549 (System.currentTimeMillis() - mCreateTime) + " mSec ago");
Robert Greenwalt9c75d4a2009-09-27 17:27:04 -0700550 stopUsingNetworkFeature(this, false);
Robert Greenwalt42acef32009-08-12 16:08:25 -0700551 }
552
Robert Greenwalt9c75d4a2009-09-27 17:27:04 -0700553 public void expire() {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800554 Slog.d(TAG, "ConnectivityService FeatureUser expire(" +
Robert Greenwaltb9285352009-12-21 18:24:07 -0800555 mNetworkType + ", " + mFeature + ", " + mBinder +"), created " +
556 (System.currentTimeMillis() - mCreateTime) + " mSec ago");
Robert Greenwalt9c75d4a2009-09-27 17:27:04 -0700557 stopUsingNetworkFeature(this, false);
558 }
Robert Greenwaltb9285352009-12-21 18:24:07 -0800559
560 public String toString() {
561 return "FeatureUser("+mNetworkType+","+mFeature+","+mPid+","+mUid+"), created " +
562 (System.currentTimeMillis() - mCreateTime) + " mSec ago";
563 }
Robert Greenwalt42acef32009-08-12 16:08:25 -0700564 }
565
Robert Greenwalt9c75d4a2009-09-27 17:27:04 -0700566 // javadoc from interface
Robert Greenwalt42acef32009-08-12 16:08:25 -0700567 public int startUsingNetworkFeature(int networkType, String feature,
568 IBinder binder) {
569 if (DBG) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800570 Slog.d(TAG, "startUsingNetworkFeature for net " + networkType +
Robert Greenwalt42acef32009-08-12 16:08:25 -0700571 ": " + feature);
572 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800573 enforceChangePermission();
Robert Greenwalt5154ae762009-10-30 14:17:42 -0700574 if (!ConnectivityManager.isNetworkTypeValid(networkType) ||
575 mNetAttributes[networkType] == null) {
Robert Greenwalt42acef32009-08-12 16:08:25 -0700576 return Phone.APN_REQUEST_FAILED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800577 }
Robert Greenwalt42acef32009-08-12 16:08:25 -0700578
Robert Greenwalt9c75d4a2009-09-27 17:27:04 -0700579 FeatureUser f = new FeatureUser(networkType, feature, binder);
Robert Greenwalt42acef32009-08-12 16:08:25 -0700580
581 // TODO - move this into the MobileDataStateTracker
582 int usedNetworkType = networkType;
583 if(networkType == ConnectivityManager.TYPE_MOBILE) {
Robert Greenwaltc03fa502010-02-23 18:58:05 -0800584 if (!getMobileDataEnabled()) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800585 if (DBG) Slog.d(TAG, "requested special network with data disabled - rejected");
Robert Greenwaltc03fa502010-02-23 18:58:05 -0800586 return Phone.APN_TYPE_NOT_AVAILABLE;
587 }
Robert Greenwalt42acef32009-08-12 16:08:25 -0700588 if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_MMS)) {
589 usedNetworkType = ConnectivityManager.TYPE_MOBILE_MMS;
590 } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_SUPL)) {
591 usedNetworkType = ConnectivityManager.TYPE_MOBILE_SUPL;
592 } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_DUN)) {
593 usedNetworkType = ConnectivityManager.TYPE_MOBILE_DUN;
594 } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_HIPRI)) {
595 usedNetworkType = ConnectivityManager.TYPE_MOBILE_HIPRI;
596 }
597 }
598 NetworkStateTracker network = mNetTrackers[usedNetworkType];
599 if (network != null) {
600 if (usedNetworkType != networkType) {
601 Integer currentPid = new Integer(getCallingPid());
602
603 NetworkStateTracker radio = mNetTrackers[networkType];
604 NetworkInfo ni = network.getNetworkInfo();
605
606 if (ni.isAvailable() == false) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800607 if (DBG) Slog.d(TAG, "special network not available");
Robert Greenwalt42acef32009-08-12 16:08:25 -0700608 return Phone.APN_TYPE_NOT_AVAILABLE;
609 }
610
Robert Greenwalt9c75d4a2009-09-27 17:27:04 -0700611 synchronized(this) {
612 mFeatureUsers.add(f);
613 if (!mNetRequestersPids[usedNetworkType].contains(currentPid)) {
614 // this gets used for per-pid dns when connected
615 mNetRequestersPids[usedNetworkType].add(currentPid);
616 }
Robert Greenwalt42acef32009-08-12 16:08:25 -0700617 }
Robert Greenwalt9c75d4a2009-09-27 17:27:04 -0700618 mHandler.sendMessageDelayed(mHandler.obtainMessage(
619 NetworkStateTracker.EVENT_RESTORE_DEFAULT_NETWORK,
620 f), getRestoreDefaultNetworkDelay());
621
Robert Greenwalt42acef32009-08-12 16:08:25 -0700622
Robert Greenwalta64bf832009-08-19 20:19:33 -0700623 if ((ni.isConnectedOrConnecting() == true) &&
624 !network.isTeardownRequested()) {
Robert Greenwalt42acef32009-08-12 16:08:25 -0700625 if (ni.isConnected() == true) {
626 // add the pid-specific dns
Robert Greenwaltc76b8fa2010-07-23 15:46:26 -0700627 handleDnsConfigurationChange(networkType);
Joe Onorato8a9b2202010-02-26 18:56:32 -0800628 if (DBG) Slog.d(TAG, "special network already active");
Robert Greenwalt42acef32009-08-12 16:08:25 -0700629 return Phone.APN_ALREADY_ACTIVE;
630 }
Joe Onorato8a9b2202010-02-26 18:56:32 -0800631 if (DBG) Slog.d(TAG, "special network already connecting");
Robert Greenwalt42acef32009-08-12 16:08:25 -0700632 return Phone.APN_REQUEST_STARTED;
633 }
634
635 // check if the radio in play can make another contact
636 // assume if cannot for now
637
Joe Onorato8a9b2202010-02-26 18:56:32 -0800638 if (DBG) Slog.d(TAG, "reconnecting to special network");
Robert Greenwalt42acef32009-08-12 16:08:25 -0700639 network.reconnect();
640 return Phone.APN_REQUEST_STARTED;
641 } else {
Robert Greenwalt02648a42010-05-18 10:52:51 -0700642 return -1;
Robert Greenwalt42acef32009-08-12 16:08:25 -0700643 }
644 }
645 return Phone.APN_TYPE_NOT_AVAILABLE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800646 }
647
Robert Greenwalt9c75d4a2009-09-27 17:27:04 -0700648 // javadoc from interface
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800649 public int stopUsingNetworkFeature(int networkType, String feature) {
Robert Greenwaltb8f16342009-10-06 17:52:40 -0700650 enforceChangePermission();
651
Robert Greenwalt9c75d4a2009-09-27 17:27:04 -0700652 int pid = getCallingPid();
653 int uid = getCallingUid();
654
655 FeatureUser u = null;
656 boolean found = false;
657
658 synchronized(this) {
659 for (int i = 0; i < mFeatureUsers.size() ; i++) {
660 u = (FeatureUser)mFeatureUsers.get(i);
661 if (uid == u.mUid && pid == u.mPid &&
662 networkType == u.mNetworkType &&
663 TextUtils.equals(feature, u.mFeature)) {
664 found = true;
665 break;
666 }
667 }
668 }
669 if (found && u != null) {
670 // stop regardless of how many other time this proc had called start
671 return stopUsingNetworkFeature(u, true);
672 } else {
673 // none found!
Joe Onorato8a9b2202010-02-26 18:56:32 -0800674 if (DBG) Slog.d(TAG, "ignoring stopUsingNetworkFeature - not a live request");
Robert Greenwalt9c75d4a2009-09-27 17:27:04 -0700675 return 1;
676 }
Robert Greenwalt42acef32009-08-12 16:08:25 -0700677 }
678
Robert Greenwalt9c75d4a2009-09-27 17:27:04 -0700679 private int stopUsingNetworkFeature(FeatureUser u, boolean ignoreDups) {
680 int networkType = u.mNetworkType;
681 String feature = u.mFeature;
682 int pid = u.mPid;
683 int uid = u.mUid;
684
685 NetworkStateTracker tracker = null;
686 boolean callTeardown = false; // used to carry our decision outside of sync block
687
Robert Greenwalt42acef32009-08-12 16:08:25 -0700688 if (DBG) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800689 Slog.d(TAG, "stopUsingNetworkFeature for net " + networkType +
Robert Greenwalt42acef32009-08-12 16:08:25 -0700690 ": " + feature);
691 }
Robert Greenwaltb8f16342009-10-06 17:52:40 -0700692
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800693 if (!ConnectivityManager.isNetworkTypeValid(networkType)) {
694 return -1;
695 }
Robert Greenwalt42acef32009-08-12 16:08:25 -0700696
Robert Greenwalt9c75d4a2009-09-27 17:27:04 -0700697 // need to link the mFeatureUsers list with the mNetRequestersPids state in this
698 // sync block
699 synchronized(this) {
700 // check if this process still has an outstanding start request
701 if (!mFeatureUsers.contains(u)) {
Robert Greenwalt78a640a2010-03-10 16:10:43 -0800702 if (DBG) Slog.d(TAG, "ignoring - this process has no outstanding requests");
Robert Greenwalt42acef32009-08-12 16:08:25 -0700703 return 1;
704 }
Robert Greenwalt9c75d4a2009-09-27 17:27:04 -0700705 u.unlinkDeathRecipient();
706 mFeatureUsers.remove(mFeatureUsers.indexOf(u));
707 // If we care about duplicate requests, check for that here.
708 //
709 // This is done to support the extension of a request - the app
710 // can request we start the network feature again and renew the
711 // auto-shutoff delay. Normal "stop" calls from the app though
712 // do not pay attention to duplicate requests - in effect the
713 // API does not refcount and a single stop will counter multiple starts.
714 if (ignoreDups == false) {
715 for (int i = 0; i < mFeatureUsers.size() ; i++) {
716 FeatureUser x = (FeatureUser)mFeatureUsers.get(i);
717 if (x.mUid == u.mUid && x.mPid == u.mPid &&
718 x.mNetworkType == u.mNetworkType &&
719 TextUtils.equals(x.mFeature, u.mFeature)) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800720 if (DBG) Slog.d(TAG, "ignoring stopUsingNetworkFeature as dup is found");
Robert Greenwalt9c75d4a2009-09-27 17:27:04 -0700721 return 1;
722 }
723 }
Robert Greenwalt42acef32009-08-12 16:08:25 -0700724 }
Robert Greenwalt9c75d4a2009-09-27 17:27:04 -0700725
726 // TODO - move to MobileDataStateTracker
727 int usedNetworkType = networkType;
728 if (networkType == ConnectivityManager.TYPE_MOBILE) {
729 if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_MMS)) {
730 usedNetworkType = ConnectivityManager.TYPE_MOBILE_MMS;
731 } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_SUPL)) {
732 usedNetworkType = ConnectivityManager.TYPE_MOBILE_SUPL;
733 } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_DUN)) {
734 usedNetworkType = ConnectivityManager.TYPE_MOBILE_DUN;
735 } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_HIPRI)) {
736 usedNetworkType = ConnectivityManager.TYPE_MOBILE_HIPRI;
737 }
738 }
739 tracker = mNetTrackers[usedNetworkType];
Robert Greenwalt5154ae762009-10-30 14:17:42 -0700740 if (tracker == null) {
Robert Greenwalt78a640a2010-03-10 16:10:43 -0800741 if (DBG) Slog.d(TAG, "ignoring - no known tracker for net type " + usedNetworkType);
Robert Greenwalt5154ae762009-10-30 14:17:42 -0700742 return -1;
743 }
744 if (usedNetworkType != networkType) {
Robert Greenwalt9c75d4a2009-09-27 17:27:04 -0700745 Integer currentPid = new Integer(pid);
Robert Greenwalt9c75d4a2009-09-27 17:27:04 -0700746 mNetRequestersPids[usedNetworkType].remove(currentPid);
Robert Greenwalt421c72b2009-12-17 14:54:59 -0800747 reassessPidDns(pid, true);
Robert Greenwalt9c75d4a2009-09-27 17:27:04 -0700748 if (mNetRequestersPids[usedNetworkType].size() != 0) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800749 if (DBG) Slog.d(TAG, "not tearing down special network - " +
Robert Greenwalt9c75d4a2009-09-27 17:27:04 -0700750 "others still using it");
751 return 1;
752 }
753 callTeardown = true;
754 }
755 }
Robert Greenwalt78a640a2010-03-10 16:10:43 -0800756 if (DBG) Slog.d(TAG, "Doing network teardown");
Robert Greenwalt9c75d4a2009-09-27 17:27:04 -0700757 if (callTeardown) {
758 tracker.teardown();
Robert Greenwalt42acef32009-08-12 16:08:25 -0700759 return 1;
760 } else {
Robert Greenwalt02648a42010-05-18 10:52:51 -0700761 return -1;
Robert Greenwalt42acef32009-08-12 16:08:25 -0700762 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800763 }
764
765 /**
Robert Greenwalt585ac0f2010-08-27 09:24:29 -0700766 * @deprecated use requestRouteToHostAddress instead
767 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800768 * Ensure that a network route exists to deliver traffic to the specified
769 * host via the specified network interface.
Robert Greenwalt86e9e552009-07-16 17:21:39 -0700770 * @param networkType the type of the network over which traffic to the
771 * specified host is to be routed
772 * @param hostAddress the IP address of the host to which the route is
773 * desired
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800774 * @return {@code true} on success, {@code false} on failure
775 */
776 public boolean requestRouteToHost(int networkType, int hostAddress) {
Robert Greenwalt585ac0f2010-08-27 09:24:29 -0700777 InetAddress inetAddress = NetworkUtils.intToInetAddress(hostAddress);
778
779 if (inetAddress == null) {
780 return false;
781 }
782
783 return requestRouteToHostAddress(networkType, inetAddress.getAddress());
784 }
785
786 /**
787 * Ensure that a network route exists to deliver traffic to the specified
788 * host via the specified network interface.
789 * @param networkType the type of the network over which traffic to the
790 * specified host is to be routed
791 * @param hostAddress the IP address of the host to which the route is
792 * desired
793 * @return {@code true} on success, {@code false} on failure
794 */
795 public boolean requestRouteToHostAddress(int networkType, byte[] hostAddress) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800796 enforceChangePermission();
797 if (!ConnectivityManager.isNetworkTypeValid(networkType)) {
798 return false;
799 }
800 NetworkStateTracker tracker = mNetTrackers[networkType];
Robert Greenwalt8206ff32009-09-10 15:06:20 -0700801
Robert Greenwalt5154ae762009-10-30 14:17:42 -0700802 if (tracker == null || !tracker.getNetworkInfo().isConnected() ||
803 tracker.isTeardownRequested()) {
Robert Greenwalt8206ff32009-09-10 15:06:20 -0700804 if (DBG) {
Robert Greenwalt585ac0f2010-08-27 09:24:29 -0700805 Slog.d(TAG, "requestRouteToHostAddress on down network " +
806 "(" + networkType + ") - dropped");
Robert Greenwalt8206ff32009-09-10 15:06:20 -0700807 }
808 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800809 }
Robert Greenwalt47f69fe2010-06-15 15:43:39 -0700810 try {
Robert Greenwalt585ac0f2010-08-27 09:24:29 -0700811 InetAddress addr = InetAddress.getByAddress(hostAddress);
Robert Greenwalt47f69fe2010-06-15 15:43:39 -0700812 return addHostRoute(tracker, addr);
813 } catch (UnknownHostException e) {}
814 return false;
Irfan Sheriffd649c122010-06-09 15:39:36 -0700815 }
816
817 /**
818 * Ensure that a network route exists to deliver traffic to the specified
819 * host via the mobile data network.
820 * @param hostAddress the IP address of the host to which the route is desired,
821 * in network byte order.
Robert Greenwalt47f69fe2010-06-15 15:43:39 -0700822 * TODO - deprecate
Irfan Sheriffd649c122010-06-09 15:39:36 -0700823 * @return {@code true} on success, {@code false} on failure
824 */
Robert Greenwalt47f69fe2010-06-15 15:43:39 -0700825 private boolean addHostRoute(NetworkStateTracker nt, InetAddress hostAddress) {
Irfan Sheriffd649c122010-06-09 15:39:36 -0700826 if (nt.getNetworkInfo().getType() == ConnectivityManager.TYPE_WIFI) {
827 return false;
828 }
829
Robert Greenwalt37e65eb2010-08-30 10:56:47 -0700830 LinkProperties p = nt.getLinkProperties();
Robert Greenwalt47f69fe2010-06-15 15:43:39 -0700831 if (p == null) return false;
832 String interfaceName = p.getInterfaceName();
Irfan Sheriffd649c122010-06-09 15:39:36 -0700833
834 if (DBG) {
Robert Greenwalt47f69fe2010-06-15 15:43:39 -0700835 Slog.d(TAG, "Requested host route to " + hostAddress + "(" + interfaceName + ")");
Irfan Sheriffd649c122010-06-09 15:39:36 -0700836 }
Robert Greenwalt47f69fe2010-06-15 15:43:39 -0700837 if (interfaceName != null) {
Robert Greenwalt585ac0f2010-08-27 09:24:29 -0700838 return NetworkUtils.addHostRoute(interfaceName, hostAddress, null);
Irfan Sheriffd649c122010-06-09 15:39:36 -0700839 } else {
Robert Greenwalt47f69fe2010-06-15 15:43:39 -0700840 if (DBG) Slog.e(TAG, "addHostRoute failed due to null interface name");
Irfan Sheriffd649c122010-06-09 15:39:36 -0700841 return false;
842 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800843 }
844
845 /**
846 * @see ConnectivityManager#getBackgroundDataSetting()
847 */
848 public boolean getBackgroundDataSetting() {
849 return Settings.Secure.getInt(mContext.getContentResolver(),
850 Settings.Secure.BACKGROUND_DATA, 1) == 1;
851 }
Robert Greenwalt86e9e552009-07-16 17:21:39 -0700852
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800853 /**
854 * @see ConnectivityManager#setBackgroundDataSetting(boolean)
855 */
856 public void setBackgroundDataSetting(boolean allowBackgroundDataUsage) {
857 mContext.enforceCallingOrSelfPermission(
858 android.Manifest.permission.CHANGE_BACKGROUND_DATA_SETTING,
859 "ConnectivityService");
Robert Greenwalt86e9e552009-07-16 17:21:39 -0700860
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800861 if (getBackgroundDataSetting() == allowBackgroundDataUsage) return;
862
863 Settings.Secure.putInt(mContext.getContentResolver(),
Robert Greenwalt86e9e552009-07-16 17:21:39 -0700864 Settings.Secure.BACKGROUND_DATA,
865 allowBackgroundDataUsage ? 1 : 0);
866
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800867 Intent broadcast = new Intent(
868 ConnectivityManager.ACTION_BACKGROUND_DATA_SETTING_CHANGED);
869 mContext.sendBroadcast(broadcast);
Robert Greenwalt86e9e552009-07-16 17:21:39 -0700870 }
871
Robert Greenwaltc03fa502010-02-23 18:58:05 -0800872 /**
873 * @see ConnectivityManager#getMobileDataEnabled()
874 */
875 public boolean getMobileDataEnabled() {
876 enforceAccessPermission();
877 boolean retVal = Settings.Secure.getInt(mContext.getContentResolver(),
878 Settings.Secure.MOBILE_DATA, 1) == 1;
Joe Onorato8a9b2202010-02-26 18:56:32 -0800879 if (DBG) Slog.d(TAG, "getMobileDataEnabled returning " + retVal);
Robert Greenwaltc03fa502010-02-23 18:58:05 -0800880 return retVal;
881 }
882
883 /**
884 * @see ConnectivityManager#setMobileDataEnabled(boolean)
885 */
886 public synchronized void setMobileDataEnabled(boolean enabled) {
887 enforceChangePermission();
Joe Onorato8a9b2202010-02-26 18:56:32 -0800888 if (DBG) Slog.d(TAG, "setMobileDataEnabled(" + enabled + ")");
Robert Greenwaltc03fa502010-02-23 18:58:05 -0800889
890 if (getMobileDataEnabled() == enabled) return;
891
892 Settings.Secure.putInt(mContext.getContentResolver(),
893 Settings.Secure.MOBILE_DATA, enabled ? 1 : 0);
894
895 if (enabled) {
896 if (mNetTrackers[ConnectivityManager.TYPE_MOBILE] != null) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800897 if (DBG) Slog.d(TAG, "starting up " + mNetTrackers[ConnectivityManager.TYPE_MOBILE]);
Robert Greenwaltc03fa502010-02-23 18:58:05 -0800898 mNetTrackers[ConnectivityManager.TYPE_MOBILE].reconnect();
899 }
900 } else {
901 for (NetworkStateTracker nt : mNetTrackers) {
902 if (nt == null) continue;
903 int netType = nt.getNetworkInfo().getType();
904 if (mNetAttributes[netType].mRadio == ConnectivityManager.TYPE_MOBILE) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800905 if (DBG) Slog.d(TAG, "tearing down " + nt);
Robert Greenwaltc03fa502010-02-23 18:58:05 -0800906 nt.teardown();
907 }
908 }
909 }
910 }
911
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800912 private int getNumConnectedNetworks() {
913 int numConnectedNets = 0;
914
915 for (NetworkStateTracker nt : mNetTrackers) {
Robert Greenwalt5154ae762009-10-30 14:17:42 -0700916 if (nt != null && nt.getNetworkInfo().isConnected() &&
Robert Greenwalt86e9e552009-07-16 17:21:39 -0700917 !nt.isTeardownRequested()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800918 ++numConnectedNets;
919 }
920 }
921 return numConnectedNets;
922 }
923
924 private void enforceAccessPermission() {
Robert Greenwalt86e9e552009-07-16 17:21:39 -0700925 mContext.enforceCallingOrSelfPermission(
926 android.Manifest.permission.ACCESS_NETWORK_STATE,
927 "ConnectivityService");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800928 }
929
930 private void enforceChangePermission() {
Robert Greenwalt86e9e552009-07-16 17:21:39 -0700931 mContext.enforceCallingOrSelfPermission(
932 android.Manifest.permission.CHANGE_NETWORK_STATE,
933 "ConnectivityService");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800934 }
935
Robert Greenwaltd0e18ff2010-01-26 11:40:34 -0800936 // TODO Make this a special check when it goes public
937 private void enforceTetherChangePermission() {
938 mContext.enforceCallingOrSelfPermission(
939 android.Manifest.permission.CHANGE_NETWORK_STATE,
940 "ConnectivityService");
941 }
942
Robert Greenwalt2a091d72010-02-11 18:18:40 -0800943 private void enforceTetherAccessPermission() {
944 mContext.enforceCallingOrSelfPermission(
945 android.Manifest.permission.ACCESS_NETWORK_STATE,
946 "ConnectivityService");
947 }
948
Robert Greenwalt14f2ef42010-06-15 12:19:37 -0700949 private void enforceConnectivityInternalPermission() {
950 mContext.enforceCallingOrSelfPermission(
951 android.Manifest.permission.CONNECTIVITY_INTERNAL,
952 "ConnectivityService");
953 }
954
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800955 /**
Robert Greenwalt86e9e552009-07-16 17:21:39 -0700956 * Handle a {@code DISCONNECTED} event. If this pertains to the non-active
957 * network, we ignore it. If it is for the active network, we send out a
958 * broadcast. But first, we check whether it might be possible to connect
959 * to a different network.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800960 * @param info the {@code NetworkInfo} for the network
961 */
962 private void handleDisconnect(NetworkInfo info) {
963
Robert Greenwalt42acef32009-08-12 16:08:25 -0700964 int prevNetType = info.getType();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800965
Robert Greenwalt42acef32009-08-12 16:08:25 -0700966 mNetTrackers[prevNetType].setTeardownRequested(false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800967 /*
968 * If the disconnected network is not the active one, then don't report
969 * this as a loss of connectivity. What probably happened is that we're
970 * getting the disconnect for a network that we explicitly disabled
971 * in accordance with network preference policies.
972 */
Robert Greenwalt42acef32009-08-12 16:08:25 -0700973 if (!mNetAttributes[prevNetType].isDefault()) {
974 List pids = mNetRequestersPids[prevNetType];
975 for (int i = 0; i<pids.size(); i++) {
976 Integer pid = (Integer)pids.get(i);
977 // will remove them because the net's no longer connected
978 // need to do this now as only now do we know the pids and
979 // can properly null things that are no longer referenced.
980 reassessPidDns(pid.intValue(), false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800981 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800982 }
983
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800984 Intent intent = new Intent(ConnectivityManager.CONNECTIVITY_ACTION);
985 intent.putExtra(ConnectivityManager.EXTRA_NETWORK_INFO, info);
986 if (info.isFailover()) {
987 intent.putExtra(ConnectivityManager.EXTRA_IS_FAILOVER, true);
988 info.setFailover(false);
989 }
990 if (info.getReason() != null) {
991 intent.putExtra(ConnectivityManager.EXTRA_REASON, info.getReason());
992 }
993 if (info.getExtraInfo() != null) {
Robert Greenwalt86e9e552009-07-16 17:21:39 -0700994 intent.putExtra(ConnectivityManager.EXTRA_EXTRA_INFO,
995 info.getExtraInfo());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800996 }
Robert Greenwalt42acef32009-08-12 16:08:25 -0700997
Robert Greenwaltcc4b4012010-01-25 17:54:29 -0800998 NetworkStateTracker newNet = null;
999 if (mNetAttributes[prevNetType].isDefault()) {
1000 newNet = tryFailover(prevNetType);
1001 if (newNet != null) {
1002 NetworkInfo switchTo = newNet.getNetworkInfo();
1003 intent.putExtra(ConnectivityManager.EXTRA_OTHER_NETWORK_INFO, switchTo);
1004 } else {
1005 intent.putExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, true);
1006 }
Robert Greenwaltda03c4e2010-01-20 19:29:41 -08001007 }
1008 // do this before we broadcast the change
Robert Greenwaltc76b8fa2010-07-23 15:46:26 -07001009 handleConnectivityChange(prevNetType);
Robert Greenwaltda03c4e2010-01-20 19:29:41 -08001010
1011 sendStickyBroadcast(intent);
1012 /*
1013 * If the failover network is already connected, then immediately send
1014 * out a followup broadcast indicating successful failover
1015 */
1016 if (newNet != null && newNet.getNetworkInfo().isConnected()) {
1017 sendConnectedBroadcast(newNet.getNetworkInfo());
1018 }
1019 }
1020
Robert Greenwaltcc4b4012010-01-25 17:54:29 -08001021 // returns null if no failover available
Robert Greenwaltda03c4e2010-01-20 19:29:41 -08001022 private NetworkStateTracker tryFailover(int prevNetType) {
Robert Greenwalt42acef32009-08-12 16:08:25 -07001023 /*
1024 * If this is a default network, check if other defaults are available
1025 * or active
1026 */
1027 NetworkStateTracker newNet = null;
1028 if (mNetAttributes[prevNetType].isDefault()) {
Robert Greenwalt42acef32009-08-12 16:08:25 -07001029 if (mActiveDefaultNetwork == prevNetType) {
1030 mActiveDefaultNetwork = -1;
1031 }
1032
1033 int newType = -1;
1034 int newPriority = -1;
Robert Greenwalt35429592010-02-25 12:04:29 -08001035 boolean noMobileData = !getMobileDataEnabled();
Robert Greenwaltda03c4e2010-01-20 19:29:41 -08001036 for (int checkType=0; checkType <= ConnectivityManager.MAX_NETWORK_TYPE; checkType++) {
Robert Greenwalt5154ae762009-10-30 14:17:42 -07001037 if (checkType == prevNetType) continue;
1038 if (mNetAttributes[checkType] == null) continue;
Robert Greenwalt35429592010-02-25 12:04:29 -08001039 if (mNetAttributes[checkType].mRadio == ConnectivityManager.TYPE_MOBILE &&
1040 noMobileData) {
1041 if (DBG) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001042 Slog.d(TAG, "not failing over to mobile type " + checkType +
Robert Greenwalt35429592010-02-25 12:04:29 -08001043 " because Mobile Data Disabled");
1044 }
1045 continue;
1046 }
Robert Greenwalt42acef32009-08-12 16:08:25 -07001047 if (mNetAttributes[checkType].isDefault()) {
1048 /* TODO - if we have multiple nets we could use
1049 * we may want to put more thought into which we choose
1050 */
1051 if (checkType == mNetworkPreference) {
1052 newType = checkType;
1053 break;
1054 }
Robert Greenwalt5154ae762009-10-30 14:17:42 -07001055 if (mNetAttributes[checkType].mPriority > newPriority) {
Robert Greenwalt42acef32009-08-12 16:08:25 -07001056 newType = checkType;
Robert Greenwalt5154ae762009-10-30 14:17:42 -07001057 newPriority = mNetAttributes[newType].mPriority;
Robert Greenwalt42acef32009-08-12 16:08:25 -07001058 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001059 }
1060 }
Robert Greenwalt42acef32009-08-12 16:08:25 -07001061
1062 if (newType != -1) {
1063 newNet = mNetTrackers[newType];
1064 /**
1065 * See if the other network is available to fail over to.
1066 * If is not available, we enable it anyway, so that it
1067 * will be able to connect when it does become available,
1068 * but we report a total loss of connectivity rather than
1069 * report that we are attempting to fail over.
1070 */
1071 if (newNet.isAvailable()) {
1072 NetworkInfo switchTo = newNet.getNetworkInfo();
1073 switchTo.setFailover(true);
Robert Greenwalta64bf832009-08-19 20:19:33 -07001074 if (!switchTo.isConnectedOrConnecting() ||
1075 newNet.isTeardownRequested()) {
Robert Greenwalt42acef32009-08-12 16:08:25 -07001076 newNet.reconnect();
1077 }
1078 if (DBG) {
1079 if (switchTo.isConnected()) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001080 Slog.v(TAG, "Switching to already connected " +
Robert Greenwalt42acef32009-08-12 16:08:25 -07001081 switchTo.getTypeName());
1082 } else {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001083 Slog.v(TAG, "Attempting to switch to " +
Robert Greenwalt42acef32009-08-12 16:08:25 -07001084 switchTo.getTypeName());
1085 }
1086 }
Robert Greenwalt42acef32009-08-12 16:08:25 -07001087 } else {
1088 newNet.reconnect();
Robert Greenwaltf0fa39e2010-03-09 14:55:08 -08001089 newNet = null; // not officially avail.. try anyway, but
1090 // report no failover
Robert Greenwalt42acef32009-08-12 16:08:25 -07001091 }
Robert Greenwalt42acef32009-08-12 16:08:25 -07001092 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001093 }
Robert Greenwalt42acef32009-08-12 16:08:25 -07001094
Robert Greenwaltda03c4e2010-01-20 19:29:41 -08001095 return newNet;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001096 }
1097
1098 private void sendConnectedBroadcast(NetworkInfo info) {
1099 Intent intent = new Intent(ConnectivityManager.CONNECTIVITY_ACTION);
1100 intent.putExtra(ConnectivityManager.EXTRA_NETWORK_INFO, info);
1101 if (info.isFailover()) {
1102 intent.putExtra(ConnectivityManager.EXTRA_IS_FAILOVER, true);
1103 info.setFailover(false);
1104 }
1105 if (info.getReason() != null) {
1106 intent.putExtra(ConnectivityManager.EXTRA_REASON, info.getReason());
1107 }
1108 if (info.getExtraInfo() != null) {
Robert Greenwalt86e9e552009-07-16 17:21:39 -07001109 intent.putExtra(ConnectivityManager.EXTRA_EXTRA_INFO,
1110 info.getExtraInfo());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001111 }
Mike Lockwood0f79b542009-08-14 14:18:49 -04001112 sendStickyBroadcast(intent);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001113 }
1114
1115 /**
1116 * Called when an attempt to fail over to another network has failed.
1117 * @param info the {@link NetworkInfo} for the failed network
1118 */
1119 private void handleConnectionFailure(NetworkInfo info) {
1120 mNetTrackers[info.getType()].setTeardownRequested(false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001121
Robert Greenwalt42acef32009-08-12 16:08:25 -07001122 String reason = info.getReason();
1123 String extraInfo = info.getExtraInfo();
Robert Greenwalt86e9e552009-07-16 17:21:39 -07001124
Robert Greenwalt42acef32009-08-12 16:08:25 -07001125 if (DBG) {
1126 String reasonText;
1127 if (reason == null) {
1128 reasonText = ".";
1129 } else {
1130 reasonText = " (" + reason + ").";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001131 }
Joe Onorato8a9b2202010-02-26 18:56:32 -08001132 Slog.v(TAG, "Attempt to connect to " + info.getTypeName() +
Robert Greenwalt42acef32009-08-12 16:08:25 -07001133 " failed" + reasonText);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001134 }
Robert Greenwalt42acef32009-08-12 16:08:25 -07001135
1136 Intent intent = new Intent(ConnectivityManager.CONNECTIVITY_ACTION);
1137 intent.putExtra(ConnectivityManager.EXTRA_NETWORK_INFO, info);
1138 if (getActiveNetworkInfo() == null) {
1139 intent.putExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, true);
1140 }
1141 if (reason != null) {
1142 intent.putExtra(ConnectivityManager.EXTRA_REASON, reason);
1143 }
1144 if (extraInfo != null) {
1145 intent.putExtra(ConnectivityManager.EXTRA_EXTRA_INFO, extraInfo);
1146 }
1147 if (info.isFailover()) {
1148 intent.putExtra(ConnectivityManager.EXTRA_IS_FAILOVER, true);
1149 info.setFailover(false);
1150 }
Robert Greenwaltda03c4e2010-01-20 19:29:41 -08001151
Robert Greenwaltcc4b4012010-01-25 17:54:29 -08001152 NetworkStateTracker newNet = null;
1153 if (mNetAttributes[info.getType()].isDefault()) {
1154 newNet = tryFailover(info.getType());
1155 if (newNet != null) {
1156 NetworkInfo switchTo = newNet.getNetworkInfo();
1157 intent.putExtra(ConnectivityManager.EXTRA_OTHER_NETWORK_INFO, switchTo);
1158 } else {
1159 intent.putExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, true);
1160 }
Robert Greenwaltda03c4e2010-01-20 19:29:41 -08001161 }
Robert Greenwaltcc4b4012010-01-25 17:54:29 -08001162
Mike Lockwood0f79b542009-08-14 14:18:49 -04001163 sendStickyBroadcast(intent);
Robert Greenwaltda03c4e2010-01-20 19:29:41 -08001164 /*
1165 * If the failover network is already connected, then immediately send
1166 * out a followup broadcast indicating successful failover
1167 */
1168 if (newNet != null && newNet.getNetworkInfo().isConnected()) {
1169 sendConnectedBroadcast(newNet.getNetworkInfo());
1170 }
Mike Lockwood0f79b542009-08-14 14:18:49 -04001171 }
1172
1173 private void sendStickyBroadcast(Intent intent) {
1174 synchronized(this) {
Dianne Hackborn1c633fc2009-12-08 19:45:14 -08001175 if (!mSystemReady) {
1176 mInitialBroadcast = new Intent(intent);
Mike Lockwood0f79b542009-08-14 14:18:49 -04001177 }
Dianne Hackborn1c633fc2009-12-08 19:45:14 -08001178 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
1179 mContext.sendStickyBroadcast(intent);
Mike Lockwood0f79b542009-08-14 14:18:49 -04001180 }
1181 }
1182
1183 void systemReady() {
1184 synchronized(this) {
1185 mSystemReady = true;
Dianne Hackborn1c633fc2009-12-08 19:45:14 -08001186 if (mInitialBroadcast != null) {
1187 mContext.sendStickyBroadcast(mInitialBroadcast);
1188 mInitialBroadcast = null;
Mike Lockwood0f79b542009-08-14 14:18:49 -04001189 }
1190 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001191 }
1192
1193 private void handleConnect(NetworkInfo info) {
Robert Greenwalt42acef32009-08-12 16:08:25 -07001194 int type = info.getType();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001195
1196 // snapshot isFailover, because sendConnectedBroadcast() resets it
1197 boolean isFailover = info.isFailover();
Robert Greenwalt42acef32009-08-12 16:08:25 -07001198 NetworkStateTracker thisNet = mNetTrackers[type];
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001199
Robert Greenwalt42acef32009-08-12 16:08:25 -07001200 // if this is a default net and other default is running
1201 // kill the one not preferred
1202 if (mNetAttributes[type].isDefault()) {
Robert Greenwalt42acef32009-08-12 16:08:25 -07001203 if (mActiveDefaultNetwork != -1 && mActiveDefaultNetwork != type) {
1204 if ((type != mNetworkPreference &&
1205 mNetAttributes[mActiveDefaultNetwork].mPriority >
1206 mNetAttributes[type].mPriority) ||
1207 mNetworkPreference == mActiveDefaultNetwork) {
1208 // don't accept this one
Joe Onorato8a9b2202010-02-26 18:56:32 -08001209 if (DBG) Slog.v(TAG, "Not broadcasting CONNECT_ACTION " +
Robert Greenwalt42acef32009-08-12 16:08:25 -07001210 "to torn down network " + info.getTypeName());
1211 teardown(thisNet);
1212 return;
1213 } else {
1214 // tear down the other
1215 NetworkStateTracker otherNet =
1216 mNetTrackers[mActiveDefaultNetwork];
Joe Onorato8a9b2202010-02-26 18:56:32 -08001217 if (DBG) Slog.v(TAG, "Policy requires " +
Robert Greenwalt42acef32009-08-12 16:08:25 -07001218 otherNet.getNetworkInfo().getTypeName() +
1219 " teardown");
1220 if (!teardown(otherNet)) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001221 Slog.e(TAG, "Network declined teardown request");
Robert Greenwalt42acef32009-08-12 16:08:25 -07001222 return;
1223 }
Robert Greenwalt14f2ef42010-06-15 12:19:37 -07001224 }
1225 }
1226 synchronized (ConnectivityService.this) {
1227 // have a new default network, release the transition wakelock in a second
1228 // if it's held. The second pause is to allow apps to reconnect over the
1229 // new network
1230 if (mNetTransitionWakeLock.isHeld()) {
1231 mHandler.sendMessageDelayed(mHandler.obtainMessage(
1232 NetworkStateTracker.EVENT_CLEAR_NET_TRANSITION_WAKELOCK,
1233 mNetTransitionWakeLockSerialNumber, 0),
1234 1000);
Robert Greenwalt42acef32009-08-12 16:08:25 -07001235 }
1236 }
1237 mActiveDefaultNetwork = type;
1238 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001239 thisNet.setTeardownRequested(false);
Irfan Sheriffd649c122010-06-09 15:39:36 -07001240 updateNetworkSettings(thisNet);
Robert Greenwaltc76b8fa2010-07-23 15:46:26 -07001241 handleConnectivityChange(type);
Robert Greenwalt42acef32009-08-12 16:08:25 -07001242 sendConnectedBroadcast(info);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001243 }
1244
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001245 /**
Robert Greenwaltc76b8fa2010-07-23 15:46:26 -07001246 * After a change in the connectivity state of a network. We're mainly
1247 * concerned with making sure that the list of DNS servers is set up
1248 * according to which networks are connected, and ensuring that the
1249 * right routing table entries exist.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001250 */
Robert Greenwaltc76b8fa2010-07-23 15:46:26 -07001251 private void handleConnectivityChange(int netType) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001252 /*
Robert Greenwalt42acef32009-08-12 16:08:25 -07001253 * If a non-default network is enabled, add the host routes that
Robert Greenwaltc76b8fa2010-07-23 15:46:26 -07001254 * will allow it's DNS servers to be accessed.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001255 */
Robert Greenwaltc76b8fa2010-07-23 15:46:26 -07001256 handleDnsConfigurationChange(netType);
Robert Greenwalt42acef32009-08-12 16:08:25 -07001257
Robert Greenwaltc76b8fa2010-07-23 15:46:26 -07001258 if (mNetTrackers[netType].getNetworkInfo().isConnected()) {
1259 if (mNetAttributes[netType].isDefault()) {
1260 addDefaultRoute(mNetTrackers[netType]);
Robert Greenwalt42acef32009-08-12 16:08:25 -07001261 } else {
Robert Greenwaltc76b8fa2010-07-23 15:46:26 -07001262 addPrivateDnsRoutes(mNetTrackers[netType]);
1263 }
1264 } else {
1265 if (mNetAttributes[netType].isDefault()) {
1266 removeDefaultRoute(mNetTrackers[netType]);
1267 } else {
1268 removePrivateDnsRoutes(mNetTrackers[netType]);
Robert Greenwalt42acef32009-08-12 16:08:25 -07001269 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001270 }
1271 }
1272
Irfan Sheriffd649c122010-06-09 15:39:36 -07001273 private void addPrivateDnsRoutes(NetworkStateTracker nt) {
Irfan Sheriffd649c122010-06-09 15:39:36 -07001274 boolean privateDnsRouteSet = nt.isPrivateDnsRouteSet();
Robert Greenwalt37e65eb2010-08-30 10:56:47 -07001275 LinkProperties p = nt.getLinkProperties();
Robert Greenwalt47f69fe2010-06-15 15:43:39 -07001276 if (p == null) return;
1277 String interfaceName = p.getInterfaceName();
Irfan Sheriffd649c122010-06-09 15:39:36 -07001278
1279 if (DBG) {
1280 Slog.d(TAG, "addPrivateDnsRoutes for " + nt +
1281 "(" + interfaceName + ") - mPrivateDnsRouteSet = " + privateDnsRouteSet);
1282 }
Irfan Sheriffd649c122010-06-09 15:39:36 -07001283 if (interfaceName != null && !privateDnsRouteSet) {
Robert Greenwalt47f69fe2010-06-15 15:43:39 -07001284 Collection<InetAddress> dnsList = p.getDnses();
1285 for (InetAddress dns : dnsList) {
1286 if (DBG) Slog.d(TAG, " adding " + dns);
Robert Greenwalt585ac0f2010-08-27 09:24:29 -07001287 NetworkUtils.addHostRoute(interfaceName, dns, null);
Irfan Sheriffd649c122010-06-09 15:39:36 -07001288 }
1289 nt.privateDnsRouteSet(true);
1290 }
1291 }
1292
1293 private void removePrivateDnsRoutes(NetworkStateTracker nt) {
1294 // TODO - we should do this explicitly but the NetUtils api doesnt
1295 // support this yet - must remove all. No worse than before
Robert Greenwalt37e65eb2010-08-30 10:56:47 -07001296 LinkProperties p = nt.getLinkProperties();
Robert Greenwalt47f69fe2010-06-15 15:43:39 -07001297 if (p == null) return;
1298 String interfaceName = p.getInterfaceName();
Irfan Sheriffd649c122010-06-09 15:39:36 -07001299 boolean privateDnsRouteSet = nt.isPrivateDnsRouteSet();
1300 if (interfaceName != null && privateDnsRouteSet) {
1301 if (DBG) {
1302 Slog.d(TAG, "removePrivateDnsRoutes for " + nt.getNetworkInfo().getTypeName() +
1303 " (" + interfaceName + ")");
1304 }
1305 NetworkUtils.removeHostRoutes(interfaceName);
1306 nt.privateDnsRouteSet(false);
1307 }
1308 }
1309
Irfan Sheriffd649c122010-06-09 15:39:36 -07001310
1311 private void addDefaultRoute(NetworkStateTracker nt) {
Robert Greenwalt37e65eb2010-08-30 10:56:47 -07001312 LinkProperties p = nt.getLinkProperties();
Robert Greenwalt47f69fe2010-06-15 15:43:39 -07001313 if (p == null) return;
1314 String interfaceName = p.getInterfaceName();
1315 InetAddress defaultGatewayAddr = p.getGateway();
Irfan Sheriffd649c122010-06-09 15:39:36 -07001316
Robert Greenwaltc76b8fa2010-07-23 15:46:26 -07001317 if ((interfaceName != null) && (defaultGatewayAddr != null )) {
Robert Greenwalt585ac0f2010-08-27 09:24:29 -07001318 if (!NetworkUtils.addDefaultRoute(interfaceName, defaultGatewayAddr) && DBG) {
Robert Greenwalt47f69fe2010-06-15 15:43:39 -07001319 NetworkInfo networkInfo = nt.getNetworkInfo();
Irfan Sheriffd649c122010-06-09 15:39:36 -07001320 Slog.d(TAG, "addDefaultRoute for " + networkInfo.getTypeName() +
1321 " (" + interfaceName + "), GatewayAddr=" + defaultGatewayAddr);
1322 }
Irfan Sheriffd649c122010-06-09 15:39:36 -07001323 }
1324 }
1325
1326
1327 public void removeDefaultRoute(NetworkStateTracker nt) {
Robert Greenwalt37e65eb2010-08-30 10:56:47 -07001328 LinkProperties p = nt.getLinkProperties();
Robert Greenwalt47f69fe2010-06-15 15:43:39 -07001329 if (p == null) return;
1330 String interfaceName = p.getInterfaceName();
Irfan Sheriffd649c122010-06-09 15:39:36 -07001331
Robert Greenwaltc76b8fa2010-07-23 15:46:26 -07001332 if (interfaceName != null) {
1333 if ((NetworkUtils.removeDefaultRoute(interfaceName) >= 0) && DBG) {
Robert Greenwalt47f69fe2010-06-15 15:43:39 -07001334 NetworkInfo networkInfo = nt.getNetworkInfo();
Irfan Sheriffd649c122010-06-09 15:39:36 -07001335 Slog.d(TAG, "removeDefaultRoute for " + networkInfo.getTypeName() + " (" +
1336 interfaceName + ")");
1337 }
Irfan Sheriffd649c122010-06-09 15:39:36 -07001338 }
1339 }
1340
1341 /**
1342 * Reads the network specific TCP buffer sizes from SystemProperties
1343 * net.tcp.buffersize.[default|wifi|umts|edge|gprs] and set them for system
1344 * wide use
1345 */
1346 public void updateNetworkSettings(NetworkStateTracker nt) {
1347 String key = nt.getTcpBufferSizesPropName();
1348 String bufferSizes = SystemProperties.get(key);
1349
1350 if (bufferSizes.length() == 0) {
1351 Slog.e(TAG, key + " not found in system properties. Using defaults");
1352
1353 // Setting to default values so we won't be stuck to previous values
1354 key = "net.tcp.buffersize.default";
1355 bufferSizes = SystemProperties.get(key);
1356 }
1357
1358 // Set values in kernel
1359 if (bufferSizes.length() != 0) {
1360 if (DBG) {
1361 Slog.v(TAG, "Setting TCP values: [" + bufferSizes
1362 + "] which comes from [" + key + "]");
1363 }
1364 setBufferSize(bufferSizes);
1365 }
1366 }
1367
1368 /**
1369 * Writes TCP buffer sizes to /sys/kernel/ipv4/tcp_[r/w]mem_[min/def/max]
1370 * which maps to /proc/sys/net/ipv4/tcp_rmem and tcpwmem
1371 *
1372 * @param bufferSizes in the format of "readMin, readInitial, readMax,
1373 * writeMin, writeInitial, writeMax"
1374 */
1375 private void setBufferSize(String bufferSizes) {
1376 try {
1377 String[] values = bufferSizes.split(",");
1378
1379 if (values.length == 6) {
1380 final String prefix = "/sys/kernel/ipv4/tcp_";
1381 stringToFile(prefix + "rmem_min", values[0]);
1382 stringToFile(prefix + "rmem_def", values[1]);
1383 stringToFile(prefix + "rmem_max", values[2]);
1384 stringToFile(prefix + "wmem_min", values[3]);
1385 stringToFile(prefix + "wmem_def", values[4]);
1386 stringToFile(prefix + "wmem_max", values[5]);
1387 } else {
1388 Slog.e(TAG, "Invalid buffersize string: " + bufferSizes);
1389 }
1390 } catch (IOException e) {
1391 Slog.e(TAG, "Can't set tcp buffer sizes:" + e);
1392 }
1393 }
1394
1395 /**
1396 * Writes string to file. Basically same as "echo -n $string > $filename"
1397 *
1398 * @param filename
1399 * @param string
1400 * @throws IOException
1401 */
1402 private void stringToFile(String filename, String string) throws IOException {
1403 FileWriter out = new FileWriter(filename);
1404 try {
1405 out.write(string);
1406 } finally {
1407 out.close();
1408 }
1409 }
1410
1411
Robert Greenwalt42acef32009-08-12 16:08:25 -07001412 /**
1413 * Adjust the per-process dns entries (net.dns<x>.<pid>) based
1414 * on the highest priority active net which this process requested.
1415 * If there aren't any, clear it out
1416 */
1417 private void reassessPidDns(int myPid, boolean doBump)
1418 {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001419 if (DBG) Slog.d(TAG, "reassessPidDns for pid " + myPid);
Robert Greenwalt42acef32009-08-12 16:08:25 -07001420 for(int i : mPriorityList) {
1421 if (mNetAttributes[i].isDefault()) {
1422 continue;
1423 }
1424 NetworkStateTracker nt = mNetTrackers[i];
Robert Greenwalt86e9e552009-07-16 17:21:39 -07001425 if (nt.getNetworkInfo().isConnected() &&
1426 !nt.isTeardownRequested()) {
Robert Greenwalt37e65eb2010-08-30 10:56:47 -07001427 LinkProperties p = nt.getLinkProperties();
Robert Greenwalt47f69fe2010-06-15 15:43:39 -07001428 if (p == null) continue;
Robert Greenwalt42acef32009-08-12 16:08:25 -07001429 List pids = mNetRequestersPids[i];
1430 for (int j=0; j<pids.size(); j++) {
1431 Integer pid = (Integer)pids.get(j);
1432 if (pid.intValue() == myPid) {
Robert Greenwalt47f69fe2010-06-15 15:43:39 -07001433 Collection<InetAddress> dnses = p.getDnses();
1434 writePidDns(dnses, myPid);
Robert Greenwalt42acef32009-08-12 16:08:25 -07001435 if (doBump) {
1436 bumpDns();
1437 }
1438 return;
1439 }
1440 }
1441 }
1442 }
1443 // nothing found - delete
1444 for (int i = 1; ; i++) {
1445 String prop = "net.dns" + i + "." + myPid;
1446 if (SystemProperties.get(prop).length() == 0) {
1447 if (doBump) {
1448 bumpDns();
1449 }
1450 return;
1451 }
1452 SystemProperties.set(prop, "");
1453 }
1454 }
1455
Robert Greenwalt47f69fe2010-06-15 15:43:39 -07001456 private void writePidDns(Collection <InetAddress> dnses, int pid) {
Robert Greenwalt42acef32009-08-12 16:08:25 -07001457 int j = 1;
Robert Greenwalt47f69fe2010-06-15 15:43:39 -07001458 for (InetAddress dns : dnses) {
1459 SystemProperties.set("net.dns" + j++ + "." + pid, dns.getHostAddress());
Robert Greenwalt42acef32009-08-12 16:08:25 -07001460 }
1461 }
1462
1463 private void bumpDns() {
1464 /*
1465 * Bump the property that tells the name resolver library to reread
1466 * the DNS server list from the properties.
1467 */
1468 String propVal = SystemProperties.get("net.dnschange");
1469 int n = 0;
1470 if (propVal.length() != 0) {
1471 try {
1472 n = Integer.parseInt(propVal);
1473 } catch (NumberFormatException e) {}
1474 }
1475 SystemProperties.set("net.dnschange", "" + (n+1));
1476 }
1477
Robert Greenwaltc76b8fa2010-07-23 15:46:26 -07001478 private void handleDnsConfigurationChange(int netType) {
Robert Greenwalt42acef32009-08-12 16:08:25 -07001479 // add default net's dns entries
Robert Greenwaltc76b8fa2010-07-23 15:46:26 -07001480 NetworkStateTracker nt = mNetTrackers[netType];
1481 if (nt != null && nt.getNetworkInfo().isConnected() && !nt.isTeardownRequested()) {
Robert Greenwalt37e65eb2010-08-30 10:56:47 -07001482 LinkProperties p = nt.getLinkProperties();
Robert Greenwaltc76b8fa2010-07-23 15:46:26 -07001483 if (p == null) return;
1484 Collection<InetAddress> dnses = p.getDnses();
1485 if (mNetAttributes[netType].isDefault()) {
1486 int j = 1;
Robert Greenwalte90aa5e2010-09-01 11:34:05 -07001487 if (dnses.size() == 0 && mDefaultDns != null) {
Robert Greenwaltc76b8fa2010-07-23 15:46:26 -07001488 if (DBG) {
Robert Greenwalte90aa5e2010-09-01 11:34:05 -07001489 Slog.d(TAG, "no dns provided - using " + mDefaultDns.getHostAddress());
Robert Greenwalt42acef32009-08-12 16:08:25 -07001490 }
Robert Greenwalte90aa5e2010-09-01 11:34:05 -07001491 SystemProperties.set("net.dns1", mDefaultDns.getHostAddress());
1492 j++;
1493 } else {
1494 for (InetAddress dns : dnses) {
1495 if (DBG) {
1496 Slog.d(TAG, "adding dns " + dns + " for " +
1497 nt.getNetworkInfo().getTypeName());
1498 }
1499 SystemProperties.set("net.dns" + j++, dns.getHostAddress());
1500 }
Robert Greenwaltc76b8fa2010-07-23 15:46:26 -07001501 }
1502 for (int k=j ; k<mNumDnsEntries; k++) {
1503 if (DBG) Slog.d(TAG, "erasing net.dns" + k);
1504 SystemProperties.set("net.dns" + k, "");
1505 }
1506 mNumDnsEntries = j;
1507 } else {
1508 // set per-pid dns for attached secondary nets
1509 List pids = mNetRequestersPids[netType];
1510 for (int y=0; y< pids.size(); y++) {
1511 Integer pid = (Integer)pids.get(y);
1512 writePidDns(dnses, pid.intValue());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001513 }
1514 }
Robert Greenwaltc76b8fa2010-07-23 15:46:26 -07001515 bumpDns();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001516 }
Robert Greenwalt42acef32009-08-12 16:08:25 -07001517 }
1518
1519 private int getRestoreDefaultNetworkDelay() {
1520 String restoreDefaultNetworkDelayStr = SystemProperties.get(
1521 NETWORK_RESTORE_DELAY_PROP_NAME);
1522 if(restoreDefaultNetworkDelayStr != null &&
1523 restoreDefaultNetworkDelayStr.length() != 0) {
1524 try {
1525 return Integer.valueOf(restoreDefaultNetworkDelayStr);
1526 } catch (NumberFormatException e) {
1527 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001528 }
Robert Greenwalt42acef32009-08-12 16:08:25 -07001529 return RESTORE_DEFAULT_NETWORK_DELAY;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001530 }
1531
1532 @Override
1533 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
Robert Greenwalt86e9e552009-07-16 17:21:39 -07001534 if (mContext.checkCallingOrSelfPermission(
1535 android.Manifest.permission.DUMP)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001536 != PackageManager.PERMISSION_GRANTED) {
Robert Greenwalt86e9e552009-07-16 17:21:39 -07001537 pw.println("Permission Denial: can't dump ConnectivityService " +
1538 "from from pid=" + Binder.getCallingPid() + ", uid=" +
1539 Binder.getCallingUid());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001540 return;
1541 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001542 pw.println();
1543 for (NetworkStateTracker nst : mNetTrackers) {
Robert Greenwaltb9285352009-12-21 18:24:07 -08001544 if (nst != null) {
1545 if (nst.getNetworkInfo().isConnected()) {
1546 pw.println("Active network: " + nst.getNetworkInfo().
1547 getTypeName());
1548 }
1549 pw.println(nst.getNetworkInfo());
1550 pw.println(nst);
1551 pw.println();
Robert Greenwalt42acef32009-08-12 16:08:25 -07001552 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001553 }
Robert Greenwaltb9285352009-12-21 18:24:07 -08001554
1555 pw.println("Network Requester Pids:");
1556 for (int net : mPriorityList) {
1557 String pidString = net + ": ";
1558 for (Object pid : mNetRequestersPids[net]) {
1559 pidString = pidString + pid.toString() + ", ";
1560 }
1561 pw.println(pidString);
1562 }
1563 pw.println();
1564
1565 pw.println("FeatureUsers:");
1566 for (Object requester : mFeatureUsers) {
1567 pw.println(requester.toString());
1568 }
1569 pw.println();
Robert Greenwalt2a091d72010-02-11 18:18:40 -08001570
Robert Greenwalt14f2ef42010-06-15 12:19:37 -07001571 synchronized (this) {
1572 pw.println("NetworkTranstionWakeLock is currently " +
1573 (mNetTransitionWakeLock.isHeld() ? "" : "not ") + "held.");
1574 pw.println("It was last requested for "+mNetTransitionWakeLockCausedBy);
1575 }
1576 pw.println();
1577
Robert Greenwalt2a091d72010-02-11 18:18:40 -08001578 mTethering.dump(fd, pw, args);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001579 }
1580
Robert Greenwalt42acef32009-08-12 16:08:25 -07001581 // must be stateless - things change under us.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001582 private class MyHandler extends Handler {
1583 @Override
1584 public void handleMessage(Message msg) {
1585 NetworkInfo info;
1586 switch (msg.what) {
1587 case NetworkStateTracker.EVENT_STATE_CHANGED:
1588 info = (NetworkInfo) msg.obj;
Robert Greenwalt511288a2009-12-07 11:33:18 -08001589 int type = info.getType();
1590 NetworkInfo.State state = info.getState();
Robert Greenwalt6e6dec22010-01-25 16:14:00 -08001591 // only do this optimization for wifi. It going into scan mode for location
1592 // services generates alot of noise. Meanwhile the mms apn won't send out
1593 // subsequent notifications when on default cellular because it never
1594 // disconnects.. so only do this to wifi notifications. Fixed better when the
1595 // APN notifications are standardized.
1596 if (mNetAttributes[type].mLastState == state &&
1597 mNetAttributes[type].mRadio == ConnectivityManager.TYPE_WIFI) {
Robert Greenwalt511288a2009-12-07 11:33:18 -08001598 if (DBG) {
Robert Greenwalt6e6dec22010-01-25 16:14:00 -08001599 // TODO - remove this after we validate the dropping doesn't break
1600 // anything
Joe Onorato8a9b2202010-02-26 18:56:32 -08001601 Slog.d(TAG, "Dropping ConnectivityChange for " +
Robert Greenwalt1193ae42010-01-13 09:36:31 -08001602 info.getTypeName() + ": " +
Robert Greenwalt511288a2009-12-07 11:33:18 -08001603 state + "/" + info.getDetailedState());
1604 }
1605 return;
1606 }
1607 mNetAttributes[type].mLastState = state;
1608
Joe Onorato8a9b2202010-02-26 18:56:32 -08001609 if (DBG) Slog.d(TAG, "ConnectivityChange for " +
Robert Greenwalt86e9e552009-07-16 17:21:39 -07001610 info.getTypeName() + ": " +
Robert Greenwalt511288a2009-12-07 11:33:18 -08001611 state + "/" + info.getDetailedState());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001612
1613 // Connectivity state changed:
1614 // [31-13] Reserved for future use
Robert Greenwalt86e9e552009-07-16 17:21:39 -07001615 // [12-9] Network subtype (for mobile network, as defined
1616 // by TelephonyManager)
1617 // [8-3] Detailed state ordinal (as defined by
1618 // NetworkInfo.DetailedState)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001619 // [2-0] Network type (as defined by ConnectivityManager)
1620 int eventLogParam = (info.getType() & 0x7) |
1621 ((info.getDetailedState().ordinal() & 0x3f) << 3) |
1622 (info.getSubtype() << 9);
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001623 EventLog.writeEvent(EventLogTags.CONNECTIVITY_STATE_CHANGED,
Robert Greenwalt86e9e552009-07-16 17:21:39 -07001624 eventLogParam);
1625
1626 if (info.getDetailedState() ==
1627 NetworkInfo.DetailedState.FAILED) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001628 handleConnectionFailure(info);
Robert Greenwalt511288a2009-12-07 11:33:18 -08001629 } else if (state == NetworkInfo.State.DISCONNECTED) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001630 handleDisconnect(info);
Robert Greenwalt511288a2009-12-07 11:33:18 -08001631 } else if (state == NetworkInfo.State.SUSPENDED) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001632 // TODO: need to think this over.
Robert Greenwalt86e9e552009-07-16 17:21:39 -07001633 // the logic here is, handle SUSPENDED the same as
1634 // DISCONNECTED. The only difference being we are
1635 // broadcasting an intent with NetworkInfo that's
1636 // suspended. This allows the applications an
1637 // opportunity to handle DISCONNECTED and SUSPENDED
1638 // differently, or not.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001639 handleDisconnect(info);
Robert Greenwalt511288a2009-12-07 11:33:18 -08001640 } else if (state == NetworkInfo.State.CONNECTED) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001641 handleConnect(info);
1642 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001643 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001644 case NetworkStateTracker.EVENT_CONFIGURATION_CHANGED:
Robert Greenwaltc76b8fa2010-07-23 15:46:26 -07001645 // TODO - make this handle ip/proxy/gateway/dns changes
1646 info = (NetworkInfo) msg.obj;
1647 type = info.getType();
1648 handleDnsConfigurationChange(type);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001649 break;
Robert Greenwalt42acef32009-08-12 16:08:25 -07001650 case NetworkStateTracker.EVENT_RESTORE_DEFAULT_NETWORK:
Robert Greenwalt9c75d4a2009-09-27 17:27:04 -07001651 FeatureUser u = (FeatureUser)msg.obj;
1652 u.expire();
Robert Greenwalt42acef32009-08-12 16:08:25 -07001653 break;
Robert Greenwalt14f2ef42010-06-15 12:19:37 -07001654 case NetworkStateTracker.EVENT_CLEAR_NET_TRANSITION_WAKELOCK:
1655 String causedBy = null;
1656 synchronized (ConnectivityService.this) {
1657 if (msg.arg1 == mNetTransitionWakeLockSerialNumber &&
1658 mNetTransitionWakeLock.isHeld()) {
1659 mNetTransitionWakeLock.release();
1660 causedBy = mNetTransitionWakeLockCausedBy;
1661 }
1662 }
1663 if (causedBy != null) {
1664 Slog.d(TAG, "NetTransition Wakelock for " +
1665 causedBy + " released by timeout");
1666 }
1667 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001668 }
1669 }
1670 }
Robert Greenwaltd0e18ff2010-01-26 11:40:34 -08001671
1672 // javadoc from interface
Robert Greenwalt5a735062010-03-02 17:25:02 -08001673 public int tether(String iface) {
Robert Greenwaltd0e18ff2010-01-26 11:40:34 -08001674 enforceTetherChangePermission();
Robert Greenwalt5a735062010-03-02 17:25:02 -08001675
1676 if (isTetheringSupported()) {
1677 return mTethering.tether(iface);
1678 } else {
1679 return ConnectivityManager.TETHER_ERROR_UNSUPPORTED;
1680 }
Robert Greenwaltd0e18ff2010-01-26 11:40:34 -08001681 }
1682
1683 // javadoc from interface
Robert Greenwalt5a735062010-03-02 17:25:02 -08001684 public int untether(String iface) {
Robert Greenwaltd0e18ff2010-01-26 11:40:34 -08001685 enforceTetherChangePermission();
Robert Greenwalt5a735062010-03-02 17:25:02 -08001686
1687 if (isTetheringSupported()) {
1688 return mTethering.untether(iface);
1689 } else {
1690 return ConnectivityManager.TETHER_ERROR_UNSUPPORTED;
1691 }
1692 }
1693
1694 // javadoc from interface
1695 public int getLastTetherError(String iface) {
1696 enforceTetherAccessPermission();
1697
1698 if (isTetheringSupported()) {
1699 return mTethering.getLastTetherError(iface);
1700 } else {
1701 return ConnectivityManager.TETHER_ERROR_UNSUPPORTED;
1702 }
Robert Greenwalt2a091d72010-02-11 18:18:40 -08001703 }
1704
1705 // TODO - proper iface API for selection by property, inspection, etc
1706 public String[] getTetherableUsbRegexs() {
1707 enforceTetherAccessPermission();
1708 if (isTetheringSupported()) {
1709 return mTethering.getTetherableUsbRegexs();
1710 } else {
1711 return new String[0];
1712 }
1713 }
1714
1715 public String[] getTetherableWifiRegexs() {
1716 enforceTetherAccessPermission();
1717 if (isTetheringSupported()) {
1718 return mTethering.getTetherableWifiRegexs();
1719 } else {
1720 return new String[0];
1721 }
Robert Greenwaltd0e18ff2010-01-26 11:40:34 -08001722 }
1723
Danica Chang6fdd0c62010-08-11 14:54:43 -07001724 public String[] getTetherableBluetoothRegexs() {
1725 enforceTetherAccessPermission();
1726 if (isTetheringSupported()) {
1727 return mTethering.getTetherableBluetoothRegexs();
1728 } else {
1729 return new String[0];
1730 }
1731 }
1732
Robert Greenwaltd0e18ff2010-01-26 11:40:34 -08001733 // TODO - move iface listing, queries, etc to new module
1734 // javadoc from interface
1735 public String[] getTetherableIfaces() {
Robert Greenwalt2a091d72010-02-11 18:18:40 -08001736 enforceTetherAccessPermission();
Robert Greenwaltd0e18ff2010-01-26 11:40:34 -08001737 return mTethering.getTetherableIfaces();
1738 }
1739
1740 public String[] getTetheredIfaces() {
Robert Greenwalt2a091d72010-02-11 18:18:40 -08001741 enforceTetherAccessPermission();
Robert Greenwaltd0e18ff2010-01-26 11:40:34 -08001742 return mTethering.getTetheredIfaces();
1743 }
Robert Greenwalt2a091d72010-02-11 18:18:40 -08001744
Robert Greenwalt5a735062010-03-02 17:25:02 -08001745 public String[] getTetheringErroredIfaces() {
1746 enforceTetherAccessPermission();
1747 return mTethering.getErroredIfaces();
1748 }
1749
Robert Greenwalt2a091d72010-02-11 18:18:40 -08001750 // if ro.tether.denied = true we default to no tethering
1751 // gservices could set the secure setting to 1 though to enable it on a build where it
1752 // had previously been turned off.
1753 public boolean isTetheringSupported() {
1754 enforceTetherAccessPermission();
1755 int defaultVal = (SystemProperties.get("ro.tether.denied").equals("true") ? 0 : 1);
Robert Greenwaltc9d5fb72010-02-25 12:29:30 -08001756 boolean tetherEnabledInSettings = (Settings.Secure.getInt(mContext.getContentResolver(),
1757 Settings.Secure.TETHER_SUPPORTED, defaultVal) != 0);
1758 return tetherEnabledInSettings && mTetheringConfigValid;
Robert Greenwalt2a091d72010-02-11 18:18:40 -08001759 }
Robert Greenwalt14f2ef42010-06-15 12:19:37 -07001760
1761 // An API NetworkStateTrackers can call when they lose their network.
1762 // This will automatically be cleared after X seconds or a network becomes CONNECTED,
1763 // whichever happens first. The timer is started by the first caller and not
1764 // restarted by subsequent callers.
1765 public void requestNetworkTransitionWakelock(String forWhom) {
1766 enforceConnectivityInternalPermission();
1767 synchronized (this) {
1768 if (mNetTransitionWakeLock.isHeld()) return;
1769 mNetTransitionWakeLockSerialNumber++;
1770 mNetTransitionWakeLock.acquire();
1771 mNetTransitionWakeLockCausedBy = forWhom;
1772 }
1773 mHandler.sendMessageDelayed(mHandler.obtainMessage(
1774 NetworkStateTracker.EVENT_CLEAR_NET_TRANSITION_WAKELOCK,
1775 mNetTransitionWakeLockSerialNumber, 0),
1776 mNetTransitionWakeLockTimeout);
1777 return;
1778 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001779}