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