Merge "Remove ConnectivityServiceTest signature perms use"
diff --git a/Tethering/Android.bp b/Tethering/Android.bp
index 5a08b23..d3b9393 100644
--- a/Tethering/Android.bp
+++ b/Tethering/Android.bp
@@ -156,7 +156,5 @@
sdk {
name: "tethering-module-sdk",
- java_sdk_libs: [
- "framework-tethering",
- ],
+ bootclasspath_fragments: ["com.android.tethering-bootclasspath-fragment"],
}
diff --git a/service/src/com/android/server/ConnectivityService.java b/service/src/com/android/server/ConnectivityService.java
index 8b91a45..fd8397f 100644
--- a/service/src/com/android/server/ConnectivityService.java
+++ b/service/src/com/android/server/ConnectivityService.java
@@ -79,6 +79,8 @@
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.OemNetworkPreferences.OEM_NETWORK_PREFERENCE_TEST;
+import static android.net.OemNetworkPreferences.OEM_NETWORK_PREFERENCE_TEST_ONLY;
import static android.net.shared.NetworkMonitorUtils.isPrivateDnsValidationRequired;
import static android.os.Process.INVALID_UID;
import static android.os.Process.VPN_UID;
@@ -2636,6 +2638,12 @@
"ConnectivityService");
}
+ private void enforceManageTestNetworksPermission() {
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.MANAGE_TEST_NETWORKS,
+ "ConnectivityService");
+ }
+
private boolean checkNetworkStackPermission() {
return checkAnyPermissionOf(
android.Manifest.permission.NETWORK_STACK,
@@ -9967,8 +9975,15 @@
@NonNull final OemNetworkPreferences preference,
@Nullable final IOnCompleteListener listener) {
- enforceAutomotiveDevice();
- enforceOemNetworkPreferencesPermission();
+ Objects.requireNonNull(preference, "OemNetworkPreferences must be non-null");
+ // Only bypass the permission/device checks if this is a valid test request.
+ if (isValidTestOemNetworkPreference(preference)) {
+ enforceManageTestNetworksPermission();
+ } else {
+ enforceAutomotiveDevice();
+ enforceOemNetworkPreferencesPermission();
+ validateOemNetworkPreferences(preference);
+ }
// TODO: Have a priority for each preference.
if (!mProfileNetworkPreferences.isEmpty() || !mMobileDataPreferredUids.isEmpty()) {
@@ -9980,18 +9995,41 @@
throwConcurrentPreferenceException();
}
- Objects.requireNonNull(preference, "OemNetworkPreferences must be non-null");
- validateOemNetworkPreferences(preference);
mHandler.sendMessage(mHandler.obtainMessage(EVENT_SET_OEM_NETWORK_PREFERENCE,
new Pair<>(preference, listener)));
}
+ /**
+ * Check the validity of an OEM network preference to be used for testing purposes.
+ * @param preference the preference to validate
+ * @return true if this is a valid OEM network preference test request.
+ */
+ private boolean isValidTestOemNetworkPreference(
+ @NonNull final OemNetworkPreferences preference) {
+ // Allow for clearing of an existing OemNetworkPreference used for testing.
+ // This isn't called on the handler thread so it is possible that mOemNetworkPreferences
+ // changes after this check is complete. This is an unlikely scenario as calling of this API
+ // is controlled by the OEM therefore the added complexity is not worth adding given those
+ // circumstances. That said, it is an edge case to be aware of hence this comment.
+ final boolean isValidTestClearPref = preference.getNetworkPreferences().size() == 0
+ && isTestOemNetworkPreference(mOemNetworkPreferences);
+ return isTestOemNetworkPreference(preference) || isValidTestClearPref;
+ }
+
+ private boolean isTestOemNetworkPreference(@NonNull final OemNetworkPreferences preference) {
+ final Map<String, Integer> prefMap = preference.getNetworkPreferences();
+ return prefMap.size() == 1
+ && (prefMap.containsValue(OEM_NETWORK_PREFERENCE_TEST)
+ || prefMap.containsValue(OEM_NETWORK_PREFERENCE_TEST_ONLY));
+ }
+
private void validateOemNetworkPreferences(@NonNull OemNetworkPreferences preference) {
for (@OemNetworkPreferences.OemNetworkPreference final int pref
: preference.getNetworkPreferences().values()) {
- if (OemNetworkPreferences.OEM_NETWORK_PREFERENCE_UNINITIALIZED == pref) {
- final String msg = "OEM_NETWORK_PREFERENCE_UNINITIALIZED is an invalid value.";
- throw new IllegalArgumentException(msg);
+ if (pref <= 0 || OemNetworkPreferences.OEM_NETWORK_PREFERENCE_MAX < pref) {
+ throw new IllegalArgumentException(
+ OemNetworkPreferences.oemNetworkPreferenceToString(pref)
+ + " is an invalid value.");
}
}
}
@@ -10215,13 +10253,21 @@
case OemNetworkPreferences.OEM_NETWORK_PREFERENCE_OEM_PRIVATE_ONLY:
requests.add(createOemPrivateNetworkRequest());
break;
+ case OEM_NETWORK_PREFERENCE_TEST:
+ requests.add(createUnmeteredNetworkRequest());
+ requests.add(createTestNetworkRequest());
+ requests.add(createDefaultRequest());
+ break;
+ case OEM_NETWORK_PREFERENCE_TEST_ONLY:
+ requests.add(createTestNetworkRequest());
+ break;
default:
// This should never happen.
throw new IllegalArgumentException("createNriFromOemNetworkPreferences()"
+ " called with invalid preference of " + preference);
}
- final ArraySet ranges = new ArraySet<Integer>();
+ final ArraySet<UidRange> ranges = new ArraySet<>();
for (final int uid : uids) {
ranges.add(new UidRange(uid, uid));
}
@@ -10254,10 +10300,17 @@
}
private NetworkCapabilities createDefaultPerAppNetCap() {
- final NetworkCapabilities netCap = new NetworkCapabilities();
- netCap.addCapability(NET_CAPABILITY_INTERNET);
- netCap.setRequestorUidAndPackageName(Process.myUid(), mContext.getPackageName());
- return netCap;
+ final NetworkCapabilities netcap = new NetworkCapabilities();
+ netcap.addCapability(NET_CAPABILITY_INTERNET);
+ netcap.setRequestorUidAndPackageName(Process.myUid(), mContext.getPackageName());
+ return netcap;
+ }
+
+ private NetworkRequest createTestNetworkRequest() {
+ final NetworkCapabilities netcap = new NetworkCapabilities();
+ netcap.clearAll();
+ netcap.addTransportType(TRANSPORT_TEST);
+ return createNetworkRequest(NetworkRequest.Type.REQUEST, netcap);
}
}
}
diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/VpnTest.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/VpnTest.java
index 532fd86..8485263 100755
--- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/VpnTest.java
+++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/VpnTest.java
@@ -17,6 +17,7 @@
package com.android.cts.net.hostside;
import static android.Manifest.permission.NETWORK_SETTINGS;
+import static android.net.ConnectivityManager.TYPE_VPN;
import static android.net.NetworkCapabilities.TRANSPORT_VPN;
import static android.os.Process.INVALID_UID;
import static android.system.OsConstants.AF_INET;
@@ -759,6 +760,7 @@
assertEquals(vpnNetwork, mCM.getActiveNetwork());
assertNotEqual(defaultNetwork, vpnNetwork);
maybeExpectVpnTransportInfo(vpnNetwork);
+ assertTrue(mCM.getNetworkInfo(vpnNetwork).getType() == TYPE_VPN);
if (SdkLevel.isAtLeastS()) {
// Check that system default network callback has not seen any network changes, even
diff --git a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java
index 1d84a1b..8b8a8fb 100644
--- a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java
+++ b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java
@@ -65,11 +65,13 @@
import static android.system.OsConstants.AF_INET6;
import static android.system.OsConstants.AF_UNSPEC;
+import static com.android.compatibility.common.util.SystemUtil.callWithShellPermissionIdentity;
import static com.android.compatibility.common.util.SystemUtil.runShellCommand;
import static com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity;
import static com.android.networkstack.apishim.ConstantsShim.BLOCKED_REASON_LOCKDOWN_VPN;
import static com.android.networkstack.apishim.ConstantsShim.BLOCKED_REASON_NONE;
import static com.android.testutils.MiscAsserts.assertThrows;
+import static com.android.testutils.TestNetworkTrackerKt.initTestNetwork;
import static com.android.testutils.TestPermissionUtil.runAsShell;
import static org.junit.Assert.assertEquals;
@@ -112,6 +114,7 @@
import android.net.NetworkSpecifier;
import android.net.NetworkStateSnapshot;
import android.net.NetworkUtils;
+import android.net.OemNetworkPreferences;
import android.net.ProxyInfo;
import android.net.SocketKeepalive;
import android.net.TelephonyNetworkSpecifier;
@@ -155,6 +158,7 @@
import com.android.testutils.DevSdkIgnoreRuleKt;
import com.android.testutils.RecorderCallback.CallbackEntry;
import com.android.testutils.SkipPresubmit;
+import com.android.testutils.TestNetworkTracker;
import com.android.testutils.TestableNetworkCallback;
import junit.framework.AssertionFailedError;
@@ -191,6 +195,7 @@
import java.util.concurrent.Executor;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
import java.util.function.Supplier;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -461,6 +466,7 @@
android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE);
}
+ @AppModeFull(reason = "Cannot request network in instant app mode")
@DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.R)
@Test
public void testGetAllNetworkStateSnapshots()
@@ -517,13 +523,8 @@
@Test
@SkipPresubmit(reason = "Virtual devices use a single internet connection for all networks")
public void testOpenConnection() throws Exception {
- boolean canRunTest = mPackageManager.hasSystemFeature(FEATURE_WIFI)
- && mPackageManager.hasSystemFeature(FEATURE_TELEPHONY);
- if (!canRunTest) {
- Log.i(TAG,"testOpenConnection cannot execute unless device supports both WiFi "
- + "and a cellular connection");
- return;
- }
+ assumeTrue(mPackageManager.hasSystemFeature(FEATURE_WIFI));
+ assumeTrue(mPackageManager.hasSystemFeature(FEATURE_TELEPHONY));
Network wifiNetwork = mCtsNetUtils.connectToWifi();
Network cellNetwork = mCtsNetUtils.connectToCell();
@@ -698,10 +699,7 @@
@AppModeFull(reason = "Cannot get WifiManager in instant app mode")
@Test
public void testRegisterNetworkCallback() {
- if (!mPackageManager.hasSystemFeature(FEATURE_WIFI)) {
- Log.i(TAG, "testRegisterNetworkCallback cannot execute unless device supports WiFi");
- return;
- }
+ assumeTrue(mPackageManager.hasSystemFeature(FEATURE_WIFI));
// We will register for a WIFI network being available or lost.
final TestNetworkCallback callback = new TestNetworkCallback();
@@ -765,10 +763,7 @@
@AppModeFull(reason = "Cannot get WifiManager in instant app mode")
@Test
public void testRegisterNetworkCallback_withPendingIntent() {
- if (!mPackageManager.hasSystemFeature(FEATURE_WIFI)) {
- Log.i(TAG, "testRegisterNetworkCallback cannot execute unless device supports WiFi");
- return;
- }
+ assumeTrue(mPackageManager.hasSystemFeature(FEATURE_WIFI));
// Create a ConnectivityActionReceiver that has an IntentFilter for our locally defined
// action, NETWORK_CALLBACK_ACTION.
@@ -939,7 +934,8 @@
}
}
- private void waitForActiveNetworkMetered(int targetTransportType, boolean requestedMeteredness)
+ private void waitForActiveNetworkMetered(final int targetTransportType,
+ final boolean requestedMeteredness, final boolean useSystemDefault)
throws Exception {
final CountDownLatch latch = new CountDownLatch(1);
final NetworkCallback networkCallback = new NetworkCallback() {
@@ -953,17 +949,36 @@
}
}
};
- // Registering a callback here guarantees onCapabilitiesChanged is called immediately
- // with the current setting. Therefore, if the setting has already been changed,
- // this method will return right away, and if not it will wait for the setting to change.
- mCm.registerDefaultNetworkCallback(networkCallback);
- // Changing meteredness on wifi involves reconnecting, which can take several seconds
- // (involves re-associating, DHCP...).
- if (!latch.await(NETWORK_CALLBACK_TIMEOUT_MS, TimeUnit.MILLISECONDS)) {
- fail("Timed out waiting for active network metered status to change to "
- + requestedMeteredness + " ; network = " + mCm.getActiveNetwork());
+
+ try {
+ // Registering a callback here guarantees onCapabilitiesChanged is called immediately
+ // with the current setting. Therefore, if the setting has already been changed,
+ // this method will return right away, and if not, it'll wait for the setting to change.
+ if (useSystemDefault) {
+ runWithShellPermissionIdentity(() ->
+ mCmShim.registerSystemDefaultNetworkCallback(networkCallback,
+ new Handler(Looper.getMainLooper())),
+ NETWORK_SETTINGS);
+ } else {
+ mCm.registerDefaultNetworkCallback(networkCallback);
+ }
+
+ // Changing meteredness on wifi involves reconnecting, which can take several seconds
+ // (involves re-associating, DHCP...).
+ if (!latch.await(NETWORK_CALLBACK_TIMEOUT_MS, TimeUnit.MILLISECONDS)) {
+ fail("Timed out waiting for active network metered status to change to "
+ + requestedMeteredness + " ; network = " + mCm.getActiveNetwork());
+ }
+ } finally {
+ mCm.unregisterNetworkCallback(networkCallback);
}
- mCm.unregisterNetworkCallback(networkCallback);
+ }
+
+ private void setWifiMeteredStatusAndWait(String ssid, boolean isMetered) throws Exception {
+ setWifiMeteredStatus(ssid, Boolean.toString(isMetered) /* metered */);
+ waitForActiveNetworkMetered(TRANSPORT_WIFI,
+ isMetered /* requestedMeteredness */,
+ true /* useSystemDefault */);
}
private void assertMultipathPreferenceIsEventually(Network network, int oldValue,
@@ -1025,10 +1040,9 @@
int newMeteredPreference = findNextPrefValue(resolver);
Settings.Global.putString(resolver, NETWORK_METERED_MULTIPATH_PREFERENCE,
Integer.toString(newMeteredPreference));
- setWifiMeteredStatus(ssid, "true");
- waitForActiveNetworkMetered(TRANSPORT_WIFI, true);
// Wifi meterness changes from unmetered to metered will disconnect and reconnect since
// R.
+ setWifiMeteredStatusAndWait(ssid, true);
final Network network = mCtsNetUtils.ensureWifiConnected();
assertEquals(ssid, unquoteSSID(mWifiManager.getConnectionInfo().getSSID()));
assertEquals(mCm.getNetworkCapabilities(network).hasCapability(
@@ -1045,9 +1059,8 @@
assertMultipathPreferenceIsEventually(network,
oldMeteredPreference, newMeteredPreference);
- setWifiMeteredStatus(ssid, "false");
// No disconnect from unmetered to metered.
- waitForActiveNetworkMetered(TRANSPORT_WIFI, false);
+ setWifiMeteredStatusAndWait(ssid, false);
assertEquals(mCm.getNetworkCapabilities(network).hasCapability(
NET_CAPABILITY_NOT_METERED), true);
assertMultipathPreferenceIsEventually(network, newMeteredPreference,
@@ -1237,11 +1250,7 @@
@AppModeFull(reason = "Cannot get WifiManager in instant app mode")
@Test
public void testKeepaliveWifiUnsupported() throws Exception {
- if (!mPackageManager.hasSystemFeature(FEATURE_WIFI)) {
- Log.i(TAG, "testKeepaliveUnsupported cannot execute unless device"
- + " supports WiFi");
- return;
- }
+ assumeTrue(mPackageManager.hasSystemFeature(FEATURE_WIFI));
final Network network = mCtsNetUtils.ensureWifiConnected();
if (getSupportedKeepalivesForNet(network) != 0) return;
@@ -1258,10 +1267,7 @@
@Test
@SkipPresubmit(reason = "Keepalive is not supported on virtual hardware")
public void testCreateTcpKeepalive() throws Exception {
- if (!mPackageManager.hasSystemFeature(FEATURE_WIFI)) {
- Log.i(TAG, "testCreateTcpKeepalive cannot execute unless device supports WiFi");
- return;
- }
+ assumeTrue(mPackageManager.hasSystemFeature(FEATURE_WIFI));
final Network network = mCtsNetUtils.ensureWifiConnected();
if (getSupportedKeepalivesForNet(network) == 0) return;
@@ -1468,11 +1474,7 @@
@Test
@SkipPresubmit(reason = "Keepalive is not supported on virtual hardware")
public void testSocketKeepaliveLimitWifi() throws Exception {
- if (!mPackageManager.hasSystemFeature(FEATURE_WIFI)) {
- Log.i(TAG, "testSocketKeepaliveLimitWifi cannot execute unless device"
- + " supports WiFi");
- return;
- }
+ assumeTrue(mPackageManager.hasSystemFeature(FEATURE_WIFI));
final Network network = mCtsNetUtils.ensureWifiConnected();
final int supported = getSupportedKeepalivesForNet(network);
@@ -1565,11 +1567,7 @@
@Test
@SkipPresubmit(reason = "Keepalive is not supported on virtual hardware")
public void testSocketKeepaliveUnprivileged() throws Exception {
- if (!mPackageManager.hasSystemFeature(FEATURE_WIFI)) {
- Log.i(TAG, "testSocketKeepaliveUnprivileged cannot execute unless device"
- + " supports WiFi");
- return;
- }
+ assumeTrue(mPackageManager.hasSystemFeature(FEATURE_WIFI));
final Network network = mCtsNetUtils.ensureWifiConnected();
final int supported = getSupportedKeepalivesForNet(network);
@@ -1716,6 +1714,24 @@
c -> c instanceof CallbackEntry.Available);
}
+ private void waitForAvailable(
+ @NonNull final TestableNetworkCallback cb, final int expectedTransport) {
+ cb.eventuallyExpect(
+ CallbackEntry.AVAILABLE, NETWORK_CALLBACK_TIMEOUT_MS,
+ entry -> {
+ final NetworkCapabilities nc = mCm.getNetworkCapabilities(entry.getNetwork());
+ return nc.hasTransport(expectedTransport);
+ }
+ );
+ }
+
+ private void waitForAvailable(
+ @NonNull final TestableNetworkCallback cb, @NonNull final Network expectedNetwork) {
+ cb.expectAvailableCallbacks(expectedNetwork, false /* suspended */,
+ true /* validated */,
+ false /* blocked */, NETWORK_CALLBACK_TIMEOUT_MS);
+ }
+
private void waitForLost(@NonNull final TestableNetworkCallback cb) {
cb.eventuallyExpect(CallbackEntry.LOST, NETWORK_CALLBACK_TIMEOUT_MS,
c -> c instanceof CallbackEntry.Lost);
@@ -2036,6 +2052,7 @@
assertThrows(SecurityException.class, () -> mCm.factoryReset());
}
+ @AppModeFull(reason = "Cannot get WifiManager in instant app mode")
@Test
public void testFactoryReset() throws Exception {
assumeTrue(TestUtils.shouldTestSApis());
@@ -2101,4 +2118,172 @@
startTetheringCallback.verifyTetheringStarted();
callback.expectTetheredInterfacesChanged(wifiRegexs, TETHERING_WIFI);
}
+
+ /**
+ * Verify that per-app OEM network preference functions as expected for network preference TEST.
+ * For specified apps, validate networks are prioritized in order: unmetered, TEST transport,
+ * default network.
+ */
+ @AppModeFull(reason = "Cannot get WifiManager in instant app mode")
+ @Test
+ public void testSetOemNetworkPreferenceForTestPref() throws Exception {
+ // Cannot use @IgnoreUpTo(Build.VERSION_CODES.R) because this test also requires API 31
+ // shims, and @IgnoreUpTo does not check that.
+ assumeTrue(TestUtils.shouldTestSApis());
+ assumeTrue(mPackageManager.hasSystemFeature(FEATURE_WIFI));
+
+ final TestNetworkTracker tnt = callWithShellPermissionIdentity(
+ () -> initTestNetwork(mContext, TEST_LINKADDR, NETWORK_CALLBACK_TIMEOUT_MS));
+ final TestableNetworkCallback defaultCallback = new TestableNetworkCallback();
+ final TestableNetworkCallback systemDefaultCallback = new TestableNetworkCallback();
+
+ final Network wifiNetwork = mCtsNetUtils.ensureWifiConnected();
+ final NetworkCapabilities wifiNetworkCapabilities = callWithShellPermissionIdentity(
+ () -> mCm.getNetworkCapabilities(wifiNetwork));
+ final String ssid = unquoteSSID(wifiNetworkCapabilities.getSsid());
+ final boolean oldMeteredValue = wifiNetworkCapabilities.isMetered();
+
+ try {
+ // This network will be used for unmetered.
+ setWifiMeteredStatusAndWait(ssid, false /* isMetered */);
+
+ setOemNetworkPreferenceForMyPackage(OemNetworkPreferences.OEM_NETWORK_PREFERENCE_TEST);
+ registerTestOemNetworkPreferenceCallbacks(defaultCallback, systemDefaultCallback);
+
+ // Validate that an unmetered network is used over other networks.
+ waitForAvailable(defaultCallback, wifiNetwork);
+ waitForAvailable(systemDefaultCallback, wifiNetwork);
+
+ // Validate when setting unmetered to metered, unmetered is lost and replaced by the
+ // network with the TEST transport.
+ setWifiMeteredStatusAndWait(ssid, true /* isMetered */);
+ defaultCallback.expectCallback(CallbackEntry.LOST, wifiNetwork);
+ waitForAvailable(defaultCallback, tnt.getNetwork());
+ // Depending on if this device has cellular connectivity or not, multiple available
+ // callbacks may be received. Eventually, metered Wi-Fi should be the final available
+ // callback in any case therefore confirm its receipt before continuing to assure the
+ // system is in the expected state.
+ waitForAvailable(systemDefaultCallback, TRANSPORT_WIFI);
+ } finally {
+ // Validate that removing the test network will fallback to the default network.
+ runWithShellPermissionIdentity(tnt::teardown);
+ defaultCallback.expectCallback(CallbackEntry.LOST, tnt.getNetwork());
+ waitForAvailable(defaultCallback);
+
+ setWifiMeteredStatusAndWait(ssid, oldMeteredValue);
+
+ // Cleanup any prior test state from setOemNetworkPreference
+ clearOemNetworkPreference();
+ unregisterTestOemNetworkPreferenceCallbacks(defaultCallback, systemDefaultCallback);
+ }
+ }
+
+ /**
+ * Verify that per-app OEM network preference functions as expected for network pref TEST_ONLY.
+ * For specified apps, validate that only TEST transport type networks are used.
+ */
+ @Test
+ public void testSetOemNetworkPreferenceForTestOnlyPref() throws Exception {
+ // Cannot use @IgnoreUpTo(Build.VERSION_CODES.R) because this test also requires API 31
+ // shims, and @IgnoreUpTo does not check that.
+ assumeTrue(TestUtils.shouldTestSApis());
+
+ final TestNetworkTracker tnt = callWithShellPermissionIdentity(
+ () -> initTestNetwork(mContext, TEST_LINKADDR, NETWORK_CALLBACK_TIMEOUT_MS));
+ final TestableNetworkCallback defaultCallback = new TestableNetworkCallback();
+ final TestableNetworkCallback systemDefaultCallback = new TestableNetworkCallback();
+
+ final Network wifiNetwork = mCtsNetUtils.ensureWifiConnected();
+
+ try {
+ setOemNetworkPreferenceForMyPackage(
+ OemNetworkPreferences.OEM_NETWORK_PREFERENCE_TEST_ONLY);
+ registerTestOemNetworkPreferenceCallbacks(defaultCallback, systemDefaultCallback);
+ waitForAvailable(defaultCallback, tnt.getNetwork());
+ waitForAvailable(systemDefaultCallback, wifiNetwork);
+ } finally {
+ runWithShellPermissionIdentity(tnt::teardown);
+ defaultCallback.expectCallback(CallbackEntry.LOST, tnt.getNetwork());
+
+ // This network preference should only ever use the test network therefore available
+ // should not trigger when the test network goes down (e.g. switch to cellular).
+ defaultCallback.assertNoCallback();
+ // The system default should still be connected to Wi-fi
+ assertEquals(wifiNetwork, systemDefaultCallback.getLastAvailableNetwork());
+
+ // Cleanup any prior test state from setOemNetworkPreference
+ clearOemNetworkPreference();
+
+ // The default (non-test) network should be available as the network pref was cleared.
+ waitForAvailable(defaultCallback);
+ unregisterTestOemNetworkPreferenceCallbacks(defaultCallback, systemDefaultCallback);
+ }
+ }
+
+ private void unregisterTestOemNetworkPreferenceCallbacks(
+ @NonNull final TestableNetworkCallback defaultCallback,
+ @NonNull final TestableNetworkCallback systemDefaultCallback) {
+ mCm.unregisterNetworkCallback(defaultCallback);
+ mCm.unregisterNetworkCallback(systemDefaultCallback);
+ }
+
+ private void registerTestOemNetworkPreferenceCallbacks(
+ @NonNull final TestableNetworkCallback defaultCallback,
+ @NonNull final TestableNetworkCallback systemDefaultCallback) {
+ mCm.registerDefaultNetworkCallback(defaultCallback);
+ runWithShellPermissionIdentity(() ->
+ mCmShim.registerSystemDefaultNetworkCallback(systemDefaultCallback,
+ new Handler(Looper.getMainLooper())), NETWORK_SETTINGS);
+ }
+
+ private static final class OnCompleteListenerCallback {
+ final CompletableFuture<Object> mDone = new CompletableFuture<>();
+
+ public void onComplete() {
+ mDone.complete(new Object());
+ }
+
+ void expectOnComplete() throws Exception {
+ try {
+ mDone.get(NETWORK_CALLBACK_TIMEOUT_MS, TimeUnit.MILLISECONDS);
+ } catch (TimeoutException e) {
+ fail("Expected onComplete() not received after "
+ + NETWORK_CALLBACK_TIMEOUT_MS + " ms");
+ }
+ }
+ }
+
+ private void setOemNetworkPreferenceForMyPackage(final int networkPref) throws Exception {
+ final OemNetworkPreferences pref = new OemNetworkPreferences.Builder()
+ .addNetworkPreference(mContext.getPackageName(), networkPref)
+ .build();
+ final OnCompleteListenerCallback oemPrefListener = new OnCompleteListenerCallback();
+ mUiAutomation.adoptShellPermissionIdentity();
+ try {
+ mCm.setOemNetworkPreference(
+ pref, mContext.getMainExecutor(), oemPrefListener::onComplete);
+ } finally {
+ mUiAutomation.dropShellPermissionIdentity();
+ }
+ oemPrefListener.expectOnComplete();
+ }
+
+ /**
+ * This will clear the OEM network preference on the device. As there is currently no way of
+ * getting the existing preference, if this is executed while an existing preference is in
+ * place, that preference will need to be reapplied after executing this test.
+ * @throws Exception
+ */
+ private void clearOemNetworkPreference() throws Exception {
+ final OemNetworkPreferences clearPref = new OemNetworkPreferences.Builder().build();
+ final OnCompleteListenerCallback oemPrefListener = new OnCompleteListenerCallback();
+ mUiAutomation.adoptShellPermissionIdentity();
+ try {
+ mCm.setOemNetworkPreference(
+ clearPref, mContext.getMainExecutor(), oemPrefListener::onComplete);
+ } finally {
+ mUiAutomation.dropShellPermissionIdentity();
+ }
+ oemPrefListener.expectOnComplete();
+ }
}
diff --git a/tests/cts/net/src/android/net/cts/IpSecAlgorithmImplTest.java b/tests/cts/net/src/android/net/cts/IpSecAlgorithmImplTest.java
index 080f7f9..2f29273 100644
--- a/tests/cts/net/src/android/net/cts/IpSecAlgorithmImplTest.java
+++ b/tests/cts/net/src/android/net/cts/IpSecAlgorithmImplTest.java
@@ -16,9 +16,13 @@
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_CHACHA20_POLY1305;
import static android.net.IpSecAlgorithm.CRYPT_AES_CTR;
+import static android.net.cts.PacketUtils.AES_CMAC;
+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;
import static android.net.cts.PacketUtils.AES_CTR_BLK_SIZE;
import static android.net.cts.PacketUtils.AES_CTR_IV_LEN;
@@ -82,7 +86,7 @@
InetAddress.parseNumericAddress("2001:db8:1::2");
private static final int REMOTE_PORT = 12345;
- private static final IpSecManager IPSEC_MANAGER =
+ private static final IpSecManager sIpSecManager =
InstrumentationRegistry.getContext().getSystemService(IpSecManager.class);
private static class CheckCryptoImplTest implements TestNetworkRunnable.Test {
@@ -92,7 +96,7 @@
private final EspCipher mEspCipher;
private final EspAuth mEspAuth;
- public CheckCryptoImplTest(
+ CheckCryptoImplTest(
IpSecAlgorithm ipsecEncryptAlgo,
IpSecAlgorithm ipsecAuthAlgo,
IpSecAlgorithm ipsecAeadAlgo,
@@ -145,19 +149,19 @@
}
}
- try (final IpSecManager.SecurityParameterIndex outSpi =
- IPSEC_MANAGER.allocateSecurityParameterIndex(REMOTE_ADDRESS);
- final IpSecManager.SecurityParameterIndex inSpi =
- IPSEC_MANAGER.allocateSecurityParameterIndex(LOCAL_ADDRESS);
- final IpSecTransform outTransform =
+ try (IpSecManager.SecurityParameterIndex outSpi =
+ sIpSecManager.allocateSecurityParameterIndex(REMOTE_ADDRESS);
+ IpSecManager.SecurityParameterIndex inSpi =
+ sIpSecManager.allocateSecurityParameterIndex(LOCAL_ADDRESS);
+ IpSecTransform outTransform =
transformBuilder.buildTransportModeTransform(LOCAL_ADDRESS, outSpi);
- final IpSecTransform inTransform =
+ IpSecTransform inTransform =
transformBuilder.buildTransportModeTransform(REMOTE_ADDRESS, inSpi);
// Bind localSocket to a random available port.
- final DatagramSocket localSocket = new DatagramSocket(0)) {
- IPSEC_MANAGER.applyTransportModeTransform(
+ DatagramSocket localSocket = new DatagramSocket(0)) {
+ sIpSecManager.applyTransportModeTransform(
localSocket, IpSecManager.DIRECTION_IN, inTransform);
- IPSEC_MANAGER.applyTransportModeTransform(
+ sIpSecManager.applyTransportModeTransform(
localSocket, IpSecManager.DIRECTION_OUT, outTransform);
// Send ESP packet
@@ -170,7 +174,7 @@
tunUtils.awaitEspPacket(outSpi.getSpi(), false /* useEncap */);
// Remove transform for good hygiene
- IPSEC_MANAGER.removeTransportModeTransforms(localSocket);
+ sIpSecManager.removeTransportModeTransforms(localSocket);
// Get the kernel-generated ESP payload
final byte[] outEspPayload = new byte[outEspPacket.length - IP6_HDRLEN];
@@ -258,6 +262,20 @@
}
@Test
+ public void testAesCmac() throws Exception {
+ assumeTrue(hasIpSecAlgorithm(AUTH_AES_CMAC));
+
+ final byte[] authKey = getKeyBytes(AES_CMAC_KEY_LEN);
+ final IpSecAlgorithm ipsecAuthAlgo =
+ new IpSecAlgorithm(IpSecAlgorithm.AUTH_AES_CMAC, authKey, AES_CMAC_ICV_LEN * 8);
+ final EspAuth espAuth = new EspAuth(AES_CMAC, authKey, AES_CMAC_ICV_LEN);
+
+ runWithShellPermissionIdentity(new TestNetworkRunnable(new CheckCryptoImplTest(
+ null /* ipsecEncryptAlgo */, ipsecAuthAlgo, null /* ipsecAeadAlgo */,
+ EspCipherNull.getInstance(), espAuth)));
+ }
+
+ @Test
public void testChaCha20Poly1305() throws Exception {
assumeTrue(hasIpSecAlgorithm(AUTH_CRYPT_CHACHA20_POLY1305));
diff --git a/tests/cts/net/src/android/net/cts/IpSecManagerTest.java b/tests/cts/net/src/android/net/cts/IpSecManagerTest.java
index 5f79a3e..5c95aa3 100644
--- a/tests/cts/net/src/android/net/cts/IpSecManagerTest.java
+++ b/tests/cts/net/src/android/net/cts/IpSecManagerTest.java
@@ -74,7 +74,6 @@
import com.android.testutils.DevSdkIgnoreRule;
import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo;
-import com.android.testutils.SkipPresubmit;
import org.junit.Rule;
import org.junit.Test;
@@ -771,7 +770,6 @@
}
@Test
- @SkipPresubmit(reason = "b/186608065 - kernel 5.10 regression in TrafficStats with ipsec")
public void testAesCbcHmacMd5Tcp6() throws Exception {
IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY);
IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_MD5, getKey(128), 96);
@@ -804,7 +802,6 @@
}
@Test
- @SkipPresubmit(reason = "b/186608065 - kernel 5.10 regression in TrafficStats with ipsec")
public void testAesCbcHmacSha1Tcp6() throws Exception {
IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY);
IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA1, getKey(160), 96);
@@ -837,7 +834,6 @@
}
@Test
- @SkipPresubmit(reason = "b/186608065 - kernel 5.10 regression in TrafficStats with ipsec")
public void testAesCbcHmacSha256Tcp6() throws Exception {
IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY);
IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA256, getKey(256), 128);
@@ -870,7 +866,6 @@
}
@Test
- @SkipPresubmit(reason = "b/186608065 - kernel 5.10 regression in TrafficStats with ipsec")
public void testAesCbcHmacSha384Tcp6() throws Exception {
IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY);
IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA384, getKey(384), 192);
@@ -903,7 +898,6 @@
}
@Test
- @SkipPresubmit(reason = "b/186608065 - kernel 5.10 regression in TrafficStats with ipsec")
public void testAesCbcHmacSha512Tcp6() throws Exception {
IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY);
IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA512, getKey(512), 256);
@@ -947,7 +941,6 @@
}
@Test
- @SkipPresubmit(reason = "b/186608065 - kernel 5.10 regression in TrafficStats with ipsec")
public void testAesCtrHmacSha512Tcp6() throws Exception {
assumeTrue(hasIpSecAlgorithm(CRYPT_AES_CTR));
@@ -1002,7 +995,6 @@
}
@Test
- @SkipPresubmit(reason = "b/186608065 - kernel 5.10 regression in TrafficStats with ipsec")
public void testAesCbcAesXCbcTcp6() throws Exception {
assumeTrue(hasIpSecAlgorithm(AUTH_AES_XCBC));
@@ -1043,7 +1035,6 @@
}
@Test
- @SkipPresubmit(reason = "b/186608065 - kernel 5.10 regression in TrafficStats with ipsec")
public void testAesCbcAesCmacTcp6() throws Exception {
assumeTrue(hasIpSecAlgorithm(AUTH_AES_CMAC));
@@ -1082,7 +1073,6 @@
}
@Test
- @SkipPresubmit(reason = "b/186608065 - kernel 5.10 regression in TrafficStats with ipsec")
public void testAesGcm64Tcp6() throws Exception {
IpSecAlgorithm authCrypt =
new IpSecAlgorithm(IpSecAlgorithm.AUTH_CRYPT_AES_GCM, AEAD_KEY, 64);
@@ -1115,7 +1105,6 @@
}
@Test
- @SkipPresubmit(reason = "b/186608065 - kernel 5.10 regression in TrafficStats with ipsec")
public void testAesGcm96Tcp6() throws Exception {
IpSecAlgorithm authCrypt =
new IpSecAlgorithm(IpSecAlgorithm.AUTH_CRYPT_AES_GCM, AEAD_KEY, 96);
@@ -1148,7 +1137,6 @@
}
@Test
- @SkipPresubmit(reason = "b/186608065 - kernel 5.10 regression in TrafficStats with ipsec")
public void testAesGcm128Tcp6() throws Exception {
IpSecAlgorithm authCrypt =
new IpSecAlgorithm(IpSecAlgorithm.AUTH_CRYPT_AES_GCM, AEAD_KEY, 128);
@@ -1187,7 +1175,6 @@
}
@Test
- @SkipPresubmit(reason = "b/186608065 - kernel 5.10 regression in TrafficStats with ipsec")
public void testChaCha20Poly1305Tcp6() throws Exception {
assumeTrue(hasIpSecAlgorithm(AUTH_CRYPT_CHACHA20_POLY1305));
@@ -1463,7 +1450,6 @@
}
@Test
- @SkipPresubmit(reason = "b/186608065 - kernel 5.10 regression in TrafficStats with ipsec")
public void testCryptTcp6() throws Exception {
IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY);
checkTransform(IPPROTO_TCP, IPV6_LOOPBACK, crypt, null, null, false, 1, false);
@@ -1471,7 +1457,6 @@
}
@Test
- @SkipPresubmit(reason = "b/186608065 - kernel 5.10 regression in TrafficStats with ipsec")
public void testAuthTcp6() throws Exception {
IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA256, getKey(256), 128);
checkTransform(IPPROTO_TCP, IPV6_LOOPBACK, null, auth, null, false, 1, false);
diff --git a/tests/cts/net/src/android/net/cts/PacketUtils.java b/tests/cts/net/src/android/net/cts/PacketUtils.java
index 0b3bad4..4d924d1 100644
--- a/tests/cts/net/src/android/net/cts/PacketUtils.java
+++ b/tests/cts/net/src/android/net/cts/PacketUtils.java
@@ -19,6 +19,8 @@
import static android.system.OsConstants.IPPROTO_IPV6;
import static android.system.OsConstants.IPPROTO_UDP;
+import android.util.ArraySet;
+
import com.android.internal.net.ipsec.ike.crypto.AesXCbcImpl;
import java.net.Inet4Address;
@@ -29,7 +31,6 @@
import java.security.GeneralSecurityException;
import java.security.SecureRandom;
import java.util.Arrays;
-import java.util.HashSet;
import java.util.Set;
import javax.crypto.Cipher;
@@ -101,6 +102,7 @@
static final String HMAC_SHA_256 = "HmacSHA256";
static final String HMAC_SHA_384 = "HmacSHA384";
static final String HMAC_SHA_512 = "HmacSHA512";
+ static final String AES_CMAC = "AESCMAC";
static final String AES_XCBC = "AesXCbc";
public interface Payload {
@@ -501,7 +503,7 @@
public final byte[] key;
public final int ivLen;
public final int saltLen;
- protected byte[] iv;
+ protected byte[] mIv;
public EspCipher(String algoName, int blockSize, byte[] key, int ivLen, int saltLen) {
this.algoName = algoName;
@@ -509,11 +511,11 @@
this.key = key;
this.ivLen = ivLen;
this.saltLen = saltLen;
- this.iv = getIv(ivLen);
+ this.mIv = getIv(ivLen);
}
public void updateIv(byte[] iv) {
- this.iv = iv;
+ this.mIv = iv;
}
public static byte[] getPaddedPayload(int nextHeader, byte[] payload, int blockSize) {
@@ -544,19 +546,19 @@
throws GeneralSecurityException;
}
- public static class EspCipherNull extends EspCipher {
+ public static final class EspCipherNull extends EspCipher {
private static final String CRYPT_NULL = "CRYPT_NULL";
private static final int IV_LEN_UNUSED = 0;
private static final byte[] KEY_UNUSED = new byte[0];
- private static final EspCipherNull INSTANCE = new EspCipherNull();
+ private static final EspCipherNull sInstance = new EspCipherNull();
private EspCipherNull() {
super(CRYPT_NULL, ESP_BLK_SIZE, KEY_UNUSED, IV_LEN_UNUSED, SALT_LEN_UNUSED);
}
public static EspCipherNull getInstance() {
- return INSTANCE;
+ return sInstance;
}
@Override
@@ -566,7 +568,7 @@
}
}
- public static class EspCryptCipher extends EspCipher {
+ public static final class EspCryptCipher extends EspCipher {
public EspCryptCipher(String algoName, int blockSize, byte[] key, int ivLen) {
this(algoName, blockSize, key, ivLen, SALT_LEN_UNUSED);
}
@@ -582,7 +584,7 @@
final SecretKeySpec secretKeySpec;
if (AES_CBC.equals(algoName)) {
- ivParameterSpec = new IvParameterSpec(iv);
+ ivParameterSpec = new IvParameterSpec(mIv);
secretKeySpec = new SecretKeySpec(key, algoName);
} else if (AES_CTR.equals(algoName)) {
// Provided key consists of encryption/decryption key plus 4-byte salt. Salt is used
@@ -592,9 +594,9 @@
secretKeySpec = new SecretKeySpec(secretKey, algoName);
final ByteBuffer ivParameterBuffer =
- ByteBuffer.allocate(iv.length + saltLen + AES_CTR_INITIAL_COUNTER.length);
+ ByteBuffer.allocate(mIv.length + saltLen + AES_CTR_INITIAL_COUNTER.length);
ivParameterBuffer.put(salt);
- ivParameterBuffer.put(iv);
+ ivParameterBuffer.put(mIv);
ivParameterBuffer.put(AES_CTR_INITIAL_COUNTER);
ivParameterSpec = new IvParameterSpec(ivParameterBuffer.array());
} else {
@@ -608,15 +610,15 @@
cipher.doFinal(getPaddedPayload(nextHeader, payload, blockSize));
// Build ciphertext
- final ByteBuffer cipherText = ByteBuffer.allocate(iv.length + encrypted.length);
- cipherText.put(iv);
+ final ByteBuffer cipherText = ByteBuffer.allocate(mIv.length + encrypted.length);
+ cipherText.put(mIv);
cipherText.put(encrypted);
return getByteArrayFromBuffer(cipherText);
}
}
- public static class EspAeadCipher extends EspCipher {
+ public static final class EspAeadCipher extends EspCipher {
public final int icvLen;
public EspAeadCipher(
@@ -635,9 +637,9 @@
final SecretKeySpec secretKeySpec = new SecretKeySpec(secretKey, algoName);
- final ByteBuffer ivParameterBuffer = ByteBuffer.allocate(saltLen + iv.length);
+ final ByteBuffer ivParameterBuffer = ByteBuffer.allocate(saltLen + mIv.length);
ivParameterBuffer.put(salt);
- ivParameterBuffer.put(iv);
+ ivParameterBuffer.put(mIv);
final IvParameterSpec ivParameterSpec = new IvParameterSpec(ivParameterBuffer.array());
final ByteBuffer aadBuffer = ByteBuffer.allocate(ESP_HDRLEN);
@@ -653,8 +655,8 @@
// Build ciphertext
final ByteBuffer cipherText =
- ByteBuffer.allocate(iv.length + encryptedTextAndIcv.length);
- cipherText.put(iv);
+ ByteBuffer.allocate(mIv.length + encryptedTextAndIcv.length);
+ cipherText.put(mIv);
cipherText.put(encryptedTextAndIcv);
return getByteArrayFromBuffer(cipherText);
@@ -666,14 +668,15 @@
public final byte[] key;
public final int icvLen;
- private static final Set<String> SUPPORTED_HMAC_ALGOS = new HashSet<>();
+ private static final Set<String> JCE_SUPPORTED_MACS = new ArraySet<>();
static {
- SUPPORTED_HMAC_ALGOS.add(HMAC_MD5);
- SUPPORTED_HMAC_ALGOS.add(HMAC_SHA1);
- SUPPORTED_HMAC_ALGOS.add(HMAC_SHA_256);
- SUPPORTED_HMAC_ALGOS.add(HMAC_SHA_384);
- SUPPORTED_HMAC_ALGOS.add(HMAC_SHA_512);
+ JCE_SUPPORTED_MACS.add(HMAC_MD5);
+ JCE_SUPPORTED_MACS.add(HMAC_SHA1);
+ JCE_SUPPORTED_MACS.add(HMAC_SHA_256);
+ JCE_SUPPORTED_MACS.add(HMAC_SHA_384);
+ JCE_SUPPORTED_MACS.add(HMAC_SHA_512);
+ JCE_SUPPORTED_MACS.add(AES_CMAC);
}
public EspAuth(String algoName, byte[] key, int icvLen) {
@@ -686,7 +689,7 @@
if (AES_XCBC.equals(algoName)) {
final Cipher aesCipher = Cipher.getInstance(AES_CBC);
return new AesXCbcImpl().mac(key, authenticatedSection, true /* needTruncation */);
- } else if (SUPPORTED_HMAC_ALGOS.contains(algoName)) {
+ } else if (JCE_SUPPORTED_MACS.contains(algoName)) {
final Mac mac = Mac.getInstance(algoName);
final SecretKeySpec authKey = new SecretKeySpec(key, algoName);
mac.init(authKey);
@@ -701,20 +704,20 @@
}
}
- public static class EspAuthNull extends EspAuth {
+ public static final class EspAuthNull extends EspAuth {
private static final String AUTH_NULL = "AUTH_NULL";
private static final int ICV_LEN_UNUSED = 0;
private static final byte[] KEY_UNUSED = new byte[0];
private static final byte[] ICV_EMPTY = new byte[0];
- private static final EspAuthNull INSTANCE = new EspAuthNull();
+ private static final EspAuthNull sInstance = new EspAuthNull();
private EspAuthNull() {
super(AUTH_NULL, KEY_UNUSED, ICV_LEN_UNUSED);
}
public static EspAuthNull getInstance() {
- return INSTANCE;
+ return sInstance;
}
@Override
diff --git a/tests/unit/java/com/android/server/ConnectivityServiceTest.java b/tests/unit/java/com/android/server/ConnectivityServiceTest.java
index eae599d..81c25e6 100644
--- a/tests/unit/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/unit/java/com/android/server/ConnectivityServiceTest.java
@@ -114,6 +114,8 @@
import static android.net.OemNetworkPreferences.OEM_NETWORK_PREFERENCE_OEM_PAID_NO_FALLBACK;
import static android.net.OemNetworkPreferences.OEM_NETWORK_PREFERENCE_OEM_PAID_ONLY;
import static android.net.OemNetworkPreferences.OEM_NETWORK_PREFERENCE_OEM_PRIVATE_ONLY;
+import static android.net.OemNetworkPreferences.OEM_NETWORK_PREFERENCE_TEST;
+import static android.net.OemNetworkPreferences.OEM_NETWORK_PREFERENCE_TEST_ONLY;
import static android.net.OemNetworkPreferences.OEM_NETWORK_PREFERENCE_UNINITIALIZED;
import static android.net.RouteInfo.RTN_UNREACHABLE;
import static android.net.resolv.aidl.IDnsResolverUnsolicitedEventListener.PREFIX_OPERATION_ADDED;
@@ -10758,8 +10760,7 @@
}
@Test
- public void testOemNetworkRequestFactoryPreferenceUninitializedThrowsError()
- throws PackageManager.NameNotFoundException {
+ public void testOemNetworkRequestFactoryPreferenceUninitializedThrowsError() {
@OemNetworkPreferences.OemNetworkPreference final int prefToTest =
OEM_NETWORK_PREFERENCE_UNINITIALIZED;
@@ -11026,7 +11027,48 @@
assertThrows(UnsupportedOperationException.class,
() -> mService.setOemNetworkPreference(
createDefaultOemNetworkPreferences(networkPref),
- new TestOemListenerCallback()));
+ null));
+ }
+
+ @Test
+ public void testSetOemNetworkPreferenceFailsForTestRequestWithoutPermission() {
+ // Calling setOemNetworkPreference() with a test pref requires the permission
+ // MANAGE_TEST_NETWORKS.
+ mockHasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE, false);
+ @OemNetworkPreferences.OemNetworkPreference final int networkPref =
+ OEM_NETWORK_PREFERENCE_TEST;
+
+ // Act on ConnectivityService.setOemNetworkPreference()
+ assertThrows(SecurityException.class,
+ () -> mService.setOemNetworkPreference(
+ createDefaultOemNetworkPreferences(networkPref),
+ null));
+ }
+
+ @Test
+ public void testSetOemNetworkPreferenceFailsForInvalidTestRequest() {
+ assertSetOemNetworkPreferenceFailsForInvalidTestRequest(OEM_NETWORK_PREFERENCE_TEST);
+ }
+
+ @Test
+ public void testSetOemNetworkPreferenceFailsForInvalidTestOnlyRequest() {
+ assertSetOemNetworkPreferenceFailsForInvalidTestRequest(OEM_NETWORK_PREFERENCE_TEST_ONLY);
+ }
+
+ private void assertSetOemNetworkPreferenceFailsForInvalidTestRequest(
+ @OemNetworkPreferences.OemNetworkPreference final int oemNetworkPreferenceForTest) {
+ mockHasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE, true);
+ final String secondPackage = "does.not.matter";
+
+ // A valid test request would only have a single mapping.
+ final OemNetworkPreferences pref = new OemNetworkPreferences.Builder()
+ .addNetworkPreference(TEST_PACKAGE_NAME, oemNetworkPreferenceForTest)
+ .addNetworkPreference(secondPackage, oemNetworkPreferenceForTest)
+ .build();
+
+ // Act on ConnectivityService.setOemNetworkPreference()
+ assertThrows(IllegalArgumentException.class,
+ () -> mService.setOemNetworkPreference(pref, null));
}
private void setOemNetworkPreferenceAgentConnected(final int transportType,
@@ -11203,8 +11245,18 @@
private void setupSetOemNetworkPreferenceForPreferenceTest(
@OemNetworkPreferences.OemNetworkPreference final int networkPrefToSetup,
@NonNull final UidRangeParcel[] uidRanges,
- @NonNull final String testPackageName)
- throws Exception {
+ @NonNull final String testPackageName) throws Exception {
+ setupSetOemNetworkPreferenceForPreferenceTest(
+ networkPrefToSetup, uidRanges, testPackageName, true);
+ }
+
+ private void setupSetOemNetworkPreferenceForPreferenceTest(
+ @OemNetworkPreferences.OemNetworkPreference final int networkPrefToSetup,
+ @NonNull final UidRangeParcel[] uidRanges,
+ @NonNull final String testPackageName,
+ final boolean hasAutomotiveFeature) throws Exception {
+ mockHasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE, hasAutomotiveFeature);
+
// These tests work off a single UID therefore using 'start' is valid.
mockGetApplicationInfo(testPackageName, uidRanges[0].start);
@@ -11509,6 +11561,55 @@
}
/**
+ * Test the tracked default requests allows test requests without standard setup.
+ */
+ @Test
+ public void testSetOemNetworkPreferenceAllowsValidTestRequestWithoutChecks() throws Exception {
+ @OemNetworkPreferences.OemNetworkPreference int networkPref =
+ OEM_NETWORK_PREFERENCE_TEST;
+ validateSetOemNetworkPreferenceAllowsValidTestPrefRequest(networkPref);
+ }
+
+ /**
+ * Test the tracked default requests allows test only requests without standard setup.
+ */
+ @Test
+ public void testSetOemNetworkPreferenceAllowsValidTestOnlyRequestWithoutChecks()
+ throws Exception {
+ @OemNetworkPreferences.OemNetworkPreference int networkPref =
+ OEM_NETWORK_PREFERENCE_TEST_ONLY;
+ validateSetOemNetworkPreferenceAllowsValidTestPrefRequest(networkPref);
+ }
+
+ private void validateSetOemNetworkPreferenceAllowsValidTestPrefRequest(int networkPref)
+ throws Exception {
+ // The caller must have the MANAGE_TEST_NETWORKS permission.
+ final int testPackageUid = 123;
+ final String validTestPackageName = "does.not.matter";
+ final UidRangeParcel[] uidRanges =
+ toUidRangeStableParcels(uidRangesForUids(testPackageUid));
+ mServiceContext.setPermission(
+ Manifest.permission.MANAGE_TEST_NETWORKS, PERMISSION_GRANTED);
+
+ // Put the system into a state in which setOemNetworkPreference() would normally fail. This
+ // will confirm that a valid test request can bypass these checks.
+ mockHasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE, false);
+ mServiceContext.setPermission(
+ Manifest.permission.CONTROL_OEM_PAID_NETWORK_PREFERENCE, PERMISSION_DENIED);
+
+ // Validate the starting requests only includes the system default request.
+ assertEquals(1, mService.mDefaultNetworkRequests.size());
+
+ // Add an OEM default network request to track.
+ setupSetOemNetworkPreferenceForPreferenceTest(
+ networkPref, uidRanges, validTestPackageName,
+ false /* hasAutomotiveFeature */);
+
+ // Two requests should now exist; the system default and the test request.
+ assertEquals(2, mService.mDefaultNetworkRequests.size());
+ }
+
+ /**
* Test the tracked default requests clear previous OEM requests on setOemNetworkPreference().
*/
@Test
@@ -11520,7 +11621,7 @@
final UidRangeParcel[] uidRanges =
toUidRangeStableParcels(uidRangesForUids(testPackageUid));
- // Validate the starting requests only includes the fallback request.
+ // Validate the starting requests only includes the system default request.
assertEquals(1, mService.mDefaultNetworkRequests.size());
// Add an OEM default network request to track.