summaryrefslogtreecommitdiffstats
path: root/services/java/com/android/server/ConnectivityService.java
diff options
context:
space:
mode:
Diffstat (limited to 'services/java/com/android/server/ConnectivityService.java')
-rw-r--r--services/java/com/android/server/ConnectivityService.java741
1 files changed, 741 insertions, 0 deletions
diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java
new file mode 100644
index 0000000..760988d
--- /dev/null
+++ b/services/java/com/android/server/ConnectivityService.java
@@ -0,0 +1,741 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server;
+
+import android.app.Notification;
+import android.app.NotificationManager;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.net.ConnectivityManager;
+import android.net.IConnectivityManager;
+import android.net.MobileDataStateTracker;
+import android.net.NetworkInfo;
+import android.net.NetworkStateTracker;
+import android.net.wifi.WifiStateTracker;
+import android.os.Binder;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.os.ServiceManager;
+import android.os.SystemProperties;
+import android.provider.Settings;
+import android.provider.Sync;
+import android.util.EventLog;
+import android.util.Log;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+
+/**
+ * @hide
+ */
+public class ConnectivityService extends IConnectivityManager.Stub {
+
+ private static final boolean DBG = false;
+ private static final String TAG = "ConnectivityService";
+
+ // Event log tags (must be in sync with event-log-tags)
+ private static final int EVENTLOG_CONNECTIVITY_STATE_CHANGED = 50020;
+
+ /**
+ * Sometimes we want to refer to the individual network state
+ * trackers separately, and sometimes we just want to treat them
+ * abstractly.
+ */
+ private NetworkStateTracker mNetTrackers[];
+ private WifiStateTracker mWifiStateTracker;
+ private MobileDataStateTracker mMobileDataStateTracker;
+ private WifiWatchdogService mWifiWatchdogService;
+
+ private Context mContext;
+ private int mNetworkPreference;
+ private NetworkStateTracker mActiveNetwork;
+
+ private int mNumDnsEntries;
+ private static int sDnsChangeCounter;
+
+ private boolean mTestMode;
+ private static ConnectivityService sServiceInstance;
+
+ private static class ConnectivityThread extends Thread {
+ private Context mContext;
+
+ private ConnectivityThread(Context context) {
+ super("ConnectivityThread");
+ mContext = context;
+ }
+
+ @Override
+ public void run() {
+ Looper.prepare();
+ synchronized (this) {
+ sServiceInstance = new ConnectivityService(mContext);
+ notifyAll();
+ }
+ Looper.loop();
+ }
+
+ public static ConnectivityService getServiceInstance(Context context) {
+ ConnectivityThread thread = new ConnectivityThread(context);
+ thread.start();
+
+ synchronized (thread) {
+ while (sServiceInstance == null) {
+ try {
+ // Wait until sServiceInstance has been initialized.
+ thread.wait();
+ } catch (InterruptedException ignore) {
+ Log.e(TAG,
+ "Unexpected InterruptedException while waiting for ConnectivityService thread");
+ }
+ }
+ }
+
+ return sServiceInstance;
+ }
+ }
+
+ public static ConnectivityService getInstance(Context context) {
+ return ConnectivityThread.getServiceInstance(context);
+ }
+
+ private ConnectivityService(Context context) {
+ if (DBG) Log.v(TAG, "ConnectivityService starting up");
+ mContext = context;
+ mNetTrackers = new NetworkStateTracker[2];
+ Handler handler = new MyHandler();
+
+ mNetworkPreference = getPersistedNetworkPreference();
+
+ /*
+ * Create the network state trackers for Wi-Fi and mobile
+ * data. Maybe this could be done with a factory class,
+ * but it's not clear that it's worth it, given that
+ * the number of different network types is not going
+ * to change very often.
+ */
+ if (DBG) Log.v(TAG, "Starting Wifi Service.");
+ mWifiStateTracker = new WifiStateTracker(context, handler);
+ WifiService wifiService = new WifiService(context, mWifiStateTracker);
+ ServiceManager.addService(Context.WIFI_SERVICE, wifiService);
+ mNetTrackers[ConnectivityManager.TYPE_WIFI] = mWifiStateTracker;
+
+ mMobileDataStateTracker = new MobileDataStateTracker(context, handler);
+ mNetTrackers[ConnectivityManager.TYPE_MOBILE] = mMobileDataStateTracker;
+
+ mActiveNetwork = null;
+ mNumDnsEntries = 0;
+
+ mTestMode = SystemProperties.get("cm.test.mode").equals("true")
+ && SystemProperties.get("ro.build.type").equals("eng");
+
+ for (NetworkStateTracker t : mNetTrackers)
+ t.startMonitoring();
+
+ // Constructing this starts it too
+ mWifiWatchdogService = new WifiWatchdogService(context, mWifiStateTracker);
+ }
+
+ /**
+ * Sets the preferred network.
+ * @param preference the new preference
+ */
+ public synchronized void setNetworkPreference(int preference) {
+ enforceChangePermission();
+ if (ConnectivityManager.isNetworkTypeValid(preference)) {
+ if (mNetworkPreference != preference) {
+ persistNetworkPreference(preference);
+ mNetworkPreference = preference;
+ enforcePreference();
+ }
+ }
+ }
+
+ public int getNetworkPreference() {
+ enforceAccessPermission();
+ return mNetworkPreference;
+ }
+
+ private void persistNetworkPreference(int networkPreference) {
+ final ContentResolver cr = mContext.getContentResolver();
+ Settings.Secure.putInt(cr, Settings.Secure.NETWORK_PREFERENCE, networkPreference);
+ }
+
+ private int getPersistedNetworkPreference() {
+ final ContentResolver cr = mContext.getContentResolver();
+
+ final int networkPrefSetting = Settings.Secure
+ .getInt(cr, Settings.Secure.NETWORK_PREFERENCE, -1);
+ if (networkPrefSetting != -1) {
+ return networkPrefSetting;
+ }
+
+ return ConnectivityManager.DEFAULT_NETWORK_PREFERENCE;
+ }
+
+ /**
+ * Make the state of network connectivity conform to the preference settings.
+ * In this method, we only tear down a non-preferred network. Establishing
+ * a connection to the preferred network is taken care of when we handle
+ * the disconnect event from the non-preferred network
+ * (see {@link #handleDisconnect(NetworkInfo)}).
+ */
+ private void enforcePreference() {
+ if (mActiveNetwork == null)
+ return;
+
+ for (NetworkStateTracker t : mNetTrackers) {
+ if (t == mActiveNetwork) {
+ int netType = t.getNetworkInfo().getType();
+ int otherNetType = ((netType == ConnectivityManager.TYPE_WIFI) ?
+ ConnectivityManager.TYPE_MOBILE :
+ ConnectivityManager.TYPE_WIFI);
+
+ if (t.getNetworkInfo().getType() != mNetworkPreference) {
+ NetworkStateTracker otherTracker = mNetTrackers[otherNetType];
+ if (otherTracker.isAvailable()) {
+ teardown(t);
+ }
+ }
+ }
+ }
+ }
+
+ private boolean teardown(NetworkStateTracker netTracker) {
+ if (netTracker.teardown()) {
+ netTracker.setTeardownRequested(true);
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * Return NetworkInfo for the active (i.e., connected) network interface.
+ * It is assumed that at most one network is active at a time. If more
+ * than one is active, it is indeterminate which will be returned.
+ * @return the info for the active network, or {@code null} if none is active
+ */
+ public NetworkInfo getActiveNetworkInfo() {
+ enforceAccessPermission();
+ for (NetworkStateTracker t : mNetTrackers) {
+ NetworkInfo info = t.getNetworkInfo();
+ if (info.isConnected()) {
+ return info;
+ }
+ }
+ return null;
+ }
+
+ public NetworkInfo getNetworkInfo(int networkType) {
+ enforceAccessPermission();
+ if (ConnectivityManager.isNetworkTypeValid(networkType)) {
+ NetworkStateTracker t = mNetTrackers[networkType];
+ if (t != null)
+ return t.getNetworkInfo();
+ }
+ return null;
+ }
+
+ public NetworkInfo[] getAllNetworkInfo() {
+ enforceAccessPermission();
+ NetworkInfo[] result = new NetworkInfo[mNetTrackers.length];
+ int i = 0;
+ for (NetworkStateTracker t : mNetTrackers) {
+ result[i++] = t.getNetworkInfo();
+ }
+ return result;
+ }
+
+ public boolean setRadios(boolean turnOn) {
+ boolean result = true;
+ enforceChangePermission();
+ for (NetworkStateTracker t : mNetTrackers) {
+ result = t.setRadio(turnOn) && result;
+ }
+ return result;
+ }
+
+ public boolean setRadio(int netType, boolean turnOn) {
+ enforceChangePermission();
+ if (!ConnectivityManager.isNetworkTypeValid(netType)) {
+ return false;
+ }
+ NetworkStateTracker tracker = mNetTrackers[netType];
+ return tracker != null && tracker.setRadio(turnOn);
+ }
+
+ public int startUsingNetworkFeature(int networkType, String feature) {
+ enforceChangePermission();
+ if (!ConnectivityManager.isNetworkTypeValid(networkType)) {
+ return -1;
+ }
+ NetworkStateTracker tracker = mNetTrackers[networkType];
+ if (tracker != null) {
+ return tracker.startUsingNetworkFeature(feature, getCallingPid(), getCallingUid());
+ }
+ return -1;
+ }
+
+ public int stopUsingNetworkFeature(int networkType, String feature) {
+ enforceChangePermission();
+ if (!ConnectivityManager.isNetworkTypeValid(networkType)) {
+ return -1;
+ }
+ NetworkStateTracker tracker = mNetTrackers[networkType];
+ if (tracker != null) {
+ return tracker.stopUsingNetworkFeature(feature, getCallingPid(), getCallingUid());
+ }
+ return -1;
+ }
+
+ /**
+ * Ensure that a network route exists to deliver traffic to the specified
+ * host via the specified network interface.
+ * @param networkType the type of the network over which traffic to the specified
+ * host is to be routed
+ * @param hostAddress the IP address of the host to which the route is desired
+ * @return {@code true} on success, {@code false} on failure
+ */
+ public boolean requestRouteToHost(int networkType, int hostAddress) {
+ enforceChangePermission();
+ if (!ConnectivityManager.isNetworkTypeValid(networkType)) {
+ return false;
+ }
+ NetworkStateTracker tracker = mNetTrackers[networkType];
+ /*
+ * If there's only one connected network, and it's the one requested,
+ * then we don't have to do anything - the requested route already
+ * exists. If it's not the requested network, then it's not possible
+ * to establish the requested route. Finally, if there is more than
+ * one connected network, then we must insert an entry in the routing
+ * table.
+ */
+ if (getNumConnectedNetworks() > 1) {
+ return tracker.requestRouteToHost(hostAddress);
+ } else {
+ return tracker.getNetworkInfo().getType() == networkType;
+ }
+ }
+
+ /**
+ * @see ConnectivityManager#getBackgroundDataSetting()
+ */
+ public boolean getBackgroundDataSetting() {
+ return Settings.Secure.getInt(mContext.getContentResolver(),
+ Settings.Secure.BACKGROUND_DATA, 1) == 1;
+ }
+
+ /**
+ * @see ConnectivityManager#setBackgroundDataSetting(boolean)
+ */
+ public void setBackgroundDataSetting(boolean allowBackgroundDataUsage) {
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.CHANGE_BACKGROUND_DATA_SETTING,
+ "ConnectivityService");
+
+ if (getBackgroundDataSetting() == allowBackgroundDataUsage) return;
+
+ Settings.Secure.putInt(mContext.getContentResolver(),
+ Settings.Secure.BACKGROUND_DATA, allowBackgroundDataUsage ? 1 : 0);
+
+ Intent broadcast = new Intent(
+ ConnectivityManager.ACTION_BACKGROUND_DATA_SETTING_CHANGED);
+ mContext.sendBroadcast(broadcast);
+ }
+
+ private int getNumConnectedNetworks() {
+ int numConnectedNets = 0;
+
+ for (NetworkStateTracker nt : mNetTrackers) {
+ if (nt.getNetworkInfo().isConnected() && !nt.isTeardownRequested()) {
+ ++numConnectedNets;
+ }
+ }
+ return numConnectedNets;
+ }
+
+ private void enforceAccessPermission() {
+ mContext.enforceCallingOrSelfPermission(android.Manifest.permission.ACCESS_NETWORK_STATE,
+ "ConnectivityService");
+ }
+
+ private void enforceChangePermission() {
+ mContext.enforceCallingOrSelfPermission(android.Manifest.permission.CHANGE_NETWORK_STATE,
+ "ConnectivityService");
+
+ }
+
+ /**
+ * Handle a {@code DISCONNECTED} event. If this pertains to the non-active network,
+ * we ignore it. If it is for the active network, we send out a broadcast.
+ * But first, we check whether it might be possible to connect to a different
+ * network.
+ * @param info the {@code NetworkInfo} for the network
+ */
+ private void handleDisconnect(NetworkInfo info) {
+
+ if (DBG) Log.v(TAG, "Handle DISCONNECT for " + info.getTypeName());
+
+ mNetTrackers[info.getType()].setTeardownRequested(false);
+ /*
+ * If the disconnected network is not the active one, then don't report
+ * this as a loss of connectivity. What probably happened is that we're
+ * getting the disconnect for a network that we explicitly disabled
+ * in accordance with network preference policies.
+ */
+ if (mActiveNetwork == null || info.getType() != mActiveNetwork.getNetworkInfo().getType())
+ return;
+
+ NetworkStateTracker newNet;
+ if (info.getType() == ConnectivityManager.TYPE_MOBILE) {
+ newNet = mWifiStateTracker;
+ } else /* info().getType() == TYPE_WIFI */ {
+ newNet = mMobileDataStateTracker;
+ }
+
+ /**
+ * See if the other network is available to fail over to.
+ * If is not available, we enable it anyway, so that it
+ * will be able to connect when it does become available,
+ * but we report a total loss of connectivity rather than
+ * report that we are attempting to fail over.
+ */
+ NetworkInfo switchTo = null;
+ if (newNet.isAvailable()) {
+ mActiveNetwork = newNet;
+ switchTo = newNet.getNetworkInfo();
+ switchTo.setFailover(true);
+ if (!switchTo.isConnectedOrConnecting()) {
+ newNet.reconnect();
+ }
+ } else {
+ newNet.reconnect();
+ }
+
+ boolean otherNetworkConnected = false;
+ Intent intent = new Intent(ConnectivityManager.CONNECTIVITY_ACTION);
+ intent.putExtra(ConnectivityManager.EXTRA_NETWORK_INFO, info);
+ if (info.isFailover()) {
+ intent.putExtra(ConnectivityManager.EXTRA_IS_FAILOVER, true);
+ info.setFailover(false);
+ }
+ if (info.getReason() != null) {
+ intent.putExtra(ConnectivityManager.EXTRA_REASON, info.getReason());
+ }
+ if (info.getExtraInfo() != null) {
+ intent.putExtra(ConnectivityManager.EXTRA_EXTRA_INFO, info.getExtraInfo());
+ }
+ if (switchTo != null) {
+ otherNetworkConnected = switchTo.isConnected();
+ if (DBG) {
+ if (otherNetworkConnected) {
+ Log.v(TAG, "Switching to already connected " + switchTo.getTypeName());
+ } else {
+ Log.v(TAG, "Attempting to switch to " + switchTo.getTypeName());
+ }
+ }
+ intent.putExtra(ConnectivityManager.EXTRA_OTHER_NETWORK_INFO, switchTo);
+ } else {
+ intent.putExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, true);
+ }
+ if (DBG) Log.v(TAG, "Sending DISCONNECT bcast for " + info.getTypeName() +
+ (switchTo == null ? "" : " other=" + switchTo.getTypeName()));
+
+ mContext.sendStickyBroadcast(intent);
+ /*
+ * If the failover network is already connected, then immediately send out
+ * a followup broadcast indicating successful failover
+ */
+ if (switchTo != null && otherNetworkConnected)
+ sendConnectedBroadcast(switchTo);
+ }
+
+ private void sendConnectedBroadcast(NetworkInfo info) {
+ Intent intent = new Intent(ConnectivityManager.CONNECTIVITY_ACTION);
+ intent.putExtra(ConnectivityManager.EXTRA_NETWORK_INFO, info);
+ if (info.isFailover()) {
+ intent.putExtra(ConnectivityManager.EXTRA_IS_FAILOVER, true);
+ info.setFailover(false);
+ }
+ if (info.getReason() != null) {
+ intent.putExtra(ConnectivityManager.EXTRA_REASON, info.getReason());
+ }
+ if (info.getExtraInfo() != null) {
+ intent.putExtra(ConnectivityManager.EXTRA_EXTRA_INFO, info.getExtraInfo());
+ }
+ mContext.sendStickyBroadcast(intent);
+ }
+
+ /**
+ * Called when an attempt to fail over to another network has failed.
+ * @param info the {@link NetworkInfo} for the failed network
+ */
+ private void handleConnectionFailure(NetworkInfo info) {
+ mNetTrackers[info.getType()].setTeardownRequested(false);
+ if (getActiveNetworkInfo() == null) {
+ String reason = info.getReason();
+ String extraInfo = info.getExtraInfo();
+
+ if (DBG) {
+ String reasonText;
+ if (reason == null) {
+ reasonText = ".";
+ } else {
+ reasonText = " (" + reason + ").";
+ }
+ Log.v(TAG, "Attempt to connect to " + info.getTypeName() + " failed" + reasonText);
+ }
+
+ Intent intent = new Intent(ConnectivityManager.CONNECTIVITY_ACTION);
+ intent.putExtra(ConnectivityManager.EXTRA_NETWORK_INFO, info);
+ intent.putExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, true);
+ if (reason != null) {
+ intent.putExtra(ConnectivityManager.EXTRA_REASON, reason);
+ }
+ if (extraInfo != null) {
+ intent.putExtra(ConnectivityManager.EXTRA_EXTRA_INFO, extraInfo);
+ }
+ if (info.isFailover()) {
+ intent.putExtra(ConnectivityManager.EXTRA_IS_FAILOVER, true);
+ info.setFailover(false);
+ }
+ mContext.sendStickyBroadcast(intent);
+ }
+ }
+
+ private void handleConnect(NetworkInfo info) {
+ if (DBG) Log.v(TAG, "Handle CONNECT for " + info.getTypeName());
+
+ // snapshot isFailover, because sendConnectedBroadcast() resets it
+ boolean isFailover = info.isFailover();
+ NetworkStateTracker thisNet = mNetTrackers[info.getType()];
+ NetworkStateTracker deadnet = null;
+ NetworkStateTracker otherNet;
+ if (info.getType() == ConnectivityManager.TYPE_MOBILE) {
+ otherNet = mWifiStateTracker;
+ } else /* info().getType() == TYPE_WIFI */ {
+ otherNet = mMobileDataStateTracker;
+ }
+ /*
+ * Check policy to see whether we are connected to a non-preferred
+ * network that now needs to be torn down.
+ */
+ NetworkInfo wifiInfo = mWifiStateTracker.getNetworkInfo();
+ NetworkInfo mobileInfo = mMobileDataStateTracker.getNetworkInfo();
+ if (wifiInfo.isConnected() && mobileInfo.isConnected()) {
+ if (mNetworkPreference == ConnectivityManager.TYPE_WIFI)
+ deadnet = mMobileDataStateTracker;
+ else
+ deadnet = mWifiStateTracker;
+ }
+
+ boolean toredown = false;
+ thisNet.setTeardownRequested(false);
+ if (!mTestMode && deadnet != null) {
+ if (DBG) Log.v(TAG, "Policy requires " +
+ deadnet.getNetworkInfo().getTypeName() + " teardown");
+ toredown = teardown(deadnet);
+ if (DBG && !toredown) {
+ Log.d(TAG, "Network declined teardown request");
+ }
+ }
+
+ /*
+ * Note that if toredown is true, deadnet cannot be null, so there is
+ * no danger of a null pointer exception here..
+ */
+ if (!toredown || deadnet.getNetworkInfo().getType() != info.getType()) {
+ mActiveNetwork = thisNet;
+ if (DBG) Log.v(TAG, "Sending CONNECT bcast for " + info.getTypeName());
+ thisNet.updateNetworkSettings();
+ sendConnectedBroadcast(info);
+ if (isFailover) {
+ otherNet.releaseWakeLock();
+ }
+ } else {
+ if (DBG) Log.v(TAG, "Not broadcasting CONNECT_ACTION to torn down network " +
+ info.getTypeName());
+ }
+ }
+
+ private void handleScanResultsAvailable(NetworkInfo info) {
+ int networkType = info.getType();
+ if (networkType != ConnectivityManager.TYPE_WIFI) {
+ if (DBG) Log.v(TAG, "Got ScanResultsAvailable for " + info.getTypeName() + " network."
+ + " Don't know how to handle.");
+ }
+
+ mNetTrackers[networkType].interpretScanResultsAvailable();
+ }
+
+ private void handleNotificationChange(boolean visible, int id, Notification notification) {
+ NotificationManager notificationManager = (NotificationManager) mContext
+ .getSystemService(Context.NOTIFICATION_SERVICE);
+
+ if (visible) {
+ notificationManager.notify(id, notification);
+ } else {
+ notificationManager.cancel(id);
+ }
+ }
+
+ /**
+ * After any kind of change in the connectivity state of any network,
+ * make sure that anything that depends on the connectivity state of
+ * more than one network is set up correctly. We're mainly concerned
+ * with making sure that the list of DNS servers is set up according
+ * to which networks are connected, and ensuring that the right routing
+ * table entries exist.
+ */
+ private void handleConnectivityChange() {
+ /*
+ * If both mobile and wifi are enabled, add the host routes that
+ * will allow MMS traffic to pass on the mobile network. But
+ * remove the default route for the mobile network, so that there
+ * will be only one default route, to ensure that all traffic
+ * except MMS will travel via Wi-Fi.
+ */
+ int numConnectedNets = handleConfigurationChange();
+ if (numConnectedNets > 1) {
+ mMobileDataStateTracker.addPrivateRoutes();
+ mMobileDataStateTracker.removeDefaultRoute();
+ } else if (mMobileDataStateTracker.getNetworkInfo().isConnected()) {
+ mMobileDataStateTracker.removePrivateRoutes();
+ mMobileDataStateTracker.restoreDefaultRoute();
+ }
+ }
+
+ private int handleConfigurationChange() {
+ /*
+ * Set DNS properties. Always put Wi-Fi entries at the front of
+ * the list if it is active.
+ */
+ int index = 1;
+ String lastDns = "";
+ int numConnectedNets = 0;
+ int incrValue = ConnectivityManager.TYPE_MOBILE - ConnectivityManager.TYPE_WIFI;
+ int stopValue = ConnectivityManager.TYPE_MOBILE + incrValue;
+
+ for (int netType = ConnectivityManager.TYPE_WIFI; netType != stopValue; netType += incrValue) {
+ NetworkStateTracker nt = mNetTrackers[netType];
+ if (nt.getNetworkInfo().isConnected() && !nt.isTeardownRequested()) {
+ ++numConnectedNets;
+ String[] dnsList = nt.getNameServers();
+ for (int i = 0; i < dnsList.length && dnsList[i] != null; i++) {
+ // skip duplicate entries
+ if (!dnsList[i].equals(lastDns)) {
+ SystemProperties.set("net.dns" + index++, dnsList[i]);
+ lastDns = dnsList[i];
+ }
+ }
+ }
+ }
+ // Null out any DNS properties that are no longer used
+ for (int i = index; i <= mNumDnsEntries; i++) {
+ SystemProperties.set("net.dns" + i, "");
+ }
+ mNumDnsEntries = index - 1;
+ // Notify the name resolver library of the change
+ SystemProperties.set("net.dnschange", String.valueOf(sDnsChangeCounter++));
+ return numConnectedNets;
+ }
+
+ @Override
+ protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
+ != PackageManager.PERMISSION_GRANTED) {
+ pw.println("Permission Denial: can't dump ConnectivityService from from pid="
+ + Binder.getCallingPid()
+ + ", uid=" + Binder.getCallingUid());
+ return;
+ }
+ if (mActiveNetwork == null) {
+ pw.println("No active network");
+ } else {
+ pw.println("Active network: " + mActiveNetwork.getNetworkInfo().getTypeName());
+ }
+ pw.println();
+ for (NetworkStateTracker nst : mNetTrackers) {
+ pw.println(nst.getNetworkInfo());
+ pw.println(nst);
+ pw.println();
+ }
+ }
+
+ private class MyHandler extends Handler {
+ @Override
+ public void handleMessage(Message msg) {
+ NetworkInfo info;
+ switch (msg.what) {
+ case NetworkStateTracker.EVENT_STATE_CHANGED:
+ info = (NetworkInfo) msg.obj;
+ if (DBG) Log.v(TAG, "ConnectivityChange for " + info.getTypeName() + ": " +
+ info.getState() + "/" + info.getDetailedState());
+
+ // Connectivity state changed:
+ // [31-13] Reserved for future use
+ // [12-9] Network subtype (for mobile network, as defined by TelephonyManager)
+ // [8-3] Detailed state ordinal (as defined by NetworkInfo.DetailedState)
+ // [2-0] Network type (as defined by ConnectivityManager)
+ int eventLogParam = (info.getType() & 0x7) |
+ ((info.getDetailedState().ordinal() & 0x3f) << 3) |
+ (info.getSubtype() << 9);
+ EventLog.writeEvent(EVENTLOG_CONNECTIVITY_STATE_CHANGED, eventLogParam);
+
+ if (info.getDetailedState() == NetworkInfo.DetailedState.FAILED) {
+ handleConnectionFailure(info);
+ } else if (info.getState() == NetworkInfo.State.DISCONNECTED) {
+ handleDisconnect(info);
+ } else if (info.getState() == NetworkInfo.State.SUSPENDED) {
+ // TODO: need to think this over.
+ // the logic here is, handle SUSPENDED the same as DISCONNECTED. The
+ // only difference being we are broadcasting an intent with NetworkInfo
+ // that's suspended. This allows the applications an opportunity to
+ // handle DISCONNECTED and SUSPENDED differently, or not.
+ handleDisconnect(info);
+ } else if (info.getState() == NetworkInfo.State.CONNECTED) {
+ handleConnect(info);
+ }
+ handleConnectivityChange();
+ break;
+
+ case NetworkStateTracker.EVENT_SCAN_RESULTS_AVAILABLE:
+ info = (NetworkInfo) msg.obj;
+ handleScanResultsAvailable(info);
+ break;
+
+ case NetworkStateTracker.EVENT_NOTIFICATION_CHANGED:
+ handleNotificationChange(msg.arg1 == 1, msg.arg2, (Notification) msg.obj);
+
+ case NetworkStateTracker.EVENT_CONFIGURATION_CHANGED:
+ handleConfigurationChange();
+ break;
+
+ case NetworkStateTracker.EVENT_ROAMING_CHANGED:
+ // fill me in
+ break;
+
+ case NetworkStateTracker.EVENT_NETWORK_SUBTYPE_CHANGED:
+ // fill me in
+ break;
+ }
+ }
+ }
+}