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.java388
1 files changed, 299 insertions, 89 deletions
diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java
index 041c13b..4da0bac 100644
--- a/services/java/com/android/server/ConnectivityService.java
+++ b/services/java/com/android/server/ConnectivityService.java
@@ -26,13 +26,16 @@ import android.net.ConnectivityManager;
import android.net.IConnectivityManager;
import android.net.MobileDataStateTracker;
import android.net.NetworkInfo;
+import android.net.NetworkProperties;
import android.net.NetworkStateTracker;
import android.net.wifi.WifiStateTracker;
+import android.net.NetworkUtils;
import android.os.Binder;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
+import android.os.PowerManager;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SystemProperties;
@@ -46,8 +49,13 @@ import com.android.internal.telephony.Phone;
import com.android.server.connectivity.Tethering;
import java.io.FileDescriptor;
+import java.io.FileWriter;
+import java.io.IOException;
import java.io.PrintWriter;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.List;
/**
@@ -64,7 +72,6 @@ public class ConnectivityService extends IConnectivityManager.Stub {
private static final String NETWORK_RESTORE_DELAY_PROP_NAME =
"android.telephony.apn-restore";
-
private Tethering mTethering;
private boolean mTetheringConfigValid = false;
@@ -81,6 +88,8 @@ public class ConnectivityService extends IConnectivityManager.Stub {
*/
private List mNetRequestersPids[];
+ private WifiWatchdogService mWifiWatchdogService;
+
// priority order of the nettrackers
// (excluding dynamically set mNetworkPreference)
// TODO - move mNetworkTypePreference into this
@@ -104,6 +113,11 @@ public class ConnectivityService extends IConnectivityManager.Stub {
private boolean mSystemReady;
private Intent mInitialBroadcast;
+ private PowerManager.WakeLock mNetTransitionWakeLock;
+ private String mNetTransitionWakeLockCausedBy = "";
+ private int mNetTransitionWakeLockSerialNumber;
+ private int mNetTransitionWakeLockTimeout;
+
private static class NetworkAttributes {
/**
* Class for holding settings read from resources.
@@ -194,6 +208,12 @@ public class ConnectivityService extends IConnectivityManager.Stub {
}
mContext = context;
+
+ PowerManager powerManager = (PowerManager)mContext.getSystemService(Context.POWER_SERVICE);
+ mNetTransitionWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
+ mNetTransitionWakeLockTimeout = mContext.getResources().getInteger(
+ com.android.internal.R.integer.config_networkTransitionTimeout);
+
mNetTrackers = new NetworkStateTracker[
ConnectivityManager.MAX_NETWORK_TYPE+1];
mHandler = new MyHandler();
@@ -293,18 +313,21 @@ public class ConnectivityService extends IConnectivityManager.Stub {
switch (mNetAttributes[netType].mRadio) {
case ConnectivityManager.TYPE_WIFI:
if (DBG) Slog.v(TAG, "Starting Wifi Service.");
- WifiStateTracker wst = new WifiStateTracker(context, mHandler);
- WifiService wifiService = new WifiService(context, wst);
+ WifiStateTracker wst = new WifiStateTracker();
+ WifiService wifiService = new WifiService(context);
ServiceManager.addService(Context.WIFI_SERVICE, wifiService);
- wifiService.startWifi();
+ wifiService.checkAndStartWifi();
mNetTrackers[ConnectivityManager.TYPE_WIFI] = wst;
- wst.startMonitoring();
+ wst.startMonitoring(context, mHandler);
+
+ //TODO: as part of WWS refactor, create only when needed
+ mWifiWatchdogService = new WifiWatchdogService(context);
break;
case ConnectivityManager.TYPE_MOBILE:
- mNetTrackers[netType] = new MobileDataStateTracker(context, mHandler,
- netType, mNetAttributes[netType].mName);
- mNetTrackers[netType].startMonitoring();
+ mNetTrackers[netType] = new MobileDataStateTracker(netType,
+ mNetAttributes[netType].mName);
+ mNetTrackers[netType].startMonitoring(context, mHandler);
if (noMobileData) {
if (DBG) Slog.d(TAG, "tearing down Mobile networks due to setting");
mNetTrackers[netType].teardown();
@@ -321,7 +344,8 @@ public class ConnectivityService extends IConnectivityManager.Stub {
mTetheringConfigValid = (((mNetTrackers[ConnectivityManager.TYPE_MOBILE_DUN] != null) ||
!mTethering.isDunRequired()) &&
(mTethering.getTetherableUsbRegexs().length != 0 ||
- mTethering.getTetherableWifiRegexs().length != 0) &&
+ mTethering.getTetherableWifiRegexs().length != 0 ||
+ mTethering.getTetherableBluetoothRegexs().length != 0) &&
mTethering.getUpstreamIfaceRegexs().length != 0);
}
@@ -597,15 +621,7 @@ public class ConnectivityService extends IConnectivityManager.Stub {
network.reconnect();
return Phone.APN_REQUEST_STARTED;
} else {
- synchronized(this) {
- mFeatureUsers.add(f);
- }
- mHandler.sendMessageDelayed(mHandler.obtainMessage(
- NetworkStateTracker.EVENT_RESTORE_DEFAULT_NETWORK,
- f), getRestoreDefaultNetworkDelay());
-
- return network.startUsingNetworkFeature(feature,
- getCallingPid(), getCallingUid());
+ return -1;
}
}
return Phone.APN_TYPE_NOT_AVAILABLE;
@@ -724,8 +740,7 @@ public class ConnectivityService extends IConnectivityManager.Stub {
tracker.teardown();
return 1;
} else {
- // do it the old fashioned way
- return tracker.stopUsingNetworkFeature(feature, pid, uid);
+ return -1;
}
}
@@ -736,6 +751,7 @@ public class ConnectivityService extends IConnectivityManager.Stub {
* specified host is to be routed
* @param hostAddress the IP address of the host to which the route is
* desired
+ * todo - deprecate (only v4!)
* @return {@code true} on success, {@code false} on failure
*/
public boolean requestRouteToHost(int networkType, int hostAddress) {
@@ -752,7 +768,39 @@ public class ConnectivityService extends IConnectivityManager.Stub {
}
return false;
}
- return tracker.requestRouteToHost(hostAddress);
+ try {
+ InetAddress addr = InetAddress.getByAddress(NetworkUtils.v4IntToArray(hostAddress));
+ return addHostRoute(tracker, addr);
+ } catch (UnknownHostException e) {}
+ return false;
+ }
+
+ /**
+ * Ensure that a network route exists to deliver traffic to the specified
+ * host via the mobile data network.
+ * @param hostAddress the IP address of the host to which the route is desired,
+ * in network byte order.
+ * TODO - deprecate
+ * @return {@code true} on success, {@code false} on failure
+ */
+ private boolean addHostRoute(NetworkStateTracker nt, InetAddress hostAddress) {
+ if (nt.getNetworkInfo().getType() == ConnectivityManager.TYPE_WIFI) {
+ return false;
+ }
+
+ NetworkProperties p = nt.getNetworkProperties();
+ if (p == null) return false;
+ String interfaceName = p.getInterfaceName();
+
+ if (DBG) {
+ Slog.d(TAG, "Requested host route to " + hostAddress + "(" + interfaceName + ")");
+ }
+ if (interfaceName != null) {
+ return NetworkUtils.addHostRoute(interfaceName, hostAddress) == 0;
+ } else {
+ if (DBG) Slog.e(TAG, "addHostRoute failed due to null interface name");
+ return false;
+ }
}
/**
@@ -859,6 +907,12 @@ public class ConnectivityService extends IConnectivityManager.Stub {
"ConnectivityService");
}
+ private void enforceConnectivityInternalPermission() {
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.CONNECTIVITY_INTERNAL,
+ "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
@@ -1131,44 +1185,30 @@ public class ConnectivityService extends IConnectivityManager.Stub {
Slog.e(TAG, "Network declined teardown request");
return;
}
- if (isFailover) {
- otherNet.releaseWakeLock();
- }
+ }
+ }
+ synchronized (ConnectivityService.this) {
+ // have a new default network, release the transition wakelock in a second
+ // if it's held. The second pause is to allow apps to reconnect over the
+ // new network
+ if (mNetTransitionWakeLock.isHeld()) {
+ mHandler.sendMessageDelayed(mHandler.obtainMessage(
+ NetworkStateTracker.EVENT_CLEAR_NET_TRANSITION_WAKELOCK,
+ mNetTransitionWakeLockSerialNumber, 0),
+ 1000);
}
}
mActiveDefaultNetwork = type;
}
thisNet.setTeardownRequested(false);
- thisNet.updateNetworkSettings();
+ updateNetworkSettings(thisNet);
handleConnectivityChange(type);
sendConnectedBroadcast(info);
}
- private void handleScanResultsAvailable(NetworkInfo info) {
- int networkType = info.getType();
- if (networkType != ConnectivityManager.TYPE_WIFI) {
- if (DBG) Slog.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 a change in the connectivity state of any network, We're mainly
- * concerned with making sure that the list of DNS servers is setupup
+ * After a change in the connectivity state of a network. 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.
*/
@@ -1181,19 +1221,158 @@ public class ConnectivityService extends IConnectivityManager.Stub {
if (mNetTrackers[netType].getNetworkInfo().isConnected()) {
if (mNetAttributes[netType].isDefault()) {
- mNetTrackers[netType].addDefaultRoute();
+ addDefaultRoute(mNetTrackers[netType]);
} else {
- mNetTrackers[netType].addPrivateDnsRoutes();
+ addPrivateDnsRoutes(mNetTrackers[netType]);
}
} else {
if (mNetAttributes[netType].isDefault()) {
- mNetTrackers[netType].removeDefaultRoute();
+ removeDefaultRoute(mNetTrackers[netType]);
+ } else {
+ removePrivateDnsRoutes(mNetTrackers[netType]);
+ }
+ }
+ }
+
+ private void addPrivateDnsRoutes(NetworkStateTracker nt) {
+ boolean privateDnsRouteSet = nt.isPrivateDnsRouteSet();
+ NetworkProperties p = nt.getNetworkProperties();
+ if (p == null) return;
+ String interfaceName = p.getInterfaceName();
+
+ if (DBG) {
+ Slog.d(TAG, "addPrivateDnsRoutes for " + nt +
+ "(" + interfaceName + ") - mPrivateDnsRouteSet = " + privateDnsRouteSet);
+ }
+ if (interfaceName != null && !privateDnsRouteSet) {
+ Collection<InetAddress> dnsList = p.getDnses();
+ for (InetAddress dns : dnsList) {
+ if (DBG) Slog.d(TAG, " adding " + dns);
+ NetworkUtils.addHostRoute(interfaceName, dns);
+ }
+ nt.privateDnsRouteSet(true);
+ }
+ }
+
+ private void removePrivateDnsRoutes(NetworkStateTracker nt) {
+ // TODO - we should do this explicitly but the NetUtils api doesnt
+ // support this yet - must remove all. No worse than before
+ NetworkProperties p = nt.getNetworkProperties();
+ if (p == null) return;
+ String interfaceName = p.getInterfaceName();
+ boolean privateDnsRouteSet = nt.isPrivateDnsRouteSet();
+ if (interfaceName != null && privateDnsRouteSet) {
+ if (DBG) {
+ Slog.d(TAG, "removePrivateDnsRoutes for " + nt.getNetworkInfo().getTypeName() +
+ " (" + interfaceName + ")");
+ }
+ NetworkUtils.removeHostRoutes(interfaceName);
+ nt.privateDnsRouteSet(false);
+ }
+ }
+
+
+ private void addDefaultRoute(NetworkStateTracker nt) {
+ NetworkProperties p = nt.getNetworkProperties();
+ if (p == null) return;
+ String interfaceName = p.getInterfaceName();
+ InetAddress defaultGatewayAddr = p.getGateway();
+
+ if ((interfaceName != null) && (defaultGatewayAddr != null )) {
+ if ((NetworkUtils.setDefaultRoute(interfaceName, defaultGatewayAddr) >= 0) && DBG) {
+ NetworkInfo networkInfo = nt.getNetworkInfo();
+ Slog.d(TAG, "addDefaultRoute for " + networkInfo.getTypeName() +
+ " (" + interfaceName + "), GatewayAddr=" + defaultGatewayAddr);
+ }
+ }
+ }
+
+
+ public void removeDefaultRoute(NetworkStateTracker nt) {
+ NetworkProperties p = nt.getNetworkProperties();
+ if (p == null) return;
+ String interfaceName = p.getInterfaceName();
+
+ if (interfaceName != null) {
+ if ((NetworkUtils.removeDefaultRoute(interfaceName) >= 0) && DBG) {
+ NetworkInfo networkInfo = nt.getNetworkInfo();
+ Slog.d(TAG, "removeDefaultRoute for " + networkInfo.getTypeName() + " (" +
+ interfaceName + ")");
+ }
+ }
+ }
+
+ /**
+ * Reads the network specific TCP buffer sizes from SystemProperties
+ * net.tcp.buffersize.[default|wifi|umts|edge|gprs] and set them for system
+ * wide use
+ */
+ public void updateNetworkSettings(NetworkStateTracker nt) {
+ String key = nt.getTcpBufferSizesPropName();
+ String bufferSizes = SystemProperties.get(key);
+
+ if (bufferSizes.length() == 0) {
+ Slog.e(TAG, key + " not found in system properties. Using defaults");
+
+ // Setting to default values so we won't be stuck to previous values
+ key = "net.tcp.buffersize.default";
+ bufferSizes = SystemProperties.get(key);
+ }
+
+ // Set values in kernel
+ if (bufferSizes.length() != 0) {
+ if (DBG) {
+ Slog.v(TAG, "Setting TCP values: [" + bufferSizes
+ + "] which comes from [" + key + "]");
+ }
+ setBufferSize(bufferSizes);
+ }
+ }
+
+ /**
+ * Writes TCP buffer sizes to /sys/kernel/ipv4/tcp_[r/w]mem_[min/def/max]
+ * which maps to /proc/sys/net/ipv4/tcp_rmem and tcpwmem
+ *
+ * @param bufferSizes in the format of "readMin, readInitial, readMax,
+ * writeMin, writeInitial, writeMax"
+ */
+ private void setBufferSize(String bufferSizes) {
+ try {
+ String[] values = bufferSizes.split(",");
+
+ if (values.length == 6) {
+ final String prefix = "/sys/kernel/ipv4/tcp_";
+ stringToFile(prefix + "rmem_min", values[0]);
+ stringToFile(prefix + "rmem_def", values[1]);
+ stringToFile(prefix + "rmem_max", values[2]);
+ stringToFile(prefix + "wmem_min", values[3]);
+ stringToFile(prefix + "wmem_def", values[4]);
+ stringToFile(prefix + "wmem_max", values[5]);
} else {
- mNetTrackers[netType].removePrivateDnsRoutes();
+ Slog.e(TAG, "Invalid buffersize string: " + bufferSizes);
}
+ } catch (IOException e) {
+ Slog.e(TAG, "Can't set tcp buffer sizes:" + e);
}
}
+ /**
+ * Writes string to file. Basically same as "echo -n $string > $filename"
+ *
+ * @param filename
+ * @param string
+ * @throws IOException
+ */
+ private void stringToFile(String filename, String string) throws IOException {
+ FileWriter out = new FileWriter(filename);
+ try {
+ out.write(string);
+ } finally {
+ out.close();
+ }
+ }
+
+
/**
* Adjust the per-process dns entries (net.dns<x>.<pid>) based
* on the highest priority active net which this process requested.
@@ -1209,12 +1388,14 @@ public class ConnectivityService extends IConnectivityManager.Stub {
NetworkStateTracker nt = mNetTrackers[i];
if (nt.getNetworkInfo().isConnected() &&
!nt.isTeardownRequested()) {
+ NetworkProperties p = nt.getNetworkProperties();
+ if (p == null) continue;
List pids = mNetRequestersPids[i];
for (int j=0; j<pids.size(); j++) {
Integer pid = (Integer)pids.get(j);
if (pid.intValue() == myPid) {
- String[] dnsList = nt.getNameServers();
- writePidDns(dnsList, myPid);
+ Collection<InetAddress> dnses = p.getDnses();
+ writePidDns(dnses, myPid);
if (doBump) {
bumpDns();
}
@@ -1236,12 +1417,10 @@ public class ConnectivityService extends IConnectivityManager.Stub {
}
}
- private void writePidDns(String[] dnsList, int pid) {
+ private void writePidDns(Collection <InetAddress> dnses, int pid) {
int j = 1;
- for (String dns : dnsList) {
- if (dns != null && !TextUtils.equals(dns, "0.0.0.0")) {
- SystemProperties.set("net.dns" + j++ + "." + pid, dns);
- }
+ for (InetAddress dns : dnses) {
+ SystemProperties.set("net.dns" + j++ + "." + pid, dns.getHostAddress());
}
}
@@ -1264,17 +1443,17 @@ public class ConnectivityService extends IConnectivityManager.Stub {
// add default net's dns entries
NetworkStateTracker nt = mNetTrackers[netType];
if (nt != null && nt.getNetworkInfo().isConnected() && !nt.isTeardownRequested()) {
- String[] dnsList = nt.getNameServers();
+ NetworkProperties p = nt.getNetworkProperties();
+ if (p == null) return;
+ Collection<InetAddress> dnses = p.getDnses();
if (mNetAttributes[netType].isDefault()) {
int j = 1;
- for (String dns : dnsList) {
- if (dns != null && !TextUtils.equals(dns, "0.0.0.0")) {
- if (DBG) {
- Slog.d(TAG, "adding dns " + dns + " for " +
- nt.getNetworkInfo().getTypeName());
- }
- SystemProperties.set("net.dns" + j++, dns);
+ for (InetAddress dns : dnses) {
+ if (DBG) {
+ Slog.d(TAG, "adding dns " + dns + " for " +
+ nt.getNetworkInfo().getTypeName());
}
+ SystemProperties.set("net.dns" + j++, dns.getHostAddress());
}
for (int k=j ; k<mNumDnsEntries; k++) {
if (DBG) Slog.d(TAG, "erasing net.dns" + k);
@@ -1286,11 +1465,11 @@ public class ConnectivityService extends IConnectivityManager.Stub {
List pids = mNetRequestersPids[netType];
for (int y=0; y< pids.size(); y++) {
Integer pid = (Integer)pids.get(y);
- writePidDns(dnsList, pid.intValue());
+ writePidDns(dnses, pid.intValue());
}
}
+ bumpDns();
}
- bumpDns();
}
private int getRestoreDefaultNetworkDelay() {
@@ -1345,6 +1524,13 @@ public class ConnectivityService extends IConnectivityManager.Stub {
}
pw.println();
+ synchronized (this) {
+ pw.println("NetworkTranstionWakeLock is currently " +
+ (mNetTransitionWakeLock.isHeld() ? "" : "not ") + "held.");
+ pw.println("It was last requested for "+mNetTransitionWakeLockCausedBy);
+ }
+ pw.println();
+
mTethering.dump(fd, pw, args);
}
@@ -1411,34 +1597,30 @@ public class ConnectivityService extends IConnectivityManager.Stub {
handleConnect(info);
}
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);
- break;
-
case NetworkStateTracker.EVENT_CONFIGURATION_CHANGED:
+ // TODO - make this handle ip/proxy/gateway/dns changes
info = (NetworkInfo) msg.obj;
type = info.getType();
handleDnsConfigurationChange(type);
break;
-
- case NetworkStateTracker.EVENT_ROAMING_CHANGED:
- // fill me in
- break;
-
- case NetworkStateTracker.EVENT_NETWORK_SUBTYPE_CHANGED:
- // fill me in
- break;
case NetworkStateTracker.EVENT_RESTORE_DEFAULT_NETWORK:
FeatureUser u = (FeatureUser)msg.obj;
u.expire();
break;
+ case NetworkStateTracker.EVENT_CLEAR_NET_TRANSITION_WAKELOCK:
+ String causedBy = null;
+ synchronized (ConnectivityService.this) {
+ if (msg.arg1 == mNetTransitionWakeLockSerialNumber &&
+ mNetTransitionWakeLock.isHeld()) {
+ mNetTransitionWakeLock.release();
+ causedBy = mNetTransitionWakeLockCausedBy;
+ }
+ }
+ if (causedBy != null) {
+ Slog.d(TAG, "NetTransition Wakelock for " +
+ causedBy + " released by timeout");
+ }
+ break;
}
}
}
@@ -1495,6 +1677,15 @@ public class ConnectivityService extends IConnectivityManager.Stub {
}
}
+ public String[] getTetherableBluetoothRegexs() {
+ enforceTetherAccessPermission();
+ if (isTetheringSupported()) {
+ return mTethering.getTetherableBluetoothRegexs();
+ } else {
+ return new String[0];
+ }
+ }
+
// TODO - move iface listing, queries, etc to new module
// javadoc from interface
public String[] getTetherableIfaces() {
@@ -1522,4 +1713,23 @@ public class ConnectivityService extends IConnectivityManager.Stub {
Settings.Secure.TETHER_SUPPORTED, defaultVal) != 0);
return tetherEnabledInSettings && mTetheringConfigValid;
}
+
+ // An API NetworkStateTrackers can call when they lose their network.
+ // This will automatically be cleared after X seconds or a network becomes CONNECTED,
+ // whichever happens first. The timer is started by the first caller and not
+ // restarted by subsequent callers.
+ public void requestNetworkTransitionWakelock(String forWhom) {
+ enforceConnectivityInternalPermission();
+ synchronized (this) {
+ if (mNetTransitionWakeLock.isHeld()) return;
+ mNetTransitionWakeLockSerialNumber++;
+ mNetTransitionWakeLock.acquire();
+ mNetTransitionWakeLockCausedBy = forWhom;
+ }
+ mHandler.sendMessageDelayed(mHandler.obtainMessage(
+ NetworkStateTracker.EVENT_CLEAR_NET_TRANSITION_WAKELOCK,
+ mNetTransitionWakeLockSerialNumber, 0),
+ mNetTransitionWakeLockTimeout);
+ return;
+ }
}