blob: aae3cffdc8ade05e5d85ddb4b1fa9685e05a8918 [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;
Wink Savillebb08caf2010-09-02 19:23:52 -070036import android.os.HandlerThread;
Robert Greenwalt42acef32009-08-12 16:08:25 -070037import android.os.IBinder;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080038import android.os.Looper;
39import android.os.Message;
Robert Greenwalt14f2ef42010-06-15 12:19:37 -070040import android.os.PowerManager;
Robert Greenwalt42acef32009-08-12 16:08:25 -070041import android.os.RemoteException;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080042import android.os.ServiceManager;
43import android.os.SystemProperties;
44import android.provider.Settings;
Robert Greenwalt42acef32009-08-12 16:08:25 -070045import android.text.TextUtils;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080046import android.util.EventLog;
Joe Onorato8a9b2202010-02-26 18:56:32 -080047import android.util.Slog;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080048
Robert Greenwalt42acef32009-08-12 16:08:25 -070049import com.android.internal.telephony.Phone;
50
Robert Greenwaltd0e18ff2010-01-26 11:40:34 -080051import com.android.server.connectivity.Tethering;
52
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080053import java.io.FileDescriptor;
Irfan Sheriffd649c122010-06-09 15:39:36 -070054import java.io.FileWriter;
55import java.io.IOException;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080056import java.io.PrintWriter;
Robert Greenwalt47f69fe2010-06-15 15:43:39 -070057import java.net.InetAddress;
58import java.net.UnknownHostException;
Robert Greenwalt42acef32009-08-12 16:08:25 -070059import java.util.ArrayList;
Robert Greenwalt47f69fe2010-06-15 15:43:39 -070060import java.util.Collection;
Robert Greenwalt4e8dfef2010-09-20 14:35:25 -070061import java.util.GregorianCalendar;
Robert Greenwalt42acef32009-08-12 16:08:25 -070062import java.util.List;
Robert Greenwalt585ac0f2010-08-27 09:24:29 -070063import java.net.InetAddress;
64import java.net.UnknownHostException;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080065
66/**
67 * @hide
68 */
69public class ConnectivityService extends IConnectivityManager.Stub {
70
Robert Greenwaltd8df1492009-10-06 14:12:53 -070071 private static final boolean DBG = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080072 private static final String TAG = "ConnectivityService";
73
Robert Greenwalt42acef32009-08-12 16:08:25 -070074 // how long to wait before switching back to a radio's default network
75 private static final int RESTORE_DEFAULT_NETWORK_DELAY = 1 * 60 * 1000;
76 // system property that can override the above value
77 private static final String NETWORK_RESTORE_DELAY_PROP_NAME =
78 "android.telephony.apn-restore";
79
Robert Greenwaltd0e18ff2010-01-26 11:40:34 -080080 private Tethering mTethering;
Robert Greenwaltc9d5fb72010-02-25 12:29:30 -080081 private boolean mTetheringConfigValid = false;
Robert Greenwaltd0e18ff2010-01-26 11:40:34 -080082
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080083 /**
84 * Sometimes we want to refer to the individual network state
85 * trackers separately, and sometimes we just want to treat them
86 * abstractly.
87 */
88 private NetworkStateTracker mNetTrackers[];
Robert Greenwalt42acef32009-08-12 16:08:25 -070089
90 /**
91 * A per Net list of the PID's that requested access to the net
92 * used both as a refcount and for per-PID DNS selection
93 */
94 private List mNetRequestersPids[];
95
Irfan Sheriffa2a1b912010-06-07 09:03:04 -070096 private WifiWatchdogService mWifiWatchdogService;
97
Robert Greenwalt42acef32009-08-12 16:08:25 -070098 // priority order of the nettrackers
99 // (excluding dynamically set mNetworkPreference)
100 // TODO - move mNetworkTypePreference into this
101 private int[] mPriorityList;
102
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800103 private Context mContext;
104 private int mNetworkPreference;
Robert Greenwalt42acef32009-08-12 16:08:25 -0700105 private int mActiveDefaultNetwork = -1;
Robert Greenwaltd7085fc2010-09-08 15:24:47 -0700106 // 0 is full bad, 100 is full good
107 private int mDefaultInetCondition = 0;
108 private int mDefaultInetConditionPublished = 0;
109 private boolean mInetConditionChangeInFlight = false;
110 private int mDefaultConnectionSequence = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800111
112 private int mNumDnsEntries;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800113
114 private boolean mTestMode;
Joe Onorato00092872010-09-01 21:18:22 -0700115 private static ConnectivityService sServiceInstance;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800116
Robert Greenwalt42acef32009-08-12 16:08:25 -0700117 private Handler mHandler;
118
119 // list of DeathRecipients used to make sure features are turned off when
120 // a process dies
121 private List mFeatureUsers;
122
Mike Lockwood0f79b542009-08-14 14:18:49 -0400123 private boolean mSystemReady;
Dianne Hackborn1c633fc2009-12-08 19:45:14 -0800124 private Intent mInitialBroadcast;
Mike Lockwood0f79b542009-08-14 14:18:49 -0400125
Robert Greenwalt14f2ef42010-06-15 12:19:37 -0700126 private PowerManager.WakeLock mNetTransitionWakeLock;
127 private String mNetTransitionWakeLockCausedBy = "";
128 private int mNetTransitionWakeLockSerialNumber;
129 private int mNetTransitionWakeLockTimeout;
130
Robert Greenwalte90aa5e2010-09-01 11:34:05 -0700131 private InetAddress mDefaultDns;
132
Robert Greenwalt4e8dfef2010-09-20 14:35:25 -0700133 // used in DBG mode to track inet condition reports
134 private static final int INET_CONDITION_LOG_MAX_SIZE = 15;
135 private ArrayList mInetLog;
136
Robert Greenwalt511288a2009-12-07 11:33:18 -0800137 private static class NetworkAttributes {
Robert Greenwalt42acef32009-08-12 16:08:25 -0700138 /**
139 * Class for holding settings read from resources.
140 */
141 public String mName;
142 public int mType;
143 public int mRadio;
144 public int mPriority;
Robert Greenwalt511288a2009-12-07 11:33:18 -0800145 public NetworkInfo.State mLastState;
Robert Greenwalt42acef32009-08-12 16:08:25 -0700146 public NetworkAttributes(String init) {
147 String fragments[] = init.split(",");
148 mName = fragments[0].toLowerCase();
Robert Greenwalt5154ae762009-10-30 14:17:42 -0700149 mType = Integer.parseInt(fragments[1]);
150 mRadio = Integer.parseInt(fragments[2]);
151 mPriority = Integer.parseInt(fragments[3]);
Robert Greenwalt511288a2009-12-07 11:33:18 -0800152 mLastState = NetworkInfo.State.UNKNOWN;
Robert Greenwalt42acef32009-08-12 16:08:25 -0700153 }
154 public boolean isDefault() {
155 return (mType == mRadio);
156 }
157 }
158 NetworkAttributes[] mNetAttributes;
Robert Greenwalt5154ae762009-10-30 14:17:42 -0700159 int mNetworksDefined;
Robert Greenwalt42acef32009-08-12 16:08:25 -0700160
Robert Greenwalt511288a2009-12-07 11:33:18 -0800161 private static class RadioAttributes {
Robert Greenwalt42acef32009-08-12 16:08:25 -0700162 public int mSimultaneity;
163 public int mType;
164 public RadioAttributes(String init) {
165 String fragments[] = init.split(",");
Robert Greenwalt5154ae762009-10-30 14:17:42 -0700166 mType = Integer.parseInt(fragments[0]);
167 mSimultaneity = Integer.parseInt(fragments[1]);
Robert Greenwalt42acef32009-08-12 16:08:25 -0700168 }
169 }
170 RadioAttributes[] mRadioAttributes;
171
Wink Savillebb08caf2010-09-02 19:23:52 -0700172 public static synchronized ConnectivityService getInstance(Context context) {
173 if (sServiceInstance == null) {
174 sServiceInstance = new ConnectivityService(context);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800175 }
Wink Savillebb08caf2010-09-02 19:23:52 -0700176 return sServiceInstance;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800177 }
Robert Greenwalt86e9e552009-07-16 17:21:39 -0700178
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800179 private ConnectivityService(Context context) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800180 if (DBG) Slog.v(TAG, "ConnectivityService starting up");
Robert Greenwaltde8383c2010-01-14 17:47:58 -0800181
Wink Savillebb08caf2010-09-02 19:23:52 -0700182 HandlerThread handlerThread = new HandlerThread("ConnectivityServiceThread");
183 handlerThread.start();
184 mHandler = new MyHandler(handlerThread.getLooper());
185
Robert Greenwaltde8383c2010-01-14 17:47:58 -0800186 // setup our unique device name
187 String id = Settings.Secure.getString(context.getContentResolver(),
188 Settings.Secure.ANDROID_ID);
189 if (id != null && id.length() > 0) {
190 String name = new String("android_").concat(id);
191 SystemProperties.set("net.hostname", name);
192 }
193
Robert Greenwalte90aa5e2010-09-01 11:34:05 -0700194 // read our default dns server ip
195 String dns = Settings.Secure.getString(context.getContentResolver(),
196 Settings.Secure.DEFAULT_DNS_SERVER);
197 if (dns == null || dns.length() == 0) {
198 dns = context.getResources().getString(
199 com.android.internal.R.string.config_default_dns_server);
200 }
201 try {
202 mDefaultDns = InetAddress.getByName(dns);
203 } catch (UnknownHostException e) {
204 Slog.e(TAG, "Error setting defaultDns using " + dns);
205 }
206
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800207 mContext = context;
Robert Greenwalt14f2ef42010-06-15 12:19:37 -0700208
209 PowerManager powerManager = (PowerManager)mContext.getSystemService(Context.POWER_SERVICE);
210 mNetTransitionWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
211 mNetTransitionWakeLockTimeout = mContext.getResources().getInteger(
212 com.android.internal.R.integer.config_networkTransitionTimeout);
213
Robert Greenwalt42acef32009-08-12 16:08:25 -0700214 mNetTrackers = new NetworkStateTracker[
215 ConnectivityManager.MAX_NETWORK_TYPE+1];
Robert Greenwalt86e9e552009-07-16 17:21:39 -0700216
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800217 mNetworkPreference = getPersistedNetworkPreference();
Robert Greenwalt86e9e552009-07-16 17:21:39 -0700218
Robert Greenwalt5154ae762009-10-30 14:17:42 -0700219 mRadioAttributes = new RadioAttributes[ConnectivityManager.MAX_RADIO_TYPE+1];
220 mNetAttributes = new NetworkAttributes[ConnectivityManager.MAX_NETWORK_TYPE+1];
221
Robert Greenwalt42acef32009-08-12 16:08:25 -0700222 // Load device network attributes from resources
Robert Greenwalt42acef32009-08-12 16:08:25 -0700223 String[] raStrings = context.getResources().getStringArray(
224 com.android.internal.R.array.radioAttributes);
Robert Greenwalt5154ae762009-10-30 14:17:42 -0700225 for (String raString : raStrings) {
226 RadioAttributes r = new RadioAttributes(raString);
227 if (r.mType > ConnectivityManager.MAX_RADIO_TYPE) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800228 Slog.e(TAG, "Error in radioAttributes - ignoring attempt to define type " + r.mType);
Robert Greenwalt5154ae762009-10-30 14:17:42 -0700229 continue;
230 }
231 if (mRadioAttributes[r.mType] != null) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800232 Slog.e(TAG, "Error in radioAttributes - ignoring attempt to redefine type " +
Robert Greenwalt5154ae762009-10-30 14:17:42 -0700233 r.mType);
234 continue;
235 }
Robert Greenwalt42acef32009-08-12 16:08:25 -0700236 mRadioAttributes[r.mType] = r;
237 }
238
Robert Greenwalt5154ae762009-10-30 14:17:42 -0700239 String[] naStrings = context.getResources().getStringArray(
240 com.android.internal.R.array.networkAttributes);
241 for (String naString : naStrings) {
242 try {
243 NetworkAttributes n = new NetworkAttributes(naString);
244 if (n.mType > ConnectivityManager.MAX_NETWORK_TYPE) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800245 Slog.e(TAG, "Error in networkAttributes - ignoring attempt to define type " +
Robert Greenwalt5154ae762009-10-30 14:17:42 -0700246 n.mType);
247 continue;
Robert Greenwalt42acef32009-08-12 16:08:25 -0700248 }
Robert Greenwalt5154ae762009-10-30 14:17:42 -0700249 if (mNetAttributes[n.mType] != null) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800250 Slog.e(TAG, "Error in networkAttributes - ignoring attempt to redefine type " +
Robert Greenwalt5154ae762009-10-30 14:17:42 -0700251 n.mType);
252 continue;
253 }
254 if (mRadioAttributes[n.mRadio] == null) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800255 Slog.e(TAG, "Error in networkAttributes - ignoring attempt to use undefined " +
Robert Greenwalt5154ae762009-10-30 14:17:42 -0700256 "radio " + n.mRadio + " in network type " + n.mType);
257 continue;
258 }
259 mNetAttributes[n.mType] = n;
260 mNetworksDefined++;
261 } catch(Exception e) {
262 // ignore it - leave the entry null
Robert Greenwalt42acef32009-08-12 16:08:25 -0700263 }
264 }
265
Robert Greenwalt5154ae762009-10-30 14:17:42 -0700266 // high priority first
267 mPriorityList = new int[mNetworksDefined];
268 {
269 int insertionPoint = mNetworksDefined-1;
270 int currentLowest = 0;
271 int nextLowest = 0;
272 while (insertionPoint > -1) {
273 for (NetworkAttributes na : mNetAttributes) {
274 if (na == null) continue;
275 if (na.mPriority < currentLowest) continue;
276 if (na.mPriority > currentLowest) {
277 if (na.mPriority < nextLowest || nextLowest == 0) {
278 nextLowest = na.mPriority;
279 }
280 continue;
281 }
282 mPriorityList[insertionPoint--] = na.mType;
283 }
284 currentLowest = nextLowest;
285 nextLowest = 0;
286 }
287 }
288
289 mNetRequestersPids = new ArrayList[ConnectivityManager.MAX_NETWORK_TYPE+1];
290 for (int i : mPriorityList) {
Robert Greenwalt42acef32009-08-12 16:08:25 -0700291 mNetRequestersPids[i] = new ArrayList();
292 }
293
294 mFeatureUsers = new ArrayList();
295
Robert Greenwalt5154ae762009-10-30 14:17:42 -0700296 mNumDnsEntries = 0;
297
298 mTestMode = SystemProperties.get("cm.test.mode").equals("true")
299 && SystemProperties.get("ro.build.type").equals("eng");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800300 /*
301 * Create the network state trackers for Wi-Fi and mobile
302 * data. Maybe this could be done with a factory class,
303 * but it's not clear that it's worth it, given that
304 * the number of different network types is not going
305 * to change very often.
306 */
Robert Greenwaltc03fa502010-02-23 18:58:05 -0800307 boolean noMobileData = !getMobileDataEnabled();
Robert Greenwalt5154ae762009-10-30 14:17:42 -0700308 for (int netType : mPriorityList) {
309 switch (mNetAttributes[netType].mRadio) {
310 case ConnectivityManager.TYPE_WIFI:
Joe Onorato8a9b2202010-02-26 18:56:32 -0800311 if (DBG) Slog.v(TAG, "Starting Wifi Service.");
Wink Savillec7a98342010-08-13 16:11:42 -0700312 WifiStateTracker wst = new WifiStateTracker();
Irfan Sheriff0d255342010-07-28 09:35:20 -0700313 WifiService wifiService = new WifiService(context);
Robert Greenwalt5154ae762009-10-30 14:17:42 -0700314 ServiceManager.addService(Context.WIFI_SERVICE, wifiService);
Irfan Sheriff0d255342010-07-28 09:35:20 -0700315 wifiService.checkAndStartWifi();
Robert Greenwalt5154ae762009-10-30 14:17:42 -0700316 mNetTrackers[ConnectivityManager.TYPE_WIFI] = wst;
Wink Savillec7a98342010-08-13 16:11:42 -0700317 wst.startMonitoring(context, mHandler);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800318
Irfan Sheriffa2a1b912010-06-07 09:03:04 -0700319 //TODO: as part of WWS refactor, create only when needed
Irfan Sheriff0d255342010-07-28 09:35:20 -0700320 mWifiWatchdogService = new WifiWatchdogService(context);
Irfan Sheriffa2a1b912010-06-07 09:03:04 -0700321
Robert Greenwalt5154ae762009-10-30 14:17:42 -0700322 break;
323 case ConnectivityManager.TYPE_MOBILE:
Wink Savillec7a98342010-08-13 16:11:42 -0700324 mNetTrackers[netType] = new MobileDataStateTracker(netType,
325 mNetAttributes[netType].mName);
326 mNetTrackers[netType].startMonitoring(context, mHandler);
Robert Greenwaltc03fa502010-02-23 18:58:05 -0800327 if (noMobileData) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800328 if (DBG) Slog.d(TAG, "tearing down Mobile networks due to setting");
Robert Greenwaltc03fa502010-02-23 18:58:05 -0800329 mNetTrackers[netType].teardown();
330 }
Robert Greenwalt5154ae762009-10-30 14:17:42 -0700331 break;
332 default:
Joe Onorato8a9b2202010-02-26 18:56:32 -0800333 Slog.e(TAG, "Trying to create a DataStateTracker for an unknown radio type " +
Robert Greenwalt5154ae762009-10-30 14:17:42 -0700334 mNetAttributes[netType].mRadio);
335 continue;
336 }
337 }
Robert Greenwaltd0e18ff2010-01-26 11:40:34 -0800338
Robert Greenwaltdfadaea2010-03-11 15:03:08 -0800339 mTethering = new Tethering(mContext, mHandler.getLooper());
Robert Greenwaltc9d5fb72010-02-25 12:29:30 -0800340 mTetheringConfigValid = (((mNetTrackers[ConnectivityManager.TYPE_MOBILE_DUN] != null) ||
341 !mTethering.isDunRequired()) &&
342 (mTethering.getTetherableUsbRegexs().length != 0 ||
Danica Chang6fdd0c62010-08-11 14:54:43 -0700343 mTethering.getTetherableWifiRegexs().length != 0 ||
344 mTethering.getTetherableBluetoothRegexs().length != 0) &&
Robert Greenwaltc9d5fb72010-02-25 12:29:30 -0800345 mTethering.getUpstreamIfaceRegexs().length != 0);
346
Robert Greenwalt4e8dfef2010-09-20 14:35:25 -0700347 if (DBG) {
348 mInetLog = new ArrayList();
349 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800350 }
351
Robert Greenwalt5154ae762009-10-30 14:17:42 -0700352
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800353 /**
Robert Greenwalt86e9e552009-07-16 17:21:39 -0700354 * Sets the preferred network.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800355 * @param preference the new preference
356 */
357 public synchronized void setNetworkPreference(int preference) {
358 enforceChangePermission();
Robert Greenwalt42acef32009-08-12 16:08:25 -0700359 if (ConnectivityManager.isNetworkTypeValid(preference) &&
Robert Greenwalt5154ae762009-10-30 14:17:42 -0700360 mNetAttributes[preference] != null &&
Robert Greenwalt42acef32009-08-12 16:08:25 -0700361 mNetAttributes[preference].isDefault()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800362 if (mNetworkPreference != preference) {
363 persistNetworkPreference(preference);
364 mNetworkPreference = preference;
365 enforcePreference();
366 }
367 }
368 }
369
370 public int getNetworkPreference() {
371 enforceAccessPermission();
372 return mNetworkPreference;
373 }
374
375 private void persistNetworkPreference(int networkPreference) {
376 final ContentResolver cr = mContext.getContentResolver();
Robert Greenwalt86e9e552009-07-16 17:21:39 -0700377 Settings.Secure.putInt(cr, Settings.Secure.NETWORK_PREFERENCE,
378 networkPreference);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800379 }
Robert Greenwalt86e9e552009-07-16 17:21:39 -0700380
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800381 private int getPersistedNetworkPreference() {
382 final ContentResolver cr = mContext.getContentResolver();
383
384 final int networkPrefSetting = Settings.Secure
385 .getInt(cr, Settings.Secure.NETWORK_PREFERENCE, -1);
386 if (networkPrefSetting != -1) {
387 return networkPrefSetting;
388 }
389
390 return ConnectivityManager.DEFAULT_NETWORK_PREFERENCE;
391 }
Robert Greenwalt86e9e552009-07-16 17:21:39 -0700392
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800393 /**
Robert Greenwalt86e9e552009-07-16 17:21:39 -0700394 * Make the state of network connectivity conform to the preference settings
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800395 * In this method, we only tear down a non-preferred network. Establishing
396 * a connection to the preferred network is taken care of when we handle
397 * the disconnect event from the non-preferred network
398 * (see {@link #handleDisconnect(NetworkInfo)}).
399 */
400 private void enforcePreference() {
Robert Greenwalt42acef32009-08-12 16:08:25 -0700401 if (mNetTrackers[mNetworkPreference].getNetworkInfo().isConnected())
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800402 return;
403
Robert Greenwalt42acef32009-08-12 16:08:25 -0700404 if (!mNetTrackers[mNetworkPreference].isAvailable())
405 return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800406
Robert Greenwalt42acef32009-08-12 16:08:25 -0700407 for (int t=0; t <= ConnectivityManager.MAX_RADIO_TYPE; t++) {
Robert Greenwalt5154ae762009-10-30 14:17:42 -0700408 if (t != mNetworkPreference && mNetTrackers[t] != null &&
Robert Greenwalt42acef32009-08-12 16:08:25 -0700409 mNetTrackers[t].getNetworkInfo().isConnected()) {
Robert Greenwaltec9fe462009-08-20 15:25:14 -0700410 if (DBG) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800411 Slog.d(TAG, "tearing down " +
Robert Greenwaltec9fe462009-08-20 15:25:14 -0700412 mNetTrackers[t].getNetworkInfo() +
413 " in enforcePreference");
414 }
Robert Greenwalt42acef32009-08-12 16:08:25 -0700415 teardown(mNetTrackers[t]);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800416 }
417 }
418 }
419
420 private boolean teardown(NetworkStateTracker netTracker) {
421 if (netTracker.teardown()) {
422 netTracker.setTeardownRequested(true);
423 return true;
424 } else {
425 return false;
426 }
427 }
428
429 /**
430 * Return NetworkInfo for the active (i.e., connected) network interface.
431 * It is assumed that at most one network is active at a time. If more
432 * than one is active, it is indeterminate which will be returned.
Robert Greenwalt86e9e552009-07-16 17:21:39 -0700433 * @return the info for the active network, or {@code null} if none is
434 * active
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800435 */
436 public NetworkInfo getActiveNetworkInfo() {
437 enforceAccessPermission();
Robert Greenwalt42acef32009-08-12 16:08:25 -0700438 for (int type=0; type <= ConnectivityManager.MAX_NETWORK_TYPE; type++) {
Robert Greenwalt5154ae762009-10-30 14:17:42 -0700439 if (mNetAttributes[type] == null || !mNetAttributes[type].isDefault()) {
Robert Greenwalt42acef32009-08-12 16:08:25 -0700440 continue;
441 }
442 NetworkStateTracker t = mNetTrackers[type];
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800443 NetworkInfo info = t.getNetworkInfo();
444 if (info.isConnected()) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800445 if (DBG && type != mActiveDefaultNetwork) Slog.e(TAG,
Robert Greenwalt42acef32009-08-12 16:08:25 -0700446 "connected default network is not " +
447 "mActiveDefaultNetwork!");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800448 return info;
449 }
450 }
451 return null;
452 }
453
454 public NetworkInfo getNetworkInfo(int networkType) {
455 enforceAccessPermission();
456 if (ConnectivityManager.isNetworkTypeValid(networkType)) {
457 NetworkStateTracker t = mNetTrackers[networkType];
458 if (t != null)
459 return t.getNetworkInfo();
460 }
461 return null;
462 }
463
464 public NetworkInfo[] getAllNetworkInfo() {
465 enforceAccessPermission();
Robert Greenwalt5154ae762009-10-30 14:17:42 -0700466 NetworkInfo[] result = new NetworkInfo[mNetworksDefined];
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800467 int i = 0;
468 for (NetworkStateTracker t : mNetTrackers) {
Robert Greenwalt5154ae762009-10-30 14:17:42 -0700469 if(t != null) result[i++] = t.getNetworkInfo();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800470 }
471 return result;
472 }
473
Robert Greenwaltd192dad2010-09-14 09:18:02 -0700474 /**
475 * Return LinkProperties for the active (i.e., connected) default
476 * network interface. It is assumed that at most one default network
477 * is active at a time. If more than one is active, it is indeterminate
478 * which will be returned.
479 * @return the ip properties for the active network, or {@code null} if
480 * none is active
481 */
482 public LinkProperties getActiveLinkProperties() {
483 enforceAccessPermission();
484 for (int type=0; type <= ConnectivityManager.MAX_NETWORK_TYPE; type++) {
485 if (mNetAttributes[type] == null || !mNetAttributes[type].isDefault()) {
486 continue;
487 }
488 NetworkStateTracker t = mNetTrackers[type];
489 NetworkInfo info = t.getNetworkInfo();
490 if (info.isConnected()) {
491 return t.getLinkProperties();
492 }
493 }
494 return null;
495 }
496
497 public LinkProperties getLinkProperties(int networkType) {
498 enforceAccessPermission();
499 if (ConnectivityManager.isNetworkTypeValid(networkType)) {
500 NetworkStateTracker t = mNetTrackers[networkType];
501 if (t != null) return t.getLinkProperties();
502 }
503 return null;
504 }
505
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800506 public boolean setRadios(boolean turnOn) {
507 boolean result = true;
508 enforceChangePermission();
509 for (NetworkStateTracker t : mNetTrackers) {
Robert Greenwalt5154ae762009-10-30 14:17:42 -0700510 if (t != null) result = t.setRadio(turnOn) && result;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800511 }
512 return result;
513 }
514
515 public boolean setRadio(int netType, boolean turnOn) {
516 enforceChangePermission();
517 if (!ConnectivityManager.isNetworkTypeValid(netType)) {
518 return false;
519 }
520 NetworkStateTracker tracker = mNetTrackers[netType];
521 return tracker != null && tracker.setRadio(turnOn);
522 }
523
Robert Greenwalt9c75d4a2009-09-27 17:27:04 -0700524 /**
525 * Used to notice when the calling process dies so we can self-expire
526 *
527 * Also used to know if the process has cleaned up after itself when
528 * our auto-expire timer goes off. The timer has a link to an object.
529 *
530 */
Robert Greenwalt42acef32009-08-12 16:08:25 -0700531 private class FeatureUser implements IBinder.DeathRecipient {
532 int mNetworkType;
533 String mFeature;
534 IBinder mBinder;
535 int mPid;
536 int mUid;
Robert Greenwaltb9285352009-12-21 18:24:07 -0800537 long mCreateTime;
Robert Greenwalt42acef32009-08-12 16:08:25 -0700538
539 FeatureUser(int type, String feature, IBinder binder) {
540 super();
541 mNetworkType = type;
542 mFeature = feature;
543 mBinder = binder;
544 mPid = getCallingPid();
545 mUid = getCallingUid();
Robert Greenwaltb9285352009-12-21 18:24:07 -0800546 mCreateTime = System.currentTimeMillis();
Robert Greenwalt9c75d4a2009-09-27 17:27:04 -0700547
Robert Greenwalt42acef32009-08-12 16:08:25 -0700548 try {
549 mBinder.linkToDeath(this, 0);
550 } catch (RemoteException e) {
551 binderDied();
552 }
553 }
554
555 void unlinkDeathRecipient() {
556 mBinder.unlinkToDeath(this, 0);
557 }
558
559 public void binderDied() {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800560 Slog.d(TAG, "ConnectivityService FeatureUser binderDied(" +
Robert Greenwaltb9285352009-12-21 18:24:07 -0800561 mNetworkType + ", " + mFeature + ", " + mBinder + "), created " +
562 (System.currentTimeMillis() - mCreateTime) + " mSec ago");
Robert Greenwalt9c75d4a2009-09-27 17:27:04 -0700563 stopUsingNetworkFeature(this, false);
Robert Greenwalt42acef32009-08-12 16:08:25 -0700564 }
565
Robert Greenwalt9c75d4a2009-09-27 17:27:04 -0700566 public void expire() {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800567 Slog.d(TAG, "ConnectivityService FeatureUser expire(" +
Robert Greenwaltb9285352009-12-21 18:24:07 -0800568 mNetworkType + ", " + mFeature + ", " + mBinder +"), created " +
569 (System.currentTimeMillis() - mCreateTime) + " mSec ago");
Robert Greenwalt9c75d4a2009-09-27 17:27:04 -0700570 stopUsingNetworkFeature(this, false);
571 }
Robert Greenwaltb9285352009-12-21 18:24:07 -0800572
573 public String toString() {
574 return "FeatureUser("+mNetworkType+","+mFeature+","+mPid+","+mUid+"), created " +
575 (System.currentTimeMillis() - mCreateTime) + " mSec ago";
576 }
Robert Greenwalt42acef32009-08-12 16:08:25 -0700577 }
578
Robert Greenwalt9c75d4a2009-09-27 17:27:04 -0700579 // javadoc from interface
Robert Greenwalt42acef32009-08-12 16:08:25 -0700580 public int startUsingNetworkFeature(int networkType, String feature,
581 IBinder binder) {
582 if (DBG) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800583 Slog.d(TAG, "startUsingNetworkFeature for net " + networkType +
Robert Greenwalt42acef32009-08-12 16:08:25 -0700584 ": " + feature);
585 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800586 enforceChangePermission();
Robert Greenwalt5154ae762009-10-30 14:17:42 -0700587 if (!ConnectivityManager.isNetworkTypeValid(networkType) ||
588 mNetAttributes[networkType] == null) {
Robert Greenwalt42acef32009-08-12 16:08:25 -0700589 return Phone.APN_REQUEST_FAILED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800590 }
Robert Greenwalt42acef32009-08-12 16:08:25 -0700591
Robert Greenwalt9c75d4a2009-09-27 17:27:04 -0700592 FeatureUser f = new FeatureUser(networkType, feature, binder);
Robert Greenwalt42acef32009-08-12 16:08:25 -0700593
594 // TODO - move this into the MobileDataStateTracker
595 int usedNetworkType = networkType;
596 if(networkType == ConnectivityManager.TYPE_MOBILE) {
Robert Greenwaltc03fa502010-02-23 18:58:05 -0800597 if (!getMobileDataEnabled()) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800598 if (DBG) Slog.d(TAG, "requested special network with data disabled - rejected");
Robert Greenwaltc03fa502010-02-23 18:58:05 -0800599 return Phone.APN_TYPE_NOT_AVAILABLE;
600 }
Robert Greenwalt42acef32009-08-12 16:08:25 -0700601 if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_MMS)) {
602 usedNetworkType = ConnectivityManager.TYPE_MOBILE_MMS;
603 } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_SUPL)) {
604 usedNetworkType = ConnectivityManager.TYPE_MOBILE_SUPL;
605 } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_DUN)) {
606 usedNetworkType = ConnectivityManager.TYPE_MOBILE_DUN;
607 } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_HIPRI)) {
608 usedNetworkType = ConnectivityManager.TYPE_MOBILE_HIPRI;
609 }
610 }
611 NetworkStateTracker network = mNetTrackers[usedNetworkType];
612 if (network != null) {
613 if (usedNetworkType != networkType) {
614 Integer currentPid = new Integer(getCallingPid());
615
616 NetworkStateTracker radio = mNetTrackers[networkType];
617 NetworkInfo ni = network.getNetworkInfo();
618
619 if (ni.isAvailable() == false) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800620 if (DBG) Slog.d(TAG, "special network not available");
Robert Greenwalt42acef32009-08-12 16:08:25 -0700621 return Phone.APN_TYPE_NOT_AVAILABLE;
622 }
623
Robert Greenwalt9c75d4a2009-09-27 17:27:04 -0700624 synchronized(this) {
625 mFeatureUsers.add(f);
626 if (!mNetRequestersPids[usedNetworkType].contains(currentPid)) {
627 // this gets used for per-pid dns when connected
628 mNetRequestersPids[usedNetworkType].add(currentPid);
629 }
Robert Greenwalt42acef32009-08-12 16:08:25 -0700630 }
Robert Greenwalt9c75d4a2009-09-27 17:27:04 -0700631 mHandler.sendMessageDelayed(mHandler.obtainMessage(
632 NetworkStateTracker.EVENT_RESTORE_DEFAULT_NETWORK,
633 f), getRestoreDefaultNetworkDelay());
634
Robert Greenwalt42acef32009-08-12 16:08:25 -0700635
Robert Greenwalta64bf832009-08-19 20:19:33 -0700636 if ((ni.isConnectedOrConnecting() == true) &&
637 !network.isTeardownRequested()) {
Robert Greenwalt42acef32009-08-12 16:08:25 -0700638 if (ni.isConnected() == true) {
639 // add the pid-specific dns
Robert Greenwaltc76b8fa2010-07-23 15:46:26 -0700640 handleDnsConfigurationChange(networkType);
Joe Onorato8a9b2202010-02-26 18:56:32 -0800641 if (DBG) Slog.d(TAG, "special network already active");
Robert Greenwalt42acef32009-08-12 16:08:25 -0700642 return Phone.APN_ALREADY_ACTIVE;
643 }
Joe Onorato8a9b2202010-02-26 18:56:32 -0800644 if (DBG) Slog.d(TAG, "special network already connecting");
Robert Greenwalt42acef32009-08-12 16:08:25 -0700645 return Phone.APN_REQUEST_STARTED;
646 }
647
648 // check if the radio in play can make another contact
649 // assume if cannot for now
650
Joe Onorato8a9b2202010-02-26 18:56:32 -0800651 if (DBG) Slog.d(TAG, "reconnecting to special network");
Robert Greenwalt42acef32009-08-12 16:08:25 -0700652 network.reconnect();
653 return Phone.APN_REQUEST_STARTED;
654 } else {
Robert Greenwalt02648a42010-05-18 10:52:51 -0700655 return -1;
Robert Greenwalt42acef32009-08-12 16:08:25 -0700656 }
657 }
658 return Phone.APN_TYPE_NOT_AVAILABLE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800659 }
660
Robert Greenwalt9c75d4a2009-09-27 17:27:04 -0700661 // javadoc from interface
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800662 public int stopUsingNetworkFeature(int networkType, String feature) {
Robert Greenwaltb8f16342009-10-06 17:52:40 -0700663 enforceChangePermission();
664
Robert Greenwalt9c75d4a2009-09-27 17:27:04 -0700665 int pid = getCallingPid();
666 int uid = getCallingUid();
667
668 FeatureUser u = null;
669 boolean found = false;
670
671 synchronized(this) {
672 for (int i = 0; i < mFeatureUsers.size() ; i++) {
673 u = (FeatureUser)mFeatureUsers.get(i);
674 if (uid == u.mUid && pid == u.mPid &&
675 networkType == u.mNetworkType &&
676 TextUtils.equals(feature, u.mFeature)) {
677 found = true;
678 break;
679 }
680 }
681 }
682 if (found && u != null) {
683 // stop regardless of how many other time this proc had called start
684 return stopUsingNetworkFeature(u, true);
685 } else {
686 // none found!
Joe Onorato8a9b2202010-02-26 18:56:32 -0800687 if (DBG) Slog.d(TAG, "ignoring stopUsingNetworkFeature - not a live request");
Robert Greenwalt9c75d4a2009-09-27 17:27:04 -0700688 return 1;
689 }
Robert Greenwalt42acef32009-08-12 16:08:25 -0700690 }
691
Robert Greenwalt9c75d4a2009-09-27 17:27:04 -0700692 private int stopUsingNetworkFeature(FeatureUser u, boolean ignoreDups) {
693 int networkType = u.mNetworkType;
694 String feature = u.mFeature;
695 int pid = u.mPid;
696 int uid = u.mUid;
697
698 NetworkStateTracker tracker = null;
699 boolean callTeardown = false; // used to carry our decision outside of sync block
700
Robert Greenwalt42acef32009-08-12 16:08:25 -0700701 if (DBG) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800702 Slog.d(TAG, "stopUsingNetworkFeature for net " + networkType +
Robert Greenwalt42acef32009-08-12 16:08:25 -0700703 ": " + feature);
704 }
Robert Greenwaltb8f16342009-10-06 17:52:40 -0700705
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800706 if (!ConnectivityManager.isNetworkTypeValid(networkType)) {
707 return -1;
708 }
Robert Greenwalt42acef32009-08-12 16:08:25 -0700709
Robert Greenwalt9c75d4a2009-09-27 17:27:04 -0700710 // need to link the mFeatureUsers list with the mNetRequestersPids state in this
711 // sync block
712 synchronized(this) {
713 // check if this process still has an outstanding start request
714 if (!mFeatureUsers.contains(u)) {
Robert Greenwalt78a640a2010-03-10 16:10:43 -0800715 if (DBG) Slog.d(TAG, "ignoring - this process has no outstanding requests");
Robert Greenwalt42acef32009-08-12 16:08:25 -0700716 return 1;
717 }
Robert Greenwalt9c75d4a2009-09-27 17:27:04 -0700718 u.unlinkDeathRecipient();
719 mFeatureUsers.remove(mFeatureUsers.indexOf(u));
720 // If we care about duplicate requests, check for that here.
721 //
722 // This is done to support the extension of a request - the app
723 // can request we start the network feature again and renew the
724 // auto-shutoff delay. Normal "stop" calls from the app though
725 // do not pay attention to duplicate requests - in effect the
726 // API does not refcount and a single stop will counter multiple starts.
727 if (ignoreDups == false) {
728 for (int i = 0; i < mFeatureUsers.size() ; i++) {
729 FeatureUser x = (FeatureUser)mFeatureUsers.get(i);
730 if (x.mUid == u.mUid && x.mPid == u.mPid &&
731 x.mNetworkType == u.mNetworkType &&
732 TextUtils.equals(x.mFeature, u.mFeature)) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800733 if (DBG) Slog.d(TAG, "ignoring stopUsingNetworkFeature as dup is found");
Robert Greenwalt9c75d4a2009-09-27 17:27:04 -0700734 return 1;
735 }
736 }
Robert Greenwalt42acef32009-08-12 16:08:25 -0700737 }
Robert Greenwalt9c75d4a2009-09-27 17:27:04 -0700738
739 // TODO - move to MobileDataStateTracker
740 int usedNetworkType = networkType;
741 if (networkType == ConnectivityManager.TYPE_MOBILE) {
742 if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_MMS)) {
743 usedNetworkType = ConnectivityManager.TYPE_MOBILE_MMS;
744 } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_SUPL)) {
745 usedNetworkType = ConnectivityManager.TYPE_MOBILE_SUPL;
746 } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_DUN)) {
747 usedNetworkType = ConnectivityManager.TYPE_MOBILE_DUN;
748 } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_HIPRI)) {
749 usedNetworkType = ConnectivityManager.TYPE_MOBILE_HIPRI;
750 }
751 }
752 tracker = mNetTrackers[usedNetworkType];
Robert Greenwalt5154ae762009-10-30 14:17:42 -0700753 if (tracker == null) {
Robert Greenwalt78a640a2010-03-10 16:10:43 -0800754 if (DBG) Slog.d(TAG, "ignoring - no known tracker for net type " + usedNetworkType);
Robert Greenwalt5154ae762009-10-30 14:17:42 -0700755 return -1;
756 }
757 if (usedNetworkType != networkType) {
Robert Greenwalt9c75d4a2009-09-27 17:27:04 -0700758 Integer currentPid = new Integer(pid);
Robert Greenwalt9c75d4a2009-09-27 17:27:04 -0700759 mNetRequestersPids[usedNetworkType].remove(currentPid);
Robert Greenwalt421c72b2009-12-17 14:54:59 -0800760 reassessPidDns(pid, true);
Robert Greenwalt9c75d4a2009-09-27 17:27:04 -0700761 if (mNetRequestersPids[usedNetworkType].size() != 0) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800762 if (DBG) Slog.d(TAG, "not tearing down special network - " +
Robert Greenwalt9c75d4a2009-09-27 17:27:04 -0700763 "others still using it");
764 return 1;
765 }
766 callTeardown = true;
767 }
768 }
Robert Greenwalt78a640a2010-03-10 16:10:43 -0800769 if (DBG) Slog.d(TAG, "Doing network teardown");
Robert Greenwalt9c75d4a2009-09-27 17:27:04 -0700770 if (callTeardown) {
771 tracker.teardown();
Robert Greenwalt42acef32009-08-12 16:08:25 -0700772 return 1;
773 } else {
Robert Greenwalt02648a42010-05-18 10:52:51 -0700774 return -1;
Robert Greenwalt42acef32009-08-12 16:08:25 -0700775 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800776 }
777
778 /**
Robert Greenwalt585ac0f2010-08-27 09:24:29 -0700779 * @deprecated use requestRouteToHostAddress instead
780 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800781 * Ensure that a network route exists to deliver traffic to the specified
782 * host via the specified network interface.
Robert Greenwalt86e9e552009-07-16 17:21:39 -0700783 * @param networkType the type of the network over which traffic to the
784 * specified host is to be routed
785 * @param hostAddress the IP address of the host to which the route is
786 * desired
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800787 * @return {@code true} on success, {@code false} on failure
788 */
789 public boolean requestRouteToHost(int networkType, int hostAddress) {
Robert Greenwalt585ac0f2010-08-27 09:24:29 -0700790 InetAddress inetAddress = NetworkUtils.intToInetAddress(hostAddress);
791
792 if (inetAddress == null) {
793 return false;
794 }
795
796 return requestRouteToHostAddress(networkType, inetAddress.getAddress());
797 }
798
799 /**
800 * Ensure that a network route exists to deliver traffic to the specified
801 * host via the specified network interface.
802 * @param networkType the type of the network over which traffic to the
803 * specified host is to be routed
804 * @param hostAddress the IP address of the host to which the route is
805 * desired
806 * @return {@code true} on success, {@code false} on failure
807 */
808 public boolean requestRouteToHostAddress(int networkType, byte[] hostAddress) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800809 enforceChangePermission();
810 if (!ConnectivityManager.isNetworkTypeValid(networkType)) {
811 return false;
812 }
813 NetworkStateTracker tracker = mNetTrackers[networkType];
Robert Greenwalt8206ff32009-09-10 15:06:20 -0700814
Robert Greenwalt5154ae762009-10-30 14:17:42 -0700815 if (tracker == null || !tracker.getNetworkInfo().isConnected() ||
816 tracker.isTeardownRequested()) {
Robert Greenwalt8206ff32009-09-10 15:06:20 -0700817 if (DBG) {
Robert Greenwalt585ac0f2010-08-27 09:24:29 -0700818 Slog.d(TAG, "requestRouteToHostAddress on down network " +
819 "(" + networkType + ") - dropped");
Robert Greenwalt8206ff32009-09-10 15:06:20 -0700820 }
821 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800822 }
Robert Greenwalt47f69fe2010-06-15 15:43:39 -0700823 try {
Robert Greenwalt585ac0f2010-08-27 09:24:29 -0700824 InetAddress addr = InetAddress.getByAddress(hostAddress);
Robert Greenwalt47f69fe2010-06-15 15:43:39 -0700825 return addHostRoute(tracker, addr);
826 } catch (UnknownHostException e) {}
827 return false;
Irfan Sheriffd649c122010-06-09 15:39:36 -0700828 }
829
830 /**
831 * Ensure that a network route exists to deliver traffic to the specified
832 * host via the mobile data network.
833 * @param hostAddress the IP address of the host to which the route is desired,
834 * in network byte order.
Robert Greenwalt47f69fe2010-06-15 15:43:39 -0700835 * TODO - deprecate
Irfan Sheriffd649c122010-06-09 15:39:36 -0700836 * @return {@code true} on success, {@code false} on failure
837 */
Robert Greenwalt47f69fe2010-06-15 15:43:39 -0700838 private boolean addHostRoute(NetworkStateTracker nt, InetAddress hostAddress) {
Irfan Sheriffd649c122010-06-09 15:39:36 -0700839 if (nt.getNetworkInfo().getType() == ConnectivityManager.TYPE_WIFI) {
840 return false;
841 }
842
Robert Greenwalt37e65eb2010-08-30 10:56:47 -0700843 LinkProperties p = nt.getLinkProperties();
Robert Greenwalt47f69fe2010-06-15 15:43:39 -0700844 if (p == null) return false;
845 String interfaceName = p.getInterfaceName();
Irfan Sheriffd649c122010-06-09 15:39:36 -0700846
847 if (DBG) {
Robert Greenwalt47f69fe2010-06-15 15:43:39 -0700848 Slog.d(TAG, "Requested host route to " + hostAddress + "(" + interfaceName + ")");
Irfan Sheriffd649c122010-06-09 15:39:36 -0700849 }
Robert Greenwalt47f69fe2010-06-15 15:43:39 -0700850 if (interfaceName != null) {
Robert Greenwalt585ac0f2010-08-27 09:24:29 -0700851 return NetworkUtils.addHostRoute(interfaceName, hostAddress, null);
Irfan Sheriffd649c122010-06-09 15:39:36 -0700852 } else {
Robert Greenwalt47f69fe2010-06-15 15:43:39 -0700853 if (DBG) Slog.e(TAG, "addHostRoute failed due to null interface name");
Irfan Sheriffd649c122010-06-09 15:39:36 -0700854 return false;
855 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800856 }
857
858 /**
859 * @see ConnectivityManager#getBackgroundDataSetting()
860 */
861 public boolean getBackgroundDataSetting() {
862 return Settings.Secure.getInt(mContext.getContentResolver(),
863 Settings.Secure.BACKGROUND_DATA, 1) == 1;
864 }
Robert Greenwalt86e9e552009-07-16 17:21:39 -0700865
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800866 /**
867 * @see ConnectivityManager#setBackgroundDataSetting(boolean)
868 */
869 public void setBackgroundDataSetting(boolean allowBackgroundDataUsage) {
870 mContext.enforceCallingOrSelfPermission(
871 android.Manifest.permission.CHANGE_BACKGROUND_DATA_SETTING,
872 "ConnectivityService");
Robert Greenwalt86e9e552009-07-16 17:21:39 -0700873
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800874 if (getBackgroundDataSetting() == allowBackgroundDataUsage) return;
875
876 Settings.Secure.putInt(mContext.getContentResolver(),
Robert Greenwalt86e9e552009-07-16 17:21:39 -0700877 Settings.Secure.BACKGROUND_DATA,
878 allowBackgroundDataUsage ? 1 : 0);
879
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800880 Intent broadcast = new Intent(
881 ConnectivityManager.ACTION_BACKGROUND_DATA_SETTING_CHANGED);
882 mContext.sendBroadcast(broadcast);
Robert Greenwalt86e9e552009-07-16 17:21:39 -0700883 }
884
Robert Greenwaltc03fa502010-02-23 18:58:05 -0800885 /**
886 * @see ConnectivityManager#getMobileDataEnabled()
887 */
888 public boolean getMobileDataEnabled() {
889 enforceAccessPermission();
890 boolean retVal = Settings.Secure.getInt(mContext.getContentResolver(),
891 Settings.Secure.MOBILE_DATA, 1) == 1;
Joe Onorato8a9b2202010-02-26 18:56:32 -0800892 if (DBG) Slog.d(TAG, "getMobileDataEnabled returning " + retVal);
Robert Greenwaltc03fa502010-02-23 18:58:05 -0800893 return retVal;
894 }
895
896 /**
897 * @see ConnectivityManager#setMobileDataEnabled(boolean)
898 */
899 public synchronized void setMobileDataEnabled(boolean enabled) {
900 enforceChangePermission();
Joe Onorato8a9b2202010-02-26 18:56:32 -0800901 if (DBG) Slog.d(TAG, "setMobileDataEnabled(" + enabled + ")");
Robert Greenwaltc03fa502010-02-23 18:58:05 -0800902
903 if (getMobileDataEnabled() == enabled) return;
904
905 Settings.Secure.putInt(mContext.getContentResolver(),
906 Settings.Secure.MOBILE_DATA, enabled ? 1 : 0);
907
908 if (enabled) {
909 if (mNetTrackers[ConnectivityManager.TYPE_MOBILE] != null) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800910 if (DBG) Slog.d(TAG, "starting up " + mNetTrackers[ConnectivityManager.TYPE_MOBILE]);
Robert Greenwaltc03fa502010-02-23 18:58:05 -0800911 mNetTrackers[ConnectivityManager.TYPE_MOBILE].reconnect();
912 }
913 } else {
914 for (NetworkStateTracker nt : mNetTrackers) {
915 if (nt == null) continue;
916 int netType = nt.getNetworkInfo().getType();
917 if (mNetAttributes[netType].mRadio == ConnectivityManager.TYPE_MOBILE) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800918 if (DBG) Slog.d(TAG, "tearing down " + nt);
Robert Greenwaltc03fa502010-02-23 18:58:05 -0800919 nt.teardown();
920 }
921 }
922 }
923 }
924
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800925 private int getNumConnectedNetworks() {
926 int numConnectedNets = 0;
927
928 for (NetworkStateTracker nt : mNetTrackers) {
Robert Greenwalt5154ae762009-10-30 14:17:42 -0700929 if (nt != null && nt.getNetworkInfo().isConnected() &&
Robert Greenwalt86e9e552009-07-16 17:21:39 -0700930 !nt.isTeardownRequested()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800931 ++numConnectedNets;
932 }
933 }
934 return numConnectedNets;
935 }
936
937 private void enforceAccessPermission() {
Robert Greenwalt86e9e552009-07-16 17:21:39 -0700938 mContext.enforceCallingOrSelfPermission(
939 android.Manifest.permission.ACCESS_NETWORK_STATE,
940 "ConnectivityService");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800941 }
942
943 private void enforceChangePermission() {
Robert Greenwalt86e9e552009-07-16 17:21:39 -0700944 mContext.enforceCallingOrSelfPermission(
945 android.Manifest.permission.CHANGE_NETWORK_STATE,
946 "ConnectivityService");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800947 }
948
Robert Greenwaltd0e18ff2010-01-26 11:40:34 -0800949 // TODO Make this a special check when it goes public
950 private void enforceTetherChangePermission() {
951 mContext.enforceCallingOrSelfPermission(
952 android.Manifest.permission.CHANGE_NETWORK_STATE,
953 "ConnectivityService");
954 }
955
Robert Greenwalt2a091d72010-02-11 18:18:40 -0800956 private void enforceTetherAccessPermission() {
957 mContext.enforceCallingOrSelfPermission(
958 android.Manifest.permission.ACCESS_NETWORK_STATE,
959 "ConnectivityService");
960 }
961
Robert Greenwalt14f2ef42010-06-15 12:19:37 -0700962 private void enforceConnectivityInternalPermission() {
963 mContext.enforceCallingOrSelfPermission(
964 android.Manifest.permission.CONNECTIVITY_INTERNAL,
965 "ConnectivityService");
966 }
967
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800968 /**
Robert Greenwalt86e9e552009-07-16 17:21:39 -0700969 * Handle a {@code DISCONNECTED} event. If this pertains to the non-active
970 * network, we ignore it. If it is for the active network, we send out a
971 * broadcast. But first, we check whether it might be possible to connect
972 * to a different network.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800973 * @param info the {@code NetworkInfo} for the network
974 */
975 private void handleDisconnect(NetworkInfo info) {
976
Robert Greenwalt42acef32009-08-12 16:08:25 -0700977 int prevNetType = info.getType();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800978
Robert Greenwalt42acef32009-08-12 16:08:25 -0700979 mNetTrackers[prevNetType].setTeardownRequested(false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800980 /*
981 * If the disconnected network is not the active one, then don't report
982 * this as a loss of connectivity. What probably happened is that we're
983 * getting the disconnect for a network that we explicitly disabled
984 * in accordance with network preference policies.
985 */
Robert Greenwalt42acef32009-08-12 16:08:25 -0700986 if (!mNetAttributes[prevNetType].isDefault()) {
987 List pids = mNetRequestersPids[prevNetType];
988 for (int i = 0; i<pids.size(); i++) {
989 Integer pid = (Integer)pids.get(i);
990 // will remove them because the net's no longer connected
991 // need to do this now as only now do we know the pids and
992 // can properly null things that are no longer referenced.
993 reassessPidDns(pid.intValue(), false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800994 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800995 }
996
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800997 Intent intent = new Intent(ConnectivityManager.CONNECTIVITY_ACTION);
998 intent.putExtra(ConnectivityManager.EXTRA_NETWORK_INFO, info);
999 if (info.isFailover()) {
1000 intent.putExtra(ConnectivityManager.EXTRA_IS_FAILOVER, true);
1001 info.setFailover(false);
1002 }
1003 if (info.getReason() != null) {
1004 intent.putExtra(ConnectivityManager.EXTRA_REASON, info.getReason());
1005 }
1006 if (info.getExtraInfo() != null) {
Robert Greenwalt86e9e552009-07-16 17:21:39 -07001007 intent.putExtra(ConnectivityManager.EXTRA_EXTRA_INFO,
1008 info.getExtraInfo());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001009 }
Robert Greenwalt42acef32009-08-12 16:08:25 -07001010
Robert Greenwaltcc4b4012010-01-25 17:54:29 -08001011 NetworkStateTracker newNet = null;
1012 if (mNetAttributes[prevNetType].isDefault()) {
1013 newNet = tryFailover(prevNetType);
1014 if (newNet != null) {
1015 NetworkInfo switchTo = newNet.getNetworkInfo();
Robert Greenwalt029be812010-09-20 18:01:43 -07001016 if (!switchTo.isConnected()) {
1017 // if the other net is connected they've already reset this and perhaps even gotten
1018 // a positive report we don't want to overwrite, but if not we need to clear this now
1019 // to turn our cellular sig strength white
1020 mDefaultInetConditionPublished = 0;
1021 }
Robert Greenwaltcc4b4012010-01-25 17:54:29 -08001022 intent.putExtra(ConnectivityManager.EXTRA_OTHER_NETWORK_INFO, switchTo);
1023 } else {
Robert Greenwalt029be812010-09-20 18:01:43 -07001024 mDefaultInetConditionPublished = 0; // we're not connected anymore
Robert Greenwaltcc4b4012010-01-25 17:54:29 -08001025 intent.putExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, true);
1026 }
Robert Greenwaltda03c4e2010-01-20 19:29:41 -08001027 }
Robert Greenwalt029be812010-09-20 18:01:43 -07001028 intent.putExtra(ConnectivityManager.EXTRA_INET_CONDITION, mDefaultInetConditionPublished);
Robert Greenwaltda03c4e2010-01-20 19:29:41 -08001029 // do this before we broadcast the change
Robert Greenwaltc76b8fa2010-07-23 15:46:26 -07001030 handleConnectivityChange(prevNetType);
Robert Greenwaltda03c4e2010-01-20 19:29:41 -08001031
1032 sendStickyBroadcast(intent);
1033 /*
1034 * If the failover network is already connected, then immediately send
1035 * out a followup broadcast indicating successful failover
1036 */
1037 if (newNet != null && newNet.getNetworkInfo().isConnected()) {
1038 sendConnectedBroadcast(newNet.getNetworkInfo());
1039 }
1040 }
1041
Robert Greenwaltcc4b4012010-01-25 17:54:29 -08001042 // returns null if no failover available
Robert Greenwaltda03c4e2010-01-20 19:29:41 -08001043 private NetworkStateTracker tryFailover(int prevNetType) {
Robert Greenwalt42acef32009-08-12 16:08:25 -07001044 /*
1045 * If this is a default network, check if other defaults are available
1046 * or active
1047 */
1048 NetworkStateTracker newNet = null;
1049 if (mNetAttributes[prevNetType].isDefault()) {
Robert Greenwalt42acef32009-08-12 16:08:25 -07001050 if (mActiveDefaultNetwork == prevNetType) {
1051 mActiveDefaultNetwork = -1;
1052 }
1053
1054 int newType = -1;
1055 int newPriority = -1;
Robert Greenwalt35429592010-02-25 12:04:29 -08001056 boolean noMobileData = !getMobileDataEnabled();
Robert Greenwaltda03c4e2010-01-20 19:29:41 -08001057 for (int checkType=0; checkType <= ConnectivityManager.MAX_NETWORK_TYPE; checkType++) {
Robert Greenwalt5154ae762009-10-30 14:17:42 -07001058 if (checkType == prevNetType) continue;
1059 if (mNetAttributes[checkType] == null) continue;
Robert Greenwalt35429592010-02-25 12:04:29 -08001060 if (mNetAttributes[checkType].mRadio == ConnectivityManager.TYPE_MOBILE &&
1061 noMobileData) {
1062 if (DBG) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001063 Slog.d(TAG, "not failing over to mobile type " + checkType +
Robert Greenwalt35429592010-02-25 12:04:29 -08001064 " because Mobile Data Disabled");
1065 }
1066 continue;
1067 }
Robert Greenwalt42acef32009-08-12 16:08:25 -07001068 if (mNetAttributes[checkType].isDefault()) {
1069 /* TODO - if we have multiple nets we could use
1070 * we may want to put more thought into which we choose
1071 */
1072 if (checkType == mNetworkPreference) {
1073 newType = checkType;
1074 break;
1075 }
Robert Greenwalt5154ae762009-10-30 14:17:42 -07001076 if (mNetAttributes[checkType].mPriority > newPriority) {
Robert Greenwalt42acef32009-08-12 16:08:25 -07001077 newType = checkType;
Robert Greenwalt5154ae762009-10-30 14:17:42 -07001078 newPriority = mNetAttributes[newType].mPriority;
Robert Greenwalt42acef32009-08-12 16:08:25 -07001079 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001080 }
1081 }
Robert Greenwalt42acef32009-08-12 16:08:25 -07001082
1083 if (newType != -1) {
1084 newNet = mNetTrackers[newType];
1085 /**
1086 * See if the other network is available to fail over to.
1087 * If is not available, we enable it anyway, so that it
1088 * will be able to connect when it does become available,
1089 * but we report a total loss of connectivity rather than
1090 * report that we are attempting to fail over.
1091 */
1092 if (newNet.isAvailable()) {
1093 NetworkInfo switchTo = newNet.getNetworkInfo();
1094 switchTo.setFailover(true);
Robert Greenwalta64bf832009-08-19 20:19:33 -07001095 if (!switchTo.isConnectedOrConnecting() ||
1096 newNet.isTeardownRequested()) {
Robert Greenwalt42acef32009-08-12 16:08:25 -07001097 newNet.reconnect();
1098 }
1099 if (DBG) {
1100 if (switchTo.isConnected()) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001101 Slog.v(TAG, "Switching to already connected " +
Robert Greenwalt42acef32009-08-12 16:08:25 -07001102 switchTo.getTypeName());
1103 } else {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001104 Slog.v(TAG, "Attempting to switch to " +
Robert Greenwalt42acef32009-08-12 16:08:25 -07001105 switchTo.getTypeName());
1106 }
1107 }
Robert Greenwalt42acef32009-08-12 16:08:25 -07001108 } else {
1109 newNet.reconnect();
Robert Greenwaltf0fa39e2010-03-09 14:55:08 -08001110 newNet = null; // not officially avail.. try anyway, but
1111 // report no failover
Robert Greenwalt42acef32009-08-12 16:08:25 -07001112 }
Robert Greenwalt42acef32009-08-12 16:08:25 -07001113 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001114 }
Robert Greenwalt42acef32009-08-12 16:08:25 -07001115
Robert Greenwaltda03c4e2010-01-20 19:29:41 -08001116 return newNet;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001117 }
1118
1119 private void sendConnectedBroadcast(NetworkInfo info) {
Robert Greenwalt1e9aac22010-09-15 17:36:33 -07001120 sendGeneralBroadcast(info, ConnectivityManager.CONNECTIVITY_ACTION);
1121 }
1122
1123 private void sendInetConditionBroadcast(NetworkInfo info) {
1124 sendGeneralBroadcast(info, ConnectivityManager.INET_CONDITION_ACTION);
1125 }
1126
1127 private void sendGeneralBroadcast(NetworkInfo info, String bcastType) {
1128 Intent intent = new Intent(bcastType);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001129 intent.putExtra(ConnectivityManager.EXTRA_NETWORK_INFO, info);
1130 if (info.isFailover()) {
1131 intent.putExtra(ConnectivityManager.EXTRA_IS_FAILOVER, true);
1132 info.setFailover(false);
1133 }
1134 if (info.getReason() != null) {
1135 intent.putExtra(ConnectivityManager.EXTRA_REASON, info.getReason());
1136 }
1137 if (info.getExtraInfo() != null) {
Robert Greenwalt86e9e552009-07-16 17:21:39 -07001138 intent.putExtra(ConnectivityManager.EXTRA_EXTRA_INFO,
1139 info.getExtraInfo());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001140 }
Robert Greenwaltd7085fc2010-09-08 15:24:47 -07001141 intent.putExtra(ConnectivityManager.EXTRA_INET_CONDITION, mDefaultInetConditionPublished);
Mike Lockwood0f79b542009-08-14 14:18:49 -04001142 sendStickyBroadcast(intent);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001143 }
1144
1145 /**
1146 * Called when an attempt to fail over to another network has failed.
1147 * @param info the {@link NetworkInfo} for the failed network
1148 */
1149 private void handleConnectionFailure(NetworkInfo info) {
1150 mNetTrackers[info.getType()].setTeardownRequested(false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001151
Robert Greenwalt42acef32009-08-12 16:08:25 -07001152 String reason = info.getReason();
1153 String extraInfo = info.getExtraInfo();
Robert Greenwalt86e9e552009-07-16 17:21:39 -07001154
Robert Greenwalt42acef32009-08-12 16:08:25 -07001155 if (DBG) {
1156 String reasonText;
1157 if (reason == null) {
1158 reasonText = ".";
1159 } else {
1160 reasonText = " (" + reason + ").";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001161 }
Joe Onorato8a9b2202010-02-26 18:56:32 -08001162 Slog.v(TAG, "Attempt to connect to " + info.getTypeName() +
Robert Greenwalt42acef32009-08-12 16:08:25 -07001163 " failed" + reasonText);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001164 }
Robert Greenwalt42acef32009-08-12 16:08:25 -07001165
1166 Intent intent = new Intent(ConnectivityManager.CONNECTIVITY_ACTION);
1167 intent.putExtra(ConnectivityManager.EXTRA_NETWORK_INFO, info);
1168 if (getActiveNetworkInfo() == null) {
1169 intent.putExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, true);
1170 }
1171 if (reason != null) {
1172 intent.putExtra(ConnectivityManager.EXTRA_REASON, reason);
1173 }
1174 if (extraInfo != null) {
1175 intent.putExtra(ConnectivityManager.EXTRA_EXTRA_INFO, extraInfo);
1176 }
1177 if (info.isFailover()) {
1178 intent.putExtra(ConnectivityManager.EXTRA_IS_FAILOVER, true);
1179 info.setFailover(false);
1180 }
Robert Greenwaltda03c4e2010-01-20 19:29:41 -08001181
Robert Greenwaltcc4b4012010-01-25 17:54:29 -08001182 NetworkStateTracker newNet = null;
1183 if (mNetAttributes[info.getType()].isDefault()) {
1184 newNet = tryFailover(info.getType());
1185 if (newNet != null) {
1186 NetworkInfo switchTo = newNet.getNetworkInfo();
Robert Greenwalt029be812010-09-20 18:01:43 -07001187 if (!switchTo.isConnected()) {
1188 // if the other net is connected they've already reset this and perhaps even gotten
1189 // a positive report we don't want to overwrite, but if not we need to clear this now
1190 // to turn our cellular sig strength white
1191 mDefaultInetConditionPublished = 0;
1192 }
Robert Greenwaltcc4b4012010-01-25 17:54:29 -08001193 intent.putExtra(ConnectivityManager.EXTRA_OTHER_NETWORK_INFO, switchTo);
1194 } else {
Robert Greenwalt029be812010-09-20 18:01:43 -07001195 mDefaultInetConditionPublished = 0;
Robert Greenwaltcc4b4012010-01-25 17:54:29 -08001196 intent.putExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, true);
1197 }
Robert Greenwaltda03c4e2010-01-20 19:29:41 -08001198 }
Robert Greenwaltcc4b4012010-01-25 17:54:29 -08001199
Robert Greenwalt029be812010-09-20 18:01:43 -07001200 intent.putExtra(ConnectivityManager.EXTRA_INET_CONDITION, mDefaultInetConditionPublished);
Mike Lockwood0f79b542009-08-14 14:18:49 -04001201 sendStickyBroadcast(intent);
Robert Greenwaltda03c4e2010-01-20 19:29:41 -08001202 /*
1203 * If the failover network is already connected, then immediately send
1204 * out a followup broadcast indicating successful failover
1205 */
1206 if (newNet != null && newNet.getNetworkInfo().isConnected()) {
1207 sendConnectedBroadcast(newNet.getNetworkInfo());
1208 }
Mike Lockwood0f79b542009-08-14 14:18:49 -04001209 }
1210
1211 private void sendStickyBroadcast(Intent intent) {
1212 synchronized(this) {
Dianne Hackborn1c633fc2009-12-08 19:45:14 -08001213 if (!mSystemReady) {
1214 mInitialBroadcast = new Intent(intent);
Mike Lockwood0f79b542009-08-14 14:18:49 -04001215 }
Dianne Hackborn1c633fc2009-12-08 19:45:14 -08001216 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
1217 mContext.sendStickyBroadcast(intent);
Mike Lockwood0f79b542009-08-14 14:18:49 -04001218 }
1219 }
1220
1221 void systemReady() {
1222 synchronized(this) {
1223 mSystemReady = true;
Dianne Hackborn1c633fc2009-12-08 19:45:14 -08001224 if (mInitialBroadcast != null) {
1225 mContext.sendStickyBroadcast(mInitialBroadcast);
1226 mInitialBroadcast = null;
Mike Lockwood0f79b542009-08-14 14:18:49 -04001227 }
1228 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001229 }
1230
1231 private void handleConnect(NetworkInfo info) {
Robert Greenwalt42acef32009-08-12 16:08:25 -07001232 int type = info.getType();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001233
1234 // snapshot isFailover, because sendConnectedBroadcast() resets it
1235 boolean isFailover = info.isFailover();
Robert Greenwalt42acef32009-08-12 16:08:25 -07001236 NetworkStateTracker thisNet = mNetTrackers[type];
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001237
Robert Greenwalt42acef32009-08-12 16:08:25 -07001238 // if this is a default net and other default is running
1239 // kill the one not preferred
1240 if (mNetAttributes[type].isDefault()) {
Robert Greenwalt42acef32009-08-12 16:08:25 -07001241 if (mActiveDefaultNetwork != -1 && mActiveDefaultNetwork != type) {
1242 if ((type != mNetworkPreference &&
1243 mNetAttributes[mActiveDefaultNetwork].mPriority >
1244 mNetAttributes[type].mPriority) ||
1245 mNetworkPreference == mActiveDefaultNetwork) {
1246 // don't accept this one
Joe Onorato8a9b2202010-02-26 18:56:32 -08001247 if (DBG) Slog.v(TAG, "Not broadcasting CONNECT_ACTION " +
Robert Greenwalt42acef32009-08-12 16:08:25 -07001248 "to torn down network " + info.getTypeName());
1249 teardown(thisNet);
1250 return;
1251 } else {
1252 // tear down the other
1253 NetworkStateTracker otherNet =
1254 mNetTrackers[mActiveDefaultNetwork];
Joe Onorato8a9b2202010-02-26 18:56:32 -08001255 if (DBG) Slog.v(TAG, "Policy requires " +
Robert Greenwalt42acef32009-08-12 16:08:25 -07001256 otherNet.getNetworkInfo().getTypeName() +
1257 " teardown");
1258 if (!teardown(otherNet)) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001259 Slog.e(TAG, "Network declined teardown request");
Robert Greenwalt42acef32009-08-12 16:08:25 -07001260 return;
1261 }
Robert Greenwalt14f2ef42010-06-15 12:19:37 -07001262 }
1263 }
1264 synchronized (ConnectivityService.this) {
1265 // have a new default network, release the transition wakelock in a second
1266 // if it's held. The second pause is to allow apps to reconnect over the
1267 // new network
1268 if (mNetTransitionWakeLock.isHeld()) {
1269 mHandler.sendMessageDelayed(mHandler.obtainMessage(
1270 NetworkStateTracker.EVENT_CLEAR_NET_TRANSITION_WAKELOCK,
1271 mNetTransitionWakeLockSerialNumber, 0),
1272 1000);
Robert Greenwalt42acef32009-08-12 16:08:25 -07001273 }
1274 }
1275 mActiveDefaultNetwork = type;
Robert Greenwaltd7085fc2010-09-08 15:24:47 -07001276 // this will cause us to come up initially as unconnected and switching
1277 // to connected after our normal pause unless somebody reports us as reall
1278 // disconnected
1279 mDefaultInetConditionPublished = 0;
1280 mDefaultConnectionSequence++;
1281 mInetConditionChangeInFlight = false;
1282 // Don't do this - if we never sign in stay, grey
1283 //reportNetworkCondition(mActiveDefaultNetwork, 100);
Robert Greenwalt42acef32009-08-12 16:08:25 -07001284 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001285 thisNet.setTeardownRequested(false);
Irfan Sheriffd649c122010-06-09 15:39:36 -07001286 updateNetworkSettings(thisNet);
Robert Greenwaltc76b8fa2010-07-23 15:46:26 -07001287 handleConnectivityChange(type);
Robert Greenwalt42acef32009-08-12 16:08:25 -07001288 sendConnectedBroadcast(info);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001289 }
1290
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001291 /**
Robert Greenwaltc76b8fa2010-07-23 15:46:26 -07001292 * After a change in the connectivity state of a network. We're mainly
1293 * concerned with making sure that the list of DNS servers is set up
1294 * according to which networks are connected, and ensuring that the
1295 * right routing table entries exist.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001296 */
Robert Greenwaltc76b8fa2010-07-23 15:46:26 -07001297 private void handleConnectivityChange(int netType) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001298 /*
Robert Greenwalt42acef32009-08-12 16:08:25 -07001299 * If a non-default network is enabled, add the host routes that
Robert Greenwaltc76b8fa2010-07-23 15:46:26 -07001300 * will allow it's DNS servers to be accessed.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001301 */
Robert Greenwaltc76b8fa2010-07-23 15:46:26 -07001302 handleDnsConfigurationChange(netType);
Robert Greenwalt42acef32009-08-12 16:08:25 -07001303
Robert Greenwaltc76b8fa2010-07-23 15:46:26 -07001304 if (mNetTrackers[netType].getNetworkInfo().isConnected()) {
1305 if (mNetAttributes[netType].isDefault()) {
1306 addDefaultRoute(mNetTrackers[netType]);
Robert Greenwalt42acef32009-08-12 16:08:25 -07001307 } else {
Robert Greenwaltc76b8fa2010-07-23 15:46:26 -07001308 addPrivateDnsRoutes(mNetTrackers[netType]);
1309 }
1310 } else {
1311 if (mNetAttributes[netType].isDefault()) {
1312 removeDefaultRoute(mNetTrackers[netType]);
1313 } else {
1314 removePrivateDnsRoutes(mNetTrackers[netType]);
Robert Greenwalt42acef32009-08-12 16:08:25 -07001315 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001316 }
1317 }
1318
Irfan Sheriffd649c122010-06-09 15:39:36 -07001319 private void addPrivateDnsRoutes(NetworkStateTracker nt) {
Irfan Sheriffd649c122010-06-09 15:39:36 -07001320 boolean privateDnsRouteSet = nt.isPrivateDnsRouteSet();
Robert Greenwalt37e65eb2010-08-30 10:56:47 -07001321 LinkProperties p = nt.getLinkProperties();
Robert Greenwalt47f69fe2010-06-15 15:43:39 -07001322 if (p == null) return;
1323 String interfaceName = p.getInterfaceName();
Irfan Sheriffd649c122010-06-09 15:39:36 -07001324
1325 if (DBG) {
1326 Slog.d(TAG, "addPrivateDnsRoutes for " + nt +
1327 "(" + interfaceName + ") - mPrivateDnsRouteSet = " + privateDnsRouteSet);
1328 }
Irfan Sheriffd649c122010-06-09 15:39:36 -07001329 if (interfaceName != null && !privateDnsRouteSet) {
Robert Greenwalt47f69fe2010-06-15 15:43:39 -07001330 Collection<InetAddress> dnsList = p.getDnses();
1331 for (InetAddress dns : dnsList) {
1332 if (DBG) Slog.d(TAG, " adding " + dns);
Robert Greenwalt585ac0f2010-08-27 09:24:29 -07001333 NetworkUtils.addHostRoute(interfaceName, dns, null);
Irfan Sheriffd649c122010-06-09 15:39:36 -07001334 }
1335 nt.privateDnsRouteSet(true);
1336 }
1337 }
1338
1339 private void removePrivateDnsRoutes(NetworkStateTracker nt) {
1340 // TODO - we should do this explicitly but the NetUtils api doesnt
1341 // support this yet - must remove all. No worse than before
Robert Greenwalt37e65eb2010-08-30 10:56:47 -07001342 LinkProperties p = nt.getLinkProperties();
Robert Greenwalt47f69fe2010-06-15 15:43:39 -07001343 if (p == null) return;
1344 String interfaceName = p.getInterfaceName();
Irfan Sheriffd649c122010-06-09 15:39:36 -07001345 boolean privateDnsRouteSet = nt.isPrivateDnsRouteSet();
1346 if (interfaceName != null && privateDnsRouteSet) {
1347 if (DBG) {
1348 Slog.d(TAG, "removePrivateDnsRoutes for " + nt.getNetworkInfo().getTypeName() +
1349 " (" + interfaceName + ")");
1350 }
1351 NetworkUtils.removeHostRoutes(interfaceName);
1352 nt.privateDnsRouteSet(false);
1353 }
1354 }
1355
Irfan Sheriffd649c122010-06-09 15:39:36 -07001356
1357 private void addDefaultRoute(NetworkStateTracker nt) {
Robert Greenwalt37e65eb2010-08-30 10:56:47 -07001358 LinkProperties p = nt.getLinkProperties();
Robert Greenwalt47f69fe2010-06-15 15:43:39 -07001359 if (p == null) return;
1360 String interfaceName = p.getInterfaceName();
1361 InetAddress defaultGatewayAddr = p.getGateway();
Irfan Sheriffd649c122010-06-09 15:39:36 -07001362
Robert Greenwaltc76b8fa2010-07-23 15:46:26 -07001363 if ((interfaceName != null) && (defaultGatewayAddr != null )) {
Robert Greenwalt585ac0f2010-08-27 09:24:29 -07001364 if (!NetworkUtils.addDefaultRoute(interfaceName, defaultGatewayAddr) && DBG) {
Robert Greenwalt47f69fe2010-06-15 15:43:39 -07001365 NetworkInfo networkInfo = nt.getNetworkInfo();
Irfan Sheriffd649c122010-06-09 15:39:36 -07001366 Slog.d(TAG, "addDefaultRoute for " + networkInfo.getTypeName() +
1367 " (" + interfaceName + "), GatewayAddr=" + defaultGatewayAddr);
1368 }
Irfan Sheriffd649c122010-06-09 15:39:36 -07001369 }
1370 }
1371
1372
1373 public void removeDefaultRoute(NetworkStateTracker nt) {
Robert Greenwalt37e65eb2010-08-30 10:56:47 -07001374 LinkProperties p = nt.getLinkProperties();
Robert Greenwalt47f69fe2010-06-15 15:43:39 -07001375 if (p == null) return;
1376 String interfaceName = p.getInterfaceName();
Irfan Sheriffd649c122010-06-09 15:39:36 -07001377
Robert Greenwaltc76b8fa2010-07-23 15:46:26 -07001378 if (interfaceName != null) {
1379 if ((NetworkUtils.removeDefaultRoute(interfaceName) >= 0) && DBG) {
Robert Greenwalt47f69fe2010-06-15 15:43:39 -07001380 NetworkInfo networkInfo = nt.getNetworkInfo();
Irfan Sheriffd649c122010-06-09 15:39:36 -07001381 Slog.d(TAG, "removeDefaultRoute for " + networkInfo.getTypeName() + " (" +
1382 interfaceName + ")");
1383 }
Irfan Sheriffd649c122010-06-09 15:39:36 -07001384 }
1385 }
1386
1387 /**
1388 * Reads the network specific TCP buffer sizes from SystemProperties
1389 * net.tcp.buffersize.[default|wifi|umts|edge|gprs] and set them for system
1390 * wide use
1391 */
1392 public void updateNetworkSettings(NetworkStateTracker nt) {
1393 String key = nt.getTcpBufferSizesPropName();
1394 String bufferSizes = SystemProperties.get(key);
1395
1396 if (bufferSizes.length() == 0) {
1397 Slog.e(TAG, key + " not found in system properties. Using defaults");
1398
1399 // Setting to default values so we won't be stuck to previous values
1400 key = "net.tcp.buffersize.default";
1401 bufferSizes = SystemProperties.get(key);
1402 }
1403
1404 // Set values in kernel
1405 if (bufferSizes.length() != 0) {
1406 if (DBG) {
1407 Slog.v(TAG, "Setting TCP values: [" + bufferSizes
1408 + "] which comes from [" + key + "]");
1409 }
1410 setBufferSize(bufferSizes);
1411 }
1412 }
1413
1414 /**
1415 * Writes TCP buffer sizes to /sys/kernel/ipv4/tcp_[r/w]mem_[min/def/max]
1416 * which maps to /proc/sys/net/ipv4/tcp_rmem and tcpwmem
1417 *
1418 * @param bufferSizes in the format of "readMin, readInitial, readMax,
1419 * writeMin, writeInitial, writeMax"
1420 */
1421 private void setBufferSize(String bufferSizes) {
1422 try {
1423 String[] values = bufferSizes.split(",");
1424
1425 if (values.length == 6) {
1426 final String prefix = "/sys/kernel/ipv4/tcp_";
1427 stringToFile(prefix + "rmem_min", values[0]);
1428 stringToFile(prefix + "rmem_def", values[1]);
1429 stringToFile(prefix + "rmem_max", values[2]);
1430 stringToFile(prefix + "wmem_min", values[3]);
1431 stringToFile(prefix + "wmem_def", values[4]);
1432 stringToFile(prefix + "wmem_max", values[5]);
1433 } else {
1434 Slog.e(TAG, "Invalid buffersize string: " + bufferSizes);
1435 }
1436 } catch (IOException e) {
1437 Slog.e(TAG, "Can't set tcp buffer sizes:" + e);
1438 }
1439 }
1440
1441 /**
1442 * Writes string to file. Basically same as "echo -n $string > $filename"
1443 *
1444 * @param filename
1445 * @param string
1446 * @throws IOException
1447 */
1448 private void stringToFile(String filename, String string) throws IOException {
1449 FileWriter out = new FileWriter(filename);
1450 try {
1451 out.write(string);
1452 } finally {
1453 out.close();
1454 }
1455 }
1456
1457
Robert Greenwalt42acef32009-08-12 16:08:25 -07001458 /**
1459 * Adjust the per-process dns entries (net.dns<x>.<pid>) based
1460 * on the highest priority active net which this process requested.
1461 * If there aren't any, clear it out
1462 */
1463 private void reassessPidDns(int myPid, boolean doBump)
1464 {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001465 if (DBG) Slog.d(TAG, "reassessPidDns for pid " + myPid);
Robert Greenwalt42acef32009-08-12 16:08:25 -07001466 for(int i : mPriorityList) {
1467 if (mNetAttributes[i].isDefault()) {
1468 continue;
1469 }
1470 NetworkStateTracker nt = mNetTrackers[i];
Robert Greenwalt86e9e552009-07-16 17:21:39 -07001471 if (nt.getNetworkInfo().isConnected() &&
1472 !nt.isTeardownRequested()) {
Robert Greenwalt37e65eb2010-08-30 10:56:47 -07001473 LinkProperties p = nt.getLinkProperties();
Robert Greenwalt47f69fe2010-06-15 15:43:39 -07001474 if (p == null) continue;
Robert Greenwalt42acef32009-08-12 16:08:25 -07001475 List pids = mNetRequestersPids[i];
1476 for (int j=0; j<pids.size(); j++) {
1477 Integer pid = (Integer)pids.get(j);
1478 if (pid.intValue() == myPid) {
Robert Greenwalt47f69fe2010-06-15 15:43:39 -07001479 Collection<InetAddress> dnses = p.getDnses();
1480 writePidDns(dnses, myPid);
Robert Greenwalt42acef32009-08-12 16:08:25 -07001481 if (doBump) {
1482 bumpDns();
1483 }
1484 return;
1485 }
1486 }
1487 }
1488 }
1489 // nothing found - delete
1490 for (int i = 1; ; i++) {
1491 String prop = "net.dns" + i + "." + myPid;
1492 if (SystemProperties.get(prop).length() == 0) {
1493 if (doBump) {
1494 bumpDns();
1495 }
1496 return;
1497 }
1498 SystemProperties.set(prop, "");
1499 }
1500 }
1501
Robert Greenwalt47f69fe2010-06-15 15:43:39 -07001502 private void writePidDns(Collection <InetAddress> dnses, int pid) {
Robert Greenwalt42acef32009-08-12 16:08:25 -07001503 int j = 1;
Robert Greenwalt47f69fe2010-06-15 15:43:39 -07001504 for (InetAddress dns : dnses) {
1505 SystemProperties.set("net.dns" + j++ + "." + pid, dns.getHostAddress());
Robert Greenwalt42acef32009-08-12 16:08:25 -07001506 }
1507 }
1508
1509 private void bumpDns() {
1510 /*
1511 * Bump the property that tells the name resolver library to reread
1512 * the DNS server list from the properties.
1513 */
1514 String propVal = SystemProperties.get("net.dnschange");
1515 int n = 0;
1516 if (propVal.length() != 0) {
1517 try {
1518 n = Integer.parseInt(propVal);
1519 } catch (NumberFormatException e) {}
1520 }
1521 SystemProperties.set("net.dnschange", "" + (n+1));
1522 }
1523
Robert Greenwaltc76b8fa2010-07-23 15:46:26 -07001524 private void handleDnsConfigurationChange(int netType) {
Robert Greenwalt42acef32009-08-12 16:08:25 -07001525 // add default net's dns entries
Robert Greenwaltc76b8fa2010-07-23 15:46:26 -07001526 NetworkStateTracker nt = mNetTrackers[netType];
1527 if (nt != null && nt.getNetworkInfo().isConnected() && !nt.isTeardownRequested()) {
Robert Greenwalt37e65eb2010-08-30 10:56:47 -07001528 LinkProperties p = nt.getLinkProperties();
Robert Greenwaltc76b8fa2010-07-23 15:46:26 -07001529 if (p == null) return;
1530 Collection<InetAddress> dnses = p.getDnses();
1531 if (mNetAttributes[netType].isDefault()) {
1532 int j = 1;
Robert Greenwalte90aa5e2010-09-01 11:34:05 -07001533 if (dnses.size() == 0 && mDefaultDns != null) {
Robert Greenwaltc76b8fa2010-07-23 15:46:26 -07001534 if (DBG) {
Robert Greenwalte90aa5e2010-09-01 11:34:05 -07001535 Slog.d(TAG, "no dns provided - using " + mDefaultDns.getHostAddress());
Robert Greenwalt42acef32009-08-12 16:08:25 -07001536 }
Robert Greenwalte90aa5e2010-09-01 11:34:05 -07001537 SystemProperties.set("net.dns1", mDefaultDns.getHostAddress());
1538 j++;
1539 } else {
1540 for (InetAddress dns : dnses) {
1541 if (DBG) {
1542 Slog.d(TAG, "adding dns " + dns + " for " +
1543 nt.getNetworkInfo().getTypeName());
1544 }
1545 SystemProperties.set("net.dns" + j++, dns.getHostAddress());
1546 }
Robert Greenwaltc76b8fa2010-07-23 15:46:26 -07001547 }
1548 for (int k=j ; k<mNumDnsEntries; k++) {
1549 if (DBG) Slog.d(TAG, "erasing net.dns" + k);
1550 SystemProperties.set("net.dns" + k, "");
1551 }
1552 mNumDnsEntries = j;
1553 } else {
1554 // set per-pid dns for attached secondary nets
1555 List pids = mNetRequestersPids[netType];
1556 for (int y=0; y< pids.size(); y++) {
1557 Integer pid = (Integer)pids.get(y);
1558 writePidDns(dnses, pid.intValue());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001559 }
1560 }
Robert Greenwaltc76b8fa2010-07-23 15:46:26 -07001561 bumpDns();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001562 }
Robert Greenwalt42acef32009-08-12 16:08:25 -07001563 }
1564
1565 private int getRestoreDefaultNetworkDelay() {
1566 String restoreDefaultNetworkDelayStr = SystemProperties.get(
1567 NETWORK_RESTORE_DELAY_PROP_NAME);
1568 if(restoreDefaultNetworkDelayStr != null &&
1569 restoreDefaultNetworkDelayStr.length() != 0) {
1570 try {
1571 return Integer.valueOf(restoreDefaultNetworkDelayStr);
1572 } catch (NumberFormatException e) {
1573 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001574 }
Robert Greenwalt42acef32009-08-12 16:08:25 -07001575 return RESTORE_DEFAULT_NETWORK_DELAY;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001576 }
1577
1578 @Override
1579 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
Robert Greenwalt86e9e552009-07-16 17:21:39 -07001580 if (mContext.checkCallingOrSelfPermission(
1581 android.Manifest.permission.DUMP)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001582 != PackageManager.PERMISSION_GRANTED) {
Robert Greenwalt86e9e552009-07-16 17:21:39 -07001583 pw.println("Permission Denial: can't dump ConnectivityService " +
1584 "from from pid=" + Binder.getCallingPid() + ", uid=" +
1585 Binder.getCallingUid());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001586 return;
1587 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001588 pw.println();
1589 for (NetworkStateTracker nst : mNetTrackers) {
Robert Greenwaltb9285352009-12-21 18:24:07 -08001590 if (nst != null) {
1591 if (nst.getNetworkInfo().isConnected()) {
1592 pw.println("Active network: " + nst.getNetworkInfo().
1593 getTypeName());
1594 }
1595 pw.println(nst.getNetworkInfo());
1596 pw.println(nst);
1597 pw.println();
Robert Greenwalt42acef32009-08-12 16:08:25 -07001598 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001599 }
Robert Greenwaltb9285352009-12-21 18:24:07 -08001600
1601 pw.println("Network Requester Pids:");
1602 for (int net : mPriorityList) {
1603 String pidString = net + ": ";
1604 for (Object pid : mNetRequestersPids[net]) {
1605 pidString = pidString + pid.toString() + ", ";
1606 }
1607 pw.println(pidString);
1608 }
1609 pw.println();
1610
1611 pw.println("FeatureUsers:");
1612 for (Object requester : mFeatureUsers) {
1613 pw.println(requester.toString());
1614 }
1615 pw.println();
Robert Greenwalt2a091d72010-02-11 18:18:40 -08001616
Robert Greenwalt14f2ef42010-06-15 12:19:37 -07001617 synchronized (this) {
1618 pw.println("NetworkTranstionWakeLock is currently " +
1619 (mNetTransitionWakeLock.isHeld() ? "" : "not ") + "held.");
1620 pw.println("It was last requested for "+mNetTransitionWakeLockCausedBy);
1621 }
1622 pw.println();
1623
Robert Greenwalt2a091d72010-02-11 18:18:40 -08001624 mTethering.dump(fd, pw, args);
Robert Greenwalt4e8dfef2010-09-20 14:35:25 -07001625
1626 if (mInetLog != null) {
1627 pw.println();
1628 pw.println("Inet condition reports:");
1629 for(int i = 0; i < mInetLog.size(); i++) {
1630 pw.println(mInetLog.get(i));
1631 }
1632 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001633 }
1634
Robert Greenwalt42acef32009-08-12 16:08:25 -07001635 // must be stateless - things change under us.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001636 private class MyHandler extends Handler {
Wink Savillebb08caf2010-09-02 19:23:52 -07001637 public MyHandler(Looper looper) {
1638 super(looper);
1639 }
1640
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001641 @Override
1642 public void handleMessage(Message msg) {
1643 NetworkInfo info;
1644 switch (msg.what) {
1645 case NetworkStateTracker.EVENT_STATE_CHANGED:
1646 info = (NetworkInfo) msg.obj;
Robert Greenwalt511288a2009-12-07 11:33:18 -08001647 int type = info.getType();
1648 NetworkInfo.State state = info.getState();
Robert Greenwalt6e6dec22010-01-25 16:14:00 -08001649 // only do this optimization for wifi. It going into scan mode for location
1650 // services generates alot of noise. Meanwhile the mms apn won't send out
1651 // subsequent notifications when on default cellular because it never
1652 // disconnects.. so only do this to wifi notifications. Fixed better when the
1653 // APN notifications are standardized.
1654 if (mNetAttributes[type].mLastState == state &&
1655 mNetAttributes[type].mRadio == ConnectivityManager.TYPE_WIFI) {
Robert Greenwalt511288a2009-12-07 11:33:18 -08001656 if (DBG) {
Robert Greenwalt6e6dec22010-01-25 16:14:00 -08001657 // TODO - remove this after we validate the dropping doesn't break
1658 // anything
Joe Onorato8a9b2202010-02-26 18:56:32 -08001659 Slog.d(TAG, "Dropping ConnectivityChange for " +
Robert Greenwalt1193ae42010-01-13 09:36:31 -08001660 info.getTypeName() + ": " +
Robert Greenwalt511288a2009-12-07 11:33:18 -08001661 state + "/" + info.getDetailedState());
1662 }
1663 return;
1664 }
1665 mNetAttributes[type].mLastState = state;
1666
Joe Onorato8a9b2202010-02-26 18:56:32 -08001667 if (DBG) Slog.d(TAG, "ConnectivityChange for " +
Robert Greenwalt86e9e552009-07-16 17:21:39 -07001668 info.getTypeName() + ": " +
Robert Greenwalt511288a2009-12-07 11:33:18 -08001669 state + "/" + info.getDetailedState());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001670
1671 // Connectivity state changed:
1672 // [31-13] Reserved for future use
Robert Greenwalt86e9e552009-07-16 17:21:39 -07001673 // [12-9] Network subtype (for mobile network, as defined
1674 // by TelephonyManager)
1675 // [8-3] Detailed state ordinal (as defined by
1676 // NetworkInfo.DetailedState)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001677 // [2-0] Network type (as defined by ConnectivityManager)
1678 int eventLogParam = (info.getType() & 0x7) |
1679 ((info.getDetailedState().ordinal() & 0x3f) << 3) |
1680 (info.getSubtype() << 9);
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001681 EventLog.writeEvent(EventLogTags.CONNECTIVITY_STATE_CHANGED,
Robert Greenwalt86e9e552009-07-16 17:21:39 -07001682 eventLogParam);
1683
1684 if (info.getDetailedState() ==
1685 NetworkInfo.DetailedState.FAILED) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001686 handleConnectionFailure(info);
Robert Greenwalt511288a2009-12-07 11:33:18 -08001687 } else if (state == NetworkInfo.State.DISCONNECTED) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001688 handleDisconnect(info);
Robert Greenwalt511288a2009-12-07 11:33:18 -08001689 } else if (state == NetworkInfo.State.SUSPENDED) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001690 // TODO: need to think this over.
Robert Greenwalt86e9e552009-07-16 17:21:39 -07001691 // the logic here is, handle SUSPENDED the same as
1692 // DISCONNECTED. The only difference being we are
1693 // broadcasting an intent with NetworkInfo that's
1694 // suspended. This allows the applications an
1695 // opportunity to handle DISCONNECTED and SUSPENDED
1696 // differently, or not.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001697 handleDisconnect(info);
Robert Greenwalt511288a2009-12-07 11:33:18 -08001698 } else if (state == NetworkInfo.State.CONNECTED) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001699 handleConnect(info);
1700 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001701 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001702 case NetworkStateTracker.EVENT_CONFIGURATION_CHANGED:
Robert Greenwaltc76b8fa2010-07-23 15:46:26 -07001703 // TODO - make this handle ip/proxy/gateway/dns changes
1704 info = (NetworkInfo) msg.obj;
1705 type = info.getType();
1706 handleDnsConfigurationChange(type);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001707 break;
Robert Greenwalt42acef32009-08-12 16:08:25 -07001708 case NetworkStateTracker.EVENT_RESTORE_DEFAULT_NETWORK:
Robert Greenwalt9c75d4a2009-09-27 17:27:04 -07001709 FeatureUser u = (FeatureUser)msg.obj;
1710 u.expire();
Robert Greenwalt42acef32009-08-12 16:08:25 -07001711 break;
Robert Greenwalt14f2ef42010-06-15 12:19:37 -07001712 case NetworkStateTracker.EVENT_CLEAR_NET_TRANSITION_WAKELOCK:
1713 String causedBy = null;
1714 synchronized (ConnectivityService.this) {
1715 if (msg.arg1 == mNetTransitionWakeLockSerialNumber &&
1716 mNetTransitionWakeLock.isHeld()) {
1717 mNetTransitionWakeLock.release();
1718 causedBy = mNetTransitionWakeLockCausedBy;
1719 }
1720 }
1721 if (causedBy != null) {
1722 Slog.d(TAG, "NetTransition Wakelock for " +
1723 causedBy + " released by timeout");
1724 }
Robert Greenwalt057d5e92010-09-09 14:05:10 -07001725 break;
Robert Greenwaltd7085fc2010-09-08 15:24:47 -07001726 case NetworkStateTracker.EVENT_INET_CONDITION_CHANGE:
1727 if (DBG) {
1728 Slog.d(TAG, "Inet connectivity change, net=" +
1729 msg.arg1 + ", condition=" + msg.arg2 +
1730 ",mActiveDefaultNetwork=" + mActiveDefaultNetwork);
1731 }
1732 if (mActiveDefaultNetwork == -1) {
1733 if (DBG) Slog.d(TAG, "no active default network - aborting");
1734 break;
1735 }
1736 if (mActiveDefaultNetwork != msg.arg1) {
1737 if (DBG) Slog.d(TAG, "given net not default - aborting");
1738 break;
1739 }
1740 mDefaultInetCondition = msg.arg2;
1741 int delay;
1742 if (mInetConditionChangeInFlight == false) {
1743 if (DBG) Slog.d(TAG, "starting a change hold");
1744 // setup a new hold to debounce this
1745 if (mDefaultInetCondition > 50) {
1746 delay = Settings.Secure.getInt(mContext.getContentResolver(),
1747 Settings.Secure.INET_CONDITION_DEBOUNCE_UP_DELAY, 500);
1748 } else {
1749 delay = Settings.Secure.getInt(mContext.getContentResolver(),
1750 Settings.Secure.INET_CONDITION_DEBOUNCE_DOWN_DELAY, 3000);
1751 }
1752 mInetConditionChangeInFlight = true;
1753 sendMessageDelayed(obtainMessage(
1754 NetworkStateTracker.EVENT_INET_CONDITION_HOLD_END,
1755 mActiveDefaultNetwork, mDefaultConnectionSequence), delay);
1756 } else {
1757 // we've set the new condition, when this hold ends that will get
1758 // picked up
1759 if (DBG) Slog.d(TAG, "currently in hold - not setting new end evt");
1760 }
1761 break;
1762 case NetworkStateTracker.EVENT_INET_CONDITION_HOLD_END:
1763 if (DBG) {
1764 Slog.d(TAG, "Inet hold end, net=" + msg.arg1 +
1765 ", condition =" + mDefaultInetCondition +
1766 ", published condition =" + mDefaultInetConditionPublished);
1767 }
1768 mInetConditionChangeInFlight = false;
1769
1770 if (mActiveDefaultNetwork == -1) {
1771 if (DBG) Slog.d(TAG, "no active default network - aborting");
1772 break;
1773 }
1774 if (mDefaultConnectionSequence != msg.arg2) {
1775 if (DBG) Slog.d(TAG, "event hold for obsolete network - aborting");
1776 break;
1777 }
1778 if (mDefaultInetConditionPublished == mDefaultInetCondition) {
1779 if (DBG) Slog.d(TAG, "no change in condition - aborting");
1780 break;
1781 }
1782 NetworkInfo networkInfo = mNetTrackers[mActiveDefaultNetwork].getNetworkInfo();
1783 if (networkInfo.isConnected() == false) {
1784 if (DBG) Slog.d(TAG, "default network not connected - aborting");
1785 break;
1786 }
1787 mDefaultInetConditionPublished = mDefaultInetCondition;
Robert Greenwalt1e9aac22010-09-15 17:36:33 -07001788 sendInetConditionBroadcast(networkInfo);
Robert Greenwalt14f2ef42010-06-15 12:19:37 -07001789 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001790 }
1791 }
1792 }
Robert Greenwaltd0e18ff2010-01-26 11:40:34 -08001793
1794 // javadoc from interface
Robert Greenwalt5a735062010-03-02 17:25:02 -08001795 public int tether(String iface) {
Robert Greenwaltd0e18ff2010-01-26 11:40:34 -08001796 enforceTetherChangePermission();
Robert Greenwalt5a735062010-03-02 17:25:02 -08001797
1798 if (isTetheringSupported()) {
1799 return mTethering.tether(iface);
1800 } else {
1801 return ConnectivityManager.TETHER_ERROR_UNSUPPORTED;
1802 }
Robert Greenwaltd0e18ff2010-01-26 11:40:34 -08001803 }
1804
1805 // javadoc from interface
Robert Greenwalt5a735062010-03-02 17:25:02 -08001806 public int untether(String iface) {
Robert Greenwaltd0e18ff2010-01-26 11:40:34 -08001807 enforceTetherChangePermission();
Robert Greenwalt5a735062010-03-02 17:25:02 -08001808
1809 if (isTetheringSupported()) {
1810 return mTethering.untether(iface);
1811 } else {
1812 return ConnectivityManager.TETHER_ERROR_UNSUPPORTED;
1813 }
1814 }
1815
1816 // javadoc from interface
1817 public int getLastTetherError(String iface) {
1818 enforceTetherAccessPermission();
1819
1820 if (isTetheringSupported()) {
1821 return mTethering.getLastTetherError(iface);
1822 } else {
1823 return ConnectivityManager.TETHER_ERROR_UNSUPPORTED;
1824 }
Robert Greenwalt2a091d72010-02-11 18:18:40 -08001825 }
1826
1827 // TODO - proper iface API for selection by property, inspection, etc
1828 public String[] getTetherableUsbRegexs() {
1829 enforceTetherAccessPermission();
1830 if (isTetheringSupported()) {
1831 return mTethering.getTetherableUsbRegexs();
1832 } else {
1833 return new String[0];
1834 }
1835 }
1836
1837 public String[] getTetherableWifiRegexs() {
1838 enforceTetherAccessPermission();
1839 if (isTetheringSupported()) {
1840 return mTethering.getTetherableWifiRegexs();
1841 } else {
1842 return new String[0];
1843 }
Robert Greenwaltd0e18ff2010-01-26 11:40:34 -08001844 }
1845
Danica Chang6fdd0c62010-08-11 14:54:43 -07001846 public String[] getTetherableBluetoothRegexs() {
1847 enforceTetherAccessPermission();
1848 if (isTetheringSupported()) {
1849 return mTethering.getTetherableBluetoothRegexs();
1850 } else {
1851 return new String[0];
1852 }
1853 }
1854
Robert Greenwaltd0e18ff2010-01-26 11:40:34 -08001855 // TODO - move iface listing, queries, etc to new module
1856 // javadoc from interface
1857 public String[] getTetherableIfaces() {
Robert Greenwalt2a091d72010-02-11 18:18:40 -08001858 enforceTetherAccessPermission();
Robert Greenwaltd0e18ff2010-01-26 11:40:34 -08001859 return mTethering.getTetherableIfaces();
1860 }
1861
1862 public String[] getTetheredIfaces() {
Robert Greenwalt2a091d72010-02-11 18:18:40 -08001863 enforceTetherAccessPermission();
Robert Greenwaltd0e18ff2010-01-26 11:40:34 -08001864 return mTethering.getTetheredIfaces();
1865 }
Robert Greenwalt2a091d72010-02-11 18:18:40 -08001866
Robert Greenwalt5a735062010-03-02 17:25:02 -08001867 public String[] getTetheringErroredIfaces() {
1868 enforceTetherAccessPermission();
1869 return mTethering.getErroredIfaces();
1870 }
1871
Robert Greenwalt2a091d72010-02-11 18:18:40 -08001872 // if ro.tether.denied = true we default to no tethering
1873 // gservices could set the secure setting to 1 though to enable it on a build where it
1874 // had previously been turned off.
1875 public boolean isTetheringSupported() {
1876 enforceTetherAccessPermission();
1877 int defaultVal = (SystemProperties.get("ro.tether.denied").equals("true") ? 0 : 1);
Robert Greenwaltc9d5fb72010-02-25 12:29:30 -08001878 boolean tetherEnabledInSettings = (Settings.Secure.getInt(mContext.getContentResolver(),
1879 Settings.Secure.TETHER_SUPPORTED, defaultVal) != 0);
1880 return tetherEnabledInSettings && mTetheringConfigValid;
Robert Greenwalt2a091d72010-02-11 18:18:40 -08001881 }
Robert Greenwalt14f2ef42010-06-15 12:19:37 -07001882
1883 // An API NetworkStateTrackers can call when they lose their network.
1884 // This will automatically be cleared after X seconds or a network becomes CONNECTED,
1885 // whichever happens first. The timer is started by the first caller and not
1886 // restarted by subsequent callers.
1887 public void requestNetworkTransitionWakelock(String forWhom) {
1888 enforceConnectivityInternalPermission();
1889 synchronized (this) {
1890 if (mNetTransitionWakeLock.isHeld()) return;
1891 mNetTransitionWakeLockSerialNumber++;
1892 mNetTransitionWakeLock.acquire();
1893 mNetTransitionWakeLockCausedBy = forWhom;
1894 }
1895 mHandler.sendMessageDelayed(mHandler.obtainMessage(
1896 NetworkStateTracker.EVENT_CLEAR_NET_TRANSITION_WAKELOCK,
1897 mNetTransitionWakeLockSerialNumber, 0),
1898 mNetTransitionWakeLockTimeout);
1899 return;
1900 }
Robert Greenwaltca4306c2010-09-09 13:15:32 -07001901
Robert Greenwaltd7085fc2010-09-08 15:24:47 -07001902 // 100 percent is full good, 0 is full bad.
1903 public void reportInetCondition(int networkType, int percentage) {
1904 if (DBG) Slog.d(TAG, "reportNetworkCondition(" + networkType + ", " + percentage + ")");
1905 mContext.enforceCallingOrSelfPermission(
1906 android.Manifest.permission.STATUS_BAR,
1907 "ConnectivityService");
1908
Robert Greenwalt4e8dfef2010-09-20 14:35:25 -07001909 if (DBG) {
1910 int pid = getCallingPid();
1911 int uid = getCallingUid();
1912 String s = pid + "(" + uid + ") reports inet is " +
1913 (percentage > 50 ? "connected" : "disconnected") + " (" + percentage + ") on " +
1914 "network Type " + networkType + " at " + GregorianCalendar.getInstance().getTime();
1915 mInetLog.add(s);
1916 while(mInetLog.size() > INET_CONDITION_LOG_MAX_SIZE) {
1917 mInetLog.remove(0);
1918 }
1919 }
Robert Greenwaltd7085fc2010-09-08 15:24:47 -07001920 mHandler.sendMessage(mHandler.obtainMessage(
1921 NetworkStateTracker.EVENT_INET_CONDITION_CHANGE, networkType, percentage));
1922 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001923}