blob: d37558f36498e36b552f19249beb1821dfb0d87a [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;
The Android Open Source Project28527d22009-03-03 19:31:44 -080021import android.content.Context;
TK MUN141623d2011-02-23 18:55:55 +090022import android.content.ContentResolver;
23import android.content.ContextWrapper;
The Android Open Source Project28527d22009-03-03 19:31:44 -080024import android.content.Intent;
25import android.content.pm.PackageManager;
TK MUN141623d2011-02-23 18:55:55 +090026import android.content.res.Resources;
27import android.content.res.Resources.NotFoundException;
The Android Open Source Project28527d22009-03-03 19:31:44 -080028import android.net.ConnectivityManager;
29import android.net.IConnectivityManager;
30import android.net.MobileDataStateTracker;
31import android.net.NetworkInfo;
32import android.net.NetworkStateTracker;
33import android.net.wifi.WifiStateTracker;
TK MUN141623d2011-02-23 18:55:55 +090034import android.net.wimax.WimaxManagerConstants;
The Android Open Source Project28527d22009-03-03 19:31:44 -080035import android.os.Binder;
36import android.os.Handler;
Robert Greenwalt2034b912009-08-12 16:08:25 -070037import android.os.IBinder;
The Android Open Source Project28527d22009-03-03 19:31:44 -080038import android.os.Looper;
39import android.os.Message;
Robert Greenwalt2034b912009-08-12 16:08:25 -070040import android.os.RemoteException;
The Android Open Source Project28527d22009-03-03 19:31:44 -080041import android.os.ServiceManager;
42import android.os.SystemProperties;
43import android.provider.Settings;
Robert Greenwalt2034b912009-08-12 16:08:25 -070044import android.text.TextUtils;
The Android Open Source Project28527d22009-03-03 19:31:44 -080045import android.util.EventLog;
Joe Onoratoc2386bb2010-02-26 18:56:32 -080046import android.util.Slog;
Robert Greenwalt2034b912009-08-12 16:08:25 -070047import com.android.internal.telephony.Phone;
Robert Greenwalt0c4828c2010-01-26 11:40:34 -080048import com.android.server.connectivity.Tethering;
TK MUN141623d2011-02-23 18:55:55 +090049import dalvik.system.DexClassLoader;
The Android Open Source Project28527d22009-03-03 19:31:44 -080050import java.io.FileDescriptor;
51import java.io.PrintWriter;
TK MUN141623d2011-02-23 18:55:55 +090052import java.lang.reflect.Constructor;
53import java.lang.reflect.Method;
54import java.lang.reflect.Modifier;
55import java.lang.reflect.InvocationTargetException;
Robert Greenwalt2034b912009-08-12 16:08:25 -070056import java.util.ArrayList;
Robert Greenwalt0e80be12010-09-20 14:35:25 -070057import java.util.GregorianCalendar;
Robert Greenwalt2034b912009-08-12 16:08:25 -070058import java.util.List;
The Android Open Source Project28527d22009-03-03 19:31:44 -080059
TK MUN141623d2011-02-23 18:55:55 +090060
61
The Android Open Source Project28527d22009-03-03 19:31:44 -080062/**
63 * @hide
64 */
65public class ConnectivityService extends IConnectivityManager.Stub {
66
Dianne Hackborn8919f5a2010-09-30 18:27:22 -070067 private static final boolean DBG = false;
The Android Open Source Project28527d22009-03-03 19:31:44 -080068 private static final String TAG = "ConnectivityService";
69
Robert Greenwalt2034b912009-08-12 16:08:25 -070070 // how long to wait before switching back to a radio's default network
71 private static final int RESTORE_DEFAULT_NETWORK_DELAY = 1 * 60 * 1000;
72 // system property that can override the above value
73 private static final String NETWORK_RESTORE_DELAY_PROP_NAME =
74 "android.telephony.apn-restore";
75
Robert Greenwalt0c4828c2010-01-26 11:40:34 -080076
77 private Tethering mTethering;
Robert Greenwaltf1b66e12010-02-25 12:29:30 -080078 private boolean mTetheringConfigValid = false;
Robert Greenwalt0c4828c2010-01-26 11:40:34 -080079
The Android Open Source Project28527d22009-03-03 19:31:44 -080080 /**
81 * Sometimes we want to refer to the individual network state
82 * trackers separately, and sometimes we just want to treat them
83 * abstractly.
84 */
85 private NetworkStateTracker mNetTrackers[];
Robert Greenwalt2034b912009-08-12 16:08:25 -070086
87 /**
88 * A per Net list of the PID's that requested access to the net
89 * used both as a refcount and for per-PID DNS selection
90 */
91 private List mNetRequestersPids[];
92
Robert Greenwalt2034b912009-08-12 16:08:25 -070093 // priority order of the nettrackers
94 // (excluding dynamically set mNetworkPreference)
95 // TODO - move mNetworkTypePreference into this
96 private int[] mPriorityList;
97
The Android Open Source Project28527d22009-03-03 19:31:44 -080098 private Context mContext;
99 private int mNetworkPreference;
Robert Greenwalt2034b912009-08-12 16:08:25 -0700100 private int mActiveDefaultNetwork = -1;
Robert Greenwalt986c7412010-09-08 15:24:47 -0700101 // 0 is full bad, 100 is full good
102 private int mDefaultInetCondition = 0;
103 private int mDefaultInetConditionPublished = 0;
104 private boolean mInetConditionChangeInFlight = false;
105 private int mDefaultConnectionSequence = 0;
The Android Open Source Project28527d22009-03-03 19:31:44 -0800106
107 private int mNumDnsEntries;
The Android Open Source Project28527d22009-03-03 19:31:44 -0800108
109 private boolean mTestMode;
110 private static ConnectivityService sServiceInstance;
Robert Greenwalt6a2db8a2010-09-23 10:05:56 -0700111 private static final int ENABLED = 1;
112 private static final int DISABLED = 0;
113
114 // Share the event space with NetworkStateTracker (which can't see this
115 // internal class but sends us events). If you change these, change
116 // NetworkStateTracker.java too.
117 private static final int MIN_NETWORK_STATE_TRACKER_EVENT = 1;
118 private static final int MAX_NETWORK_STATE_TRACKER_EVENT = 100;
119
120 /**
121 * used internally as a delayed event to make us switch back to the
122 * default network
123 */
124 private static final int EVENT_RESTORE_DEFAULT_NETWORK =
125 MAX_NETWORK_STATE_TRACKER_EVENT + 1;
126
127 /**
128 * used internally to change our mobile data enabled flag
129 */
130 private static final int EVENT_CHANGE_MOBILE_DATA_ENABLED =
131 MAX_NETWORK_STATE_TRACKER_EVENT + 2;
132
133 /**
134 * used internally to change our network preference setting
135 * arg1 = networkType to prefer
136 */
137 private static final int EVENT_SET_NETWORK_PREFERENCE =
138 MAX_NETWORK_STATE_TRACKER_EVENT + 3;
139
140 /**
141 * used internally to synchronize inet condition reports
142 * arg1 = networkType
143 * arg2 = condition (0 bad, 100 good)
144 */
145 private static final int EVENT_INET_CONDITION_CHANGE =
146 MAX_NETWORK_STATE_TRACKER_EVENT + 4;
147
148 /**
149 * used internally to mark the end of inet condition hold periods
150 * arg1 = networkType
151 */
152 private static final int EVENT_INET_CONDITION_HOLD_END =
153 MAX_NETWORK_STATE_TRACKER_EVENT + 5;
154
155 /**
156 * used internally to set the background data preference
157 * arg1 = TRUE for enabled, FALSE for disabled
158 */
159 private static final int EVENT_SET_BACKGROUND_DATA =
160 MAX_NETWORK_STATE_TRACKER_EVENT + 6;
161
162 /**
163 * used internally to set enable/disable cellular data
164 * arg1 = ENBALED or DISABLED
165 */
166 private static final int EVENT_SET_MOBILE_DATA =
167 MAX_NETWORK_STATE_TRACKER_EVENT + 7;
168
Robert Greenwalt2034b912009-08-12 16:08:25 -0700169 private Handler mHandler;
170
171 // list of DeathRecipients used to make sure features are turned off when
172 // a process dies
173 private List mFeatureUsers;
174
Mike Lockwoodfde2b762009-08-14 14:18:49 -0400175 private boolean mSystemReady;
Dianne Hackborna417ff82009-12-08 19:45:14 -0800176 private Intent mInitialBroadcast;
Mike Lockwoodfde2b762009-08-14 14:18:49 -0400177
Robert Greenwalt0e80be12010-09-20 14:35:25 -0700178 // used in DBG mode to track inet condition reports
179 private static final int INET_CONDITION_LOG_MAX_SIZE = 15;
180 private ArrayList mInetLog;
181
Robert Greenwalt12c44552009-12-07 11:33:18 -0800182 private static class NetworkAttributes {
Robert Greenwalt2034b912009-08-12 16:08:25 -0700183 /**
184 * Class for holding settings read from resources.
185 */
186 public String mName;
187 public int mType;
188 public int mRadio;
189 public int mPriority;
Robert Greenwalt12c44552009-12-07 11:33:18 -0800190 public NetworkInfo.State mLastState;
Robert Greenwalt2034b912009-08-12 16:08:25 -0700191 public NetworkAttributes(String init) {
192 String fragments[] = init.split(",");
193 mName = fragments[0].toLowerCase();
Robert Greenwaltec05b3c2009-10-30 14:17:42 -0700194 mType = Integer.parseInt(fragments[1]);
195 mRadio = Integer.parseInt(fragments[2]);
196 mPriority = Integer.parseInt(fragments[3]);
Robert Greenwalt12c44552009-12-07 11:33:18 -0800197 mLastState = NetworkInfo.State.UNKNOWN;
Robert Greenwalt2034b912009-08-12 16:08:25 -0700198 }
199 public boolean isDefault() {
200 return (mType == mRadio);
201 }
202 }
203 NetworkAttributes[] mNetAttributes;
Robert Greenwaltec05b3c2009-10-30 14:17:42 -0700204 int mNetworksDefined;
Robert Greenwalt2034b912009-08-12 16:08:25 -0700205
Robert Greenwalt12c44552009-12-07 11:33:18 -0800206 private static class RadioAttributes {
Robert Greenwalt2034b912009-08-12 16:08:25 -0700207 public int mSimultaneity;
208 public int mType;
209 public RadioAttributes(String init) {
210 String fragments[] = init.split(",");
Robert Greenwaltec05b3c2009-10-30 14:17:42 -0700211 mType = Integer.parseInt(fragments[0]);
212 mSimultaneity = Integer.parseInt(fragments[1]);
Robert Greenwalt2034b912009-08-12 16:08:25 -0700213 }
214 }
215 RadioAttributes[] mRadioAttributes;
216
The Android Open Source Project28527d22009-03-03 19:31:44 -0800217 private static class ConnectivityThread extends Thread {
218 private Context mContext;
Robert Greenwalt0659da32009-07-16 17:21:39 -0700219
The Android Open Source Project28527d22009-03-03 19:31:44 -0800220 private ConnectivityThread(Context context) {
221 super("ConnectivityThread");
222 mContext = context;
223 }
224
225 @Override
226 public void run() {
227 Looper.prepare();
228 synchronized (this) {
229 sServiceInstance = new ConnectivityService(mContext);
230 notifyAll();
231 }
232 Looper.loop();
233 }
Robert Greenwalt0659da32009-07-16 17:21:39 -0700234
The Android Open Source Project28527d22009-03-03 19:31:44 -0800235 public static ConnectivityService getServiceInstance(Context context) {
236 ConnectivityThread thread = new ConnectivityThread(context);
237 thread.start();
Robert Greenwalt0659da32009-07-16 17:21:39 -0700238
The Android Open Source Project28527d22009-03-03 19:31:44 -0800239 synchronized (thread) {
240 while (sServiceInstance == null) {
241 try {
242 // Wait until sServiceInstance has been initialized.
243 thread.wait();
244 } catch (InterruptedException ignore) {
Joe Onoratoc2386bb2010-02-26 18:56:32 -0800245 Slog.e(TAG,
Robert Greenwalt0659da32009-07-16 17:21:39 -0700246 "Unexpected InterruptedException while waiting"+
247 " for ConnectivityService thread");
The Android Open Source Project28527d22009-03-03 19:31:44 -0800248 }
249 }
250 }
Robert Greenwalt0659da32009-07-16 17:21:39 -0700251
The Android Open Source Project28527d22009-03-03 19:31:44 -0800252 return sServiceInstance;
253 }
254 }
Robert Greenwalt0659da32009-07-16 17:21:39 -0700255
The Android Open Source Project28527d22009-03-03 19:31:44 -0800256 public static ConnectivityService getInstance(Context context) {
257 return ConnectivityThread.getServiceInstance(context);
258 }
Robert Greenwalt0659da32009-07-16 17:21:39 -0700259
The Android Open Source Project28527d22009-03-03 19:31:44 -0800260 private ConnectivityService(Context context) {
Joe Onoratoc2386bb2010-02-26 18:56:32 -0800261 if (DBG) Slog.v(TAG, "ConnectivityService starting up");
Robert Greenwaltd48f8ee2010-01-14 17:47:58 -0800262
263 // setup our unique device name
264 String id = Settings.Secure.getString(context.getContentResolver(),
265 Settings.Secure.ANDROID_ID);
266 if (id != null && id.length() > 0) {
267 String name = new String("android_").concat(id);
268 SystemProperties.set("net.hostname", name);
269 }
270
The Android Open Source Project28527d22009-03-03 19:31:44 -0800271 mContext = context;
Robert Greenwalt2034b912009-08-12 16:08:25 -0700272 mNetTrackers = new NetworkStateTracker[
273 ConnectivityManager.MAX_NETWORK_TYPE+1];
274 mHandler = new MyHandler();
Robert Greenwalt0659da32009-07-16 17:21:39 -0700275
The Android Open Source Project28527d22009-03-03 19:31:44 -0800276 mNetworkPreference = getPersistedNetworkPreference();
Robert Greenwalt0659da32009-07-16 17:21:39 -0700277
Robert Greenwaltec05b3c2009-10-30 14:17:42 -0700278 mRadioAttributes = new RadioAttributes[ConnectivityManager.MAX_RADIO_TYPE+1];
279 mNetAttributes = new NetworkAttributes[ConnectivityManager.MAX_NETWORK_TYPE+1];
280
Robert Greenwalt2034b912009-08-12 16:08:25 -0700281 // Load device network attributes from resources
Robert Greenwalt2034b912009-08-12 16:08:25 -0700282 String[] raStrings = context.getResources().getStringArray(
283 com.android.internal.R.array.radioAttributes);
Robert Greenwaltec05b3c2009-10-30 14:17:42 -0700284 for (String raString : raStrings) {
285 RadioAttributes r = new RadioAttributes(raString);
286 if (r.mType > ConnectivityManager.MAX_RADIO_TYPE) {
Joe Onoratoc2386bb2010-02-26 18:56:32 -0800287 Slog.e(TAG, "Error in radioAttributes - ignoring attempt to define type " + r.mType);
Robert Greenwaltec05b3c2009-10-30 14:17:42 -0700288 continue;
289 }
290 if (mRadioAttributes[r.mType] != null) {
Joe Onoratoc2386bb2010-02-26 18:56:32 -0800291 Slog.e(TAG, "Error in radioAttributes - ignoring attempt to redefine type " +
Robert Greenwaltec05b3c2009-10-30 14:17:42 -0700292 r.mType);
293 continue;
294 }
Robert Greenwalt2034b912009-08-12 16:08:25 -0700295 mRadioAttributes[r.mType] = r;
296 }
297
Robert Greenwaltec05b3c2009-10-30 14:17:42 -0700298 String[] naStrings = context.getResources().getStringArray(
299 com.android.internal.R.array.networkAttributes);
300 for (String naString : naStrings) {
301 try {
302 NetworkAttributes n = new NetworkAttributes(naString);
303 if (n.mType > ConnectivityManager.MAX_NETWORK_TYPE) {
Joe Onoratoc2386bb2010-02-26 18:56:32 -0800304 Slog.e(TAG, "Error in networkAttributes - ignoring attempt to define type " +
Robert Greenwaltec05b3c2009-10-30 14:17:42 -0700305 n.mType);
306 continue;
Robert Greenwalt2034b912009-08-12 16:08:25 -0700307 }
Robert Greenwaltec05b3c2009-10-30 14:17:42 -0700308 if (mNetAttributes[n.mType] != null) {
Joe Onoratoc2386bb2010-02-26 18:56:32 -0800309 Slog.e(TAG, "Error in networkAttributes - ignoring attempt to redefine type " +
Robert Greenwaltec05b3c2009-10-30 14:17:42 -0700310 n.mType);
311 continue;
312 }
313 if (mRadioAttributes[n.mRadio] == null) {
Joe Onoratoc2386bb2010-02-26 18:56:32 -0800314 Slog.e(TAG, "Error in networkAttributes - ignoring attempt to use undefined " +
Robert Greenwaltec05b3c2009-10-30 14:17:42 -0700315 "radio " + n.mRadio + " in network type " + n.mType);
316 continue;
317 }
318 mNetAttributes[n.mType] = n;
319 mNetworksDefined++;
320 } catch(Exception e) {
321 // ignore it - leave the entry null
Robert Greenwalt2034b912009-08-12 16:08:25 -0700322 }
323 }
324
Robert Greenwaltec05b3c2009-10-30 14:17:42 -0700325 // high priority first
326 mPriorityList = new int[mNetworksDefined];
327 {
328 int insertionPoint = mNetworksDefined-1;
329 int currentLowest = 0;
330 int nextLowest = 0;
331 while (insertionPoint > -1) {
332 for (NetworkAttributes na : mNetAttributes) {
333 if (na == null) continue;
334 if (na.mPriority < currentLowest) continue;
335 if (na.mPriority > currentLowest) {
336 if (na.mPriority < nextLowest || nextLowest == 0) {
337 nextLowest = na.mPriority;
338 }
339 continue;
340 }
341 mPriorityList[insertionPoint--] = na.mType;
342 }
343 currentLowest = nextLowest;
344 nextLowest = 0;
345 }
346 }
347
348 mNetRequestersPids = new ArrayList[ConnectivityManager.MAX_NETWORK_TYPE+1];
349 for (int i : mPriorityList) {
Robert Greenwalt2034b912009-08-12 16:08:25 -0700350 mNetRequestersPids[i] = new ArrayList();
351 }
352
353 mFeatureUsers = new ArrayList();
354
Robert Greenwaltec05b3c2009-10-30 14:17:42 -0700355 mNumDnsEntries = 0;
356
357 mTestMode = SystemProperties.get("cm.test.mode").equals("true")
358 && SystemProperties.get("ro.build.type").equals("eng");
The Android Open Source Project28527d22009-03-03 19:31:44 -0800359 /*
360 * Create the network state trackers for Wi-Fi and mobile
361 * data. Maybe this could be done with a factory class,
362 * but it's not clear that it's worth it, given that
363 * the number of different network types is not going
364 * to change very often.
365 */
Robert Greenwalt1b21f6c2010-02-23 18:58:05 -0800366 boolean noMobileData = !getMobileDataEnabled();
Robert Greenwaltec05b3c2009-10-30 14:17:42 -0700367 for (int netType : mPriorityList) {
368 switch (mNetAttributes[netType].mRadio) {
369 case ConnectivityManager.TYPE_WIFI:
Joe Onoratoc2386bb2010-02-26 18:56:32 -0800370 if (DBG) Slog.v(TAG, "Starting Wifi Service.");
Robert Greenwaltec05b3c2009-10-30 14:17:42 -0700371 WifiStateTracker wst = new WifiStateTracker(context, mHandler);
372 WifiService wifiService = new WifiService(context, wst);
373 ServiceManager.addService(Context.WIFI_SERVICE, wifiService);
Irfan Sheriff324ec572010-03-11 16:37:45 -0800374 wifiService.startWifi();
Robert Greenwaltec05b3c2009-10-30 14:17:42 -0700375 mNetTrackers[ConnectivityManager.TYPE_WIFI] = wst;
376 wst.startMonitoring();
The Android Open Source Project28527d22009-03-03 19:31:44 -0800377
Robert Greenwaltec05b3c2009-10-30 14:17:42 -0700378 break;
379 case ConnectivityManager.TYPE_MOBILE:
380 mNetTrackers[netType] = new MobileDataStateTracker(context, mHandler,
381 netType, mNetAttributes[netType].mName);
382 mNetTrackers[netType].startMonitoring();
Robert Greenwalt1b21f6c2010-02-23 18:58:05 -0800383 if (noMobileData) {
Joe Onoratoc2386bb2010-02-26 18:56:32 -0800384 if (DBG) Slog.d(TAG, "tearing down Mobile networks due to setting");
Robert Greenwalt1b21f6c2010-02-23 18:58:05 -0800385 mNetTrackers[netType].teardown();
386 }
Robert Greenwaltec05b3c2009-10-30 14:17:42 -0700387 break;
TK MUN141623d2011-02-23 18:55:55 +0900388 case ConnectivityManager.TYPE_WIMAX:
389 NetworkStateTracker nst = makeWimaxStateTracker();
390 if (nst != null) {
391 nst.startMonitoring();
392 }
393 mNetTrackers[netType] = nst;
394 break;
Robert Greenwaltec05b3c2009-10-30 14:17:42 -0700395 default:
Joe Onoratoc2386bb2010-02-26 18:56:32 -0800396 Slog.e(TAG, "Trying to create a DataStateTracker for an unknown radio type " +
Robert Greenwaltec05b3c2009-10-30 14:17:42 -0700397 mNetAttributes[netType].mRadio);
398 continue;
399 }
400 }
Robert Greenwalt0c4828c2010-01-26 11:40:34 -0800401
Robert Greenwaltc0b6c602010-03-11 15:03:08 -0800402 mTethering = new Tethering(mContext, mHandler.getLooper());
Robert Greenwaltf1b66e12010-02-25 12:29:30 -0800403 mTetheringConfigValid = (((mNetTrackers[ConnectivityManager.TYPE_MOBILE_DUN] != null) ||
404 !mTethering.isDunRequired()) &&
405 (mTethering.getTetherableUsbRegexs().length != 0 ||
406 mTethering.getTetherableWifiRegexs().length != 0) &&
407 mTethering.getUpstreamIfaceRegexs().length != 0);
408
Robert Greenwalt0e80be12010-09-20 14:35:25 -0700409 if (DBG) {
410 mInetLog = new ArrayList();
411 }
The Android Open Source Project28527d22009-03-03 19:31:44 -0800412 }
413
TK MUN141623d2011-02-23 18:55:55 +0900414 private NetworkStateTracker makeWimaxStateTracker() {
415 //Initialize Wimax
416 DexClassLoader wimaxClassLoader;
417 Class wimaxStateTrackerClass = null;
418 Class wimaxServiceClass = null;
419 Class wimaxManagerClass;
420 String wimaxJarLocation;
421 String wimaxLibLocation;
422 String wimaxManagerClassName;
423 String wimaxServiceClassName;
424 String wimaxStateTrackerClassName;
425
426 NetworkStateTracker wimaxStateTracker = null;
427
428 boolean isWimaxEnabled = mContext.getResources().getBoolean(
429 com.android.internal.R.bool.config_wimaxEnabled);
430
431 if (isWimaxEnabled) {
432 try {
433 wimaxJarLocation = mContext.getResources().getString(
434 com.android.internal.R.string.config_wimaxServiceJarLocation);
435 wimaxLibLocation = mContext.getResources().getString(
436 com.android.internal.R.string.config_wimaxNativeLibLocation);
437 wimaxManagerClassName = mContext.getResources().getString(
438 com.android.internal.R.string.config_wimaxManagerClassname);
439 wimaxServiceClassName = mContext.getResources().getString(
440 com.android.internal.R.string.config_wimaxServiceClassname);
441 wimaxStateTrackerClassName = mContext.getResources().getString(
442 com.android.internal.R.string.config_wimaxStateTrackerClassname);
443
444 wimaxClassLoader = new DexClassLoader(wimaxJarLocation,
445 new ContextWrapper(mContext).getCacheDir().getAbsolutePath(),
446 wimaxLibLocation,ClassLoader.getSystemClassLoader());
447
448 try {
449 wimaxManagerClass = wimaxClassLoader.loadClass(wimaxManagerClassName);
450 wimaxStateTrackerClass = wimaxClassLoader.loadClass(wimaxStateTrackerClassName);
451 wimaxServiceClass = wimaxClassLoader.loadClass(wimaxServiceClassName);
452 } catch (ClassNotFoundException ex) {
453 ex.printStackTrace();
454 return null;
455 }
456 } catch(Resources.NotFoundException ex) {
457 Slog.e(TAG, "Wimax Resources does not exist!!! ");
458 return null;
459 }
460
461 try {
462 Slog.v(TAG, "Starting Wimax Service... ");
463
464 Constructor wmxStTrkrConst = wimaxStateTrackerClass.getConstructor
465 (new Class[] {Context.class,Handler.class});
466 wimaxStateTracker = (NetworkStateTracker)wmxStTrkrConst.newInstance(mContext,mHandler);
467
468 Constructor wmxSrvConst = wimaxServiceClass.getDeclaredConstructor
469 (new Class[] {Context.class,wimaxStateTrackerClass});
470 wmxSrvConst.setAccessible(true);
471 IBinder svcInvoker = (IBinder) wmxSrvConst.newInstance(mContext,wimaxStateTracker);
472 wmxSrvConst.setAccessible(false);
473
474 ServiceManager.addService(WimaxManagerConstants.WIMAX_SERVICE, svcInvoker);
475
476 } catch(ClassCastException ex) {
477 ex.printStackTrace();
478 return null;
479 } catch (NoSuchMethodException ex) {
480 ex.printStackTrace();
481 return null;
482 } catch (InstantiationException ex) {
483 ex.printStackTrace();
484 return null;
485 } catch(IllegalAccessException ex) {
486 ex.printStackTrace();
487 return null;
488 } catch(InvocationTargetException ex) {
489 ex.printStackTrace();
490 return null;
491 } catch(Exception ex) {
492 ex.printStackTrace();
493 return null;
494 }
495 } else {
496 Slog.e(TAG, "Wimax is not enabled or not added to the network attributes!!! ");
497 return null;
498 }
499
500 return wimaxStateTracker;
501 }
Robert Greenwaltec05b3c2009-10-30 14:17:42 -0700502
The Android Open Source Project28527d22009-03-03 19:31:44 -0800503 /**
Robert Greenwalt0659da32009-07-16 17:21:39 -0700504 * Sets the preferred network.
The Android Open Source Project28527d22009-03-03 19:31:44 -0800505 * @param preference the new preference
506 */
Robert Greenwalt6a2db8a2010-09-23 10:05:56 -0700507 public void setNetworkPreference(int preference) {
The Android Open Source Project28527d22009-03-03 19:31:44 -0800508 enforceChangePermission();
Robert Greenwalt6a2db8a2010-09-23 10:05:56 -0700509
510 mHandler.sendMessage(mHandler.obtainMessage(EVENT_SET_NETWORK_PREFERENCE, preference, 0));
The Android Open Source Project28527d22009-03-03 19:31:44 -0800511 }
512
513 public int getNetworkPreference() {
514 enforceAccessPermission();
Robert Greenwalt6a2db8a2010-09-23 10:05:56 -0700515 int preference;
516 synchronized(this) {
517 preference = mNetworkPreference;
518 }
519 return preference;
The Android Open Source Project28527d22009-03-03 19:31:44 -0800520 }
521
Robert Greenwalt6a2db8a2010-09-23 10:05:56 -0700522 private void handleSetNetworkPreference(int preference) {
523 if (ConnectivityManager.isNetworkTypeValid(preference) &&
524 mNetAttributes[preference] != null &&
525 mNetAttributes[preference].isDefault()) {
526 if (mNetworkPreference != preference) {
527 final ContentResolver cr = mContext.getContentResolver();
528 Settings.Secure.putInt(cr, Settings.Secure.NETWORK_PREFERENCE, preference);
529 synchronized(this) {
530 mNetworkPreference = preference;
531 }
532 enforcePreference();
533 }
534 }
The Android Open Source Project28527d22009-03-03 19:31:44 -0800535 }
Robert Greenwalt0659da32009-07-16 17:21:39 -0700536
The Android Open Source Project28527d22009-03-03 19:31:44 -0800537 private int getPersistedNetworkPreference() {
538 final ContentResolver cr = mContext.getContentResolver();
539
540 final int networkPrefSetting = Settings.Secure
541 .getInt(cr, Settings.Secure.NETWORK_PREFERENCE, -1);
542 if (networkPrefSetting != -1) {
543 return networkPrefSetting;
544 }
545
546 return ConnectivityManager.DEFAULT_NETWORK_PREFERENCE;
547 }
Robert Greenwalt0659da32009-07-16 17:21:39 -0700548
The Android Open Source Project28527d22009-03-03 19:31:44 -0800549 /**
Robert Greenwalt0659da32009-07-16 17:21:39 -0700550 * Make the state of network connectivity conform to the preference settings
The Android Open Source Project28527d22009-03-03 19:31:44 -0800551 * In this method, we only tear down a non-preferred network. Establishing
552 * a connection to the preferred network is taken care of when we handle
553 * the disconnect event from the non-preferred network
554 * (see {@link #handleDisconnect(NetworkInfo)}).
555 */
556 private void enforcePreference() {
Robert Greenwalt2034b912009-08-12 16:08:25 -0700557 if (mNetTrackers[mNetworkPreference].getNetworkInfo().isConnected())
The Android Open Source Project28527d22009-03-03 19:31:44 -0800558 return;
559
Robert Greenwalt2034b912009-08-12 16:08:25 -0700560 if (!mNetTrackers[mNetworkPreference].isAvailable())
561 return;
The Android Open Source Project28527d22009-03-03 19:31:44 -0800562
Robert Greenwalt2034b912009-08-12 16:08:25 -0700563 for (int t=0; t <= ConnectivityManager.MAX_RADIO_TYPE; t++) {
Robert Greenwaltec05b3c2009-10-30 14:17:42 -0700564 if (t != mNetworkPreference && mNetTrackers[t] != null &&
Robert Greenwalt2034b912009-08-12 16:08:25 -0700565 mNetTrackers[t].getNetworkInfo().isConnected()) {
Robert Greenwaltf3f045b2009-08-20 15:25:14 -0700566 if (DBG) {
Joe Onoratoc2386bb2010-02-26 18:56:32 -0800567 Slog.d(TAG, "tearing down " +
Robert Greenwaltf3f045b2009-08-20 15:25:14 -0700568 mNetTrackers[t].getNetworkInfo() +
569 " in enforcePreference");
570 }
Robert Greenwalt2034b912009-08-12 16:08:25 -0700571 teardown(mNetTrackers[t]);
The Android Open Source Project28527d22009-03-03 19:31:44 -0800572 }
573 }
574 }
575
576 private boolean teardown(NetworkStateTracker netTracker) {
577 if (netTracker.teardown()) {
578 netTracker.setTeardownRequested(true);
579 return true;
580 } else {
581 return false;
582 }
583 }
584
585 /**
586 * Return NetworkInfo for the active (i.e., connected) network interface.
587 * It is assumed that at most one network is active at a time. If more
588 * than one is active, it is indeterminate which will be returned.
Robert Greenwalt0659da32009-07-16 17:21:39 -0700589 * @return the info for the active network, or {@code null} if none is
590 * active
The Android Open Source Project28527d22009-03-03 19:31:44 -0800591 */
592 public NetworkInfo getActiveNetworkInfo() {
593 enforceAccessPermission();
Robert Greenwalt2034b912009-08-12 16:08:25 -0700594 for (int type=0; type <= ConnectivityManager.MAX_NETWORK_TYPE; type++) {
Robert Greenwaltec05b3c2009-10-30 14:17:42 -0700595 if (mNetAttributes[type] == null || !mNetAttributes[type].isDefault()) {
Robert Greenwalt2034b912009-08-12 16:08:25 -0700596 continue;
597 }
598 NetworkStateTracker t = mNetTrackers[type];
The Android Open Source Project28527d22009-03-03 19:31:44 -0800599 NetworkInfo info = t.getNetworkInfo();
600 if (info.isConnected()) {
Joe Onoratoc2386bb2010-02-26 18:56:32 -0800601 if (DBG && type != mActiveDefaultNetwork) Slog.e(TAG,
Robert Greenwalt2034b912009-08-12 16:08:25 -0700602 "connected default network is not " +
603 "mActiveDefaultNetwork!");
The Android Open Source Project28527d22009-03-03 19:31:44 -0800604 return info;
605 }
606 }
607 return null;
608 }
609
610 public NetworkInfo getNetworkInfo(int networkType) {
611 enforceAccessPermission();
612 if (ConnectivityManager.isNetworkTypeValid(networkType)) {
613 NetworkStateTracker t = mNetTrackers[networkType];
614 if (t != null)
615 return t.getNetworkInfo();
616 }
617 return null;
618 }
619
620 public NetworkInfo[] getAllNetworkInfo() {
621 enforceAccessPermission();
Robert Greenwaltec05b3c2009-10-30 14:17:42 -0700622 NetworkInfo[] result = new NetworkInfo[mNetworksDefined];
The Android Open Source Project28527d22009-03-03 19:31:44 -0800623 int i = 0;
624 for (NetworkStateTracker t : mNetTrackers) {
Robert Greenwaltec05b3c2009-10-30 14:17:42 -0700625 if(t != null) result[i++] = t.getNetworkInfo();
The Android Open Source Project28527d22009-03-03 19:31:44 -0800626 }
627 return result;
628 }
629
630 public boolean setRadios(boolean turnOn) {
631 boolean result = true;
632 enforceChangePermission();
633 for (NetworkStateTracker t : mNetTrackers) {
Robert Greenwaltec05b3c2009-10-30 14:17:42 -0700634 if (t != null) result = t.setRadio(turnOn) && result;
The Android Open Source Project28527d22009-03-03 19:31:44 -0800635 }
636 return result;
637 }
638
639 public boolean setRadio(int netType, boolean turnOn) {
640 enforceChangePermission();
641 if (!ConnectivityManager.isNetworkTypeValid(netType)) {
642 return false;
643 }
644 NetworkStateTracker tracker = mNetTrackers[netType];
645 return tracker != null && tracker.setRadio(turnOn);
646 }
647
Robert Greenwaltaffc3a12009-09-27 17:27:04 -0700648 /**
649 * Used to notice when the calling process dies so we can self-expire
650 *
651 * Also used to know if the process has cleaned up after itself when
652 * our auto-expire timer goes off. The timer has a link to an object.
653 *
654 */
Robert Greenwalt2034b912009-08-12 16:08:25 -0700655 private class FeatureUser implements IBinder.DeathRecipient {
656 int mNetworkType;
657 String mFeature;
658 IBinder mBinder;
659 int mPid;
660 int mUid;
Robert Greenwalt3eeb6032009-12-21 18:24:07 -0800661 long mCreateTime;
Robert Greenwalt2034b912009-08-12 16:08:25 -0700662
663 FeatureUser(int type, String feature, IBinder binder) {
664 super();
665 mNetworkType = type;
666 mFeature = feature;
667 mBinder = binder;
668 mPid = getCallingPid();
669 mUid = getCallingUid();
Robert Greenwalt3eeb6032009-12-21 18:24:07 -0800670 mCreateTime = System.currentTimeMillis();
Robert Greenwaltaffc3a12009-09-27 17:27:04 -0700671
Robert Greenwalt2034b912009-08-12 16:08:25 -0700672 try {
673 mBinder.linkToDeath(this, 0);
674 } catch (RemoteException e) {
675 binderDied();
676 }
677 }
678
679 void unlinkDeathRecipient() {
680 mBinder.unlinkToDeath(this, 0);
681 }
682
683 public void binderDied() {
Joe Onoratoc2386bb2010-02-26 18:56:32 -0800684 Slog.d(TAG, "ConnectivityService FeatureUser binderDied(" +
Robert Greenwalt3eeb6032009-12-21 18:24:07 -0800685 mNetworkType + ", " + mFeature + ", " + mBinder + "), created " +
686 (System.currentTimeMillis() - mCreateTime) + " mSec ago");
Robert Greenwaltaffc3a12009-09-27 17:27:04 -0700687 stopUsingNetworkFeature(this, false);
Robert Greenwalt2034b912009-08-12 16:08:25 -0700688 }
689
Robert Greenwaltaffc3a12009-09-27 17:27:04 -0700690 public void expire() {
Joe Onoratoc2386bb2010-02-26 18:56:32 -0800691 Slog.d(TAG, "ConnectivityService FeatureUser expire(" +
Robert Greenwalt3eeb6032009-12-21 18:24:07 -0800692 mNetworkType + ", " + mFeature + ", " + mBinder +"), created " +
693 (System.currentTimeMillis() - mCreateTime) + " mSec ago");
Robert Greenwaltaffc3a12009-09-27 17:27:04 -0700694 stopUsingNetworkFeature(this, false);
695 }
Robert Greenwalt3eeb6032009-12-21 18:24:07 -0800696
697 public String toString() {
698 return "FeatureUser("+mNetworkType+","+mFeature+","+mPid+","+mUid+"), created " +
699 (System.currentTimeMillis() - mCreateTime) + " mSec ago";
700 }
Robert Greenwalt2034b912009-08-12 16:08:25 -0700701 }
702
Robert Greenwaltaffc3a12009-09-27 17:27:04 -0700703 // javadoc from interface
Robert Greenwalt2034b912009-08-12 16:08:25 -0700704 public int startUsingNetworkFeature(int networkType, String feature,
705 IBinder binder) {
706 if (DBG) {
Joe Onoratoc2386bb2010-02-26 18:56:32 -0800707 Slog.d(TAG, "startUsingNetworkFeature for net " + networkType +
Robert Greenwalt2034b912009-08-12 16:08:25 -0700708 ": " + feature);
709 }
The Android Open Source Project28527d22009-03-03 19:31:44 -0800710 enforceChangePermission();
Robert Greenwaltec05b3c2009-10-30 14:17:42 -0700711 if (!ConnectivityManager.isNetworkTypeValid(networkType) ||
712 mNetAttributes[networkType] == null) {
Robert Greenwalt2034b912009-08-12 16:08:25 -0700713 return Phone.APN_REQUEST_FAILED;
The Android Open Source Project28527d22009-03-03 19:31:44 -0800714 }
Robert Greenwalt2034b912009-08-12 16:08:25 -0700715
Robert Greenwaltaffc3a12009-09-27 17:27:04 -0700716 FeatureUser f = new FeatureUser(networkType, feature, binder);
Robert Greenwalt2034b912009-08-12 16:08:25 -0700717
718 // TODO - move this into the MobileDataStateTracker
719 int usedNetworkType = networkType;
720 if(networkType == ConnectivityManager.TYPE_MOBILE) {
Robert Greenwalt1b21f6c2010-02-23 18:58:05 -0800721 if (!getMobileDataEnabled()) {
Joe Onoratoc2386bb2010-02-26 18:56:32 -0800722 if (DBG) Slog.d(TAG, "requested special network with data disabled - rejected");
Robert Greenwalt1b21f6c2010-02-23 18:58:05 -0800723 return Phone.APN_TYPE_NOT_AVAILABLE;
724 }
Robert Greenwalt2034b912009-08-12 16:08:25 -0700725 if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_MMS)) {
726 usedNetworkType = ConnectivityManager.TYPE_MOBILE_MMS;
727 } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_SUPL)) {
728 usedNetworkType = ConnectivityManager.TYPE_MOBILE_SUPL;
729 } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_DUN)) {
730 usedNetworkType = ConnectivityManager.TYPE_MOBILE_DUN;
731 } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_HIPRI)) {
732 usedNetworkType = ConnectivityManager.TYPE_MOBILE_HIPRI;
733 }
734 }
735 NetworkStateTracker network = mNetTrackers[usedNetworkType];
736 if (network != null) {
737 if (usedNetworkType != networkType) {
738 Integer currentPid = new Integer(getCallingPid());
739
740 NetworkStateTracker radio = mNetTrackers[networkType];
741 NetworkInfo ni = network.getNetworkInfo();
742
743 if (ni.isAvailable() == false) {
Joe Onoratoc2386bb2010-02-26 18:56:32 -0800744 if (DBG) Slog.d(TAG, "special network not available");
Robert Greenwalt2034b912009-08-12 16:08:25 -0700745 return Phone.APN_TYPE_NOT_AVAILABLE;
746 }
747
Robert Greenwaltaffc3a12009-09-27 17:27:04 -0700748 synchronized(this) {
749 mFeatureUsers.add(f);
750 if (!mNetRequestersPids[usedNetworkType].contains(currentPid)) {
751 // this gets used for per-pid dns when connected
752 mNetRequestersPids[usedNetworkType].add(currentPid);
753 }
Robert Greenwalt2034b912009-08-12 16:08:25 -0700754 }
Robert Greenwalt6a2db8a2010-09-23 10:05:56 -0700755 mHandler.sendMessageDelayed(mHandler.obtainMessage(EVENT_RESTORE_DEFAULT_NETWORK,
Robert Greenwaltaffc3a12009-09-27 17:27:04 -0700756 f), getRestoreDefaultNetworkDelay());
757
Robert Greenwalt2034b912009-08-12 16:08:25 -0700758
Robert Greenwalta52c75a2009-08-19 20:19:33 -0700759 if ((ni.isConnectedOrConnecting() == true) &&
760 !network.isTeardownRequested()) {
Robert Greenwalt2034b912009-08-12 16:08:25 -0700761 if (ni.isConnected() == true) {
762 // add the pid-specific dns
Robert Greenwalt0ef68752010-08-13 14:16:12 -0700763 handleDnsConfigurationChange(networkType);
Joe Onoratoc2386bb2010-02-26 18:56:32 -0800764 if (DBG) Slog.d(TAG, "special network already active");
Robert Greenwalt2034b912009-08-12 16:08:25 -0700765 return Phone.APN_ALREADY_ACTIVE;
766 }
Joe Onoratoc2386bb2010-02-26 18:56:32 -0800767 if (DBG) Slog.d(TAG, "special network already connecting");
Robert Greenwalt2034b912009-08-12 16:08:25 -0700768 return Phone.APN_REQUEST_STARTED;
769 }
770
771 // check if the radio in play can make another contact
772 // assume if cannot for now
773
Joe Onoratoc2386bb2010-02-26 18:56:32 -0800774 if (DBG) Slog.d(TAG, "reconnecting to special network");
Robert Greenwalt2034b912009-08-12 16:08:25 -0700775 network.reconnect();
776 return Phone.APN_REQUEST_STARTED;
777 } else {
Robert Greenwaltaffc3a12009-09-27 17:27:04 -0700778 synchronized(this) {
779 mFeatureUsers.add(f);
780 }
Robert Greenwalt6a2db8a2010-09-23 10:05:56 -0700781 mHandler.sendMessageDelayed(mHandler.obtainMessage(EVENT_RESTORE_DEFAULT_NETWORK,
Robert Greenwaltaffc3a12009-09-27 17:27:04 -0700782 f), getRestoreDefaultNetworkDelay());
783
Robert Greenwalt2034b912009-08-12 16:08:25 -0700784 return network.startUsingNetworkFeature(feature,
785 getCallingPid(), getCallingUid());
786 }
787 }
788 return Phone.APN_TYPE_NOT_AVAILABLE;
The Android Open Source Project28527d22009-03-03 19:31:44 -0800789 }
790
Robert Greenwaltaffc3a12009-09-27 17:27:04 -0700791 // javadoc from interface
The Android Open Source Project28527d22009-03-03 19:31:44 -0800792 public int stopUsingNetworkFeature(int networkType, String feature) {
Robert Greenwalt28f43012009-10-06 17:52:40 -0700793 enforceChangePermission();
794
Robert Greenwaltaffc3a12009-09-27 17:27:04 -0700795 int pid = getCallingPid();
796 int uid = getCallingUid();
797
798 FeatureUser u = null;
799 boolean found = false;
800
801 synchronized(this) {
802 for (int i = 0; i < mFeatureUsers.size() ; i++) {
803 u = (FeatureUser)mFeatureUsers.get(i);
804 if (uid == u.mUid && pid == u.mPid &&
805 networkType == u.mNetworkType &&
806 TextUtils.equals(feature, u.mFeature)) {
807 found = true;
808 break;
809 }
810 }
811 }
812 if (found && u != null) {
813 // stop regardless of how many other time this proc had called start
814 return stopUsingNetworkFeature(u, true);
815 } else {
816 // none found!
Joe Onoratoc2386bb2010-02-26 18:56:32 -0800817 if (DBG) Slog.d(TAG, "ignoring stopUsingNetworkFeature - not a live request");
Robert Greenwaltaffc3a12009-09-27 17:27:04 -0700818 return 1;
819 }
Robert Greenwalt2034b912009-08-12 16:08:25 -0700820 }
821
Robert Greenwaltaffc3a12009-09-27 17:27:04 -0700822 private int stopUsingNetworkFeature(FeatureUser u, boolean ignoreDups) {
823 int networkType = u.mNetworkType;
824 String feature = u.mFeature;
825 int pid = u.mPid;
826 int uid = u.mUid;
827
828 NetworkStateTracker tracker = null;
829 boolean callTeardown = false; // used to carry our decision outside of sync block
830
Robert Greenwalt2034b912009-08-12 16:08:25 -0700831 if (DBG) {
Joe Onoratoc2386bb2010-02-26 18:56:32 -0800832 Slog.d(TAG, "stopUsingNetworkFeature for net " + networkType +
Robert Greenwalt2034b912009-08-12 16:08:25 -0700833 ": " + feature);
834 }
Robert Greenwalt28f43012009-10-06 17:52:40 -0700835
The Android Open Source Project28527d22009-03-03 19:31:44 -0800836 if (!ConnectivityManager.isNetworkTypeValid(networkType)) {
837 return -1;
838 }
Robert Greenwalt2034b912009-08-12 16:08:25 -0700839
Robert Greenwaltaffc3a12009-09-27 17:27:04 -0700840 // need to link the mFeatureUsers list with the mNetRequestersPids state in this
841 // sync block
842 synchronized(this) {
843 // check if this process still has an outstanding start request
844 if (!mFeatureUsers.contains(u)) {
Robert Greenwalt46ceefa2010-03-10 16:10:43 -0800845 if (DBG) Slog.d(TAG, "ignoring - this process has no outstanding requests");
Robert Greenwalt2034b912009-08-12 16:08:25 -0700846 return 1;
847 }
Robert Greenwaltaffc3a12009-09-27 17:27:04 -0700848 u.unlinkDeathRecipient();
849 mFeatureUsers.remove(mFeatureUsers.indexOf(u));
850 // If we care about duplicate requests, check for that here.
851 //
852 // This is done to support the extension of a request - the app
853 // can request we start the network feature again and renew the
854 // auto-shutoff delay. Normal "stop" calls from the app though
855 // do not pay attention to duplicate requests - in effect the
856 // API does not refcount and a single stop will counter multiple starts.
857 if (ignoreDups == false) {
858 for (int i = 0; i < mFeatureUsers.size() ; i++) {
859 FeatureUser x = (FeatureUser)mFeatureUsers.get(i);
860 if (x.mUid == u.mUid && x.mPid == u.mPid &&
861 x.mNetworkType == u.mNetworkType &&
862 TextUtils.equals(x.mFeature, u.mFeature)) {
Joe Onoratoc2386bb2010-02-26 18:56:32 -0800863 if (DBG) Slog.d(TAG, "ignoring stopUsingNetworkFeature as dup is found");
Robert Greenwaltaffc3a12009-09-27 17:27:04 -0700864 return 1;
865 }
866 }
Robert Greenwalt2034b912009-08-12 16:08:25 -0700867 }
Robert Greenwaltaffc3a12009-09-27 17:27:04 -0700868
869 // TODO - move to MobileDataStateTracker
870 int usedNetworkType = networkType;
871 if (networkType == ConnectivityManager.TYPE_MOBILE) {
872 if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_MMS)) {
873 usedNetworkType = ConnectivityManager.TYPE_MOBILE_MMS;
874 } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_SUPL)) {
875 usedNetworkType = ConnectivityManager.TYPE_MOBILE_SUPL;
876 } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_DUN)) {
877 usedNetworkType = ConnectivityManager.TYPE_MOBILE_DUN;
878 } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_HIPRI)) {
879 usedNetworkType = ConnectivityManager.TYPE_MOBILE_HIPRI;
880 }
881 }
882 tracker = mNetTrackers[usedNetworkType];
Robert Greenwaltec05b3c2009-10-30 14:17:42 -0700883 if (tracker == null) {
Robert Greenwalt46ceefa2010-03-10 16:10:43 -0800884 if (DBG) Slog.d(TAG, "ignoring - no known tracker for net type " + usedNetworkType);
Robert Greenwaltec05b3c2009-10-30 14:17:42 -0700885 return -1;
886 }
887 if (usedNetworkType != networkType) {
Robert Greenwaltaffc3a12009-09-27 17:27:04 -0700888 Integer currentPid = new Integer(pid);
Robert Greenwaltaffc3a12009-09-27 17:27:04 -0700889 mNetRequestersPids[usedNetworkType].remove(currentPid);
Robert Greenwalt0ca68a02009-12-17 14:54:59 -0800890 reassessPidDns(pid, true);
Robert Greenwaltaffc3a12009-09-27 17:27:04 -0700891 if (mNetRequestersPids[usedNetworkType].size() != 0) {
Joe Onoratoc2386bb2010-02-26 18:56:32 -0800892 if (DBG) Slog.d(TAG, "not tearing down special network - " +
Robert Greenwaltaffc3a12009-09-27 17:27:04 -0700893 "others still using it");
894 return 1;
895 }
896 callTeardown = true;
897 }
898 }
Robert Greenwalt46ceefa2010-03-10 16:10:43 -0800899 if (DBG) Slog.d(TAG, "Doing network teardown");
Robert Greenwaltaffc3a12009-09-27 17:27:04 -0700900 if (callTeardown) {
901 tracker.teardown();
Robert Greenwalt2034b912009-08-12 16:08:25 -0700902 return 1;
903 } else {
Robert Greenwaltaffc3a12009-09-27 17:27:04 -0700904 // do it the old fashioned way
Robert Greenwalt2034b912009-08-12 16:08:25 -0700905 return tracker.stopUsingNetworkFeature(feature, pid, uid);
906 }
The Android Open Source Project28527d22009-03-03 19:31:44 -0800907 }
908
909 /**
910 * Ensure that a network route exists to deliver traffic to the specified
911 * host via the specified network interface.
Robert Greenwalt0659da32009-07-16 17:21:39 -0700912 * @param networkType the type of the network over which traffic to the
913 * specified host is to be routed
914 * @param hostAddress the IP address of the host to which the route is
915 * desired
The Android Open Source Project28527d22009-03-03 19:31:44 -0800916 * @return {@code true} on success, {@code false} on failure
917 */
918 public boolean requestRouteToHost(int networkType, int hostAddress) {
919 enforceChangePermission();
920 if (!ConnectivityManager.isNetworkTypeValid(networkType)) {
921 return false;
922 }
923 NetworkStateTracker tracker = mNetTrackers[networkType];
Robert Greenwalt4666ed02009-09-10 15:06:20 -0700924
Robert Greenwaltec05b3c2009-10-30 14:17:42 -0700925 if (tracker == null || !tracker.getNetworkInfo().isConnected() ||
926 tracker.isTeardownRequested()) {
Robert Greenwalt4666ed02009-09-10 15:06:20 -0700927 if (DBG) {
Joe Onoratoc2386bb2010-02-26 18:56:32 -0800928 Slog.d(TAG, "requestRouteToHost on down network (" + networkType + ") - dropped");
Robert Greenwalt4666ed02009-09-10 15:06:20 -0700929 }
930 return false;
The Android Open Source Project28527d22009-03-03 19:31:44 -0800931 }
Robert Greenwalt4666ed02009-09-10 15:06:20 -0700932 return tracker.requestRouteToHost(hostAddress);
The Android Open Source Project28527d22009-03-03 19:31:44 -0800933 }
934
935 /**
936 * @see ConnectivityManager#getBackgroundDataSetting()
937 */
938 public boolean getBackgroundDataSetting() {
939 return Settings.Secure.getInt(mContext.getContentResolver(),
940 Settings.Secure.BACKGROUND_DATA, 1) == 1;
941 }
Robert Greenwalt0659da32009-07-16 17:21:39 -0700942
The Android Open Source Project28527d22009-03-03 19:31:44 -0800943 /**
944 * @see ConnectivityManager#setBackgroundDataSetting(boolean)
945 */
946 public void setBackgroundDataSetting(boolean allowBackgroundDataUsage) {
947 mContext.enforceCallingOrSelfPermission(
948 android.Manifest.permission.CHANGE_BACKGROUND_DATA_SETTING,
949 "ConnectivityService");
Robert Greenwalt0659da32009-07-16 17:21:39 -0700950
Robert Greenwalt6a2db8a2010-09-23 10:05:56 -0700951 mHandler.sendMessage(mHandler.obtainMessage(EVENT_SET_BACKGROUND_DATA,
952 (allowBackgroundDataUsage ? ENABLED : DISABLED), 0));
953 }
The Android Open Source Project28527d22009-03-03 19:31:44 -0800954
Robert Greenwalt6a2db8a2010-09-23 10:05:56 -0700955 private void handleSetBackgroundData(boolean enabled) {
956 if (enabled != getBackgroundDataSetting()) {
957 Settings.Secure.putInt(mContext.getContentResolver(),
958 Settings.Secure.BACKGROUND_DATA, enabled ? 1 : 0);
959 Intent broadcast = new Intent(
960 ConnectivityManager.ACTION_BACKGROUND_DATA_SETTING_CHANGED);
961 mContext.sendBroadcast(broadcast);
962 }
Robert Greenwalt0659da32009-07-16 17:21:39 -0700963 }
964
Robert Greenwalt1b21f6c2010-02-23 18:58:05 -0800965 /**
966 * @see ConnectivityManager#getMobileDataEnabled()
967 */
968 public boolean getMobileDataEnabled() {
969 enforceAccessPermission();
970 boolean retVal = Settings.Secure.getInt(mContext.getContentResolver(),
971 Settings.Secure.MOBILE_DATA, 1) == 1;
Joe Onoratoc2386bb2010-02-26 18:56:32 -0800972 if (DBG) Slog.d(TAG, "getMobileDataEnabled returning " + retVal);
Robert Greenwalt1b21f6c2010-02-23 18:58:05 -0800973 return retVal;
974 }
975
976 /**
977 * @see ConnectivityManager#setMobileDataEnabled(boolean)
978 */
Robert Greenwalt6a2db8a2010-09-23 10:05:56 -0700979 public void setMobileDataEnabled(boolean enabled) {
Robert Greenwalt1b21f6c2010-02-23 18:58:05 -0800980 enforceChangePermission();
Joe Onoratoc2386bb2010-02-26 18:56:32 -0800981 if (DBG) Slog.d(TAG, "setMobileDataEnabled(" + enabled + ")");
Robert Greenwalt1b21f6c2010-02-23 18:58:05 -0800982
Robert Greenwalt6a2db8a2010-09-23 10:05:56 -0700983 mHandler.sendMessage(mHandler.obtainMessage(EVENT_SET_MOBILE_DATA,
984 (enabled ? ENABLED : DISABLED), 0));
985 }
986
987 private void handleSetMobileData(boolean enabled) {
Robert Greenwalt1b21f6c2010-02-23 18:58:05 -0800988 if (getMobileDataEnabled() == enabled) return;
989
990 Settings.Secure.putInt(mContext.getContentResolver(),
991 Settings.Secure.MOBILE_DATA, enabled ? 1 : 0);
992
993 if (enabled) {
994 if (mNetTrackers[ConnectivityManager.TYPE_MOBILE] != null) {
Robert Greenwalt6a2db8a2010-09-23 10:05:56 -0700995 if (DBG) {
996 Slog.d(TAG, "starting up " + mNetTrackers[ConnectivityManager.TYPE_MOBILE]);
997 }
Robert Greenwalt1b21f6c2010-02-23 18:58:05 -0800998 mNetTrackers[ConnectivityManager.TYPE_MOBILE].reconnect();
999 }
1000 } else {
1001 for (NetworkStateTracker nt : mNetTrackers) {
1002 if (nt == null) continue;
1003 int netType = nt.getNetworkInfo().getType();
1004 if (mNetAttributes[netType].mRadio == ConnectivityManager.TYPE_MOBILE) {
Joe Onoratoc2386bb2010-02-26 18:56:32 -08001005 if (DBG) Slog.d(TAG, "tearing down " + nt);
Robert Greenwalt1b21f6c2010-02-23 18:58:05 -08001006 nt.teardown();
1007 }
1008 }
1009 }
1010 }
1011
The Android Open Source Project28527d22009-03-03 19:31:44 -08001012 private int getNumConnectedNetworks() {
1013 int numConnectedNets = 0;
1014
1015 for (NetworkStateTracker nt : mNetTrackers) {
Robert Greenwaltec05b3c2009-10-30 14:17:42 -07001016 if (nt != null && nt.getNetworkInfo().isConnected() &&
Robert Greenwalt0659da32009-07-16 17:21:39 -07001017 !nt.isTeardownRequested()) {
The Android Open Source Project28527d22009-03-03 19:31:44 -08001018 ++numConnectedNets;
1019 }
1020 }
1021 return numConnectedNets;
1022 }
1023
1024 private void enforceAccessPermission() {
Robert Greenwalt0659da32009-07-16 17:21:39 -07001025 mContext.enforceCallingOrSelfPermission(
1026 android.Manifest.permission.ACCESS_NETWORK_STATE,
1027 "ConnectivityService");
The Android Open Source Project28527d22009-03-03 19:31:44 -08001028 }
1029
1030 private void enforceChangePermission() {
Robert Greenwalt0659da32009-07-16 17:21:39 -07001031 mContext.enforceCallingOrSelfPermission(
1032 android.Manifest.permission.CHANGE_NETWORK_STATE,
1033 "ConnectivityService");
The Android Open Source Project28527d22009-03-03 19:31:44 -08001034 }
1035
Robert Greenwalt0c4828c2010-01-26 11:40:34 -08001036 // TODO Make this a special check when it goes public
1037 private void enforceTetherChangePermission() {
1038 mContext.enforceCallingOrSelfPermission(
1039 android.Manifest.permission.CHANGE_NETWORK_STATE,
1040 "ConnectivityService");
1041 }
1042
Robert Greenwalt8e87f122010-02-11 18:18:40 -08001043 private void enforceTetherAccessPermission() {
1044 mContext.enforceCallingOrSelfPermission(
1045 android.Manifest.permission.ACCESS_NETWORK_STATE,
1046 "ConnectivityService");
1047 }
1048
The Android Open Source Project28527d22009-03-03 19:31:44 -08001049 /**
Robert Greenwalt0659da32009-07-16 17:21:39 -07001050 * Handle a {@code DISCONNECTED} event. If this pertains to the non-active
1051 * network, we ignore it. If it is for the active network, we send out a
1052 * broadcast. But first, we check whether it might be possible to connect
1053 * to a different network.
The Android Open Source Project28527d22009-03-03 19:31:44 -08001054 * @param info the {@code NetworkInfo} for the network
1055 */
1056 private void handleDisconnect(NetworkInfo info) {
1057
Robert Greenwalt2034b912009-08-12 16:08:25 -07001058 int prevNetType = info.getType();
The Android Open Source Project28527d22009-03-03 19:31:44 -08001059
Robert Greenwalt2034b912009-08-12 16:08:25 -07001060 mNetTrackers[prevNetType].setTeardownRequested(false);
The Android Open Source Project28527d22009-03-03 19:31:44 -08001061 /*
1062 * If the disconnected network is not the active one, then don't report
1063 * this as a loss of connectivity. What probably happened is that we're
1064 * getting the disconnect for a network that we explicitly disabled
1065 * in accordance with network preference policies.
1066 */
Robert Greenwalt2034b912009-08-12 16:08:25 -07001067 if (!mNetAttributes[prevNetType].isDefault()) {
1068 List pids = mNetRequestersPids[prevNetType];
1069 for (int i = 0; i<pids.size(); i++) {
1070 Integer pid = (Integer)pids.get(i);
1071 // will remove them because the net's no longer connected
1072 // need to do this now as only now do we know the pids and
1073 // can properly null things that are no longer referenced.
1074 reassessPidDns(pid.intValue(), false);
The Android Open Source Project28527d22009-03-03 19:31:44 -08001075 }
The Android Open Source Project28527d22009-03-03 19:31:44 -08001076 }
1077
The Android Open Source Project28527d22009-03-03 19:31:44 -08001078 Intent intent = new Intent(ConnectivityManager.CONNECTIVITY_ACTION);
1079 intent.putExtra(ConnectivityManager.EXTRA_NETWORK_INFO, info);
1080 if (info.isFailover()) {
1081 intent.putExtra(ConnectivityManager.EXTRA_IS_FAILOVER, true);
1082 info.setFailover(false);
1083 }
1084 if (info.getReason() != null) {
1085 intent.putExtra(ConnectivityManager.EXTRA_REASON, info.getReason());
1086 }
1087 if (info.getExtraInfo() != null) {
Robert Greenwalt0659da32009-07-16 17:21:39 -07001088 intent.putExtra(ConnectivityManager.EXTRA_EXTRA_INFO,
1089 info.getExtraInfo());
The Android Open Source Project28527d22009-03-03 19:31:44 -08001090 }
Robert Greenwalt2034b912009-08-12 16:08:25 -07001091
Robert Greenwalt3cc68d32010-01-25 17:54:29 -08001092 if (mNetAttributes[prevNetType].isDefault()) {
Robert Greenwalt9e081592011-03-10 16:58:31 -08001093 tryFailover(prevNetType);
1094 if (mActiveDefaultNetwork != -1) {
1095 NetworkInfo switchTo = mNetTrackers[mActiveDefaultNetwork].getNetworkInfo();
Robert Greenwalt3cc68d32010-01-25 17:54:29 -08001096 intent.putExtra(ConnectivityManager.EXTRA_OTHER_NETWORK_INFO, switchTo);
1097 } else {
Robert Greenwaltb2a9e492010-09-20 18:01:43 -07001098 mDefaultInetConditionPublished = 0; // we're not connected anymore
Robert Greenwalt3cc68d32010-01-25 17:54:29 -08001099 intent.putExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, true);
1100 }
Robert Greenwaltf55ced92010-01-20 19:29:41 -08001101 }
Robert Greenwaltb2a9e492010-09-20 18:01:43 -07001102 intent.putExtra(ConnectivityManager.EXTRA_INET_CONDITION, mDefaultInetConditionPublished);
Robert Greenwaltf55ced92010-01-20 19:29:41 -08001103 // do this before we broadcast the change
Robert Greenwalt0ef68752010-08-13 14:16:12 -07001104 handleConnectivityChange(prevNetType);
Robert Greenwaltf55ced92010-01-20 19:29:41 -08001105
1106 sendStickyBroadcast(intent);
1107 /*
1108 * If the failover network is already connected, then immediately send
1109 * out a followup broadcast indicating successful failover
1110 */
Robert Greenwalt9e081592011-03-10 16:58:31 -08001111 if (mActiveDefaultNetwork != -1) {
1112 sendConnectedBroadcast(mNetTrackers[mActiveDefaultNetwork].getNetworkInfo());
Robert Greenwaltf55ced92010-01-20 19:29:41 -08001113 }
1114 }
1115
Robert Greenwalt9e081592011-03-10 16:58:31 -08001116 private void tryFailover(int prevNetType) {
Robert Greenwalt2034b912009-08-12 16:08:25 -07001117 /*
1118 * If this is a default network, check if other defaults are available
1119 * or active
1120 */
Robert Greenwalt2034b912009-08-12 16:08:25 -07001121 if (mNetAttributes[prevNetType].isDefault()) {
Robert Greenwalt2034b912009-08-12 16:08:25 -07001122 if (mActiveDefaultNetwork == prevNetType) {
1123 mActiveDefaultNetwork = -1;
1124 }
1125
Robert Greenwalt72451bf2010-02-25 12:04:29 -08001126 boolean noMobileData = !getMobileDataEnabled();
Robert Greenwaltf55ced92010-01-20 19:29:41 -08001127 for (int checkType=0; checkType <= ConnectivityManager.MAX_NETWORK_TYPE; checkType++) {
Robert Greenwaltec05b3c2009-10-30 14:17:42 -07001128 if (checkType == prevNetType) continue;
1129 if (mNetAttributes[checkType] == null) continue;
Robert Greenwalt084e4772011-02-11 17:32:58 -08001130 if (mNetAttributes[checkType].isDefault() == false) continue;
Robert Greenwalt72451bf2010-02-25 12:04:29 -08001131 if (mNetAttributes[checkType].mRadio == ConnectivityManager.TYPE_MOBILE &&
1132 noMobileData) {
Robert Greenwalte981bc52010-10-08 16:35:52 -07001133 Slog.e(TAG, "not failing over to mobile type " + checkType +
1134 " because Mobile Data Disabled");
Robert Greenwalt72451bf2010-02-25 12:04:29 -08001135 continue;
1136 }
Robert Greenwalt9e081592011-03-10 16:58:31 -08001137 NetworkStateTracker checkTracker = mNetTrackers[checkType];
1138 NetworkInfo checkInfo = checkTracker.getNetworkInfo();
1139 if (!checkInfo.isConnectedOrConnecting() || checkTracker.isTeardownRequested()) {
1140 checkInfo.setFailover(true);
1141 checkTracker.reconnect();
The Android Open Source Project28527d22009-03-03 19:31:44 -08001142 }
Robert Greenwalt9e081592011-03-10 16:58:31 -08001143 if (DBG) Slog.d(TAG, "Attempting to switch to " + checkInfo.getTypeName());
Robert Greenwalt2034b912009-08-12 16:08:25 -07001144 }
The Android Open Source Project28527d22009-03-03 19:31:44 -08001145 }
The Android Open Source Project28527d22009-03-03 19:31:44 -08001146 }
1147
1148 private void sendConnectedBroadcast(NetworkInfo info) {
Robert Greenwaltd3401f92010-09-15 17:36:33 -07001149 sendGeneralBroadcast(info, ConnectivityManager.CONNECTIVITY_ACTION);
1150 }
1151
1152 private void sendInetConditionBroadcast(NetworkInfo info) {
1153 sendGeneralBroadcast(info, ConnectivityManager.INET_CONDITION_ACTION);
1154 }
1155
1156 private void sendGeneralBroadcast(NetworkInfo info, String bcastType) {
1157 Intent intent = new Intent(bcastType);
The Android Open Source Project28527d22009-03-03 19:31:44 -08001158 intent.putExtra(ConnectivityManager.EXTRA_NETWORK_INFO, info);
1159 if (info.isFailover()) {
1160 intent.putExtra(ConnectivityManager.EXTRA_IS_FAILOVER, true);
1161 info.setFailover(false);
1162 }
1163 if (info.getReason() != null) {
1164 intent.putExtra(ConnectivityManager.EXTRA_REASON, info.getReason());
1165 }
1166 if (info.getExtraInfo() != null) {
Robert Greenwalt0659da32009-07-16 17:21:39 -07001167 intent.putExtra(ConnectivityManager.EXTRA_EXTRA_INFO,
1168 info.getExtraInfo());
The Android Open Source Project28527d22009-03-03 19:31:44 -08001169 }
Robert Greenwalt986c7412010-09-08 15:24:47 -07001170 intent.putExtra(ConnectivityManager.EXTRA_INET_CONDITION, mDefaultInetConditionPublished);
Mike Lockwoodfde2b762009-08-14 14:18:49 -04001171 sendStickyBroadcast(intent);
The Android Open Source Project28527d22009-03-03 19:31:44 -08001172 }
1173
1174 /**
1175 * Called when an attempt to fail over to another network has failed.
1176 * @param info the {@link NetworkInfo} for the failed network
1177 */
1178 private void handleConnectionFailure(NetworkInfo info) {
1179 mNetTrackers[info.getType()].setTeardownRequested(false);
The Android Open Source Project28527d22009-03-03 19:31:44 -08001180
Robert Greenwalt2034b912009-08-12 16:08:25 -07001181 String reason = info.getReason();
1182 String extraInfo = info.getExtraInfo();
Robert Greenwalt0659da32009-07-16 17:21:39 -07001183
Robert Greenwalte981bc52010-10-08 16:35:52 -07001184 String reasonText;
1185 if (reason == null) {
1186 reasonText = ".";
1187 } else {
1188 reasonText = " (" + reason + ").";
The Android Open Source Project28527d22009-03-03 19:31:44 -08001189 }
Robert Greenwalte981bc52010-10-08 16:35:52 -07001190 Slog.e(TAG, "Attempt to connect to " + info.getTypeName() + " failed" + reasonText);
Robert Greenwalt2034b912009-08-12 16:08:25 -07001191
1192 Intent intent = new Intent(ConnectivityManager.CONNECTIVITY_ACTION);
1193 intent.putExtra(ConnectivityManager.EXTRA_NETWORK_INFO, info);
1194 if (getActiveNetworkInfo() == null) {
1195 intent.putExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, true);
1196 }
1197 if (reason != null) {
1198 intent.putExtra(ConnectivityManager.EXTRA_REASON, reason);
1199 }
1200 if (extraInfo != null) {
1201 intent.putExtra(ConnectivityManager.EXTRA_EXTRA_INFO, extraInfo);
1202 }
1203 if (info.isFailover()) {
1204 intent.putExtra(ConnectivityManager.EXTRA_IS_FAILOVER, true);
1205 info.setFailover(false);
1206 }
Robert Greenwaltf55ced92010-01-20 19:29:41 -08001207
Robert Greenwalt3cc68d32010-01-25 17:54:29 -08001208 if (mNetAttributes[info.getType()].isDefault()) {
Robert Greenwalt9e081592011-03-10 16:58:31 -08001209 tryFailover(info.getType());
1210 if (mActiveDefaultNetwork != -1) {
1211 NetworkInfo switchTo = mNetTrackers[mActiveDefaultNetwork].getNetworkInfo();
Robert Greenwalt3cc68d32010-01-25 17:54:29 -08001212 intent.putExtra(ConnectivityManager.EXTRA_OTHER_NETWORK_INFO, switchTo);
1213 } else {
Robert Greenwaltb2a9e492010-09-20 18:01:43 -07001214 mDefaultInetConditionPublished = 0;
Robert Greenwalt3cc68d32010-01-25 17:54:29 -08001215 intent.putExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, true);
1216 }
Robert Greenwaltf55ced92010-01-20 19:29:41 -08001217 }
Robert Greenwalt3cc68d32010-01-25 17:54:29 -08001218
Robert Greenwaltb2a9e492010-09-20 18:01:43 -07001219 intent.putExtra(ConnectivityManager.EXTRA_INET_CONDITION, mDefaultInetConditionPublished);
Mike Lockwoodfde2b762009-08-14 14:18:49 -04001220 sendStickyBroadcast(intent);
Robert Greenwaltf55ced92010-01-20 19:29:41 -08001221 /*
1222 * If the failover network is already connected, then immediately send
1223 * out a followup broadcast indicating successful failover
1224 */
Robert Greenwalt9e081592011-03-10 16:58:31 -08001225 if (mActiveDefaultNetwork != -1) {
1226 sendConnectedBroadcast(mNetTrackers[mActiveDefaultNetwork].getNetworkInfo());
Robert Greenwaltf55ced92010-01-20 19:29:41 -08001227 }
Mike Lockwoodfde2b762009-08-14 14:18:49 -04001228 }
1229
1230 private void sendStickyBroadcast(Intent intent) {
1231 synchronized(this) {
Dianne Hackborna417ff82009-12-08 19:45:14 -08001232 if (!mSystemReady) {
1233 mInitialBroadcast = new Intent(intent);
Mike Lockwoodfde2b762009-08-14 14:18:49 -04001234 }
Dianne Hackborna417ff82009-12-08 19:45:14 -08001235 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
1236 mContext.sendStickyBroadcast(intent);
Mike Lockwoodfde2b762009-08-14 14:18:49 -04001237 }
1238 }
1239
1240 void systemReady() {
1241 synchronized(this) {
1242 mSystemReady = true;
Dianne Hackborna417ff82009-12-08 19:45:14 -08001243 if (mInitialBroadcast != null) {
1244 mContext.sendStickyBroadcast(mInitialBroadcast);
1245 mInitialBroadcast = null;
Mike Lockwoodfde2b762009-08-14 14:18:49 -04001246 }
1247 }
The Android Open Source Project28527d22009-03-03 19:31:44 -08001248 }
1249
1250 private void handleConnect(NetworkInfo info) {
Robert Greenwalt2034b912009-08-12 16:08:25 -07001251 int type = info.getType();
The Android Open Source Project28527d22009-03-03 19:31:44 -08001252
1253 // snapshot isFailover, because sendConnectedBroadcast() resets it
1254 boolean isFailover = info.isFailover();
Robert Greenwalt2034b912009-08-12 16:08:25 -07001255 NetworkStateTracker thisNet = mNetTrackers[type];
The Android Open Source Project28527d22009-03-03 19:31:44 -08001256
Robert Greenwalt2034b912009-08-12 16:08:25 -07001257 // if this is a default net and other default is running
1258 // kill the one not preferred
1259 if (mNetAttributes[type].isDefault()) {
Robert Greenwalt2034b912009-08-12 16:08:25 -07001260 if (mActiveDefaultNetwork != -1 && mActiveDefaultNetwork != type) {
1261 if ((type != mNetworkPreference &&
1262 mNetAttributes[mActiveDefaultNetwork].mPriority >
1263 mNetAttributes[type].mPriority) ||
1264 mNetworkPreference == mActiveDefaultNetwork) {
1265 // don't accept this one
Joe Onoratoc2386bb2010-02-26 18:56:32 -08001266 if (DBG) Slog.v(TAG, "Not broadcasting CONNECT_ACTION " +
Robert Greenwalt2034b912009-08-12 16:08:25 -07001267 "to torn down network " + info.getTypeName());
1268 teardown(thisNet);
1269 return;
1270 } else {
1271 // tear down the other
1272 NetworkStateTracker otherNet =
1273 mNetTrackers[mActiveDefaultNetwork];
Joe Onoratoc2386bb2010-02-26 18:56:32 -08001274 if (DBG) Slog.v(TAG, "Policy requires " +
Robert Greenwalt2034b912009-08-12 16:08:25 -07001275 otherNet.getNetworkInfo().getTypeName() +
1276 " teardown");
1277 if (!teardown(otherNet)) {
Joe Onoratoc2386bb2010-02-26 18:56:32 -08001278 Slog.e(TAG, "Network declined teardown request");
Robert Greenwalt2034b912009-08-12 16:08:25 -07001279 return;
1280 }
1281 if (isFailover) {
1282 otherNet.releaseWakeLock();
1283 }
1284 }
1285 }
1286 mActiveDefaultNetwork = type;
Robert Greenwalt986c7412010-09-08 15:24:47 -07001287 // this will cause us to come up initially as unconnected and switching
1288 // to connected after our normal pause unless somebody reports us as reall
1289 // disconnected
1290 mDefaultInetConditionPublished = 0;
1291 mDefaultConnectionSequence++;
1292 mInetConditionChangeInFlight = false;
1293 // Don't do this - if we never sign in stay, grey
1294 //reportNetworkCondition(mActiveDefaultNetwork, 100);
Robert Greenwalt2034b912009-08-12 16:08:25 -07001295 }
The Android Open Source Project28527d22009-03-03 19:31:44 -08001296 thisNet.setTeardownRequested(false);
Robert Greenwalt2034b912009-08-12 16:08:25 -07001297 thisNet.updateNetworkSettings();
Robert Greenwalt0ef68752010-08-13 14:16:12 -07001298 handleConnectivityChange(type);
Robert Greenwalt2034b912009-08-12 16:08:25 -07001299 sendConnectedBroadcast(info);
The Android Open Source Project28527d22009-03-03 19:31:44 -08001300 }
1301
1302 private void handleScanResultsAvailable(NetworkInfo info) {
1303 int networkType = info.getType();
1304 if (networkType != ConnectivityManager.TYPE_WIFI) {
Joe Onoratoc2386bb2010-02-26 18:56:32 -08001305 if (DBG) Slog.v(TAG, "Got ScanResultsAvailable for " +
Robert Greenwalt0659da32009-07-16 17:21:39 -07001306 info.getTypeName() + " network. Don't know how to handle.");
The Android Open Source Project28527d22009-03-03 19:31:44 -08001307 }
Robert Greenwalt0659da32009-07-16 17:21:39 -07001308
The Android Open Source Project28527d22009-03-03 19:31:44 -08001309 mNetTrackers[networkType].interpretScanResultsAvailable();
1310 }
1311
Robert Greenwalt0659da32009-07-16 17:21:39 -07001312 private void handleNotificationChange(boolean visible, int id,
1313 Notification notification) {
The Android Open Source Project28527d22009-03-03 19:31:44 -08001314 NotificationManager notificationManager = (NotificationManager) mContext
1315 .getSystemService(Context.NOTIFICATION_SERVICE);
Robert Greenwalt0659da32009-07-16 17:21:39 -07001316
The Android Open Source Project28527d22009-03-03 19:31:44 -08001317 if (visible) {
1318 notificationManager.notify(id, notification);
1319 } else {
1320 notificationManager.cancel(id);
1321 }
1322 }
1323
1324 /**
Robert Greenwalt0ef68752010-08-13 14:16:12 -07001325 * After a change in the connectivity state of any network, We're mainly
1326 * concerned with making sure that the list of DNS servers is setupup
1327 * according to which networks are connected, and ensuring that the
1328 * right routing table entries exist.
The Android Open Source Project28527d22009-03-03 19:31:44 -08001329 */
Robert Greenwalt0ef68752010-08-13 14:16:12 -07001330 private void handleConnectivityChange(int netType) {
The Android Open Source Project28527d22009-03-03 19:31:44 -08001331 /*
Robert Greenwalt2034b912009-08-12 16:08:25 -07001332 * If a non-default network is enabled, add the host routes that
Robert Greenwalt0ef68752010-08-13 14:16:12 -07001333 * will allow it's DNS servers to be accessed.
The Android Open Source Project28527d22009-03-03 19:31:44 -08001334 */
Robert Greenwalt0ef68752010-08-13 14:16:12 -07001335 handleDnsConfigurationChange(netType);
Robert Greenwalt2034b912009-08-12 16:08:25 -07001336
Robert Greenwalt0ef68752010-08-13 14:16:12 -07001337 if (mNetTrackers[netType].getNetworkInfo().isConnected()) {
1338 if (mNetAttributes[netType].isDefault()) {
1339 mNetTrackers[netType].addDefaultRoute();
Robert Greenwalt2034b912009-08-12 16:08:25 -07001340 } else {
Robert Greenwalt0ef68752010-08-13 14:16:12 -07001341 mNetTrackers[netType].addPrivateDnsRoutes();
1342 }
1343 } else {
1344 if (mNetAttributes[netType].isDefault()) {
1345 mNetTrackers[netType].removeDefaultRoute();
1346 } else {
1347 mNetTrackers[netType].removePrivateDnsRoutes();
Robert Greenwalt2034b912009-08-12 16:08:25 -07001348 }
The Android Open Source Project28527d22009-03-03 19:31:44 -08001349 }
1350 }
1351
Robert Greenwalt2034b912009-08-12 16:08:25 -07001352 /**
1353 * Adjust the per-process dns entries (net.dns<x>.<pid>) based
1354 * on the highest priority active net which this process requested.
1355 * If there aren't any, clear it out
1356 */
1357 private void reassessPidDns(int myPid, boolean doBump)
1358 {
Joe Onoratoc2386bb2010-02-26 18:56:32 -08001359 if (DBG) Slog.d(TAG, "reassessPidDns for pid " + myPid);
Robert Greenwalt2034b912009-08-12 16:08:25 -07001360 for(int i : mPriorityList) {
1361 if (mNetAttributes[i].isDefault()) {
1362 continue;
1363 }
1364 NetworkStateTracker nt = mNetTrackers[i];
Robert Greenwalt0659da32009-07-16 17:21:39 -07001365 if (nt.getNetworkInfo().isConnected() &&
1366 !nt.isTeardownRequested()) {
Robert Greenwalt2034b912009-08-12 16:08:25 -07001367 List pids = mNetRequestersPids[i];
1368 for (int j=0; j<pids.size(); j++) {
1369 Integer pid = (Integer)pids.get(j);
1370 if (pid.intValue() == myPid) {
1371 String[] dnsList = nt.getNameServers();
1372 writePidDns(dnsList, myPid);
1373 if (doBump) {
1374 bumpDns();
1375 }
1376 return;
1377 }
1378 }
1379 }
1380 }
1381 // nothing found - delete
1382 for (int i = 1; ; i++) {
1383 String prop = "net.dns" + i + "." + myPid;
1384 if (SystemProperties.get(prop).length() == 0) {
1385 if (doBump) {
1386 bumpDns();
1387 }
1388 return;
1389 }
1390 SystemProperties.set(prop, "");
1391 }
1392 }
1393
1394 private void writePidDns(String[] dnsList, int pid) {
1395 int j = 1;
1396 for (String dns : dnsList) {
1397 if (dns != null && !TextUtils.equals(dns, "0.0.0.0")) {
1398 SystemProperties.set("net.dns" + j++ + "." + pid, dns);
1399 }
1400 }
1401 }
1402
1403 private void bumpDns() {
1404 /*
1405 * Bump the property that tells the name resolver library to reread
1406 * the DNS server list from the properties.
1407 */
1408 String propVal = SystemProperties.get("net.dnschange");
1409 int n = 0;
1410 if (propVal.length() != 0) {
1411 try {
1412 n = Integer.parseInt(propVal);
1413 } catch (NumberFormatException e) {}
1414 }
1415 SystemProperties.set("net.dnschange", "" + (n+1));
1416 }
1417
Robert Greenwalt0ef68752010-08-13 14:16:12 -07001418 private void handleDnsConfigurationChange(int netType) {
Robert Greenwalt2034b912009-08-12 16:08:25 -07001419 // add default net's dns entries
Robert Greenwalt0ef68752010-08-13 14:16:12 -07001420 NetworkStateTracker nt = mNetTrackers[netType];
1421 if (nt != null && nt.getNetworkInfo().isConnected() && !nt.isTeardownRequested()) {
1422 String[] dnsList = nt.getNameServers();
1423 if (mNetAttributes[netType].isDefault()) {
1424 int j = 1;
1425 for (String dns : dnsList) {
1426 if (dns != null && !TextUtils.equals(dns, "0.0.0.0")) {
1427 if (DBG) {
1428 Slog.d(TAG, "adding dns " + dns + " for " +
1429 nt.getNetworkInfo().getTypeName());
Robert Greenwalt2034b912009-08-12 16:08:25 -07001430 }
Robert Greenwalt0ef68752010-08-13 14:16:12 -07001431 SystemProperties.set("net.dns" + j++, dns);
Robert Greenwalt2034b912009-08-12 16:08:25 -07001432 }
Robert Greenwalt0ef68752010-08-13 14:16:12 -07001433 }
1434 for (int k=j ; k<mNumDnsEntries; k++) {
1435 if (DBG) Slog.d(TAG, "erasing net.dns" + k);
1436 SystemProperties.set("net.dns" + k, "");
1437 }
1438 mNumDnsEntries = j;
1439 } else {
1440 // set per-pid dns for attached secondary nets
1441 List pids = mNetRequestersPids[netType];
1442 for (int y=0; y< pids.size(); y++) {
1443 Integer pid = (Integer)pids.get(y);
1444 writePidDns(dnsList, pid.intValue());
The Android Open Source Project28527d22009-03-03 19:31:44 -08001445 }
1446 }
1447 }
Robert Greenwalt2034b912009-08-12 16:08:25 -07001448 bumpDns();
1449 }
1450
1451 private int getRestoreDefaultNetworkDelay() {
1452 String restoreDefaultNetworkDelayStr = SystemProperties.get(
1453 NETWORK_RESTORE_DELAY_PROP_NAME);
1454 if(restoreDefaultNetworkDelayStr != null &&
1455 restoreDefaultNetworkDelayStr.length() != 0) {
1456 try {
1457 return Integer.valueOf(restoreDefaultNetworkDelayStr);
1458 } catch (NumberFormatException e) {
1459 }
The Android Open Source Project28527d22009-03-03 19:31:44 -08001460 }
Robert Greenwalt2034b912009-08-12 16:08:25 -07001461 return RESTORE_DEFAULT_NETWORK_DELAY;
The Android Open Source Project28527d22009-03-03 19:31:44 -08001462 }
1463
1464 @Override
1465 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
Robert Greenwalt0659da32009-07-16 17:21:39 -07001466 if (mContext.checkCallingOrSelfPermission(
1467 android.Manifest.permission.DUMP)
The Android Open Source Project28527d22009-03-03 19:31:44 -08001468 != PackageManager.PERMISSION_GRANTED) {
Robert Greenwalt0659da32009-07-16 17:21:39 -07001469 pw.println("Permission Denial: can't dump ConnectivityService " +
1470 "from from pid=" + Binder.getCallingPid() + ", uid=" +
1471 Binder.getCallingUid());
The Android Open Source Project28527d22009-03-03 19:31:44 -08001472 return;
1473 }
The Android Open Source Project28527d22009-03-03 19:31:44 -08001474 pw.println();
1475 for (NetworkStateTracker nst : mNetTrackers) {
Robert Greenwalt3eeb6032009-12-21 18:24:07 -08001476 if (nst != null) {
1477 if (nst.getNetworkInfo().isConnected()) {
1478 pw.println("Active network: " + nst.getNetworkInfo().
1479 getTypeName());
1480 }
1481 pw.println(nst.getNetworkInfo());
1482 pw.println(nst);
1483 pw.println();
Robert Greenwalt2034b912009-08-12 16:08:25 -07001484 }
The Android Open Source Project28527d22009-03-03 19:31:44 -08001485 }
Robert Greenwalt3eeb6032009-12-21 18:24:07 -08001486
1487 pw.println("Network Requester Pids:");
1488 for (int net : mPriorityList) {
1489 String pidString = net + ": ";
1490 for (Object pid : mNetRequestersPids[net]) {
1491 pidString = pidString + pid.toString() + ", ";
1492 }
1493 pw.println(pidString);
1494 }
1495 pw.println();
1496
1497 pw.println("FeatureUsers:");
1498 for (Object requester : mFeatureUsers) {
1499 pw.println(requester.toString());
1500 }
1501 pw.println();
Robert Greenwalt8e87f122010-02-11 18:18:40 -08001502
1503 mTethering.dump(fd, pw, args);
Robert Greenwalt0e80be12010-09-20 14:35:25 -07001504
1505 if (mInetLog != null) {
1506 pw.println();
1507 pw.println("Inet condition reports:");
1508 for(int i = 0; i < mInetLog.size(); i++) {
1509 pw.println(mInetLog.get(i));
1510 }
1511 }
The Android Open Source Project28527d22009-03-03 19:31:44 -08001512 }
1513
Robert Greenwalt2034b912009-08-12 16:08:25 -07001514 // must be stateless - things change under us.
The Android Open Source Project28527d22009-03-03 19:31:44 -08001515 private class MyHandler extends Handler {
1516 @Override
1517 public void handleMessage(Message msg) {
1518 NetworkInfo info;
1519 switch (msg.what) {
1520 case NetworkStateTracker.EVENT_STATE_CHANGED:
1521 info = (NetworkInfo) msg.obj;
Robert Greenwalt12c44552009-12-07 11:33:18 -08001522 int type = info.getType();
1523 NetworkInfo.State state = info.getState();
Robert Greenwalt24e2d2b2010-01-25 16:14:00 -08001524 // only do this optimization for wifi. It going into scan mode for location
1525 // services generates alot of noise. Meanwhile the mms apn won't send out
1526 // subsequent notifications when on default cellular because it never
1527 // disconnects.. so only do this to wifi notifications. Fixed better when the
1528 // APN notifications are standardized.
1529 if (mNetAttributes[type].mLastState == state &&
1530 mNetAttributes[type].mRadio == ConnectivityManager.TYPE_WIFI) {
Robert Greenwalt12c44552009-12-07 11:33:18 -08001531 if (DBG) {
Robert Greenwalt24e2d2b2010-01-25 16:14:00 -08001532 // TODO - remove this after we validate the dropping doesn't break
1533 // anything
Joe Onoratoc2386bb2010-02-26 18:56:32 -08001534 Slog.d(TAG, "Dropping ConnectivityChange for " +
Robert Greenwalt2adbc7f2010-01-13 09:36:31 -08001535 info.getTypeName() + ": " +
Robert Greenwalt12c44552009-12-07 11:33:18 -08001536 state + "/" + info.getDetailedState());
1537 }
1538 return;
1539 }
1540 mNetAttributes[type].mLastState = state;
1541
Joe Onoratoc2386bb2010-02-26 18:56:32 -08001542 if (DBG) Slog.d(TAG, "ConnectivityChange for " +
Robert Greenwalt0659da32009-07-16 17:21:39 -07001543 info.getTypeName() + ": " +
Robert Greenwalt12c44552009-12-07 11:33:18 -08001544 state + "/" + info.getDetailedState());
The Android Open Source Project28527d22009-03-03 19:31:44 -08001545
1546 // Connectivity state changed:
1547 // [31-13] Reserved for future use
Robert Greenwalt0659da32009-07-16 17:21:39 -07001548 // [12-9] Network subtype (for mobile network, as defined
1549 // by TelephonyManager)
1550 // [8-3] Detailed state ordinal (as defined by
1551 // NetworkInfo.DetailedState)
The Android Open Source Project28527d22009-03-03 19:31:44 -08001552 // [2-0] Network type (as defined by ConnectivityManager)
1553 int eventLogParam = (info.getType() & 0x7) |
1554 ((info.getDetailedState().ordinal() & 0x3f) << 3) |
1555 (info.getSubtype() << 9);
Doug Zongker2fc96232009-12-04 10:31:43 -08001556 EventLog.writeEvent(EventLogTags.CONNECTIVITY_STATE_CHANGED,
Robert Greenwalt0659da32009-07-16 17:21:39 -07001557 eventLogParam);
1558
1559 if (info.getDetailedState() ==
1560 NetworkInfo.DetailedState.FAILED) {
The Android Open Source Project28527d22009-03-03 19:31:44 -08001561 handleConnectionFailure(info);
Robert Greenwalt12c44552009-12-07 11:33:18 -08001562 } else if (state == NetworkInfo.State.DISCONNECTED) {
The Android Open Source Project28527d22009-03-03 19:31:44 -08001563 handleDisconnect(info);
Robert Greenwalt12c44552009-12-07 11:33:18 -08001564 } else if (state == NetworkInfo.State.SUSPENDED) {
The Android Open Source Project28527d22009-03-03 19:31:44 -08001565 // TODO: need to think this over.
Robert Greenwalt0659da32009-07-16 17:21:39 -07001566 // the logic here is, handle SUSPENDED the same as
1567 // DISCONNECTED. The only difference being we are
1568 // broadcasting an intent with NetworkInfo that's
1569 // suspended. This allows the applications an
1570 // opportunity to handle DISCONNECTED and SUSPENDED
1571 // differently, or not.
The Android Open Source Project28527d22009-03-03 19:31:44 -08001572 handleDisconnect(info);
Robert Greenwalt12c44552009-12-07 11:33:18 -08001573 } else if (state == NetworkInfo.State.CONNECTED) {
The Android Open Source Project28527d22009-03-03 19:31:44 -08001574 handleConnect(info);
1575 }
The Android Open Source Project28527d22009-03-03 19:31:44 -08001576 break;
1577
1578 case NetworkStateTracker.EVENT_SCAN_RESULTS_AVAILABLE:
1579 info = (NetworkInfo) msg.obj;
1580 handleScanResultsAvailable(info);
1581 break;
Robert Greenwalt0659da32009-07-16 17:21:39 -07001582
The Android Open Source Project28527d22009-03-03 19:31:44 -08001583 case NetworkStateTracker.EVENT_NOTIFICATION_CHANGED:
Robert Greenwalt0659da32009-07-16 17:21:39 -07001584 handleNotificationChange(msg.arg1 == 1, msg.arg2,
1585 (Notification) msg.obj);
Robert Greenwalt0ef68752010-08-13 14:16:12 -07001586 break;
The Android Open Source Project28527d22009-03-03 19:31:44 -08001587
1588 case NetworkStateTracker.EVENT_CONFIGURATION_CHANGED:
Robert Greenwalt0ef68752010-08-13 14:16:12 -07001589 info = (NetworkInfo) msg.obj;
1590 type = info.getType();
1591 handleDnsConfigurationChange(type);
The Android Open Source Project28527d22009-03-03 19:31:44 -08001592 break;
1593
1594 case NetworkStateTracker.EVENT_ROAMING_CHANGED:
1595 // fill me in
1596 break;
1597
1598 case NetworkStateTracker.EVENT_NETWORK_SUBTYPE_CHANGED:
1599 // fill me in
1600 break;
Robert Greenwalt6a2db8a2010-09-23 10:05:56 -07001601 case EVENT_RESTORE_DEFAULT_NETWORK:
Robert Greenwaltaffc3a12009-09-27 17:27:04 -07001602 FeatureUser u = (FeatureUser)msg.obj;
1603 u.expire();
Robert Greenwalt2034b912009-08-12 16:08:25 -07001604 break;
Robert Greenwalt6a2db8a2010-09-23 10:05:56 -07001605 case EVENT_INET_CONDITION_CHANGE:
1606 {
1607 int netType = msg.arg1;
1608 int condition = msg.arg2;
1609 handleInetConditionChange(netType, condition);
Robert Greenwalt986c7412010-09-08 15:24:47 -07001610 break;
Robert Greenwalt6a2db8a2010-09-23 10:05:56 -07001611 }
1612 case EVENT_INET_CONDITION_HOLD_END:
1613 {
1614 int netType = msg.arg1;
1615 int sequence = msg.arg2;
1616 handleInetConditionHoldEnd(netType, sequence);
Robert Greenwalt986c7412010-09-08 15:24:47 -07001617 break;
Robert Greenwalt6a2db8a2010-09-23 10:05:56 -07001618 }
1619 case EVENT_SET_NETWORK_PREFERENCE:
1620 {
1621 int preference = msg.arg1;
1622 handleSetNetworkPreference(preference);
1623 break;
1624 }
1625 case EVENT_SET_BACKGROUND_DATA:
1626 {
1627 boolean enabled = (msg.arg1 == ENABLED);
1628 handleSetBackgroundData(enabled);
1629 break;
1630 }
1631 case EVENT_SET_MOBILE_DATA:
1632 {
1633 boolean enabled = (msg.arg1 == ENABLED);
1634 handleSetMobileData(enabled);
1635 break;
1636 }
The Android Open Source Project28527d22009-03-03 19:31:44 -08001637 }
1638 }
1639 }
Robert Greenwalt0c4828c2010-01-26 11:40:34 -08001640
1641 // javadoc from interface
Robert Greenwalt4283ded2010-03-02 17:25:02 -08001642 public int tether(String iface) {
Robert Greenwalt0c4828c2010-01-26 11:40:34 -08001643 enforceTetherChangePermission();
Robert Greenwalt4283ded2010-03-02 17:25:02 -08001644
1645 if (isTetheringSupported()) {
1646 return mTethering.tether(iface);
1647 } else {
1648 return ConnectivityManager.TETHER_ERROR_UNSUPPORTED;
1649 }
Robert Greenwalt0c4828c2010-01-26 11:40:34 -08001650 }
1651
1652 // javadoc from interface
Robert Greenwalt4283ded2010-03-02 17:25:02 -08001653 public int untether(String iface) {
Robert Greenwalt0c4828c2010-01-26 11:40:34 -08001654 enforceTetherChangePermission();
Robert Greenwalt4283ded2010-03-02 17:25:02 -08001655
1656 if (isTetheringSupported()) {
1657 return mTethering.untether(iface);
1658 } else {
1659 return ConnectivityManager.TETHER_ERROR_UNSUPPORTED;
1660 }
1661 }
1662
1663 // javadoc from interface
1664 public int getLastTetherError(String iface) {
1665 enforceTetherAccessPermission();
1666
1667 if (isTetheringSupported()) {
1668 return mTethering.getLastTetherError(iface);
1669 } else {
1670 return ConnectivityManager.TETHER_ERROR_UNSUPPORTED;
1671 }
Robert Greenwalt8e87f122010-02-11 18:18:40 -08001672 }
1673
1674 // TODO - proper iface API for selection by property, inspection, etc
1675 public String[] getTetherableUsbRegexs() {
1676 enforceTetherAccessPermission();
1677 if (isTetheringSupported()) {
1678 return mTethering.getTetherableUsbRegexs();
1679 } else {
1680 return new String[0];
1681 }
1682 }
1683
1684 public String[] getTetherableWifiRegexs() {
1685 enforceTetherAccessPermission();
1686 if (isTetheringSupported()) {
1687 return mTethering.getTetherableWifiRegexs();
1688 } else {
1689 return new String[0];
1690 }
Robert Greenwalt0c4828c2010-01-26 11:40:34 -08001691 }
1692
1693 // TODO - move iface listing, queries, etc to new module
1694 // javadoc from interface
1695 public String[] getTetherableIfaces() {
Robert Greenwalt8e87f122010-02-11 18:18:40 -08001696 enforceTetherAccessPermission();
Robert Greenwalt0c4828c2010-01-26 11:40:34 -08001697 return mTethering.getTetherableIfaces();
1698 }
1699
1700 public String[] getTetheredIfaces() {
Robert Greenwalt8e87f122010-02-11 18:18:40 -08001701 enforceTetherAccessPermission();
Robert Greenwalt0c4828c2010-01-26 11:40:34 -08001702 return mTethering.getTetheredIfaces();
1703 }
Robert Greenwalt8e87f122010-02-11 18:18:40 -08001704
Robert Greenwalt4283ded2010-03-02 17:25:02 -08001705 public String[] getTetheringErroredIfaces() {
1706 enforceTetherAccessPermission();
1707 return mTethering.getErroredIfaces();
1708 }
1709
Robert Greenwalt8e87f122010-02-11 18:18:40 -08001710 // if ro.tether.denied = true we default to no tethering
1711 // gservices could set the secure setting to 1 though to enable it on a build where it
1712 // had previously been turned off.
1713 public boolean isTetheringSupported() {
1714 enforceTetherAccessPermission();
1715 int defaultVal = (SystemProperties.get("ro.tether.denied").equals("true") ? 0 : 1);
Robert Greenwaltf1b66e12010-02-25 12:29:30 -08001716 boolean tetherEnabledInSettings = (Settings.Secure.getInt(mContext.getContentResolver(),
1717 Settings.Secure.TETHER_SUPPORTED, defaultVal) != 0);
1718 return tetherEnabledInSettings && mTetheringConfigValid;
Robert Greenwalt8e87f122010-02-11 18:18:40 -08001719 }
Robert Greenwalt986c7412010-09-08 15:24:47 -07001720
1721 // 100 percent is full good, 0 is full bad.
1722 public void reportInetCondition(int networkType, int percentage) {
1723 if (DBG) Slog.d(TAG, "reportNetworkCondition(" + networkType + ", " + percentage + ")");
1724 mContext.enforceCallingOrSelfPermission(
1725 android.Manifest.permission.STATUS_BAR,
1726 "ConnectivityService");
1727
Robert Greenwalt0e80be12010-09-20 14:35:25 -07001728 if (DBG) {
1729 int pid = getCallingPid();
1730 int uid = getCallingUid();
1731 String s = pid + "(" + uid + ") reports inet is " +
1732 (percentage > 50 ? "connected" : "disconnected") + " (" + percentage + ") on " +
1733 "network Type " + networkType + " at " + GregorianCalendar.getInstance().getTime();
1734 mInetLog.add(s);
1735 while(mInetLog.size() > INET_CONDITION_LOG_MAX_SIZE) {
1736 mInetLog.remove(0);
1737 }
1738 }
Robert Greenwalt986c7412010-09-08 15:24:47 -07001739 mHandler.sendMessage(mHandler.obtainMessage(
Robert Greenwalt6a2db8a2010-09-23 10:05:56 -07001740 EVENT_INET_CONDITION_CHANGE, networkType, percentage));
1741 }
1742
1743 private void handleInetConditionChange(int netType, int condition) {
1744 if (DBG) {
1745 Slog.d(TAG, "Inet connectivity change, net=" +
1746 netType + ", condition=" + condition +
1747 ",mActiveDefaultNetwork=" + mActiveDefaultNetwork);
1748 }
1749 if (mActiveDefaultNetwork == -1) {
1750 if (DBG) Slog.d(TAG, "no active default network - aborting");
1751 return;
1752 }
1753 if (mActiveDefaultNetwork != netType) {
1754 if (DBG) Slog.d(TAG, "given net not default - aborting");
1755 return;
1756 }
1757 mDefaultInetCondition = condition;
1758 int delay;
1759 if (mInetConditionChangeInFlight == false) {
1760 if (DBG) Slog.d(TAG, "starting a change hold");
1761 // setup a new hold to debounce this
1762 if (mDefaultInetCondition > 50) {
1763 delay = Settings.Secure.getInt(mContext.getContentResolver(),
1764 Settings.Secure.INET_CONDITION_DEBOUNCE_UP_DELAY, 500);
1765 } else {
1766 delay = Settings.Secure.getInt(mContext.getContentResolver(),
1767 Settings.Secure.INET_CONDITION_DEBOUNCE_DOWN_DELAY, 3000);
1768 }
1769 mInetConditionChangeInFlight = true;
1770 mHandler.sendMessageDelayed(mHandler.obtainMessage(EVENT_INET_CONDITION_HOLD_END,
1771 mActiveDefaultNetwork, mDefaultConnectionSequence), delay);
1772 } else {
1773 // we've set the new condition, when this hold ends that will get
1774 // picked up
1775 if (DBG) Slog.d(TAG, "currently in hold - not setting new end evt");
1776 }
1777 }
1778
1779 private void handleInetConditionHoldEnd(int netType, int sequence) {
1780 if (DBG) {
1781 Slog.d(TAG, "Inet hold end, net=" + netType +
1782 ", condition =" + mDefaultInetCondition +
1783 ", published condition =" + mDefaultInetConditionPublished);
1784 }
1785 mInetConditionChangeInFlight = false;
1786
1787 if (mActiveDefaultNetwork == -1) {
1788 if (DBG) Slog.d(TAG, "no active default network - aborting");
1789 return;
1790 }
1791 if (mDefaultConnectionSequence != sequence) {
1792 if (DBG) Slog.d(TAG, "event hold for obsolete network - aborting");
1793 return;
1794 }
1795 if (mDefaultInetConditionPublished == mDefaultInetCondition) {
1796 if (DBG) Slog.d(TAG, "no change in condition - aborting");
1797 return;
1798 }
1799 NetworkInfo networkInfo = mNetTrackers[mActiveDefaultNetwork].getNetworkInfo();
1800 if (networkInfo.isConnected() == false) {
1801 if (DBG) Slog.d(TAG, "default network not connected - aborting");
1802 return;
1803 }
1804 mDefaultInetConditionPublished = mDefaultInetCondition;
1805 sendInetConditionBroadcast(networkInfo);
1806 return;
Robert Greenwalt986c7412010-09-08 15:24:47 -07001807 }
The Android Open Source Project28527d22009-03-03 19:31:44 -08001808}