Merge "Cleanup the public API getActiveNetworkForUid on AOSP"
diff --git a/core/java/Android.bp b/core/java/Android.bp
index 874704e..7ad5e05 100644
--- a/core/java/Android.bp
+++ b/core/java/Android.bp
@@ -277,6 +277,10 @@
backend: {
rust: {
enabled: true,
+ apex_available: [
+ "//apex_available:platform",
+ "com.android.virt", // for virtualizationservice
+ ],
},
},
}
diff --git a/core/java/com/android/internal/os/Zygote.java b/core/java/com/android/internal/os/Zygote.java
index fb9942a..7ceb304 100644
--- a/core/java/com/android/internal/os/Zygote.java
+++ b/core/java/com/android/internal/os/Zygote.java
@@ -742,7 +742,7 @@
new DataOutputStream(sessionSocket.getOutputStream());
Credentials peerCredentials = sessionSocket.getPeerCredentials();
tmpArgBuffer = new ZygoteCommandBuffer(sessionSocket);
- args = ZygoteArguments.getInstance(argBuffer);
+ args = ZygoteArguments.getInstance(tmpArgBuffer);
applyUidSecurityPolicy(args, peerCredentials);
// TODO (chriswailes): Should this only be run for debug builds?
validateUsapCommand(args);
diff --git a/core/jni/android_os_Debug.cpp b/core/jni/android_os_Debug.cpp
index f379ba0..5814a18 100644
--- a/core/jni/android_os_Debug.cpp
+++ b/core/jni/android_os_Debug.cpp
@@ -877,7 +877,7 @@
continue;
}
- sizeKb += importer_info->second.size;
+ sizeKb += importer_info->second.size / 1024;
}
return sizeKb;
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index 2b7a579..10600e3 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -480,6 +480,10 @@
<uses-permission android:name="android.permission.MANAGE_HOTWORD_DETECTION" />
<uses-permission android:name="android.permission.BIND_HOTWORD_DETECTION_SERVICE" />
+ <!-- Permission required to run the `vm` tool which manages on-device virtual machines -->
+ <uses-permission android:name="android.permission.MANAGE_VIRTUAL_MACHINE" />
+ <uses-permission android:name="android.permission.DEBUG_VIRTUAL_MACHINE" />
+
<application android:label="@string/app_label"
android:theme="@android:style/Theme.DeviceDefault.DayNight"
android:defaultToDeviceProtectedStorage="true"
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
index b500e16..8d2363b 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -2293,23 +2293,30 @@
}
final int callingUid = Binder.getCallingUid();
- final int userId = UserHandle.getUserId(newPackage.getUid());
- int numRequestedPermissions = newPackage.getRequestedPermissions().size();
- for (int i = 0; i < numRequestedPermissions; i++) {
- PermissionInfo permInfo = getPermissionInfo(newPackage.getRequestedPermissions().get(i),
- newPackage.getPackageName(), 0);
- if (permInfo == null || !STORAGE_PERMISSIONS.contains(permInfo.name)) {
- continue;
+ for (int userId: mUserManagerInt.getUserIds()) {
+ int numRequestedPermissions = newPackage.getRequestedPermissions().size();
+ for (int i = 0; i < numRequestedPermissions; i++) {
+ PermissionInfo permInfo = getPermissionInfo(
+ newPackage.getRequestedPermissions().get(i),
+ newPackage.getPackageName(), 0);
+ if (permInfo == null || !STORAGE_PERMISSIONS.contains(permInfo.name)) {
+ continue;
+ }
+
+ EventLog.writeEvent(0x534e4554, "171430330", newPackage.getUid(),
+ "Revoking permission " + permInfo.name + " from package "
+ + newPackage.getPackageName() + " as either the sdk downgraded "
+ + downgradedSdk + " or newly requested legacy full storage "
+ + newlyRequestsLegacy);
+
+ try {
+ revokeRuntimePermissionInternal(permInfo.name, newPackage.getPackageName(),
+ false, callingUid, userId, null, permissionCallback);
+ } catch (IllegalStateException | SecurityException e) {
+ Log.e(TAG, "unable to revoke " + permInfo.name + " for "
+ + newPackage.getPackageName() + " user " + userId, e);
+ }
}
-
- EventLog.writeEvent(0x534e4554, "171430330", newPackage.getUid(),
- "Revoking permission " + permInfo.name + " from package "
- + newPackage.getPackageName() + " as either the sdk downgraded "
- + downgradedSdk + " or newly requested legacy full storage "
- + newlyRequestsLegacy);
-
- revokeRuntimePermissionInternal(permInfo.name, newPackage.getPackageName(),
- false, callingUid, userId, null, permissionCallback);
}
}
diff --git a/services/core/java/com/android/server/recoverysystem/RecoverySystemService.java b/services/core/java/com/android/server/recoverysystem/RecoverySystemService.java
index ed4a7bf..1b4e36b 100644
--- a/services/core/java/com/android/server/recoverysystem/RecoverySystemService.java
+++ b/services/core/java/com/android/server/recoverysystem/RecoverySystemService.java
@@ -968,6 +968,12 @@
}
try {
CompressedApexInfoList apexInfoList = getCompressedApexInfoList(packageFile);
+ if (apexInfoList == null) {
+ Log.i(TAG, "apex_info.pb not present in OTA package. "
+ + "Assuming device doesn't support compressed"
+ + "APEX, continueing without allocating space.");
+ return true;
+ }
ApexManager apexManager = ApexManager.getInstance();
apexManager.reserveSpaceForCompressedApex(apexInfoList);
return true;
diff --git a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
index 81878e7..8ec1bf8 100644
--- a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
+++ b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
@@ -554,8 +554,10 @@
PackageInstaller.SessionInfo session = mContext.getPackageManager()
.getPackageInstaller().getSessionInfo(rollback.getStagedSessionId());
if (session == null || session.isStagedSessionFailed()) {
- iter.remove();
- rollback.delete(mAppDataRollbackHelper);
+ if (rollback.isEnabling()) {
+ iter.remove();
+ rollback.delete(mAppDataRollbackHelper);
+ }
continue;
}
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index eaf7693..ddad1db 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -3372,7 +3372,7 @@
}
/**
- * Find all visible task stacks containing {@param userId} and intercept them with an activity
+ * Find all task stacks containing {@param userId} and intercept them with an activity
* to block out the contents and possibly start a credential-confirming intent.
*
* @param userId user handle for the locked managed profile.
@@ -3380,42 +3380,18 @@
void lockAllProfileTasks(@UserIdInt int userId) {
mService.deferWindowLayout();
try {
- final PooledConsumer c = PooledLambda.obtainConsumer(
- RootWindowContainer::taskTopActivityIsUser, this, PooledLambda.__(Task.class),
- userId);
- forAllLeafTasks(c, true /* traverseTopToBottom */);
- c.recycle();
+ forAllLeafTasks(task -> {
+ if (task.getActivity(activity -> !activity.finishing && activity.mUserId == userId)
+ != null) {
+ mService.getTaskChangeNotificationController().notifyTaskProfileLocked(
+ task.mTaskId, userId);
+ }
+ }, true /* traverseTopToBottom */);
} finally {
mService.continueWindowLayout();
}
}
- /**
- * Detects whether we should show a lock screen in front of this task for a locked user.
- * <p>
- * We'll do this if either of the following holds:
- * <ul>
- * <li>The top activity explicitly belongs to {@param userId}.</li>
- * <li>The top activity returns a result to an activity belonging to {@param userId}.</li>
- * </ul>
- *
- * @return {@code true} if the top activity looks like it belongs to {@param userId}.
- */
- private void taskTopActivityIsUser(Task task, @UserIdInt int userId) {
- // To handle the case that work app is in the task but just is not the top one.
- final ActivityRecord activityRecord = task.getTopNonFinishingActivity();
- final ActivityRecord resultTo = (activityRecord != null ? activityRecord.resultTo : null);
-
- // Check the task for a top activity belonging to userId, or returning a
- // result to an activity belonging to userId. Example case: a document
- // picker for personal files, opened by a work app, should still get locked.
- if ((activityRecord != null && activityRecord.mUserId == userId)
- || (resultTo != null && resultTo.mUserId == userId)) {
- mService.getTaskChangeNotificationController().notifyTaskProfileLocked(
- task.mTaskId, userId);
- }
- }
-
void cancelInitializingActivities() {
for (int displayNdx = getChildCount() - 1; displayNdx >= 0; --displayNdx) {
final DisplayContent display = getChildAt(displayNdx);
diff --git a/services/net/Android.bp b/services/net/Android.bp
index fb3db8b..5a5f504 100644
--- a/services/net/Android.bp
+++ b/services/net/Android.bp
@@ -23,7 +23,6 @@
],
static_libs: [
"netd-client",
- "netlink-client",
"networkstack-client",
"net-utils-services-common",
],
@@ -37,6 +36,7 @@
name: "services.net-module-wifi",
srcs: [
":framework-services-net-module-wifi-shared-srcs",
+ ":net-module-utils-srcs",
":net-utils-services-common-srcs",
],
sdk_version: "module_current",
@@ -44,13 +44,15 @@
libs: [
"unsupportedappusage",
"framework-wifi-util-lib",
- "framework-connectivity"
+ "framework-connectivity",
+ "modules-utils-build_system",
],
static_libs: [
// All the classes in netd_aidl_interface must be jarjar so they do not conflict with the
// classes generated by netd_aidl_interfaces-platform-java above.
"netd_aidl_interface-V3-java",
"networkstack-client",
+ "modules-utils-build_system",
],
apex_available: [
"com.android.wifi",
@@ -71,7 +73,7 @@
],
visibility: [
"//frameworks/base/packages/Tethering",
- "//packages/modules/Connectivity/Tethering"
+ "//packages/modules/Connectivity/Tethering",
],
}
diff --git a/services/tests/servicestests/Android.bp b/services/tests/servicestests/Android.bp
index 11d050c..5ecf6bb 100644
--- a/services/tests/servicestests/Android.bp
+++ b/services/tests/servicestests/Android.bp
@@ -38,6 +38,7 @@
"services.people",
"services.usage",
"guava",
+ "guava-android-testlib",
"androidx.test.core",
"androidx.test.ext.truth",
"androidx.test.runner",
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTest.java
index e0bada31..3e5cbea 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTest.java
@@ -35,6 +35,8 @@
import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
+import com.google.common.testing.EqualsTester;
+
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -131,6 +133,24 @@
}
@Test
+ public void testEqualsActiveSource() {
+ int logicalAddress = 0;
+ int physicalAddress = 0x0000;
+ new EqualsTester()
+ .addEqualityGroup(
+ new HdmiCecLocalDevice.ActiveSource(logicalAddress, physicalAddress),
+ new HdmiCecLocalDevice.ActiveSource(logicalAddress, physicalAddress))
+ .addEqualityGroup(
+ new HdmiCecLocalDevice.ActiveSource(logicalAddress, physicalAddress + 1))
+ .addEqualityGroup(
+ new HdmiCecLocalDevice.ActiveSource(logicalAddress + 1, physicalAddress))
+ .addEqualityGroup(
+ new HdmiCecLocalDevice.ActiveSource(
+ logicalAddress + 1, physicalAddress + 1))
+ .testEquals();
+ }
+
+ @Test
public void dispatchMessage_desNotValid() {
HdmiCecMessage msg =
new HdmiCecMessage(
diff --git a/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java
index 35d1b17..1aff8a7 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java
@@ -25,6 +25,7 @@
import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;
import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
import static com.android.server.wm.ActivityStack.ActivityState.FINISHING;
import static com.android.server.wm.ActivityStack.ActivityState.PAUSED;
import static com.android.server.wm.ActivityStack.ActivityState.PAUSING;
@@ -36,10 +37,13 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.verify;
import android.app.WindowConfiguration;
import android.content.ComponentName;
import android.content.pm.ActivityInfo;
+import android.os.UserHandle;
import android.platform.test.annotations.Presubmit;
import androidx.test.filters.SmallTest;
@@ -169,5 +173,34 @@
activity.setState(FINISHING, "test FINISHING");
assertThat(mWm.mRoot.allPausedActivitiesComplete()).isTrue();
}
+
+ @Test
+ public void testLockAllProfileTasks() {
+ // Make an activity visible with the user id set to 0
+ DisplayContent displayContent = mWm.mRoot.getDisplayContent(DEFAULT_DISPLAY);
+ TaskDisplayArea taskDisplayArea = displayContent.getTaskDisplayAreaAt(0);
+ final ActivityStack stack = createTaskStackOnDisplay(WINDOWING_MODE_FULLSCREEN,
+ ACTIVITY_TYPE_STANDARD, displayContent);
+ final ActivityRecord activity = new ActivityTestsBase.ActivityBuilder(stack.mAtmService)
+ .setStack(stack)
+ .setUid(0)
+ .setCreateTask(true)
+ .build();
+
+ // Create another activity on top and the user id is 1
+ Task task = activity.getTask();
+ final ActivityRecord topActivity = new ActivityTestsBase.ActivityBuilder(mWm.mAtmService)
+ .setStack(stack)
+ .setUid(UserHandle.PER_USER_RANGE + 1)
+ .setTask(task)
+ .build();
+
+ // Make sure the listeners will be notified for putting the task to locked state
+ TaskChangeNotificationController controller =
+ mWm.mAtmService.getTaskChangeNotificationController();
+ spyOn(controller);
+ mWm.mRoot.lockAllProfileTasks(0);
+ verify(controller).notifyTaskProfileLocked(eq(task.mTaskId), eq(0));
+ }
}
diff --git a/telecomm/java/android/telecom/PhoneAccountHandle.java b/telecomm/java/android/telecom/PhoneAccountHandle.java
index e1bcb5f..e3485de 100644
--- a/telecomm/java/android/telecom/PhoneAccountHandle.java
+++ b/telecomm/java/android/telecom/PhoneAccountHandle.java
@@ -34,7 +34,10 @@
* <ul>
* <li>The component name of the associated connection service.</li>
* <li>A string identifier that is unique across {@code PhoneAccountHandle}s with the same
- * component name.</li>
+ * component name. Apps registering {@link PhoneAccountHandle}s should ensure that the
+ * {@link #getId()} provided does not expose personally identifying information. A
+ * {@link ConnectionService} should use an opaque token as the {@link PhoneAccountHandle}
+ * identifier.</li>
* </ul>
*
* Note: This Class requires a non-null {@link ComponentName} and {@link UserHandle} to operate
@@ -49,12 +52,35 @@
private final String mId;
private final UserHandle mUserHandle;
+ /**
+ * Creates a new {@link PhoneAccountHandle}.
+ *
+ * @param componentName The {@link ComponentName} of the {@link ConnectionService} which
+ * services this {@link PhoneAccountHandle}.
+ * @param id A string identifier that is unique across {@code PhoneAccountHandle}s with the same
+ * component name. Apps registering {@link PhoneAccountHandle}s should ensure that the
+ * ID provided does not expose personally identifying information. A
+ * {@link ConnectionService} should use an opaque token as the
+ * {@link PhoneAccountHandle} identifier.
+ */
public PhoneAccountHandle(
@NonNull ComponentName componentName,
@NonNull String id) {
this(componentName, id, Process.myUserHandle());
}
+ /**
+ * Creates a new {@link PhoneAccountHandle}.
+ *
+ * @param componentName The {@link ComponentName} of the {@link ConnectionService} which
+ * services this {@link PhoneAccountHandle}.
+ * @param id A string identifier that is unique across {@code PhoneAccountHandle}s with the same
+ * component name. Apps registering {@link PhoneAccountHandle}s should ensure that the
+ * ID provided does not expose personally identifying information. A
+ * {@link ConnectionService} should use an opaque token as the
+ * {@link PhoneAccountHandle} identifier.
+ * @param userHandle The {@link UserHandle} associated with this {@link PhoneAccountHandle}.
+ */
public PhoneAccountHandle(
@NonNull ComponentName componentName,
@NonNull String id,
@@ -80,17 +106,17 @@
* others supported by the connection service that created it.
* <p>
* A connection service must select identifiers that are stable for the lifetime of
- * their users' relationship with their service, across many Android devices. For example, a
- * good set of identifiers might be the email addresses with which with users registered for
- * their accounts with a particular service. Depending on how a service chooses to operate,
- * a bad set of identifiers might be an increasing series of integers
- * ({@code 0}, {@code 1}, {@code 2}, ...) that are generated locally on each phone and could
- * collide with values generated on other phones or after a data wipe of a given phone.
- *
+ * their users' relationship with their service, across many Android devices. The identifier
+ * should be a stable opaque token which uniquely identifies the user within the service.
+ * Depending on how a service chooses to operate, a bad set of identifiers might be an
+ * increasing series of integers ({@code 0}, {@code 1}, {@code 2}, ...) that are generated
+ * locally on each phone and could collide with values generated on other phones or after a data
+ * wipe of a given phone.
+ * <p>
* Important: A non-unique identifier could cause non-deterministic call-log backup/restore
* behavior.
*
- * @return A service-specific unique identifier for this {@code PhoneAccountHandle}.
+ * @return A service-specific unique opaque identifier for this {@code PhoneAccountHandle}.
*/
public String getId() {
return mId;
@@ -157,7 +183,8 @@
}
}
- public static final @android.annotation.NonNull Creator<PhoneAccountHandle> CREATOR = new Creator<PhoneAccountHandle>() {
+ public static final @android.annotation.NonNull Creator<PhoneAccountHandle> CREATOR =
+ new Creator<PhoneAccountHandle>() {
@Override
public PhoneAccountHandle createFromParcel(Parcel in) {
return new PhoneAccountHandle(in);
diff --git a/telephony/java/android/telephony/AccessNetworkConstants.java b/telephony/java/android/telephony/AccessNetworkConstants.java
index 96e715e..1d7a476 100644
--- a/telephony/java/android/telephony/AccessNetworkConstants.java
+++ b/telephony/java/android/telephony/AccessNetworkConstants.java
@@ -62,6 +62,7 @@
switch (transportType) {
case TRANSPORT_TYPE_WWAN: return "WWAN";
case TRANSPORT_TYPE_WLAN: return "WLAN";
+ case TRANSPORT_TYPE_INVALID: return "INVALID";
default: return Integer.toString(transportType);
}
}
diff --git a/telephony/java/android/telephony/data/ApnSetting.java b/telephony/java/android/telephony/data/ApnSetting.java
index bb90fb1..be1502a 100644
--- a/telephony/java/android/telephony/data/ApnSetting.java
+++ b/telephony/java/android/telephony/data/ApnSetting.java
@@ -1582,16 +1582,6 @@
}
/**
- * Same as {@link #getApnTypeString(int)}, but returns "Unknown" instead of an empty string
- * when provided with an invalid int for compatibility purposes.
- * @hide
- */
- public static @NonNull String getApnTypeStringInternal(@ApnType int apnType) {
- String result = getApnTypeString(apnType);
- return TextUtils.isEmpty(result) ? "Unknown" : result;
- }
-
- /**
* Converts the string representation of an APN type to its integer representation.
*
* @param apnType APN type as a string
diff --git a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java
index 00bd4cf..eaf9c7b4 100644
--- a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java
+++ b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java
@@ -482,6 +482,33 @@
}
@Test
+ public void testExpireSession_Phase1_Install() throws Exception {
+ assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(-1);
+ Install.single(TestApp.A1).commit();
+ assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(1);
+ Install.single(TestApp.A2).setEnableRollback().setStaged().commit();
+ }
+
+ @Test
+ public void testExpireSession_Phase2_VerifyInstall() throws Exception {
+ assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(2);
+ RollbackManager rm = RollbackUtils.getRollbackManager();
+ RollbackInfo rollback = getUniqueRollbackInfoForPackage(
+ rm.getAvailableRollbacks(), TestApp.A);
+ assertThat(rollback).isNotNull();
+ assertThat(rollback).packagesContainsExactly(Rollback.from(TestApp.A2).to(TestApp.A1));
+ assertThat(rollback.isStaged()).isTrue();
+ }
+
+ @Test
+ public void testExpireSession_Phase3_VerifyRollback() throws Exception {
+ RollbackManager rm = RollbackUtils.getRollbackManager();
+ RollbackInfo rollback = getUniqueRollbackInfoForPackage(
+ rm.getAvailableRollbacks(), TestApp.A);
+ assertThat(rollback).isNotNull();
+ }
+
+ @Test
public void hasMainlineModule() throws Exception {
String pkgName = getModuleMetadataPackageName();
boolean existed = InstrumentationRegistry.getInstrumentation().getContext()
diff --git a/tests/RollbackTest/StagedRollbackTest/src/com/android/tests/rollback/host/StagedRollbackTest.java b/tests/RollbackTest/StagedRollbackTest/src/com/android/tests/rollback/host/StagedRollbackTest.java
index be74e33..bd6b813 100644
--- a/tests/RollbackTest/StagedRollbackTest/src/com/android/tests/rollback/host/StagedRollbackTest.java
+++ b/tests/RollbackTest/StagedRollbackTest/src/com/android/tests/rollback/host/StagedRollbackTest.java
@@ -39,7 +39,9 @@
import org.junit.runner.RunWith;
import java.io.File;
+import java.time.Instant;
import java.util.Collections;
+import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
@@ -445,6 +447,27 @@
after.forEach(dir -> assertDirectoryIsEmpty(dir));
}
+ /**
+ * Tests an available rollback shouldn't be deleted when its session expires.
+ */
+ @Test
+ public void testExpireSession() throws Exception {
+ runPhase("testExpireSession_Phase1_Install");
+ getDevice().reboot();
+ runPhase("testExpireSession_Phase2_VerifyInstall");
+
+ // Advance system clock by 7 days to expire the staged session
+ Instant t1 = Instant.ofEpochMilli(getDevice().getDeviceDate());
+ Instant t2 = t1.plusMillis(TimeUnit.DAYS.toMillis(7));
+ runAsRoot(() -> getDevice().setDate(Date.from(t2)));
+
+ // Somehow we need to wait for a while before reboot. Otherwise the change to the
+ // system clock will be reset after reboot.
+ Thread.sleep(3000);
+ getDevice().reboot();
+ runPhase("testExpireSession_Phase3_VerifyRollback");
+ }
+
private void pushTestApex() throws Exception {
CompatibilityBuildHelper buildHelper = new CompatibilityBuildHelper(getBuild());
final String fileName = APK_IN_APEX_TESTAPEX_NAME + "_v1.apex";
@@ -525,4 +548,18 @@
return false;
}
}
+
+ @FunctionalInterface
+ private interface ExceptionalRunnable {
+ void run() throws Exception;
+ }
+
+ private void runAsRoot(ExceptionalRunnable runnable) throws Exception {
+ try {
+ getDevice().enableAdbRoot();
+ runnable.run();
+ } finally {
+ getDevice().disableAdbRoot();
+ }
+ }
}
diff --git a/tests/net/integration/src/com/android/server/net/integrationtests/TestNetworkStackService.kt b/tests/net/integration/src/com/android/server/net/integrationtests/TestNetworkStackService.kt
new file mode 100644
index 0000000..649f71d
--- /dev/null
+++ b/tests/net/integration/src/com/android/server/net/integrationtests/TestNetworkStackService.kt
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2019 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 com.android.server.net.integrationtests
+
+import android.app.Service
+import android.content.Context
+import android.content.Intent
+import android.net.INetworkMonitorCallbacks
+import android.net.Network
+import android.net.metrics.IpConnectivityLog
+import android.net.util.SharedLog
+import android.os.IBinder
+import com.android.networkstack.netlink.TcpSocketTracker
+import com.android.server.NetworkStackService
+import com.android.server.NetworkStackService.NetworkMonitorConnector
+import com.android.server.NetworkStackService.NetworkStackConnector
+import com.android.server.connectivity.NetworkMonitor
+import com.android.server.net.integrationtests.NetworkStackInstrumentationService.InstrumentationConnector
+import org.mockito.Mockito.doReturn
+import org.mockito.Mockito.mock
+import org.mockito.Mockito.spy
+import java.net.HttpURLConnection
+import java.net.URL
+import java.net.URLConnection
+
+private const val TEST_NETID = 42
+
+/**
+ * Android service that can return an [android.net.INetworkStackConnector] which can be instrumented
+ * through [NetworkStackInstrumentationService].
+ * Useful in tests to create test instrumented NetworkStack components that can receive
+ * instrumentation commands through [NetworkStackInstrumentationService].
+ */
+class TestNetworkStackService : Service() {
+ override fun onBind(intent: Intent): IBinder = TestNetworkStackConnector(makeTestContext())
+
+ private fun makeTestContext() = spy(applicationContext).also {
+ doReturn(mock(IBinder::class.java)).`when`(it).getSystemService(Context.NETD_SERVICE)
+ }
+
+ private class TestPermissionChecker : NetworkStackService.PermissionChecker() {
+ override fun enforceNetworkStackCallingPermission() = Unit
+ }
+
+ private class NetworkMonitorDeps(private val privateDnsBypassNetwork: Network) :
+ NetworkMonitor.Dependencies() {
+ override fun getPrivateDnsBypassNetwork(network: Network?) = privateDnsBypassNetwork
+ }
+
+ private inner class TestNetworkStackConnector(context: Context) : NetworkStackConnector(
+ context, TestPermissionChecker(), NetworkStackService.Dependencies()) {
+
+ private val network = Network(TEST_NETID)
+ private val privateDnsBypassNetwork = TestNetwork(TEST_NETID)
+
+ private inner class TestNetwork(netId: Int) : Network(netId) {
+ override fun openConnection(url: URL): URLConnection {
+ val response = InstrumentationConnector.processRequest(url)
+
+ val connection = mock(HttpURLConnection::class.java)
+ doReturn(response.responseCode).`when`(connection).responseCode
+ doReturn(response.contentLength).`when`(connection).contentLengthLong
+ doReturn(response.redirectUrl).`when`(connection).getHeaderField("location")
+ return connection
+ }
+ }
+
+ override fun makeNetworkMonitor(
+ network: Network,
+ name: String?,
+ cb: INetworkMonitorCallbacks
+ ) {
+ val nm = NetworkMonitor(this@TestNetworkStackService, cb,
+ this.network,
+ mock(IpConnectivityLog::class.java), mock(SharedLog::class.java),
+ mock(NetworkStackService.NetworkStackServiceManager::class.java),
+ NetworkMonitorDeps(privateDnsBypassNetwork),
+ mock(TcpSocketTracker::class.java))
+ cb.onNetworkMonitorCreated(NetworkMonitorConnector(nm, TestPermissionChecker()))
+ }
+ }
+}