Merge "Add unit test for NetworkStatsSubscriptionsMonitor"
diff --git a/core/java/android/net/ConnectivityDiagnosticsManager.java b/core/java/android/net/ConnectivityDiagnosticsManager.java
index 275e38c..704f31d 100644
--- a/core/java/android/net/ConnectivityDiagnosticsManager.java
+++ b/core/java/android/net/ConnectivityDiagnosticsManager.java
@@ -711,6 +711,13 @@
* not currently registered. If a ConnectivityDiagnosticsCallback instance is registered with
* multiple NetworkRequests, an IllegalArgumentException will be thrown.
*
+ * <p>To avoid performance issues due to apps leaking callbacks, the system will limit the
+ * number of outstanding requests to 100 per app (identified by their UID), shared with
+ * callbacks in {@link ConnectivityManager}. Registering a callback with this method will count
+ * toward this limit. If this limit is exceeded, an exception will be thrown. To avoid hitting
+ * this issue and to conserve resources, make sure to unregister the callbacks with
+ * {@link #unregisterConnectivityDiagnosticsCallback}.
+ *
* @param request The NetworkRequest that will be used to match with Networks for which
* callbacks will be fired
* @param e The Executor to be used for running the callback method invocations
@@ -718,6 +725,7 @@
* System
* @throws IllegalArgumentException if the same callback instance is registered with multiple
* NetworkRequests
+ * @throws RuntimeException if the app already has too many callbacks registered.
*/
public void registerConnectivityDiagnosticsCallback(
@NonNull NetworkRequest request,
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index 6b71360..9c994eb 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -2271,27 +2271,6 @@
throwException);
}
- /** {@hide} */
- public static final void enforceTetherChangePermission(Context context, String callingPkg,
- String callingAttributionTag) {
- Preconditions.checkNotNull(context, "Context cannot be null");
- Preconditions.checkNotNull(callingPkg, "callingPkg cannot be null");
-
- if (context.getResources().getStringArray(
- com.android.internal.R.array.config_mobile_hotspot_provision_app).length == 2) {
- // Have a provisioning app - must only let system apps (which check this app)
- // turn on tethering
- context.enforceCallingOrSelfPermission(
- android.Manifest.permission.TETHER_PRIVILEGED, "ConnectivityService");
- } else {
- int uid = Binder.getCallingUid();
- // If callingPkg's uid is not same as Binder.getCallingUid(),
- // AppOpsService throws SecurityException.
- checkAndNoteWriteSettingsOperation(context, uid, callingPkg,
- callingAttributionTag, true /* throwException */);
- }
- }
-
/**
* Check if the package is a allowed to write settings. This also accounts that such an access
* happened.
@@ -3855,13 +3834,22 @@
* or the ability to modify system settings as determined by
* {@link android.provider.Settings.System#canWrite}.</p>
*
+ * <p>To avoid performance issues due to apps leaking callbacks, the system will limit the
+ * number of outstanding requests to 100 per app (identified by their UID), shared with
+ * all variants of this method, of {@link #registerNetworkCallback} as well as
+ * {@link ConnectivityDiagnosticsManager#registerConnectivityDiagnosticsCallback}.
+ * Requesting a network with this method will count toward this limit. If this limit is
+ * exceeded, an exception will be thrown. To avoid hitting this issue and to conserve resources,
+ * make sure to unregister the callbacks with
+ * {@link #unregisterNetworkCallback(NetworkCallback)}.
+ *
* @param request {@link NetworkRequest} describing this request.
* @param networkCallback The {@link NetworkCallback} to be utilized for this request. Note
* the callback must not be shared - it uniquely specifies this request.
* The callback is invoked on the default internal Handler.
* @throws IllegalArgumentException if {@code request} contains invalid network capabilities.
* @throws SecurityException if missing the appropriate permissions.
- * @throws RuntimeException if request limit per UID is exceeded.
+ * @throws RuntimeException if the app already has too many callbacks registered.
*/
public void requestNetwork(@NonNull NetworkRequest request,
@NonNull NetworkCallback networkCallback) {
@@ -3875,8 +3863,8 @@
* but runs all the callbacks on the passed Handler.
*
* <p>This method has the same permission requirements as
- * {@link #requestNetwork(NetworkRequest, NetworkCallback)} and throws the same exceptions in
- * the same conditions.
+ * {@link #requestNetwork(NetworkRequest, NetworkCallback)}, is subject to the same limitations,
+ * and throws the same exceptions in the same conditions.
*
* @param request {@link NetworkRequest} describing this request.
* @param networkCallback The {@link NetworkCallback} to be utilized for this request. Note
@@ -3907,8 +3895,8 @@
* for that purpose. Calling this method will attempt to bring up the requested network.
*
* <p>This method has the same permission requirements as
- * {@link #requestNetwork(NetworkRequest, NetworkCallback)} and throws the same exceptions in
- * the same conditions.
+ * {@link #requestNetwork(NetworkRequest, NetworkCallback)}, is subject to the same limitations,
+ * and throws the same exceptions in the same conditions.
*
* @param request {@link NetworkRequest} describing this request.
* @param networkCallback The {@link NetworkCallback} to be utilized for this request. Note
@@ -3934,8 +3922,8 @@
* on the passed Handler.
*
* <p>This method has the same permission requirements as
- * {@link #requestNetwork(NetworkRequest, NetworkCallback, int)} and throws the same exceptions
- * in the same conditions.
+ * {@link #requestNetwork(NetworkRequest, NetworkCallback)}, is subject to the same limitations,
+ * and throws the same exceptions in the same conditions.
*
* @param request {@link NetworkRequest} describing this request.
* @param networkCallback The {@link NetworkCallback} to be utilized for this request. Note
@@ -4004,6 +3992,15 @@
* is unknown prior to bringing up the network so the framework does not
* know how to go about satisfying a request with these capabilities.
*
+ * <p>To avoid performance issues due to apps leaking callbacks, the system will limit the
+ * number of outstanding requests to 100 per app (identified by their UID), shared with
+ * all variants of this method, of {@link #registerNetworkCallback} as well as
+ * {@link ConnectivityDiagnosticsManager#registerConnectivityDiagnosticsCallback}.
+ * Requesting a network with this method will count toward this limit. If this limit is
+ * exceeded, an exception will be thrown. To avoid hitting this issue and to conserve resources,
+ * make sure to unregister the callbacks with {@link #unregisterNetworkCallback(PendingIntent)}
+ * or {@link #releaseNetworkRequest(PendingIntent)}.
+ *
* <p>This method requires the caller to hold either the
* {@link android.Manifest.permission#CHANGE_NETWORK_STATE} permission
* or the ability to modify system settings as determined by
@@ -4015,7 +4012,7 @@
* comes from {@link PendingIntent#getBroadcast}. Cannot be null.
* @throws IllegalArgumentException if {@code request} contains invalid network capabilities.
* @throws SecurityException if missing the appropriate permissions.
- * @throws RuntimeException if request limit per UID is exceeded.
+ * @throws RuntimeException if the app already has too many callbacks registered.
*/
public void requestNetwork(@NonNull NetworkRequest request,
@NonNull PendingIntent operation) {
@@ -4072,10 +4069,20 @@
* either the application exits or {@link #unregisterNetworkCallback(NetworkCallback)} is
* called.
*
+ * <p>To avoid performance issues due to apps leaking callbacks, the system will limit the
+ * number of outstanding requests to 100 per app (identified by their UID), shared with
+ * all variants of this method, of {@link #requestNetwork} as well as
+ * {@link ConnectivityDiagnosticsManager#registerConnectivityDiagnosticsCallback}.
+ * Requesting a network with this method will count toward this limit. If this limit is
+ * exceeded, an exception will be thrown. To avoid hitting this issue and to conserve resources,
+ * make sure to unregister the callbacks with
+ * {@link #unregisterNetworkCallback(NetworkCallback)}.
+ *
* @param request {@link NetworkRequest} describing this request.
* @param networkCallback The {@link NetworkCallback} that the system will call as suitable
* networks change state.
* The callback is invoked on the default internal Handler.
+ * @throws RuntimeException if the app already has too many callbacks registered.
*/
@RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE)
public void registerNetworkCallback(@NonNull NetworkRequest request,
@@ -4089,10 +4096,21 @@
* either the application exits or {@link #unregisterNetworkCallback(NetworkCallback)} is
* called.
*
+ * <p>To avoid performance issues due to apps leaking callbacks, the system will limit the
+ * number of outstanding requests to 100 per app (identified by their UID), shared with
+ * all variants of this method, of {@link #requestNetwork} as well as
+ * {@link ConnectivityDiagnosticsManager#registerConnectivityDiagnosticsCallback}.
+ * Requesting a network with this method will count toward this limit. If this limit is
+ * exceeded, an exception will be thrown. To avoid hitting this issue and to conserve resources,
+ * make sure to unregister the callbacks with
+ * {@link #unregisterNetworkCallback(NetworkCallback)}.
+ *
+ *
* @param request {@link NetworkRequest} describing this request.
* @param networkCallback The {@link NetworkCallback} that the system will call as suitable
* networks change state.
* @param handler {@link Handler} to specify the thread upon which the callback will be invoked.
+ * @throws RuntimeException if the app already has too many callbacks registered.
*/
@RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE)
public void registerNetworkCallback(@NonNull NetworkRequest request,
@@ -4126,10 +4144,21 @@
* <p>
* The request may be released normally by calling
* {@link #unregisterNetworkCallback(android.app.PendingIntent)}.
+ *
+ * <p>To avoid performance issues due to apps leaking callbacks, the system will limit the
+ * number of outstanding requests to 100 per app (identified by their UID), shared with
+ * all variants of this method, of {@link #requestNetwork} as well as
+ * {@link ConnectivityDiagnosticsManager#registerConnectivityDiagnosticsCallback}.
+ * Requesting a network with this method will count toward this limit. If this limit is
+ * exceeded, an exception will be thrown. To avoid hitting this issue and to conserve resources,
+ * make sure to unregister the callbacks with {@link #unregisterNetworkCallback(PendingIntent)}
+ * or {@link #releaseNetworkRequest(PendingIntent)}.
+ *
* @param request {@link NetworkRequest} describing this request.
* @param operation Action to perform when the network is available (corresponds
* to the {@link NetworkCallback#onAvailable} call. Typically
* comes from {@link PendingIntent#getBroadcast}. Cannot be null.
+ * @throws RuntimeException if the app already has too many callbacks registered.
*/
@RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE)
public void registerNetworkCallback(@NonNull NetworkRequest request,
@@ -4151,9 +4180,19 @@
* will continue to be called until either the application exits or
* {@link #unregisterNetworkCallback(NetworkCallback)} is called.
*
+ * <p>To avoid performance issues due to apps leaking callbacks, the system will limit the
+ * number of outstanding requests to 100 per app (identified by their UID), shared with
+ * all variants of this method, of {@link #requestNetwork} as well as
+ * {@link ConnectivityDiagnosticsManager#registerConnectivityDiagnosticsCallback}.
+ * Requesting a network with this method will count toward this limit. If this limit is
+ * exceeded, an exception will be thrown. To avoid hitting this issue and to conserve resources,
+ * make sure to unregister the callbacks with
+ * {@link #unregisterNetworkCallback(NetworkCallback)}.
+ *
* @param networkCallback The {@link NetworkCallback} that the system will call as the
* system default network changes.
* The callback is invoked on the default internal Handler.
+ * @throws RuntimeException if the app already has too many callbacks registered.
*/
@RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE)
public void registerDefaultNetworkCallback(@NonNull NetworkCallback networkCallback) {
@@ -4165,9 +4204,19 @@
* will continue to be called until either the application exits or
* {@link #unregisterNetworkCallback(NetworkCallback)} is called.
*
+ * <p>To avoid performance issues due to apps leaking callbacks, the system will limit the
+ * number of outstanding requests to 100 per app (identified by their UID), shared with
+ * all variants of this method, of {@link #requestNetwork} as well as
+ * {@link ConnectivityDiagnosticsManager#registerConnectivityDiagnosticsCallback}.
+ * Requesting a network with this method will count toward this limit. If this limit is
+ * exceeded, an exception will be thrown. To avoid hitting this issue and to conserve resources,
+ * make sure to unregister the callbacks with
+ * {@link #unregisterNetworkCallback(NetworkCallback)}.
+ *
* @param networkCallback The {@link NetworkCallback} that the system will call as the
* system default network changes.
* @param handler {@link Handler} to specify the thread upon which the callback will be invoked.
+ * @throws RuntimeException if the app already has too many callbacks registered.
*/
@RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE)
public void registerDefaultNetworkCallback(@NonNull NetworkCallback networkCallback,
@@ -4259,7 +4308,6 @@
* Cannot be null.
*/
public void unregisterNetworkCallback(@NonNull PendingIntent operation) {
- checkPendingIntentNotNull(operation);
releaseNetworkRequest(operation);
}
diff --git a/core/java/android/net/NetworkCapabilities.java b/core/java/android/net/NetworkCapabilities.java
index 0fbffba..ec87091 100644
--- a/core/java/android/net/NetworkCapabilities.java
+++ b/core/java/android/net/NetworkCapabilities.java
@@ -900,9 +900,17 @@
* <p>For NetworkCapability instances being sent from ConnectivityService, this value MUST be
* reset to Process.INVALID_UID unless all the following conditions are met:
*
+ * <p>The caller is the network owner, AND one of the following sets of requirements is met:
+ *
* <ol>
- * <li>The destination app is the network owner
- * <li>The destination app has the ACCESS_FINE_LOCATION permission granted
+ * <li>The described Network is a VPN
+ * </ol>
+ *
+ * <p>OR:
+ *
+ * <ol>
+ * <li>The calling app is the network owner
+ * <li>The calling app has the ACCESS_FINE_LOCATION permission granted
* <li>The user's location toggle is on
* </ol>
*
@@ -928,7 +936,16 @@
/**
* Retrieves the UID of the app that owns this network.
*
- * <p>For user privacy reasons, this field will only be populated if:
+ * <p>For user privacy reasons, this field will only be populated if the following conditions
+ * are met:
+ *
+ * <p>The caller is the network owner, AND one of the following sets of requirements is met:
+ *
+ * <ol>
+ * <li>The described Network is a VPN
+ * </ol>
+ *
+ * <p>OR:
*
* <ol>
* <li>The calling app is the network owner
@@ -936,8 +953,8 @@
* <li>The user's location toggle is on
* </ol>
*
- * Instances of NetworkCapabilities sent to apps without the appropriate permissions will
- * have this field cleared out.
+ * Instances of NetworkCapabilities sent to apps without the appropriate permissions will have
+ * this field cleared out.
*/
public int getOwnerUid() {
return mOwnerUid;
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 483d4b6..320f3fb 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -1698,6 +1698,12 @@
return newNc;
}
+ // Allow VPNs to see ownership of their own VPN networks - not location sensitive.
+ if (nc.hasTransport(TRANSPORT_VPN)) {
+ // Owner UIDs already checked above. No need to re-check.
+ return newNc;
+ }
+
Binder.withCleanCallingIdentity(
() -> {
if (!mLocationPermissionChecker.checkLocationPermission(
@@ -6422,7 +6428,7 @@
final boolean shouldFilter = requiresVpnIsolation(nai, newNc, nai.linkProperties);
final String iface = nai.linkProperties.getInterfaceName();
// For VPN uid interface filtering, old ranges need to be removed before new ranges can
- // be added, due to the range being expanded and stored as invidiual UIDs. For example
+ // be added, due to the range being expanded and stored as individual UIDs. For example
// the UIDs might be updated from [0, 99999] to ([0, 10012], [10014, 99999]) which means
// prevRanges = [0, 99999] while newRanges = [0, 10012], [10014, 99999]. If prevRanges
// were added first and then newRanges got removed later, there would be only one uid
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index ea4982e..bc85374 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -100,6 +100,7 @@
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.ArgumentMatchers.isNull;
import static org.mockito.ArgumentMatchers.startsWith;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Mockito.any;
@@ -164,6 +165,8 @@
import android.net.LinkProperties;
import android.net.MatchAllNetworkSpecifier;
import android.net.Network;
+import android.net.NetworkAgent;
+import android.net.NetworkAgentConfig;
import android.net.NetworkCapabilities;
import android.net.NetworkFactory;
import android.net.NetworkInfo;
@@ -6808,6 +6811,30 @@
assertEquals(wifiLp, mService.getActiveLinkProperties());
}
+ @Test
+ public void testLegacyExtraInfoSentToNetworkMonitor() throws Exception {
+ class TestNetworkAgent extends NetworkAgent {
+ TestNetworkAgent(Context context, Looper looper, NetworkAgentConfig config) {
+ super(context, looper, "MockAgent", new NetworkCapabilities(),
+ new LinkProperties(), 40 , config, null /* provider */);
+ }
+ }
+ final NetworkAgent naNoExtraInfo = new TestNetworkAgent(
+ mServiceContext, mCsHandlerThread.getLooper(), new NetworkAgentConfig());
+ naNoExtraInfo.register();
+ verify(mNetworkStack).makeNetworkMonitor(any(), isNull(String.class), any());
+ naNoExtraInfo.unregister();
+
+ reset(mNetworkStack);
+ final NetworkAgentConfig config =
+ new NetworkAgentConfig.Builder().setLegacyExtraInfo("legacyinfo").build();
+ final NetworkAgent naExtraInfo = new TestNetworkAgent(
+ mServiceContext, mCsHandlerThread.getLooper(), config);
+ naExtraInfo.register();
+ verify(mNetworkStack).makeNetworkMonitor(any(), eq("legacyinfo"), any());
+ naExtraInfo.unregister();
+ }
+
private void setupLocationPermissions(
int targetSdk, boolean locationToggle, String op, String perm) throws Exception {
final ApplicationInfo applicationInfo = new ApplicationInfo();