summaryrefslogtreecommitdiffstats
path: root/wifi
diff options
context:
space:
mode:
authorLorenzo Colitti <lorenzo@google.com>2015-04-08 23:52:39 +0900
committerLorenzo Colitti <lorenzo@google.com>2015-04-17 00:26:46 +0900
commit1022dde719ca430f062f9e628574d70ae1320677 (patch)
treeeb5f48be73b55539c94f41f782f4bfcd6f959866 /wifi
parentbdc4549dcd2b0ebbdc87a3e8d6eb47f54cc58ce6 (diff)
downloadframeworks_base-1022dde719ca430f062f9e628574d70ae1320677.zip
frameworks_base-1022dde719ca430f062f9e628574d70ae1320677.tar.gz
frameworks_base-1022dde719ca430f062f9e628574d70ae1320677.tar.bz2
Pin a process to wifi when it calls enableNetwork(..., true)
Bug: 20081183 Change-Id: I12bbda1061bbebeb4d0844d0b0d7f51237645958
Diffstat (limited to 'wifi')
-rw-r--r--wifi/java/android/net/wifi/WifiManager.java131
1 files changed, 129 insertions, 2 deletions
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index 4e4f9b2..18f90d8 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -20,10 +20,16 @@ import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
import android.annotation.SystemApi;
import android.content.Context;
+import android.net.ConnectivityManager;
+import android.net.ConnectivityManager.NetworkCallback;
import android.net.DhcpInfo;
+import android.net.Network;
+import android.net.NetworkCapabilities;
+import android.net.NetworkRequest;
import android.net.wifi.ScanSettings;
import android.net.wifi.WifiChannel;
import android.os.Binder;
+import android.os.Build;
import android.os.IBinder;
import android.os.Handler;
import android.os.HandlerThread;
@@ -38,6 +44,7 @@ import android.util.SparseArray;
import java.net.InetAddress;
import java.util.concurrent.CountDownLatch;
+import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.AsyncChannel;
import com.android.internal.util.Protocol;
@@ -568,6 +575,7 @@ public class WifiManager {
private Context mContext;
IWifiManager mService;
+ private final int mTargetSdkVersion;
private static final int INVALID_KEY = 0;
private static int sListenerKey = 1;
@@ -576,11 +584,17 @@ public class WifiManager {
private static AsyncChannel sAsyncChannel;
private static CountDownLatch sConnected;
+ private static ConnectivityManager sCM;
private static final Object sThreadRefLock = new Object();
private static int sThreadRefCount;
private static HandlerThread sHandlerThread;
+ @GuardedBy("sCM")
+ // TODO: Introduce refcounting and make this a per-process static callback, instead of a
+ // per-WifiManager callback.
+ private PinningNetworkCallback mNetworkCallback;
+
/**
* Create a new WifiManager instance.
* Applications will almost always want to use
@@ -594,6 +608,7 @@ public class WifiManager {
public WifiManager(Context context, IWifiManager service) {
mContext = context;
mService = service;
+ mTargetSdkVersion = context.getApplicationInfo().targetSdkVersion;
init();
}
@@ -740,6 +755,20 @@ public class WifiManager {
* networks are disabled, and an attempt to connect to the selected
* network is initiated. This may result in the asynchronous delivery
* of state change events.
+ * <p>
+ * <b>Note:</b> If an application's target SDK version is
+ * {@link android.os.Build.VERSION_CODES#MNC} or newer, network
+ * communication may not use Wi-Fi even if Wi-Fi is connected; traffic may
+ * instead be sent through another network, such as cellular data,
+ * Bluetooth tethering, or Ethernet. For example, traffic will never use a
+ * Wi-Fi network that does not provide Internet access (e.g. a wireless
+ * printer), if another network that does offer Internet access (e.g.
+ * cellular data) is available. Applications that need to ensure that their
+ * network traffic uses Wi-Fi should use APIs such as
+ * {@link Network#bindSocket(java.net.Socket)},
+ * {@link Network#openConnection(java.net.URL)}, or
+ * {@link ConnectivityManager#bindProcessToNetwork} to do so.
+ *
* @param netId the ID of the network in the list of configured networks
* @param disableOthers if true, disable all other networks. The way to
* select a particular network to connect to is specify {@code true}
@@ -747,11 +776,23 @@ public class WifiManager {
* @return {@code true} if the operation succeeded
*/
public boolean enableNetwork(int netId, boolean disableOthers) {
+ final boolean pin = disableOthers && mTargetSdkVersion < Build.VERSION_CODES.MNC;
+ if (pin) {
+ registerPinningNetworkCallback();
+ }
+
+ boolean success;
try {
- return mService.enableNetwork(netId, disableOthers);
+ success = mService.enableNetwork(netId, disableOthers);
} catch (RemoteException e) {
- return false;
+ success = false;
+ }
+
+ if (pin && !success) {
+ unregisterPinningNetworkCallback();
}
+
+ return success;
}
/**
@@ -1951,6 +1992,92 @@ public class WifiManager {
"No permission to access and change wifi or a bad initialization");
}
+ private void initConnectivityManager() {
+ // TODO: what happens if an app calls a WifiManager API before ConnectivityManager is
+ // registered? Can we fix this by starting ConnectivityService before WifiService?
+ if (sCM == null) {
+ sCM = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
+ if (sCM == null) {
+ throw new IllegalStateException("Bad luck, ConnectivityService not started.");
+ }
+ }
+ }
+
+ /**
+ * A NetworkCallback that pins the process to the first wifi network to connect.
+ *
+ * We use this to maintain compatibility with pre-M apps that call WifiManager.enableNetwork()
+ * to connect to a Wi-Fi network that has no Internet access, and then assume that they will be
+ * able to use that network because it's the system default.
+ *
+ * In order to maintain compatibility with apps that call setProcessDefaultNetwork themselves,
+ * we try not to set the default network unless they have already done so, and we try not to
+ * clear the default network unless we set it ourselves.
+ *
+ * This should maintain behaviour that's compatible with L, which would pin the whole system to
+ * any wifi network that was created via enableNetwork(..., true) until that network
+ * disconnected.
+ *
+ * Note that while this hack allows network traffic to flow, it is quite limited. For example:
+ *
+ * 1. setProcessDefaultNetwork only affects this process, so:
+ * - Any subprocesses spawned by this process will not be pinned to Wi-Fi.
+ * - If this app relies on any other apps on the device also being on Wi-Fi, that won't work
+ * either, because other apps on the device will not be pinned.
+ * 2. The behaviour of other APIs is not modified. For example:
+ * - getActiveNetworkInfo will return the system default network, not Wi-Fi.
+ * - There will be no CONNECTIVITY_ACTION broadcasts about TYPE_WIFI.
+ * - getProcessDefaultNetwork will not return null, so if any apps are relying on that, they
+ * will be surprised as well.
+ */
+ private class PinningNetworkCallback extends NetworkCallback {
+ private Network mPinnedNetwork;
+
+ @Override
+ public void onPreCheck(Network network) {
+ if (sCM.getProcessDefaultNetwork() == null && mPinnedNetwork == null) {
+ sCM.setProcessDefaultNetwork(network);
+ mPinnedNetwork = network;
+ Log.d(TAG, "Wifi alternate reality enabled on network " + network);
+ }
+ }
+
+ @Override
+ public void onLost(Network network) {
+ if (network.equals(mPinnedNetwork) && network.equals(sCM.getProcessDefaultNetwork())) {
+ sCM.setProcessDefaultNetwork(null);
+ Log.d(TAG, "Wifi alternate reality disabled on network " + network);
+ mPinnedNetwork = null;
+ unregisterPinningNetworkCallback();
+ }
+ }
+ }
+
+ private void registerPinningNetworkCallback() {
+ initConnectivityManager();
+ synchronized (sCM) {
+ if (mNetworkCallback == null) {
+ // TODO: clear all capabilities.
+ NetworkRequest request = new NetworkRequest.Builder()
+ .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
+ .removeCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
+ .build();
+ mNetworkCallback = new PinningNetworkCallback();
+ sCM.registerNetworkCallback(request, mNetworkCallback);
+ }
+ }
+ }
+
+ private void unregisterPinningNetworkCallback() {
+ initConnectivityManager();
+ synchronized (sCM) {
+ if (mNetworkCallback != null) {
+ sCM.unregisterNetworkCallback(mNetworkCallback);
+ mNetworkCallback = null;
+ }
+ }
+ }
+
/**
* Connect to a network with the given configuration. The network also
* gets added to the supplicant configuration.