diff options
17 files changed, 306 insertions, 72 deletions
diff --git a/core/java/Android.bp b/core/java/Android.bp index 874704e6350e..7ad5e05f79b9 100644 --- a/core/java/Android.bp +++ b/core/java/Android.bp @@ -277,6 +277,10 @@ aidl_interface { backend: { rust: { enabled: true, + apex_available: [ + "//apex_available:platform", + "com.android.virt", // for virtualizationservice + ], }, }, } diff --git a/core/jni/android_os_Debug.cpp b/core/jni/android_os_Debug.cpp index f379ba0ddebb..5814a187506f 100644 --- a/core/jni/android_os_Debug.cpp +++ b/core/jni/android_os_Debug.cpp @@ -877,7 +877,7 @@ static jlong android_os_Debug_getGpuDmaBufUsageKb(JNIEnv* env, jobject clazz) { 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 2b7a579213d3..10600e37b220 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 b500e1631fb5..8d2363b6e831 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 @@ public class PermissionManagerService extends IPermissionManager.Stub { } 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); + 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); + 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); + } + } } } diff --git a/services/core/java/com/android/server/recoverysystem/RecoverySystemService.java b/services/core/java/com/android/server/recoverysystem/RecoverySystemService.java index ed4a7bf107d1..1b4e36b6c464 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 @@ public class RecoverySystemService extends IRecoverySystem.Stub implements Reboo } 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 81878e7f5321..8ec1bf828599 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 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { 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 eaf76938e2e8..ddad1dbd9b3d 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 @@ class RootWindowContainer extends WindowContainer<DisplayContent> } /** - * 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 @@ class RootWindowContainer extends WindowContainer<DisplayContent> 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 fb3db8b5ee52..a24d9731887a 100644 --- a/services/net/Android.bp +++ b/services/net/Android.bp @@ -37,6 +37,7 @@ java_library { 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 +45,15 @@ java_library { 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 +74,7 @@ filegroup { ], 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 11d050c0dc7e..5ecf6bb4056f 100644 --- a/services/tests/servicestests/Android.bp +++ b/services/tests/servicestests/Android.bp @@ -38,6 +38,7 @@ android_test { "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 e0bada3138e0..3e5cbea6a2a4 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 android.os.test.TestLooper; 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 @@ public class HdmiCecLocalDeviceTest { } @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 35d1b17d5822..1aff8a7b5382 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_NOTIFICATION_SHADE; 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 com.google.common.truth.Truth.assertThat; 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 @@ public class RootWindowContainerTests extends WindowTestsBase { 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 e1bcb5fbdf00..e3485deb9080 100644 --- a/telecomm/java/android/telecom/PhoneAccountHandle.java +++ b/telecomm/java/android/telecom/PhoneAccountHandle.java @@ -34,7 +34,10 @@ import java.util.Objects; * <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 @@ public final class PhoneAccountHandle implements Parcelable { 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 @@ public final class PhoneAccountHandle implements Parcelable { * 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 final class PhoneAccountHandle implements Parcelable { } } - 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 96e715ee0495..1d7a4761dec6 100644 --- a/telephony/java/android/telephony/AccessNetworkConstants.java +++ b/telephony/java/android/telephony/AccessNetworkConstants.java @@ -62,6 +62,7 @@ public final class AccessNetworkConstants { 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 bb90fb17f4bb..be1502ad49f2 100644 --- a/telephony/java/android/telephony/data/ApnSetting.java +++ b/telephony/java/android/telephony/data/ApnSetting.java @@ -1582,16 +1582,6 @@ public class ApnSetting implements Parcelable { } /** - * 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 00bd4cf388ce..eaf9c7b4cb2e 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 @@ public class StagedRollbackTest { } @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 be74e338d7ac..bd6b81374168 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.Test; 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 @@ public class StagedRollbackTest extends BaseHostJUnit4Test { 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 @@ public class StagedRollbackTest extends BaseHostJUnit4Test { 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 000000000000..649f71d4293f --- /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())) + } + } +} |