[automerger skipped] Ignore some ConnectivityManagerTest CTS tests that can't be run in the instant app mode am: e7d085e87d -s ours
am skip reason: Merged-In Ice43bcf7a1dc34f4a54fefba7f408767f0a4341e with SHA-1 279a8ee8f7 is already in history
Original change: https://googleplex-android-review.googlesource.com/c/platform/packages/modules/Connectivity/+/15068259
Change-Id: Id72506f437433c38bb34c7687799930f783e8644
diff --git a/Tethering/TEST_MAPPING b/Tethering/TEST_MAPPING
deleted file mode 100644
index 5617b0c..0000000
--- a/Tethering/TEST_MAPPING
+++ /dev/null
@@ -1,12 +0,0 @@
-{
- "presubmit": [
- {
- "name": "TetheringTests"
- }
- ],
- "postsubmit": [
- {
- "name": "TetheringIntegrationTests"
- }
- ]
-}
diff --git a/Tethering/common/TetheringLib/Android.bp b/Tethering/common/TetheringLib/Android.bp
index fce4360..f652772 100644
--- a/Tethering/common/TetheringLib/Android.bp
+++ b/Tethering/common/TetheringLib/Android.bp
@@ -22,6 +22,7 @@
defaults: ["framework-module-defaults"],
impl_library_visibility: [
"//packages/modules/Connectivity/Tethering:__subpackages__",
+ "//packages/modules/Connectivity/tests:__subpackages__",
],
srcs: [":framework-tethering-srcs"],
diff --git a/Tethering/tests/integration/Android.bp b/Tethering/tests/integration/Android.bp
index 351b9f4..e807613 100644
--- a/Tethering/tests/integration/Android.bp
+++ b/Tethering/tests/integration/Android.bp
@@ -51,7 +51,8 @@
defaults: ["TetheringIntegrationTestsDefaults"],
visibility: [
"//packages/modules/Connectivity/tests/cts/tethering",
- "//packages/modules/Connectivity/Tethering/tests/mts",
+ "//packages/modules/Connectivity/tests:__subpackages__",
+ "//packages/modules/Connectivity/Tethering/tests:__subpackages__",
]
}
@@ -104,7 +105,6 @@
"libnetworkstackutilsjni",
"libtetherutilsjni",
],
- jarjar_rules: ":TetheringTestsJarJarRules",
compile_multilib: "both",
manifest: "AndroidManifest_coverage.xml",
}
diff --git a/Tethering/tests/unit/Android.bp b/Tethering/tests/unit/Android.bp
index c6f19d7..1233345 100644
--- a/Tethering/tests/unit/Android.bp
+++ b/Tethering/tests/unit/Android.bp
@@ -77,6 +77,7 @@
"libstaticjvmtiagent",
"libtetherutilsjni",
],
+ jarjar_rules: ":TetheringTestsJarJarRules",
}
// Library containing the unit tests. This is used by the coverage test target to pull in the
@@ -87,7 +88,8 @@
defaults: ["TetheringTestsDefaults"],
target_sdk_version: "30",
visibility: [
- "//packages/modules/Connectivity/Tethering/tests/integration",
+ "//packages/modules/Connectivity/tests:__subpackages__",
+ "//packages/modules/Connectivity/Tethering/tests:__subpackages__",
]
}
@@ -98,7 +100,6 @@
"device-tests",
"mts",
],
- jarjar_rules: ":TetheringTestsJarJarRules",
defaults: ["TetheringTestsDefaults"],
compile_multilib: "both",
}
diff --git a/Tethering/tests/unit/src/com/android/networkstack/tethering/MockTetheringService.java b/Tethering/tests/unit/src/com/android/networkstack/tethering/MockTetheringService.java
index 071a290..4865e03 100644
--- a/Tethering/tests/unit/src/com/android/networkstack/tethering/MockTetheringService.java
+++ b/Tethering/tests/unit/src/com/android/networkstack/tethering/MockTetheringService.java
@@ -25,12 +25,14 @@
import android.net.ITetheringConnector;
import android.os.Binder;
import android.os.IBinder;
+import android.util.ArrayMap;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
public class MockTetheringService extends TetheringService {
private final Tethering mTethering = mock(Tethering.class);
+ private final ArrayMap<String, Integer> mMockedPermissions = new ArrayMap<>();
@Override
public IBinder onBind(Intent intent) {
@@ -51,6 +53,15 @@
return context.checkCallingOrSelfPermission(WRITE_SETTINGS) == PERMISSION_GRANTED;
}
+ @Override
+ public int checkCallingOrSelfPermission(String permission) {
+ final Integer mocked = mMockedPermissions.getOrDefault(permission, null);
+ if (mocked != null) {
+ return mocked;
+ }
+ return super.checkCallingOrSelfPermission(permission);
+ }
+
public Tethering getTethering() {
return mTethering;
}
@@ -68,5 +79,18 @@
public MockTetheringService getService() {
return MockTetheringService.this;
}
+
+ /**
+ * Mock a permission
+ * @param permission Permission to mock
+ * @param granted One of PackageManager.PERMISSION_*, or null to reset to default behavior
+ */
+ public void setPermission(String permission, Integer granted) {
+ if (granted == null) {
+ mMockedPermissions.remove(permission);
+ } else {
+ mMockedPermissions.put(permission, granted);
+ }
+ }
}
}
diff --git a/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringServiceTest.java b/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringServiceTest.java
index 941cd78..1b52f6e 100644
--- a/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringServiceTest.java
+++ b/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringServiceTest.java
@@ -19,6 +19,7 @@
import static android.Manifest.permission.ACCESS_NETWORK_STATE;
import static android.Manifest.permission.TETHER_PRIVILEGED;
import static android.Manifest.permission.WRITE_SETTINGS;
+import static android.content.pm.PackageManager.PERMISSION_DENIED;
import static android.net.TetheringManager.TETHERING_WIFI;
import static android.net.TetheringManager.TETHER_ERROR_NO_ACCESS_TETHERING_PERMISSION;
import static android.net.TetheringManager.TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION;
@@ -50,6 +51,7 @@
import androidx.test.rule.ServiceTestRule;
import androidx.test.runner.AndroidJUnit4;
+import com.android.net.module.util.CollectionUtils;
import com.android.networkstack.tethering.MockTetheringService.MockTetheringConnector;
import org.junit.After;
@@ -70,6 +72,7 @@
@Rule public ServiceTestRule mServiceTestRule;
private Tethering mTethering;
private Intent mMockServiceIntent;
+ private MockTetheringConnector mMockConnector;
private ITetheringConnector mTetheringConnector;
private UiAutomation mUiAutomation;
@@ -109,10 +112,9 @@
mMockServiceIntent = new Intent(
InstrumentationRegistry.getTargetContext(),
MockTetheringService.class);
- final MockTetheringConnector mockConnector =
- (MockTetheringConnector) mServiceTestRule.bindService(mMockServiceIntent);
- mTetheringConnector = mockConnector.getTetheringConnector();
- final MockTetheringService service = mockConnector.getService();
+ mMockConnector = (MockTetheringConnector) mServiceTestRule.bindService(mMockServiceIntent);
+ mTetheringConnector = mMockConnector.getTetheringConnector();
+ final MockTetheringService service = mMockConnector.getService();
mTethering = service.getTethering();
}
@@ -144,12 +146,18 @@
private void runTetheringCall(final TestTetheringCall test, String... permissions)
throws Exception {
+ // Allow the test to run even if ACCESS_NETWORK_STATE was granted at the APK level
+ if (!CollectionUtils.contains(permissions, ACCESS_NETWORK_STATE)) {
+ mMockConnector.setPermission(ACCESS_NETWORK_STATE, PERMISSION_DENIED);
+ }
+
if (permissions.length > 0) mUiAutomation.adoptShellPermissionIdentity(permissions);
try {
when(mTethering.isTetheringSupported()).thenReturn(true);
test.runTetheringCall(new TestTetheringResult());
} finally {
mUiAutomation.dropShellPermissionIdentity();
+ mMockConnector.setPermission(ACCESS_NETWORK_STATE, null);
}
}
diff --git a/framework/src/android/net/ConnectivityManager.java b/framework/src/android/net/ConnectivityManager.java
index e496966..758c612 100644
--- a/framework/src/android/net/ConnectivityManager.java
+++ b/framework/src/android/net/ConnectivityManager.java
@@ -4722,6 +4722,22 @@
}
/**
+ * Temporarily allow bad wifi to override {@code config_networkAvoidBadWifi} configuration.
+ *
+ * @param timeMs The expired current time. The value should be set within a limited time from
+ * now.
+ *
+ * @hide
+ */
+ public void setTestAllowBadWifiUntil(long timeMs) {
+ try {
+ mService.setTestAllowBadWifiUntil(timeMs);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Requests that the system open the captive portal app on the specified network.
*
* <p>This is to be used on networks where a captive portal was detected, as per
diff --git a/framework/src/android/net/ConnectivitySettingsManager.java b/framework/src/android/net/ConnectivitySettingsManager.java
index 4644e4f..085de6b 100644
--- a/framework/src/android/net/ConnectivitySettingsManager.java
+++ b/framework/src/android/net/ConnectivitySettingsManager.java
@@ -562,7 +562,7 @@
public static void setNetworkSwitchNotificationMaximumDailyCount(@NonNull Context context,
@IntRange(from = 0) int count) {
if (count < 0) {
- throw new IllegalArgumentException("Count must be 0~10.");
+ throw new IllegalArgumentException("Count must be more than 0.");
}
Settings.Global.putInt(
context.getContentResolver(), NETWORK_SWITCH_NOTIFICATION_DAILY_LIMIT, count);
@@ -585,6 +585,7 @@
/**
* Set minimum duration (to {@link Settings}) between each switching network notifications.
+ * The duration will be rounded down to the next millisecond, and must be positive.
*
* @param context The {@link Context} to set the setting.
* @param duration The minimum duration between notifications when switching networks.
@@ -612,10 +613,11 @@
/**
* Set URL (to {@link Settings}) used for HTTP captive portal detection upon a new connection.
- * This URL should respond with a 204 response to a GET request to indicate no captive portal is
- * present. And this URL must be HTTP as redirect responses are used to find captive portal
- * sign-in pages. If the URL set to null or be incorrect, it will result in captive portal
- * detection failed and lost the connection.
+ * The URL is accessed to check for connectivity and presence of a captive portal on a network.
+ * The URL should respond with HTTP status 204 to a GET request, and the stack will use
+ * redirection status as a signal for captive portal detection.
+ * If the URL is set to null or is otherwise incorrect or inaccessible, the stack will fail to
+ * detect connectivity and portals. This will often result in loss of connectivity.
*
* @param context The {@link Context} to set the setting.
* @param url The URL used for HTTP captive portal detection upon a new connection.
@@ -819,6 +821,7 @@
/**
* Set duration (to {@link Settings}) to keep a PendingIntent-based request.
+ * The duration will be rounded down to the next millisecond, and must be positive.
*
* @param context The {@link Context} to set the setting.
* @param duration The duration to keep a PendingIntent-based request.
diff --git a/framework/src/android/net/IConnectivityManager.aidl b/framework/src/android/net/IConnectivityManager.aidl
index c434bbc..50ec781 100644
--- a/framework/src/android/net/IConnectivityManager.aidl
+++ b/framework/src/android/net/IConnectivityManager.aidl
@@ -226,4 +226,6 @@
void offerNetwork(int providerId, in NetworkScore score,
in NetworkCapabilities caps, in INetworkOfferCallback callback);
void unofferNetwork(in INetworkOfferCallback callback);
+
+ void setTestAllowBadWifiUntil(long timeMs);
}
diff --git a/framework/src/android/net/util/MultinetworkPolicyTracker.java b/framework/src/android/net/util/MultinetworkPolicyTracker.java
index 0b42a00..7e62d28 100644
--- a/framework/src/android/net/util/MultinetworkPolicyTracker.java
+++ b/framework/src/android/net/util/MultinetworkPolicyTracker.java
@@ -75,6 +75,7 @@
private volatile boolean mAvoidBadWifi = true;
private volatile int mMeteredMultipathPreference;
private int mActiveSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
+ private volatile long mTestAllowBadWifiUntilMs = 0;
// Mainline module can't use internal HandlerExecutor, so add an identical executor here.
private static class HandlerExecutor implements Executor {
@@ -162,14 +163,31 @@
* Whether the device or carrier configuration disables avoiding bad wifi by default.
*/
public boolean configRestrictsAvoidBadWifi() {
+ final boolean allowBadWifi = mTestAllowBadWifiUntilMs > 0
+ && mTestAllowBadWifiUntilMs > System.currentTimeMillis();
+ // If the config returns true, then avoid bad wifi design can be controlled by the
+ // NETWORK_AVOID_BAD_WIFI setting.
+ if (allowBadWifi) return true;
+
// TODO: use R.integer.config_networkAvoidBadWifi directly
final int id = mResources.get().getIdentifier("config_networkAvoidBadWifi",
"integer", mResources.getResourcesContext().getPackageName());
return (getResourcesForActiveSubId().getInteger(id) == 0);
}
+ /**
+ * Temporarily allow bad wifi to override {@code config_networkAvoidBadWifi} configuration.
+ * The value works when the time set is more than {@link System.currentTimeMillis()}.
+ */
+ public void setTestAllowBadWifiUntil(long timeMs) {
+ Log.d(TAG, "setTestAllowBadWifiUntil: " + mTestAllowBadWifiUntilMs);
+ mTestAllowBadWifiUntilMs = timeMs;
+ updateAvoidBadWifi();
+ }
+
+ @VisibleForTesting
@NonNull
- private Resources getResourcesForActiveSubId() {
+ protected Resources getResourcesForActiveSubId() {
return SubscriptionManager.getResourcesForSubId(
mResources.getResourcesContext(), mActiveSubId);
}
diff --git a/service/src/com/android/server/ConnectivityService.java b/service/src/com/android/server/ConnectivityService.java
index 899286b..1f91eca 100644
--- a/service/src/com/android/server/ConnectivityService.java
+++ b/service/src/com/android/server/ConnectivityService.java
@@ -652,6 +652,12 @@
private static final int EVENT_MOBILE_DATA_PREFERRED_UIDS_CHANGED = 54;
/**
+ * Event to set temporary allow bad wifi within a limited time to override
+ * {@code config_networkAvoidBadWifi}.
+ */
+ private static final int EVENT_SET_TEST_ALLOW_BAD_WIFI_UNTIL = 55;
+
+ /**
* Argument for {@link #EVENT_PROVISIONING_NOTIFICATION} to indicate that the notification
* should be shown.
*/
@@ -663,6 +669,11 @@
*/
private static final int PROVISIONING_NOTIFICATION_HIDE = 0;
+ /**
+ * The maximum alive time to allow bad wifi configuration for testing.
+ */
+ private static final long MAX_TEST_ALLOW_BAD_WIFI_UNTIL_MS = 5 * 60 * 1000L;
+
private static String eventName(int what) {
return sMagicDecoderRing.get(what, Integer.toString(what));
}
@@ -1276,6 +1287,20 @@
public boolean getCellular464XlatEnabled() {
return NetworkProperties.isCellular464XlatEnabled().orElse(true);
}
+
+ /**
+ * @see PendingIntent#intentFilterEquals
+ */
+ public boolean intentFilterEquals(PendingIntent a, PendingIntent b) {
+ return a.intentFilterEquals(b);
+ }
+
+ /**
+ * @see LocationPermissionChecker
+ */
+ public LocationPermissionChecker makeLocationPermissionChecker(Context context) {
+ return new LocationPermissionChecker(context);
+ }
}
public ConnectivityService(Context context) {
@@ -1343,7 +1368,7 @@
mNetd = netd;
mTelephonyManager = (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
mAppOpsManager = (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE);
- mLocationPermissionChecker = new LocationPermissionChecker(mContext);
+ mLocationPermissionChecker = mDeps.makeLocationPermissionChecker(mContext);
// To ensure uid state is synchronized with Network Policy, register for
// NetworkPolicyManagerService events must happen prior to NetworkPolicyManagerService
@@ -3934,7 +3959,7 @@
for (Map.Entry<NetworkRequest, NetworkRequestInfo> entry : mNetworkRequests.entrySet()) {
PendingIntent existingPendingIntent = entry.getValue().mPendingIntent;
if (existingPendingIntent != null &&
- existingPendingIntent.intentFilterEquals(pendingIntent)) {
+ mDeps.intentFilterEquals(existingPendingIntent, pendingIntent)) {
return entry.getValue();
}
}
@@ -4328,6 +4353,22 @@
mHandler.sendMessage(mHandler.obtainMessage(EVENT_SET_AVOID_UNVALIDATED, network));
}
+ @Override
+ public void setTestAllowBadWifiUntil(long timeMs) {
+ enforceSettingsPermission();
+ if (!Build.isDebuggable()) {
+ throw new IllegalStateException("Does not support in non-debuggable build");
+ }
+
+ if (timeMs > System.currentTimeMillis() + MAX_TEST_ALLOW_BAD_WIFI_UNTIL_MS) {
+ throw new IllegalArgumentException("It should not exceed "
+ + MAX_TEST_ALLOW_BAD_WIFI_UNTIL_MS + "ms from now");
+ }
+
+ mHandler.sendMessage(
+ mHandler.obtainMessage(EVENT_SET_TEST_ALLOW_BAD_WIFI_UNTIL, timeMs));
+ }
+
private void handleSetAcceptUnvalidated(Network network, boolean accept, boolean always) {
if (DBG) log("handleSetAcceptUnvalidated network=" + network +
" accept=" + accept + " always=" + always);
@@ -4870,6 +4911,10 @@
case EVENT_MOBILE_DATA_PREFERRED_UIDS_CHANGED:
handleMobileDataPreferredUidsChanged();
break;
+ case EVENT_SET_TEST_ALLOW_BAD_WIFI_UNTIL:
+ final long timeMs = ((Long) msg.obj).longValue();
+ mMultinetworkPolicyTracker.setTestAllowBadWifiUntil(timeMs);
+ break;
}
}
}
diff --git a/tests/OWNERS b/tests/OWNERS
deleted file mode 100644
index d3836d4..0000000
--- a/tests/OWNERS
+++ /dev/null
@@ -1,8 +0,0 @@
-set noparent
-
-codewiz@google.com
-jchalard@google.com
-junyulai@google.com
-lorenzo@google.com
-reminv@google.com
-satk@google.com
diff --git a/tests/common/Android.bp b/tests/common/Android.bp
index e8963b9..28339f1 100644
--- a/tests/common/Android.bp
+++ b/tests/common/Android.bp
@@ -43,6 +43,53 @@
],
}
+android_test {
+ name: "ConnectivityCoverageTests",
+ // Tethering started on SDK 30
+ min_sdk_version: "30",
+ // TODO: change to 31 as soon as it is available
+ target_sdk_version: "30",
+ test_suites: ["device-tests", "mts"],
+ defaults: [
+ "framework-connectivity-test-defaults",
+ "FrameworksNetTests-jni-defaults",
+ "libnetworkstackutilsjni_deps",
+ ],
+ manifest: "AndroidManifest_coverage.xml",
+ test_config: "AndroidTest_Coverage.xml",
+ static_libs: [
+ // Added first so all tests use extended mockito, instead of all tests using regular mockito
+ // (some tests would fail).
+ // TODO: consider removing extended mockito usage in tests that use it, for performance
+ "mockito-target-extended-minus-junit4",
+ "FrameworksNetTestsLib",
+ "modules-utils-native-coverage-listener",
+ "NetdStaticLibTestsLib",
+ "NetworkStaticLibTestsLib",
+ "NetworkStackTestsLib",
+ "TetheringTestsLatestSdkLib",
+ "TetheringIntegrationTestsLatestSdkLib",
+ ],
+ jni_libs: [
+ // For mockito extended
+ "libdexmakerjvmtiagent",
+ "libstaticjvmtiagent",
+ // For NetworkStackUtils included in NetworkStackBase
+ "libnetworkstackutilsjni",
+ "libtetherutilsjni",
+ // For framework tests
+ "libservice-connectivity",
+ ],
+ libs: [
+ // Although not required to compile the static libs together, the "libs" used to build each
+ // of the common static test libs are necessary for R8 to avoid "Missing class" warnings and
+ // incorrect optimizations
+ "framework-tethering.impl",
+ "framework-wifi.stubs.module_lib",
+ ],
+ compile_multilib: "both",
+}
+
// defaults for tests that need to build against framework-connectivity's @hide APIs
// Only usable from targets that have visibility on framework-connectivity.impl.
// Instead of using this, consider avoiding to depend on hidden connectivity APIs in
diff --git a/tests/common/AndroidManifest_coverage.xml b/tests/common/AndroidManifest_coverage.xml
new file mode 100644
index 0000000..8a22792
--- /dev/null
+++ b/tests/common/AndroidManifest_coverage.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ package="com.android.connectivity.tests.coverage">
+
+ <application tools:replace="android:label"
+ android:debuggable="true"
+ android:label="Connectivity coverage tests">
+ <uses-library android:name="android.test.runner" />
+ </application>
+ <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="com.android.connectivity.tests.coverage"
+ android:label="Connectivity coverage tests">
+ </instrumentation>
+</manifest>
diff --git a/tests/common/AndroidTest_Coverage.xml b/tests/common/AndroidTest_Coverage.xml
new file mode 100644
index 0000000..577f36a
--- /dev/null
+++ b/tests/common/AndroidTest_Coverage.xml
@@ -0,0 +1,27 @@
+<!-- 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.
+-->
+<configuration description="Runs coverage tests for Connectivity">
+ <target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup">
+ <option name="test-file-name" value="ConnectivityCoverageTests.apk" />
+ </target_preparer>
+
+ <option name="test-tag" value="ConnectivityCoverageTests" />
+ <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+ <option name="package" value="com.android.connectivity.tests.coverage" />
+ <option name="runner" value="androidx.test.runner.AndroidJUnitRunner" />
+ <option name="hidden-api-checks" value="false"/>
+ <option name="device-listeners" value="com.android.modules.utils.testing.NativeCoverageHackInstrumentationListener" />
+ </test>
+</configuration>
diff --git a/tests/unit/java/android/net/ConnectivityDiagnosticsManagerTest.java b/tests/common/java/android/net/ConnectivityDiagnosticsManagerTest.java
similarity index 98%
rename from tests/unit/java/android/net/ConnectivityDiagnosticsManagerTest.java
rename to tests/common/java/android/net/ConnectivityDiagnosticsManagerTest.java
index 06e9405..294ed10 100644
--- a/tests/unit/java/android/net/ConnectivityDiagnosticsManagerTest.java
+++ b/tests/common/java/android/net/ConnectivityDiagnosticsManagerTest.java
@@ -36,9 +36,11 @@
import static org.mockito.Mockito.verifyNoMoreInteractions;
import android.content.Context;
+import android.os.Build;
import android.os.PersistableBundle;
import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SdkSuppress;
import org.junit.After;
import org.junit.Before;
@@ -50,6 +52,7 @@
import java.util.concurrent.Executor;
@RunWith(JUnit4.class)
+@SdkSuppress(minSdkVersion = Build.VERSION_CODES.S, codeName = "S")
public class ConnectivityDiagnosticsManagerTest {
private static final int NET_ID = 1;
private static final int DETECTION_METHOD = 2;
diff --git a/tests/common/java/android/net/ConnectivitySettingsManagerTest.kt b/tests/common/java/android/net/ConnectivitySettingsManagerTest.kt
new file mode 100644
index 0000000..ebaa787
--- /dev/null
+++ b/tests/common/java/android/net/ConnectivitySettingsManagerTest.kt
@@ -0,0 +1,295 @@
+/*
+ * 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.net.ConnectivitySettingsManager.CAPTIVE_PORTAL_MODE
+import android.net.ConnectivitySettingsManager.CAPTIVE_PORTAL_MODE_AVOID
+import android.net.ConnectivitySettingsManager.CAPTIVE_PORTAL_MODE_IGNORE
+import android.net.ConnectivitySettingsManager.CAPTIVE_PORTAL_MODE_PROMPT
+import android.net.ConnectivitySettingsManager.CONNECTIVITY_RELEASE_PENDING_INTENT_DELAY_MS
+import android.net.ConnectivitySettingsManager.DATA_ACTIVITY_TIMEOUT_MOBILE
+import android.net.ConnectivitySettingsManager.DATA_ACTIVITY_TIMEOUT_WIFI
+import android.net.ConnectivitySettingsManager.DNS_RESOLVER_MAX_SAMPLES
+import android.net.ConnectivitySettingsManager.DNS_RESOLVER_MIN_SAMPLES
+import android.net.ConnectivitySettingsManager.DNS_RESOLVER_SAMPLE_VALIDITY_SECONDS
+import android.net.ConnectivitySettingsManager.DNS_RESOLVER_SUCCESS_THRESHOLD_PERCENT
+import android.net.ConnectivitySettingsManager.MOBILE_DATA_ALWAYS_ON
+import android.net.ConnectivitySettingsManager.NETWORK_SWITCH_NOTIFICATION_DAILY_LIMIT
+import android.net.ConnectivitySettingsManager.NETWORK_SWITCH_NOTIFICATION_RATE_LIMIT_MILLIS
+import android.net.ConnectivitySettingsManager.PRIVATE_DNS_DEFAULT_MODE
+import android.net.ConnectivitySettingsManager.PRIVATE_DNS_MODE_OFF
+import android.net.ConnectivitySettingsManager.PRIVATE_DNS_MODE_OPPORTUNISTIC
+import android.net.ConnectivitySettingsManager.WIFI_ALWAYS_REQUESTED
+import android.net.ConnectivitySettingsManager.getCaptivePortalMode
+import android.net.ConnectivitySettingsManager.getConnectivityKeepPendingIntentDuration
+import android.net.ConnectivitySettingsManager.getDnsResolverSampleRanges
+import android.net.ConnectivitySettingsManager.getDnsResolverSampleValidityDuration
+import android.net.ConnectivitySettingsManager.getDnsResolverSuccessThresholdPercent
+import android.net.ConnectivitySettingsManager.getMobileDataActivityTimeout
+import android.net.ConnectivitySettingsManager.getMobileDataAlwaysOn
+import android.net.ConnectivitySettingsManager.getNetworkSwitchNotificationMaximumDailyCount
+import android.net.ConnectivitySettingsManager.getNetworkSwitchNotificationRateDuration
+import android.net.ConnectivitySettingsManager.getPrivateDnsDefaultMode
+import android.net.ConnectivitySettingsManager.getWifiAlwaysRequested
+import android.net.ConnectivitySettingsManager.getWifiDataActivityTimeout
+import android.net.ConnectivitySettingsManager.setCaptivePortalMode
+import android.net.ConnectivitySettingsManager.setConnectivityKeepPendingIntentDuration
+import android.net.ConnectivitySettingsManager.setDnsResolverSampleRanges
+import android.net.ConnectivitySettingsManager.setDnsResolverSampleValidityDuration
+import android.net.ConnectivitySettingsManager.setDnsResolverSuccessThresholdPercent
+import android.net.ConnectivitySettingsManager.setMobileDataActivityTimeout
+import android.net.ConnectivitySettingsManager.setMobileDataAlwaysOn
+import android.net.ConnectivitySettingsManager.setNetworkSwitchNotificationMaximumDailyCount
+import android.net.ConnectivitySettingsManager.setNetworkSwitchNotificationRateDuration
+import android.net.ConnectivitySettingsManager.setPrivateDnsDefaultMode
+import android.net.ConnectivitySettingsManager.setWifiAlwaysRequested
+import android.net.ConnectivitySettingsManager.setWifiDataActivityTimeout
+import android.os.Build
+import android.platform.test.annotations.AppModeFull
+import android.provider.Settings
+import android.util.Range
+import androidx.test.InstrumentationRegistry
+import androidx.test.filters.SmallTest
+import com.android.net.module.util.ConnectivitySettingsUtils.getPrivateDnsModeAsString
+import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo
+import com.android.testutils.DevSdkIgnoreRunner
+import junit.framework.Assert.assertEquals
+import org.junit.Test
+import org.junit.runner.RunWith
+import java.time.Duration
+import java.util.Objects
+import kotlin.test.assertFailsWith
+
+/**
+ * Tests for [ConnectivitySettingsManager].
+ *
+ * Build, install and run with:
+ * atest android.net.ConnectivitySettingsManagerTest
+ */
+@RunWith(DevSdkIgnoreRunner::class)
+@IgnoreUpTo(Build.VERSION_CODES.R)
+@SmallTest
+@AppModeFull(reason = "WRITE_SECURE_SETTINGS permission can't be granted to instant apps")
+class ConnectivitySettingsManagerTest {
+ private val instrumentation = InstrumentationRegistry.getInstrumentation()
+ private val context = instrumentation.context
+ private val resolver = context.contentResolver
+
+ private val defaultDuration = Duration.ofSeconds(0L)
+ private val testTime1 = 5L
+ private val testTime2 = 10L
+ private val settingsTypeGlobal = "global"
+ private val settingsTypeSecure = "secure"
+
+ /*** Reset setting value or delete setting if the setting was not existed before testing. */
+ private fun resetSettings(names: Array<String>, type: String, values: Array<String?>) {
+ for (i in names.indices) {
+ if (Objects.equals(values[i], null)) {
+ instrumentation.uiAutomation.executeShellCommand(
+ "settings delete $type ${names[i]}")
+ } else {
+ if (settingsTypeSecure.equals(type)) {
+ Settings.Secure.putString(resolver, names[i], values[i])
+ } else {
+ Settings.Global.putString(resolver, names[i], values[i])
+ }
+ }
+ }
+ }
+
+ fun <T> testIntSetting(
+ names: Array<String>,
+ type: String,
+ value1: T,
+ value2: T,
+ getter: () -> T,
+ setter: (value: T) -> Unit,
+ testIntValues: IntArray
+ ) {
+ val originals: Array<String?> = Array(names.size) { i ->
+ if (settingsTypeSecure.equals(type)) {
+ Settings.Secure.getString(resolver, names[i])
+ } else {
+ Settings.Global.getString(resolver, names[i])
+ }
+ }
+
+ try {
+ for (i in names.indices) {
+ if (settingsTypeSecure.equals(type)) {
+ Settings.Secure.putString(resolver, names[i], testIntValues[i].toString())
+ } else {
+ Settings.Global.putString(resolver, names[i], testIntValues[i].toString())
+ }
+ }
+ assertEquals(value1, getter())
+
+ setter(value2)
+ assertEquals(value2, getter())
+ } finally {
+ resetSettings(names, type, originals)
+ }
+ }
+
+ @Test
+ fun testMobileDataActivityTimeout() {
+ testIntSetting(names = arrayOf(DATA_ACTIVITY_TIMEOUT_MOBILE), type = settingsTypeGlobal,
+ value1 = Duration.ofSeconds(testTime1), value2 = Duration.ofSeconds(testTime2),
+ getter = { getMobileDataActivityTimeout(context, defaultDuration) },
+ setter = { setMobileDataActivityTimeout(context, it) },
+ testIntValues = intArrayOf(testTime1.toInt()))
+ }
+
+ @Test
+ fun testWifiDataActivityTimeout() {
+ testIntSetting(names = arrayOf(DATA_ACTIVITY_TIMEOUT_WIFI), type = settingsTypeGlobal,
+ value1 = Duration.ofSeconds(testTime1), value2 = Duration.ofSeconds(testTime2),
+ getter = { getWifiDataActivityTimeout(context, defaultDuration) },
+ setter = { setWifiDataActivityTimeout(context, it) },
+ testIntValues = intArrayOf(testTime1.toInt()))
+ }
+
+ @Test
+ fun testDnsResolverSampleValidityDuration() {
+ testIntSetting(names = arrayOf(DNS_RESOLVER_SAMPLE_VALIDITY_SECONDS),
+ type = settingsTypeGlobal, value1 = Duration.ofSeconds(testTime1),
+ value2 = Duration.ofSeconds(testTime2),
+ getter = { getDnsResolverSampleValidityDuration(context, defaultDuration) },
+ setter = { setDnsResolverSampleValidityDuration(context, it) },
+ testIntValues = intArrayOf(testTime1.toInt()))
+
+ assertFailsWith<IllegalArgumentException>("Expect fail but argument accepted.") {
+ setDnsResolverSampleValidityDuration(context, Duration.ofSeconds(-1L)) }
+ }
+
+ @Test
+ fun testDnsResolverSuccessThresholdPercent() {
+ testIntSetting(names = arrayOf(DNS_RESOLVER_SUCCESS_THRESHOLD_PERCENT),
+ type = settingsTypeGlobal, value1 = 5, value2 = 10,
+ getter = { getDnsResolverSuccessThresholdPercent(context, 0 /* def */) },
+ setter = { setDnsResolverSuccessThresholdPercent(context, it) },
+ testIntValues = intArrayOf(5))
+
+ assertFailsWith<IllegalArgumentException>("Expect fail but argument accepted.") {
+ setDnsResolverSuccessThresholdPercent(context, -1) }
+ assertFailsWith<IllegalArgumentException>("Expect fail but argument accepted.") {
+ setDnsResolverSuccessThresholdPercent(context, 120) }
+ }
+
+ @Test
+ fun testDnsResolverSampleRanges() {
+ testIntSetting(names = arrayOf(DNS_RESOLVER_MIN_SAMPLES, DNS_RESOLVER_MAX_SAMPLES),
+ type = settingsTypeGlobal, value1 = Range(1, 63), value2 = Range(2, 62),
+ getter = { getDnsResolverSampleRanges(context) },
+ setter = { setDnsResolverSampleRanges(context, it) },
+ testIntValues = intArrayOf(1, 63))
+
+ assertFailsWith<IllegalArgumentException>("Expect fail but argument accepted.") {
+ setDnsResolverSampleRanges(context, Range(-1, 62)) }
+ assertFailsWith<IllegalArgumentException>("Expect fail but argument accepted.") {
+ setDnsResolverSampleRanges(context, Range(2, 65)) }
+ }
+
+ @Test
+ fun testNetworkSwitchNotificationMaximumDailyCount() {
+ testIntSetting(names = arrayOf(NETWORK_SWITCH_NOTIFICATION_DAILY_LIMIT),
+ type = settingsTypeGlobal, value1 = 5, value2 = 15,
+ getter = { getNetworkSwitchNotificationMaximumDailyCount(context, 0 /* def */) },
+ setter = { setNetworkSwitchNotificationMaximumDailyCount(context, it) },
+ testIntValues = intArrayOf(5))
+
+ assertFailsWith<IllegalArgumentException>("Expect fail but argument accepted.") {
+ setNetworkSwitchNotificationMaximumDailyCount(context, -1) }
+ }
+
+ @Test
+ fun testNetworkSwitchNotificationRateDuration() {
+ testIntSetting(names = arrayOf(NETWORK_SWITCH_NOTIFICATION_RATE_LIMIT_MILLIS),
+ type = settingsTypeGlobal, value1 = Duration.ofMillis(testTime1),
+ value2 = Duration.ofMillis(testTime2),
+ getter = { getNetworkSwitchNotificationRateDuration(context, defaultDuration) },
+ setter = { setNetworkSwitchNotificationRateDuration(context, it) },
+ testIntValues = intArrayOf(testTime1.toInt()))
+
+ assertFailsWith<IllegalArgumentException>("Expect fail but argument accepted.") {
+ setNetworkSwitchNotificationRateDuration(context, Duration.ofMillis(-1L)) }
+ }
+
+ @Test
+ fun testCaptivePortalMode() {
+ testIntSetting(names = arrayOf(CAPTIVE_PORTAL_MODE), type = settingsTypeGlobal,
+ value1 = CAPTIVE_PORTAL_MODE_AVOID, value2 = CAPTIVE_PORTAL_MODE_PROMPT,
+ getter = { getCaptivePortalMode(context, CAPTIVE_PORTAL_MODE_IGNORE) },
+ setter = { setCaptivePortalMode(context, it) },
+ testIntValues = intArrayOf(CAPTIVE_PORTAL_MODE_AVOID))
+
+ assertFailsWith<IllegalArgumentException>("Expect fail but argument accepted.") {
+ setCaptivePortalMode(context, 5 /* mode */) }
+ }
+
+ @Test
+ fun testPrivateDnsDefaultMode() {
+ val original = Settings.Global.getString(resolver, PRIVATE_DNS_DEFAULT_MODE)
+
+ try {
+ val mode = getPrivateDnsModeAsString(PRIVATE_DNS_MODE_OPPORTUNISTIC)
+ Settings.Global.putString(resolver, PRIVATE_DNS_DEFAULT_MODE, mode)
+ assertEquals(mode, getPrivateDnsDefaultMode(context))
+
+ setPrivateDnsDefaultMode(context, PRIVATE_DNS_MODE_OFF)
+ assertEquals(getPrivateDnsModeAsString(PRIVATE_DNS_MODE_OFF),
+ getPrivateDnsDefaultMode(context))
+ } finally {
+ resetSettings(names = arrayOf(PRIVATE_DNS_DEFAULT_MODE), type = settingsTypeGlobal,
+ values = arrayOf(original))
+ }
+
+ assertFailsWith<IllegalArgumentException>("Expect fail but argument accepted.") {
+ setPrivateDnsDefaultMode(context, -1) }
+ }
+
+ @Test
+ fun testConnectivityKeepPendingIntentDuration() {
+ testIntSetting(names = arrayOf(CONNECTIVITY_RELEASE_PENDING_INTENT_DELAY_MS),
+ type = settingsTypeSecure, value1 = Duration.ofMillis(testTime1),
+ value2 = Duration.ofMillis(testTime2),
+ getter = { getConnectivityKeepPendingIntentDuration(context, defaultDuration) },
+ setter = { setConnectivityKeepPendingIntentDuration(context, it) },
+ testIntValues = intArrayOf(testTime1.toInt()))
+
+ assertFailsWith<IllegalArgumentException>("Expect fail but argument accepted.") {
+ setConnectivityKeepPendingIntentDuration(context, Duration.ofMillis(-1L)) }
+ }
+
+ @Test
+ fun testMobileDataAlwaysOn() {
+ testIntSetting(names = arrayOf(MOBILE_DATA_ALWAYS_ON), type = settingsTypeGlobal,
+ value1 = false, value2 = true,
+ getter = { getMobileDataAlwaysOn(context, true /* def */) },
+ setter = { setMobileDataAlwaysOn(context, it) },
+ testIntValues = intArrayOf(0))
+ }
+
+ @Test
+ fun testWifiAlwaysRequested() {
+ testIntSetting(names = arrayOf(WIFI_ALWAYS_REQUESTED), type = settingsTypeGlobal,
+ value1 = false, value2 = true,
+ getter = { getWifiAlwaysRequested(context, true /* def */) },
+ setter = { setWifiAlwaysRequested(context, it) },
+ testIntValues = intArrayOf(0))
+ }
+}
\ No newline at end of file
diff --git a/tests/cts/net/jni/Android.bp b/tests/cts/net/jni/Android.bp
index 13f38d7..8f0d78f 100644
--- a/tests/cts/net/jni/Android.bp
+++ b/tests/cts/net/jni/Android.bp
@@ -16,35 +16,14 @@
default_applicable_licenses: ["Android-Apache-2.0"],
}
-cc_library_shared {
- name: "libnativedns_jni",
+cc_defaults {
+ name: "net_jni_defaults",
- srcs: ["NativeDnsJni.c"],
- sdk_version: "current",
-
- shared_libs: [
- "libnativehelper_compat_libc++",
- "liblog",
- ],
- stl: "libc++_static",
-
- cflags: [
- "-Wall",
- "-Werror",
- "-Wno-unused-parameter",
- ],
-
-}
-
-cc_library_shared {
- name: "libnativemultinetwork_jni",
-
- srcs: ["NativeMultinetworkJni.cpp"],
- sdk_version: "current",
cflags: [
"-Wall",
"-Werror",
"-Wno-format",
+ "-Wno-unused-parameter",
],
shared_libs: [
"libandroid",
@@ -52,4 +31,19 @@
"liblog",
],
stl: "libc++_static",
+ // To be compatible with Q devices, the min_sdk_version must be 29.
+ sdk_version: "current",
+ min_sdk_version: "29",
+}
+
+cc_library_shared {
+ name: "libnativedns_jni",
+ defaults: ["net_jni_defaults"],
+ srcs: ["NativeDnsJni.c"],
+}
+
+cc_library_shared {
+ name: "libnativemultinetwork_jni",
+ defaults: ["net_jni_defaults"],
+ srcs: ["NativeMultinetworkJni.cpp"],
}
diff --git a/tests/cts/net/native/dns/Android.bp b/tests/cts/net/native/dns/Android.bp
index 5e9af8e..434e529 100644
--- a/tests/cts/net/native/dns/Android.bp
+++ b/tests/cts/net/native/dns/Android.bp
@@ -24,6 +24,8 @@
"liblog",
"libutils",
],
+ // To be compatible with Q devices, the min_sdk_version must be 29.
+ min_sdk_version: "29",
}
cc_test {
diff --git a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java
index c2613c8..dc1fd34 100644
--- a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java
+++ b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java
@@ -29,6 +29,8 @@
import static android.content.pm.PackageManager.FEATURE_WIFI_DIRECT;
import static android.content.pm.PackageManager.GET_PERMISSIONS;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
+import static android.net.ConnectivityManager.EXTRA_NETWORK;
+import static android.net.ConnectivityManager.EXTRA_NETWORK_REQUEST;
import static android.net.ConnectivityManager.PROFILE_NETWORK_PREFERENCE_ENTERPRISE;
import static android.net.ConnectivityManager.TYPE_BLUETOOTH;
import static android.net.ConnectivityManager.TYPE_ETHERNET;
@@ -74,12 +76,14 @@
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.modules.utils.build.SdkLevel.isAtLeastS;
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.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
@@ -206,6 +210,7 @@
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
+import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Supplier;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -849,6 +854,119 @@
}
}
+ private void runIdenticalPendingIntentsRequestTest(boolean useListen) throws Exception {
+ assumeTrue(mPackageManager.hasSystemFeature(FEATURE_WIFI));
+
+ // Disconnect before registering callbacks, reconnect later to fire them
+ mCtsNetUtils.ensureWifiDisconnected(null);
+
+ final NetworkRequest firstRequest = makeWifiNetworkRequest();
+ final NetworkRequest secondRequest = new NetworkRequest(firstRequest);
+ // Will match wifi or test, since transports are ORed; but there should only be wifi
+ secondRequest.networkCapabilities.addTransportType(TRANSPORT_TEST);
+
+ PendingIntent firstIntent = null;
+ PendingIntent secondIntent = null;
+ BroadcastReceiver receiver = null;
+
+ // Avoid receiving broadcasts from other runs by appending a timestamp
+ final String broadcastAction = NETWORK_CALLBACK_ACTION + System.currentTimeMillis();
+ try {
+ // TODO: replace with PendingIntent.FLAG_MUTABLE when this code compiles against S+
+ // Intent is mutable to receive EXTRA_NETWORK_REQUEST from ConnectivityService
+ final int pendingIntentFlagMutable = 1 << 25;
+ final String extraBoolKey = "extra_bool";
+ firstIntent = PendingIntent.getBroadcast(mContext,
+ 0 /* requestCode */,
+ new Intent(broadcastAction).putExtra(extraBoolKey, false),
+ PendingIntent.FLAG_UPDATE_CURRENT | pendingIntentFlagMutable);
+
+ if (useListen) {
+ mCm.registerNetworkCallback(firstRequest, firstIntent);
+ } else {
+ mCm.requestNetwork(firstRequest, firstIntent);
+ }
+
+ // Second intent equals the first as per filterEquals (extras don't count), so first
+ // intent will be updated with the new extras
+ secondIntent = PendingIntent.getBroadcast(mContext,
+ 0 /* requestCode */,
+ new Intent(broadcastAction).putExtra(extraBoolKey, true),
+ PendingIntent.FLAG_UPDATE_CURRENT | pendingIntentFlagMutable);
+
+ // Because secondIntent.intentFilterEquals the first, the request should be replaced
+ if (useListen) {
+ mCm.registerNetworkCallback(secondRequest, secondIntent);
+ } else {
+ mCm.requestNetwork(secondRequest, secondIntent);
+ }
+
+ final IntentFilter filter = new IntentFilter();
+ filter.addAction(broadcastAction);
+
+ final CompletableFuture<Network> networkFuture = new CompletableFuture<>();
+ final AtomicInteger receivedCount = new AtomicInteger(0);
+ receiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ final NetworkRequest request = intent.getParcelableExtra(EXTRA_NETWORK_REQUEST);
+ assertPendingIntentRequestMatches(request, secondRequest, useListen);
+ receivedCount.incrementAndGet();
+ networkFuture.complete(intent.getParcelableExtra(EXTRA_NETWORK));
+ }
+ };
+ mContext.registerReceiver(receiver, filter);
+
+ final Network wifiNetwork = mCtsNetUtils.ensureWifiConnected();
+ try {
+ assertEquals(wifiNetwork, networkFuture.get(
+ NETWORK_CALLBACK_TIMEOUT_MS, TimeUnit.MILLISECONDS));
+ } catch (TimeoutException e) {
+ throw new AssertionError("PendingIntent not received for " + secondRequest, e);
+ }
+
+ // Sleep for a small amount of time to try to check that only one callback is ever
+ // received (so the first callback was really unregistered). This does not guarantee
+ // that the test will fail if it runs very slowly, but it should at least be very
+ // noticeably flaky.
+ Thread.sleep(NO_CALLBACK_TIMEOUT_MS);
+
+ // TODO: BUG (b/189868426): this should also apply to listens
+ if (!useListen) {
+ assertEquals("PendingIntent should only be received once", 1, receivedCount.get());
+ }
+ } finally {
+ if (firstIntent != null) mCm.unregisterNetworkCallback(firstIntent);
+ if (secondIntent != null) mCm.unregisterNetworkCallback(secondIntent);
+ if (receiver != null) mContext.unregisterReceiver(receiver);
+ mCtsNetUtils.ensureWifiConnected();
+ }
+ }
+
+ private void assertPendingIntentRequestMatches(NetworkRequest broadcasted, NetworkRequest filed,
+ boolean useListen) {
+ // TODO: BUG (b/191713869): on S the request extra is null on listens
+ if (isAtLeastS() && useListen && broadcasted == null) return;
+ assertArrayEquals(filed.networkCapabilities.getCapabilities(),
+ broadcasted.networkCapabilities.getCapabilities());
+ // TODO: BUG (b/189868426): this should also apply to listens
+ if (useListen) return;
+ assertArrayEquals(filed.networkCapabilities.getTransportTypes(),
+ broadcasted.networkCapabilities.getTransportTypes());
+ }
+
+ @AppModeFull(reason = "Cannot get WifiManager in instant app mode")
+ @Test
+ public void testRegisterNetworkRequest_identicalPendingIntents() throws Exception {
+ runIdenticalPendingIntentsRequestTest(false /* useListen */);
+ }
+
+ @AppModeFull(reason = "Cannot get WifiManager in instant app mode")
+ @Test
+ public void testRegisterNetworkCallback_identicalPendingIntents() throws Exception {
+ runIdenticalPendingIntentsRequestTest(true /* useListen */);
+ }
+
/**
* Exercises the requestNetwork with NetworkCallback API. This checks to
* see if we get a callback for an INTERNET request.
diff --git a/tests/cts/net/src/android/net/cts/IpSecManagerTunnelTest.java b/tests/cts/net/src/android/net/cts/IpSecManagerTunnelTest.java
index ae38faa..a9a3380 100644
--- a/tests/cts/net/src/android/net/cts/IpSecManagerTunnelTest.java
+++ b/tests/cts/net/src/android/net/cts/IpSecManagerTunnelTest.java
@@ -43,6 +43,7 @@
import android.net.ConnectivityManager;
import android.net.IpSecAlgorithm;
import android.net.IpSecManager;
+import android.net.IpSecManager.IpSecTunnelInterface;
import android.net.IpSecTransform;
import android.net.LinkAddress;
import android.net.Network;
@@ -50,25 +51,33 @@
import android.net.TestNetworkManager;
import android.net.cts.PacketUtils.Payload;
import android.net.cts.util.CtsNetUtils;
+import android.os.Build;
import android.os.ParcelFileDescriptor;
import android.platform.test.annotations.AppModeFull;
import androidx.test.InstrumentationRegistry;
import androidx.test.runner.AndroidJUnit4;
-import java.net.Inet6Address;
-import java.net.InetAddress;
-import java.net.NetworkInterface;
+import com.android.testutils.DevSdkIgnoreRule;
+import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
+import java.net.Inet4Address;
+import java.net.Inet6Address;
+import java.net.InetAddress;
+import java.net.NetworkInterface;
+
@RunWith(AndroidJUnit4.class)
@AppModeFull(reason = "MANAGE_TEST_NETWORKS permission can't be granted to instant apps")
public class IpSecManagerTunnelTest extends IpSecBaseTest {
+ @Rule public final DevSdkIgnoreRule ignoreRule = new DevSdkIgnoreRule();
+
private static final String TAG = IpSecManagerTunnelTest.class.getSimpleName();
private static final InetAddress LOCAL_OUTER_4 = InetAddress.parseNumericAddress("192.0.2.1");
@@ -78,6 +87,15 @@
private static final InetAddress REMOTE_OUTER_6 =
InetAddress.parseNumericAddress("2001:db8:1::2");
+ private static final InetAddress LOCAL_OUTER_4_NEW =
+ InetAddress.parseNumericAddress("192.0.2.101");
+ private static final InetAddress REMOTE_OUTER_4_NEW =
+ InetAddress.parseNumericAddress("192.0.2.102");
+ private static final InetAddress LOCAL_OUTER_6_NEW =
+ InetAddress.parseNumericAddress("2001:db8:1::101");
+ private static final InetAddress REMOTE_OUTER_6_NEW =
+ InetAddress.parseNumericAddress("2001:db8:1::102");
+
private static final InetAddress LOCAL_INNER_4 =
InetAddress.parseNumericAddress("198.51.100.1");
private static final InetAddress REMOTE_INNER_4 =
@@ -95,10 +113,9 @@
// Static state to reduce setup/teardown
private static ConnectivityManager sCM;
private static TestNetworkManager sTNM;
- private static ParcelFileDescriptor sTunFd;
- private static TestNetworkCallback sTunNetworkCallback;
- private static Network sTunNetwork;
- private static TunUtils sTunUtils;
+
+ private static TunNetworkWrapper sTunWrapper;
+ private static TunNetworkWrapper sTunWrapperNew;
private static Context sContext = InstrumentationRegistry.getContext();
private static final CtsNetUtils mCtsNetUtils = new CtsNetUtils(sContext);
@@ -116,19 +133,8 @@
// right appop permissions.
mCtsNetUtils.setAppopPrivileged(OP_MANAGE_IPSEC_TUNNELS, true);
- TestNetworkInterface testIface =
- sTNM.createTunInterface(
- new LinkAddress[] {
- new LinkAddress(LOCAL_OUTER_4, IP4_PREFIX_LEN),
- new LinkAddress(LOCAL_OUTER_6, IP6_PREFIX_LEN)
- });
-
- sTunFd = testIface.getFileDescriptor();
- sTunNetworkCallback = mCtsNetUtils.setupAndGetTestNetwork(testIface.getInterfaceName());
- sTunNetworkCallback.waitForAvailable();
- sTunNetwork = sTunNetworkCallback.currentNetwork;
-
- sTunUtils = new TunUtils(sTunFd);
+ sTunWrapper = new TunNetworkWrapper(LOCAL_OUTER_4, LOCAL_OUTER_6);
+ sTunWrapperNew = new TunNetworkWrapper(LOCAL_OUTER_4_NEW, LOCAL_OUTER_6_NEW);
}
@Before
@@ -139,24 +145,76 @@
// Set to true before every run; some tests flip this.
mCtsNetUtils.setAppopPrivileged(OP_MANAGE_IPSEC_TUNNELS, true);
- // Clear sTunUtils state
- sTunUtils.reset();
+ // Clear TunUtils state
+ sTunWrapper.utils.reset();
+ sTunWrapperNew.utils.reset();
+ }
+
+ private static void tearDownTunWrapperIfNotNull(TunNetworkWrapper tunWrapper) throws Exception {
+ if (tunWrapper != null) {
+ tunWrapper.tearDown();
+ }
}
@AfterClass
public static void tearDownAfterClass() throws Exception {
mCtsNetUtils.setAppopPrivileged(OP_MANAGE_IPSEC_TUNNELS, false);
- sCM.unregisterNetworkCallback(sTunNetworkCallback);
-
- sTNM.teardownTestNetwork(sTunNetwork);
- sTunFd.close();
+ tearDownTunWrapperIfNotNull(sTunWrapper);
+ tearDownTunWrapperIfNotNull(sTunWrapperNew);
InstrumentationRegistry.getInstrumentation()
.getUiAutomation()
.dropShellPermissionIdentity();
}
+ private static class TunNetworkWrapper {
+ public final ParcelFileDescriptor fd;
+ public final TestNetworkCallback networkCallback;
+ public final Network network;
+ public final TunUtils utils;
+
+ TunNetworkWrapper(InetAddress... addresses) throws Exception {
+ final LinkAddress[] linkAddresses = new LinkAddress[addresses.length];
+ for (int i = 0; i < linkAddresses.length; i++) {
+ InetAddress addr = addresses[i];
+ if (addr instanceof Inet4Address) {
+ linkAddresses[i] = new LinkAddress(addr, IP4_PREFIX_LEN);
+ } else {
+ linkAddresses[i] = new LinkAddress(addr, IP6_PREFIX_LEN);
+ }
+ }
+
+ try {
+ final TestNetworkInterface testIface = sTNM.createTunInterface(linkAddresses);
+
+ fd = testIface.getFileDescriptor();
+ networkCallback = mCtsNetUtils.setupAndGetTestNetwork(testIface.getInterfaceName());
+ networkCallback.waitForAvailable();
+ network = networkCallback.currentNetwork;
+ } catch (Exception e) {
+ tearDown();
+ throw e;
+ }
+
+ utils = new TunUtils(fd);
+ }
+
+ public void tearDown() throws Exception {
+ if (networkCallback != null) {
+ sCM.unregisterNetworkCallback(networkCallback);
+ }
+
+ if (network != null) {
+ sTNM.teardownTestNetwork(network);
+ }
+
+ if (fd != null) {
+ fd.close();
+ }
+ }
+ }
+
@Test
public void testSecurityExceptionCreateTunnelInterfaceWithoutAppop() throws Exception {
assumeTrue(mCtsNetUtils.hasIpsecTunnelsFeature());
@@ -166,7 +224,7 @@
// Security exceptions are thrown regardless of IPv4/IPv6. Just test one
try {
- mISM.createIpSecTunnelInterface(LOCAL_INNER_6, REMOTE_INNER_6, sTunNetwork);
+ mISM.createIpSecTunnelInterface(LOCAL_INNER_6, REMOTE_INNER_6, sTunWrapper.network);
fail("Did not throw SecurityException for Tunnel creation without appop");
} catch (SecurityException expected) {
}
@@ -196,11 +254,16 @@
* Runs the test code, and returns the inner socket port, if any.
*
* @param ipsecNetwork The IPsec Interface based Network for binding sockets on
+ * @param tunnelIface The IPsec tunnel interface that will be tested
+ * @param underlyingTunUtils The utility of the IPsec tunnel interface's underlying TUN
+ * network
* @return the integer port of the inner socket if outbound, or 0 if inbound
* IpSecTunnelTestRunnable
* @throws Exception if any part of the test failed.
*/
- public abstract int run(Network ipsecNetwork) throws Exception;
+ public abstract int run(
+ Network ipsecNetwork, IpSecTunnelInterface tunnelIface, TunUtils underlyingTunUtils)
+ throws Exception;
}
private int getPacketSize(
@@ -265,7 +328,9 @@
int expectedPacketSize) {
return new IpSecTunnelTestRunnable() {
@Override
- public int run(Network ipsecNetwork) throws Exception {
+ public int run(
+ Network ipsecNetwork, IpSecTunnelInterface tunnelIface, TunUtils tunUtils)
+ throws Exception {
// Build a socket and send traffic
JavaUdpSocket socket = new JavaUdpSocket(localInner);
ipsecNetwork.bindSocket(socket.mSocket);
@@ -284,7 +349,7 @@
// Verify that an encrypted packet is sent. As of right now, checking encrypted
// body is not possible, due to the test not knowing some of the fields of the
// inner IP header (flow label, flags, etc)
- sTunUtils.awaitEspPacketNoPlaintext(
+ tunUtils.awaitEspPacketNoPlaintext(
spi, TEST_DATA, encapPort != 0, expectedPacketSize);
socket.close();
@@ -312,7 +377,9 @@
throws Exception {
return new IpSecTunnelTestRunnable() {
@Override
- public int run(Network ipsecNetwork) throws Exception {
+ public int run(
+ Network ipsecNetwork, IpSecTunnelInterface tunnelIface, TunUtils tunUtils)
+ throws Exception {
// Build a socket and receive traffic
JavaUdpSocket socket = new JavaUdpSocket(localInner, innerSocketPort);
ipsecNetwork.bindSocket(socket.mSocket);
@@ -325,7 +392,7 @@
socket.mSocket, IpSecManager.DIRECTION_OUT, inTransportTransform);
}
- sTunUtils.reflectPackets();
+ tunUtils.reflectPackets();
// Receive packet from socket, and validate that the payload is correct
receiveAndValidatePacket(socket);
@@ -355,7 +422,9 @@
throws Exception {
return new IpSecTunnelTestRunnable() {
@Override
- public int run(Network ipsecNetwork) throws Exception {
+ public int run(
+ Network ipsecNetwork, IpSecTunnelInterface tunnelIface, TunUtils tunUtils)
+ throws Exception {
// Build a socket and receive traffic
JavaUdpSocket socket = new JavaUdpSocket(localInner);
ipsecNetwork.bindSocket(socket.mSocket);
@@ -391,7 +460,7 @@
socket.getPort(),
encapPort);
}
- sTunUtils.injectPacket(pkt);
+ tunUtils.injectPacket(pkt);
// Receive packet from socket, and validate
receiveAndValidatePacket(socket);
@@ -404,6 +473,161 @@
}
}
+ private class MigrateIpSecTunnelTestRunnableFactory implements IpSecTunnelTestRunnableFactory {
+ private final IpSecTunnelTestRunnableFactory mTestRunnableFactory;
+
+ MigrateIpSecTunnelTestRunnableFactory(boolean isOutputTest) {
+ if (isOutputTest) {
+ mTestRunnableFactory = new OutputIpSecTunnelTestRunnableFactory();
+ } else {
+ mTestRunnableFactory = new InputPacketGeneratorIpSecTunnelTestRunnableFactory();
+ }
+ }
+
+ @Override
+ public IpSecTunnelTestRunnable getIpSecTunnelTestRunnable(
+ boolean transportInTunnelMode,
+ int spi,
+ InetAddress localInner,
+ InetAddress remoteInner,
+ InetAddress localOuter,
+ InetAddress remoteOuter,
+ IpSecTransform inTransportTransform,
+ IpSecTransform outTransportTransform,
+ int encapPort,
+ int unusedInnerSocketPort,
+ int expectedPacketSize) {
+ return new IpSecTunnelTestRunnable() {
+ @Override
+ public int run(
+ Network ipsecNetwork, IpSecTunnelInterface tunnelIface, TunUtils tunUtils)
+ throws Exception {
+ mTestRunnableFactory
+ .getIpSecTunnelTestRunnable(
+ transportInTunnelMode,
+ spi,
+ localInner,
+ remoteInner,
+ localOuter,
+ remoteOuter,
+ inTransportTransform,
+ outTransportTransform,
+ encapPort,
+ unusedInnerSocketPort,
+ expectedPacketSize)
+ .run(ipsecNetwork, tunnelIface, sTunWrapper.utils);
+
+ tunnelIface.setUnderlyingNetwork(sTunWrapperNew.network);
+
+ // Verify migrating to IPv4 and IPv6 addresses. It ensures that not only
+ // can IPsec tunnel migrate across interfaces, IPsec tunnel can also migrate to
+ // a different address on the same interface.
+ checkMigratedTunnel(
+ localInner,
+ remoteInner,
+ LOCAL_OUTER_4_NEW,
+ REMOTE_OUTER_4_NEW,
+ encapPort != 0,
+ transportInTunnelMode,
+ sTunWrapperNew.utils,
+ tunnelIface,
+ ipsecNetwork);
+ checkMigratedTunnel(
+ localInner,
+ remoteInner,
+ LOCAL_OUTER_6_NEW,
+ REMOTE_OUTER_6_NEW,
+ false, // IPv6 does not support UDP encapsulation
+ transportInTunnelMode,
+ sTunWrapperNew.utils,
+ tunnelIface,
+ ipsecNetwork);
+
+ return 0;
+ }
+ };
+ }
+
+ private void checkMigratedTunnel(
+ InetAddress localInner,
+ InetAddress remoteInner,
+ InetAddress localOuter,
+ InetAddress remoteOuter,
+ boolean useEncap,
+ boolean transportInTunnelMode,
+ TunUtils tunUtils,
+ IpSecTunnelInterface tunnelIface,
+ Network ipsecNetwork)
+ throws Exception {
+
+ // Preselect both SPI and encap port, to be used for both inbound and outbound tunnels.
+ // Re-uses the same SPI to ensure that even in cases of symmetric SPIs shared across
+ // tunnel and transport mode, packets are encrypted/decrypted properly based on the
+ // src/dst.
+ int spi = getRandomSpi(localOuter, remoteOuter);
+
+ int innerFamily = localInner instanceof Inet4Address ? AF_INET : AF_INET6;
+ int outerFamily = localOuter instanceof Inet4Address ? AF_INET : AF_INET6;
+ int expectedPacketSize =
+ getPacketSize(innerFamily, outerFamily, useEncap, transportInTunnelMode);
+
+ // Build transport mode transforms and encapsulation socket for verifying
+ // transport-in-tunnel case and encapsulation case.
+ try (IpSecManager.SecurityParameterIndex inTransportSpi =
+ mISM.allocateSecurityParameterIndex(localInner, spi);
+ IpSecManager.SecurityParameterIndex outTransportSpi =
+ mISM.allocateSecurityParameterIndex(remoteInner, spi);
+ IpSecTransform inTransportTransform =
+ buildIpSecTransform(sContext, inTransportSpi, null, remoteInner);
+ IpSecTransform outTransportTransform =
+ buildIpSecTransform(sContext, outTransportSpi, null, localInner);
+ UdpEncapsulationSocket encapSocket = mISM.openUdpEncapsulationSocket()) {
+
+ // Configure tunnel mode Transform parameters
+ IpSecTransform.Builder transformBuilder = new IpSecTransform.Builder(sContext);
+ transformBuilder.setEncryption(
+ new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY));
+ transformBuilder.setAuthentication(
+ new IpSecAlgorithm(
+ IpSecAlgorithm.AUTH_HMAC_SHA256, AUTH_KEY, AUTH_KEY.length * 4));
+
+ if (useEncap) {
+ transformBuilder.setIpv4Encapsulation(encapSocket, encapSocket.getPort());
+ }
+
+ // Apply transform and check that traffic is properly encrypted
+ try (IpSecManager.SecurityParameterIndex inSpi =
+ mISM.allocateSecurityParameterIndex(localOuter, spi);
+ IpSecManager.SecurityParameterIndex outSpi =
+ mISM.allocateSecurityParameterIndex(remoteOuter, spi);
+ IpSecTransform inTransform =
+ transformBuilder.buildTunnelModeTransform(remoteOuter, inSpi);
+ IpSecTransform outTransform =
+ transformBuilder.buildTunnelModeTransform(localOuter, outSpi)) {
+ mISM.applyTunnelModeTransform(
+ tunnelIface, IpSecManager.DIRECTION_IN, inTransform);
+ mISM.applyTunnelModeTransform(
+ tunnelIface, IpSecManager.DIRECTION_OUT, outTransform);
+
+ mTestRunnableFactory
+ .getIpSecTunnelTestRunnable(
+ transportInTunnelMode,
+ spi,
+ localInner,
+ remoteInner,
+ localOuter,
+ remoteOuter,
+ inTransportTransform,
+ outTransportTransform,
+ useEncap ? encapSocket.getPort() : 0,
+ 0,
+ expectedPacketSize)
+ .run(ipsecNetwork, tunnelIface, tunUtils);
+ }
+ }
+ }
+ }
+
private void checkTunnelOutput(
int innerFamily, int outerFamily, boolean useEncap, boolean transportInTunnelMode)
throws Exception {
@@ -426,6 +650,28 @@
new InputPacketGeneratorIpSecTunnelTestRunnableFactory());
}
+ private void checkMigrateTunnelOutput(
+ int innerFamily, int outerFamily, boolean useEncap, boolean transportInTunnelMode)
+ throws Exception {
+ checkTunnel(
+ innerFamily,
+ outerFamily,
+ useEncap,
+ transportInTunnelMode,
+ new MigrateIpSecTunnelTestRunnableFactory(true));
+ }
+
+ private void checkMigrateTunnelInput(
+ int innerFamily, int outerFamily, boolean useEncap, boolean transportInTunnelMode)
+ throws Exception {
+ checkTunnel(
+ innerFamily,
+ outerFamily,
+ useEncap,
+ transportInTunnelMode,
+ new MigrateIpSecTunnelTestRunnableFactory(false));
+ }
+
/**
* Validates that the kernel can talk to itself.
*
@@ -579,7 +825,8 @@
IpSecManager.SecurityParameterIndex outSpi =
mISM.allocateSecurityParameterIndex(remoteOuter, spi);
IpSecManager.IpSecTunnelInterface tunnelIface =
- mISM.createIpSecTunnelInterface(localOuter, remoteOuter, sTunNetwork)) {
+ mISM.createIpSecTunnelInterface(
+ localOuter, remoteOuter, sTunWrapper.network)) {
// Build the test network
tunnelIface.addAddress(localInner, innerPrefixLen);
testNetworkCb = mCtsNetUtils.setupAndGetTestNetwork(tunnelIface.getInterfaceName());
@@ -615,7 +862,7 @@
mISM.applyTunnelModeTransform(
tunnelIface, IpSecManager.DIRECTION_OUT, outTransform);
- innerSocketPort = test.run(testNetwork);
+ innerSocketPort = test.run(testNetwork, tunnelIface, sTunWrapper.utils);
}
// Teardown the test network
@@ -739,6 +986,14 @@
return maybeEncapPacket(srcOuter, dstOuter, encapPort, espPayload).getPacketBytes();
}
+ private void doTestMigrateTunnel(
+ int innerFamily, int outerFamily, boolean useEncap, boolean transportInTunnelMode)
+ throws Exception {
+ assumeTrue(mCtsNetUtils.hasIpsecTunnelsFeature());
+ checkTunnelOutput(innerFamily, outerFamily, useEncap, transportInTunnelMode);
+ checkTunnelInput(innerFamily, outerFamily, useEncap, transportInTunnelMode);
+ }
+
// Transport-in-Tunnel mode tests
@Test
public void testTransportInTunnelModeV4InV4() throws Exception {
@@ -747,6 +1002,12 @@
checkTunnelInput(AF_INET, AF_INET, false, true);
}
+ @IgnoreUpTo(Build.VERSION_CODES.R)
+ @Test
+ public void testMigrateTransportInTunnelModeV4InV4() throws Exception {
+ doTestMigrateTunnel(AF_INET, AF_INET, false, true);
+ }
+
@Test
public void testTransportInTunnelModeV4InV4Reflected() throws Exception {
assumeTrue(mCtsNetUtils.hasIpsecTunnelsFeature());
@@ -760,6 +1021,12 @@
checkTunnelInput(AF_INET, AF_INET, true, true);
}
+ @IgnoreUpTo(Build.VERSION_CODES.R)
+ @Test
+ public void testMigrateTransportInTunnelModeV4InV4UdpEncap() throws Exception {
+ doTestMigrateTunnel(AF_INET, AF_INET, true, true);
+ }
+
@Test
public void testTransportInTunnelModeV4InV4UdpEncapReflected() throws Exception {
assumeTrue(mCtsNetUtils.hasIpsecTunnelsFeature());
@@ -773,6 +1040,12 @@
checkTunnelInput(AF_INET, AF_INET6, false, true);
}
+ @IgnoreUpTo(Build.VERSION_CODES.R)
+ @Test
+ public void testMigrateTransportInTunnelModeV4InV6() throws Exception {
+ doTestMigrateTunnel(AF_INET, AF_INET6, false, true);
+ }
+
@Test
public void testTransportInTunnelModeV4InV6Reflected() throws Exception {
assumeTrue(mCtsNetUtils.hasIpsecTunnelsFeature());
@@ -786,6 +1059,12 @@
checkTunnelInput(AF_INET6, AF_INET, false, true);
}
+ @IgnoreUpTo(Build.VERSION_CODES.R)
+ @Test
+ public void testMigrateTransportInTunnelModeV6InV4() throws Exception {
+ doTestMigrateTunnel(AF_INET6, AF_INET, false, true);
+ }
+
@Test
public void testTransportInTunnelModeV6InV4Reflected() throws Exception {
assumeTrue(mCtsNetUtils.hasIpsecTunnelsFeature());
@@ -799,6 +1078,12 @@
checkTunnelInput(AF_INET6, AF_INET, true, true);
}
+ @IgnoreUpTo(Build.VERSION_CODES.R)
+ @Test
+ public void testMigrateTransportInTunnelModeV6InV4UdpEncap() throws Exception {
+ doTestMigrateTunnel(AF_INET6, AF_INET, true, true);
+ }
+
@Test
public void testTransportInTunnelModeV6InV4UdpEncapReflected() throws Exception {
assumeTrue(mCtsNetUtils.hasIpsecTunnelsFeature());
@@ -812,6 +1097,12 @@
checkTunnelInput(AF_INET, AF_INET6, false, true);
}
+ @IgnoreUpTo(Build.VERSION_CODES.R)
+ @Test
+ public void testMigrateTransportInTunnelModeV6InV6() throws Exception {
+ doTestMigrateTunnel(AF_INET, AF_INET6, false, true);
+ }
+
@Test
public void testTransportInTunnelModeV6InV6Reflected() throws Exception {
assumeTrue(mCtsNetUtils.hasIpsecTunnelsFeature());
@@ -826,6 +1117,12 @@
checkTunnelInput(AF_INET, AF_INET, false, false);
}
+ @IgnoreUpTo(Build.VERSION_CODES.R)
+ @Test
+ public void testMigrateTunnelV4InV4() throws Exception {
+ doTestMigrateTunnel(AF_INET, AF_INET, false, false);
+ }
+
@Test
public void testTunnelV4InV4Reflected() throws Exception {
assumeTrue(mCtsNetUtils.hasIpsecTunnelsFeature());
@@ -839,6 +1136,12 @@
checkTunnelInput(AF_INET, AF_INET, true, false);
}
+ @IgnoreUpTo(Build.VERSION_CODES.R)
+ @Test
+ public void testMigrateTunnelV4InV4UdpEncap() throws Exception {
+ doTestMigrateTunnel(AF_INET, AF_INET, true, false);
+ }
+
@Test
public void testTunnelV4InV4UdpEncapReflected() throws Exception {
assumeTrue(mCtsNetUtils.hasIpsecTunnelsFeature());
@@ -852,6 +1155,12 @@
checkTunnelInput(AF_INET, AF_INET6, false, false);
}
+ @IgnoreUpTo(Build.VERSION_CODES.R)
+ @Test
+ public void testMigrateTunnelV4InV6() throws Exception {
+ doTestMigrateTunnel(AF_INET, AF_INET6, false, false);
+ }
+
@Test
public void testTunnelV4InV6Reflected() throws Exception {
assumeTrue(mCtsNetUtils.hasIpsecTunnelsFeature());
@@ -865,6 +1174,12 @@
checkTunnelInput(AF_INET6, AF_INET, false, false);
}
+ @IgnoreUpTo(Build.VERSION_CODES.R)
+ @Test
+ public void testMigrateTunnelV6InV4() throws Exception {
+ doTestMigrateTunnel(AF_INET6, AF_INET, false, false);
+ }
+
@Test
public void testTunnelV6InV4Reflected() throws Exception {
assumeTrue(mCtsNetUtils.hasIpsecTunnelsFeature());
@@ -878,6 +1193,12 @@
checkTunnelInput(AF_INET6, AF_INET, true, false);
}
+ @IgnoreUpTo(Build.VERSION_CODES.R)
+ @Test
+ public void testMigrateTunnelV6InV4UdpEncap() throws Exception {
+ doTestMigrateTunnel(AF_INET6, AF_INET, true, false);
+ }
+
@Test
public void testTunnelV6InV4UdpEncapReflected() throws Exception {
assumeTrue(mCtsNetUtils.hasIpsecTunnelsFeature());
@@ -891,6 +1212,12 @@
checkTunnelInput(AF_INET6, AF_INET6, false, false);
}
+ @IgnoreUpTo(Build.VERSION_CODES.R)
+ @Test
+ public void testMigrateTunnelV6InV6() throws Exception {
+ doTestMigrateTunnel(AF_INET6, AF_INET6, false, false);
+ }
+
@Test
public void testTunnelV6InV6Reflected() throws Exception {
assumeTrue(mCtsNetUtils.hasIpsecTunnelsFeature());
diff --git a/tests/unit/Android.bp b/tests/unit/Android.bp
index beae0cf..ffff681 100644
--- a/tests/unit/Android.bp
+++ b/tests/unit/Android.bp
@@ -49,22 +49,21 @@
],
}
-android_test {
- name: "FrameworksNetTests",
+android_library {
+ name: "FrameworksNetTestsLib",
+ min_sdk_version: "30",
defaults: [
"framework-connectivity-test-defaults",
- "FrameworksNetTests-jni-defaults",
],
srcs: [
"java/**/*.java",
"java/**/*.kt",
],
- test_suites: ["device-tests"],
- certificate: "platform",
jarjar_rules: "jarjar-rules.txt",
static_libs: [
"androidx.test.rules",
"bouncycastle-repackaged-unbundled",
+ "core-tests-support",
"FrameworksNetCommonTests",
"frameworks-base-testutils",
"frameworks-net-integration-testutils",
@@ -83,7 +82,21 @@
"android.test.mock",
"ServiceConnectivityResources",
],
+ visibility: ["//packages/modules/Connectivity/tests:__subpackages__"],
+}
+
+android_test {
+ name: "FrameworksNetTests",
+ min_sdk_version: "30",
+ defaults: [
+ "framework-connectivity-test-defaults",
+ "FrameworksNetTests-jni-defaults",
+ ],
+ test_suites: ["device-tests"],
+ static_libs: [
+ "FrameworksNetTestsLib",
+ ],
jni_libs: [
"libservice-connectivity",
- ],
+ ]
}
diff --git a/tests/unit/java/android/net/ConnectivityManagerTest.java b/tests/unit/java/android/net/ConnectivityManagerTest.java
index c804e10..b8cd3f6 100644
--- a/tests/unit/java/android/net/ConnectivityManagerTest.java
+++ b/tests/unit/java/android/net/ConnectivityManagerTest.java
@@ -44,6 +44,7 @@
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.nullable;
+import static org.mockito.Mockito.CALLS_REAL_METHODS;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.anyInt;
import static org.mockito.Mockito.mock;
@@ -215,7 +216,8 @@
public void testCallbackRelease() throws Exception {
ConnectivityManager manager = new ConnectivityManager(mCtx, mService);
NetworkRequest request = makeRequest(1);
- NetworkCallback callback = mock(ConnectivityManager.NetworkCallback.class);
+ NetworkCallback callback = mock(ConnectivityManager.NetworkCallback.class,
+ CALLS_REAL_METHODS);
Handler handler = new Handler(Looper.getMainLooper());
ArgumentCaptor<Messenger> captor = ArgumentCaptor.forClass(Messenger.class);
@@ -243,7 +245,8 @@
ConnectivityManager manager = new ConnectivityManager(mCtx, mService);
NetworkRequest req1 = makeRequest(1);
NetworkRequest req2 = makeRequest(2);
- NetworkCallback callback = mock(ConnectivityManager.NetworkCallback.class);
+ NetworkCallback callback = mock(ConnectivityManager.NetworkCallback.class,
+ CALLS_REAL_METHODS);
Handler handler = new Handler(Looper.getMainLooper());
ArgumentCaptor<Messenger> captor = ArgumentCaptor.forClass(Messenger.class);
diff --git a/tests/unit/java/android/net/KeepalivePacketDataUtilTest.java b/tests/unit/java/android/net/KeepalivePacketDataUtilTest.java
index fc739fb..bc6dbf2 100644
--- a/tests/unit/java/android/net/KeepalivePacketDataUtilTest.java
+++ b/tests/unit/java/android/net/KeepalivePacketDataUtilTest.java
@@ -24,7 +24,9 @@
import static org.junit.Assert.fail;
import android.net.util.KeepalivePacketDataUtil;
+import android.util.Log;
+import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -38,8 +40,19 @@
private static final byte[] IPV4_KEEPALIVE_SRC_ADDR = {10, 0, 0, 1};
private static final byte[] IPV4_KEEPALIVE_DST_ADDR = {10, 0, 0, 5};
+ private Log.TerribleFailureHandler mOriginalHandler;
+
@Before
- public void setUp() {}
+ public void setUp() {
+ // Terrible failures are logged when using deprecated methods on newer platforms
+ mOriginalHandler = Log.setWtfHandler((tag, what, sys) ->
+ Log.e(tag, "Terrible failure in test", what));
+ }
+
+ @After
+ public void tearDown() {
+ Log.setWtfHandler(mOriginalHandler);
+ }
@Test
public void testFromTcpKeepaliveStableParcelable() throws Exception {
diff --git a/tests/unit/java/android/net/nsd/NsdManagerTest.java b/tests/unit/java/android/net/nsd/NsdManagerTest.java
index b0a9b8a..370179c 100644
--- a/tests/unit/java/android/net/nsd/NsdManagerTest.java
+++ b/tests/unit/java/android/net/nsd/NsdManagerTest.java
@@ -20,12 +20,12 @@
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.fail;
import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.timeout;
import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
import android.content.Context;
import android.os.Handler;
@@ -66,7 +66,7 @@
MockitoAnnotations.initMocks(this);
mServiceHandler = spy(MockServiceHandler.create(mContext));
- when(mService.getMessenger()).thenReturn(new Messenger(mServiceHandler));
+ doReturn(new Messenger(mServiceHandler)).when(mService).getMessenger();
mManager = makeManager();
}
diff --git a/tests/unit/java/android/net/util/MultinetworkPolicyTrackerTest.kt b/tests/unit/java/android/net/util/MultinetworkPolicyTrackerTest.kt
index 25aa626..78c8fa4 100644
--- a/tests/unit/java/android/net/util/MultinetworkPolicyTrackerTest.kt
+++ b/tests/unit/java/android/net/util/MultinetworkPolicyTrackerTest.kt
@@ -45,6 +45,7 @@
import org.mockito.ArgumentMatchers.argThat
import org.mockito.ArgumentMatchers.eq
import org.mockito.Mockito.any
+import org.mockito.Mockito.doCallRealMethod
import org.mockito.Mockito.doReturn
import org.mockito.Mockito.mock
import org.mockito.Mockito.times
@@ -74,6 +75,10 @@
doReturn(Context.TELEPHONY_SERVICE).`when`(it)
.getSystemServiceName(TelephonyManager::class.java)
doReturn(telephonyManager).`when`(it).getSystemService(Context.TELEPHONY_SERVICE)
+ if (it.getSystemService(TelephonyManager::class.java) == null) {
+ // Test is using mockito extended
+ doCallRealMethod().`when`(it).getSystemService(TelephonyManager::class.java)
+ }
doReturn(subscriptionManager).`when`(it)
.getSystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE)
doReturn(resolver).`when`(it).contentResolver
diff --git a/tests/unit/java/com/android/server/ConnectivityServiceTest.java b/tests/unit/java/com/android/server/ConnectivityServiceTest.java
index be7239d..5f37440 100644
--- a/tests/unit/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/unit/java/com/android/server/ConnectivityServiceTest.java
@@ -18,10 +18,15 @@
import static android.Manifest.permission.CHANGE_NETWORK_STATE;
import static android.Manifest.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS;
+import static android.Manifest.permission.CONTROL_OEM_PAID_NETWORK_PREFERENCE;
+import static android.Manifest.permission.CREATE_USERS;
import static android.Manifest.permission.DUMP;
+import static android.Manifest.permission.GET_INTENT_SENDER_INTENT;
import static android.Manifest.permission.LOCAL_MAC_ADDRESS;
import static android.Manifest.permission.NETWORK_FACTORY;
import static android.Manifest.permission.NETWORK_SETTINGS;
+import static android.Manifest.permission.NETWORK_STACK;
+import static android.Manifest.permission.PACKET_KEEPALIVE_OFFLOAD;
import static android.app.PendingIntent.FLAG_IMMUTABLE;
import static android.content.Intent.ACTION_PACKAGE_ADDED;
import static android.content.Intent.ACTION_PACKAGE_REMOVED;
@@ -134,6 +139,7 @@
import static com.android.testutils.MiscAsserts.assertRunsInAtMost;
import static com.android.testutils.MiscAsserts.assertSameElements;
import static com.android.testutils.MiscAsserts.assertThrows;
+import static com.android.testutils.TestPermissionUtil.runAsShell;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
@@ -259,6 +265,7 @@
import android.net.shared.PrivateDnsConfig;
import android.net.util.MultinetworkPolicyTracker;
import android.os.BadParcelableException;
+import android.os.BatteryStatsManager;
import android.os.Binder;
import android.os.Build;
import android.os.Bundle;
@@ -297,6 +304,7 @@
import androidx.test.runner.AndroidJUnit4;
import com.android.connectivity.resources.R;
+import com.android.internal.app.IBatteryStats;
import com.android.internal.net.VpnConfig;
import com.android.internal.net.VpnProfile;
import com.android.internal.util.ArrayUtils;
@@ -305,6 +313,7 @@
import com.android.internal.util.test.FakeSettingsProvider;
import com.android.net.module.util.ArrayTrackRecord;
import com.android.net.module.util.CollectionUtils;
+import com.android.net.module.util.LocationPermissionChecker;
import com.android.server.ConnectivityService.ConnectivityDiagnosticsCallbackInfo;
import com.android.server.ConnectivityService.NetworkRequestInfo;
import com.android.server.connectivity.MockableSystemProperties;
@@ -384,7 +393,7 @@
public class ConnectivityServiceTest {
private static final String TAG = "ConnectivityServiceTest";
- private static final int TIMEOUT_MS = 500;
+ private static final int TIMEOUT_MS = 2_000;
// Broadcasts can take a long time to be delivered. The test will not wait for that long unless
// there is a failure, so use a long timeout.
private static final int BROADCAST_TIMEOUT_MS = 30_000;
@@ -488,6 +497,11 @@
@Mock Resources mResources;
@Mock ProxyTracker mProxyTracker;
+ // BatteryStatsManager is final and cannot be mocked with regular mockito, so just mock the
+ // underlying binder calls.
+ final BatteryStatsManager mBatteryStatsManager =
+ new BatteryStatsManager(mock(IBatteryStats.class));
+
private ArgumentCaptor<ResolverParamsParcel> mResolverParamsParcelCaptor =
ArgumentCaptor.forClass(ResolverParamsParcel.class);
@@ -579,6 +593,7 @@
if (Context.NETWORK_POLICY_SERVICE.equals(name)) return mNetworkPolicyManager;
if (Context.SYSTEM_CONFIG_SERVICE.equals(name)) return mSystemConfigManager;
if (Context.NETWORK_STATS_SERVICE.equals(name)) return mStatsManager;
+ if (Context.BATTERY_STATS_SERVICE.equals(name)) return mBatteryStatsManager;
return super.getSystemService(name);
}
@@ -659,6 +674,15 @@
public void setPermission(String permission, Integer granted) {
mMockedPermissions.put(permission, granted);
}
+
+ @Override
+ public Intent registerReceiverForAllUsers(@Nullable BroadcastReceiver receiver,
+ @NonNull IntentFilter filter, @Nullable String broadcastPermission,
+ @Nullable Handler scheduler) {
+ // TODO: ensure MultinetworkPolicyTracker's BroadcastReceiver is tested; just returning
+ // null should not pass the test
+ return null;
+ }
}
private void waitForIdle() {
@@ -1208,7 +1232,24 @@
return mDeviceIdleInternal;
}
},
- mNetworkManagementService, mMockNetd, userId, mVpnProfileStore);
+ mNetworkManagementService, mMockNetd, userId, mVpnProfileStore,
+ new SystemServices(mServiceContext) {
+ @Override
+ public String settingsSecureGetStringForUser(String key, int userId) {
+ switch (key) {
+ // Settings keys not marked as @Readable are not readable from
+ // non-privileged apps, unless marked as testOnly=true
+ // (atest refuses to install testOnly=true apps), even if mocked
+ // in the content provider, because
+ // Settings.Secure.NameValueCache#getStringForUser checks the key
+ // before querying the mock settings provider.
+ case Settings.Secure.ALWAYS_ON_VPN_APP:
+ return null;
+ default:
+ return super.settingsSecureGetStringForUser(key, userId);
+ }
+ }
+ }, new Ikev2SessionCreator());
}
public void setUids(Set<UidRange> uids) {
@@ -1455,8 +1496,7 @@
return mService.getNetworkAgentInfoForNetwork(mna.getNetwork()).clatd;
}
- private static class WrappedMultinetworkPolicyTracker extends MultinetworkPolicyTracker {
- volatile boolean mConfigRestrictsAvoidBadWifi;
+ private class WrappedMultinetworkPolicyTracker extends MultinetworkPolicyTracker {
volatile int mConfigMeteredMultipathPreference;
WrappedMultinetworkPolicyTracker(Context c, Handler h, Runnable r) {
@@ -1464,8 +1504,8 @@
}
@Override
- public boolean configRestrictsAvoidBadWifi() {
- return mConfigRestrictsAvoidBadWifi;
+ protected Resources getResourcesForActiveSubId() {
+ return mResources;
}
@Override
@@ -1592,6 +1632,11 @@
mServiceContext = new MockContext(InstrumentationRegistry.getContext(),
new FakeSettingsProvider());
mServiceContext.setUseRegisteredHandlers(true);
+ mServiceContext.setPermission(NETWORK_FACTORY, PERMISSION_GRANTED);
+ mServiceContext.setPermission(NETWORK_STACK, PERMISSION_GRANTED);
+ mServiceContext.setPermission(CONTROL_OEM_PAID_NETWORK_PREFERENCE, PERMISSION_GRANTED);
+ mServiceContext.setPermission(PACKET_KEEPALIVE_OFFLOAD, PERMISSION_GRANTED);
+ mServiceContext.setPermission(CONNECTIVITY_USE_RESTRICTED_NETWORKS, PERMISSION_GRANTED);
mAlarmManagerThread = new HandlerThread("TestAlarmManager");
mAlarmManagerThread.start();
@@ -1651,6 +1696,13 @@
return mPolicyTracker;
}).when(deps).makeMultinetworkPolicyTracker(any(), any(), any());
doReturn(true).when(deps).getCellular464XlatEnabled();
+ doAnswer(inv ->
+ new LocationPermissionChecker(inv.getArgument(0)) {
+ @Override
+ protected int getCurrentUser() {
+ return runAsShell(CREATE_USERS, () -> super.getCurrentUser());
+ }
+ }).when(deps).makeLocationPermissionChecker(any());
doReturn(60000).when(mResources).getInteger(R.integer.config_networkTransitionTimeout);
doReturn("").when(mResources).getString(R.string.config_networkCaptivePortalServerUrl);
@@ -1670,7 +1722,9 @@
.getIdentifier(eq("config_networkSupportedKeepaliveCount"), eq("array"), any());
doReturn(R.array.network_switch_type_name).when(mResources)
.getIdentifier(eq("network_switch_type_name"), eq("array"), any());
-
+ doReturn(R.integer.config_networkAvoidBadWifi).when(mResources)
+ .getIdentifier(eq("config_networkAvoidBadWifi"), eq("integer"), any());
+ doReturn(1).when(mResources).getInteger(R.integer.config_networkAvoidBadWifi);
final ConnectivityResources connRes = mock(ConnectivityResources.class);
doReturn(mResources).when(connRes).get();
@@ -1680,6 +1734,12 @@
doReturn(mResources).when(mockResContext).getResources();
ConnectivityResources.setResourcesContextForTest(mockResContext);
+ doAnswer(inv -> {
+ final PendingIntent a = inv.getArgument(0);
+ final PendingIntent b = inv.getArgument(1);
+ return runAsShell(GET_INTENT_SENDER_INTENT, () -> a.intentFilterEquals(b));
+ }).when(deps).intentFilterEquals(any(), any());
+
return deps;
}
@@ -4704,30 +4764,29 @@
}
@Test
- public void testAvoidBadWifiSetting() throws Exception {
+ public void testSetAllowBadWifiUntil() throws Exception {
+ runAsShell(NETWORK_SETTINGS,
+ () -> mService.setTestAllowBadWifiUntil(System.currentTimeMillis() + 5_000L));
+ waitForIdle();
+ testAvoidBadWifiConfig_controlledBySettings();
+
+ runAsShell(NETWORK_SETTINGS,
+ () -> mService.setTestAllowBadWifiUntil(System.currentTimeMillis() - 5_000L));
+ waitForIdle();
+ testAvoidBadWifiConfig_ignoreSettings();
+ }
+
+ private void testAvoidBadWifiConfig_controlledBySettings() {
final ContentResolver cr = mServiceContext.getContentResolver();
final String settingName = ConnectivitySettingsManager.NETWORK_AVOID_BAD_WIFI;
- mPolicyTracker.mConfigRestrictsAvoidBadWifi = false;
- String[] values = new String[] {null, "0", "1"};
- for (int i = 0; i < values.length; i++) {
- Settings.Global.putInt(cr, settingName, 1);
- mPolicyTracker.reevaluate();
- waitForIdle();
- String msg = String.format("config=false, setting=%s", values[i]);
- assertTrue(mService.avoidBadWifi());
- assertFalse(msg, mPolicyTracker.shouldNotifyWifiUnvalidated());
- }
-
- mPolicyTracker.mConfigRestrictsAvoidBadWifi = true;
-
- Settings.Global.putInt(cr, settingName, 0);
+ Settings.Global.putString(cr, settingName, "0");
mPolicyTracker.reevaluate();
waitForIdle();
assertFalse(mService.avoidBadWifi());
assertFalse(mPolicyTracker.shouldNotifyWifiUnvalidated());
- Settings.Global.putInt(cr, settingName, 1);
+ Settings.Global.putString(cr, settingName, "1");
mPolicyTracker.reevaluate();
waitForIdle();
assertTrue(mService.avoidBadWifi());
@@ -4740,13 +4799,40 @@
assertTrue(mPolicyTracker.shouldNotifyWifiUnvalidated());
}
+ private void testAvoidBadWifiConfig_ignoreSettings() {
+ final ContentResolver cr = mServiceContext.getContentResolver();
+ final String settingName = ConnectivitySettingsManager.NETWORK_AVOID_BAD_WIFI;
+
+ String[] values = new String[] {null, "0", "1"};
+ for (int i = 0; i < values.length; i++) {
+ Settings.Global.putString(cr, settingName, values[i]);
+ mPolicyTracker.reevaluate();
+ waitForIdle();
+ String msg = String.format("config=false, setting=%s", values[i]);
+ assertTrue(mService.avoidBadWifi());
+ assertFalse(msg, mPolicyTracker.shouldNotifyWifiUnvalidated());
+ }
+ }
+
+ @Test
+ public void testAvoidBadWifiSetting() throws Exception {
+ final ContentResolver cr = mServiceContext.getContentResolver();
+ final String settingName = ConnectivitySettingsManager.NETWORK_AVOID_BAD_WIFI;
+
+ doReturn(1).when(mResources).getInteger(R.integer.config_networkAvoidBadWifi);
+ testAvoidBadWifiConfig_ignoreSettings();
+
+ doReturn(0).when(mResources).getInteger(R.integer.config_networkAvoidBadWifi);
+ testAvoidBadWifiConfig_controlledBySettings();
+ }
+
@Ignore("Refactoring in progress b/178071397")
@Test
public void testAvoidBadWifi() throws Exception {
final ContentResolver cr = mServiceContext.getContentResolver();
// Pretend we're on a carrier that restricts switching away from bad wifi.
- mPolicyTracker.mConfigRestrictsAvoidBadWifi = true;
+ doReturn(0).when(mResources).getInteger(R.integer.config_networkAvoidBadWifi);
// File a request for cell to ensure it doesn't go down.
final TestNetworkCallback cellNetworkCallback = new TestNetworkCallback();
@@ -4797,13 +4883,13 @@
// Simulate switching to a carrier that does not restrict avoiding bad wifi, and expect
// that we switch back to cell.
- mPolicyTracker.mConfigRestrictsAvoidBadWifi = false;
+ doReturn(1).when(mResources).getInteger(R.integer.config_networkAvoidBadWifi);
mPolicyTracker.reevaluate();
defaultCallback.expectAvailableCallbacksValidated(mCellNetworkAgent);
assertEquals(mCm.getActiveNetwork(), cellNetwork);
// Switch back to a restrictive carrier.
- mPolicyTracker.mConfigRestrictsAvoidBadWifi = true;
+ doReturn(0).when(mResources).getInteger(R.integer.config_networkAvoidBadWifi);
mPolicyTracker.reevaluate();
defaultCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
assertEquals(mCm.getActiveNetwork(), wifiNetwork);
@@ -9357,8 +9443,7 @@
mServiceContext.setPermission(NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK,
PERMISSION_DENIED);
mServiceContext.setPermission(NETWORK_SETTINGS, PERMISSION_DENIED);
- mServiceContext.setPermission(Manifest.permission.NETWORK_STACK,
- PERMISSION_DENIED);
+ mServiceContext.setPermission(NETWORK_STACK, PERMISSION_DENIED);
mServiceContext.setPermission(Manifest.permission.NETWORK_SETUP_WIZARD,
PERMISSION_DENIED);
}
@@ -9799,7 +9884,7 @@
setupConnectionOwnerUid(vpnOwnerUid, vpnType);
// Test as VPN app
- mServiceContext.setPermission(android.Manifest.permission.NETWORK_STACK, PERMISSION_DENIED);
+ mServiceContext.setPermission(NETWORK_STACK, PERMISSION_DENIED);
mServiceContext.setPermission(
NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, PERMISSION_DENIED);
}
@@ -9839,8 +9924,7 @@
public void testGetConnectionOwnerUidVpnServiceNetworkStackDoesNotThrow() throws Exception {
final int myUid = Process.myUid();
setupConnectionOwnerUid(myUid, VpnManager.TYPE_VPN_SERVICE);
- mServiceContext.setPermission(
- android.Manifest.permission.NETWORK_STACK, PERMISSION_GRANTED);
+ mServiceContext.setPermission(NETWORK_STACK, PERMISSION_GRANTED);
assertEquals(42, mService.getConnectionOwnerUid(getTestConnectionInfo()));
}
@@ -10008,8 +10092,7 @@
public void testCheckConnectivityDiagnosticsPermissionsNetworkStack() throws Exception {
final NetworkAgentInfo naiWithoutUid = fakeMobileNai(new NetworkCapabilities());
- mServiceContext.setPermission(
- android.Manifest.permission.NETWORK_STACK, PERMISSION_GRANTED);
+ mServiceContext.setPermission(NETWORK_STACK, PERMISSION_GRANTED);
assertTrue(
"NetworkStack permission not applied",
mService.checkConnectivityDiagnosticsPermissions(
@@ -10025,7 +10108,7 @@
nc.setAdministratorUids(new int[] {wrongUid});
final NetworkAgentInfo naiWithUid = fakeWifiNai(nc);
- mServiceContext.setPermission(android.Manifest.permission.NETWORK_STACK, PERMISSION_DENIED);
+ mServiceContext.setPermission(NETWORK_STACK, PERMISSION_DENIED);
assertFalse(
"Mismatched uid/package name should not pass the location permission check",
@@ -10035,7 +10118,7 @@
private void verifyConnectivityDiagnosticsPermissionsWithNetworkAgentInfo(
NetworkAgentInfo info, boolean expectPermission) {
- mServiceContext.setPermission(android.Manifest.permission.NETWORK_STACK, PERMISSION_DENIED);
+ mServiceContext.setPermission(NETWORK_STACK, PERMISSION_DENIED);
assertEquals(
"Unexpected ConnDiags permission",
@@ -10103,7 +10186,7 @@
setupLocationPermissions(Build.VERSION_CODES.Q, true, AppOpsManager.OPSTR_FINE_LOCATION,
Manifest.permission.ACCESS_FINE_LOCATION);
- mServiceContext.setPermission(android.Manifest.permission.NETWORK_STACK, PERMISSION_DENIED);
+ mServiceContext.setPermission(NETWORK_STACK, PERMISSION_DENIED);
assertTrue(
"NetworkCapabilities administrator uid permission not applied",
@@ -10120,7 +10203,7 @@
setupLocationPermissions(Build.VERSION_CODES.Q, true, AppOpsManager.OPSTR_FINE_LOCATION,
Manifest.permission.ACCESS_FINE_LOCATION);
- mServiceContext.setPermission(android.Manifest.permission.NETWORK_STACK, PERMISSION_DENIED);
+ mServiceContext.setPermission(NETWORK_STACK, PERMISSION_DENIED);
// Use wrong pid and uid
assertFalse(
@@ -10146,8 +10229,7 @@
final NetworkRequest request = new NetworkRequest.Builder().build();
when(mConnectivityDiagnosticsCallback.asBinder()).thenReturn(mIBinder);
- mServiceContext.setPermission(
- android.Manifest.permission.NETWORK_STACK, PERMISSION_GRANTED);
+ mServiceContext.setPermission(NETWORK_STACK, PERMISSION_GRANTED);
mService.registerConnectivityDiagnosticsCallback(
mConnectivityDiagnosticsCallback, request, mContext.getPackageName());
@@ -10166,8 +10248,7 @@
final NetworkRequest request = new NetworkRequest.Builder().build();
when(mConnectivityDiagnosticsCallback.asBinder()).thenReturn(mIBinder);
- mServiceContext.setPermission(
- android.Manifest.permission.NETWORK_STACK, PERMISSION_GRANTED);
+ mServiceContext.setPermission(NETWORK_STACK, PERMISSION_GRANTED);
mService.registerConnectivityDiagnosticsCallback(
mConnectivityDiagnosticsCallback, request, mContext.getPackageName());
diff --git a/tests/unit/java/com/android/server/connectivity/MultipathPolicyTrackerTest.java b/tests/unit/java/com/android/server/connectivity/MultipathPolicyTrackerTest.java
index 38f6d7f..4c80f6a 100644
--- a/tests/unit/java/com/android/server/connectivity/MultipathPolicyTrackerTest.java
+++ b/tests/unit/java/com/android/server/connectivity/MultipathPolicyTrackerTest.java
@@ -34,6 +34,7 @@
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doCallRealMethod;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
@@ -114,8 +115,12 @@
private boolean mRecurrenceRuleClockMocked;
private <T> void mockService(String serviceName, Class<T> serviceClass, T service) {
- when(mContext.getSystemServiceName(serviceClass)).thenReturn(serviceName);
- when(mContext.getSystemService(serviceName)).thenReturn(service);
+ doReturn(serviceName).when(mContext).getSystemServiceName(serviceClass);
+ doReturn(service).when(mContext).getSystemService(serviceName);
+ if (mContext.getSystemService(serviceClass) == null) {
+ // Test is using mockito-extended
+ doCallRealMethod().when(mContext).getSystemService(serviceClass);
+ }
}
@Before
diff --git a/tests/unit/java/com/android/server/connectivity/PermissionMonitorTest.java b/tests/unit/java/com/android/server/connectivity/PermissionMonitorTest.java
index e98f5db..8b45755 100644
--- a/tests/unit/java/com/android/server/connectivity/PermissionMonitorTest.java
+++ b/tests/unit/java/com/android/server/connectivity/PermissionMonitorTest.java
@@ -51,6 +51,7 @@
import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.doCallRealMethod;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.reset;
@@ -139,6 +140,10 @@
.thenReturn(Context.SYSTEM_CONFIG_SERVICE);
when(mContext.getSystemService(Context.SYSTEM_CONFIG_SERVICE))
.thenReturn(mSystemConfigManager);
+ if (mContext.getSystemService(SystemConfigManager.class) == null) {
+ // Test is using mockito-extended
+ doCallRealMethod().when(mContext).getSystemService(SystemConfigManager.class);
+ }
when(mSystemConfigManager.getSystemPermissionUids(anyString())).thenReturn(new int[0]);
final Context asUserCtx = mock(Context.class, AdditionalAnswers.delegatesTo(mContext));
doReturn(UserHandle.ALL).when(asUserCtx).getUser();
diff --git a/tests/unit/java/com/android/server/connectivity/VpnTest.java b/tests/unit/java/com/android/server/connectivity/VpnTest.java
index b725b82..6ff47ae 100644
--- a/tests/unit/java/com/android/server/connectivity/VpnTest.java
+++ b/tests/unit/java/com/android/server/connectivity/VpnTest.java
@@ -39,6 +39,7 @@
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.doCallRealMethod;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.inOrder;
@@ -219,19 +220,11 @@
when(mContext.getPackageName()).thenReturn(TEST_VPN_PKG);
when(mContext.getOpPackageName()).thenReturn(TEST_VPN_PKG);
- when(mContext.getSystemServiceName(UserManager.class))
- .thenReturn(Context.USER_SERVICE);
- when(mContext.getSystemService(eq(Context.USER_SERVICE))).thenReturn(mUserManager);
- when(mContext.getSystemService(eq(Context.APP_OPS_SERVICE))).thenReturn(mAppOps);
- when(mContext.getSystemServiceName(NotificationManager.class))
- .thenReturn(Context.NOTIFICATION_SERVICE);
- when(mContext.getSystemService(eq(Context.NOTIFICATION_SERVICE)))
- .thenReturn(mNotificationManager);
- when(mContext.getSystemService(eq(Context.CONNECTIVITY_SERVICE)))
- .thenReturn(mConnectivityManager);
- when(mContext.getSystemServiceName(eq(ConnectivityManager.class)))
- .thenReturn(Context.CONNECTIVITY_SERVICE);
- when(mContext.getSystemService(eq(Context.IPSEC_SERVICE))).thenReturn(mIpSecManager);
+ mockService(UserManager.class, Context.USER_SERVICE, mUserManager);
+ mockService(AppOpsManager.class, Context.APP_OPS_SERVICE, mAppOps);
+ mockService(NotificationManager.class, Context.NOTIFICATION_SERVICE, mNotificationManager);
+ mockService(ConnectivityManager.class, Context.CONNECTIVITY_SERVICE, mConnectivityManager);
+ mockService(IpSecManager.class, Context.IPSEC_SERVICE, mIpSecManager);
when(mContext.getString(R.string.config_customVpnAlwaysOnDisconnectedDialogComponent))
.thenReturn(Resources.getSystem().getString(
R.string.config_customVpnAlwaysOnDisconnectedDialogComponent));
@@ -259,6 +252,16 @@
.thenReturn(tunnelResp);
}
+ private <T> void mockService(Class<T> clazz, String name, T service) {
+ doReturn(service).when(mContext).getSystemService(name);
+ doReturn(name).when(mContext).getSystemServiceName(clazz);
+ if (mContext.getSystemService(clazz).getClass().equals(Object.class)) {
+ // Test is using mockito-extended (mContext uses Answers.RETURNS_DEEP_STUBS and returned
+ // a mock object on a final method)
+ doCallRealMethod().when(mContext).getSystemService(clazz);
+ }
+ }
+
private Set<Range<Integer>> rangeSet(Range<Integer> ... ranges) {
final Set<Range<Integer>> range = new ArraySet<>();
for (Range<Integer> r : ranges) range.add(r);
diff --git a/tests/unit/java/com/android/server/net/NetworkStatsFactoryTest.java b/tests/unit/java/com/android/server/net/NetworkStatsFactoryTest.java
index f3ae9b0..40d4446 100644
--- a/tests/unit/java/com/android/server/net/NetworkStatsFactoryTest.java
+++ b/tests/unit/java/com/android/server/net/NetworkStatsFactoryTest.java
@@ -46,6 +46,7 @@
import libcore.io.IoUtils;
import libcore.io.Streams;
+import libcore.testing.io.TestIoUtils;
import org.junit.After;
import org.junit.Before;
@@ -69,10 +70,7 @@
@Before
public void setUp() throws Exception {
- mTestProc = new File(InstrumentationRegistry.getContext().getFilesDir(), "proc");
- if (mTestProc.exists()) {
- IoUtils.deleteContents(mTestProc);
- }
+ mTestProc = TestIoUtils.createTemporaryDirectory("proc");
// The libandroid_servers which have the native method is not available to
// applications. So in order to have a test support native library, the native code
@@ -85,10 +83,6 @@
@After
public void tearDown() throws Exception {
mFactory = null;
-
- if (mTestProc.exists()) {
- IoUtils.deleteContents(mTestProc);
- }
}
@Test
diff --git a/tests/unit/java/com/android/server/net/NetworkStatsServiceTest.java b/tests/unit/java/com/android/server/net/NetworkStatsServiceTest.java
index c32c1d2..ee94ae9 100644
--- a/tests/unit/java/com/android/server/net/NetworkStatsServiceTest.java
+++ b/tests/unit/java/com/android/server/net/NetworkStatsServiceTest.java
@@ -16,12 +16,17 @@
package com.android.server.net;
+import static android.Manifest.permission.READ_NETWORK_USAGE_HISTORY;
+import static android.Manifest.permission.UPDATE_DEVICE_STATS;
import static android.content.Intent.ACTION_UID_REMOVED;
import static android.content.Intent.EXTRA_UID;
+import static android.content.pm.PackageManager.PERMISSION_DENIED;
+import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.net.ConnectivityManager.TYPE_MOBILE;
import static android.net.ConnectivityManager.TYPE_WIFI;
import static android.net.NetworkIdentity.OEM_PAID;
import static android.net.NetworkIdentity.OEM_PRIVATE;
+import static android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK;
import static android.net.NetworkStats.DEFAULT_NETWORK_ALL;
import static android.net.NetworkStats.DEFAULT_NETWORK_NO;
import static android.net.NetworkStats.DEFAULT_NETWORK_YES;
@@ -106,6 +111,7 @@
import android.provider.Settings;
import android.telephony.TelephonyManager;
+import androidx.annotation.Nullable;
import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
@@ -117,7 +123,7 @@
import com.android.testutils.HandlerUtils;
import com.android.testutils.TestableNetworkStatsProviderBinder;
-import libcore.io.IoUtils;
+import libcore.testing.io.TestIoUtils;
import org.junit.After;
import org.junit.Before;
@@ -200,6 +206,26 @@
if (Context.TELEPHONY_SERVICE.equals(name)) return mTelephonyManager;
return mBaseContext.getSystemService(name);
}
+
+ @Override
+ public void enforceCallingOrSelfPermission(String permission, @Nullable String message) {
+ if (checkCallingOrSelfPermission(permission) != PERMISSION_GRANTED) {
+ throw new SecurityException("Test does not have mocked permission " + permission);
+ }
+ }
+
+ @Override
+ public int checkCallingOrSelfPermission(String permission) {
+ switch (permission) {
+ case PERMISSION_MAINLINE_NETWORK_STACK:
+ case READ_NETWORK_USAGE_HISTORY:
+ case UPDATE_DEVICE_STATS:
+ return PERMISSION_GRANTED;
+ default:
+ return PERMISSION_DENIED;
+ }
+
+ }
}
private final Clock mClock = new SimpleClock(ZoneOffset.UTC) {
@@ -213,10 +239,7 @@
MockitoAnnotations.initMocks(this);
final Context context = InstrumentationRegistry.getContext();
mServiceContext = new MockContext(context);
- mStatsDir = context.getFilesDir();
- if (mStatsDir.exists()) {
- IoUtils.deleteContents(mStatsDir);
- }
+ mStatsDir = TestIoUtils.createTemporaryDirectory(getClass().getSimpleName());
PowerManager powerManager = (PowerManager) mServiceContext.getSystemService(
Context.POWER_SERVICE);
@@ -285,8 +308,6 @@
@After
public void tearDown() throws Exception {
- IoUtils.deleteContents(mStatsDir);
-
mServiceContext = null;
mStatsDir = null;