[Ravenwood] Decouple environment setup from RavenwoodConfig
- Also deprecate RavenwoodRule.setServicesRequired so that RavenwoodRule
is only used for setting system properties.
Flag: EXEMPT host test change only
Bug: 377765941
Test: $ANDROID_BUILD_TOP/frameworks/base/ravenwood/scripts/run-ravenwood-tests.sh
Change-Id: Id7ca551bd797e786f2d71777eb9f972fb5fb6c88
diff --git a/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodAwareTestRunner.java b/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodAwareTestRunner.java
index 9b71f80..de3c5f2 100644
--- a/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodAwareTestRunner.java
+++ b/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodAwareTestRunner.java
@@ -133,9 +133,6 @@
Log.v(TAG, "RavenwoodAwareTestRunner starting for " + testClass.getCanonicalName());
- // This is needed to make AndroidJUnit4ClassRunner happy.
- InstrumentationRegistry.registerInstance(null, Bundle.EMPTY);
-
// Hook point to allow more customization.
runAnnotatedMethodsOnRavenwood(RavenwoodTestRunnerInitializing.class, null);
diff --git a/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodConfigState.java b/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodConfigState.java
deleted file mode 100644
index 870a10a..0000000
--- a/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodConfigState.java
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * Copyright (C) 2024 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.platform.test.ravenwood;
-
-import static com.android.ravenwood.common.RavenwoodCommonUtils.RAVENWOOD_EMPTY_RESOURCES_APK;
-
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-
-import android.annotation.Nullable;
-import android.app.ResourcesManager;
-import android.content.res.Resources;
-import android.view.DisplayAdjustments;
-
-import java.io.File;
-import java.util.HashMap;
-
-/**
- * Used to store various states associated with {@link RavenwoodConfig} that's inly needed
- * in junit-impl.
- *
- * We don't want to put it in junit-src to avoid having to recompile all the downstream
- * dependencies after changing this class.
- *
- * All members must be called from the runner's main thread.
- */
-public class RavenwoodConfigState {
- private static final String TAG = "RavenwoodConfigState";
-
- private final RavenwoodConfig mConfig;
-
- // TODO: Move the other contexts from RavenwoodConfig to here too? They're used by
- // RavenwoodRule too, but RavenwoodRule can probably use InstrumentationRegistry?
- RavenwoodContext mSystemServerContext;
-
- public RavenwoodConfigState(RavenwoodConfig config) {
- mConfig = config;
- }
-
- /** Map from path -> resources. */
- private final HashMap<File, Resources> mCachedResources = new HashMap<>();
-
- /**
- * Load {@link Resources} from an APK, with cache.
- */
- public Resources loadResources(@Nullable File apkPath) {
- var cached = mCachedResources.get(apkPath);
- if (cached != null) {
- return cached;
- }
-
- var fileToLoad = apkPath != null ? apkPath : new File(RAVENWOOD_EMPTY_RESOURCES_APK);
-
- assertTrue("File " + fileToLoad + " doesn't exist.", fileToLoad.isFile());
-
- final String path = fileToLoad.getAbsolutePath();
- final var emptyPaths = new String[0];
-
- ResourcesManager.getInstance().initializeApplicationPaths(path, emptyPaths);
-
- final var ret = ResourcesManager.getInstance().getResources(null, path,
- emptyPaths, emptyPaths, emptyPaths,
- emptyPaths, null, null,
- new DisplayAdjustments().getCompatibilityInfo(),
- RavenwoodRuntimeEnvironmentController.class.getClassLoader(), null);
-
- assertNotNull(ret);
-
- mCachedResources.put(apkPath, ret);
- return ret;
- }
-}
diff --git a/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRunnerState.java b/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRunnerState.java
index ec00e8f..4ab1fa1 100644
--- a/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRunnerState.java
+++ b/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRunnerState.java
@@ -53,11 +53,6 @@
}
/**
- * The RavenwoodConfig used to configure the current Ravenwood environment.
- * This can either come from mConfig or mRule.
- */
- private RavenwoodConfig mCurrentConfig;
- /**
* The RavenwoodConfig declared in the test class
*/
private RavenwoodConfig mConfig;
@@ -68,10 +63,6 @@
private boolean mHasRavenwoodRule;
private Description mMethodDescription;
- public RavenwoodConfig getConfig() {
- return mCurrentConfig;
- }
-
public void enterTestRunner() {
Log.i(TAG, "enterTestRunner: " + mRunner);
@@ -83,31 +74,19 @@
fail("RavenwoodConfig and RavenwoodRule cannot be used in the same class."
+ " Suggest migrating to RavenwoodConfig.");
}
- mCurrentConfig = mConfig;
- } else if (!mHasRavenwoodRule) {
- // If no RavenwoodConfig and no RavenwoodRule, use a default config
- mCurrentConfig = new RavenwoodConfig.Builder().build();
}
- if (mCurrentConfig != null) {
- RavenwoodRuntimeEnvironmentController.init(mRunner);
- }
+ RavenwoodRuntimeEnvironmentController.initForRunner();
}
public void enterTestClass() {
Log.i(TAG, "enterTestClass: " + mRunner.mTestJavaClass.getName());
-
- if (mCurrentConfig != null) {
- RavenwoodRuntimeEnvironmentController.init(mRunner);
- }
}
public void exitTestClass() {
Log.i(TAG, "exitTestClass: " + mRunner.mTestJavaClass.getName());
try {
- if (mCurrentConfig != null) {
- RavenwoodRuntimeEnvironmentController.reset();
- }
+ RavenwoodRuntimeEnvironmentController.exitTestClass();
} finally {
mConfig = null;
mRule = null;
@@ -116,11 +95,11 @@
public void enterTestMethod(Description description) {
mMethodDescription = description;
+ RavenwoodRuntimeEnvironmentController.initForMethod();
}
public void exitTestMethod() {
mMethodDescription = null;
- RavenwoodRuntimeEnvironmentController.reinit();
}
public void enterRavenwoodRule(RavenwoodRule rule) {
@@ -133,10 +112,7 @@
+ " which is not supported.");
}
mRule = rule;
- if (mCurrentConfig == null) {
- mCurrentConfig = rule.getConfiguration();
- }
- RavenwoodRuntimeEnvironmentController.init(mRunner);
+ RavenwoodRuntimeEnvironmentController.setSystemProperties(rule.mSystemProperties);
}
public void exitRavenwoodRule(RavenwoodRule rule) {
diff --git a/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRuntimeEnvironmentController.java b/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRuntimeEnvironmentController.java
index 979076e..c2ed45d 100644
--- a/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRuntimeEnvironmentController.java
+++ b/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRuntimeEnvironmentController.java
@@ -16,8 +16,11 @@
package android.platform.test.ravenwood;
+import static android.os.Process.FIRST_APPLICATION_UID;
+import static android.os.UserHandle.SYSTEM;
import static android.platform.test.ravenwood.RavenwoodSystemServer.ANDROID_PACKAGE_NAME;
+import static com.android.ravenwood.common.RavenwoodCommonUtils.RAVENWOOD_EMPTY_RESOURCES_APK;
import static com.android.ravenwood.common.RavenwoodCommonUtils.RAVENWOOD_INST_RESOURCE_APK;
import static com.android.ravenwood.common.RavenwoodCommonUtils.RAVENWOOD_RESOURCE_APK;
import static com.android.ravenwood.common.RavenwoodCommonUtils.RAVENWOOD_VERBOSE_LOGGING;
@@ -25,7 +28,9 @@
import static com.android.ravenwood.common.RavenwoodCommonUtils.parseNullableInt;
import static com.android.ravenwood.common.RavenwoodCommonUtils.withDefault;
+import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertThrows;
+import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.mock;
@@ -53,6 +58,7 @@
import android.system.ErrnoException;
import android.system.Os;
import android.util.Log;
+import android.view.DisplayAdjustments;
import androidx.test.platform.app.InstrumentationRegistry;
@@ -62,7 +68,6 @@
import com.android.ravenwood.RavenwoodRuntimeNative;
import com.android.ravenwood.RavenwoodRuntimeState;
import com.android.ravenwood.common.RavenwoodCommonUtils;
-import com.android.ravenwood.common.RavenwoodRuntimeException;
import com.android.ravenwood.common.SneakyThrow;
import com.android.server.LocalServices;
import com.android.server.compat.PlatformCompat;
@@ -74,8 +79,10 @@
import java.io.IOException;
import java.io.PrintStream;
import java.util.Collections;
+import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
+import java.util.Random;
import java.util.Set;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
@@ -85,8 +92,7 @@
import java.util.function.Supplier;
/**
- * Responsible for initializing and de-initializing the environment, according to a
- * {@link RavenwoodConfig}.
+ * Responsible for initializing and the environment.
*/
public class RavenwoodRuntimeEnvironmentController {
private static final String TAG = "RavenwoodRuntimeEnvironmentController";
@@ -113,8 +119,6 @@
private static ScheduledFuture<?> sPendingTimeout;
- private static long sOriginalIdentityToken = -1;
-
/**
* When enabled, attempt to detect uncaught exceptions from background threads.
*/
@@ -147,6 +151,10 @@
return res;
}
+ /** Map from path -> resources. */
+ private static final HashMap<File, Resources> sCachedResources = new HashMap<>();
+ private static Set<String> sAdoptedPermissions = Collections.emptySet();
+
private static final Object sInitializationLock = new Object();
@GuardedBy("sInitializationLock")
@@ -155,15 +163,18 @@
@GuardedBy("sInitializationLock")
private static Throwable sExceptionFromGlobalInit;
- private static RavenwoodAwareTestRunner sRunner;
private static RavenwoodSystemProperties sProps;
private static final int DEFAULT_TARGET_SDK_LEVEL = VERSION_CODES.CUR_DEVELOPMENT;
private static final String DEFAULT_PACKAGE_NAME = "com.android.ravenwoodtests.defaultname";
+ private static final int sMyPid = new Random().nextInt(100, 32768);
private static int sTargetSdkLevel;
private static String sTestPackageName;
private static String sTargetPackageName;
+ private static Instrumentation sInstrumentation;
+ private static final long sCallingIdentity =
+ packBinderIdentityToken(false, FIRST_APPLICATION_UID, sMyPid);
/**
* Initialize the global environment.
@@ -182,7 +193,7 @@
Log.e(TAG, "globalInit() failed", th);
sExceptionFromGlobalInit = th;
- throw th;
+ SneakyThrow.sneakyThrow(th);
}
} else {
// Subsequent calls. If the first call threw, just throw the same error, to prevent
@@ -197,10 +208,13 @@
}
}
- private static void globalInitInner() {
+ private static void globalInitInner() throws IOException {
if (RAVENWOOD_VERBOSE_LOGGING) {
Log.v(TAG, "globalInit() called here...", new RuntimeException("NOT A CRASH"));
}
+ if (ENABLE_UNCAUGHT_EXCEPTION_DETECTION) {
+ Thread.setDefaultUncaughtExceptionHandler(sUncaughtExceptionHandler);
+ }
// Some process-wide initialization. (maybe redirect stdout/stderr)
RavenwoodCommonUtils.loadJniLibrary(LIBRAVENWOOD_INITIALIZER_NAME);
@@ -251,6 +265,74 @@
loadRavenwoodProperties();
assertMockitoVersion();
+
+ Log.i(TAG, "TargetPackageName=" + sTargetPackageName);
+ Log.i(TAG, "TestPackageName=" + sTestPackageName);
+ Log.i(TAG, "TargetSdkLevel=" + sTargetSdkLevel);
+
+ RavenwoodRuntimeState.sUid = FIRST_APPLICATION_UID;
+ RavenwoodRuntimeState.sPid = sMyPid;
+ RavenwoodRuntimeState.sTargetSdkLevel = sTargetSdkLevel;
+
+ ServiceManager.init$ravenwood();
+ LocalServices.removeAllServicesForTest();
+
+ ActivityManager.init$ravenwood(SYSTEM.getIdentifier());
+
+ final var main = new HandlerThread(MAIN_THREAD_NAME);
+ main.start();
+ Looper.setMainLooperForTest(main.getLooper());
+
+ final boolean isSelfInstrumenting =
+ Objects.equals(sTestPackageName, sTargetPackageName);
+
+ // This will load the resources from the apk set to `resource_apk` in the build file.
+ // This is supposed to be the "target app"'s resources.
+ final Supplier<Resources> targetResourcesLoader = () -> {
+ var file = new File(RAVENWOOD_RESOURCE_APK);
+ return loadResources(file.exists() ? file : null);
+ };
+
+ // Set up test context's (== instrumentation context's) resources.
+ // If the target package name == test package name, then we use the main resources.
+ final Supplier<Resources> instResourcesLoader;
+ if (isSelfInstrumenting) {
+ instResourcesLoader = targetResourcesLoader;
+ } else {
+ instResourcesLoader = () -> {
+ var file = new File(RAVENWOOD_INST_RESOURCE_APK);
+ return loadResources(file.exists() ? file : null);
+ };
+ }
+
+ var instContext = new RavenwoodContext(
+ sTestPackageName, main, instResourcesLoader);
+ var targetContext = new RavenwoodContext(
+ sTargetPackageName, main, targetResourcesLoader);
+
+ // Set up app context.
+ var appContext = new RavenwoodContext(sTargetPackageName, main, targetResourcesLoader);
+ appContext.setApplicationContext(appContext);
+ if (isSelfInstrumenting) {
+ instContext.setApplicationContext(appContext);
+ targetContext.setApplicationContext(appContext);
+ } else {
+ // When instrumenting into another APK, the test context doesn't have an app context.
+ targetContext.setApplicationContext(appContext);
+ }
+
+ final Supplier<Resources> systemResourcesLoader = () -> loadResources(null);
+
+ var systemServerContext =
+ new RavenwoodContext(ANDROID_PACKAGE_NAME, main, systemResourcesLoader);
+
+ sInstrumentation = new Instrumentation();
+ sInstrumentation.basicInit(instContext, targetContext, null);
+ InstrumentationRegistry.registerInstance(sInstrumentation, Bundle.EMPTY);
+
+ RavenwoodSystemServer.init(systemServerContext);
+
+ initializeCompatIds();
}
private static void loadRavenwoodProperties() {
@@ -265,134 +347,38 @@
}
/**
- * Initialize the environment.
+ * Partially reset and initialize before each test class invocation
*/
- public static void init(RavenwoodAwareTestRunner runner) {
- if (RAVENWOOD_VERBOSE_LOGGING) {
- Log.v(TAG, "init() called here: " + runner, new RuntimeException("STACKTRACE"));
- }
- if (sRunner == runner) {
- return;
- }
- if (sRunner != null) {
- reset();
- }
- sRunner = runner;
- try {
- initInner(runner.mState.getConfig());
- } catch (Exception th) {
- Log.e(TAG, "init() failed", th);
+ public static void initForRunner() {
+ var targetContext = sInstrumentation.getTargetContext();
+ var instContext = sInstrumentation.getContext();
+ // We need to recreate the mock UiAutomation for each test class, because sometimes tests
+ // will call Mockito.framework().clearInlineMocks() after execution.
+ sInstrumentation.basicInit(instContext, targetContext, createMockUiAutomation());
- RavenwoodCommonUtils.runIgnoringException(()-> reset());
-
- SneakyThrow.sneakyThrow(th);
- }
- }
-
- private static void initInner(RavenwoodConfig config) throws IOException {
- if (ENABLE_UNCAUGHT_EXCEPTION_DETECTION) {
- maybeThrowPendingUncaughtException(false);
- Thread.setDefaultUncaughtExceptionHandler(sUncaughtExceptionHandler);
- }
-
- config.mTargetPackageName = sTargetPackageName;
- config.mTestPackageName = sTestPackageName;
- config.mTargetSdkLevel = sTargetSdkLevel;
-
- Log.i(TAG, "TargetPackageName=" + sTargetPackageName);
- Log.i(TAG, "TestPackageName=" + sTestPackageName);
- Log.i(TAG, "TargetSdkLevel=" + sTargetSdkLevel);
-
- RavenwoodRuntimeState.sUid = config.mUid;
- RavenwoodRuntimeState.sPid = config.mPid;
- RavenwoodRuntimeState.sTargetSdkLevel = config.mTargetSdkLevel;
- sOriginalIdentityToken = Binder.clearCallingIdentity();
- reinit();
- setSystemProperties(config.mSystemProperties);
-
- ServiceManager.init$ravenwood();
- LocalServices.removeAllServicesForTest();
-
- ActivityManager.init$ravenwood(config.mCurrentUser);
-
- final var main = new HandlerThread(MAIN_THREAD_NAME);
- main.start();
- Looper.setMainLooperForTest(main.getLooper());
-
- final boolean isSelfInstrumenting =
- Objects.equals(config.mTestPackageName, config.mTargetPackageName);
-
- // This will load the resources from the apk set to `resource_apk` in the build file.
- // This is supposed to be the "target app"'s resources.
- final Supplier<Resources> targetResourcesLoader = () -> {
- var file = new File(RAVENWOOD_RESOURCE_APK);
- return config.mState.loadResources(file.exists() ? file : null);
- };
-
- // Set up test context's (== instrumentation context's) resources.
- // If the target package name == test package name, then we use the main resources.
- final Supplier<Resources> instResourcesLoader;
- if (isSelfInstrumenting) {
- instResourcesLoader = targetResourcesLoader;
- } else {
- instResourcesLoader = () -> {
- var file = new File(RAVENWOOD_INST_RESOURCE_APK);
- return config.mState.loadResources(file.exists() ? file : null);
- };
- }
-
- var instContext = new RavenwoodContext(
- config.mTestPackageName, main, instResourcesLoader);
- var targetContext = new RavenwoodContext(
- config.mTargetPackageName, main, targetResourcesLoader);
-
- // Set up app context.
- var appContext = new RavenwoodContext(
- config.mTargetPackageName, main, targetResourcesLoader);
- appContext.setApplicationContext(appContext);
- if (isSelfInstrumenting) {
- instContext.setApplicationContext(appContext);
- targetContext.setApplicationContext(appContext);
- } else {
- // When instrumenting into another APK, the test context doesn't have an app context.
- targetContext.setApplicationContext(appContext);
- }
- config.mInstContext = instContext;
- config.mTargetContext = targetContext;
-
- final Supplier<Resources> systemResourcesLoader = () -> config.mState.loadResources(null);
-
- config.mState.mSystemServerContext =
- new RavenwoodContext(ANDROID_PACKAGE_NAME, main, systemResourcesLoader);
-
- // Prepare other fields.
- config.mInstrumentation = new Instrumentation();
- config.mInstrumentation.basicInit(instContext, targetContext, createMockUiAutomation());
- InstrumentationRegistry.registerInstance(config.mInstrumentation, Bundle.EMPTY);
-
- RavenwoodSystemServer.init(config);
-
- initializeCompatIds(config);
+ Process_ravenwood.reset();
+ DeviceConfig_host.reset();
+ Binder.restoreCallingIdentity(sCallingIdentity);
if (ENABLE_TIMEOUT_STACKS) {
sPendingTimeout = sTimeoutExecutor.schedule(
RavenwoodRuntimeEnvironmentController::dumpStacks,
TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
}
- }
-
- /**
- * Partially re-initialize after each test method invocation
- */
- public static void reinit() {
- // sRunner could be null, if there was a failure in the initialization.
- if (sRunner != null) {
- var config = sRunner.mState.getConfig();
- Binder.restoreCallingIdentity(packBinderIdentityToken(false, config.mUid, config.mPid));
+ if (ENABLE_UNCAUGHT_EXCEPTION_DETECTION) {
+ maybeThrowPendingUncaughtException(false);
}
}
- private static void initializeCompatIds(RavenwoodConfig config) {
+ /**
+ * Partially reset and initialize before each test method invocation
+ */
+ public static void initForMethod() {
+ // TODO(b/375272444): this is a hacky workaround to ensure binder identity
+ Binder.restoreCallingIdentity(sCallingIdentity);
+ }
+
+ private static void initializeCompatIds() {
// Set up compat-IDs for the app side.
// TODO: Inside the system server, all the compat-IDs should be enabled,
// Due to the `AppCompatCallbacks.install(new long[0], new long[0])` call in
@@ -400,8 +386,8 @@
// Compat framework only uses the package name and the target SDK level.
ApplicationInfo appInfo = new ApplicationInfo();
- appInfo.packageName = config.mTargetPackageName;
- appInfo.targetSdkVersion = config.mTargetSdkLevel;
+ appInfo.packageName = sTargetPackageName;
+ appInfo.targetSdkVersion = sTargetSdkLevel;
PlatformCompat platformCompat = null;
try {
@@ -418,65 +404,42 @@
}
/**
- * De-initialize.
- *
- * Note, we call this method when init() fails too, so this method should deal with
- * any partially-initialized states.
+ * Load {@link Resources} from an APK, with cache.
*/
- public static void reset() {
- if (RAVENWOOD_VERBOSE_LOGGING) {
- Log.v(TAG, "reset() called here", new RuntimeException("STACKTRACE"));
+ private static Resources loadResources(@Nullable File apkPath) {
+ var cached = sCachedResources.get(apkPath);
+ if (cached != null) {
+ return cached;
}
- if (sRunner == null) {
- throw new RavenwoodRuntimeException("Internal error: reset() already called");
- }
- var config = sRunner.mState.getConfig();
- sRunner = null;
+ var fileToLoad = apkPath != null ? apkPath : new File(RAVENWOOD_EMPTY_RESOURCES_APK);
+
+ assertTrue("File " + fileToLoad + " doesn't exist.", fileToLoad.isFile());
+
+ final String path = fileToLoad.getAbsolutePath();
+ final var emptyPaths = new String[0];
+
+ ResourcesManager.getInstance().initializeApplicationPaths(path, emptyPaths);
+
+ final var ret = ResourcesManager.getInstance().getResources(null, path,
+ emptyPaths, emptyPaths, emptyPaths,
+ emptyPaths, null, null,
+ new DisplayAdjustments().getCompatibilityInfo(),
+ RavenwoodRuntimeEnvironmentController.class.getClassLoader(), null);
+
+ assertNotNull(ret);
+
+ sCachedResources.put(apkPath, ret);
+ return ret;
+ }
+
+ /**
+ * A callback when a test class finishes its execution, mostly only for debugging.
+ */
+ public static void exitTestClass() {
if (ENABLE_TIMEOUT_STACKS) {
sPendingTimeout.cancel(false);
}
-
- RavenwoodSystemServer.reset(config);
-
- InstrumentationRegistry.registerInstance(null, Bundle.EMPTY);
- config.mInstrumentation = null;
- if (config.mInstContext != null) {
- ((RavenwoodContext) config.mInstContext).cleanUp();
- config.mInstContext = null;
- }
- if (config.mTargetContext != null) {
- ((RavenwoodContext) config.mTargetContext).cleanUp();
- config.mTargetContext = null;
- }
- if (config.mState.mSystemServerContext != null) {
- config.mState.mSystemServerContext.cleanUp();
- }
-
- if (Looper.getMainLooper() != null) {
- Looper.getMainLooper().quit();
- }
- Looper.clearMainLooperForTest();
-
- ActivityManager.reset$ravenwood();
-
- LocalServices.removeAllServicesForTest();
- ServiceManager.reset$ravenwood();
-
- setSystemProperties(null);
- if (sOriginalIdentityToken != -1) {
- Binder.restoreCallingIdentity(sOriginalIdentityToken);
- }
- RavenwoodRuntimeState.reset();
- Process_ravenwood.reset();
- DeviceConfig_host.reset();
-
- try {
- ResourcesManager.setInstance(null); // Better structure needed.
- } catch (Exception e) {
- // AOSP-CHANGE: AOSP doesn't support resources yet.
- }
-
if (ENABLE_UNCAUGHT_EXCEPTION_DETECTION) {
maybeThrowPendingUncaughtException(true);
}
@@ -524,7 +487,7 @@
/**
* Set the current configuration to the actual SystemProperties.
*/
- private static void setSystemProperties(@Nullable RavenwoodSystemProperties systemProperties) {
+ public static void setSystemProperties(@Nullable RavenwoodSystemProperties systemProperties) {
SystemProperties.clearChangeCallbacksForTest();
RavenwoodRuntimeNative.clearSystemProperties();
if (systemProperties == null) systemProperties = new RavenwoodSystemProperties();
@@ -558,28 +521,28 @@
// TODO: use the real UiAutomation class instead of a mock
private static UiAutomation createMockUiAutomation() {
- final Set[] adoptedPermission = { Collections.emptySet() };
+ sAdoptedPermissions = Collections.emptySet();
var mock = mock(UiAutomation.class, inv -> {
HostTestUtils.onThrowMethodCalled();
return null;
});
doAnswer(inv -> {
- adoptedPermission[0] = UiAutomation.ALL_PERMISSIONS;
+ sAdoptedPermissions = UiAutomation.ALL_PERMISSIONS;
return null;
}).when(mock).adoptShellPermissionIdentity();
doAnswer(inv -> {
if (inv.getArgument(0) == null) {
- adoptedPermission[0] = UiAutomation.ALL_PERMISSIONS;
+ sAdoptedPermissions = UiAutomation.ALL_PERMISSIONS;
} else {
- adoptedPermission[0] = Set.of(inv.getArguments());
+ sAdoptedPermissions = (Set) Set.of(inv.getArguments());
}
return null;
}).when(mock).adoptShellPermissionIdentity(any());
doAnswer(inv -> {
- adoptedPermission[0] = Collections.emptySet();
+ sAdoptedPermissions = Collections.emptySet();
return null;
}).when(mock).dropShellPermissionIdentity();
- doAnswer(inv -> adoptedPermission[0]).when(mock).getAdoptedShellPermissions();
+ doAnswer(inv -> sAdoptedPermissions).when(mock).getAdoptedShellPermissions();
return mock;
}
diff --git a/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodSystemServer.java b/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodSystemServer.java
index 438a2bf..3346635 100644
--- a/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodSystemServer.java
+++ b/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodSystemServer.java
@@ -33,7 +33,7 @@
import com.android.server.compat.PlatformCompatNative;
import com.android.server.utils.TimingsTraceAndSlog;
-import java.util.List;
+import java.util.Collection;
import java.util.Set;
public class RavenwoodSystemServer {
@@ -68,27 +68,24 @@
private static TimingsTraceAndSlog sTimings;
private static SystemServiceManager sServiceManager;
- public static void init(RavenwoodConfig config) {
+ public static void init(Context systemServerContext) {
// Always start PlatformCompat, regardless of the requested services.
// PlatformCompat is not really a SystemService, so it won't receive boot phases / etc.
// This initialization code is copied from SystemServer.java.
- PlatformCompat platformCompat = new PlatformCompat(config.mState.mSystemServerContext);
+ PlatformCompat platformCompat = new PlatformCompat(systemServerContext);
ServiceManager.addService(Context.PLATFORM_COMPAT_SERVICE, platformCompat);
ServiceManager.addService(Context.PLATFORM_COMPAT_NATIVE_SERVICE,
new PlatformCompatNative(platformCompat));
- // Avoid overhead if no services required
- if (config.mServicesRequired.isEmpty()) return;
-
sStartedServices = new ArraySet<>();
sTimings = new TimingsTraceAndSlog();
- sServiceManager = new SystemServiceManager(config.mState.mSystemServerContext);
+ sServiceManager = new SystemServiceManager(systemServerContext);
sServiceManager.setStartInfo(false,
SystemClock.elapsedRealtime(),
SystemClock.uptimeMillis());
LocalServices.addService(SystemServiceManager.class, sServiceManager);
- startServices(config.mServicesRequired);
+ startServices(sKnownServices.keySet());
sServiceManager.sealStartedServices();
// TODO: expand to include additional boot phases when relevant
@@ -96,7 +93,7 @@
sServiceManager.startBootPhase(sTimings, SystemService.PHASE_BOOT_COMPLETED);
}
- public static void reset(RavenwoodConfig config) {
+ public static void reset() {
// TODO: consider introducing shutdown boot phases
LocalServices.removeServiceForTest(SystemServiceManager.class);
@@ -105,7 +102,7 @@
sStartedServices = null;
}
- private static void startServices(List<Class<?>> serviceClasses) {
+ private static void startServices(Collection<Class<?>> serviceClasses) {
for (Class<?> serviceClass : serviceClasses) {
// Quietly ignore duplicate requests if service already started
if (sStartedServices.contains(serviceClass)) continue;
diff --git a/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodConfig.java b/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodConfig.java
index 7ca9239..3ed0f50 100644
--- a/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodConfig.java
+++ b/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodConfig.java
@@ -15,21 +15,13 @@
*/
package android.platform.test.ravenwood;
-import static android.os.Process.FIRST_APPLICATION_UID;
-import static android.os.UserHandle.SYSTEM;
-
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.app.Instrumentation;
-import android.content.Context;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.concurrent.atomic.AtomicInteger;
/**
* @deprecated This class will be removed. Reach out to g/ravenwood if you need any features in it.
@@ -45,37 +37,10 @@
public @interface Config {
}
- private static final int NOBODY_UID = 9999;
-
- private static final AtomicInteger sNextPid = new AtomicInteger(100);
-
- int mCurrentUser = SYSTEM.getIdentifier();
-
- /**
- * Unless the test author requests differently, run as "nobody", and give each collection of
- * tests its own unique PID.
- */
- int mUid = FIRST_APPLICATION_UID;
- int mPid = sNextPid.getAndIncrement();
-
- String mTestPackageName;
- String mTargetPackageName;
-
- int mTargetSdkLevel;
-
- final RavenwoodSystemProperties mSystemProperties = new RavenwoodSystemProperties();
-
- final List<Class<?>> mServicesRequired = new ArrayList<>();
-
- volatile Context mInstContext;
- volatile Context mTargetContext;
- volatile Instrumentation mInstrumentation;
-
/**
* Stores internal states / methods associated with this config that's only needed in
* junit-impl.
*/
- final RavenwoodConfigState mState = new RavenwoodConfigState(this);
private RavenwoodConfig() {
}
@@ -159,34 +124,11 @@
return this;
}
- Builder setSystemPropertyImmutableReal(@NonNull String key,
- @Nullable Object value) {
- mConfig.mSystemProperties.setValue(key, value);
- mConfig.mSystemProperties.setAccessReadOnly(key);
- return this;
- }
-
- Builder setSystemPropertyMutableReal(@NonNull String key,
- @Nullable Object value) {
- mConfig.mSystemProperties.setValue(key, value);
- mConfig.mSystemProperties.setAccessReadWrite(key);
- return this;
- }
-
/**
- * Configure the set of system services that are required for this test to operate.
- *
- * For example, passing {@code android.hardware.SerialManager.class} as an argument will
- * ensure that the underlying service is created, initialized, and ready to use for the
- * duration of the test. The {@code SerialManager} instance can be obtained via
- * {@code RavenwoodRule.getContext()} and {@code Context.getSystemService()}, and
- * {@code SerialManagerInternal} can be obtained via {@code LocalServices.getService()}.
+ * @deprecated no longer used. All supported services are available.
*/
+ @Deprecated
public Builder setServicesRequired(@NonNull Class<?>... services) {
- mConfig.mServicesRequired.clear();
- for (Class<?> service : services) {
- mConfig.mServicesRequired.add(service);
- }
return this;
}
diff --git a/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodRule.java b/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodRule.java
index 5681a90..6262ad1 100644
--- a/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodRule.java
+++ b/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodRule.java
@@ -92,19 +92,11 @@
}
}
- private final RavenwoodConfig mConfiguration;
-
- public RavenwoodRule() {
- mConfiguration = new RavenwoodConfig.Builder().build();
- }
-
- private RavenwoodRule(RavenwoodConfig config) {
- mConfiguration = config;
- }
+ final RavenwoodSystemProperties mSystemProperties = new RavenwoodSystemProperties();
public static class Builder {
- private final RavenwoodConfig.Builder mBuilder =
- new RavenwoodConfig.Builder();
+
+ private final RavenwoodRule mRule = new RavenwoodRule();
public Builder() {
}
@@ -152,7 +144,8 @@
* Has no effect on non-Ravenwood environments.
*/
public Builder setSystemPropertyImmutable(@NonNull String key, @Nullable Object value) {
- mBuilder.setSystemPropertyImmutableReal(key, value);
+ mRule.mSystemProperties.setValue(key, value);
+ mRule.mSystemProperties.setAccessReadOnly(key);
return this;
}
@@ -167,26 +160,21 @@
* Has no effect on non-Ravenwood environments.
*/
public Builder setSystemPropertyMutable(@NonNull String key, @Nullable Object value) {
- mBuilder.setSystemPropertyMutableReal(key, value);
+ mRule.mSystemProperties.setValue(key, value);
+ mRule.mSystemProperties.setAccessReadWrite(key);
return this;
}
/**
- * Configure the set of system services that are required for this test to operate.
- *
- * For example, passing {@code android.hardware.SerialManager.class} as an argument will
- * ensure that the underlying service is created, initialized, and ready to use for the
- * duration of the test. The {@code SerialManager} instance can be obtained via
- * {@code RavenwoodRule.getContext()} and {@code Context.getSystemService()}, and
- * {@code SerialManagerInternal} can be obtained via {@code LocalServices.getService()}.
+ * @deprecated no longer used. All supported services are available.
*/
+ @Deprecated
public Builder setServicesRequired(@NonNull Class<?>... services) {
- mBuilder.setServicesRequired(services);
return this;
}
public RavenwoodRule build() {
- return new RavenwoodRule(mBuilder.build());
+ return mRule;
}
}
@@ -227,7 +215,7 @@
@Override
public Statement apply(Statement base, Description description) {
- if (!RavenwoodConfig.isOnRavenwood()) {
+ if (!IS_ON_RAVENWOOD) {
return base;
}
return new Statement() {
@@ -296,8 +284,4 @@
public static RavenwoodPrivate private$ravenwood() {
return sRavenwoodPrivate;
}
-
- RavenwoodConfig getConfiguration() {
- return mConfiguration;
- }
}
diff --git a/ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodConfigState.java b/ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodConfigState.java
deleted file mode 100644
index 7d3d8b9..0000000
--- a/ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodConfigState.java
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * Copyright (C) 2024 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.platform.test.ravenwood;
-
-/** Stub class. The actual implementation is in junit-impl-src. */
-public class RavenwoodConfigState {
- public RavenwoodConfigState(RavenwoodConfig config) {
- }
-}