blob: 80129d0671bd655b0a42fe35bbf0022f39934c42 [file] [log] [blame]
The Android Open Source Project28527d22009-03-03 19:31:44 -08001/*
2 * Copyright (C) 2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.server;
18
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;
29import android.net.NetworkStateTracker;
30import android.net.wifi.WifiStateTracker;
31import android.os.Binder;
32import android.os.Handler;
Robert Greenwalt2034b912009-08-12 16:08:25 -070033import android.os.IBinder;
The Android Open Source Project28527d22009-03-03 19:31:44 -080034import android.os.Looper;
35import android.os.Message;
Robert Greenwalt2034b912009-08-12 16:08:25 -070036import android.os.RemoteException;
The Android Open Source Project28527d22009-03-03 19:31:44 -080037import android.os.ServiceManager;
38import android.os.SystemProperties;
39import android.provider.Settings;
Robert Greenwalt2034b912009-08-12 16:08:25 -070040import android.text.TextUtils;
The Android Open Source Project28527d22009-03-03 19:31:44 -080041import android.util.EventLog;
42import android.util.Log;
43
Robert Greenwalt2034b912009-08-12 16:08:25 -070044import com.android.internal.telephony.Phone;
45
The Android Open Source Project28527d22009-03-03 19:31:44 -080046import java.io.FileDescriptor;
47import java.io.PrintWriter;
Robert Greenwalt2034b912009-08-12 16:08:25 -070048import java.util.ArrayList;
49import java.util.List;
The Android Open Source Project28527d22009-03-03 19:31:44 -080050
51/**
52 * @hide
53 */
54public class ConnectivityService extends IConnectivityManager.Stub {
55
Robert Greenwalta25fd712009-10-06 14:12:53 -070056 private static final boolean DBG = true;
The Android Open Source Project28527d22009-03-03 19:31:44 -080057 private static final String TAG = "ConnectivityService";
58
Robert Greenwalt2034b912009-08-12 16:08:25 -070059 // how long to wait before switching back to a radio's default network
60 private static final int RESTORE_DEFAULT_NETWORK_DELAY = 1 * 60 * 1000;
61 // system property that can override the above value
62 private static final String NETWORK_RESTORE_DELAY_PROP_NAME =
63 "android.telephony.apn-restore";
64
The Android Open Source Project28527d22009-03-03 19:31:44 -080065 /**
66 * Sometimes we want to refer to the individual network state
67 * trackers separately, and sometimes we just want to treat them
68 * abstractly.
69 */
70 private NetworkStateTracker mNetTrackers[];
Robert Greenwalt2034b912009-08-12 16:08:25 -070071
72 /**
73 * A per Net list of the PID's that requested access to the net
74 * used both as a refcount and for per-PID DNS selection
75 */
76 private List mNetRequestersPids[];
77
The Android Open Source Project28527d22009-03-03 19:31:44 -080078 private WifiWatchdogService mWifiWatchdogService;
79
Robert Greenwalt2034b912009-08-12 16:08:25 -070080 // priority order of the nettrackers
81 // (excluding dynamically set mNetworkPreference)
82 // TODO - move mNetworkTypePreference into this
83 private int[] mPriorityList;
84
The Android Open Source Project28527d22009-03-03 19:31:44 -080085 private Context mContext;
86 private int mNetworkPreference;
Robert Greenwalt2034b912009-08-12 16:08:25 -070087 private int mActiveDefaultNetwork = -1;
The Android Open Source Project28527d22009-03-03 19:31:44 -080088
89 private int mNumDnsEntries;
The Android Open Source Project28527d22009-03-03 19:31:44 -080090
91 private boolean mTestMode;
92 private static ConnectivityService sServiceInstance;
93
Robert Greenwalt2034b912009-08-12 16:08:25 -070094 private Handler mHandler;
95
96 // list of DeathRecipients used to make sure features are turned off when
97 // a process dies
98 private List mFeatureUsers;
99
Mike Lockwoodfde2b762009-08-14 14:18:49 -0400100 private boolean mSystemReady;
Dianne Hackborna417ff82009-12-08 19:45:14 -0800101 private Intent mInitialBroadcast;
Mike Lockwoodfde2b762009-08-14 14:18:49 -0400102
Robert Greenwalt12c44552009-12-07 11:33:18 -0800103 private static class NetworkAttributes {
Robert Greenwalt2034b912009-08-12 16:08:25 -0700104 /**
105 * Class for holding settings read from resources.
106 */
107 public String mName;
108 public int mType;
109 public int mRadio;
110 public int mPriority;
Robert Greenwalt12c44552009-12-07 11:33:18 -0800111 public NetworkInfo.State mLastState;
Robert Greenwalt2034b912009-08-12 16:08:25 -0700112 public NetworkAttributes(String init) {
113 String fragments[] = init.split(",");
114 mName = fragments[0].toLowerCase();
Robert Greenwaltec05b3c2009-10-30 14:17:42 -0700115 mType = Integer.parseInt(fragments[1]);
116 mRadio = Integer.parseInt(fragments[2]);
117 mPriority = Integer.parseInt(fragments[3]);
Robert Greenwalt12c44552009-12-07 11:33:18 -0800118 mLastState = NetworkInfo.State.UNKNOWN;
Robert Greenwalt2034b912009-08-12 16:08:25 -0700119 }
120 public boolean isDefault() {
121 return (mType == mRadio);
122 }
123 }
124 NetworkAttributes[] mNetAttributes;
Robert Greenwaltec05b3c2009-10-30 14:17:42 -0700125 int mNetworksDefined;
Robert Greenwalt2034b912009-08-12 16:08:25 -0700126
Robert Greenwalt12c44552009-12-07 11:33:18 -0800127 private static class RadioAttributes {
Robert Greenwalt2034b912009-08-12 16:08:25 -0700128 public int mSimultaneity;
129 public int mType;
130 public RadioAttributes(String init) {
131 String fragments[] = init.split(",");
Robert Greenwaltec05b3c2009-10-30 14:17:42 -0700132 mType = Integer.parseInt(fragments[0]);
133 mSimultaneity = Integer.parseInt(fragments[1]);
Robert Greenwalt2034b912009-08-12 16:08:25 -0700134 }
135 }
136 RadioAttributes[] mRadioAttributes;
137
The Android Open Source Project28527d22009-03-03 19:31:44 -0800138 private static class ConnectivityThread extends Thread {
139 private Context mContext;
Robert Greenwalt0659da32009-07-16 17:21:39 -0700140
The Android Open Source Project28527d22009-03-03 19:31:44 -0800141 private ConnectivityThread(Context context) {
142 super("ConnectivityThread");
143 mContext = context;
144 }
145
146 @Override
147 public void run() {
148 Looper.prepare();
149 synchronized (this) {
150 sServiceInstance = new ConnectivityService(mContext);
151 notifyAll();
152 }
153 Looper.loop();
154 }
Robert Greenwalt0659da32009-07-16 17:21:39 -0700155
The Android Open Source Project28527d22009-03-03 19:31:44 -0800156 public static ConnectivityService getServiceInstance(Context context) {
157 ConnectivityThread thread = new ConnectivityThread(context);
158 thread.start();
Robert Greenwalt0659da32009-07-16 17:21:39 -0700159
The Android Open Source Project28527d22009-03-03 19:31:44 -0800160 synchronized (thread) {
161 while (sServiceInstance == null) {
162 try {
163 // Wait until sServiceInstance has been initialized.
164 thread.wait();
165 } catch (InterruptedException ignore) {
166 Log.e(TAG,
Robert Greenwalt0659da32009-07-16 17:21:39 -0700167 "Unexpected InterruptedException while waiting"+
168 " for ConnectivityService thread");
The Android Open Source Project28527d22009-03-03 19:31:44 -0800169 }
170 }
171 }
Robert Greenwalt0659da32009-07-16 17:21:39 -0700172
The Android Open Source Project28527d22009-03-03 19:31:44 -0800173 return sServiceInstance;
174 }
175 }
Robert Greenwalt0659da32009-07-16 17:21:39 -0700176
The Android Open Source Project28527d22009-03-03 19:31:44 -0800177 public static ConnectivityService getInstance(Context context) {
178 return ConnectivityThread.getServiceInstance(context);
179 }
Robert Greenwalt0659da32009-07-16 17:21:39 -0700180
The Android Open Source Project28527d22009-03-03 19:31:44 -0800181 private ConnectivityService(Context context) {
182 if (DBG) Log.v(TAG, "ConnectivityService starting up");
183 mContext = context;
Robert Greenwalt2034b912009-08-12 16:08:25 -0700184 mNetTrackers = new NetworkStateTracker[
185 ConnectivityManager.MAX_NETWORK_TYPE+1];
186 mHandler = new MyHandler();
Robert Greenwalt0659da32009-07-16 17:21:39 -0700187
The Android Open Source Project28527d22009-03-03 19:31:44 -0800188 mNetworkPreference = getPersistedNetworkPreference();
Robert Greenwalt0659da32009-07-16 17:21:39 -0700189
Robert Greenwaltec05b3c2009-10-30 14:17:42 -0700190 mRadioAttributes = new RadioAttributes[ConnectivityManager.MAX_RADIO_TYPE+1];
191 mNetAttributes = new NetworkAttributes[ConnectivityManager.MAX_NETWORK_TYPE+1];
192
Robert Greenwalt2034b912009-08-12 16:08:25 -0700193 // Load device network attributes from resources
Robert Greenwalt2034b912009-08-12 16:08:25 -0700194 String[] raStrings = context.getResources().getStringArray(
195 com.android.internal.R.array.radioAttributes);
Robert Greenwaltec05b3c2009-10-30 14:17:42 -0700196 for (String raString : raStrings) {
197 RadioAttributes r = new RadioAttributes(raString);
198 if (r.mType > ConnectivityManager.MAX_RADIO_TYPE) {
199 Log.e(TAG, "Error in radioAttributes - ignoring attempt to define type " + r.mType);
200 continue;
201 }
202 if (mRadioAttributes[r.mType] != null) {
203 Log.e(TAG, "Error in radioAttributes - ignoring attempt to redefine type " +
204 r.mType);
205 continue;
206 }
Robert Greenwalt2034b912009-08-12 16:08:25 -0700207 mRadioAttributes[r.mType] = r;
208 }
209
Robert Greenwaltec05b3c2009-10-30 14:17:42 -0700210 String[] naStrings = context.getResources().getStringArray(
211 com.android.internal.R.array.networkAttributes);
212 for (String naString : naStrings) {
213 try {
214 NetworkAttributes n = new NetworkAttributes(naString);
215 if (n.mType > ConnectivityManager.MAX_NETWORK_TYPE) {
216 Log.e(TAG, "Error in networkAttributes - ignoring attempt to define type " +
217 n.mType);
218 continue;
Robert Greenwalt2034b912009-08-12 16:08:25 -0700219 }
Robert Greenwaltec05b3c2009-10-30 14:17:42 -0700220 if (mNetAttributes[n.mType] != null) {
221 Log.e(TAG, "Error in networkAttributes - ignoring attempt to redefine type " +
222 n.mType);
223 continue;
224 }
225 if (mRadioAttributes[n.mRadio] == null) {
226 Log.e(TAG, "Error in networkAttributes - ignoring attempt to use undefined " +
227 "radio " + n.mRadio + " in network type " + n.mType);
228 continue;
229 }
230 mNetAttributes[n.mType] = n;
231 mNetworksDefined++;
232 } catch(Exception e) {
233 // ignore it - leave the entry null
Robert Greenwalt2034b912009-08-12 16:08:25 -0700234 }
235 }
236
Robert Greenwaltec05b3c2009-10-30 14:17:42 -0700237 // high priority first
238 mPriorityList = new int[mNetworksDefined];
239 {
240 int insertionPoint = mNetworksDefined-1;
241 int currentLowest = 0;
242 int nextLowest = 0;
243 while (insertionPoint > -1) {
244 for (NetworkAttributes na : mNetAttributes) {
245 if (na == null) continue;
246 if (na.mPriority < currentLowest) continue;
247 if (na.mPriority > currentLowest) {
248 if (na.mPriority < nextLowest || nextLowest == 0) {
249 nextLowest = na.mPriority;
250 }
251 continue;
252 }
253 mPriorityList[insertionPoint--] = na.mType;
254 }
255 currentLowest = nextLowest;
256 nextLowest = 0;
257 }
258 }
259
260 mNetRequestersPids = new ArrayList[ConnectivityManager.MAX_NETWORK_TYPE+1];
261 for (int i : mPriorityList) {
Robert Greenwalt2034b912009-08-12 16:08:25 -0700262 mNetRequestersPids[i] = new ArrayList();
263 }
264
265 mFeatureUsers = new ArrayList();
266
Robert Greenwaltec05b3c2009-10-30 14:17:42 -0700267 mNumDnsEntries = 0;
268
269 mTestMode = SystemProperties.get("cm.test.mode").equals("true")
270 && SystemProperties.get("ro.build.type").equals("eng");
The Android Open Source Project28527d22009-03-03 19:31:44 -0800271 /*
272 * Create the network state trackers for Wi-Fi and mobile
273 * data. Maybe this could be done with a factory class,
274 * but it's not clear that it's worth it, given that
275 * the number of different network types is not going
276 * to change very often.
277 */
Robert Greenwaltec05b3c2009-10-30 14:17:42 -0700278 for (int netType : mPriorityList) {
279 switch (mNetAttributes[netType].mRadio) {
280 case ConnectivityManager.TYPE_WIFI:
281 if (DBG) Log.v(TAG, "Starting Wifi Service.");
282 WifiStateTracker wst = new WifiStateTracker(context, mHandler);
283 WifiService wifiService = new WifiService(context, wst);
284 ServiceManager.addService(Context.WIFI_SERVICE, wifiService);
285 mNetTrackers[ConnectivityManager.TYPE_WIFI] = wst;
286 wst.startMonitoring();
The Android Open Source Project28527d22009-03-03 19:31:44 -0800287
Robert Greenwaltec05b3c2009-10-30 14:17:42 -0700288 // Constructing this starts it too
289 mWifiWatchdogService = new WifiWatchdogService(context, wst);
290 break;
291 case ConnectivityManager.TYPE_MOBILE:
292 mNetTrackers[netType] = new MobileDataStateTracker(context, mHandler,
293 netType, mNetAttributes[netType].mName);
294 mNetTrackers[netType].startMonitoring();
295 break;
296 default:
297 Log.e(TAG, "Trying to create a DataStateTracker for an unknown radio type " +
298 mNetAttributes[netType].mRadio);
299 continue;
300 }
301 }
The Android Open Source Project28527d22009-03-03 19:31:44 -0800302 }
303
Robert Greenwaltec05b3c2009-10-30 14:17:42 -0700304
The Android Open Source Project28527d22009-03-03 19:31:44 -0800305 /**
Robert Greenwalt0659da32009-07-16 17:21:39 -0700306 * Sets the preferred network.
The Android Open Source Project28527d22009-03-03 19:31:44 -0800307 * @param preference the new preference
308 */
309 public synchronized void setNetworkPreference(int preference) {
310 enforceChangePermission();
Robert Greenwalt2034b912009-08-12 16:08:25 -0700311 if (ConnectivityManager.isNetworkTypeValid(preference) &&
Robert Greenwaltec05b3c2009-10-30 14:17:42 -0700312 mNetAttributes[preference] != null &&
Robert Greenwalt2034b912009-08-12 16:08:25 -0700313 mNetAttributes[preference].isDefault()) {
The Android Open Source Project28527d22009-03-03 19:31:44 -0800314 if (mNetworkPreference != preference) {
315 persistNetworkPreference(preference);
316 mNetworkPreference = preference;
317 enforcePreference();
318 }
319 }
320 }
321
322 public int getNetworkPreference() {
323 enforceAccessPermission();
324 return mNetworkPreference;
325 }
326
327 private void persistNetworkPreference(int networkPreference) {
328 final ContentResolver cr = mContext.getContentResolver();
Robert Greenwalt0659da32009-07-16 17:21:39 -0700329 Settings.Secure.putInt(cr, Settings.Secure.NETWORK_PREFERENCE,
330 networkPreference);
The Android Open Source Project28527d22009-03-03 19:31:44 -0800331 }
Robert Greenwalt0659da32009-07-16 17:21:39 -0700332
The Android Open Source Project28527d22009-03-03 19:31:44 -0800333 private int getPersistedNetworkPreference() {
334 final ContentResolver cr = mContext.getContentResolver();
335
336 final int networkPrefSetting = Settings.Secure
337 .getInt(cr, Settings.Secure.NETWORK_PREFERENCE, -1);
338 if (networkPrefSetting != -1) {
339 return networkPrefSetting;
340 }
341
342 return ConnectivityManager.DEFAULT_NETWORK_PREFERENCE;
343 }
Robert Greenwalt0659da32009-07-16 17:21:39 -0700344
The Android Open Source Project28527d22009-03-03 19:31:44 -0800345 /**
Robert Greenwalt0659da32009-07-16 17:21:39 -0700346 * Make the state of network connectivity conform to the preference settings
The Android Open Source Project28527d22009-03-03 19:31:44 -0800347 * In this method, we only tear down a non-preferred network. Establishing
348 * a connection to the preferred network is taken care of when we handle
349 * the disconnect event from the non-preferred network
350 * (see {@link #handleDisconnect(NetworkInfo)}).
351 */
352 private void enforcePreference() {
Robert Greenwalt2034b912009-08-12 16:08:25 -0700353 if (mNetTrackers[mNetworkPreference].getNetworkInfo().isConnected())
The Android Open Source Project28527d22009-03-03 19:31:44 -0800354 return;
355
Robert Greenwalt2034b912009-08-12 16:08:25 -0700356 if (!mNetTrackers[mNetworkPreference].isAvailable())
357 return;
The Android Open Source Project28527d22009-03-03 19:31:44 -0800358
Robert Greenwalt2034b912009-08-12 16:08:25 -0700359 for (int t=0; t <= ConnectivityManager.MAX_RADIO_TYPE; t++) {
Robert Greenwaltec05b3c2009-10-30 14:17:42 -0700360 if (t != mNetworkPreference && mNetTrackers[t] != null &&
Robert Greenwalt2034b912009-08-12 16:08:25 -0700361 mNetTrackers[t].getNetworkInfo().isConnected()) {
Robert Greenwaltf3f045b2009-08-20 15:25:14 -0700362 if (DBG) {
363 Log.d(TAG, "tearing down " +
364 mNetTrackers[t].getNetworkInfo() +
365 " in enforcePreference");
366 }
Robert Greenwalt2034b912009-08-12 16:08:25 -0700367 teardown(mNetTrackers[t]);
The Android Open Source Project28527d22009-03-03 19:31:44 -0800368 }
369 }
370 }
371
372 private boolean teardown(NetworkStateTracker netTracker) {
373 if (netTracker.teardown()) {
374 netTracker.setTeardownRequested(true);
375 return true;
376 } else {
377 return false;
378 }
379 }
380
381 /**
382 * Return NetworkInfo for the active (i.e., connected) network interface.
383 * It is assumed that at most one network is active at a time. If more
384 * than one is active, it is indeterminate which will be returned.
Robert Greenwalt0659da32009-07-16 17:21:39 -0700385 * @return the info for the active network, or {@code null} if none is
386 * active
The Android Open Source Project28527d22009-03-03 19:31:44 -0800387 */
388 public NetworkInfo getActiveNetworkInfo() {
389 enforceAccessPermission();
Robert Greenwalt2034b912009-08-12 16:08:25 -0700390 for (int type=0; type <= ConnectivityManager.MAX_NETWORK_TYPE; type++) {
Robert Greenwaltec05b3c2009-10-30 14:17:42 -0700391 if (mNetAttributes[type] == null || !mNetAttributes[type].isDefault()) {
Robert Greenwalt2034b912009-08-12 16:08:25 -0700392 continue;
393 }
394 NetworkStateTracker t = mNetTrackers[type];
The Android Open Source Project28527d22009-03-03 19:31:44 -0800395 NetworkInfo info = t.getNetworkInfo();
396 if (info.isConnected()) {
Robert Greenwalt2034b912009-08-12 16:08:25 -0700397 if (DBG && type != mActiveDefaultNetwork) Log.e(TAG,
398 "connected default network is not " +
399 "mActiveDefaultNetwork!");
The Android Open Source Project28527d22009-03-03 19:31:44 -0800400 return info;
401 }
402 }
403 return null;
404 }
405
406 public NetworkInfo getNetworkInfo(int networkType) {
407 enforceAccessPermission();
408 if (ConnectivityManager.isNetworkTypeValid(networkType)) {
409 NetworkStateTracker t = mNetTrackers[networkType];
410 if (t != null)
411 return t.getNetworkInfo();
412 }
413 return null;
414 }
415
416 public NetworkInfo[] getAllNetworkInfo() {
417 enforceAccessPermission();
Robert Greenwaltec05b3c2009-10-30 14:17:42 -0700418 NetworkInfo[] result = new NetworkInfo[mNetworksDefined];
The Android Open Source Project28527d22009-03-03 19:31:44 -0800419 int i = 0;
420 for (NetworkStateTracker t : mNetTrackers) {
Robert Greenwaltec05b3c2009-10-30 14:17:42 -0700421 if(t != null) result[i++] = t.getNetworkInfo();
The Android Open Source Project28527d22009-03-03 19:31:44 -0800422 }
423 return result;
424 }
425
426 public boolean setRadios(boolean turnOn) {
427 boolean result = true;
428 enforceChangePermission();
429 for (NetworkStateTracker t : mNetTrackers) {
Robert Greenwaltec05b3c2009-10-30 14:17:42 -0700430 if (t != null) result = t.setRadio(turnOn) && result;
The Android Open Source Project28527d22009-03-03 19:31:44 -0800431 }
432 return result;
433 }
434
435 public boolean setRadio(int netType, boolean turnOn) {
436 enforceChangePermission();
437 if (!ConnectivityManager.isNetworkTypeValid(netType)) {
438 return false;
439 }
440 NetworkStateTracker tracker = mNetTrackers[netType];
441 return tracker != null && tracker.setRadio(turnOn);
442 }
443
Robert Greenwaltaffc3a12009-09-27 17:27:04 -0700444 /**
445 * Used to notice when the calling process dies so we can self-expire
446 *
447 * Also used to know if the process has cleaned up after itself when
448 * our auto-expire timer goes off. The timer has a link to an object.
449 *
450 */
Robert Greenwalt2034b912009-08-12 16:08:25 -0700451 private class FeatureUser implements IBinder.DeathRecipient {
452 int mNetworkType;
453 String mFeature;
454 IBinder mBinder;
455 int mPid;
456 int mUid;
Robert Greenwalt3eeb6032009-12-21 18:24:07 -0800457 long mCreateTime;
Robert Greenwalt2034b912009-08-12 16:08:25 -0700458
459 FeatureUser(int type, String feature, IBinder binder) {
460 super();
461 mNetworkType = type;
462 mFeature = feature;
463 mBinder = binder;
464 mPid = getCallingPid();
465 mUid = getCallingUid();
Robert Greenwalt3eeb6032009-12-21 18:24:07 -0800466 mCreateTime = System.currentTimeMillis();
Robert Greenwaltaffc3a12009-09-27 17:27:04 -0700467
Robert Greenwalt2034b912009-08-12 16:08:25 -0700468 try {
469 mBinder.linkToDeath(this, 0);
470 } catch (RemoteException e) {
471 binderDied();
472 }
473 }
474
475 void unlinkDeathRecipient() {
476 mBinder.unlinkToDeath(this, 0);
477 }
478
479 public void binderDied() {
480 Log.d(TAG, "ConnectivityService FeatureUser binderDied(" +
Robert Greenwalt3eeb6032009-12-21 18:24:07 -0800481 mNetworkType + ", " + mFeature + ", " + mBinder + "), created " +
482 (System.currentTimeMillis() - mCreateTime) + " mSec ago");
Robert Greenwaltaffc3a12009-09-27 17:27:04 -0700483 stopUsingNetworkFeature(this, false);
Robert Greenwalt2034b912009-08-12 16:08:25 -0700484 }
485
Robert Greenwaltaffc3a12009-09-27 17:27:04 -0700486 public void expire() {
487 Log.d(TAG, "ConnectivityService FeatureUser expire(" +
Robert Greenwalt3eeb6032009-12-21 18:24:07 -0800488 mNetworkType + ", " + mFeature + ", " + mBinder +"), created " +
489 (System.currentTimeMillis() - mCreateTime) + " mSec ago");
Robert Greenwaltaffc3a12009-09-27 17:27:04 -0700490 stopUsingNetworkFeature(this, false);
491 }
Robert Greenwalt3eeb6032009-12-21 18:24:07 -0800492
493 public String toString() {
494 return "FeatureUser("+mNetworkType+","+mFeature+","+mPid+","+mUid+"), created " +
495 (System.currentTimeMillis() - mCreateTime) + " mSec ago";
496 }
Robert Greenwalt2034b912009-08-12 16:08:25 -0700497 }
498
Robert Greenwaltaffc3a12009-09-27 17:27:04 -0700499 // javadoc from interface
Robert Greenwalt2034b912009-08-12 16:08:25 -0700500 public int startUsingNetworkFeature(int networkType, String feature,
501 IBinder binder) {
502 if (DBG) {
503 Log.d(TAG, "startUsingNetworkFeature for net " + networkType +
504 ": " + feature);
505 }
The Android Open Source Project28527d22009-03-03 19:31:44 -0800506 enforceChangePermission();
Robert Greenwaltec05b3c2009-10-30 14:17:42 -0700507 if (!ConnectivityManager.isNetworkTypeValid(networkType) ||
508 mNetAttributes[networkType] == null) {
Robert Greenwalt2034b912009-08-12 16:08:25 -0700509 return Phone.APN_REQUEST_FAILED;
The Android Open Source Project28527d22009-03-03 19:31:44 -0800510 }
Robert Greenwalt2034b912009-08-12 16:08:25 -0700511
Robert Greenwaltaffc3a12009-09-27 17:27:04 -0700512 FeatureUser f = new FeatureUser(networkType, feature, binder);
Robert Greenwalt2034b912009-08-12 16:08:25 -0700513
514 // TODO - move this into the MobileDataStateTracker
515 int usedNetworkType = networkType;
516 if(networkType == ConnectivityManager.TYPE_MOBILE) {
517 if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_MMS)) {
518 usedNetworkType = ConnectivityManager.TYPE_MOBILE_MMS;
519 } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_SUPL)) {
520 usedNetworkType = ConnectivityManager.TYPE_MOBILE_SUPL;
521 } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_DUN)) {
522 usedNetworkType = ConnectivityManager.TYPE_MOBILE_DUN;
523 } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_HIPRI)) {
524 usedNetworkType = ConnectivityManager.TYPE_MOBILE_HIPRI;
525 }
526 }
527 NetworkStateTracker network = mNetTrackers[usedNetworkType];
528 if (network != null) {
529 if (usedNetworkType != networkType) {
530 Integer currentPid = new Integer(getCallingPid());
531
532 NetworkStateTracker radio = mNetTrackers[networkType];
533 NetworkInfo ni = network.getNetworkInfo();
534
535 if (ni.isAvailable() == false) {
536 if (DBG) Log.d(TAG, "special network not available");
537 return Phone.APN_TYPE_NOT_AVAILABLE;
538 }
539
Robert Greenwaltaffc3a12009-09-27 17:27:04 -0700540 synchronized(this) {
541 mFeatureUsers.add(f);
542 if (!mNetRequestersPids[usedNetworkType].contains(currentPid)) {
543 // this gets used for per-pid dns when connected
544 mNetRequestersPids[usedNetworkType].add(currentPid);
545 }
Robert Greenwalt2034b912009-08-12 16:08:25 -0700546 }
Robert Greenwaltaffc3a12009-09-27 17:27:04 -0700547 mHandler.sendMessageDelayed(mHandler.obtainMessage(
548 NetworkStateTracker.EVENT_RESTORE_DEFAULT_NETWORK,
549 f), getRestoreDefaultNetworkDelay());
550
Robert Greenwalt2034b912009-08-12 16:08:25 -0700551
Robert Greenwalta52c75a2009-08-19 20:19:33 -0700552 if ((ni.isConnectedOrConnecting() == true) &&
553 !network.isTeardownRequested()) {
Robert Greenwalt2034b912009-08-12 16:08:25 -0700554 if (ni.isConnected() == true) {
555 // add the pid-specific dns
556 handleDnsConfigurationChange();
557 if (DBG) Log.d(TAG, "special network already active");
558 return Phone.APN_ALREADY_ACTIVE;
559 }
560 if (DBG) Log.d(TAG, "special network already connecting");
561 return Phone.APN_REQUEST_STARTED;
562 }
563
564 // check if the radio in play can make another contact
565 // assume if cannot for now
566
Robert Greenwalt2034b912009-08-12 16:08:25 -0700567 if (DBG) Log.d(TAG, "reconnecting to special network");
568 network.reconnect();
569 return Phone.APN_REQUEST_STARTED;
570 } else {
Robert Greenwaltaffc3a12009-09-27 17:27:04 -0700571 synchronized(this) {
572 mFeatureUsers.add(f);
573 }
574 mHandler.sendMessageDelayed(mHandler.obtainMessage(
575 NetworkStateTracker.EVENT_RESTORE_DEFAULT_NETWORK,
576 f), getRestoreDefaultNetworkDelay());
577
Robert Greenwalt2034b912009-08-12 16:08:25 -0700578 return network.startUsingNetworkFeature(feature,
579 getCallingPid(), getCallingUid());
580 }
581 }
582 return Phone.APN_TYPE_NOT_AVAILABLE;
The Android Open Source Project28527d22009-03-03 19:31:44 -0800583 }
584
Robert Greenwaltaffc3a12009-09-27 17:27:04 -0700585 // javadoc from interface
The Android Open Source Project28527d22009-03-03 19:31:44 -0800586 public int stopUsingNetworkFeature(int networkType, String feature) {
Robert Greenwalt28f43012009-10-06 17:52:40 -0700587 enforceChangePermission();
588
Robert Greenwaltaffc3a12009-09-27 17:27:04 -0700589 int pid = getCallingPid();
590 int uid = getCallingUid();
591
592 FeatureUser u = null;
593 boolean found = false;
594
595 synchronized(this) {
596 for (int i = 0; i < mFeatureUsers.size() ; i++) {
597 u = (FeatureUser)mFeatureUsers.get(i);
598 if (uid == u.mUid && pid == u.mPid &&
599 networkType == u.mNetworkType &&
600 TextUtils.equals(feature, u.mFeature)) {
601 found = true;
602 break;
603 }
604 }
605 }
606 if (found && u != null) {
607 // stop regardless of how many other time this proc had called start
608 return stopUsingNetworkFeature(u, true);
609 } else {
610 // none found!
Robert Greenwalt3eeb6032009-12-21 18:24:07 -0800611 if (DBG) Log.d(TAG, "ignoring stopUsingNetworkFeature - not a live request");
Robert Greenwaltaffc3a12009-09-27 17:27:04 -0700612 return 1;
613 }
Robert Greenwalt2034b912009-08-12 16:08:25 -0700614 }
615
Robert Greenwaltaffc3a12009-09-27 17:27:04 -0700616 private int stopUsingNetworkFeature(FeatureUser u, boolean ignoreDups) {
617 int networkType = u.mNetworkType;
618 String feature = u.mFeature;
619 int pid = u.mPid;
620 int uid = u.mUid;
621
622 NetworkStateTracker tracker = null;
623 boolean callTeardown = false; // used to carry our decision outside of sync block
624
Robert Greenwalt2034b912009-08-12 16:08:25 -0700625 if (DBG) {
626 Log.d(TAG, "stopUsingNetworkFeature for net " + networkType +
627 ": " + feature);
628 }
Robert Greenwalt28f43012009-10-06 17:52:40 -0700629
The Android Open Source Project28527d22009-03-03 19:31:44 -0800630 if (!ConnectivityManager.isNetworkTypeValid(networkType)) {
631 return -1;
632 }
Robert Greenwalt2034b912009-08-12 16:08:25 -0700633
Robert Greenwaltaffc3a12009-09-27 17:27:04 -0700634 // need to link the mFeatureUsers list with the mNetRequestersPids state in this
635 // sync block
636 synchronized(this) {
637 // check if this process still has an outstanding start request
638 if (!mFeatureUsers.contains(u)) {
Robert Greenwalt2034b912009-08-12 16:08:25 -0700639 return 1;
640 }
Robert Greenwaltaffc3a12009-09-27 17:27:04 -0700641 u.unlinkDeathRecipient();
642 mFeatureUsers.remove(mFeatureUsers.indexOf(u));
643 // If we care about duplicate requests, check for that here.
644 //
645 // This is done to support the extension of a request - the app
646 // can request we start the network feature again and renew the
647 // auto-shutoff delay. Normal "stop" calls from the app though
648 // do not pay attention to duplicate requests - in effect the
649 // API does not refcount and a single stop will counter multiple starts.
650 if (ignoreDups == false) {
651 for (int i = 0; i < mFeatureUsers.size() ; i++) {
652 FeatureUser x = (FeatureUser)mFeatureUsers.get(i);
653 if (x.mUid == u.mUid && x.mPid == u.mPid &&
654 x.mNetworkType == u.mNetworkType &&
655 TextUtils.equals(x.mFeature, u.mFeature)) {
Robert Greenwalt3eeb6032009-12-21 18:24:07 -0800656 if (DBG) Log.d(TAG, "ignoring stopUsingNetworkFeature as dup is found");
Robert Greenwaltaffc3a12009-09-27 17:27:04 -0700657 return 1;
658 }
659 }
Robert Greenwalt2034b912009-08-12 16:08:25 -0700660 }
Robert Greenwaltaffc3a12009-09-27 17:27:04 -0700661
662 // TODO - move to MobileDataStateTracker
663 int usedNetworkType = networkType;
664 if (networkType == ConnectivityManager.TYPE_MOBILE) {
665 if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_MMS)) {
666 usedNetworkType = ConnectivityManager.TYPE_MOBILE_MMS;
667 } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_SUPL)) {
668 usedNetworkType = ConnectivityManager.TYPE_MOBILE_SUPL;
669 } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_DUN)) {
670 usedNetworkType = ConnectivityManager.TYPE_MOBILE_DUN;
671 } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_HIPRI)) {
672 usedNetworkType = ConnectivityManager.TYPE_MOBILE_HIPRI;
673 }
674 }
675 tracker = mNetTrackers[usedNetworkType];
Robert Greenwaltec05b3c2009-10-30 14:17:42 -0700676 if (tracker == null) {
677 return -1;
678 }
679 if (usedNetworkType != networkType) {
Robert Greenwaltaffc3a12009-09-27 17:27:04 -0700680 Integer currentPid = new Integer(pid);
Robert Greenwaltaffc3a12009-09-27 17:27:04 -0700681 mNetRequestersPids[usedNetworkType].remove(currentPid);
Robert Greenwalt0ca68a02009-12-17 14:54:59 -0800682 reassessPidDns(pid, true);
Robert Greenwaltaffc3a12009-09-27 17:27:04 -0700683 if (mNetRequestersPids[usedNetworkType].size() != 0) {
684 if (DBG) Log.d(TAG, "not tearing down special network - " +
685 "others still using it");
686 return 1;
687 }
688 callTeardown = true;
689 }
690 }
691
692 if (callTeardown) {
693 tracker.teardown();
Robert Greenwalt2034b912009-08-12 16:08:25 -0700694 return 1;
695 } else {
Robert Greenwaltaffc3a12009-09-27 17:27:04 -0700696 // do it the old fashioned way
Robert Greenwalt2034b912009-08-12 16:08:25 -0700697 return tracker.stopUsingNetworkFeature(feature, pid, uid);
698 }
The Android Open Source Project28527d22009-03-03 19:31:44 -0800699 }
700
701 /**
702 * Ensure that a network route exists to deliver traffic to the specified
703 * host via the specified network interface.
Robert Greenwalt0659da32009-07-16 17:21:39 -0700704 * @param networkType the type of the network over which traffic to the
705 * specified host is to be routed
706 * @param hostAddress the IP address of the host to which the route is
707 * desired
The Android Open Source Project28527d22009-03-03 19:31:44 -0800708 * @return {@code true} on success, {@code false} on failure
709 */
710 public boolean requestRouteToHost(int networkType, int hostAddress) {
711 enforceChangePermission();
712 if (!ConnectivityManager.isNetworkTypeValid(networkType)) {
713 return false;
714 }
715 NetworkStateTracker tracker = mNetTrackers[networkType];
Robert Greenwalt4666ed02009-09-10 15:06:20 -0700716
Robert Greenwaltec05b3c2009-10-30 14:17:42 -0700717 if (tracker == null || !tracker.getNetworkInfo().isConnected() ||
718 tracker.isTeardownRequested()) {
Robert Greenwalt4666ed02009-09-10 15:06:20 -0700719 if (DBG) {
Robert Greenwaltec05b3c2009-10-30 14:17:42 -0700720 Log.d(TAG, "requestRouteToHost on down network (" + networkType + ") - dropped");
Robert Greenwalt4666ed02009-09-10 15:06:20 -0700721 }
722 return false;
The Android Open Source Project28527d22009-03-03 19:31:44 -0800723 }
Robert Greenwalt4666ed02009-09-10 15:06:20 -0700724 return tracker.requestRouteToHost(hostAddress);
The Android Open Source Project28527d22009-03-03 19:31:44 -0800725 }
726
727 /**
728 * @see ConnectivityManager#getBackgroundDataSetting()
729 */
730 public boolean getBackgroundDataSetting() {
731 return Settings.Secure.getInt(mContext.getContentResolver(),
732 Settings.Secure.BACKGROUND_DATA, 1) == 1;
733 }
Robert Greenwalt0659da32009-07-16 17:21:39 -0700734
The Android Open Source Project28527d22009-03-03 19:31:44 -0800735 /**
736 * @see ConnectivityManager#setBackgroundDataSetting(boolean)
737 */
738 public void setBackgroundDataSetting(boolean allowBackgroundDataUsage) {
739 mContext.enforceCallingOrSelfPermission(
740 android.Manifest.permission.CHANGE_BACKGROUND_DATA_SETTING,
741 "ConnectivityService");
Robert Greenwalt0659da32009-07-16 17:21:39 -0700742
The Android Open Source Project28527d22009-03-03 19:31:44 -0800743 if (getBackgroundDataSetting() == allowBackgroundDataUsage) return;
744
745 Settings.Secure.putInt(mContext.getContentResolver(),
Robert Greenwalt0659da32009-07-16 17:21:39 -0700746 Settings.Secure.BACKGROUND_DATA,
747 allowBackgroundDataUsage ? 1 : 0);
748
The Android Open Source Project28527d22009-03-03 19:31:44 -0800749 Intent broadcast = new Intent(
750 ConnectivityManager.ACTION_BACKGROUND_DATA_SETTING_CHANGED);
751 mContext.sendBroadcast(broadcast);
Robert Greenwalt0659da32009-07-16 17:21:39 -0700752 }
753
The Android Open Source Project28527d22009-03-03 19:31:44 -0800754 private int getNumConnectedNetworks() {
755 int numConnectedNets = 0;
756
757 for (NetworkStateTracker nt : mNetTrackers) {
Robert Greenwaltec05b3c2009-10-30 14:17:42 -0700758 if (nt != null && nt.getNetworkInfo().isConnected() &&
Robert Greenwalt0659da32009-07-16 17:21:39 -0700759 !nt.isTeardownRequested()) {
The Android Open Source Project28527d22009-03-03 19:31:44 -0800760 ++numConnectedNets;
761 }
762 }
763 return numConnectedNets;
764 }
765
766 private void enforceAccessPermission() {
Robert Greenwalt0659da32009-07-16 17:21:39 -0700767 mContext.enforceCallingOrSelfPermission(
768 android.Manifest.permission.ACCESS_NETWORK_STATE,
769 "ConnectivityService");
The Android Open Source Project28527d22009-03-03 19:31:44 -0800770 }
771
772 private void enforceChangePermission() {
Robert Greenwalt0659da32009-07-16 17:21:39 -0700773 mContext.enforceCallingOrSelfPermission(
774 android.Manifest.permission.CHANGE_NETWORK_STATE,
775 "ConnectivityService");
The Android Open Source Project28527d22009-03-03 19:31:44 -0800776 }
777
778 /**
Robert Greenwalt0659da32009-07-16 17:21:39 -0700779 * Handle a {@code DISCONNECTED} event. If this pertains to the non-active
780 * network, we ignore it. If it is for the active network, we send out a
781 * broadcast. But first, we check whether it might be possible to connect
782 * to a different network.
The Android Open Source Project28527d22009-03-03 19:31:44 -0800783 * @param info the {@code NetworkInfo} for the network
784 */
785 private void handleDisconnect(NetworkInfo info) {
786
Robert Greenwalt2034b912009-08-12 16:08:25 -0700787 int prevNetType = info.getType();
The Android Open Source Project28527d22009-03-03 19:31:44 -0800788
Robert Greenwalt2034b912009-08-12 16:08:25 -0700789 mNetTrackers[prevNetType].setTeardownRequested(false);
The Android Open Source Project28527d22009-03-03 19:31:44 -0800790 /*
791 * If the disconnected network is not the active one, then don't report
792 * this as a loss of connectivity. What probably happened is that we're
793 * getting the disconnect for a network that we explicitly disabled
794 * in accordance with network preference policies.
795 */
Robert Greenwalt2034b912009-08-12 16:08:25 -0700796 if (!mNetAttributes[prevNetType].isDefault()) {
797 List pids = mNetRequestersPids[prevNetType];
798 for (int i = 0; i<pids.size(); i++) {
799 Integer pid = (Integer)pids.get(i);
800 // will remove them because the net's no longer connected
801 // need to do this now as only now do we know the pids and
802 // can properly null things that are no longer referenced.
803 reassessPidDns(pid.intValue(), false);
The Android Open Source Project28527d22009-03-03 19:31:44 -0800804 }
The Android Open Source Project28527d22009-03-03 19:31:44 -0800805 }
806
The Android Open Source Project28527d22009-03-03 19:31:44 -0800807 Intent intent = new Intent(ConnectivityManager.CONNECTIVITY_ACTION);
Dianne Hackborna417ff82009-12-08 19:45:14 -0800808 intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
The Android Open Source Project28527d22009-03-03 19:31:44 -0800809 intent.putExtra(ConnectivityManager.EXTRA_NETWORK_INFO, info);
810 if (info.isFailover()) {
811 intent.putExtra(ConnectivityManager.EXTRA_IS_FAILOVER, true);
812 info.setFailover(false);
813 }
814 if (info.getReason() != null) {
815 intent.putExtra(ConnectivityManager.EXTRA_REASON, info.getReason());
816 }
817 if (info.getExtraInfo() != null) {
Robert Greenwalt0659da32009-07-16 17:21:39 -0700818 intent.putExtra(ConnectivityManager.EXTRA_EXTRA_INFO,
819 info.getExtraInfo());
The Android Open Source Project28527d22009-03-03 19:31:44 -0800820 }
Robert Greenwalt2034b912009-08-12 16:08:25 -0700821
822 /*
823 * If this is a default network, check if other defaults are available
824 * or active
825 */
826 NetworkStateTracker newNet = null;
827 if (mNetAttributes[prevNetType].isDefault()) {
Robert Greenwalt2034b912009-08-12 16:08:25 -0700828 if (mActiveDefaultNetwork == prevNetType) {
829 mActiveDefaultNetwork = -1;
830 }
831
832 int newType = -1;
833 int newPriority = -1;
834 for (int checkType=0; checkType <=
835 ConnectivityManager.MAX_NETWORK_TYPE; checkType++) {
Robert Greenwaltec05b3c2009-10-30 14:17:42 -0700836 if (checkType == prevNetType) continue;
837 if (mNetAttributes[checkType] == null) continue;
Robert Greenwalt2034b912009-08-12 16:08:25 -0700838 if (mNetAttributes[checkType].isDefault()) {
839 /* TODO - if we have multiple nets we could use
840 * we may want to put more thought into which we choose
841 */
842 if (checkType == mNetworkPreference) {
843 newType = checkType;
844 break;
845 }
Robert Greenwaltec05b3c2009-10-30 14:17:42 -0700846 if (mNetAttributes[checkType].mPriority > newPriority) {
Robert Greenwalt2034b912009-08-12 16:08:25 -0700847 newType = checkType;
Robert Greenwaltec05b3c2009-10-30 14:17:42 -0700848 newPriority = mNetAttributes[newType].mPriority;
Robert Greenwalt2034b912009-08-12 16:08:25 -0700849 }
The Android Open Source Project28527d22009-03-03 19:31:44 -0800850 }
851 }
Robert Greenwalt2034b912009-08-12 16:08:25 -0700852
853 if (newType != -1) {
854 newNet = mNetTrackers[newType];
855 /**
856 * See if the other network is available to fail over to.
857 * If is not available, we enable it anyway, so that it
858 * will be able to connect when it does become available,
859 * but we report a total loss of connectivity rather than
860 * report that we are attempting to fail over.
861 */
862 if (newNet.isAvailable()) {
863 NetworkInfo switchTo = newNet.getNetworkInfo();
864 switchTo.setFailover(true);
Robert Greenwalta52c75a2009-08-19 20:19:33 -0700865 if (!switchTo.isConnectedOrConnecting() ||
866 newNet.isTeardownRequested()) {
Robert Greenwalt2034b912009-08-12 16:08:25 -0700867 newNet.reconnect();
868 }
869 if (DBG) {
870 if (switchTo.isConnected()) {
871 Log.v(TAG, "Switching to already connected " +
872 switchTo.getTypeName());
873 } else {
874 Log.v(TAG, "Attempting to switch to " +
875 switchTo.getTypeName());
876 }
877 }
878 intent.putExtra(ConnectivityManager.
879 EXTRA_OTHER_NETWORK_INFO, switchTo);
880 } else {
Robert Greenwalt149d5ac2009-09-17 14:58:16 -0700881 intent.putExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY,
882 true);
Robert Greenwalt2034b912009-08-12 16:08:25 -0700883 newNet.reconnect();
884 }
885 } else {
886 intent.putExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY,
887 true);
888 }
The Android Open Source Project28527d22009-03-03 19:31:44 -0800889 }
Robert Greenwalt2034b912009-08-12 16:08:25 -0700890
891 // do this before we broadcast the change
892 handleConnectivityChange();
893
Mike Lockwoodfde2b762009-08-14 14:18:49 -0400894 sendStickyBroadcast(intent);
The Android Open Source Project28527d22009-03-03 19:31:44 -0800895 /*
Robert Greenwalt0659da32009-07-16 17:21:39 -0700896 * If the failover network is already connected, then immediately send
897 * out a followup broadcast indicating successful failover
The Android Open Source Project28527d22009-03-03 19:31:44 -0800898 */
Robert Greenwalt2034b912009-08-12 16:08:25 -0700899 if (newNet != null && newNet.getNetworkInfo().isConnected())
900 sendConnectedBroadcast(newNet.getNetworkInfo());
The Android Open Source Project28527d22009-03-03 19:31:44 -0800901 }
902
903 private void sendConnectedBroadcast(NetworkInfo info) {
904 Intent intent = new Intent(ConnectivityManager.CONNECTIVITY_ACTION);
Dianne Hackborna417ff82009-12-08 19:45:14 -0800905 intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
The Android Open Source Project28527d22009-03-03 19:31:44 -0800906 intent.putExtra(ConnectivityManager.EXTRA_NETWORK_INFO, info);
907 if (info.isFailover()) {
908 intent.putExtra(ConnectivityManager.EXTRA_IS_FAILOVER, true);
909 info.setFailover(false);
910 }
911 if (info.getReason() != null) {
912 intent.putExtra(ConnectivityManager.EXTRA_REASON, info.getReason());
913 }
914 if (info.getExtraInfo() != null) {
Robert Greenwalt0659da32009-07-16 17:21:39 -0700915 intent.putExtra(ConnectivityManager.EXTRA_EXTRA_INFO,
916 info.getExtraInfo());
The Android Open Source Project28527d22009-03-03 19:31:44 -0800917 }
Mike Lockwoodfde2b762009-08-14 14:18:49 -0400918 sendStickyBroadcast(intent);
The Android Open Source Project28527d22009-03-03 19:31:44 -0800919 }
920
921 /**
922 * Called when an attempt to fail over to another network has failed.
923 * @param info the {@link NetworkInfo} for the failed network
924 */
925 private void handleConnectionFailure(NetworkInfo info) {
926 mNetTrackers[info.getType()].setTeardownRequested(false);
The Android Open Source Project28527d22009-03-03 19:31:44 -0800927
Robert Greenwalt2034b912009-08-12 16:08:25 -0700928 String reason = info.getReason();
929 String extraInfo = info.getExtraInfo();
Robert Greenwalt0659da32009-07-16 17:21:39 -0700930
Robert Greenwalt2034b912009-08-12 16:08:25 -0700931 if (DBG) {
932 String reasonText;
933 if (reason == null) {
934 reasonText = ".";
935 } else {
936 reasonText = " (" + reason + ").";
The Android Open Source Project28527d22009-03-03 19:31:44 -0800937 }
Robert Greenwalt2034b912009-08-12 16:08:25 -0700938 Log.v(TAG, "Attempt to connect to " + info.getTypeName() +
939 " failed" + reasonText);
The Android Open Source Project28527d22009-03-03 19:31:44 -0800940 }
Robert Greenwalt2034b912009-08-12 16:08:25 -0700941
942 Intent intent = new Intent(ConnectivityManager.CONNECTIVITY_ACTION);
Dianne Hackborna417ff82009-12-08 19:45:14 -0800943 intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
Robert Greenwalt2034b912009-08-12 16:08:25 -0700944 intent.putExtra(ConnectivityManager.EXTRA_NETWORK_INFO, info);
945 if (getActiveNetworkInfo() == null) {
946 intent.putExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, true);
947 }
948 if (reason != null) {
949 intent.putExtra(ConnectivityManager.EXTRA_REASON, reason);
950 }
951 if (extraInfo != null) {
952 intent.putExtra(ConnectivityManager.EXTRA_EXTRA_INFO, extraInfo);
953 }
954 if (info.isFailover()) {
955 intent.putExtra(ConnectivityManager.EXTRA_IS_FAILOVER, true);
956 info.setFailover(false);
957 }
Mike Lockwoodfde2b762009-08-14 14:18:49 -0400958 sendStickyBroadcast(intent);
959 }
960
961 private void sendStickyBroadcast(Intent intent) {
962 synchronized(this) {
Dianne Hackborna417ff82009-12-08 19:45:14 -0800963 if (!mSystemReady) {
964 mInitialBroadcast = new Intent(intent);
Mike Lockwoodfde2b762009-08-14 14:18:49 -0400965 }
Dianne Hackborna417ff82009-12-08 19:45:14 -0800966 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
967 mContext.sendStickyBroadcast(intent);
Mike Lockwoodfde2b762009-08-14 14:18:49 -0400968 }
969 }
970
971 void systemReady() {
972 synchronized(this) {
973 mSystemReady = true;
Dianne Hackborna417ff82009-12-08 19:45:14 -0800974 if (mInitialBroadcast != null) {
975 mContext.sendStickyBroadcast(mInitialBroadcast);
976 mInitialBroadcast = null;
Mike Lockwoodfde2b762009-08-14 14:18:49 -0400977 }
978 }
The Android Open Source Project28527d22009-03-03 19:31:44 -0800979 }
980
981 private void handleConnect(NetworkInfo info) {
Robert Greenwalt2034b912009-08-12 16:08:25 -0700982 int type = info.getType();
The Android Open Source Project28527d22009-03-03 19:31:44 -0800983
984 // snapshot isFailover, because sendConnectedBroadcast() resets it
985 boolean isFailover = info.isFailover();
Robert Greenwalt2034b912009-08-12 16:08:25 -0700986 NetworkStateTracker thisNet = mNetTrackers[type];
The Android Open Source Project28527d22009-03-03 19:31:44 -0800987
Robert Greenwalt2034b912009-08-12 16:08:25 -0700988 // if this is a default net and other default is running
989 // kill the one not preferred
990 if (mNetAttributes[type].isDefault()) {
Robert Greenwalt2034b912009-08-12 16:08:25 -0700991 if (mActiveDefaultNetwork != -1 && mActiveDefaultNetwork != type) {
992 if ((type != mNetworkPreference &&
993 mNetAttributes[mActiveDefaultNetwork].mPriority >
994 mNetAttributes[type].mPriority) ||
995 mNetworkPreference == mActiveDefaultNetwork) {
996 // don't accept this one
997 if (DBG) Log.v(TAG, "Not broadcasting CONNECT_ACTION " +
998 "to torn down network " + info.getTypeName());
999 teardown(thisNet);
1000 return;
1001 } else {
1002 // tear down the other
1003 NetworkStateTracker otherNet =
1004 mNetTrackers[mActiveDefaultNetwork];
1005 if (DBG) Log.v(TAG, "Policy requires " +
1006 otherNet.getNetworkInfo().getTypeName() +
1007 " teardown");
1008 if (!teardown(otherNet)) {
1009 Log.e(TAG, "Network declined teardown request");
1010 return;
1011 }
1012 if (isFailover) {
1013 otherNet.releaseWakeLock();
1014 }
1015 }
1016 }
1017 mActiveDefaultNetwork = type;
1018 }
The Android Open Source Project28527d22009-03-03 19:31:44 -08001019 thisNet.setTeardownRequested(false);
Robert Greenwalt2034b912009-08-12 16:08:25 -07001020 thisNet.updateNetworkSettings();
1021 handleConnectivityChange();
1022 sendConnectedBroadcast(info);
The Android Open Source Project28527d22009-03-03 19:31:44 -08001023 }
1024
1025 private void handleScanResultsAvailable(NetworkInfo info) {
1026 int networkType = info.getType();
1027 if (networkType != ConnectivityManager.TYPE_WIFI) {
Robert Greenwalt0659da32009-07-16 17:21:39 -07001028 if (DBG) Log.v(TAG, "Got ScanResultsAvailable for " +
1029 info.getTypeName() + " network. Don't know how to handle.");
The Android Open Source Project28527d22009-03-03 19:31:44 -08001030 }
Robert Greenwalt0659da32009-07-16 17:21:39 -07001031
The Android Open Source Project28527d22009-03-03 19:31:44 -08001032 mNetTrackers[networkType].interpretScanResultsAvailable();
1033 }
1034
Robert Greenwalt0659da32009-07-16 17:21:39 -07001035 private void handleNotificationChange(boolean visible, int id,
1036 Notification notification) {
The Android Open Source Project28527d22009-03-03 19:31:44 -08001037 NotificationManager notificationManager = (NotificationManager) mContext
1038 .getSystemService(Context.NOTIFICATION_SERVICE);
Robert Greenwalt0659da32009-07-16 17:21:39 -07001039
The Android Open Source Project28527d22009-03-03 19:31:44 -08001040 if (visible) {
1041 notificationManager.notify(id, notification);
1042 } else {
1043 notificationManager.cancel(id);
1044 }
1045 }
1046
1047 /**
1048 * After any kind of change in the connectivity state of any network,
1049 * make sure that anything that depends on the connectivity state of
1050 * more than one network is set up correctly. We're mainly concerned
1051 * with making sure that the list of DNS servers is set up according
1052 * to which networks are connected, and ensuring that the right routing
1053 * table entries exist.
1054 */
1055 private void handleConnectivityChange() {
1056 /*
Robert Greenwalt2034b912009-08-12 16:08:25 -07001057 * If a non-default network is enabled, add the host routes that
Robert Greenwalt423dbbc2009-09-30 21:01:30 -07001058 * will allow it's DNS servers to be accessed. Only
The Android Open Source Project28527d22009-03-03 19:31:44 -08001059 * If both mobile and wifi are enabled, add the host routes that
1060 * will allow MMS traffic to pass on the mobile network. But
1061 * remove the default route for the mobile network, so that there
1062 * will be only one default route, to ensure that all traffic
1063 * except MMS will travel via Wi-Fi.
1064 */
Robert Greenwalt2034b912009-08-12 16:08:25 -07001065 handleDnsConfigurationChange();
1066
1067 for (int netType : mPriorityList) {
1068 if (mNetTrackers[netType].getNetworkInfo().isConnected()) {
1069 if (mNetAttributes[netType].isDefault()) {
1070 mNetTrackers[netType].addDefaultRoute();
1071 } else {
1072 mNetTrackers[netType].addPrivateDnsRoutes();
1073 }
1074 } else {
1075 if (mNetAttributes[netType].isDefault()) {
1076 mNetTrackers[netType].removeDefaultRoute();
1077 } else {
1078 mNetTrackers[netType].removePrivateDnsRoutes();
1079 }
1080 }
The Android Open Source Project28527d22009-03-03 19:31:44 -08001081 }
1082 }
1083
Robert Greenwalt2034b912009-08-12 16:08:25 -07001084 /**
1085 * Adjust the per-process dns entries (net.dns<x>.<pid>) based
1086 * on the highest priority active net which this process requested.
1087 * If there aren't any, clear it out
1088 */
1089 private void reassessPidDns(int myPid, boolean doBump)
1090 {
1091 if (DBG) Log.d(TAG, "reassessPidDns for pid " + myPid);
1092 for(int i : mPriorityList) {
1093 if (mNetAttributes[i].isDefault()) {
1094 continue;
1095 }
1096 NetworkStateTracker nt = mNetTrackers[i];
Robert Greenwalt0659da32009-07-16 17:21:39 -07001097 if (nt.getNetworkInfo().isConnected() &&
1098 !nt.isTeardownRequested()) {
Robert Greenwalt2034b912009-08-12 16:08:25 -07001099 List pids = mNetRequestersPids[i];
1100 for (int j=0; j<pids.size(); j++) {
1101 Integer pid = (Integer)pids.get(j);
1102 if (pid.intValue() == myPid) {
1103 String[] dnsList = nt.getNameServers();
1104 writePidDns(dnsList, myPid);
1105 if (doBump) {
1106 bumpDns();
1107 }
1108 return;
1109 }
1110 }
1111 }
1112 }
1113 // nothing found - delete
1114 for (int i = 1; ; i++) {
1115 String prop = "net.dns" + i + "." + myPid;
1116 if (SystemProperties.get(prop).length() == 0) {
1117 if (doBump) {
1118 bumpDns();
1119 }
1120 return;
1121 }
1122 SystemProperties.set(prop, "");
1123 }
1124 }
1125
1126 private void writePidDns(String[] dnsList, int pid) {
1127 int j = 1;
1128 for (String dns : dnsList) {
1129 if (dns != null && !TextUtils.equals(dns, "0.0.0.0")) {
1130 SystemProperties.set("net.dns" + j++ + "." + pid, dns);
1131 }
1132 }
1133 }
1134
1135 private void bumpDns() {
1136 /*
1137 * Bump the property that tells the name resolver library to reread
1138 * the DNS server list from the properties.
1139 */
1140 String propVal = SystemProperties.get("net.dnschange");
1141 int n = 0;
1142 if (propVal.length() != 0) {
1143 try {
1144 n = Integer.parseInt(propVal);
1145 } catch (NumberFormatException e) {}
1146 }
1147 SystemProperties.set("net.dnschange", "" + (n+1));
1148 }
1149
1150 private void handleDnsConfigurationChange() {
Robert Greenwalt2034b912009-08-12 16:08:25 -07001151 // add default net's dns entries
1152 for (int x = mPriorityList.length-1; x>= 0; x--) {
1153 int netType = mPriorityList[x];
1154 NetworkStateTracker nt = mNetTrackers[netType];
Robert Greenwalt2034b912009-08-12 16:08:25 -07001155 if (nt != null && nt.getNetworkInfo().isConnected() &&
1156 !nt.isTeardownRequested()) {
The Android Open Source Project28527d22009-03-03 19:31:44 -08001157 String[] dnsList = nt.getNameServers();
Robert Greenwalt2034b912009-08-12 16:08:25 -07001158 if (mNetAttributes[netType].isDefault()) {
1159 int j = 1;
1160 for (String dns : dnsList) {
1161 if (dns != null && !TextUtils.equals(dns, "0.0.0.0")) {
Robert Greenwalt423dbbc2009-09-30 21:01:30 -07001162 if (DBG) {
1163 Log.d(TAG, "adding dns " + dns + " for " +
1164 nt.getNetworkInfo().getTypeName());
1165 }
Robert Greenwalt2034b912009-08-12 16:08:25 -07001166 SystemProperties.set("net.dns" + j++, dns);
1167 }
1168 }
1169 for (int k=j ; k<mNumDnsEntries; k++) {
Robert Greenwalt8e5b8532009-08-25 14:00:10 -07001170 if (DBG) Log.d(TAG, "erasing net.dns" + k);
1171 SystemProperties.set("net.dns" + k, "");
Robert Greenwalt2034b912009-08-12 16:08:25 -07001172 }
1173 mNumDnsEntries = j;
1174 } else {
1175 // set per-pid dns for attached secondary nets
1176 List pids = mNetRequestersPids[netType];
1177 for (int y=0; y< pids.size(); y++) {
1178 Integer pid = (Integer)pids.get(y);
1179 writePidDns(dnsList, pid.intValue());
The Android Open Source Project28527d22009-03-03 19:31:44 -08001180 }
1181 }
1182 }
1183 }
Robert Greenwalt2034b912009-08-12 16:08:25 -07001184
1185 bumpDns();
1186 }
1187
1188 private int getRestoreDefaultNetworkDelay() {
1189 String restoreDefaultNetworkDelayStr = SystemProperties.get(
1190 NETWORK_RESTORE_DELAY_PROP_NAME);
1191 if(restoreDefaultNetworkDelayStr != null &&
1192 restoreDefaultNetworkDelayStr.length() != 0) {
1193 try {
1194 return Integer.valueOf(restoreDefaultNetworkDelayStr);
1195 } catch (NumberFormatException e) {
1196 }
The Android Open Source Project28527d22009-03-03 19:31:44 -08001197 }
Robert Greenwalt2034b912009-08-12 16:08:25 -07001198 return RESTORE_DEFAULT_NETWORK_DELAY;
The Android Open Source Project28527d22009-03-03 19:31:44 -08001199 }
1200
1201 @Override
1202 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
Robert Greenwalt0659da32009-07-16 17:21:39 -07001203 if (mContext.checkCallingOrSelfPermission(
1204 android.Manifest.permission.DUMP)
The Android Open Source Project28527d22009-03-03 19:31:44 -08001205 != PackageManager.PERMISSION_GRANTED) {
Robert Greenwalt0659da32009-07-16 17:21:39 -07001206 pw.println("Permission Denial: can't dump ConnectivityService " +
1207 "from from pid=" + Binder.getCallingPid() + ", uid=" +
1208 Binder.getCallingUid());
The Android Open Source Project28527d22009-03-03 19:31:44 -08001209 return;
1210 }
The Android Open Source Project28527d22009-03-03 19:31:44 -08001211 pw.println();
1212 for (NetworkStateTracker nst : mNetTrackers) {
Robert Greenwalt3eeb6032009-12-21 18:24:07 -08001213 if (nst != null) {
1214 if (nst.getNetworkInfo().isConnected()) {
1215 pw.println("Active network: " + nst.getNetworkInfo().
1216 getTypeName());
1217 }
1218 pw.println(nst.getNetworkInfo());
1219 pw.println(nst);
1220 pw.println();
Robert Greenwalt2034b912009-08-12 16:08:25 -07001221 }
The Android Open Source Project28527d22009-03-03 19:31:44 -08001222 }
Robert Greenwalt3eeb6032009-12-21 18:24:07 -08001223
1224 pw.println("Network Requester Pids:");
1225 for (int net : mPriorityList) {
1226 String pidString = net + ": ";
1227 for (Object pid : mNetRequestersPids[net]) {
1228 pidString = pidString + pid.toString() + ", ";
1229 }
1230 pw.println(pidString);
1231 }
1232 pw.println();
1233
1234 pw.println("FeatureUsers:");
1235 for (Object requester : mFeatureUsers) {
1236 pw.println(requester.toString());
1237 }
1238 pw.println();
The Android Open Source Project28527d22009-03-03 19:31:44 -08001239 }
1240
Robert Greenwalt2034b912009-08-12 16:08:25 -07001241 // must be stateless - things change under us.
The Android Open Source Project28527d22009-03-03 19:31:44 -08001242 private class MyHandler extends Handler {
1243 @Override
1244 public void handleMessage(Message msg) {
1245 NetworkInfo info;
1246 switch (msg.what) {
1247 case NetworkStateTracker.EVENT_STATE_CHANGED:
1248 info = (NetworkInfo) msg.obj;
Robert Greenwalt12c44552009-12-07 11:33:18 -08001249 int type = info.getType();
1250 NetworkInfo.State state = info.getState();
1251 if(mNetAttributes[type].mLastState == state) {
1252 if (DBG) {
1253 // TODO - remove this after we validate the dropping doesn't break anything
1254 Log.d(TAG, "Dropping ConnectivityChange for " +
1255 info.getTypeName() +": " +
1256 state + "/" + info.getDetailedState());
1257 }
1258 return;
1259 }
1260 mNetAttributes[type].mLastState = state;
1261
Robert Greenwalt2034b912009-08-12 16:08:25 -07001262 if (DBG) Log.d(TAG, "ConnectivityChange for " +
Robert Greenwalt0659da32009-07-16 17:21:39 -07001263 info.getTypeName() + ": " +
Robert Greenwalt12c44552009-12-07 11:33:18 -08001264 state + "/" + info.getDetailedState());
The Android Open Source Project28527d22009-03-03 19:31:44 -08001265
1266 // Connectivity state changed:
1267 // [31-13] Reserved for future use
Robert Greenwalt0659da32009-07-16 17:21:39 -07001268 // [12-9] Network subtype (for mobile network, as defined
1269 // by TelephonyManager)
1270 // [8-3] Detailed state ordinal (as defined by
1271 // NetworkInfo.DetailedState)
The Android Open Source Project28527d22009-03-03 19:31:44 -08001272 // [2-0] Network type (as defined by ConnectivityManager)
1273 int eventLogParam = (info.getType() & 0x7) |
1274 ((info.getDetailedState().ordinal() & 0x3f) << 3) |
1275 (info.getSubtype() << 9);
Doug Zongker2fc96232009-12-04 10:31:43 -08001276 EventLog.writeEvent(EventLogTags.CONNECTIVITY_STATE_CHANGED,
Robert Greenwalt0659da32009-07-16 17:21:39 -07001277 eventLogParam);
1278
1279 if (info.getDetailedState() ==
1280 NetworkInfo.DetailedState.FAILED) {
The Android Open Source Project28527d22009-03-03 19:31:44 -08001281 handleConnectionFailure(info);
Robert Greenwalt12c44552009-12-07 11:33:18 -08001282 } else if (state == NetworkInfo.State.DISCONNECTED) {
The Android Open Source Project28527d22009-03-03 19:31:44 -08001283 handleDisconnect(info);
Robert Greenwalt12c44552009-12-07 11:33:18 -08001284 } else if (state == NetworkInfo.State.SUSPENDED) {
The Android Open Source Project28527d22009-03-03 19:31:44 -08001285 // TODO: need to think this over.
Robert Greenwalt0659da32009-07-16 17:21:39 -07001286 // the logic here is, handle SUSPENDED the same as
1287 // DISCONNECTED. The only difference being we are
1288 // broadcasting an intent with NetworkInfo that's
1289 // suspended. This allows the applications an
1290 // opportunity to handle DISCONNECTED and SUSPENDED
1291 // differently, or not.
The Android Open Source Project28527d22009-03-03 19:31:44 -08001292 handleDisconnect(info);
Robert Greenwalt12c44552009-12-07 11:33:18 -08001293 } else if (state == NetworkInfo.State.CONNECTED) {
The Android Open Source Project28527d22009-03-03 19:31:44 -08001294 handleConnect(info);
1295 }
The Android Open Source Project28527d22009-03-03 19:31:44 -08001296 break;
1297
1298 case NetworkStateTracker.EVENT_SCAN_RESULTS_AVAILABLE:
1299 info = (NetworkInfo) msg.obj;
1300 handleScanResultsAvailable(info);
1301 break;
Robert Greenwalt0659da32009-07-16 17:21:39 -07001302
The Android Open Source Project28527d22009-03-03 19:31:44 -08001303 case NetworkStateTracker.EVENT_NOTIFICATION_CHANGED:
Robert Greenwalt0659da32009-07-16 17:21:39 -07001304 handleNotificationChange(msg.arg1 == 1, msg.arg2,
1305 (Notification) msg.obj);
The Android Open Source Project28527d22009-03-03 19:31:44 -08001306
1307 case NetworkStateTracker.EVENT_CONFIGURATION_CHANGED:
Robert Greenwalt2034b912009-08-12 16:08:25 -07001308 handleDnsConfigurationChange();
The Android Open Source Project28527d22009-03-03 19:31:44 -08001309 break;
1310
1311 case NetworkStateTracker.EVENT_ROAMING_CHANGED:
1312 // fill me in
1313 break;
1314
1315 case NetworkStateTracker.EVENT_NETWORK_SUBTYPE_CHANGED:
1316 // fill me in
1317 break;
Robert Greenwalt2034b912009-08-12 16:08:25 -07001318 case NetworkStateTracker.EVENT_RESTORE_DEFAULT_NETWORK:
Robert Greenwaltaffc3a12009-09-27 17:27:04 -07001319 FeatureUser u = (FeatureUser)msg.obj;
1320 u.expire();
Robert Greenwalt2034b912009-08-12 16:08:25 -07001321 break;
The Android Open Source Project28527d22009-03-03 19:31:44 -08001322 }
1323 }
1324 }
1325}