From 9786d92050dac1e0ffcfdf93bab7eb08592d90e2 Mon Sep 17 00:00:00 2001 From: Etan Cohen Date: Wed, 18 Nov 2015 10:56:15 -0800 Subject: [PATCH] Allow NetworkFactories to match any network specifier on a request Current usage of NetworkSpecifier: network factory will match a request if the request has either a (1) empty network specifier, or (2) a network specifier which is identical to that of the network factory. Note: 'matching' w.r.t. network specifier - all other matching rules are still in effect. Change: add rule (3) or the network specifier of the network factory is the special string (which is defined as "*" and which user-facing network requests aren't allowed to use). Rationale: allows on-demand network creation. Example: - Can specify a Wi-Fi NetworkRequest with NetworkSpecifier="ssid" - It will match a Wi-Fi network factory specifying NetworkSpecifier="*" - That network factory will bring up a Wi-Fi network, connecting to the specified SSID. - Once the network is created it will create a NetworkAgent which will now have a NetworkSpecifier matching that of the request (not the match-all special string!) That final step of making sure that the NetworkAgent matches the request and not the match-all is critical to delivering any subsequent callbacks correctly. I.e. your network will only get callbacks which match it. Bug: 26192833 Change-Id: I49e3b492e0bb48a3f6e9a34e3f94f0e1cf89741f --- .../java/android/net/NetworkCapabilities.java | 16 ++++++++- core/java/android/net/NetworkRequest.java | 4 +++ .../android/server/ConnectivityService.java | 6 ++++ .../server/ConnectivityServiceTest.java | 33 +++++++++++++++++++ 4 files changed, 58 insertions(+), 1 deletion(-) diff --git a/core/java/android/net/NetworkCapabilities.java b/core/java/android/net/NetworkCapabilities.java index 3bd12c0607..e27c0fb2dd 100644 --- a/core/java/android/net/NetworkCapabilities.java +++ b/core/java/android/net/NetworkCapabilities.java @@ -196,6 +196,19 @@ public final class NetworkCapabilities implements Parcelable { (1 << NET_CAPABILITY_VALIDATED) | (1 << NET_CAPABILITY_CAPTIVE_PORTAL); + /** + * Network specifier for factories which want to match any network specifier + * (NS) in a request. Behavior: + *
  • Empty NS in request matches any network factory NS
  • + *
  • Empty NS in the network factory NS only matches a request with an + * empty NS
  • + *
  • "*" (this constant) NS in the network factory matches requests with + * any NS
  • + * + * @hide + */ + public static final String MATCH_ALL_REQUESTS_NETWORK_SPECIFIER = "*"; + /** * Network capabilities that are not allowed in NetworkRequests. This exists because the * NetworkFactory / NetworkAgent model does not deal well with the situation where a @@ -596,7 +609,8 @@ public final class NetworkCapabilities implements Parcelable { } private boolean satisfiedBySpecifier(NetworkCapabilities nc) { return (TextUtils.isEmpty(mNetworkSpecifier) || - mNetworkSpecifier.equals(nc.mNetworkSpecifier)); + mNetworkSpecifier.equals(nc.mNetworkSpecifier) || + MATCH_ALL_REQUESTS_NETWORK_SPECIFIER.equals(nc.mNetworkSpecifier)); } private boolean equalsSpecifier(NetworkCapabilities nc) { if (TextUtils.isEmpty(mNetworkSpecifier)) { diff --git a/core/java/android/net/NetworkRequest.java b/core/java/android/net/NetworkRequest.java index 7da4818991..f1edcbe30d 100644 --- a/core/java/android/net/NetworkRequest.java +++ b/core/java/android/net/NetworkRequest.java @@ -188,6 +188,10 @@ public class NetworkRequest implements Parcelable { * networks. */ public Builder setNetworkSpecifier(String networkSpecifier) { + if (NetworkCapabilities.MATCH_ALL_REQUESTS_NETWORK_SPECIFIER.equals(networkSpecifier)) { + throw new IllegalArgumentException("Invalid network specifier - must not be '" + + NetworkCapabilities.MATCH_ALL_REQUESTS_NETWORK_SPECIFIER + "'"); + } mNetworkCapabilities.setNetworkSpecifier(networkSpecifier); return this; } diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index 327fb8a7ef..9c09f246c1 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -3678,6 +3678,12 @@ public class ConnectivityService extends IConnectivityManager.Stub throw new IllegalArgumentException("Bad timeout specified"); } + if (NetworkCapabilities.MATCH_ALL_REQUESTS_NETWORK_SPECIFIER + .equals(networkCapabilities.getNetworkSpecifier())) { + throw new IllegalArgumentException("Invalid network specifier - must not be '" + + NetworkCapabilities.MATCH_ALL_REQUESTS_NETWORK_SPECIFIER + "'"); + } + NetworkRequest networkRequest = new NetworkRequest(networkCapabilities, legacyType, nextNetworkRequestId()); NetworkRequestInfo nri = new NetworkRequestInfo(messenger, networkRequest, binder, diff --git a/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java b/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java index 97e16da427..d096c28aa0 100644 --- a/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java @@ -52,13 +52,16 @@ import android.net.RouteInfo; import android.os.ConditionVariable; import android.os.Handler; import android.os.HandlerThread; +import android.os.IBinder; import android.os.INetworkManagementService; import android.os.Looper; import android.os.Message; import android.os.MessageQueue; +import android.os.Messenger; import android.os.MessageQueue.IdleHandler; import android.test.AndroidTestCase; import android.test.suitebuilder.annotation.LargeTest; +import android.test.suitebuilder.annotation.SmallTest; import android.util.Log; import android.util.LogPrinter; @@ -1291,6 +1294,36 @@ public class ConnectivityServiceTest extends AndroidTestCase { validatedCallback.expectCallback(CallbackState.LOST); } + @SmallTest + public void testInvalidNetworkSpecifier() { + boolean execptionCalled = true; + + try { + NetworkRequest.Builder builder = new NetworkRequest.Builder(); + builder.setNetworkSpecifier(MATCH_ALL_REQUESTS_NETWORK_SPECIFIER); + execptionCalled = false; + } catch (IllegalArgumentException e) { + // do nothing - should get here + } + + assertTrue("NetworkReqeuest builder with MATCH_ALL_REQUESTS_NETWORK_SPECIFIER", + execptionCalled); + + try { + NetworkCapabilities networkCapabilities = new NetworkCapabilities(); + networkCapabilities.addTransportType(TRANSPORT_WIFI) + .setNetworkSpecifier(NetworkCapabilities.MATCH_ALL_REQUESTS_NETWORK_SPECIFIER); + mService.requestNetwork(networkCapabilities, null, 0, null, + ConnectivityManager.TYPE_WIFI); + execptionCalled = false; + } catch (IllegalArgumentException e) { + // do nothing - should get here + } + + assertTrue("ConnectivityService requestNetwork with MATCH_ALL_REQUESTS_NETWORK_SPECIFIER", + execptionCalled); + } + private static class TestKeepaliveCallback extends PacketKeepaliveCallback { public static enum CallbackType { ON_STARTED, ON_STOPPED, ON_ERROR };