blob: 65e36509a9c51759982dabb70df29e4588ae8d18 [file] [log] [blame]
The Android Open Source Project54a942f2008-10-21 07:00:00 -07001/*
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;
33import android.os.Looper;
34import android.os.Message;
35import android.os.ServiceManager;
36import android.os.SystemProperties;
37import android.provider.Settings;
The Android Open Source Project54a942f2008-10-21 07:00:00 -070038import android.util.EventLog;
39import android.util.Log;
40
41import java.io.FileDescriptor;
42import java.io.PrintWriter;
43
44/**
The Android Open Source Project0caef3f2008-12-17 18:05:43 -080045 * @hide
The Android Open Source Project54a942f2008-10-21 07:00:00 -070046 */
47public class ConnectivityService extends IConnectivityManager.Stub {
48
49 private static final boolean DBG = false;
50 private static final String TAG = "ConnectivityService";
51
52 // Event log tags (must be in sync with event-log-tags)
53 private static final int EVENTLOG_CONNECTIVITY_STATE_CHANGED = 50020;
54
55 /**
56 * Sometimes we want to refer to the individual network state
57 * trackers separately, and sometimes we just want to treat them
58 * abstractly.
59 */
60 private NetworkStateTracker mNetTrackers[];
The Android Open Source Project54a942f2008-10-21 07:00:00 -070061 private WifiStateTracker mWifiStateTracker;
62 private MobileDataStateTracker mMobileDataStateTracker;
63 private WifiWatchdogService mWifiWatchdogService;
64
65 private Context mContext;
66 private int mNetworkPreference;
67 private NetworkStateTracker mActiveNetwork;
68
69 private int mNumDnsEntries;
The Android Open Source Project0caef3f2008-12-17 18:05:43 -080070 private static int sDnsChangeCounter;
The Android Open Source Project54a942f2008-10-21 07:00:00 -070071
72 private boolean mTestMode;
73 private static ConnectivityService sServiceInstance;
The Android Open Source Project0caef3f2008-12-17 18:05:43 -080074
The Android Open Source Project54a942f2008-10-21 07:00:00 -070075 private static class ConnectivityThread extends Thread {
76 private Context mContext;
77
78 private ConnectivityThread(Context context) {
79 super("ConnectivityThread");
80 mContext = context;
81 }
82
83 @Override
84 public void run() {
85 Looper.prepare();
86 synchronized (this) {
87 sServiceInstance = new ConnectivityService(mContext);
88 notifyAll();
89 }
90 Looper.loop();
91 }
92
93 public static ConnectivityService getServiceInstance(Context context) {
94 ConnectivityThread thread = new ConnectivityThread(context);
95 thread.start();
96
97 synchronized (thread) {
98 while (sServiceInstance == null) {
99 try {
100 // Wait until sServiceInstance has been initialized.
101 thread.wait();
The Android Open Source Project0caef3f2008-12-17 18:05:43 -0800102 } catch (InterruptedException ignore) {
103 Log.e(TAG,
104 "Unexpected InterruptedException while waiting for ConnectivityService thread");
The Android Open Source Project54a942f2008-10-21 07:00:00 -0700105 }
106 }
107 }
108
109 return sServiceInstance;
110 }
111 }
112
113 public static ConnectivityService getInstance(Context context) {
114 return ConnectivityThread.getServiceInstance(context);
115 }
116
117 private ConnectivityService(Context context) {
118 if (DBG) Log.v(TAG, "ConnectivityService starting up");
119 mContext = context;
120 mNetTrackers = new NetworkStateTracker[2];
The Android Open Source Project54a942f2008-10-21 07:00:00 -0700121 Handler handler = new MyHandler();
122
123 mNetworkPreference = getPersistedNetworkPreference();
124
125 /*
126 * Create the network state trackers for Wi-Fi and mobile
127 * data. Maybe this could be done with a factory class,
128 * but it's not clear that it's worth it, given that
129 * the number of different network types is not going
130 * to change very often.
131 */
132 if (DBG) Log.v(TAG, "Starting Wifi Service.");
133 mWifiStateTracker = new WifiStateTracker(context, handler);
134 WifiService wifiService = new WifiService(context, mWifiStateTracker);
135 ServiceManager.addService(Context.WIFI_SERVICE, wifiService);
The Android Open Source Project54a942f2008-10-21 07:00:00 -0700136 mNetTrackers[ConnectivityManager.TYPE_WIFI] = mWifiStateTracker;
137
138 mMobileDataStateTracker = new MobileDataStateTracker(context, handler);
139 mNetTrackers[ConnectivityManager.TYPE_MOBILE] = mMobileDataStateTracker;
140
141 mActiveNetwork = null;
142 mNumDnsEntries = 0;
143
144 mTestMode = SystemProperties.get("cm.test.mode").equals("true")
145 && SystemProperties.get("ro.build.type").equals("eng");
146
147 for (NetworkStateTracker t : mNetTrackers)
148 t.startMonitoring();
149
150 // Constructing this starts it too
151 mWifiWatchdogService = new WifiWatchdogService(context, mWifiStateTracker);
152 }
153
154 /**
155 * Sets the preferred network.
156 * @param preference the new preference
157 */
158 public synchronized void setNetworkPreference(int preference) {
159 enforceChangePermission();
160 if (ConnectivityManager.isNetworkTypeValid(preference)) {
The Android Open Source Project0caef3f2008-12-17 18:05:43 -0800161 if (mNetworkPreference != preference) {
162 persistNetworkPreference(preference);
163 mNetworkPreference = preference;
The Android Open Source Project54a942f2008-10-21 07:00:00 -0700164 enforcePreference();
The Android Open Source Project0caef3f2008-12-17 18:05:43 -0800165 }
The Android Open Source Project54a942f2008-10-21 07:00:00 -0700166 }
167 }
168
169 public int getNetworkPreference() {
170 enforceAccessPermission();
171 return mNetworkPreference;
172 }
173
174 private void persistNetworkPreference(int networkPreference) {
175 final ContentResolver cr = mContext.getContentResolver();
The Android Open Source Project0caef3f2008-12-17 18:05:43 -0800176 Settings.Secure.putInt(cr, Settings.Secure.NETWORK_PREFERENCE, networkPreference);
The Android Open Source Project54a942f2008-10-21 07:00:00 -0700177 }
178
179 private int getPersistedNetworkPreference() {
180 final ContentResolver cr = mContext.getContentResolver();
181
The Android Open Source Project0caef3f2008-12-17 18:05:43 -0800182 final int networkPrefSetting = Settings.Secure
183 .getInt(cr, Settings.Secure.NETWORK_PREFERENCE, -1);
The Android Open Source Project54a942f2008-10-21 07:00:00 -0700184 if (networkPrefSetting != -1) {
185 return networkPrefSetting;
186 }
187
188 return ConnectivityManager.DEFAULT_NETWORK_PREFERENCE;
189 }
190
191 /**
192 * Make the state of network connectivity conform to the preference settings.
193 * In this method, we only tear down a non-preferred network. Establishing
194 * a connection to the preferred network is taken care of when we handle
195 * the disconnect event from the non-preferred network
196 * (see {@link #handleDisconnect(NetworkInfo)}).
197 */
198 private void enforcePreference() {
199 if (mActiveNetwork == null)
200 return;
201
202 for (NetworkStateTracker t : mNetTrackers) {
203 if (t == mActiveNetwork) {
204 int netType = t.getNetworkInfo().getType();
205 int otherNetType = ((netType == ConnectivityManager.TYPE_WIFI) ?
206 ConnectivityManager.TYPE_MOBILE :
207 ConnectivityManager.TYPE_WIFI);
208
209 if (t.getNetworkInfo().getType() != mNetworkPreference) {
210 NetworkStateTracker otherTracker = mNetTrackers[otherNetType];
211 if (otherTracker.isAvailable()) {
212 teardown(t);
213 }
214 }
215 }
216 }
217 }
218
219 private boolean teardown(NetworkStateTracker netTracker) {
220 if (netTracker.teardown()) {
The Android Open Source Project0caef3f2008-12-17 18:05:43 -0800221 netTracker.setTeardownRequested(true);
The Android Open Source Project54a942f2008-10-21 07:00:00 -0700222 return true;
223 } else {
224 return false;
225 }
226 }
227
228 /**
The Android Open Source Project0caef3f2008-12-17 18:05:43 -0800229 * Return NetworkInfo for the active (i.e., connected) network interface.
230 * It is assumed that at most one network is active at a time. If more
231 * than one is active, it is indeterminate which will be returned.
The Android Open Source Project54a942f2008-10-21 07:00:00 -0700232 * @return the info for the active network, or {@code null} if none is active
233 */
234 public NetworkInfo getActiveNetworkInfo() {
235 enforceAccessPermission();
236 for (NetworkStateTracker t : mNetTrackers) {
237 NetworkInfo info = t.getNetworkInfo();
238 if (info.isConnected()) {
239 return info;
240 }
241 }
242 return null;
243 }
244
245 public NetworkInfo getNetworkInfo(int networkType) {
246 enforceAccessPermission();
247 if (ConnectivityManager.isNetworkTypeValid(networkType)) {
248 NetworkStateTracker t = mNetTrackers[networkType];
249 if (t != null)
250 return t.getNetworkInfo();
251 }
252 return null;
253 }
254
255 public NetworkInfo[] getAllNetworkInfo() {
256 enforceAccessPermission();
257 NetworkInfo[] result = new NetworkInfo[mNetTrackers.length];
258 int i = 0;
259 for (NetworkStateTracker t : mNetTrackers) {
260 result[i++] = t.getNetworkInfo();
261 }
262 return result;
263 }
264
265 public boolean setRadios(boolean turnOn) {
266 boolean result = true;
267 enforceChangePermission();
268 for (NetworkStateTracker t : mNetTrackers) {
269 result = t.setRadio(turnOn) && result;
270 }
271 return result;
272 }
273
274 public boolean setRadio(int netType, boolean turnOn) {
275 enforceChangePermission();
276 if (!ConnectivityManager.isNetworkTypeValid(netType)) {
277 return false;
278 }
279 NetworkStateTracker tracker = mNetTrackers[netType];
280 return tracker != null && tracker.setRadio(turnOn);
281 }
282
283 public int startUsingNetworkFeature(int networkType, String feature) {
284 enforceChangePermission();
285 if (!ConnectivityManager.isNetworkTypeValid(networkType)) {
286 return -1;
287 }
288 NetworkStateTracker tracker = mNetTrackers[networkType];
289 if (tracker != null) {
290 return tracker.startUsingNetworkFeature(feature, getCallingPid(), getCallingUid());
291 }
292 return -1;
The Android Open Source Project54a942f2008-10-21 07:00:00 -0700293 }
294
295 public int stopUsingNetworkFeature(int networkType, String feature) {
296 enforceChangePermission();
297 if (!ConnectivityManager.isNetworkTypeValid(networkType)) {
298 return -1;
299 }
300 NetworkStateTracker tracker = mNetTrackers[networkType];
301 if (tracker != null) {
302 return tracker.stopUsingNetworkFeature(feature, getCallingPid(), getCallingUid());
303 }
304 return -1;
305 }
306
307 /**
308 * Ensure that a network route exists to deliver traffic to the specified
309 * host via the specified network interface.
310 * @param networkType the type of the network over which traffic to the specified
311 * host is to be routed
312 * @param hostAddress the IP address of the host to which the route is desired
313 * @return {@code true} on success, {@code false} on failure
314 */
315 public boolean requestRouteToHost(int networkType, int hostAddress) {
316 enforceChangePermission();
317 if (!ConnectivityManager.isNetworkTypeValid(networkType)) {
318 return false;
319 }
320 NetworkStateTracker tracker = mNetTrackers[networkType];
321 /*
322 * If there's only one connected network, and it's the one requested,
323 * then we don't have to do anything - the requested route already
324 * exists. If it's not the requested network, then it's not possible
325 * to establish the requested route. Finally, if there is more than
326 * one connected network, then we must insert an entry in the routing
327 * table.
328 */
329 if (getNumConnectedNetworks() > 1) {
330 return tracker.requestRouteToHost(hostAddress);
331 } else {
332 return tracker.getNetworkInfo().getType() == networkType;
333 }
334 }
335
336 private int getNumConnectedNetworks() {
337 int numConnectedNets = 0;
338
339 for (NetworkStateTracker nt : mNetTrackers) {
The Android Open Source Project0caef3f2008-12-17 18:05:43 -0800340 if (nt.getNetworkInfo().isConnected() && !nt.isTeardownRequested()) {
The Android Open Source Project54a942f2008-10-21 07:00:00 -0700341 ++numConnectedNets;
342 }
343 }
344 return numConnectedNets;
345 }
346
347 private void enforceAccessPermission() {
348 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.ACCESS_NETWORK_STATE,
349 "ConnectivityService");
350 }
351
352 private void enforceChangePermission() {
353 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.CHANGE_NETWORK_STATE,
354 "ConnectivityService");
355
356 }
357
358 /**
359 * Handle a {@code DISCONNECTED} event. If this pertains to the non-active network,
360 * we ignore it. If it is for the active network, we send out a broadcast.
361 * But first, we check whether it might be possible to connect to a different
362 * network.
363 * @param info the {@code NetworkInfo} for the network
364 */
365 private void handleDisconnect(NetworkInfo info) {
366
367 if (DBG) Log.v(TAG, "Handle DISCONNECT for " + info.getTypeName());
368
The Android Open Source Project0caef3f2008-12-17 18:05:43 -0800369 mNetTrackers[info.getType()].setTeardownRequested(false);
The Android Open Source Project54a942f2008-10-21 07:00:00 -0700370 /*
371 * If the disconnected network is not the active one, then don't report
372 * this as a loss of connectivity. What probably happened is that we're
373 * getting the disconnect for a network that we explicitly disabled
374 * in accordance with network preference policies.
375 */
The Android Open Source Project54a942f2008-10-21 07:00:00 -0700376 if (mActiveNetwork == null || info.getType() != mActiveNetwork.getNetworkInfo().getType())
377 return;
378
379 NetworkStateTracker newNet;
380 if (info.getType() == ConnectivityManager.TYPE_MOBILE) {
381 newNet = mWifiStateTracker;
382 } else /* info().getType() == TYPE_WIFI */ {
383 newNet = mMobileDataStateTracker;
384 }
385
The Android Open Source Project0caef3f2008-12-17 18:05:43 -0800386 /**
387 * See if the other network is available to fail over to.
388 * If is not available, we enable it anyway, so that it
389 * will be able to connect when it does become available,
390 * but we report a total loss of connectivity rather than
391 * report that we are attempting to fail over.
392 */
The Android Open Source Project54a942f2008-10-21 07:00:00 -0700393 NetworkInfo switchTo = null;
394 if (newNet.isAvailable()) {
395 mActiveNetwork = newNet;
396 switchTo = newNet.getNetworkInfo();
397 switchTo.setFailover(true);
The Android Open Source Project0caef3f2008-12-17 18:05:43 -0800398 if (!switchTo.isConnectedOrConnecting()) {
The Android Open Source Project54a942f2008-10-21 07:00:00 -0700399 newNet.reconnect();
The Android Open Source Project0caef3f2008-12-17 18:05:43 -0800400 }
401 } else {
402 newNet.reconnect();
The Android Open Source Project54a942f2008-10-21 07:00:00 -0700403 }
404
405 boolean otherNetworkConnected = false;
406 Intent intent = new Intent(ConnectivityManager.CONNECTIVITY_ACTION);
407 intent.putExtra(ConnectivityManager.EXTRA_NETWORK_INFO, info);
408 if (info.isFailover()) {
409 intent.putExtra(ConnectivityManager.EXTRA_IS_FAILOVER, true);
410 info.setFailover(false);
411 }
412 if (info.getReason() != null) {
413 intent.putExtra(ConnectivityManager.EXTRA_REASON, info.getReason());
414 }
415 if (info.getExtraInfo() != null) {
416 intent.putExtra(ConnectivityManager.EXTRA_EXTRA_INFO, info.getExtraInfo());
417 }
418 if (switchTo != null) {
419 otherNetworkConnected = switchTo.isConnected();
420 if (DBG) {
421 if (otherNetworkConnected) {
422 Log.v(TAG, "Switching to already connected " + switchTo.getTypeName());
423 } else {
424 Log.v(TAG, "Attempting to switch to " + switchTo.getTypeName());
425 }
426 }
427 intent.putExtra(ConnectivityManager.EXTRA_OTHER_NETWORK_INFO, switchTo);
428 } else {
429 intent.putExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, true);
430 }
431 if (DBG) Log.v(TAG, "Sending DISCONNECT bcast for " + info.getTypeName() +
432 (switchTo == null ? "" : " other=" + switchTo.getTypeName()));
433
434 mContext.sendStickyBroadcast(intent);
435 /*
436 * If the failover network is already connected, then immediately send out
437 * a followup broadcast indicating successful failover
438 */
439 if (switchTo != null && otherNetworkConnected)
440 sendConnectedBroadcast(switchTo);
441 }
442
443 private void sendConnectedBroadcast(NetworkInfo info) {
444 Intent intent = new Intent(ConnectivityManager.CONNECTIVITY_ACTION);
445 intent.putExtra(ConnectivityManager.EXTRA_NETWORK_INFO, info);
446 if (info.isFailover()) {
447 intent.putExtra(ConnectivityManager.EXTRA_IS_FAILOVER, true);
448 info.setFailover(false);
449 }
450 if (info.getReason() != null) {
451 intent.putExtra(ConnectivityManager.EXTRA_REASON, info.getReason());
452 }
453 if (info.getExtraInfo() != null) {
454 intent.putExtra(ConnectivityManager.EXTRA_EXTRA_INFO, info.getExtraInfo());
455 }
456 mContext.sendStickyBroadcast(intent);
457 }
458
The Android Open Source Project0caef3f2008-12-17 18:05:43 -0800459 /**
460 * Called when an attempt to fail over to another network has failed.
461 * @param info the {@link NetworkInfo} for the failed network
462 */
The Android Open Source Project54a942f2008-10-21 07:00:00 -0700463 private void handleConnectionFailure(NetworkInfo info) {
The Android Open Source Project0caef3f2008-12-17 18:05:43 -0800464 mNetTrackers[info.getType()].setTeardownRequested(false);
The Android Open Source Project54a942f2008-10-21 07:00:00 -0700465 if (getActiveNetworkInfo() == null) {
466 String reason = info.getReason();
467 String extraInfo = info.getExtraInfo();
468
469 if (DBG) {
470 String reasonText;
471 if (reason == null) {
472 reasonText = ".";
473 } else {
474 reasonText = " (" + reason + ").";
475 }
476 Log.v(TAG, "Attempt to connect to " + info.getTypeName() + " failed" + reasonText);
477 }
478
479 Intent intent = new Intent(ConnectivityManager.CONNECTIVITY_ACTION);
480 intent.putExtra(ConnectivityManager.EXTRA_NETWORK_INFO, info);
481 intent.putExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, true);
482 if (reason != null) {
483 intent.putExtra(ConnectivityManager.EXTRA_REASON, reason);
484 }
485 if (extraInfo != null) {
486 intent.putExtra(ConnectivityManager.EXTRA_EXTRA_INFO, extraInfo);
487 }
488 if (info.isFailover()) {
489 intent.putExtra(ConnectivityManager.EXTRA_IS_FAILOVER, true);
490 info.setFailover(false);
491 }
492 mContext.sendStickyBroadcast(intent);
493 }
494 }
495
496 private void handleConnect(NetworkInfo info) {
497 if (DBG) Log.v(TAG, "Handle CONNECT for " + info.getTypeName());
498
499 // snapshot isFailover, because sendConnectedBroadcast() resets it
500 boolean isFailover = info.isFailover();
501 NetworkStateTracker thisNet = mNetTrackers[info.getType()];
502 NetworkStateTracker deadnet = null;
503 NetworkStateTracker otherNet;
504 if (info.getType() == ConnectivityManager.TYPE_MOBILE) {
505 otherNet = mWifiStateTracker;
506 } else /* info().getType() == TYPE_WIFI */ {
507 otherNet = mMobileDataStateTracker;
508 }
509 /*
The Android Open Source Project0caef3f2008-12-17 18:05:43 -0800510 * Check policy to see whether we are connected to a non-preferred
511 * network that now needs to be torn down.
512 */
The Android Open Source Project54a942f2008-10-21 07:00:00 -0700513 NetworkInfo wifiInfo = mWifiStateTracker.getNetworkInfo();
514 NetworkInfo mobileInfo = mMobileDataStateTracker.getNetworkInfo();
515 if (wifiInfo.isConnected() && mobileInfo.isConnected()) {
516 if (mNetworkPreference == ConnectivityManager.TYPE_WIFI)
517 deadnet = mMobileDataStateTracker;
518 else
519 deadnet = mWifiStateTracker;
520 }
521
522 boolean toredown = false;
The Android Open Source Project0caef3f2008-12-17 18:05:43 -0800523 thisNet.setTeardownRequested(false);
The Android Open Source Project54a942f2008-10-21 07:00:00 -0700524 if (!mTestMode && deadnet != null) {
525 if (DBG) Log.v(TAG, "Policy requires " +
526 deadnet.getNetworkInfo().getTypeName() + " teardown");
527 toredown = teardown(deadnet);
528 if (DBG && !toredown) {
529 Log.d(TAG, "Network declined teardown request");
530 }
531 }
532
The Android Open Source Project0caef3f2008-12-17 18:05:43 -0800533 /*
534 * Note that if toredown is true, deadnet cannot be null, so there is
535 * no danger of a null pointer exception here..
536 */
The Android Open Source Project54a942f2008-10-21 07:00:00 -0700537 if (!toredown || deadnet.getNetworkInfo().getType() != info.getType()) {
538 mActiveNetwork = thisNet;
539 if (DBG) Log.v(TAG, "Sending CONNECT bcast for " + info.getTypeName());
540 thisNet.updateNetworkSettings();
541 sendConnectedBroadcast(info);
542 if (isFailover) {
543 otherNet.releaseWakeLock();
544 }
545 } else {
546 if (DBG) Log.v(TAG, "Not broadcasting CONNECT_ACTION to torn down network " +
547 info.getTypeName());
548 }
549 }
550
551 private void handleScanResultsAvailable(NetworkInfo info) {
552 int networkType = info.getType();
553 if (networkType != ConnectivityManager.TYPE_WIFI) {
554 if (DBG) Log.v(TAG, "Got ScanResultsAvailable for " + info.getTypeName() + " network."
555 + " Don't know how to handle.");
556 }
557
558 mNetTrackers[networkType].interpretScanResultsAvailable();
559 }
560
561 private void handleNotificationChange(boolean visible, int id, Notification notification) {
562 NotificationManager notificationManager = (NotificationManager) mContext
563 .getSystemService(Context.NOTIFICATION_SERVICE);
564
565 if (visible) {
566 notificationManager.notify(id, notification);
567 } else {
568 notificationManager.cancel(id);
569 }
570 }
571
572 /**
573 * After any kind of change in the connectivity state of any network,
574 * make sure that anything that depends on the connectivity state of
575 * more than one network is set up correctly. We're mainly concerned
576 * with making sure that the list of DNS servers is set up according
577 * to which networks are connected, and ensuring that the right routing
578 * table entries exist.
579 */
580 private void handleConnectivityChange() {
581 /*
582 * If both mobile and wifi are enabled, add the host routes that
583 * will allow MMS traffic to pass on the mobile network. But
584 * remove the default route for the mobile network, so that there
585 * will be only one default route, to ensure that all traffic
586 * except MMS will travel via Wi-Fi.
587 */
588 int numConnectedNets = handleConfigurationChange();
589 if (numConnectedNets > 1) {
590 mMobileDataStateTracker.addPrivateRoutes();
591 mMobileDataStateTracker.removeDefaultRoute();
592 } else if (mMobileDataStateTracker.getNetworkInfo().isConnected()) {
593 mMobileDataStateTracker.removePrivateRoutes();
594 mMobileDataStateTracker.restoreDefaultRoute();
595 }
596 }
597
598 private int handleConfigurationChange() {
599 /*
600 * Set DNS properties. Always put Wi-Fi entries at the front of
601 * the list if it is active.
602 */
603 int index = 1;
604 String lastDns = "";
605 int numConnectedNets = 0;
606 int incrValue = ConnectivityManager.TYPE_MOBILE - ConnectivityManager.TYPE_WIFI;
607 int stopValue = ConnectivityManager.TYPE_MOBILE + incrValue;
608
The Android Open Source Project0caef3f2008-12-17 18:05:43 -0800609 for (int netType = ConnectivityManager.TYPE_WIFI; netType != stopValue; netType += incrValue) {
610 NetworkStateTracker nt = mNetTrackers[netType];
611 if (nt.getNetworkInfo().isConnected() && !nt.isTeardownRequested()) {
The Android Open Source Project54a942f2008-10-21 07:00:00 -0700612 ++numConnectedNets;
613 String[] dnsList = nt.getNameServers();
614 for (int i = 0; i < dnsList.length && dnsList[i] != null; i++) {
615 // skip duplicate entries
616 if (!dnsList[i].equals(lastDns)) {
617 SystemProperties.set("net.dns" + index++, dnsList[i]);
618 lastDns = dnsList[i];
619 }
620 }
621 }
622 }
623 // Null out any DNS properties that are no longer used
624 for (int i = index; i <= mNumDnsEntries; i++) {
625 SystemProperties.set("net.dns" + i, "");
626 }
627 mNumDnsEntries = index - 1;
628 // Notify the name resolver library of the change
The Android Open Source Project0caef3f2008-12-17 18:05:43 -0800629 SystemProperties.set("net.dnschange", String.valueOf(sDnsChangeCounter++));
The Android Open Source Project54a942f2008-10-21 07:00:00 -0700630 return numConnectedNets;
631 }
632
633 @Override
634 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
635 if (mContext.checkCallingPermission(android.Manifest.permission.DUMP)
636 != PackageManager.PERMISSION_GRANTED) {
637 pw.println("Permission Denial: can't dump ConnectivityService from from pid="
638 + Binder.getCallingPid()
639 + ", uid=" + Binder.getCallingUid());
640 return;
641 }
642 if (mActiveNetwork == null) {
643 pw.println("No active network");
644 } else {
645 pw.println("Active network: " + mActiveNetwork.getNetworkInfo().getTypeName());
646 }
647 pw.println();
648 for (NetworkStateTracker nst : mNetTrackers) {
649 pw.println(nst.getNetworkInfo());
650 pw.println(nst);
651 pw.println();
652 }
653 }
654
655 private class MyHandler extends Handler {
656 @Override
657 public void handleMessage(Message msg) {
658 NetworkInfo info;
659 switch (msg.what) {
660 case NetworkStateTracker.EVENT_STATE_CHANGED:
661 info = (NetworkInfo) msg.obj;
662 if (DBG) Log.v(TAG, "ConnectivityChange for " + info.getTypeName() + ": " +
663 info.getState() + "/" + info.getDetailedState());
664
665 // Connectivity state changed:
The Android Open Source Project0caef3f2008-12-17 18:05:43 -0800666 // [31-13] Reserved for future use
667 // [12-9] Network subtype (for mobile network, as defined by TelephonyManager)
668 // [8-3] Detailed state ordinal (as defined by NetworkInfo.DetailedState)
The Android Open Source Project54a942f2008-10-21 07:00:00 -0700669 // [2-0] Network type (as defined by ConnectivityManager)
670 int eventLogParam = (info.getType() & 0x7) |
The Android Open Source Project0caef3f2008-12-17 18:05:43 -0800671 ((info.getDetailedState().ordinal() & 0x3f) << 3) |
672 (info.getSubtype() << 9);
The Android Open Source Project54a942f2008-10-21 07:00:00 -0700673 EventLog.writeEvent(EVENTLOG_CONNECTIVITY_STATE_CHANGED, eventLogParam);
674
675 if (info.getDetailedState() == NetworkInfo.DetailedState.FAILED) {
676 handleConnectionFailure(info);
677 } else if (info.getState() == NetworkInfo.State.DISCONNECTED) {
678 handleDisconnect(info);
679 } else if (info.getState() == NetworkInfo.State.SUSPENDED) {
680 // TODO: need to think this over.
681 // the logic here is, handle SUSPENDED the same as DISCONNECTED. The
682 // only difference being we are broadcasting an intent with NetworkInfo
683 // that's suspended. This allows the applications an opportunity to
684 // handle DISCONNECTED and SUSPENDED differently, or not.
685 handleDisconnect(info);
686 } else if (info.getState() == NetworkInfo.State.CONNECTED) {
687 handleConnect(info);
688 }
689 handleConnectivityChange();
690 break;
691
692 case NetworkStateTracker.EVENT_SCAN_RESULTS_AVAILABLE:
693 info = (NetworkInfo) msg.obj;
694 handleScanResultsAvailable(info);
695 break;
696
697 case NetworkStateTracker.EVENT_NOTIFICATION_CHANGED:
698 handleNotificationChange(msg.arg1 == 1, msg.arg2, (Notification) msg.obj);
699
700 case NetworkStateTracker.EVENT_CONFIGURATION_CHANGED:
701 handleConfigurationChange();
702 break;
The Android Open Source Project0caef3f2008-12-17 18:05:43 -0800703
704 case NetworkStateTracker.EVENT_ROAMING_CHANGED:
705 // fill me in
706 break;
707
708 case NetworkStateTracker.EVENT_NETWORK_SUBTYPE_CHANGED:
709 // fill me in
710 break;
The Android Open Source Project54a942f2008-10-21 07:00:00 -0700711 }
712 }
713 }
714}