Merge changes Ib8fe719f,Ia8c05780 into sc-dev
* changes:
Suppress IpServer message logs
Remove *Locked wording
diff --git a/Tethering/Android.bp b/Tethering/Android.bp
index f469d89..b5054cf 100644
--- a/Tethering/Android.bp
+++ b/Tethering/Android.bp
@@ -158,7 +158,5 @@
sdk {
name: "tethering-module-sdk",
- java_sdk_libs: [
- "framework-tethering",
- ],
+ bootclasspath_fragments: ["com.android.tethering-bootclasspath-fragment"],
}
diff --git a/Tethering/apex/Android.bp b/Tethering/apex/Android.bp
index dcdf693..2a9e31a 100644
--- a/Tethering/apex/Android.bp
+++ b/Tethering/apex/Android.bp
@@ -45,8 +45,12 @@
"ServiceConnectivityResources",
"Tethering",
],
+ prebuilts: ["current_sdkinfo"],
manifest: "manifest.json",
key: "com.android.tethering.key",
+ // Indicates that pre-installed version of this apex can be compressed.
+ // Whether it actually will be compressed is controlled on per-device basis.
+ compressible: true,
androidManifest: "AndroidManifest.xml",
}
diff --git a/Tethering/jni/com_android_networkstack_tethering_BpfUtils.cpp b/Tethering/jni/com_android_networkstack_tethering_BpfUtils.cpp
index 1611f9d..2fb5985 100644
--- a/Tethering/jni/com_android_networkstack_tethering_BpfUtils.cpp
+++ b/Tethering/jni/com_android_networkstack_tethering_BpfUtils.cpp
@@ -183,7 +183,7 @@
return false;
default:
jniThrowExceptionFmt(env, "java/io/IOException",
- "Unknown hardware address type %s on interface %s", rv,
+ "Unknown hardware address type %d on interface %s", rv,
interface.c_str());
return false;
}
diff --git a/Tethering/tests/mts/src/android/tethering/mts/TetheringModuleTest.java b/Tethering/tests/mts/src/android/tethering/mts/TetheringModuleTest.java
index e0fcbfa..07aab63 100644
--- a/Tethering/tests/mts/src/android/tethering/mts/TetheringModuleTest.java
+++ b/Tethering/tests/mts/src/android/tethering/mts/TetheringModuleTest.java
@@ -15,6 +15,7 @@
*/
package android.tethering.mts;
+import static android.Manifest.permission.ACCESS_WIFI_STATE;
import static android.Manifest.permission.MANAGE_TEST_NETWORKS;
import static android.Manifest.permission.NETWORK_SETTINGS;
import static android.Manifest.permission.READ_DEVICE_CONFIG;
@@ -70,7 +71,7 @@
@Before
public void setUp() throws Exception {
mUiAutomation.adoptShellPermissionIdentity(MANAGE_TEST_NETWORKS, NETWORK_SETTINGS,
- WRITE_SETTINGS, READ_DEVICE_CONFIG, TETHER_PRIVILEGED);
+ WRITE_SETTINGS, READ_DEVICE_CONFIG, TETHER_PRIVILEGED, ACCESS_WIFI_STATE);
mContext = InstrumentationRegistry.getContext();
mTm = mContext.getSystemService(TetheringManager.class);
mCtsTetheringUtils = new CtsTetheringUtils(mContext);
@@ -102,7 +103,7 @@
TestNetworkTracker tnt = null;
try {
tetherEventCallback.assumeTetheringSupported();
- assumeTrue(isWifiTetheringSupported(tetherEventCallback));
+ assumeTrue(isWifiTetheringSupported(mContext, tetherEventCallback));
tetherEventCallback.expectNoTetheringActive();
final TetheringInterface tetheredIface =
diff --git a/Tethering/tests/unit/src/com/android/networkstack/tethering/TestConnectivityManager.java b/Tethering/tests/unit/src/com/android/networkstack/tethering/TestConnectivityManager.java
index 6090213..b8389ea 100644
--- a/Tethering/tests/unit/src/com/android/networkstack/tethering/TestConnectivityManager.java
+++ b/Tethering/tests/unit/src/com/android/networkstack/tethering/TestConnectivityManager.java
@@ -36,6 +36,7 @@
import android.os.UserHandle;
import android.util.ArrayMap;
+import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import java.util.Map;
@@ -67,10 +68,10 @@
public static final boolean BROADCAST_FIRST = false;
public static final boolean CALLBACKS_FIRST = true;
- final Map<NetworkCallback, NetworkRequestInfo> mAllCallbacks = new ArrayMap<>();
+ final Map<NetworkCallback, NetworkCallbackInfo> mAllCallbacks = new ArrayMap<>();
// This contains the callbacks tracking the system default network, whether it's registered
// with registerSystemDefaultNetworkCallback (S+) or with a custom request (R-).
- final Map<NetworkCallback, NetworkRequestInfo> mTrackingDefault = new ArrayMap<>();
+ final Map<NetworkCallback, NetworkCallbackInfo> mTrackingDefault = new ArrayMap<>();
final Map<NetworkCallback, NetworkRequestInfo> mListening = new ArrayMap<>();
final Map<NetworkCallback, NetworkRequestInfo> mRequested = new ArrayMap<>();
final Map<NetworkCallback, Integer> mLegacyTypeMap = new ArrayMap<>();
@@ -91,15 +92,21 @@
mContext = ctx;
}
- class NetworkRequestInfo {
- public final NetworkRequest request;
+ static class NetworkCallbackInfo {
public final Handler handler;
- NetworkRequestInfo(NetworkRequest r, Handler h) {
- request = r;
+ NetworkCallbackInfo(Handler h) {
handler = h;
}
}
+ static class NetworkRequestInfo extends NetworkCallbackInfo {
+ public final NetworkRequest request;
+ NetworkRequestInfo(NetworkRequest r, Handler h) {
+ super(h);
+ request = r;
+ }
+ }
+
boolean hasNoCallbacks() {
return mAllCallbacks.isEmpty()
&& mTrackingDefault.isEmpty()
@@ -145,7 +152,7 @@
private void sendDefaultNetworkCallbacks(TestNetworkAgent formerDefault,
TestNetworkAgent defaultNetwork) {
for (NetworkCallback cb : mTrackingDefault.keySet()) {
- final NetworkRequestInfo nri = mTrackingDefault.get(cb);
+ final NetworkCallbackInfo nri = mTrackingDefault.get(cb);
if (defaultNetwork != null) {
nri.handler.post(() -> cb.onAvailable(defaultNetwork.networkId));
nri.handler.post(() -> cb.onCapabilitiesChanged(
@@ -191,20 +198,28 @@
@Override
public void requestNetwork(NetworkRequest req, NetworkCallback cb, Handler h) {
- assertFalse(mAllCallbacks.containsKey(cb));
- mAllCallbacks.put(cb, new NetworkRequestInfo(req, h));
// For R- devices, Tethering will invoke this function in 2 cases, one is to request mobile
// network, the other is to track system default network.
if (looksLikeDefaultRequest(req)) {
- assertFalse(mTrackingDefault.containsKey(cb));
- mTrackingDefault.put(cb, new NetworkRequestInfo(req, h));
+ registerSystemDefaultNetworkCallback(cb, h);
} else {
+ assertFalse(mAllCallbacks.containsKey(cb));
+ mAllCallbacks.put(cb, new NetworkRequestInfo(req, h));
assertFalse(mRequested.containsKey(cb));
mRequested.put(cb, new NetworkRequestInfo(req, h));
}
}
@Override
+ public void registerSystemDefaultNetworkCallback(
+ @NonNull NetworkCallback cb, @NonNull Handler h) {
+ assertFalse(mAllCallbacks.containsKey(cb));
+ mAllCallbacks.put(cb, new NetworkCallbackInfo(h));
+ assertFalse(mTrackingDefault.containsKey(cb));
+ mTrackingDefault.put(cb, new NetworkCallbackInfo(h));
+ }
+
+ @Override
public void requestNetwork(NetworkRequest req, NetworkCallback cb) {
fail("Should never be called.");
}
diff --git a/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java b/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java
index 2b15866..c636384 100644
--- a/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java
+++ b/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java
@@ -60,6 +60,7 @@
import static android.system.OsConstants.RT_SCOPE_UNIVERSE;
import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID;
+import static com.android.modules.utils.build.SdkLevel.isAtLeastS;
import static com.android.net.module.util.Inet4AddressUtils.inet4AddressToIntHTH;
import static com.android.net.module.util.Inet4AddressUtils.intToInet4AddressHTH;
import static com.android.networkstack.tethering.OffloadHardwareInterface.OFFLOAD_HAL_VERSION_1_0;
@@ -779,14 +780,19 @@
}
private void verifyDefaultNetworkRequestFiled() {
- ArgumentCaptor<NetworkRequest> reqCaptor = ArgumentCaptor.forClass(NetworkRequest.class);
- verify(mCm, times(1)).requestNetwork(reqCaptor.capture(),
- any(NetworkCallback.class), any(Handler.class));
- assertTrue(TestConnectivityManager.looksLikeDefaultRequest(reqCaptor.getValue()));
+ if (isAtLeastS()) {
+ verify(mCm, times(1)).registerSystemDefaultNetworkCallback(
+ any(NetworkCallback.class), any(Handler.class));
+ } else {
+ ArgumentCaptor<NetworkRequest> reqCaptor = ArgumentCaptor.forClass(
+ NetworkRequest.class);
+ verify(mCm, times(1)).requestNetwork(reqCaptor.capture(),
+ any(NetworkCallback.class), any(Handler.class));
+ assertTrue(TestConnectivityManager.looksLikeDefaultRequest(reqCaptor.getValue()));
+ }
+
// The default network request is only ever filed once.
verifyNoMoreInteractions(mCm);
- mUpstreamNetworkMonitor.startTrackDefaultNetwork(mEntitleMgr);
- verifyNoMoreInteractions(mCm);
}
private void verifyInterfaceServingModeStarted(String ifname) throws Exception {
diff --git a/Tethering/tests/unit/src/com/android/networkstack/tethering/UpstreamNetworkMonitorTest.java b/Tethering/tests/unit/src/com/android/networkstack/tethering/UpstreamNetworkMonitorTest.java
index ce4ba85..173679d 100644
--- a/Tethering/tests/unit/src/com/android/networkstack/tethering/UpstreamNetworkMonitorTest.java
+++ b/Tethering/tests/unit/src/com/android/networkstack/tethering/UpstreamNetworkMonitorTest.java
@@ -24,6 +24,7 @@
import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
+import static com.android.modules.utils.build.SdkLevel.isAtLeastS;
import static com.android.networkstack.tethering.UpstreamNetworkMonitor.TYPE_NONE;
import static org.junit.Assert.assertEquals;
@@ -172,12 +173,17 @@
// Verify the fired default request matches expectation.
final ArgumentCaptor<NetworkRequest> requestCaptor =
ArgumentCaptor.forClass(NetworkRequest.class);
- verify(mCM, times(1)).requestNetwork(
- requestCaptor.capture(), any(NetworkCallback.class), any(Handler.class));
- // For R- devices, Tethering will invoke this function in 2 cases, one is to
- // request mobile network, the other is to track system default network. Verify
- // the request is the one tracks default network.
- assertTrue(TestConnectivityManager.looksLikeDefaultRequest(requestCaptor.getValue()));
+
+ if (isAtLeastS()) {
+ verify(mCM).registerSystemDefaultNetworkCallback(any(), any());
+ } else {
+ verify(mCM).requestNetwork(
+ requestCaptor.capture(), any(NetworkCallback.class), any(Handler.class));
+ // For R- devices, Tethering will invoke this function in 2 cases, one is to
+ // request mobile network, the other is to track system default network. Verify
+ // the request is the one tracks default network.
+ assertTrue(TestConnectivityManager.looksLikeDefaultRequest(requestCaptor.getValue()));
+ }
mUNM.startObserveAllNetworks();
verify(mCM, times(1)).registerNetworkCallback(
diff --git a/framework/Android.bp b/framework/Android.bp
index ee71e15..a447a9c 100644
--- a/framework/Android.bp
+++ b/framework/Android.bp
@@ -55,22 +55,6 @@
],
}
-java_library {
- name: "framework-connectivity-annotations",
- sdk_version: "module_current",
- srcs: [
- "src/android/net/ConnectivityAnnotations.java",
- ],
- libs: [
- "framework-annotations-lib",
- "framework-connectivity",
- ],
- visibility: [
- "//frameworks/base:__subpackages__",
- "//packages/modules/Connectivity:__subpackages__",
- ],
-}
-
java_sdk_library {
name: "framework-connectivity",
sdk_version: "module_current",
diff --git a/framework/api/module-lib-current.txt b/framework/api/module-lib-current.txt
index 6c454bc..7fc0382 100644
--- a/framework/api/module-lib-current.txt
+++ b/framework/api/module-lib-current.txt
@@ -48,7 +48,6 @@
public class ConnectivitySettingsManager {
method public static void clearGlobalProxy(@NonNull android.content.Context);
- method @NonNull public static java.util.Set<java.lang.String> getAppsAllowedOnRestrictedNetworks(@NonNull android.content.Context);
method @Nullable public static String getCaptivePortalHttpUrl(@NonNull android.content.Context);
method public static int getCaptivePortalMode(@NonNull android.content.Context, int);
method @NonNull public static java.time.Duration getConnectivityKeepPendingIntentDuration(@NonNull android.content.Context, @NonNull java.time.Duration);
@@ -66,9 +65,9 @@
method @NonNull public static String getPrivateDnsDefaultMode(@NonNull android.content.Context);
method @Nullable public static String getPrivateDnsHostname(@NonNull android.content.Context);
method public static int getPrivateDnsMode(@NonNull android.content.Context);
+ method @NonNull public static java.util.Set<java.lang.Integer> getUidsAllowedOnRestrictedNetworks(@NonNull android.content.Context);
method public static boolean getWifiAlwaysRequested(@NonNull android.content.Context, boolean);
method @NonNull public static java.time.Duration getWifiDataActivityTimeout(@NonNull android.content.Context, @NonNull java.time.Duration);
- method public static void setAppsAllowedOnRestrictedNetworks(@NonNull android.content.Context, @NonNull java.util.Set<java.lang.String>);
method public static void setCaptivePortalHttpUrl(@NonNull android.content.Context, @Nullable String);
method public static void setCaptivePortalMode(@NonNull android.content.Context, int);
method public static void setConnectivityKeepPendingIntentDuration(@NonNull android.content.Context, @NonNull java.time.Duration);
@@ -86,6 +85,7 @@
method public static void setPrivateDnsDefaultMode(@NonNull android.content.Context, @NonNull int);
method public static void setPrivateDnsHostname(@NonNull android.content.Context, @Nullable String);
method public static void setPrivateDnsMode(@NonNull android.content.Context, int);
+ method public static void setUidsAllowedOnRestrictedNetworks(@NonNull android.content.Context, @NonNull java.util.Set<java.lang.Integer>);
method public static void setWifiAlwaysRequested(@NonNull android.content.Context, boolean);
method public static void setWifiDataActivityTimeout(@NonNull android.content.Context, @NonNull java.time.Duration);
field public static final int CAPTIVE_PORTAL_MODE_AVOID = 2; // 0x2
diff --git a/framework/src/android/net/ConnectivityAnnotations.java b/framework/src/android/net/ConnectivityAnnotations.java
deleted file mode 100644
index eb1faa0..0000000
--- a/framework/src/android/net/ConnectivityAnnotations.java
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Copyright (C) 2021 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 android.net;
-
-import android.annotation.IntDef;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-
-/**
- * Type annotations for constants used in the connectivity API surface.
- *
- * The annotations are maintained in a separate class so that it can be built as
- * a separate library that other modules can build against, as Typedef should not
- * be exposed as SystemApi.
- *
- * @hide
- */
-public final class ConnectivityAnnotations {
- private ConnectivityAnnotations() {}
-
- @Retention(RetentionPolicy.SOURCE)
- @IntDef(flag = true, value = {
- ConnectivityManager.MULTIPATH_PREFERENCE_HANDOVER,
- ConnectivityManager.MULTIPATH_PREFERENCE_RELIABILITY,
- ConnectivityManager.MULTIPATH_PREFERENCE_PERFORMANCE,
- })
- public @interface MultipathPreference {}
-
- @Retention(RetentionPolicy.SOURCE)
- @IntDef(flag = false, value = {
- ConnectivityManager.RESTRICT_BACKGROUND_STATUS_DISABLED,
- ConnectivityManager.RESTRICT_BACKGROUND_STATUS_WHITELISTED,
- ConnectivityManager.RESTRICT_BACKGROUND_STATUS_ENABLED,
- })
- public @interface RestrictBackgroundStatus {}
-}
diff --git a/framework/src/android/net/ConnectivityManager.java b/framework/src/android/net/ConnectivityManager.java
index 93455bc..a3fc621 100644
--- a/framework/src/android/net/ConnectivityManager.java
+++ b/framework/src/android/net/ConnectivityManager.java
@@ -40,8 +40,6 @@
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
-import android.net.ConnectivityAnnotations.MultipathPreference;
-import android.net.ConnectivityAnnotations.RestrictBackgroundStatus;
import android.net.ConnectivityDiagnosticsManager.DataStallReport.DetectionMethod;
import android.net.IpSecManager.UdpEncapsulationSocket;
import android.net.SocketKeepalive.Callback;
@@ -4809,6 +4807,16 @@
MULTIPATH_PREFERENCE_RELIABILITY |
MULTIPATH_PREFERENCE_PERFORMANCE;
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(flag = true, value = {
+ MULTIPATH_PREFERENCE_HANDOVER,
+ MULTIPATH_PREFERENCE_RELIABILITY,
+ MULTIPATH_PREFERENCE_PERFORMANCE,
+ })
+ public @interface MultipathPreference {
+ }
+
/**
* Provides a hint to the calling application on whether it is desirable to use the
* multinetwork APIs (e.g., {@link Network#openConnection}, {@link Network#bindSocket}, etc.)
@@ -4918,7 +4926,7 @@
InetAddressCompat.clearDnsCache();
// Must flush socket pool as idle sockets will be bound to previous network and may
// cause subsequent fetches to be performed on old network.
- NetworkEventDispatcher.getInstance().onNetworkConfigurationChanged();
+ NetworkEventDispatcher.getInstance().dispatchNetworkConfigurationChange();
}
return true;
@@ -5030,6 +5038,16 @@
public static final String ACTION_RESTRICT_BACKGROUND_CHANGED =
"android.net.conn.RESTRICT_BACKGROUND_CHANGED";
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(flag = false, value = {
+ RESTRICT_BACKGROUND_STATUS_DISABLED,
+ RESTRICT_BACKGROUND_STATUS_WHITELISTED,
+ RESTRICT_BACKGROUND_STATUS_ENABLED,
+ })
+ public @interface RestrictBackgroundStatus {
+ }
+
/**
* Determines if the calling application is subject to metered network restrictions while
* running on background.
diff --git a/framework/src/android/net/ConnectivitySettingsManager.java b/framework/src/android/net/ConnectivitySettingsManager.java
index 1a69099..03c3600 100644
--- a/framework/src/android/net/ConnectivitySettingsManager.java
+++ b/framework/src/android/net/ConnectivitySettingsManager.java
@@ -27,7 +27,7 @@
import android.annotation.SystemApi;
import android.content.ContentResolver;
import android.content.Context;
-import android.net.ConnectivityAnnotations.MultipathPreference;
+import android.net.ConnectivityManager.MultipathPreference;
import android.os.Process;
import android.os.UserHandle;
import android.provider.Settings;
@@ -374,12 +374,12 @@
private static final String PRIVATE_DNS_MODE_PROVIDER_HOSTNAME_STRING = "hostname";
/**
- * A list of apps that is allowed on restricted networks.
+ * A list of uids that is allowed to use restricted networks.
*
* @hide
*/
- public static final String APPS_ALLOWED_ON_RESTRICTED_NETWORKS =
- "apps_allowed_on_restricted_networks";
+ public static final String UIDS_ALLOWED_ON_RESTRICTED_NETWORKS =
+ "uids_allowed_on_restricted_networks";
/**
* Get mobile data activity timeout from {@link Settings}.
@@ -1003,6 +1003,28 @@
context.getContentResolver(), NETWORK_METERED_MULTIPATH_PREFERENCE, preference);
}
+ private static Set<Integer> getUidSetFromString(@Nullable String uidList) {
+ final Set<Integer> uids = new ArraySet<>();
+ if (TextUtils.isEmpty(uidList)) {
+ return uids;
+ }
+ for (String uid : uidList.split(";")) {
+ uids.add(Integer.valueOf(uid));
+ }
+ return uids;
+ }
+
+ private static String getUidStringFromSet(@NonNull Set<Integer> uidList) {
+ final StringJoiner joiner = new StringJoiner(";");
+ for (Integer uid : uidList) {
+ if (uid < 0 || UserHandle.getAppId(uid) > Process.LAST_APPLICATION_UID) {
+ throw new IllegalArgumentException("Invalid uid");
+ }
+ joiner.add(uid.toString());
+ }
+ return joiner.toString();
+ }
+
/**
* Get the list of uids(from {@link Settings}) that should go on cellular networks in preference
* even when higher-priority networks are connected.
@@ -1015,14 +1037,7 @@
public static Set<Integer> getMobileDataPreferredUids(@NonNull Context context) {
final String uidList = Settings.Secure.getString(
context.getContentResolver(), MOBILE_DATA_PREFERRED_UIDS);
- final Set<Integer> uids = new ArraySet<>();
- if (TextUtils.isEmpty(uidList)) {
- return uids;
- }
- for (String uid : uidList.split(";")) {
- uids.add(Integer.valueOf(uid));
- }
- return uids;
+ return getUidSetFromString(uidList);
}
/**
@@ -1035,53 +1050,41 @@
*/
public static void setMobileDataPreferredUids(@NonNull Context context,
@NonNull Set<Integer> uidList) {
- final StringJoiner joiner = new StringJoiner(";");
- for (Integer uid : uidList) {
- if (uid < 0 || UserHandle.getAppId(uid) > Process.LAST_APPLICATION_UID) {
- throw new IllegalArgumentException("Invalid uid");
- }
- joiner.add(uid.toString());
- }
- Settings.Secure.putString(
- context.getContentResolver(), MOBILE_DATA_PREFERRED_UIDS, joiner.toString());
+ final String uids = getUidStringFromSet(uidList);
+ Settings.Secure.putString(context.getContentResolver(), MOBILE_DATA_PREFERRED_UIDS, uids);
}
/**
- * Get the list of apps(from {@link Settings}) that is allowed on restricted networks.
+ * Get the list of uids (from {@link Settings}) allowed to use restricted networks.
+ *
+ * Access to restricted networks is controlled by the (preinstalled-only)
+ * CONNECTIVITY_USE_RESTRICTED_NETWORKS permission, but highly privileged
+ * callers can also set a list of uids that can access restricted networks.
+ *
+ * This is useful for example in some jurisdictions where government apps,
+ * that can't be preinstalled, must still have access to emergency services.
*
* @param context The {@link Context} to query the setting.
- * @return A list of apps that is allowed on restricted networks or null if no setting
+ * @return A list of uids that is allowed to use restricted networks or null if no setting
* value.
*/
@NonNull
- public static Set<String> getAppsAllowedOnRestrictedNetworks(@NonNull Context context) {
- final String appList = Settings.Secure.getString(
- context.getContentResolver(), APPS_ALLOWED_ON_RESTRICTED_NETWORKS);
- if (TextUtils.isEmpty(appList)) {
- return new ArraySet<>();
- }
- return new ArraySet<>(appList.split(";"));
+ public static Set<Integer> getUidsAllowedOnRestrictedNetworks(@NonNull Context context) {
+ final String uidList = Settings.Global.getString(
+ context.getContentResolver(), UIDS_ALLOWED_ON_RESTRICTED_NETWORKS);
+ return getUidSetFromString(uidList);
}
/**
- * Set the list of apps(from {@link Settings}) that is allowed on restricted networks.
- *
- * Note: Please refer to android developer guidelines for valid app(package name).
- * https://developer.android.com/guide/topics/manifest/manifest-element.html#package
+ * Set the list of uids(from {@link Settings}) that is allowed to use restricted networks.
*
* @param context The {@link Context} to set the setting.
- * @param list A list of apps that is allowed on restricted networks.
+ * @param uidList A list of uids that is allowed to use restricted networks.
*/
- public static void setAppsAllowedOnRestrictedNetworks(@NonNull Context context,
- @NonNull Set<String> list) {
- final StringJoiner joiner = new StringJoiner(";");
- for (String app : list) {
- if (app == null || app.contains(";")) {
- throw new IllegalArgumentException("Invalid app(package name)");
- }
- joiner.add(app);
- }
- Settings.Secure.putString(context.getContentResolver(), APPS_ALLOWED_ON_RESTRICTED_NETWORKS,
- joiner.toString());
+ public static void setUidsAllowedOnRestrictedNetworks(@NonNull Context context,
+ @NonNull Set<Integer> uidList) {
+ final String uids = getUidStringFromSet(uidList);
+ Settings.Global.putString(context.getContentResolver(), UIDS_ALLOWED_ON_RESTRICTED_NETWORKS,
+ uids);
}
}
diff --git a/service/Android.bp b/service/Android.bp
index 28bcdcb..c4fac90 100644
--- a/service/Android.bp
+++ b/service/Android.bp
@@ -61,7 +61,6 @@
"stable.core.platform.api.stubs",
"android_system_server_stubs_current",
"framework-annotations-lib",
- "framework-connectivity-annotations",
"framework-connectivity.impl",
"framework-tethering.stubs.module_lib",
"framework-wifi.stubs.module_lib",
diff --git a/service/src/com/android/server/ConnectivityService.java b/service/src/com/android/server/ConnectivityService.java
index 5c47f27..b4355b9 100644
--- a/service/src/com/android/server/ConnectivityService.java
+++ b/service/src/com/android/server/ConnectivityService.java
@@ -78,6 +78,7 @@
import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
import static android.net.NetworkCapabilities.TRANSPORT_TEST;
import static android.net.NetworkCapabilities.TRANSPORT_VPN;
+import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
import static android.net.NetworkRequest.Type.LISTEN_FOR_BEST;
import static android.net.shared.NetworkMonitorUtils.isPrivateDnsValidationRequired;
import static android.os.Process.INVALID_UID;
@@ -105,12 +106,12 @@
import android.net.CaptivePortal;
import android.net.CaptivePortalData;
import android.net.ConnectionInfo;
-import android.net.ConnectivityAnnotations.RestrictBackgroundStatus;
import android.net.ConnectivityDiagnosticsManager.ConnectivityReport;
import android.net.ConnectivityDiagnosticsManager.DataStallReport;
import android.net.ConnectivityManager;
import android.net.ConnectivityManager.BlockedReason;
import android.net.ConnectivityManager.NetworkCallback;
+import android.net.ConnectivityManager.RestrictBackgroundStatus;
import android.net.ConnectivityResources;
import android.net.ConnectivitySettingsManager;
import android.net.DataStallReportParcelable;
@@ -618,6 +619,11 @@
private static final int EVENT_UNREGISTER_NETWORK_OFFER = 53;
/**
+ * Used internally when MOBILE_DATA_PREFERRED_UIDS setting changed.
+ */
+ private static final int EVENT_MOBILE_DATA_PREFERRED_UIDS_CHANGED = 54;
+
+ /**
* Argument for {@link #EVENT_PROVISIONING_NOTIFICATION} to indicate that the notification
* should be shown.
*/
@@ -1461,6 +1467,11 @@
mHandler.sendEmptyMessage(EVENT_PRIVATE_DNS_SETTINGS_CHANGED);
}
+ @VisibleForTesting
+ void updateMobileDataPreferredUids() {
+ mHandler.sendEmptyMessage(EVENT_MOBILE_DATA_PREFERRED_UIDS_CHANGED);
+ }
+
private void handleAlwaysOnNetworkRequest(NetworkRequest networkRequest, int id) {
final boolean enable = mContext.getResources().getBoolean(id);
handleAlwaysOnNetworkRequest(networkRequest, enable);
@@ -1500,6 +1511,8 @@
handleAlwaysOnNetworkRequest(mDefaultVehicleRequest, vehicleAlwaysRequested);
}
+ // Note that registering observer for setting do not get initial callback when registering,
+ // callers might have self-initialization to update status if need.
private void registerSettingsCallbacks() {
// Watch for global HTTP proxy changes.
mSettingsObserver.observe(
@@ -1515,6 +1528,11 @@
mSettingsObserver.observe(
Settings.Global.getUriFor(ConnectivitySettingsManager.WIFI_ALWAYS_REQUESTED),
EVENT_CONFIGURE_ALWAYS_ON_NETWORKS);
+
+ // Watch for mobile data preferred uids changes.
+ mSettingsObserver.observe(
+ Settings.Secure.getUriFor(ConnectivitySettingsManager.MOBILE_DATA_PREFERRED_UIDS),
+ EVENT_MOBILE_DATA_PREFERRED_UIDS_CHANGED);
}
private void registerPrivateDnsSettingsCallbacks() {
@@ -2725,6 +2743,13 @@
// Create network requests for always-on networks.
mHandler.sendMessage(mHandler.obtainMessage(EVENT_CONFIGURE_ALWAYS_ON_NETWORKS));
+
+ // Update mobile data preference if necessary.
+ // Note that empty uid list can be skip here only because no uid rules applied before system
+ // ready. Normally, the empty uid list means to clear the uids rules on netd.
+ if (!ConnectivitySettingsManager.getMobileDataPreferredUids(mContext).isEmpty()) {
+ updateMobileDataPreferredUids();
+ }
}
/**
@@ -4806,6 +4831,9 @@
case EVENT_REPORT_NETWORK_ACTIVITY:
mNetworkActivityTracker.handleReportNetworkActivity();
break;
+ case EVENT_MOBILE_DATA_PREFERRED_UIDS_CHANGED:
+ handleMobileDataPreferredUidsChanged();
+ break;
}
}
}
@@ -5592,7 +5620,7 @@
* Get the list of UIDs this nri applies to.
*/
@NonNull
- private Set<UidRange> getUids() {
+ Set<UidRange> getUids() {
// networkCapabilities.getUids() returns a defensive copy.
// multilayer requests will all have the same uids so return the first one.
final Set<UidRange> uids = mRequests.get(0).networkCapabilities.getUidRanges();
@@ -6308,6 +6336,11 @@
@NonNull
private ProfileNetworkPreferences mProfileNetworkPreferences = new ProfileNetworkPreferences();
+ // A set of UIDs that should use mobile data preferentially if available. This object follows
+ // the same threading rules as the OEM network preferences above.
+ @NonNull
+ private Set<Integer> mMobileDataPreferredUids = new ArraySet<>();
+
// OemNetworkPreferences activity String log entries.
private static final int MAX_OEM_NETWORK_PREFERENCE_LOGS = 20;
@NonNull
@@ -9162,6 +9195,12 @@
return results;
}
+ private boolean isLocationPermissionRequiredForConnectivityDiagnostics(
+ @NonNull NetworkAgentInfo nai) {
+ // TODO(b/188483916): replace with a transport-agnostic location-aware check
+ return nai.networkCapabilities.hasTransport(TRANSPORT_WIFI);
+ }
+
private boolean hasLocationPermission(String packageName, int uid) {
// LocationPermissionChecker#checkLocationPermission can throw SecurityException if the uid
// and package name don't match. Throwing on the CS thread is not acceptable, so wrap the
@@ -9204,7 +9243,8 @@
return false;
}
- return hasLocationPermission(callbackPackageName, callbackUid);
+ return !isLocationPermissionRequiredForConnectivityDiagnostics(nai)
+ || hasLocationPermission(callbackPackageName, callbackUid);
}
@Override
@@ -9670,7 +9710,8 @@
// safe - it's just possible the value is slightly outdated. For the final check,
// see #handleSetProfileNetworkPreference. But if this can be caught here it is a
// lot easier to understand, so opportunistically check it.
- if (!mOemNetworkPreferences.isEmpty()) {
+ // TODO: Have a priority for each preference.
+ if (!mOemNetworkPreferences.isEmpty() || !mMobileDataPreferredUids.isEmpty()) {
throwConcurrentPreferenceException();
}
final NetworkCapabilities nc;
@@ -9729,7 +9770,8 @@
// The binder call has already checked this, but as mOemNetworkPreferences is only
// touched on the handler thread, it's theoretically not impossible that it has changed
// since.
- if (!mOemNetworkPreferences.isEmpty()) {
+ // TODO: Have a priority for each preference.
+ if (!mOemNetworkPreferences.isEmpty() || !mMobileDataPreferredUids.isEmpty()) {
// This may happen on a device with an OEM preference set when a user is removed.
// In this case, it's safe to ignore. In particular this happens in the tests.
loge("handleSetProfileNetworkPreference, but OEM network preferences not empty");
@@ -9758,6 +9800,56 @@
}
}
+ @VisibleForTesting
+ @NonNull
+ ArraySet<NetworkRequestInfo> createNrisFromMobileDataPreferredUids(
+ @NonNull final Set<Integer> uids) {
+ final ArraySet<NetworkRequestInfo> nris = new ArraySet<>();
+ if (uids.size() == 0) {
+ // Should not create NetworkRequestInfo if no preferences. Without uid range in
+ // NetworkRequestInfo, makeDefaultForApps() would treat it as a illegal NRI.
+ if (DBG) log("Don't create NetworkRequestInfo because no preferences");
+ return nris;
+ }
+
+ final List<NetworkRequest> requests = new ArrayList<>();
+ // The NRI should be comprised of two layers:
+ // - The request for the mobile network preferred.
+ // - The request for the default network, for fallback.
+ requests.add(createDefaultInternetRequestForTransport(
+ TRANSPORT_CELLULAR, NetworkRequest.Type.LISTEN));
+ requests.add(createDefaultInternetRequestForTransport(
+ TYPE_NONE, NetworkRequest.Type.TRACK_DEFAULT));
+ final Set<UidRange> ranges = new ArraySet<>();
+ for (final int uid : uids) {
+ ranges.add(new UidRange(uid, uid));
+ }
+ setNetworkRequestUids(requests, ranges);
+ nris.add(new NetworkRequestInfo(Process.myUid(), requests));
+ return nris;
+ }
+
+ private void handleMobileDataPreferredUidsChanged() {
+ // Ignore update preference because it's not clear what preference should win in case both
+ // apply to the same app.
+ // TODO: Have a priority for each preference.
+ if (!mOemNetworkPreferences.isEmpty() || !mProfileNetworkPreferences.isEmpty()) {
+ loge("Ignore mobile data preference change because other preferences are not empty");
+ return;
+ }
+
+ mMobileDataPreferredUids = ConnectivitySettingsManager.getMobileDataPreferredUids(mContext);
+ mSystemNetworkRequestCounter.transact(
+ mDeps.getCallingUid(), 1 /* numOfNewRequests */,
+ () -> {
+ final ArraySet<NetworkRequestInfo> nris =
+ createNrisFromMobileDataPreferredUids(mMobileDataPreferredUids);
+ replaceDefaultNetworkRequestsForPreference(nris);
+ });
+ // Finally, rematch.
+ rematchAllNetworksAndRequests();
+ }
+
private void enforceAutomotiveDevice() {
final boolean isAutomotiveDevice =
mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE);
@@ -9787,7 +9879,8 @@
enforceAutomotiveDevice();
enforceOemNetworkPreferencesPermission();
- if (!mProfileNetworkPreferences.isEmpty()) {
+ // TODO: Have a priority for each preference.
+ if (!mProfileNetworkPreferences.isEmpty() || !mMobileDataPreferredUids.isEmpty()) {
// Strictly speaking, mProfileNetworkPreferences should only be touched on the
// handler thread. However it is an immutable object, so reading the reference is
// safe - it's just possible the value is slightly outdated. For the final check,
@@ -9825,7 +9918,8 @@
// The binder call has already checked this, but as mOemNetworkPreferences is only
// touched on the handler thread, it's theoretically not impossible that it has changed
// since.
- if (!mProfileNetworkPreferences.isEmpty()) {
+ // TODO: Have a priority for each preference.
+ if (!mProfileNetworkPreferences.isEmpty() || !mMobileDataPreferredUids.isEmpty()) {
logwtf("handleSetOemPreference, but per-profile network preferences not empty");
return;
}
diff --git a/service/src/com/android/server/connectivity/PermissionMonitor.java b/service/src/com/android/server/connectivity/PermissionMonitor.java
index 9bda59c..3328846 100644
--- a/service/src/com/android/server/connectivity/PermissionMonitor.java
+++ b/service/src/com/android/server/connectivity/PermissionMonitor.java
@@ -24,7 +24,7 @@
import static android.content.pm.PackageInfo.REQUESTED_PERMISSION_GRANTED;
import static android.content.pm.PackageManager.GET_PERMISSIONS;
import static android.content.pm.PackageManager.MATCH_ANY_USER;
-import static android.net.ConnectivitySettingsManager.APPS_ALLOWED_ON_RESTRICTED_NETWORKS;
+import static android.net.ConnectivitySettingsManager.UIDS_ALLOWED_ON_RESTRICTED_NETWORKS;
import static android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK;
import static android.os.Process.INVALID_UID;
import static android.os.Process.SYSTEM_UID;
@@ -109,13 +109,13 @@
@GuardedBy("this")
private final Set<Integer> mAllApps = new HashSet<>();
- // A set of apps which are allowed to use restricted networks. These apps can't hold the
- // CONNECTIVITY_USE_RESTRICTED_NETWORKS permission because they can't be signature|privileged
- // apps. However, these apps should still be able to use restricted networks under certain
- // conditions (e.g. government app using emergency services). So grant netd system permission
- // to uids whose package name is listed in APPS_ALLOWED_ON_RESTRICTED_NETWORKS setting.
+ // A set of uids which are allowed to use restricted networks. The packages of these uids can't
+ // hold the CONNECTIVITY_USE_RESTRICTED_NETWORKS permission because they can't be
+ // signature|privileged apps. However, these apps should still be able to use restricted
+ // networks under certain conditions (e.g. government app using emergency services). So grant
+ // netd system permission to these uids which is listed in UIDS_ALLOWED_ON_RESTRICTED_NETWORKS.
@GuardedBy("this")
- private final Set<String> mAppsAllowedOnRestrictedNetworks = new ArraySet<>();
+ private final Set<Integer> mUidsAllowedOnRestrictedNetworks = new ArraySet<>();
private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
@Override
@@ -149,10 +149,10 @@
}
/**
- * Get apps allowed to use restricted networks via ConnectivitySettingsManager.
+ * Get uids allowed to use restricted networks via ConnectivitySettingsManager.
*/
- public Set<String> getAppsAllowedOnRestrictedNetworks(@NonNull Context context) {
- return ConnectivitySettingsManager.getAppsAllowedOnRestrictedNetworks(context);
+ public Set<Integer> getUidsAllowedOnRestrictedNetworks(@NonNull Context context) {
+ return ConnectivitySettingsManager.getUidsAllowedOnRestrictedNetworks(context);
}
/**
@@ -194,10 +194,10 @@
mIntentReceiver, intentFilter, null /* broadcastPermission */,
null /* scheduler */);
- // Register APPS_ALLOWED_ON_RESTRICTED_NETWORKS setting observer
+ // Register UIDS_ALLOWED_ON_RESTRICTED_NETWORKS setting observer
mDeps.registerContentObserver(
userAllContext,
- Settings.Secure.getUriFor(APPS_ALLOWED_ON_RESTRICTED_NETWORKS),
+ Settings.Global.getUriFor(UIDS_ALLOWED_ON_RESTRICTED_NETWORKS),
false /* notifyForDescendants */,
new ContentObserver(null) {
@Override
@@ -206,9 +206,9 @@
}
});
- // Read APPS_ALLOWED_ON_RESTRICTED_NETWORKS setting and update
- // mAppsAllowedOnRestrictedNetworks.
- updateAppsAllowedOnRestrictedNetworks(mDeps.getAppsAllowedOnRestrictedNetworks(mContext));
+ // Read UIDS_ALLOWED_ON_RESTRICTED_NETWORKS setting and update
+ // mUidsAllowedOnRestrictedNetworks.
+ updateUidsAllowedOnRestrictedNetworks(mDeps.getUidsAllowedOnRestrictedNetworks(mContext));
List<PackageInfo> apps = mPackageManager.getInstalledPackages(GET_PERMISSIONS
| MATCH_ANY_USER);
@@ -265,9 +265,9 @@
}
@VisibleForTesting
- void updateAppsAllowedOnRestrictedNetworks(final Set<String> apps) {
- mAppsAllowedOnRestrictedNetworks.clear();
- mAppsAllowedOnRestrictedNetworks.addAll(apps);
+ synchronized void updateUidsAllowedOnRestrictedNetworks(final Set<Integer> uids) {
+ mUidsAllowedOnRestrictedNetworks.clear();
+ mUidsAllowedOnRestrictedNetworks.addAll(uids);
}
@VisibleForTesting
@@ -285,10 +285,11 @@
}
@VisibleForTesting
- boolean isAppAllowedOnRestrictedNetworks(@NonNull final PackageInfo app) {
- // Check whether package name is in allowed on restricted networks app list. If so, this app
- // can have netd system permission.
- return mAppsAllowedOnRestrictedNetworks.contains(app.packageName);
+ synchronized boolean isUidAllowedOnRestrictedNetworks(final ApplicationInfo appInfo) {
+ if (appInfo == null) return false;
+ // Check whether package's uid is in allowed on restricted networks uid list. If so, this
+ // uid can have netd system permission.
+ return mUidsAllowedOnRestrictedNetworks.contains(appInfo.uid);
}
@VisibleForTesting
@@ -310,7 +311,8 @@
boolean hasRestrictedNetworkPermission(@NonNull final PackageInfo app) {
// TODO : remove carryover package check in the future(b/31479477). All apps should just
// request the appropriate permission for their use case since android Q.
- return isCarryoverPackage(app.applicationInfo) || isAppAllowedOnRestrictedNetworks(app)
+ return isCarryoverPackage(app.applicationInfo)
+ || isUidAllowedOnRestrictedNetworks(app.applicationInfo)
|| hasPermission(app, PERMISSION_MAINLINE_NETWORK_STACK)
|| hasPermission(app, NETWORK_STACK)
|| hasPermission(app, CONNECTIVITY_USE_RESTRICTED_NETWORKS);
@@ -387,6 +389,14 @@
update(users, mApps, false);
}
+ /**
+ * Compare the current network permission and the given package's permission to find out highest
+ * permission for the uid.
+ *
+ * @param currentPermission Current uid network permission
+ * @param name The package has same uid that need compare its permission to update uid network
+ * permission.
+ */
@VisibleForTesting
protected Boolean highestPermissionForUid(Boolean currentPermission, String name) {
if (currentPermission == SYSTEM) {
@@ -470,6 +480,8 @@
final String[] packages = mPackageManager.getPackagesForUid(uid);
if (!CollectionUtils.isEmpty(packages)) {
for (String name : packages) {
+ // If multiple packages have the same UID, give the UID all permissions that
+ // any package in that UID has.
permission = highestPermissionForUid(permission, name);
if (permission == SYSTEM) {
break;
@@ -770,35 +782,31 @@
}
private synchronized void onSettingChanged() {
- // Step1. Update apps allowed to use restricted networks and compute the set of packages to
+ // Step1. Update uids allowed to use restricted networks and compute the set of uids to
// update.
- final Set<String> packagesToUpdate = new ArraySet<>(mAppsAllowedOnRestrictedNetworks);
- updateAppsAllowedOnRestrictedNetworks(mDeps.getAppsAllowedOnRestrictedNetworks(mContext));
- packagesToUpdate.addAll(mAppsAllowedOnRestrictedNetworks);
+ final Set<Integer> uidsToUpdate = new ArraySet<>(mUidsAllowedOnRestrictedNetworks);
+ updateUidsAllowedOnRestrictedNetworks(mDeps.getUidsAllowedOnRestrictedNetworks(mContext));
+ uidsToUpdate.addAll(mUidsAllowedOnRestrictedNetworks);
- final Map<Integer, Boolean> updatedApps = new HashMap<>();
- final Map<Integer, Boolean> removedApps = new HashMap<>();
+ final Map<Integer, Boolean> updatedUids = new HashMap<>();
+ final Map<Integer, Boolean> removedUids = new HashMap<>();
- // Step2. For each package to update, find out its new permission.
- for (String app : packagesToUpdate) {
- final PackageInfo info = getPackageInfo(app);
- if (info == null || info.applicationInfo == null) continue;
-
- final int uid = info.applicationInfo.uid;
+ // Step2. For each uid to update, find out its new permission.
+ for (Integer uid : uidsToUpdate) {
final Boolean permission = highestUidNetworkPermission(uid);
if (null == permission) {
- removedApps.put(uid, NETWORK); // Doesn't matter which permission is set here.
+ removedUids.put(uid, NETWORK); // Doesn't matter which permission is set here.
mApps.remove(uid);
} else {
- updatedApps.put(uid, permission);
+ updatedUids.put(uid, permission);
mApps.put(uid, permission);
}
}
// Step3. Update or revoke permission for uids with netd.
- update(mUsers, updatedApps, true /* add */);
- update(mUsers, removedApps, false /* add */);
+ update(mUsers, updatedUids, true /* add */);
+ update(mUsers, removedUids, false /* add */);
}
/** Dump info to dumpsys */
diff --git a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java
index 90efba0..98b5a98 100644
--- a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java
+++ b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java
@@ -49,11 +49,16 @@
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED;
import static android.net.NetworkCapabilities.TRANSPORT_TEST;
import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
+import static android.net.TetheringManager.TETHERING_WIFI;
+import static android.net.TetheringManager.TetheringRequest;
import static android.net.cts.util.CtsNetUtils.ConnectivityActionReceiver;
import static android.net.cts.util.CtsNetUtils.HTTP_PORT;
import static android.net.cts.util.CtsNetUtils.NETWORK_CALLBACK_ACTION;
import static android.net.cts.util.CtsNetUtils.TEST_HOST;
import static android.net.cts.util.CtsNetUtils.TestNetworkCallback;
+import static android.net.cts.util.CtsTetheringUtils.StartTetheringCallback;
+import static android.net.cts.util.CtsTetheringUtils.TestTetheringEventCallback;
+import static android.net.cts.util.CtsTetheringUtils.isWifiTetheringSupported;
import static android.os.MessageQueue.OnFileDescriptorEventListener.EVENT_INPUT;
import static android.provider.Settings.Global.NETWORK_METERED_MULTIPATH_PREFERENCE;
import static android.system.OsConstants.AF_INET;
@@ -92,6 +97,7 @@
import android.content.res.Resources;
import android.net.ConnectivityManager;
import android.net.ConnectivityManager.NetworkCallback;
+import android.net.ConnectivitySettingsManager;
import android.net.InetAddresses;
import android.net.IpSecManager;
import android.net.IpSecManager.UdpEncapsulationSocket;
@@ -111,6 +117,7 @@
import android.net.TelephonyNetworkSpecifier;
import android.net.TestNetworkInterface;
import android.net.TestNetworkManager;
+import android.net.TetheringManager;
import android.net.cts.util.CtsNetUtils;
import android.net.util.KeepaliveUtils;
import android.net.wifi.WifiManager;
@@ -228,6 +235,9 @@
private static final LinkAddress TEST_LINKADDR = new LinkAddress(
InetAddresses.parseNumericAddress("2001:db8::8"), 64);
+ private static final int AIRPLANE_MODE_OFF = 0;
+ private static final int AIRPLANE_MODE_ON = 1;
+
private Context mContext;
private Instrumentation mInstrumentation;
private ConnectivityManager mCm;
@@ -237,6 +247,7 @@
private final ArraySet<Integer> mNetworkTypes = new ArraySet<>();
private UiAutomation mUiAutomation;
private CtsNetUtils mCtsNetUtils;
+ private TetheringManager mTm;
// Used for cleanup purposes.
private final List<Range<Integer>> mVpnRequiredUidRanges = new ArrayList<>();
@@ -250,6 +261,7 @@
mWifiManager = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE);
mPackageManager = mContext.getPackageManager();
mCtsNetUtils = new CtsNetUtils(mContext);
+ mTm = mContext.getSystemService(TetheringManager.class);
if (DevSdkIgnoreRuleKt.isDevSdkInRange(null /* minExclusive */,
Build.VERSION_CODES.R /* maxInclusive */)) {
@@ -1995,4 +2007,76 @@
assertThrows(SecurityException.class, () -> mCm.setGlobalProxy(
ProxyInfo.buildDirectProxy("example.com" /* host */, 8080 /* port */)));
}
+
+ @Test
+ public void testFactoryResetWithoutPermission() {
+ assumeTrue(TestUtils.shouldTestSApis());
+ assertThrows(SecurityException.class, () -> mCm.factoryReset());
+ }
+
+ @Test
+ public void testFactoryReset() throws Exception {
+ assumeTrue(TestUtils.shouldTestSApis());
+
+ // Store current settings.
+ final int curAvoidBadWifi =
+ ConnectivitySettingsManager.getNetworkAvoidBadWifi(mContext);
+ final int curPrivateDnsMode = ConnectivitySettingsManager.getPrivateDnsMode(mContext);
+
+ final TestTetheringEventCallback tetherEventCallback = new TestTetheringEventCallback();
+ try {
+ mTm.registerTetheringEventCallback(c -> c.run() /* executor */, tetherEventCallback);
+ // Adopt for NETWORK_SETTINGS permission.
+ mUiAutomation.adoptShellPermissionIdentity();
+ // start tethering
+ tetherEventCallback.assumeWifiTetheringSupported(mContext);
+ startWifiTethering(tetherEventCallback);
+ // Update setting to verify the behavior.
+ mCm.setAirplaneMode(true);
+ ConnectivitySettingsManager.setPrivateDnsMode(mContext,
+ ConnectivitySettingsManager.PRIVATE_DNS_MODE_OFF);
+ ConnectivitySettingsManager.setNetworkAvoidBadWifi(mContext,
+ ConnectivitySettingsManager.NETWORK_AVOID_BAD_WIFI_IGNORE);
+ assertEquals(AIRPLANE_MODE_ON, Settings.Global.getInt(
+ mContext.getContentResolver(), Settings.Global.AIRPLANE_MODE_ON));
+ // Verify factoryReset
+ mCm.factoryReset();
+ verifySettings(AIRPLANE_MODE_OFF,
+ ConnectivitySettingsManager.PRIVATE_DNS_MODE_OPPORTUNISTIC,
+ ConnectivitySettingsManager.NETWORK_AVOID_BAD_WIFI_PROMPT);
+
+ tetherEventCallback.expectNoTetheringActive();
+ } finally {
+ // Restore settings.
+ mCm.setAirplaneMode(false);
+ ConnectivitySettingsManager.setNetworkAvoidBadWifi(mContext, curAvoidBadWifi);
+ ConnectivitySettingsManager.setPrivateDnsMode(mContext, curPrivateDnsMode);
+ mTm.unregisterTetheringEventCallback(tetherEventCallback);
+ mTm.stopAllTethering();
+ mUiAutomation.dropShellPermissionIdentity();
+ }
+ }
+
+ private void verifySettings(int expectedAirplaneMode, int expectedPrivateDnsMode,
+ int expectedAvoidBadWifi) throws Exception {
+ assertEquals(expectedAirplaneMode, Settings.Global.getInt(
+ mContext.getContentResolver(), Settings.Global.AIRPLANE_MODE_ON));
+ assertEquals(expectedPrivateDnsMode,
+ ConnectivitySettingsManager.getPrivateDnsMode(mContext));
+ assertEquals(expectedAvoidBadWifi,
+ ConnectivitySettingsManager.getNetworkAvoidBadWifi(mContext));
+ }
+
+ private void startWifiTethering(final TestTetheringEventCallback callback) throws Exception {
+ if (!isWifiTetheringSupported(mContext, callback)) return;
+
+ final List<String> wifiRegexs =
+ callback.getTetheringInterfaceRegexps().getTetherableWifiRegexs();
+ final StartTetheringCallback startTetheringCallback = new StartTetheringCallback();
+ final TetheringRequest request = new TetheringRequest.Builder(TETHERING_WIFI)
+ .setShouldShowEntitlementUi(false).build();
+ mTm.startTethering(request, c -> c.run() /* executor */, startTetheringCallback);
+ startTetheringCallback.verifyTetheringStarted();
+ callback.expectTetheredInterfacesChanged(wifiRegexs, TETHERING_WIFI);
+ }
}
diff --git a/tests/cts/net/src/android/net/cts/IpSecBaseTest.java b/tests/cts/net/src/android/net/cts/IpSecBaseTest.java
index 10e43e7..c54ee91 100644
--- a/tests/cts/net/src/android/net/cts/IpSecBaseTest.java
+++ b/tests/cts/net/src/android/net/cts/IpSecBaseTest.java
@@ -16,6 +16,14 @@
package android.net.cts;
+import static android.net.IpSecAlgorithm.AUTH_CRYPT_AES_GCM;
+import static android.net.IpSecAlgorithm.AUTH_HMAC_MD5;
+import static android.net.IpSecAlgorithm.AUTH_HMAC_SHA1;
+import static android.net.IpSecAlgorithm.AUTH_HMAC_SHA256;
+import static android.net.IpSecAlgorithm.AUTH_HMAC_SHA384;
+import static android.net.IpSecAlgorithm.AUTH_HMAC_SHA512;
+import static android.net.IpSecAlgorithm.CRYPT_AES_CBC;
+
import static org.junit.Assert.assertArrayEquals;
import android.content.Context;
@@ -31,6 +39,12 @@
import androidx.test.InstrumentationRegistry;
import androidx.test.runner.AndroidJUnit4;
+import com.android.modules.utils.build.SdkLevel;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
import java.io.FileDescriptor;
import java.io.IOException;
import java.net.DatagramPacket;
@@ -42,12 +56,10 @@
import java.net.Socket;
import java.net.SocketException;
import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
@RunWith(AndroidJUnit4.class)
public class IpSecBaseTest {
@@ -71,6 +83,18 @@
0x20, 0x21, 0x22, 0x23
};
+ private static final Set<String> MANDATORY_IPSEC_ALGOS_SINCE_P = new HashSet<>();
+
+ static {
+ MANDATORY_IPSEC_ALGOS_SINCE_P.add(CRYPT_AES_CBC);
+ MANDATORY_IPSEC_ALGOS_SINCE_P.add(AUTH_HMAC_MD5);
+ MANDATORY_IPSEC_ALGOS_SINCE_P.add(AUTH_HMAC_SHA1);
+ MANDATORY_IPSEC_ALGOS_SINCE_P.add(AUTH_HMAC_SHA256);
+ MANDATORY_IPSEC_ALGOS_SINCE_P.add(AUTH_HMAC_SHA384);
+ MANDATORY_IPSEC_ALGOS_SINCE_P.add(AUTH_HMAC_SHA512);
+ MANDATORY_IPSEC_ALGOS_SINCE_P.add(AUTH_CRYPT_AES_GCM);
+ }
+
protected static final byte[] AUTH_KEY = getKey(256);
protected static final byte[] CRYPT_KEY = getKey(256);
@@ -89,8 +113,24 @@
.getSystemService(Context.CONNECTIVITY_SERVICE);
}
+ /** Checks if an IPsec algorithm is enabled on the device */
+ protected static boolean hasIpSecAlgorithm(String algorithm) {
+ if (SdkLevel.isAtLeastS()) {
+ return IpSecAlgorithm.getSupportedAlgorithms().contains(algorithm);
+ } else {
+ return MANDATORY_IPSEC_ALGOS_SINCE_P.contains(algorithm);
+ }
+ }
+
+ protected static byte[] getKeyBytes(int byteLength) {
+ return Arrays.copyOf(KEY_DATA, byteLength);
+ }
+
protected static byte[] getKey(int bitLength) {
- return Arrays.copyOf(KEY_DATA, bitLength / 8);
+ if (bitLength % 8 != 0) {
+ throw new IllegalArgumentException("Invalid key length in bits" + bitLength);
+ }
+ return getKeyBytes(bitLength / 8);
}
protected static int getDomain(InetAddress address) {
diff --git a/tests/cts/net/src/android/net/cts/IpSecManagerTest.java b/tests/cts/net/src/android/net/cts/IpSecManagerTest.java
index d08f6e9..e7e1d67 100644
--- a/tests/cts/net/src/android/net/cts/IpSecManagerTest.java
+++ b/tests/cts/net/src/android/net/cts/IpSecManagerTest.java
@@ -16,10 +16,33 @@
package android.net.cts;
+import static android.net.IpSecAlgorithm.AUTH_AES_CMAC;
+import static android.net.IpSecAlgorithm.AUTH_AES_XCBC;
+import static android.net.IpSecAlgorithm.AUTH_CRYPT_AES_GCM;
+import static android.net.IpSecAlgorithm.AUTH_CRYPT_CHACHA20_POLY1305;
+import static android.net.IpSecAlgorithm.AUTH_HMAC_MD5;
+import static android.net.IpSecAlgorithm.AUTH_HMAC_SHA1;
+import static android.net.IpSecAlgorithm.AUTH_HMAC_SHA256;
+import static android.net.IpSecAlgorithm.AUTH_HMAC_SHA384;
+import static android.net.IpSecAlgorithm.AUTH_HMAC_SHA512;
+import static android.net.IpSecAlgorithm.CRYPT_AES_CBC;
+import static android.net.IpSecAlgorithm.CRYPT_AES_CTR;
import static android.net.cts.PacketUtils.AES_CBC_BLK_SIZE;
import static android.net.cts.PacketUtils.AES_CBC_IV_LEN;
+import static android.net.cts.PacketUtils.AES_CMAC_ICV_LEN;
+import static android.net.cts.PacketUtils.AES_CMAC_KEY_LEN;
+import static android.net.cts.PacketUtils.AES_CTR_BLK_SIZE;
+import static android.net.cts.PacketUtils.AES_CTR_IV_LEN;
+import static android.net.cts.PacketUtils.AES_CTR_KEY_LEN;
import static android.net.cts.PacketUtils.AES_GCM_BLK_SIZE;
import static android.net.cts.PacketUtils.AES_GCM_IV_LEN;
+import static android.net.cts.PacketUtils.AES_XCBC_ICV_LEN;
+import static android.net.cts.PacketUtils.AES_XCBC_KEY_LEN;
+import static android.net.cts.PacketUtils.CHACHA20_POLY1305_BLK_SIZE;
+import static android.net.cts.PacketUtils.CHACHA20_POLY1305_ICV_LEN;
+import static android.net.cts.PacketUtils.CHACHA20_POLY1305_IV_LEN;
+import static android.net.cts.PacketUtils.HMAC_SHA512_ICV_LEN;
+import static android.net.cts.PacketUtils.HMAC_SHA512_KEY_LEN;
import static android.net.cts.PacketUtils.IP4_HDRLEN;
import static android.net.cts.PacketUtils.IP6_HDRLEN;
import static android.net.cts.PacketUtils.TCP_HDRLEN_WITH_TIMESTAMP_OPT;
@@ -27,15 +50,20 @@
import static android.system.OsConstants.IPPROTO_TCP;
import static android.system.OsConstants.IPPROTO_UDP;
+import static com.android.compatibility.common.util.PropertyUtil.getFirstApiLevel;
+import static com.android.compatibility.common.util.PropertyUtil.getVendorApiLevel;
+
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
+import static org.junit.Assume.assumeTrue;
import android.net.IpSecAlgorithm;
import android.net.IpSecManager;
import android.net.IpSecTransform;
import android.net.TrafficStats;
+import android.os.Build;
import android.platform.test.annotations.AppModeFull;
import android.system.ErrnoException;
import android.system.Os;
@@ -44,8 +72,11 @@
import androidx.test.InstrumentationRegistry;
import androidx.test.runner.AndroidJUnit4;
+import com.android.testutils.DevSdkIgnoreRule;
+import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo;
import com.android.testutils.SkipPresubmit;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -56,10 +87,15 @@
import java.net.Inet6Address;
import java.net.InetAddress;
import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
@RunWith(AndroidJUnit4.class)
@AppModeFull(reason = "Socket cannot bind in instant app mode")
public class IpSecManagerTest extends IpSecBaseTest {
+ @Rule public final DevSdkIgnoreRule ignoreRule = new DevSdkIgnoreRule();
private static final String TAG = IpSecManagerTest.class.getSimpleName();
@@ -417,8 +453,12 @@
switch (cryptOrAead.getName()) {
case IpSecAlgorithm.CRYPT_AES_CBC:
return AES_CBC_IV_LEN;
+ case IpSecAlgorithm.CRYPT_AES_CTR:
+ return AES_CTR_IV_LEN;
case IpSecAlgorithm.AUTH_CRYPT_AES_GCM:
return AES_GCM_IV_LEN;
+ case IpSecAlgorithm.AUTH_CRYPT_CHACHA20_POLY1305:
+ return CHACHA20_POLY1305_IV_LEN;
default:
throw new IllegalArgumentException(
"IV length unknown for algorithm" + cryptOrAead.getName());
@@ -433,8 +473,12 @@
switch (cryptOrAead.getName()) {
case IpSecAlgorithm.CRYPT_AES_CBC:
return AES_CBC_BLK_SIZE;
+ case IpSecAlgorithm.CRYPT_AES_CTR:
+ return AES_CTR_BLK_SIZE;
case IpSecAlgorithm.AUTH_CRYPT_AES_GCM:
return AES_GCM_BLK_SIZE;
+ case IpSecAlgorithm.AUTH_CRYPT_CHACHA20_POLY1305:
+ return CHACHA20_POLY1305_BLK_SIZE;
default:
throw new IllegalArgumentException(
"Blk size unknown for algorithm" + cryptOrAead.getName());
@@ -516,7 +560,6 @@
int blkSize,
int truncLenBits)
throws Exception {
-
int innerPacketSize = TEST_DATA.length + transportHdrLen + ipHdrLen;
int outerPacketSize =
PacketUtils.calculateEspPacketSize(
@@ -663,6 +706,41 @@
// checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, crypt, auth, true, 1000);
// }
+ @IgnoreUpTo(Build.VERSION_CODES.R)
+ @Test
+ public void testGetSupportedAlgorithms() throws Exception {
+ final Map<String, Integer> algoToRequiredMinSdk = new HashMap<>();
+ algoToRequiredMinSdk.put(CRYPT_AES_CBC, Build.VERSION_CODES.P);
+ algoToRequiredMinSdk.put(AUTH_HMAC_MD5, Build.VERSION_CODES.P);
+ algoToRequiredMinSdk.put(AUTH_HMAC_SHA1, Build.VERSION_CODES.P);
+ algoToRequiredMinSdk.put(AUTH_HMAC_SHA256, Build.VERSION_CODES.P);
+ algoToRequiredMinSdk.put(AUTH_HMAC_SHA384, Build.VERSION_CODES.P);
+ algoToRequiredMinSdk.put(AUTH_HMAC_SHA512, Build.VERSION_CODES.P);
+ algoToRequiredMinSdk.put(AUTH_CRYPT_AES_GCM, Build.VERSION_CODES.P);
+
+ // TODO: b/170424293 Use Build.VERSION_CODES.S when is finalized
+ algoToRequiredMinSdk.put(CRYPT_AES_CTR, Build.VERSION_CODES.R + 1);
+ algoToRequiredMinSdk.put(AUTH_AES_CMAC, Build.VERSION_CODES.R + 1);
+ algoToRequiredMinSdk.put(AUTH_AES_XCBC, Build.VERSION_CODES.R + 1);
+ algoToRequiredMinSdk.put(AUTH_CRYPT_CHACHA20_POLY1305, Build.VERSION_CODES.R + 1);
+
+ final Set<String> supportedAlgos = IpSecAlgorithm.getSupportedAlgorithms();
+
+ // Verify all supported algorithms are valid
+ for (String algo : supportedAlgos) {
+ assertTrue("Found invalid algo " + algo, algoToRequiredMinSdk.keySet().contains(algo));
+ }
+
+ // Verify all mandatory algorithms are supported
+ for (Entry<String, Integer> entry : algoToRequiredMinSdk.entrySet()) {
+ if (Math.min(getFirstApiLevel(), getVendorApiLevel()) >= entry.getValue()) {
+ assertTrue(
+ "Fail to support " + entry.getKey(),
+ supportedAlgos.contains(entry.getKey()));
+ }
+ }
+ }
+
@Test
public void testInterfaceCountersUdp4() throws Exception {
IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY);
@@ -849,6 +927,152 @@
checkTransform(IPPROTO_UDP, IPV6_LOOPBACK, crypt, auth, null, false, 1, true);
}
+ private static IpSecAlgorithm buildCryptAesCtr() throws Exception {
+ return new IpSecAlgorithm(CRYPT_AES_CTR, getKeyBytes(AES_CTR_KEY_LEN));
+ }
+
+ private static IpSecAlgorithm buildAuthHmacSha512() throws Exception {
+ return new IpSecAlgorithm(
+ AUTH_HMAC_SHA512, getKeyBytes(HMAC_SHA512_KEY_LEN), HMAC_SHA512_ICV_LEN * 8);
+ }
+
+ @Test
+ public void testAesCtrHmacSha512Tcp4() throws Exception {
+ assumeTrue(hasIpSecAlgorithm(CRYPT_AES_CTR));
+
+ final IpSecAlgorithm crypt = buildCryptAesCtr();
+ final IpSecAlgorithm auth = buildAuthHmacSha512();
+ checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, crypt, auth, null, false, 1, false);
+ checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, crypt, auth, null, false, 1, true);
+ }
+
+ @Test
+ @SkipPresubmit(reason = "b/186608065 - kernel 5.10 regression in TrafficStats with ipsec")
+ public void testAesCtrHmacSha512Tcp6() throws Exception {
+ assumeTrue(hasIpSecAlgorithm(CRYPT_AES_CTR));
+
+ final IpSecAlgorithm crypt = buildCryptAesCtr();
+ final IpSecAlgorithm auth = buildAuthHmacSha512();
+ checkTransform(IPPROTO_TCP, IPV6_LOOPBACK, crypt, auth, null, false, 1, false);
+ checkTransform(IPPROTO_TCP, IPV6_LOOPBACK, crypt, auth, null, false, 1, true);
+ }
+
+ @Test
+ public void testAesCtrHmacSha512Udp4() throws Exception {
+ assumeTrue(hasIpSecAlgorithm(CRYPT_AES_CTR));
+
+ final IpSecAlgorithm crypt = buildCryptAesCtr();
+ final IpSecAlgorithm auth = buildAuthHmacSha512();
+ checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, crypt, auth, null, false, 1, false);
+ checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, crypt, auth, null, false, 1, true);
+ }
+
+ @Test
+ public void testAesCtrHmacSha512Udp6() throws Exception {
+ assumeTrue(hasIpSecAlgorithm(CRYPT_AES_CTR));
+
+ final IpSecAlgorithm crypt = buildCryptAesCtr();
+ final IpSecAlgorithm auth = buildAuthHmacSha512();
+ checkTransform(IPPROTO_UDP, IPV6_LOOPBACK, crypt, auth, null, false, 1, false);
+ checkTransform(IPPROTO_UDP, IPV6_LOOPBACK, crypt, auth, null, false, 1, true);
+ }
+
+ private static IpSecAlgorithm buildCryptAesCbc() throws Exception {
+ return new IpSecAlgorithm(CRYPT_AES_CBC, CRYPT_KEY);
+ }
+
+ private static IpSecAlgorithm buildAuthAesXcbc() throws Exception {
+ return new IpSecAlgorithm(
+ AUTH_AES_XCBC, getKeyBytes(AES_XCBC_KEY_LEN), AES_XCBC_ICV_LEN * 8);
+ }
+
+ private static IpSecAlgorithm buildAuthAesCmac() throws Exception {
+ return new IpSecAlgorithm(
+ AUTH_AES_CMAC, getKeyBytes(AES_CMAC_KEY_LEN), AES_CMAC_ICV_LEN * 8);
+ }
+
+ @Test
+ public void testAesCbcAesXCbcTcp4() throws Exception {
+ assumeTrue(hasIpSecAlgorithm(AUTH_AES_XCBC));
+
+ final IpSecAlgorithm crypt = buildCryptAesCbc();
+ final IpSecAlgorithm auth = buildAuthAesXcbc();
+ checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, crypt, auth, null, false, 1, false);
+ checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, crypt, auth, null, false, 1, true);
+ }
+
+ @Test
+ @SkipPresubmit(reason = "b/186608065 - kernel 5.10 regression in TrafficStats with ipsec")
+ public void testAesCbcAesXCbcTcp6() throws Exception {
+ assumeTrue(hasIpSecAlgorithm(AUTH_AES_XCBC));
+
+ final IpSecAlgorithm crypt = buildCryptAesCbc();
+ final IpSecAlgorithm auth = buildAuthAesXcbc();
+ checkTransform(IPPROTO_TCP, IPV6_LOOPBACK, crypt, auth, null, false, 1, false);
+ checkTransform(IPPROTO_TCP, IPV6_LOOPBACK, crypt, auth, null, false, 1, true);
+ }
+
+ @Test
+ public void testAesCbcAesXCbcUdp4() throws Exception {
+ assumeTrue(hasIpSecAlgorithm(AUTH_AES_XCBC));
+
+ final IpSecAlgorithm crypt = buildCryptAesCbc();
+ final IpSecAlgorithm auth = buildAuthAesXcbc();
+ checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, crypt, auth, null, false, 1, false);
+ checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, crypt, auth, null, false, 1, true);
+ }
+
+ @Test
+ public void testAesCbcAesXCbcUdp6() throws Exception {
+ assumeTrue(hasIpSecAlgorithm(AUTH_AES_XCBC));
+
+ final IpSecAlgorithm crypt = buildCryptAesCbc();
+ final IpSecAlgorithm auth = buildAuthAesXcbc();
+ checkTransform(IPPROTO_UDP, IPV6_LOOPBACK, crypt, auth, null, false, 1, false);
+ checkTransform(IPPROTO_UDP, IPV6_LOOPBACK, crypt, auth, null, false, 1, true);
+ }
+
+ @Test
+ public void testAesCbcAesCmacTcp4() throws Exception {
+ assumeTrue(hasIpSecAlgorithm(AUTH_AES_CMAC));
+
+ final IpSecAlgorithm crypt = buildCryptAesCbc();
+ final IpSecAlgorithm auth = buildAuthAesCmac();
+ checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, crypt, auth, null, false, 1, false);
+ checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, crypt, auth, null, false, 1, true);
+ }
+
+ @Test
+ @SkipPresubmit(reason = "b/186608065 - kernel 5.10 regression in TrafficStats with ipsec")
+ public void testAesCbcAesCmacTcp6() throws Exception {
+ assumeTrue(hasIpSecAlgorithm(AUTH_AES_CMAC));
+
+ final IpSecAlgorithm crypt = buildCryptAesCbc();
+ final IpSecAlgorithm auth = buildAuthAesCmac();
+ checkTransform(IPPROTO_TCP, IPV6_LOOPBACK, crypt, auth, null, false, 1, false);
+ checkTransform(IPPROTO_TCP, IPV6_LOOPBACK, crypt, auth, null, false, 1, true);
+ }
+
+ @Test
+ public void testAesCbcAesCmacUdp4() throws Exception {
+ assumeTrue(hasIpSecAlgorithm(AUTH_AES_CMAC));
+
+ final IpSecAlgorithm crypt = buildCryptAesCbc();
+ final IpSecAlgorithm auth = buildAuthAesCmac();
+ checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, crypt, auth, null, false, 1, false);
+ checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, crypt, auth, null, false, 1, true);
+ }
+
+ @Test
+ public void testAesCbcAesCmacUdp6() throws Exception {
+ assumeTrue(hasIpSecAlgorithm(AUTH_AES_CMAC));
+
+ final IpSecAlgorithm crypt = buildCryptAesCbc();
+ final IpSecAlgorithm auth = buildAuthAesCmac();
+ checkTransform(IPPROTO_UDP, IPV6_LOOPBACK, crypt, auth, null, false, 1, false);
+ checkTransform(IPPROTO_UDP, IPV6_LOOPBACK, crypt, auth, null, false, 1, true);
+ }
+
@Test
public void testAesGcm64Tcp4() throws Exception {
IpSecAlgorithm authCrypt =
@@ -948,6 +1172,48 @@
checkTransform(IPPROTO_UDP, IPV6_LOOPBACK, null, null, authCrypt, false, 1, true);
}
+ private static IpSecAlgorithm buildAuthCryptChaCha20Poly1305() throws Exception {
+ return new IpSecAlgorithm(
+ AUTH_CRYPT_CHACHA20_POLY1305, AEAD_KEY, CHACHA20_POLY1305_ICV_LEN * 8);
+ }
+
+ @Test
+ public void testChaCha20Poly1305Tcp4() throws Exception {
+ assumeTrue(hasIpSecAlgorithm(AUTH_CRYPT_CHACHA20_POLY1305));
+
+ final IpSecAlgorithm authCrypt = buildAuthCryptChaCha20Poly1305();
+ checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, null, null, authCrypt, false, 1, false);
+ checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, null, null, authCrypt, false, 1, true);
+ }
+
+ @Test
+ @SkipPresubmit(reason = "b/186608065 - kernel 5.10 regression in TrafficStats with ipsec")
+ public void testChaCha20Poly1305Tcp6() throws Exception {
+ assumeTrue(hasIpSecAlgorithm(AUTH_CRYPT_CHACHA20_POLY1305));
+
+ final IpSecAlgorithm authCrypt = buildAuthCryptChaCha20Poly1305();
+ checkTransform(IPPROTO_TCP, IPV6_LOOPBACK, null, null, authCrypt, false, 1, false);
+ checkTransform(IPPROTO_TCP, IPV6_LOOPBACK, null, null, authCrypt, false, 1, true);
+ }
+
+ @Test
+ public void testChaCha20Poly1305Udp4() throws Exception {
+ assumeTrue(hasIpSecAlgorithm(AUTH_CRYPT_CHACHA20_POLY1305));
+
+ final IpSecAlgorithm authCrypt = buildAuthCryptChaCha20Poly1305();
+ checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, null, null, authCrypt, false, 1, false);
+ checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, null, null, authCrypt, false, 1, true);
+ }
+
+ @Test
+ public void testChaCha20Poly1305Udp6() throws Exception {
+ assumeTrue(hasIpSecAlgorithm(AUTH_CRYPT_CHACHA20_POLY1305));
+
+ final IpSecAlgorithm authCrypt = buildAuthCryptChaCha20Poly1305();
+ checkTransform(IPPROTO_UDP, IPV6_LOOPBACK, null, null, authCrypt, false, 1, false);
+ checkTransform(IPPROTO_UDP, IPV6_LOOPBACK, null, null, authCrypt, false, 1, true);
+ }
+
@Test
public void testAesCbcHmacMd5Tcp4UdpEncap() throws Exception {
IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY);
@@ -1029,6 +1295,66 @@
}
@Test
+ public void testAesCtrHmacSha512Tcp4UdpEncap() throws Exception {
+ assumeTrue(hasIpSecAlgorithm(CRYPT_AES_CTR));
+
+ final IpSecAlgorithm crypt = buildCryptAesCtr();
+ final IpSecAlgorithm auth = buildAuthHmacSha512();
+ checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, crypt, auth, null, true, 1, false);
+ checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, crypt, auth, null, true, 1, true);
+ }
+
+ @Test
+ public void testAesCtrHmacSha512Udp4UdpEncap() throws Exception {
+ assumeTrue(hasIpSecAlgorithm(CRYPT_AES_CTR));
+
+ final IpSecAlgorithm crypt = buildCryptAesCtr();
+ final IpSecAlgorithm auth = buildAuthHmacSha512();
+ checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, crypt, auth, null, true, 1, false);
+ checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, crypt, auth, null, true, 1, true);
+ }
+
+ @Test
+ public void testAesCbcAesXCbcTcp4UdpEncap() throws Exception {
+ assumeTrue(hasIpSecAlgorithm(AUTH_AES_XCBC));
+
+ final IpSecAlgorithm crypt = new IpSecAlgorithm(CRYPT_AES_CBC, CRYPT_KEY);
+ final IpSecAlgorithm auth = new IpSecAlgorithm(AUTH_AES_XCBC, getKey(128), 96);
+ checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, crypt, auth, null, true, 1, false);
+ checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, crypt, auth, null, true, 1, true);
+ }
+
+ @Test
+ public void testAesCbcAesXCbcUdp4UdpEncap() throws Exception {
+ assumeTrue(hasIpSecAlgorithm(AUTH_AES_XCBC));
+
+ final IpSecAlgorithm crypt = new IpSecAlgorithm(CRYPT_AES_CBC, CRYPT_KEY);
+ final IpSecAlgorithm auth = new IpSecAlgorithm(AUTH_AES_XCBC, getKey(128), 96);
+ checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, crypt, auth, null, true, 1, false);
+ checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, crypt, auth, null, true, 1, true);
+ }
+
+ @Test
+ public void testAesCbcAesCmacTcp4UdpEncap() throws Exception {
+ assumeTrue(hasIpSecAlgorithm(AUTH_AES_CMAC));
+
+ final IpSecAlgorithm crypt = new IpSecAlgorithm(CRYPT_AES_CBC, CRYPT_KEY);
+ final IpSecAlgorithm auth = new IpSecAlgorithm(AUTH_AES_CMAC, getKey(128), 96);
+ checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, crypt, auth, null, true, 1, false);
+ checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, crypt, auth, null, true, 1, true);
+ }
+
+ @Test
+ public void testAesCbcAesCmacUdp4UdpEncap() throws Exception {
+ assumeTrue(hasIpSecAlgorithm(AUTH_AES_CMAC));
+
+ final IpSecAlgorithm crypt = new IpSecAlgorithm(CRYPT_AES_CBC, CRYPT_KEY);
+ final IpSecAlgorithm auth = new IpSecAlgorithm(AUTH_AES_CMAC, getKey(128), 96);
+ checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, crypt, auth, null, true, 1, false);
+ checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, crypt, auth, null, true, 1, true);
+ }
+
+ @Test
public void testAesGcm64Tcp4UdpEncap() throws Exception {
IpSecAlgorithm authCrypt =
new IpSecAlgorithm(IpSecAlgorithm.AUTH_CRYPT_AES_GCM, AEAD_KEY, 64);
@@ -1077,6 +1403,24 @@
}
@Test
+ public void testChaCha20Poly1305Tcp4UdpEncap() throws Exception {
+ assumeTrue(hasIpSecAlgorithm(AUTH_CRYPT_CHACHA20_POLY1305));
+
+ final IpSecAlgorithm authCrypt = buildAuthCryptChaCha20Poly1305();
+ checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, null, null, authCrypt, true, 1, false);
+ checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, null, null, authCrypt, true, 1, true);
+ }
+
+ @Test
+ public void testChaCha20Poly1305Udp4UdpEncap() throws Exception {
+ assumeTrue(hasIpSecAlgorithm(AUTH_CRYPT_CHACHA20_POLY1305));
+
+ final IpSecAlgorithm authCrypt = buildAuthCryptChaCha20Poly1305();
+ checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, null, null, authCrypt, true, 1, false);
+ checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, null, null, authCrypt, true, 1, true);
+ }
+
+ @Test
public void testCryptUdp4() throws Exception {
IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY);
checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, crypt, null, null, false, 1, false);
diff --git a/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt b/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt
index 1c9aba1..8e2b310 100644
--- a/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt
+++ b/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt
@@ -306,6 +306,11 @@
return foundCallback
}
+ inline fun <reified T : CallbackEntry> eventuallyExpect() =
+ history.poll(DEFAULT_TIMEOUT_MS) { it is T }.also {
+ assertNotNull(it, "Callback ${T::class} not received")
+ } as T
+
fun assertNoCallback() {
assertTrue(waitForIdle(DEFAULT_TIMEOUT_MS),
"Handler didn't became idle after ${DEFAULT_TIMEOUT_MS}ms")
@@ -383,13 +388,12 @@
callback.expectAvailableThenValidatedCallbacks(agent.network)
agent.expectEmptySignalStrengths()
agent.expectNoInternetValidationStatus()
- agent.unregister()
+
+ unregister(agent)
callback.expectCallback<Lost>(agent.network)
- agent.expectCallback<OnNetworkUnwanted>()
assertFailsWith<IllegalStateException>("Must not be able to register an agent twice") {
agent.register()
}
- agent.expectCallback<OnNetworkDestroyed>()
}
@Test
@@ -400,7 +404,7 @@
agent.expectNoInternetValidationStatus()
mCM.requestBandwidthUpdate(agent.network)
agent.expectCallback<OnBandwidthUpdateRequested>()
- agent.unregister()
+ unregister(agent)
}
@Test
@@ -648,10 +652,16 @@
}
}
- agent.unregister()
+ unregister(agent)
callback.expectCallback<Lost>(agent.network)
}
+ private fun unregister(agent: TestableNetworkAgent) {
+ agent.unregister()
+ agent.eventuallyExpect<OnNetworkUnwanted>()
+ agent.eventuallyExpect<OnNetworkDestroyed>()
+ }
+
@Test
@IgnoreUpTo(Build.VERSION_CODES.R)
fun testAgentStartsInConnecting() {
diff --git a/tests/cts/net/src/android/net/cts/NetworkScoreTest.kt b/tests/cts/net/src/android/net/cts/NetworkScoreTest.kt
new file mode 100644
index 0000000..8f17199
--- /dev/null
+++ b/tests/cts/net/src/android/net/cts/NetworkScoreTest.kt
@@ -0,0 +1,217 @@
+/*
+ * Copyright (C) 2021 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 android.net.cts
+
+import android.Manifest.permission.MANAGE_TEST_NETWORKS
+import android.content.Context
+import android.net.ConnectivityManager
+import android.net.LinkProperties
+import android.net.NetworkAgent
+import android.net.NetworkAgentConfig
+import android.net.NetworkCapabilities
+import android.net.NetworkProvider
+import android.net.NetworkRequest
+import android.net.NetworkScore
+import android.net.VpnManager
+import android.net.VpnTransportInfo
+import android.os.Build
+import android.os.Handler
+import android.os.HandlerThread
+import androidx.test.InstrumentationRegistry
+import com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity
+import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo
+import com.android.testutils.DevSdkIgnoreRunner
+import com.android.testutils.TestableNetworkCallback
+import com.android.testutils.TestableNetworkCallback.HasNetwork
+import org.junit.After
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+// This test doesn't really have a constraint on how fast the methods should return. If it's
+// going to fail, it will simply wait forever, so setting a high timeout lowers the flake ratio
+// without affecting the run time of successful runs. Thus, set a very high timeout.
+private const val TIMEOUT_MS = 30_000L
+// When waiting for a NetworkCallback to determine there was no timeout, waiting is the
+// only possible thing (the relevant handler is the one in the real ConnectivityService,
+// and then there is the Binder call), so have a short timeout for this as it will be
+// exhausted every time.
+private const val NO_CALLBACK_TIMEOUT = 200L
+
+private val testContext: Context
+ get() = InstrumentationRegistry.getContext()
+
+private fun score(exiting: Boolean = false, primary: Boolean = false) =
+ NetworkScore.Builder().setExiting(exiting).setTransportPrimary(primary)
+ // TODO : have a constant KEEP_CONNECTED_FOR_TEST ?
+ .setKeepConnectedReason(NetworkScore.KEEP_CONNECTED_FOR_HANDOVER)
+ .build()
+
+@IgnoreUpTo(Build.VERSION_CODES.R)
+@RunWith(DevSdkIgnoreRunner::class)
+class NetworkScoreTest {
+ private val mCm = testContext.getSystemService(ConnectivityManager::class.java)
+ private val mHandlerThread = HandlerThread("${javaClass.simpleName} handler thread")
+ private val mHandler by lazy { Handler(mHandlerThread.looper) }
+ private val agentsToCleanUp = mutableListOf<NetworkAgent>()
+ private val callbacksToCleanUp = mutableListOf<TestableNetworkCallback>()
+
+ @Before
+ fun setUp() {
+ mHandlerThread.start()
+ }
+
+ @After
+ fun tearDown() {
+ agentsToCleanUp.forEach { it.unregister() }
+ mHandlerThread.quitSafely()
+ callbacksToCleanUp.forEach { mCm.unregisterNetworkCallback(it) }
+ }
+
+ // Returns a networkCallback that sends onAvailable on the best network with TRANSPORT_TEST.
+ private fun makeTestNetworkCallback() = TestableNetworkCallback(TIMEOUT_MS).also { cb ->
+ mCm.registerBestMatchingNetworkCallback(NetworkRequest.Builder().clearCapabilities()
+ .addTransportType(NetworkCapabilities.TRANSPORT_TEST).build(), cb, mHandler)
+ callbacksToCleanUp.add(cb)
+ }
+
+ // TestNetworkCallback is made to interact with a wrapper of NetworkAgent, because it's
+ // made for ConnectivityServiceTest.
+ // TODO : have TestNetworkCallback work for NetworkAgent too and remove this class.
+ private class AgentWrapper(val agent: NetworkAgent) : HasNetwork {
+ override val network = agent.network
+ fun sendNetworkScore(s: NetworkScore) = agent.sendNetworkScore(s)
+ }
+
+ private fun createTestNetworkAgent(
+ // The network always has TRANSPORT_TEST, plus optional transports
+ optionalTransports: IntArray = IntArray(size = 0),
+ everUserSelected: Boolean = false,
+ acceptUnvalidated: Boolean = false,
+ isExiting: Boolean = false,
+ isPrimary: Boolean = false
+ ): AgentWrapper {
+ val nc = NetworkCapabilities.Builder().apply {
+ addTransportType(NetworkCapabilities.TRANSPORT_TEST)
+ optionalTransports.forEach { addTransportType(it) }
+ // Add capabilities that are common, just for realism. It's not strictly necessary
+ addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED)
+ addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING)
+ // Remove capabilities that a test network agent shouldn't have and that are not
+ // needed for the purposes of this test.
+ removeCapability(NetworkCapabilities.NET_CAPABILITY_TRUSTED)
+ removeCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
+ removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED)
+ if (optionalTransports.contains(NetworkCapabilities.TRANSPORT_VPN)) {
+ addTransportType(NetworkCapabilities.TRANSPORT_VPN)
+ removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN)
+ setTransportInfo(VpnTransportInfo(VpnManager.TYPE_VPN_SERVICE, null))
+ }
+ addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED)
+ }.build()
+ val config = NetworkAgentConfig.Builder()
+ .setExplicitlySelected(everUserSelected)
+ .setUnvalidatedConnectivityAcceptable(acceptUnvalidated)
+ .build()
+ val score = score(exiting = isExiting, primary = isPrimary)
+ val context = testContext
+ val looper = mHandlerThread.looper
+ val agent = object : NetworkAgent(context, looper, "NetworkScore test agent", nc,
+ LinkProperties(), score, config, NetworkProvider(context, looper,
+ "NetworkScore test provider")) {}.also {
+ agentsToCleanUp.add(it)
+ }
+ runWithShellPermissionIdentity({ agent.register() }, MANAGE_TEST_NETWORKS)
+ agent.markConnected()
+ return AgentWrapper(agent)
+ }
+
+ @Test
+ fun testExitingLosesAndOldSatisfierWins() {
+ val cb = makeTestNetworkCallback()
+ val agent1 = createTestNetworkAgent()
+ cb.expectAvailableThenValidatedCallbacks(agent1)
+ val agent2 = createTestNetworkAgent()
+ // Because the existing network must win, the callback stays on agent1.
+ cb.assertNoCallback(NO_CALLBACK_TIMEOUT)
+ agent1.sendNetworkScore(score(exiting = true))
+ // Now that agent1 is exiting, the callback is satisfied by agent2.
+ cb.expectAvailableCallbacks(agent2.network)
+ agent1.sendNetworkScore(score(exiting = false))
+ // Agent1 is no longer exiting, but agent2 is the current satisfier.
+ cb.assertNoCallback(NO_CALLBACK_TIMEOUT)
+ }
+
+ @Test
+ fun testVpnWins() {
+ val cb = makeTestNetworkCallback()
+ val agent1 = createTestNetworkAgent()
+ cb.expectAvailableThenValidatedCallbacks(agent1.network)
+ val agent2 = createTestNetworkAgent(intArrayOf(NetworkCapabilities.TRANSPORT_VPN))
+ // VPN wins out against agent1 even before it's validated (hence the "then validated",
+ // because it becomes the best network for this callback before it validates)
+ cb.expectAvailableThenValidatedCallbacks(agent2.network)
+ }
+
+ @Test
+ fun testEverUserSelectedAcceptUnvalidatedWins() {
+ val cb = makeTestNetworkCallback()
+ val agent1 = createTestNetworkAgent()
+ cb.expectAvailableThenValidatedCallbacks(agent1.network)
+ val agent2 = createTestNetworkAgent(everUserSelected = true, acceptUnvalidated = true)
+ // agent2 wins out against agent1 even before it's validated, because user-selected and
+ // accept unvalidated networks should win against even networks that are validated.
+ cb.expectAvailableThenValidatedCallbacks(agent2.network)
+ }
+
+ @Test
+ fun testPreferredTransportOrder() {
+ val cb = makeTestNetworkCallback()
+ val agentCell = createTestNetworkAgent(intArrayOf(NetworkCapabilities.TRANSPORT_CELLULAR))
+ cb.expectAvailableThenValidatedCallbacks(agentCell.network)
+ val agentWifi = createTestNetworkAgent(intArrayOf(NetworkCapabilities.TRANSPORT_WIFI))
+ // In the absence of other discriminating factors, agentWifi wins against agentCell because
+ // of its better transport, but only after it validates.
+ cb.expectAvailableDoubleValidatedCallbacks(agentWifi)
+ val agentEth = createTestNetworkAgent(intArrayOf(NetworkCapabilities.TRANSPORT_ETHERNET))
+ // Likewise, agentEth wins against agentWifi after validation because of its better
+ // transport.
+ cb.expectAvailableCallbacksValidated(agentEth)
+ }
+
+ @Test
+ fun testTransportPrimary() {
+ val cb = makeTestNetworkCallback()
+ val agent1 = createTestNetworkAgent()
+ cb.expectAvailableThenValidatedCallbacks(agent1)
+ val agent2 = createTestNetworkAgent()
+ // Because the existing network must win, the callback stays on agent1.
+ cb.assertNoCallback(NO_CALLBACK_TIMEOUT)
+ agent2.sendNetworkScore(score(primary = true))
+ // Now that agent2 is primary, the callback is satisfied by agent2.
+ cb.expectAvailableCallbacks(agent2.network)
+ agent1.sendNetworkScore(score(primary = true))
+ // Agent1 is primary too, but agent2 is the current satisfier
+ cb.assertNoCallback(NO_CALLBACK_TIMEOUT)
+ agent2.sendNetworkScore(score(primary = false))
+ // Now agent1 is primary and agent2 isn't
+ cb.expectAvailableCallbacks(agent1.network)
+ }
+
+ // TODO (b/187929636) : add a test making sure that validated networks win over unvalidated
+ // ones. Right now this is not possible because this CTS can't directly manipulate the
+ // validation state of a network.
+}
diff --git a/tests/cts/net/src/android/net/cts/PacketUtils.java b/tests/cts/net/src/android/net/cts/PacketUtils.java
index 0aedecb..7e622f6 100644
--- a/tests/cts/net/src/android/net/cts/PacketUtils.java
+++ b/tests/cts/net/src/android/net/cts/PacketUtils.java
@@ -43,17 +43,35 @@
static final int UDP_HDRLEN = 8;
static final int TCP_HDRLEN = 20;
static final int TCP_HDRLEN_WITH_TIMESTAMP_OPT = TCP_HDRLEN + 12;
+ static final int ESP_BLK_SIZE = 4; // ESP has to be 4-byte aligned
// Not defined in OsConstants
static final int IPPROTO_IPV4 = 4;
static final int IPPROTO_ESP = 50;
// Encryption parameters
- static final int AES_GCM_IV_LEN = 8;
static final int AES_CBC_IV_LEN = 16;
- static final int AES_GCM_BLK_SIZE = 4;
static final int AES_CBC_BLK_SIZE = 16;
+ static final int AES_CTR_KEY_LEN = 20;
+ static final int AES_CTR_BLK_SIZE = ESP_BLK_SIZE;
+ static final int AES_CTR_IV_LEN = 8;
+
+ // AEAD parameters
+ static final int AES_GCM_IV_LEN = 8;
+ static final int AES_GCM_BLK_SIZE = 4;
+ static final int CHACHA20_POLY1305_BLK_SIZE = ESP_BLK_SIZE;
+ static final int CHACHA20_POLY1305_IV_LEN = 8;
+ static final int CHACHA20_POLY1305_ICV_LEN = 16;
+
+ // Authentication parameters
+ static final int HMAC_SHA512_KEY_LEN = 64;
+ static final int HMAC_SHA512_ICV_LEN = 32;
+ static final int AES_XCBC_KEY_LEN = 16;
+ static final int AES_XCBC_ICV_LEN = 12;
+ static final int AES_CMAC_KEY_LEN = 16;
+ static final int AES_CMAC_ICV_LEN = 12;
+
// Encryption algorithms
static final String AES = "AES";
static final String AES_CBC = "AES/CBC/NoPadding";
diff --git a/tests/cts/net/util/Android.bp b/tests/cts/net/util/Android.bp
index 88a2068..b5f1208 100644
--- a/tests/cts/net/util/Android.bp
+++ b/tests/cts/net/util/Android.bp
@@ -26,5 +26,6 @@
"compatibility-device-util-axt",
"junit",
"net-tests-utils",
+ "modules-utils-build",
],
}
diff --git a/tests/cts/net/util/java/android/net/cts/util/CtsNetUtils.java b/tests/cts/net/util/java/android/net/cts/util/CtsNetUtils.java
index d5a26c4..b32218b 100644
--- a/tests/cts/net/util/java/android/net/cts/util/CtsNetUtils.java
+++ b/tests/cts/net/util/java/android/net/cts/util/CtsNetUtils.java
@@ -23,6 +23,7 @@
import static android.net.NetworkCapabilities.TRANSPORT_TEST;
import static android.net.wifi.WifiManager.SCAN_RESULTS_AVAILABLE_ACTION;
+import static com.android.compatibility.common.util.PropertyUtil.getFirstApiLevel;
import static com.android.testutils.TestPermissionUtil.runAsShell;
import static org.junit.Assert.assertEquals;
@@ -55,7 +56,6 @@
import android.os.Binder;
import android.os.Build;
import android.os.IBinder;
-import android.os.SystemProperties;
import android.provider.Settings;
import android.system.Os;
import android.system.OsConstants;
@@ -87,6 +87,7 @@
private static final int PRIVATE_DNS_SETTING_TIMEOUT_MS = 10_000;
private static final int CONNECTIVITY_CHANGE_TIMEOUT_SECS = 30;
private static final String PRIVATE_DNS_MODE_OPPORTUNISTIC = "opportunistic";
+ private static final String PRIVATE_DNS_MODE_STRICT = "hostname";
public static final int HTTP_PORT = 80;
public static final String TEST_HOST = "connectivitycheck.gstatic.com";
public static final String HTTP_REQUEST =
@@ -116,8 +117,7 @@
/** Checks if FEATURE_IPSEC_TUNNELS is enabled on the device */
public boolean hasIpsecTunnelsFeature() {
return mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_IPSEC_TUNNELS)
- || SystemProperties.getInt("ro.product.first_api_level", 0)
- >= Build.VERSION_CODES.Q;
+ || getFirstApiLevel() >= Build.VERSION_CODES.Q;
}
/**
@@ -524,12 +524,17 @@
}
public void restorePrivateDnsSetting() throws InterruptedException {
- if (mOldPrivateDnsMode == null || mOldPrivateDnsSpecifier == null) {
- return;
+ if (mOldPrivateDnsMode == null) {
+ fail("restorePrivateDnsSetting without storing settings first");
}
// restore private DNS setting
- if ("hostname".equals(mOldPrivateDnsMode)) {
+ if (PRIVATE_DNS_MODE_STRICT.equals(mOldPrivateDnsMode)) {
setPrivateDnsStrictMode(mOldPrivateDnsSpecifier);
+
+ // In case of invalid setting, still restore it but fail the test
+ if (mOldPrivateDnsSpecifier == null) {
+ fail("Invalid private DNS setting: no hostname specified in strict mode");
+ }
awaitPrivateDnsSetting("restorePrivateDnsSetting timeout",
mCm.getActiveNetwork(),
mOldPrivateDnsSpecifier, true);
@@ -540,13 +545,14 @@
public void setPrivateDnsStrictMode(String server) {
// To reduce flake rate, set PRIVATE_DNS_SPECIFIER before PRIVATE_DNS_MODE. This ensures
- // that if the previous private DNS mode was not "hostname", the system only sees one
+ // that if the previous private DNS mode was not strict, the system only sees one
// EVENT_PRIVATE_DNS_SETTINGS_CHANGED event instead of two.
Settings.Global.putString(mCR, Settings.Global.PRIVATE_DNS_SPECIFIER, server);
final String mode = Settings.Global.getString(mCR, Settings.Global.PRIVATE_DNS_MODE);
- // If current private DNS mode is "hostname", we only need to set PRIVATE_DNS_SPECIFIER.
- if (!"hostname".equals(mode)) {
- Settings.Global.putString(mCR, Settings.Global.PRIVATE_DNS_MODE, "hostname");
+ // If current private DNS mode is strict, we only need to set PRIVATE_DNS_SPECIFIER.
+ if (!PRIVATE_DNS_MODE_STRICT.equals(mode)) {
+ Settings.Global.putString(mCR, Settings.Global.PRIVATE_DNS_MODE,
+ PRIVATE_DNS_MODE_STRICT);
}
}
diff --git a/tests/cts/net/util/java/android/net/cts/util/CtsTetheringUtils.java b/tests/cts/net/util/java/android/net/cts/util/CtsTetheringUtils.java
index 1bdd533..c220326 100644
--- a/tests/cts/net/util/java/android/net/cts/util/CtsTetheringUtils.java
+++ b/tests/cts/net/util/java/android/net/cts/util/CtsTetheringUtils.java
@@ -388,20 +388,7 @@
assumeTetheringSupported();
assumeTrue(!getTetheringInterfaceRegexps().getTetherableWifiRegexs().isEmpty());
-
- final PackageManager pm = ctx.getPackageManager();
- assumeTrue(pm.hasSystemFeature(PackageManager.FEATURE_WIFI));
-
- WifiManager wm = ctx.getSystemService(WifiManager.class);
- // Wifi feature flags only work when wifi is on.
- final boolean previousWifiEnabledState = wm.isWifiEnabled();
- try {
- if (!previousWifiEnabledState) SystemUtil.runShellCommand("svc wifi enable");
- waitForWifiEnabled(ctx);
- assumeTrue(wm.isPortableHotspotSupported());
- } finally {
- if (!previousWifiEnabledState) SystemUtil.runShellCommand("svc wifi disable");
- }
+ assumeTrue(isPortableHotspotSupported(ctx));
}
public TetheringInterfaceRegexps getTetheringInterfaceRegexps() {
@@ -453,8 +440,26 @@
return callback.getTetheringInterfaceRegexps().getTetherableWifiRegexs();
}
- public static boolean isWifiTetheringSupported(final TestTetheringEventCallback callback) {
- return !getWifiTetherableInterfaceRegexps(callback).isEmpty();
+ public static boolean isWifiTetheringSupported(final Context ctx,
+ final TestTetheringEventCallback callback) throws Exception {
+ return !getWifiTetherableInterfaceRegexps(callback).isEmpty()
+ && isPortableHotspotSupported(ctx);
+ }
+
+ /* Returns if wifi supports hotspot. */
+ private static boolean isPortableHotspotSupported(final Context ctx) throws Exception {
+ final PackageManager pm = ctx.getPackageManager();
+ if (!pm.hasSystemFeature(PackageManager.FEATURE_WIFI)) return false;
+ final WifiManager wm = ctx.getSystemService(WifiManager.class);
+ // Wifi feature flags only work when wifi is on.
+ final boolean previousWifiEnabledState = wm.isWifiEnabled();
+ try {
+ if (!previousWifiEnabledState) SystemUtil.runShellCommand("svc wifi enable");
+ waitForWifiEnabled(ctx);
+ return wm.isPortableHotspotSupported();
+ } finally {
+ if (!previousWifiEnabledState) SystemUtil.runShellCommand("svc wifi disable");
+ }
}
public TetheringInterface startWifiTethering(final TestTetheringEventCallback callback)
diff --git a/tests/unit/java/com/android/server/ConnectivityServiceTest.java b/tests/unit/java/com/android/server/ConnectivityServiceTest.java
index 4661385..dee312d 100644
--- a/tests/unit/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/unit/java/com/android/server/ConnectivityServiceTest.java
@@ -300,7 +300,9 @@
import com.android.internal.util.test.BroadcastInterceptingContext;
import com.android.internal.util.test.FakeSettingsProvider;
import com.android.net.module.util.ArrayTrackRecord;
+import com.android.net.module.util.CollectionUtils;
import com.android.server.ConnectivityService.ConnectivityDiagnosticsCallbackInfo;
+import com.android.server.ConnectivityService.NetworkRequestInfo;
import com.android.server.connectivity.MockableSystemProperties;
import com.android.server.connectivity.Nat464Xlat;
import com.android.server.connectivity.NetworkAgentInfo;
@@ -415,6 +417,7 @@
private static final String VPN_IFNAME = "tun10042";
private static final String TEST_PACKAGE_NAME = "com.android.test.package";
private static final int TEST_PACKAGE_UID = 123;
+ private static final int TEST_PACKAGE_UID2 = 321;
private static final String ALWAYS_ON_PACKAGE = "com.android.test.alwaysonvpn";
private static final String INTERFACE_NAME = "interface";
@@ -1157,6 +1160,10 @@
return ranges;
}
+ private Set<UidRange> uidRangesForUids(Collection<Integer> uids) {
+ return uidRangesForUids(CollectionUtils.toIntArray(uids));
+ }
+
private static Looper startHandlerThreadAndReturnLooper() {
final HandlerThread handlerThread = new HandlerThread("MockVpnThread");
handlerThread.start();
@@ -1523,6 +1530,8 @@
private static final UserInfo PRIMARY_USER_INFO = new UserInfo(PRIMARY_USER, "",
UserInfo.FLAG_PRIMARY);
private static final UserHandle PRIMARY_USER_HANDLE = new UserHandle(PRIMARY_USER);
+ private static final int SECONDARY_USER = 10;
+ private static final UserHandle SECONDARY_USER_HANDLE = new UserHandle(SECONDARY_USER);
private static final int RESTRICTED_USER = 1;
private static final UserInfo RESTRICTED_USER_INFO = new UserInfo(RESTRICTED_USER, "",
@@ -9915,10 +9924,24 @@
}
public NetworkAgentInfo fakeMobileNai(NetworkCapabilities nc) {
+ final NetworkCapabilities cellNc = new NetworkCapabilities.Builder(nc)
+ .addTransportType(TRANSPORT_CELLULAR).build();
final NetworkInfo info = new NetworkInfo(TYPE_MOBILE, TelephonyManager.NETWORK_TYPE_LTE,
ConnectivityManager.getNetworkTypeName(TYPE_MOBILE),
TelephonyManager.getNetworkTypeName(TelephonyManager.NETWORK_TYPE_LTE));
- return new NetworkAgentInfo(null, new Network(NET_ID), info, new LinkProperties(),
+ return fakeNai(cellNc, info);
+ }
+
+ private NetworkAgentInfo fakeWifiNai(NetworkCapabilities nc) {
+ final NetworkCapabilities wifiNc = new NetworkCapabilities.Builder(nc)
+ .addTransportType(TRANSPORT_WIFI).build();
+ final NetworkInfo info = new NetworkInfo(TYPE_WIFI, 0 /* subtype */,
+ ConnectivityManager.getNetworkTypeName(TYPE_WIFI), "" /* subtypeName */);
+ return fakeNai(wifiNc, info);
+ }
+
+ private NetworkAgentInfo fakeNai(NetworkCapabilities nc, NetworkInfo networkInfo) {
+ return new NetworkAgentInfo(null, new Network(NET_ID), networkInfo, new LinkProperties(),
nc, new NetworkScore.Builder().setLegacyInt(0).build(),
mServiceContext, null, new NetworkAgentConfig(), mService, null, null, 0,
INVALID_UID, TEST_LINGER_DELAY_MS, mQosCallbackTracker,
@@ -9944,7 +9967,7 @@
final NetworkCapabilities nc = new NetworkCapabilities();
nc.setAdministratorUids(new int[] {wrongUid});
- final NetworkAgentInfo naiWithUid = fakeMobileNai(nc);
+ final NetworkAgentInfo naiWithUid = fakeWifiNai(nc);
mServiceContext.setPermission(android.Manifest.permission.NETWORK_STACK, PERMISSION_DENIED);
@@ -9954,18 +9977,37 @@
Process.myPid() + 1, wrongUid, naiWithUid, mContext.getOpPackageName()));
}
+ private void verifyConnectivityDiagnosticsPermissionsWithNetworkAgentInfo(
+ NetworkAgentInfo info, boolean expectPermission) {
+ mServiceContext.setPermission(android.Manifest.permission.NETWORK_STACK, PERMISSION_DENIED);
+
+ assertEquals(
+ "Unexpected ConnDiags permission",
+ expectPermission,
+ mService.checkConnectivityDiagnosticsPermissions(
+ Process.myPid(), Process.myUid(), info, mContext.getOpPackageName()));
+ }
+
@Test
- public void testCheckConnectivityDiagnosticsPermissionsNoLocationPermission() throws Exception {
+ public void testCheckConnectivityDiagnosticsPermissionsCellularNoLocationPermission()
+ throws Exception {
final NetworkCapabilities nc = new NetworkCapabilities();
nc.setAdministratorUids(new int[] {Process.myUid()});
final NetworkAgentInfo naiWithUid = fakeMobileNai(nc);
- mServiceContext.setPermission(android.Manifest.permission.NETWORK_STACK, PERMISSION_DENIED);
+ verifyConnectivityDiagnosticsPermissionsWithNetworkAgentInfo(naiWithUid,
+ true /* expectPermission */);
+ }
- assertFalse(
- "ACCESS_FINE_LOCATION permission necessary for Connectivity Diagnostics",
- mService.checkConnectivityDiagnosticsPermissions(
- Process.myPid(), Process.myUid(), naiWithUid, mContext.getOpPackageName()));
+ @Test
+ public void testCheckConnectivityDiagnosticsPermissionsWifiNoLocationPermission()
+ throws Exception {
+ final NetworkCapabilities nc = new NetworkCapabilities();
+ nc.setAdministratorUids(new int[] {Process.myUid()});
+ final NetworkAgentInfo naiWithUid = fakeWifiNai(nc);
+
+ verifyConnectivityDiagnosticsPermissionsWithNetworkAgentInfo(naiWithUid,
+ false /* expectPermission */);
}
@Test
@@ -10247,7 +10289,7 @@
mCm.registerNetworkCallback(cellRequest, cellNetworkCallback);
waitForIdle();
- final ConnectivityService.NetworkRequestInfo[] nriOutput = mService.requestsSortedById();
+ final NetworkRequestInfo[] nriOutput = mService.requestsSortedById();
assertTrue(nriOutput.length > 1);
for (int i = 0; i < nriOutput.length - 1; i++) {
@@ -10607,8 +10649,7 @@
.thenReturn(hasFeature);
}
- private Range<Integer> getNriFirstUidRange(
- @NonNull final ConnectivityService.NetworkRequestInfo nri) {
+ private Range<Integer> getNriFirstUidRange(@NonNull final NetworkRequestInfo nri) {
return nri.mRequests.get(0).networkCapabilities.getUids().iterator().next();
}
@@ -10647,7 +10688,7 @@
OEM_NETWORK_PREFERENCE_OEM_PAID;
// Act on OemNetworkRequestFactory.createNrisFromOemNetworkPreferences()
- final ArraySet<ConnectivityService.NetworkRequestInfo> nris =
+ final ArraySet<NetworkRequestInfo> nris =
mService.new OemNetworkRequestFactory()
.createNrisFromOemNetworkPreferences(
createDefaultOemNetworkPreferences(prefToTest));
@@ -10676,7 +10717,7 @@
OEM_NETWORK_PREFERENCE_OEM_PAID_NO_FALLBACK;
// Act on OemNetworkRequestFactory.createNrisFromOemNetworkPreferences()
- final ArraySet<ConnectivityService.NetworkRequestInfo> nris =
+ final ArraySet<NetworkRequestInfo> nris =
mService.new OemNetworkRequestFactory()
.createNrisFromOemNetworkPreferences(
createDefaultOemNetworkPreferences(prefToTest));
@@ -10702,7 +10743,7 @@
OEM_NETWORK_PREFERENCE_OEM_PAID_ONLY;
// Act on OemNetworkRequestFactory.createNrisFromOemNetworkPreferences()
- final ArraySet<ConnectivityService.NetworkRequestInfo> nris =
+ final ArraySet<NetworkRequestInfo> nris =
mService.new OemNetworkRequestFactory()
.createNrisFromOemNetworkPreferences(
createDefaultOemNetworkPreferences(prefToTest));
@@ -10725,7 +10766,7 @@
OEM_NETWORK_PREFERENCE_OEM_PRIVATE_ONLY;
// Act on OemNetworkRequestFactory.createNrisFromOemNetworkPreferences()
- final ArraySet<ConnectivityService.NetworkRequestInfo> nris =
+ final ArraySet<NetworkRequestInfo> nris =
mService.new OemNetworkRequestFactory()
.createNrisFromOemNetworkPreferences(
createDefaultOemNetworkPreferences(prefToTest));
@@ -10758,7 +10799,7 @@
.build();
// Act on OemNetworkRequestFactory.createNrisFromOemNetworkPreferences()
- final ArraySet<ConnectivityService.NetworkRequestInfo> nris =
+ final ArraySet<NetworkRequestInfo> nris =
mService.new OemNetworkRequestFactory().createNrisFromOemNetworkPreferences(pref);
assertNotNull(nris);
@@ -10783,7 +10824,7 @@
.build();
// Act on OemNetworkRequestFactory.createNrisFromOemNetworkPreferences()
- final List<ConnectivityService.NetworkRequestInfo> nris =
+ final List<NetworkRequestInfo> nris =
new ArrayList<>(
mService.new OemNetworkRequestFactory().createNrisFromOemNetworkPreferences(
pref));
@@ -10815,7 +10856,7 @@
.build();
// Act on OemNetworkRequestFactory.createNrisFromOemNetworkPreferences()
- final List<ConnectivityService.NetworkRequestInfo> nris =
+ final List<NetworkRequestInfo> nris =
new ArrayList<>(
mService.new OemNetworkRequestFactory().createNrisFromOemNetworkPreferences(
pref));
@@ -10857,7 +10898,7 @@
.build();
// Act on OemNetworkRequestFactory.createNrisFromOemNetworkPreferences()
- final ArraySet<ConnectivityService.NetworkRequestInfo> nris =
+ final ArraySet<NetworkRequestInfo> nris =
mService.new OemNetworkRequestFactory().createNrisFromOemNetworkPreferences(pref);
assertEquals(expectedNumOfNris, nris.size());
@@ -10950,8 +10991,7 @@
// each time to confirm it doesn't change under test.
final int expectedDefaultNetworkRequestsSize = 2;
assertEquals(expectedDefaultNetworkRequestsSize, mService.mDefaultNetworkRequests.size());
- for (final ConnectivityService.NetworkRequestInfo defaultRequest
- : mService.mDefaultNetworkRequests) {
+ for (final NetworkRequestInfo defaultRequest : mService.mDefaultNetworkRequests) {
final Network defaultNetwork = defaultRequest.getSatisfier() == null
? null : defaultRequest.getSatisfier().network();
// If this is the default request.
@@ -12898,4 +12938,73 @@
}
}
}
+
+ private void assertCreateNrisFromMobileDataPreferredUids(Set<Integer> uids) {
+ final Set<NetworkRequestInfo> nris =
+ mService.createNrisFromMobileDataPreferredUids(uids);
+ final NetworkRequestInfo nri = nris.iterator().next();
+ // Verify that one NRI is created with multilayer requests. Because one NRI can contain
+ // multiple uid ranges, so it only need create one NRI here.
+ assertEquals(1, nris.size());
+ assertTrue(nri.isMultilayerRequest());
+ assertEquals(nri.getUids(), uidRangesForUids(uids));
+ }
+
+ /**
+ * Test createNrisFromMobileDataPreferredUids returns correct NetworkRequestInfo.
+ */
+ @Test
+ public void testCreateNrisFromMobileDataPreferredUids() {
+ // Verify that empty uid set should not create any NRI for it.
+ final Set<NetworkRequestInfo> nrisNoUid =
+ mService.createNrisFromMobileDataPreferredUids(new ArraySet<>());
+ assertEquals(0, nrisNoUid.size());
+
+ final int uid1 = PRIMARY_USER_HANDLE.getUid(TEST_PACKAGE_UID);
+ final int uid2 = PRIMARY_USER_HANDLE.getUid(TEST_PACKAGE_UID2);
+ final int uid3 = SECONDARY_USER_HANDLE.getUid(TEST_PACKAGE_UID);
+ assertCreateNrisFromMobileDataPreferredUids(Set.of(uid1));
+ assertCreateNrisFromMobileDataPreferredUids(Set.of(uid1, uid3));
+ assertCreateNrisFromMobileDataPreferredUids(Set.of(uid1, uid2));
+ }
+
+ private void setAndUpdateMobileDataPreferredUids(Set<Integer> uids) {
+ ConnectivitySettingsManager.setMobileDataPreferredUids(mServiceContext, uids);
+ mService.updateMobileDataPreferredUids();
+ waitForIdle();
+ }
+
+ /**
+ * Test that MOBILE_DATA_PREFERRED_UIDS changes will send correct net id and uid ranges to netd.
+ */
+ @Test
+ public void testMobileDataPreferredUidsChanged() throws Exception {
+ final InOrder inorder = inOrder(mMockNetd);
+ mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
+ mCellNetworkAgent.connect(true);
+ waitForIdle();
+
+ final int cellNetId = mCellNetworkAgent.getNetwork().netId;
+ inorder.verify(mMockNetd, times(1)).networkCreate(nativeNetworkConfigPhysical(
+ cellNetId, INetd.PERMISSION_NONE));
+
+ // Initial mobile data preferred uids status.
+ setAndUpdateMobileDataPreferredUids(Set.of());
+ inorder.verify(mMockNetd, never()).networkAddUidRanges(anyInt(), any());
+ inorder.verify(mMockNetd, never()).networkRemoveUidRanges(anyInt(), any());
+
+ final Set<Integer> uids1 = Set.of(PRIMARY_USER_HANDLE.getUid(TEST_PACKAGE_UID));
+ final UidRangeParcel[] uidRanges1 = toUidRangeStableParcels(uidRangesForUids(uids1));
+ setAndUpdateMobileDataPreferredUids(uids1);
+ inorder.verify(mMockNetd, times(1)).networkAddUidRanges(cellNetId, uidRanges1);
+ inorder.verify(mMockNetd, never()).networkRemoveUidRanges(anyInt(), any());
+
+ final Set<Integer> uids2 = Set.of(PRIMARY_USER_HANDLE.getUid(TEST_PACKAGE_UID),
+ PRIMARY_USER_HANDLE.getUid(TEST_PACKAGE_UID2),
+ SECONDARY_USER_HANDLE.getUid(TEST_PACKAGE_UID));
+ final UidRangeParcel[] uidRanges2 = toUidRangeStableParcels(uidRangesForUids(uids2));
+ setAndUpdateMobileDataPreferredUids(uids2);
+ inorder.verify(mMockNetd, times(1)).networkRemoveUidRanges(cellNetId, uidRanges1);
+ inorder.verify(mMockNetd, times(1)).networkAddUidRanges(cellNetId, uidRanges2);
+ }
}
diff --git a/tests/unit/java/com/android/server/connectivity/PermissionMonitorTest.java b/tests/unit/java/com/android/server/connectivity/PermissionMonitorTest.java
index c75618f..e98f5db 100644
--- a/tests/unit/java/com/android/server/connectivity/PermissionMonitorTest.java
+++ b/tests/unit/java/com/android/server/connectivity/PermissionMonitorTest.java
@@ -30,7 +30,7 @@
import static android.content.pm.PackageInfo.REQUESTED_PERMISSION_REQUIRED;
import static android.content.pm.PackageManager.GET_PERMISSIONS;
import static android.content.pm.PackageManager.MATCH_ANY_USER;
-import static android.net.ConnectivitySettingsManager.APPS_ALLOWED_ON_RESTRICTED_NETWORKS;
+import static android.net.ConnectivitySettingsManager.UIDS_ALLOWED_ON_RESTRICTED_NETWORKS;
import static android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK;
import static android.os.Process.SYSTEM_UID;
@@ -73,6 +73,7 @@
import android.os.SystemConfigManager;
import android.os.UserHandle;
import android.os.UserManager;
+import android.provider.Settings;
import android.util.ArraySet;
import android.util.SparseIntArray;
@@ -142,7 +143,7 @@
final Context asUserCtx = mock(Context.class, AdditionalAnswers.delegatesTo(mContext));
doReturn(UserHandle.ALL).when(asUserCtx).getUser();
when(mContext.createContextAsUser(eq(UserHandle.ALL), anyInt())).thenReturn(asUserCtx);
- when(mDeps.getAppsAllowedOnRestrictedNetworks(any())).thenReturn(new ArraySet<>());
+ when(mDeps.getUidsAllowedOnRestrictedNetworks(any())).thenReturn(new ArraySet<>());
mPermissionMonitor = spy(new PermissionMonitor(mContext, mNetdService, mDeps));
@@ -341,9 +342,9 @@
}
@Test
- public void testHasRestrictedNetworkPermissionAppAllowedOnRestrictedNetworks() {
- mPermissionMonitor.updateAppsAllowedOnRestrictedNetworks(
- new ArraySet<>(new String[] { MOCK_PACKAGE1 }));
+ public void testHasRestrictedNetworkPermissionUidAllowedOnRestrictedNetworks() {
+ mPermissionMonitor.updateUidsAllowedOnRestrictedNetworks(
+ new ArraySet<>(new Integer[] { MOCK_UID1 }));
assertTrue(hasRestrictedNetworkPermission(
PARTITION_VENDOR, VERSION_Q, MOCK_PACKAGE1, MOCK_UID1));
assertTrue(hasRestrictedNetworkPermission(
@@ -352,11 +353,11 @@
PARTITION_VENDOR, VERSION_Q, MOCK_PACKAGE1, MOCK_UID1, CONNECTIVITY_INTERNAL));
assertFalse(hasRestrictedNetworkPermission(
- PARTITION_VENDOR, VERSION_Q, MOCK_PACKAGE2, MOCK_UID1));
+ PARTITION_VENDOR, VERSION_Q, MOCK_PACKAGE2, MOCK_UID2));
assertFalse(hasRestrictedNetworkPermission(
- PARTITION_VENDOR, VERSION_Q, MOCK_PACKAGE2, MOCK_UID1, CHANGE_NETWORK_STATE));
+ PARTITION_VENDOR, VERSION_Q, MOCK_PACKAGE2, MOCK_UID2, CHANGE_NETWORK_STATE));
assertFalse(hasRestrictedNetworkPermission(
- PARTITION_VENDOR, VERSION_Q, MOCK_PACKAGE2, MOCK_UID1, CONNECTIVITY_INTERNAL));
+ PARTITION_VENDOR, VERSION_Q, MOCK_PACKAGE2, MOCK_UID2, CONNECTIVITY_INTERNAL));
}
@@ -396,32 +397,32 @@
assertFalse(wouldBeCarryoverPackage(PARTITION_PRODUCT, VERSION_Q, MOCK_UID1));
}
- private boolean wouldBeAppAllowedOnRestrictedNetworks(String packageName) {
- final PackageInfo packageInfo = new PackageInfo();
- packageInfo.packageName = packageName;
- return mPermissionMonitor.isAppAllowedOnRestrictedNetworks(packageInfo);
+ private boolean wouldBeUidAllowedOnRestrictedNetworks(int uid) {
+ final ApplicationInfo applicationInfo = new ApplicationInfo();
+ applicationInfo.uid = uid;
+ return mPermissionMonitor.isUidAllowedOnRestrictedNetworks(applicationInfo);
}
@Test
public void testIsAppAllowedOnRestrictedNetworks() {
- mPermissionMonitor.updateAppsAllowedOnRestrictedNetworks(new ArraySet<>());
- assertFalse(wouldBeAppAllowedOnRestrictedNetworks(MOCK_PACKAGE1));
- assertFalse(wouldBeAppAllowedOnRestrictedNetworks(MOCK_PACKAGE2));
+ mPermissionMonitor.updateUidsAllowedOnRestrictedNetworks(new ArraySet<>());
+ assertFalse(wouldBeUidAllowedOnRestrictedNetworks(MOCK_UID1));
+ assertFalse(wouldBeUidAllowedOnRestrictedNetworks(MOCK_UID2));
- mPermissionMonitor.updateAppsAllowedOnRestrictedNetworks(
- new ArraySet<>(new String[] { MOCK_PACKAGE1 }));
- assertTrue(wouldBeAppAllowedOnRestrictedNetworks(MOCK_PACKAGE1));
- assertFalse(wouldBeAppAllowedOnRestrictedNetworks(MOCK_PACKAGE2));
+ mPermissionMonitor.updateUidsAllowedOnRestrictedNetworks(
+ new ArraySet<>(new Integer[] { MOCK_UID1 }));
+ assertTrue(wouldBeUidAllowedOnRestrictedNetworks(MOCK_UID1));
+ assertFalse(wouldBeUidAllowedOnRestrictedNetworks(MOCK_UID2));
- mPermissionMonitor.updateAppsAllowedOnRestrictedNetworks(
- new ArraySet<>(new String[] { MOCK_PACKAGE2 }));
- assertFalse(wouldBeAppAllowedOnRestrictedNetworks(MOCK_PACKAGE1));
- assertTrue(wouldBeAppAllowedOnRestrictedNetworks(MOCK_PACKAGE2));
+ mPermissionMonitor.updateUidsAllowedOnRestrictedNetworks(
+ new ArraySet<>(new Integer[] { MOCK_UID2 }));
+ assertFalse(wouldBeUidAllowedOnRestrictedNetworks(MOCK_UID1));
+ assertTrue(wouldBeUidAllowedOnRestrictedNetworks(MOCK_UID2));
- mPermissionMonitor.updateAppsAllowedOnRestrictedNetworks(
- new ArraySet<>(new String[] { "com.android.test" }));
- assertFalse(wouldBeAppAllowedOnRestrictedNetworks(MOCK_PACKAGE1));
- assertFalse(wouldBeAppAllowedOnRestrictedNetworks(MOCK_PACKAGE2));
+ mPermissionMonitor.updateUidsAllowedOnRestrictedNetworks(
+ new ArraySet<>(new Integer[] { 123 }));
+ assertFalse(wouldBeUidAllowedOnRestrictedNetworks(MOCK_UID1));
+ assertFalse(wouldBeUidAllowedOnRestrictedNetworks(MOCK_UID2));
}
private void assertBackgroundPermission(boolean hasPermission, String name, int uid,
@@ -515,7 +516,7 @@
@Test
public void testUserAndPackageAddRemove() throws Exception {
- final NetdMonitor mNetdMonitor = new NetdMonitor(mNetdService);
+ final NetdMonitor netdMonitor = new NetdMonitor(mNetdService);
// MOCK_UID1: MOCK_PACKAGE1 only has network permission.
// SYSTEM_UID: SYSTEM_PACKAGE1 has system permission.
@@ -531,47 +532,47 @@
// Add SYSTEM_PACKAGE2, expect only have network permission.
mPermissionMonitor.onUserAdded(MOCK_USER1);
addPackageForUsers(new UserHandle[]{MOCK_USER1}, SYSTEM_PACKAGE2, SYSTEM_UID);
- mNetdMonitor.expectPermission(NETWORK, new UserHandle[]{MOCK_USER1}, new int[]{SYSTEM_UID});
+ netdMonitor.expectPermission(NETWORK, new UserHandle[]{MOCK_USER1}, new int[]{SYSTEM_UID});
// Add SYSTEM_PACKAGE1, expect permission escalate.
addPackageForUsers(new UserHandle[]{MOCK_USER1}, SYSTEM_PACKAGE1, SYSTEM_UID);
- mNetdMonitor.expectPermission(SYSTEM, new UserHandle[]{MOCK_USER1}, new int[]{SYSTEM_UID});
+ netdMonitor.expectPermission(SYSTEM, new UserHandle[]{MOCK_USER1}, new int[]{SYSTEM_UID});
mPermissionMonitor.onUserAdded(MOCK_USER2);
- mNetdMonitor.expectPermission(SYSTEM, new UserHandle[]{MOCK_USER1, MOCK_USER2},
+ netdMonitor.expectPermission(SYSTEM, new UserHandle[]{MOCK_USER1, MOCK_USER2},
new int[]{SYSTEM_UID});
addPackageForUsers(new UserHandle[]{MOCK_USER1, MOCK_USER2}, MOCK_PACKAGE1, MOCK_UID1);
- mNetdMonitor.expectPermission(SYSTEM, new UserHandle[]{MOCK_USER1, MOCK_USER2},
+ netdMonitor.expectPermission(SYSTEM, new UserHandle[]{MOCK_USER1, MOCK_USER2},
new int[]{SYSTEM_UID});
- mNetdMonitor.expectPermission(NETWORK, new UserHandle[]{MOCK_USER1, MOCK_USER2},
+ netdMonitor.expectPermission(NETWORK, new UserHandle[]{MOCK_USER1, MOCK_USER2},
new int[]{MOCK_UID1});
// Remove MOCK_UID1, expect no permission left for all user.
mPermissionMonitor.onPackageRemoved(MOCK_PACKAGE1, MOCK_UID1);
removePackageForUsers(new UserHandle[]{MOCK_USER1, MOCK_USER2}, MOCK_PACKAGE1, MOCK_UID1);
- mNetdMonitor.expectNoPermission(new UserHandle[]{MOCK_USER1, MOCK_USER2},
+ netdMonitor.expectNoPermission(new UserHandle[]{MOCK_USER1, MOCK_USER2},
new int[]{MOCK_UID1});
// Remove SYSTEM_PACKAGE1, expect permission downgrade.
when(mPackageManager.getPackagesForUid(anyInt())).thenReturn(new String[]{SYSTEM_PACKAGE2});
removePackageForUsers(new UserHandle[]{MOCK_USER1, MOCK_USER2},
SYSTEM_PACKAGE1, SYSTEM_UID);
- mNetdMonitor.expectPermission(NETWORK, new UserHandle[]{MOCK_USER1, MOCK_USER2},
+ netdMonitor.expectPermission(NETWORK, new UserHandle[]{MOCK_USER1, MOCK_USER2},
new int[]{SYSTEM_UID});
mPermissionMonitor.onUserRemoved(MOCK_USER1);
- mNetdMonitor.expectPermission(NETWORK, new UserHandle[]{MOCK_USER2}, new int[]{SYSTEM_UID});
+ netdMonitor.expectPermission(NETWORK, new UserHandle[]{MOCK_USER2}, new int[]{SYSTEM_UID});
// Remove all packages, expect no permission left.
when(mPackageManager.getPackagesForUid(anyInt())).thenReturn(new String[]{});
removePackageForUsers(new UserHandle[]{MOCK_USER2}, SYSTEM_PACKAGE2, SYSTEM_UID);
- mNetdMonitor.expectNoPermission(new UserHandle[]{MOCK_USER1, MOCK_USER2},
+ netdMonitor.expectNoPermission(new UserHandle[]{MOCK_USER1, MOCK_USER2},
new int[]{SYSTEM_UID, MOCK_UID1});
// Remove last user, expect no redundant clearPermission is invoked.
mPermissionMonitor.onUserRemoved(MOCK_USER2);
- mNetdMonitor.expectNoPermission(new UserHandle[]{MOCK_USER1, MOCK_USER2},
+ netdMonitor.expectNoPermission(new UserHandle[]{MOCK_USER1, MOCK_USER2},
new int[]{SYSTEM_UID, MOCK_UID1});
}
@@ -698,7 +699,7 @@
@Test
public void testPackagePermissionUpdate() throws Exception {
- final NetdServiceMonitor mNetdServiceMonitor = new NetdServiceMonitor(mNetdService);
+ final NetdServiceMonitor netdServiceMonitor = new NetdServiceMonitor(mNetdService);
// MOCK_UID1: MOCK_PACKAGE1 only has internet permission.
// MOCK_UID2: MOCK_PACKAGE2 does not have any permission.
// SYSTEM_UID1: SYSTEM_PACKAGE1 has internet permission and update device stats permission.
@@ -714,29 +715,29 @@
// Send the permission information to netd, expect permission updated.
mPermissionMonitor.sendPackagePermissionsToNetd(netdPermissionsAppIds);
- mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET,
+ netdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET,
new int[]{MOCK_UID1});
- mNetdServiceMonitor.expectPermission(INetd.PERMISSION_NONE, new int[]{MOCK_UID2});
- mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET
+ netdServiceMonitor.expectPermission(INetd.PERMISSION_NONE, new int[]{MOCK_UID2});
+ netdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET
| INetd.PERMISSION_UPDATE_DEVICE_STATS, new int[]{SYSTEM_UID1});
- mNetdServiceMonitor.expectPermission(INetd.PERMISSION_UPDATE_DEVICE_STATS,
+ netdServiceMonitor.expectPermission(INetd.PERMISSION_UPDATE_DEVICE_STATS,
new int[]{SYSTEM_UID2});
// Update permission of MOCK_UID1, expect new permission show up.
mPermissionMonitor.sendPackagePermissionsForUid(MOCK_UID1,
INetd.PERMISSION_INTERNET | INetd.PERMISSION_UPDATE_DEVICE_STATS);
- mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET
+ netdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET
| INetd.PERMISSION_UPDATE_DEVICE_STATS, new int[]{MOCK_UID1});
// Change permissions of SYSTEM_UID2, expect new permission show up and old permission
// revoked.
mPermissionMonitor.sendPackagePermissionsForUid(SYSTEM_UID2,
INetd.PERMISSION_INTERNET);
- mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET, new int[]{SYSTEM_UID2});
+ netdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET, new int[]{SYSTEM_UID2});
// Revoke permission from SYSTEM_UID1, expect no permission stored.
mPermissionMonitor.sendPackagePermissionsForUid(SYSTEM_UID1, INetd.PERMISSION_NONE);
- mNetdServiceMonitor.expectPermission(INetd.PERMISSION_NONE, new int[]{SYSTEM_UID1});
+ netdServiceMonitor.expectPermission(INetd.PERMISSION_NONE, new int[]{SYSTEM_UID1});
}
private PackageInfo setPackagePermissions(String packageName, int uid, String[] permissions)
@@ -757,23 +758,23 @@
@Test
public void testPackageInstall() throws Exception {
- final NetdServiceMonitor mNetdServiceMonitor = new NetdServiceMonitor(mNetdService);
+ final NetdServiceMonitor netdServiceMonitor = new NetdServiceMonitor(mNetdService);
addPackage(MOCK_PACKAGE1, MOCK_UID1, new String[] {INTERNET, UPDATE_DEVICE_STATS});
- mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET
+ netdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET
| INetd.PERMISSION_UPDATE_DEVICE_STATS, new int[]{MOCK_UID1});
addPackage(MOCK_PACKAGE2, MOCK_UID2, new String[] {INTERNET});
- mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET, new int[]{MOCK_UID2});
+ netdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET, new int[]{MOCK_UID2});
}
@Test
public void testPackageInstallSharedUid() throws Exception {
- final NetdServiceMonitor mNetdServiceMonitor = new NetdServiceMonitor(mNetdService);
+ final NetdServiceMonitor netdServiceMonitor = new NetdServiceMonitor(mNetdService);
PackageInfo packageInfo1 = addPackage(MOCK_PACKAGE1, MOCK_UID1,
new String[] {INTERNET, UPDATE_DEVICE_STATS});
- mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET
+ netdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET
| INetd.PERMISSION_UPDATE_DEVICE_STATS, new int[]{MOCK_UID1});
// Install another package with the same uid and no permissions should not cause the UID to
@@ -783,56 +784,56 @@
when(mPackageManager.getPackagesForUid(MOCK_UID1))
.thenReturn(new String[]{MOCK_PACKAGE1, MOCK_PACKAGE2});
mPermissionMonitor.onPackageAdded(MOCK_PACKAGE2, MOCK_UID1);
- mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET
+ netdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET
| INetd.PERMISSION_UPDATE_DEVICE_STATS, new int[]{MOCK_UID1});
}
@Test
public void testPackageUninstallBasic() throws Exception {
- final NetdServiceMonitor mNetdServiceMonitor = new NetdServiceMonitor(mNetdService);
+ final NetdServiceMonitor netdServiceMonitor = new NetdServiceMonitor(mNetdService);
addPackage(MOCK_PACKAGE1, MOCK_UID1, new String[] {INTERNET, UPDATE_DEVICE_STATS});
- mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET
+ netdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET
| INetd.PERMISSION_UPDATE_DEVICE_STATS, new int[]{MOCK_UID1});
when(mPackageManager.getPackagesForUid(MOCK_UID1)).thenReturn(new String[]{});
mPermissionMonitor.onPackageRemoved(MOCK_PACKAGE1, MOCK_UID1);
- mNetdServiceMonitor.expectPermission(INetd.PERMISSION_UNINSTALLED, new int[]{MOCK_UID1});
+ netdServiceMonitor.expectPermission(INetd.PERMISSION_UNINSTALLED, new int[]{MOCK_UID1});
}
@Test
public void testPackageRemoveThenAdd() throws Exception {
- final NetdServiceMonitor mNetdServiceMonitor = new NetdServiceMonitor(mNetdService);
+ final NetdServiceMonitor netdServiceMonitor = new NetdServiceMonitor(mNetdService);
addPackage(MOCK_PACKAGE1, MOCK_UID1, new String[] {INTERNET, UPDATE_DEVICE_STATS});
- mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET
+ netdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET
| INetd.PERMISSION_UPDATE_DEVICE_STATS, new int[]{MOCK_UID1});
when(mPackageManager.getPackagesForUid(MOCK_UID1)).thenReturn(new String[]{});
mPermissionMonitor.onPackageRemoved(MOCK_PACKAGE1, MOCK_UID1);
- mNetdServiceMonitor.expectPermission(INetd.PERMISSION_UNINSTALLED, new int[]{MOCK_UID1});
+ netdServiceMonitor.expectPermission(INetd.PERMISSION_UNINSTALLED, new int[]{MOCK_UID1});
addPackage(MOCK_PACKAGE1, MOCK_UID1, new String[] {INTERNET});
- mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET, new int[]{MOCK_UID1});
+ netdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET, new int[]{MOCK_UID1});
}
@Test
public void testPackageUpdate() throws Exception {
- final NetdServiceMonitor mNetdServiceMonitor = new NetdServiceMonitor(mNetdService);
+ final NetdServiceMonitor netdServiceMonitor = new NetdServiceMonitor(mNetdService);
addPackage(MOCK_PACKAGE1, MOCK_UID1, new String[] {});
- mNetdServiceMonitor.expectPermission(INetd.PERMISSION_NONE, new int[]{MOCK_UID1});
+ netdServiceMonitor.expectPermission(INetd.PERMISSION_NONE, new int[]{MOCK_UID1});
addPackage(MOCK_PACKAGE1, MOCK_UID1, new String[] {INTERNET});
- mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET, new int[]{MOCK_UID1});
+ netdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET, new int[]{MOCK_UID1});
}
@Test
public void testPackageUninstallWithMultiplePackages() throws Exception {
- final NetdServiceMonitor mNetdServiceMonitor = new NetdServiceMonitor(mNetdService);
+ final NetdServiceMonitor netdServiceMonitor = new NetdServiceMonitor(mNetdService);
addPackage(MOCK_PACKAGE1, MOCK_UID1, new String[] {INTERNET, UPDATE_DEVICE_STATS});
- mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET
+ netdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET
| INetd.PERMISSION_UPDATE_DEVICE_STATS, new int[]{MOCK_UID1});
// Mock another package with the same uid but different permissions.
@@ -842,7 +843,7 @@
MOCK_PACKAGE2});
mPermissionMonitor.onPackageRemoved(MOCK_PACKAGE1, MOCK_UID1);
- mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET, new int[]{MOCK_UID1});
+ netdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET, new int[]{MOCK_UID1});
}
@Test
@@ -859,7 +860,7 @@
@Test
public void testUpdateUidPermissionsFromSystemConfig() throws Exception {
- final NetdServiceMonitor mNetdServiceMonitor = new NetdServiceMonitor(mNetdService);
+ final NetdServiceMonitor netdServiceMonitor = new NetdServiceMonitor(mNetdService);
when(mPackageManager.getInstalledPackages(anyInt())).thenReturn(new ArrayList<>());
when(mSystemConfigManager.getSystemPermissionUids(eq(INTERNET)))
.thenReturn(new int[]{ MOCK_UID1, MOCK_UID2 });
@@ -867,15 +868,15 @@
.thenReturn(new int[]{ MOCK_UID2 });
mPermissionMonitor.startMonitoring();
- mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET, new int[]{ MOCK_UID1 });
- mNetdServiceMonitor.expectPermission(
+ netdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET, new int[]{ MOCK_UID1 });
+ netdServiceMonitor.expectPermission(
INetd.PERMISSION_INTERNET | INetd.PERMISSION_UPDATE_DEVICE_STATS,
new int[]{ MOCK_UID2 });
}
@Test
public void testIntentReceiver() throws Exception {
- final NetdServiceMonitor mNetdServiceMonitor = new NetdServiceMonitor(mNetdService);
+ final NetdServiceMonitor netdServiceMonitor = new NetdServiceMonitor(mNetdService);
final ArgumentCaptor<BroadcastReceiver> receiverCaptor =
ArgumentCaptor.forClass(BroadcastReceiver.class);
verify(mContext, times(1)).registerReceiver(receiverCaptor.capture(), any(), any(), any());
@@ -888,7 +889,7 @@
setPackagePermissions(MOCK_PACKAGE1, MOCK_UID1,
new String[] { INTERNET, UPDATE_DEVICE_STATS });
receiver.onReceive(mContext, addedIntent);
- mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET
+ netdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET
| INetd.PERMISSION_UPDATE_DEVICE_STATS, new int[] { MOCK_UID1 });
// Verify receiving PACKAGE_REMOVED intent.
@@ -897,105 +898,140 @@
Uri.fromParts("package", MOCK_PACKAGE1, null /* fragment */));
removedIntent.putExtra(Intent.EXTRA_UID, MOCK_UID1);
receiver.onReceive(mContext, removedIntent);
- mNetdServiceMonitor.expectPermission(INetd.PERMISSION_UNINSTALLED, new int[] { MOCK_UID1 });
+ netdServiceMonitor.expectPermission(INetd.PERMISSION_UNINSTALLED, new int[] { MOCK_UID1 });
+ }
+
+ private ContentObserver expectRegisterContentObserver(Uri expectedUri) {
+ final ArgumentCaptor<ContentObserver> captor =
+ ArgumentCaptor.forClass(ContentObserver.class);
+ verify(mDeps).registerContentObserver(any(),
+ argThat(uri -> uri.equals(expectedUri)), anyBoolean(), captor.capture());
+ return captor.getValue();
+ }
+
+ private void buildAndMockPackageInfoWithPermissions(String packageName, int uid,
+ String... permissions) throws Exception {
+ final PackageInfo packageInfo = setPackagePermissions(packageName, uid, permissions);
+ packageInfo.packageName = packageName;
+ packageInfo.applicationInfo.uid = uid;
}
@Test
- public void testAppsAllowedOnRestrictedNetworksChanged() throws Exception {
- final NetdMonitor mNetdMonitor = new NetdMonitor(mNetdService);
- final ArgumentCaptor<ContentObserver> captor =
- ArgumentCaptor.forClass(ContentObserver.class);
- verify(mDeps, times(1)).registerContentObserver(any(),
- argThat(uri -> uri.getEncodedPath().contains(APPS_ALLOWED_ON_RESTRICTED_NETWORKS)),
- anyBoolean(), captor.capture());
- final ContentObserver contentObserver = captor.getValue();
+ public void testUidsAllowedOnRestrictedNetworksChanged() throws Exception {
+ final NetdMonitor netdMonitor = new NetdMonitor(mNetdService);
+ final ContentObserver contentObserver = expectRegisterContentObserver(
+ Settings.Global.getUriFor(UIDS_ALLOWED_ON_RESTRICTED_NETWORKS));
mPermissionMonitor.onUserAdded(MOCK_USER1);
- // Prepare PackageInfo for MOCK_PACKAGE1
- final PackageInfo packageInfo = buildPackageInfo(
- false /* hasSystemPermission */, MOCK_UID1, MOCK_USER1);
- packageInfo.packageName = MOCK_PACKAGE1;
- when(mPackageManager.getPackageInfo(eq(MOCK_PACKAGE1), anyInt())).thenReturn(packageInfo);
- when(mPackageManager.getPackagesForUid(MOCK_UID1)).thenReturn(new String[]{MOCK_PACKAGE1});
- // Prepare PackageInfo for MOCK_PACKAGE2
- final PackageInfo packageInfo2 = buildPackageInfo(
- false /* hasSystemPermission */, MOCK_UID2, MOCK_USER1);
- packageInfo2.packageName = MOCK_PACKAGE2;
- when(mPackageManager.getPackageInfo(eq(MOCK_PACKAGE2), anyInt())).thenReturn(packageInfo2);
- when(mPackageManager.getPackagesForUid(MOCK_UID2)).thenReturn(new String[]{MOCK_PACKAGE2});
+ // Prepare PackageInfo for MOCK_PACKAGE1 and MOCK_PACKAGE2
+ buildAndMockPackageInfoWithPermissions(MOCK_PACKAGE1, MOCK_UID1);
+ buildAndMockPackageInfoWithPermissions(MOCK_PACKAGE2, MOCK_UID2);
- // MOCK_PACKAGE1 is listed in setting that allow to use restricted networks, MOCK_UID1
+ // MOCK_UID1 is listed in setting that allow to use restricted networks, MOCK_UID1
// should have SYSTEM permission.
- when(mDeps.getAppsAllowedOnRestrictedNetworks(any())).thenReturn(
- new ArraySet<>(new String[] { MOCK_PACKAGE1 }));
+ when(mDeps.getUidsAllowedOnRestrictedNetworks(any())).thenReturn(
+ new ArraySet<>(new Integer[] { MOCK_UID1 }));
contentObserver.onChange(true /* selfChange */);
- mNetdMonitor.expectPermission(SYSTEM, new UserHandle[]{MOCK_USER1}, new int[]{MOCK_UID1});
- mNetdMonitor.expectNoPermission(new UserHandle[]{MOCK_USER1}, new int[]{MOCK_UID2});
+ netdMonitor.expectPermission(SYSTEM, new UserHandle[]{MOCK_USER1}, new int[]{MOCK_UID1});
+ netdMonitor.expectNoPermission(new UserHandle[]{MOCK_USER1}, new int[]{MOCK_UID2});
- // MOCK_PACKAGE2 is listed in setting that allow to use restricted networks, MOCK_UID2
+ // MOCK_UID2 is listed in setting that allow to use restricted networks, MOCK_UID2
// should have SYSTEM permission but MOCK_UID1 should revoke permission.
- when(mDeps.getAppsAllowedOnRestrictedNetworks(any())).thenReturn(
- new ArraySet<>(new String[] { MOCK_PACKAGE2 }));
+ when(mDeps.getUidsAllowedOnRestrictedNetworks(any())).thenReturn(
+ new ArraySet<>(new Integer[] { MOCK_UID2 }));
contentObserver.onChange(true /* selfChange */);
- mNetdMonitor.expectPermission(SYSTEM, new UserHandle[]{MOCK_USER1}, new int[]{MOCK_UID2});
- mNetdMonitor.expectNoPermission(new UserHandle[]{MOCK_USER1}, new int[]{MOCK_UID1});
+ netdMonitor.expectPermission(SYSTEM, new UserHandle[]{MOCK_USER1}, new int[]{MOCK_UID2});
+ netdMonitor.expectNoPermission(new UserHandle[]{MOCK_USER1}, new int[]{MOCK_UID1});
- // No app lists in setting, should revoke permission from all uids.
- when(mDeps.getAppsAllowedOnRestrictedNetworks(any())).thenReturn(new ArraySet<>());
+ // No uid lists in setting, should revoke permission from all uids.
+ when(mDeps.getUidsAllowedOnRestrictedNetworks(any())).thenReturn(new ArraySet<>());
contentObserver.onChange(true /* selfChange */);
- mNetdMonitor.expectNoPermission(
+ netdMonitor.expectNoPermission(
new UserHandle[]{MOCK_USER1}, new int[]{MOCK_UID1, MOCK_UID2});
}
@Test
- public void testAppsAllowedOnRestrictedNetworksChangedWithSharedUid() throws Exception {
- final NetdMonitor mNetdMonitor = new NetdMonitor(mNetdService);
- final ArgumentCaptor<ContentObserver> captor =
- ArgumentCaptor.forClass(ContentObserver.class);
- verify(mDeps, times(1)).registerContentObserver(any(),
- argThat(uri -> uri.getEncodedPath().contains(APPS_ALLOWED_ON_RESTRICTED_NETWORKS)),
- anyBoolean(), captor.capture());
- final ContentObserver contentObserver = captor.getValue();
+ public void testUidsAllowedOnRestrictedNetworksChangedWithSharedUid() throws Exception {
+ final NetdMonitor netdMonitor = new NetdMonitor(mNetdService);
+ final ContentObserver contentObserver = expectRegisterContentObserver(
+ Settings.Global.getUriFor(UIDS_ALLOWED_ON_RESTRICTED_NETWORKS));
mPermissionMonitor.onUserAdded(MOCK_USER1);
- // Prepare PackageInfo for MOCK_PACKAGE1 and MOCK_PACKAGE2 with shared uid MOCK_UID1.
- final PackageInfo packageInfo = systemPackageInfoWithPermissions(CHANGE_NETWORK_STATE);
- packageInfo.applicationInfo.uid = MOCK_USER1.getUid(MOCK_UID1);
- packageInfo.packageName = MOCK_PACKAGE1;
- final PackageInfo packageInfo2 = buildPackageInfo(
- false /* hasSystemPermission */, MOCK_UID1, MOCK_USER1);
- packageInfo2.packageName = MOCK_PACKAGE2;
- when(mPackageManager.getPackageInfo(eq(MOCK_PACKAGE1), anyInt())).thenReturn(packageInfo);
- when(mPackageManager.getPackageInfo(eq(MOCK_PACKAGE2), anyInt())).thenReturn(packageInfo2);
+ buildAndMockPackageInfoWithPermissions(MOCK_PACKAGE1, MOCK_UID1, CHANGE_NETWORK_STATE);
+ buildAndMockPackageInfoWithPermissions(MOCK_PACKAGE2, MOCK_UID1);
when(mPackageManager.getPackagesForUid(MOCK_UID1))
.thenReturn(new String[]{MOCK_PACKAGE1, MOCK_PACKAGE2});
// MOCK_PACKAGE1 have CHANGE_NETWORK_STATE, MOCK_UID1 should have NETWORK permission.
addPackageForUsers(new UserHandle[]{MOCK_USER1}, MOCK_PACKAGE1, MOCK_UID1);
- mNetdMonitor.expectPermission(NETWORK, new UserHandle[]{MOCK_USER1}, new int[]{MOCK_UID1});
+ netdMonitor.expectPermission(NETWORK, new UserHandle[]{MOCK_USER1}, new int[]{MOCK_UID1});
- // MOCK_PACKAGE2 is listed in setting that allow to use restricted networks, MOCK_UID1
+ // MOCK_UID1 is listed in setting that allow to use restricted networks, MOCK_UID1
// should upgrade to SYSTEM permission.
- when(mDeps.getAppsAllowedOnRestrictedNetworks(any())).thenReturn(
- new ArraySet<>(new String[] { MOCK_PACKAGE2 }));
+ when(mDeps.getUidsAllowedOnRestrictedNetworks(any())).thenReturn(
+ new ArraySet<>(new Integer[] { MOCK_UID1 }));
contentObserver.onChange(true /* selfChange */);
- mNetdMonitor.expectPermission(SYSTEM, new UserHandle[]{MOCK_USER1}, new int[]{MOCK_UID1});
-
- // MOCK_PACKAGE1 is listed in setting that allow to use restricted networks, MOCK_UID1
- // should still have SYSTEM permission.
- when(mDeps.getAppsAllowedOnRestrictedNetworks(any())).thenReturn(
- new ArraySet<>(new String[] { MOCK_PACKAGE1 }));
- contentObserver.onChange(true /* selfChange */);
- mNetdMonitor.expectPermission(SYSTEM, new UserHandle[]{MOCK_USER1}, new int[]{MOCK_UID1});
+ netdMonitor.expectPermission(SYSTEM, new UserHandle[]{MOCK_USER1}, new int[]{MOCK_UID1});
// No app lists in setting, MOCK_UID1 should downgrade to NETWORK permission.
- when(mDeps.getAppsAllowedOnRestrictedNetworks(any())).thenReturn(new ArraySet<>());
+ when(mDeps.getUidsAllowedOnRestrictedNetworks(any())).thenReturn(new ArraySet<>());
contentObserver.onChange(true /* selfChange */);
- mNetdMonitor.expectPermission(NETWORK, new UserHandle[]{MOCK_USER1}, new int[]{MOCK_UID1});
+ netdMonitor.expectPermission(NETWORK, new UserHandle[]{MOCK_USER1}, new int[]{MOCK_UID1});
// MOCK_PACKAGE1 removed, should revoke permission from MOCK_UID1.
when(mPackageManager.getPackagesForUid(MOCK_UID1)).thenReturn(new String[]{MOCK_PACKAGE2});
removePackageForUsers(new UserHandle[]{MOCK_USER1}, MOCK_PACKAGE1, MOCK_UID1);
- mNetdMonitor.expectNoPermission(new UserHandle[]{MOCK_USER1}, new int[]{MOCK_UID1});
+ netdMonitor.expectNoPermission(new UserHandle[]{MOCK_USER1}, new int[]{MOCK_UID1});
}
-}
\ No newline at end of file
+
+ @Test
+ public void testUidsAllowedOnRestrictedNetworksChangedWithMultipleUsers() throws Exception {
+ final NetdMonitor netdMonitor = new NetdMonitor(mNetdService);
+ final ContentObserver contentObserver = expectRegisterContentObserver(
+ Settings.Global.getUriFor(UIDS_ALLOWED_ON_RESTRICTED_NETWORKS));
+
+ // One user MOCK_USER1
+ mPermissionMonitor.onUserAdded(MOCK_USER1);
+ // Prepare PackageInfo for MOCK_PACKAGE1 and MOCK_PACKAGE2.
+ buildAndMockPackageInfoWithPermissions(MOCK_PACKAGE1, MOCK_UID1);
+ buildAndMockPackageInfoWithPermissions(MOCK_PACKAGE2, MOCK_UID2);
+
+ // MOCK_UID1 is listed in setting that allow to use restricted networks, MOCK_UID1
+ // in MOCK_USER1 should have SYSTEM permission and MOCK_UID2 has no permissions.
+ when(mDeps.getUidsAllowedOnRestrictedNetworks(any())).thenReturn(
+ new ArraySet<>(new Integer[] { MOCK_UID1 }));
+ contentObserver.onChange(true /* selfChange */);
+ netdMonitor.expectPermission(SYSTEM, new UserHandle[]{MOCK_USER1}, new int[]{MOCK_UID1});
+ netdMonitor.expectNoPermission(new UserHandle[]{MOCK_USER1}, new int[]{MOCK_UID2});
+
+ // Add user MOCK_USER2.
+ mPermissionMonitor.onUserAdded(MOCK_USER2);
+ // MOCK_UID1 in both users should all have SYSTEM permission and MOCK_UID2 has no
+ // permissions in either user.
+ netdMonitor.expectPermission(
+ SYSTEM, new UserHandle[] { MOCK_USER1, MOCK_USER2 }, new int[]{MOCK_UID1});
+ netdMonitor.expectNoPermission(
+ new UserHandle[] { MOCK_USER1, MOCK_USER2 }, new int[]{MOCK_UID2});
+
+ // MOCK_UID2 is listed in setting that allow to use restricted networks, MOCK_UID2
+ // in both users should have SYSTEM permission and MOCK_UID1 has no permissions.
+ when(mDeps.getUidsAllowedOnRestrictedNetworks(any())).thenReturn(
+ new ArraySet<>(new Integer[] { MOCK_UID2 }));
+ contentObserver.onChange(true /* selfChange */);
+ netdMonitor.expectPermission(
+ SYSTEM, new UserHandle[] { MOCK_USER1, MOCK_USER2 }, new int[]{MOCK_UID2});
+ netdMonitor.expectNoPermission(
+ new UserHandle[] { MOCK_USER1, MOCK_USER2 }, new int[]{MOCK_UID1});
+
+ // Remove user MOCK_USER1
+ mPermissionMonitor.onUserRemoved(MOCK_USER1);
+ netdMonitor.expectPermission(SYSTEM, new UserHandle[] {MOCK_USER2}, new int[]{MOCK_UID2});
+ netdMonitor.expectNoPermission(new UserHandle[] {MOCK_USER2}, new int[]{MOCK_UID1});
+
+ // No uid lists in setting, should revoke permission from all uids.
+ when(mDeps.getUidsAllowedOnRestrictedNetworks(any())).thenReturn(new ArraySet<>());
+ contentObserver.onChange(true /* selfChange */);
+ netdMonitor.expectNoPermission(
+ new UserHandle[]{MOCK_USER2}, new int[]{ MOCK_UID1, MOCK_UID2 });
+ }
+}