Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 55cb426b authored by Makoto Onuki's avatar Makoto Onuki
Browse files

Support test / target context, app context

- Instrumentation.getContext() and getTargetContext() now returns
different context objects to simulate the real behavior.

- Now RavenwoodConfig allows to set "target app package name".

- Make sure the resources apk is connected to the correct context.

- Unsupported behavior:
On the real device, tests can access resouces of both the target APK
and the test APK, but Ravenwood currently only supports resouces from
the target APK. But this resources is available on the test context as
well, if the test package name and the target package name are the same.
(which is the default behavior)

- Also made some internal clean up -- now RavenwoodRunnerState is
just a member of RavenwoodAwareTestRunner. We put a stub class
in junit-stub-src.

Flag: EXEMPT host test change only
Bug: 292141694
Test: $ANDROID_BUILD_TOP/frameworks/base/ravenwood/scripts/run-ravenwood-tests.sh

Change-Id: I3bffb04b227730f21c757f356ae0820cc85963ab
parent 686b26fe
Loading
Loading
Loading
Loading
+3 −3
Original line number Diff line number Diff line
@@ -2408,9 +2408,9 @@ public class Instrumentation {
     * @hide
     */
    @android.ravenwood.annotation.RavenwoodKeep
    public final void basicInit(Context context) {
        mInstrContext = context;
        mAppContext = context;
    public final void basicInit(Context instrContext, Context appContext) {
        mInstrContext = instrContext;
        mAppContext = appContext;
    }

    /** @hide */
+11 −0
Original line number Diff line number Diff line
@@ -7,6 +7,9 @@
    { "name": "RavenwoodMockitoTest_device" },
    { "name": "RavenwoodBivalentTest_device" },

    { "name": "RavenwoodBivalentInstTest_nonself_inst" },
    { "name": "RavenwoodBivalentInstTest_self_inst_device" },

    // The sysui tests should match vendor/unbundled_google/packages/SystemUIGoogle/TEST_MAPPING
    {
      "name": "SystemUIGoogleTests",
@@ -137,6 +140,14 @@
      "name": "PowerStatsTestsRavenwood",
      "host": true
    },
    {
      "name": "RavenwoodBivalentInstTest_nonself_inst",
      "host": true
    },
    {
      "name": "RavenwoodBivalentInstTest_self_inst",
      "host": true
    },
    {
      "name": "RavenwoodBivalentTest",
      "host": true
+8 −8
Original line number Diff line number Diff line
@@ -100,7 +100,7 @@ public class RavenwoodAwareTestRunnerHook {
        Log.v(TAG, "onBeforeInnerRunnerStart: description=" + description);

        // Prepare the environment before the inner runner starts.
        RavenwoodRunnerState.forRunner(runner).enterTestClass(description);
        runner.mState.enterTestClass(description);
    }

    /**
@@ -111,7 +111,7 @@ public class RavenwoodAwareTestRunnerHook {
        Log.v(TAG, "onAfterInnerRunnerFinished: description=" + description);

        RavenwoodTestStats.getInstance().onClassFinished(description);
        RavenwoodRunnerState.forRunner(runner).exitTestClass();
        runner.mState.exitTestClass();
    }

    /**
@@ -125,10 +125,10 @@ public class RavenwoodAwareTestRunnerHook {

        if (scope == Scope.Instance && order == Order.Outer) {
            // Start of a test method.
            RavenwoodRunnerState.forRunner(runner).enterTestMethod(description);
            runner.mState.enterTestMethod(description);
        }

        final var classDescription = RavenwoodRunnerState.forRunner(runner).getClassDescription();
        final var classDescription = runner.mState.getClassDescription();

        // Class-level annotations are checked by the runner already, so we only check
        // method-level annotations here.
@@ -152,11 +152,11 @@ public class RavenwoodAwareTestRunnerHook {
            Scope scope, Order order, Throwable th) {
        Log.v(TAG, "onAfter: description=" + description + ", " + scope + ", " + order + ", " + th);

        final var classDescription = RavenwoodRunnerState.forRunner(runner).getClassDescription();
        final var classDescription = runner.mState.getClassDescription();

        if (scope == Scope.Instance && order == Order.Outer) {
            // End of a test method.
            RavenwoodRunnerState.forRunner(runner).exitTestMethod();
            runner.mState.exitTestMethod();
            RavenwoodTestStats.getInstance().onTestFinished(classDescription, description,
                    th == null ? Result.Passed : Result.Failed);
        }
@@ -206,7 +206,7 @@ public class RavenwoodAwareTestRunnerHook {
            Description description, RavenwoodRule rule) throws Throwable {
        Log.v(TAG, "onRavenwoodRuleEnter: description=" + description);

        RavenwoodRunnerState.forRunner(runner).enterRavenwoodRule(rule);
        runner.mState.enterRavenwoodRule(rule);
    }


@@ -217,6 +217,6 @@ public class RavenwoodAwareTestRunnerHook {
            Description description, RavenwoodRule rule) throws Throwable {
        Log.v(TAG, "onRavenwoodRuleExit: description=" + description);

        RavenwoodRunnerState.forRunner(runner).exitRavenwoodRule(rule);
        runner.mState.exitRavenwoodRule(rule);
    }
}
 No newline at end of file
+81 −0
Original line number Diff line number Diff line
/*
 * 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;

    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;
    }
}
+19 −7
Original line number Diff line number Diff line
@@ -60,6 +60,8 @@ public class RavenwoodContext extends RavenwoodBaseContext {
    private final File mCacheDir;
    private final Supplier<Resources> mResourcesSupplier;

    private RavenwoodContext mAppContext;

    @GuardedBy("mLock")
    private Resources mResources;

@@ -77,8 +79,8 @@ public class RavenwoodContext extends RavenwoodBaseContext {
        mPackageName = packageName;
        mMainThread = mainThread;
        mResourcesSupplier = resourcesSupplier;
        mFilesDir = createTempDir("files-dir");
        mCacheDir = createTempDir("cache-dir");
        mFilesDir = createTempDir(packageName + "_files-dir");
        mCacheDir = createTempDir(packageName + "_cache-dir");

        // Services provided by a typical shipping device
        registerService(ClipboardManager.class,
@@ -131,34 +133,35 @@ public class RavenwoodContext extends RavenwoodBaseContext {
    @Override
    public Looper getMainLooper() {
        Objects.requireNonNull(mMainThread,
                "Test must request setProvideMainThread() via RavenwoodRule");
                "Test must request setProvideMainThread() via RavenwoodConfig");
        return mMainThread.getLooper();
    }

    @Override
    public Handler getMainThreadHandler() {
        Objects.requireNonNull(mMainThread,
                "Test must request setProvideMainThread() via RavenwoodRule");
                "Test must request setProvideMainThread() via RavenwoodConfig");
        return mMainThread.getThreadHandler();
    }

    @Override
    public Executor getMainExecutor() {
        Objects.requireNonNull(mMainThread,
                "Test must request setProvideMainThread() via RavenwoodRule");
                "Test must request setProvideMainThread() via RavenwoodConfig");
        return mMainThread.getThreadExecutor();
    }

    @Override
    public String getPackageName() {
        return Objects.requireNonNull(mPackageName,
                "Test must request setPackageName() via RavenwoodRule");
                "Test must request setPackageName() (or setTargetPackageName())"
                + " via RavenwoodConfig");
    }

    @Override
    public String getOpPackageName() {
        return Objects.requireNonNull(mPackageName,
                "Test must request setPackageName() via RavenwoodRule");
                "Test must request setPackageName() via RavenwoodConfig");
    }

    @Override
@@ -227,6 +230,15 @@ public class RavenwoodContext extends RavenwoodBaseContext {
        return new File(RAVENWOOD_RESOURCE_APK).getAbsolutePath();
    }

    public void setApplicationContext(RavenwoodContext appContext) {
        mAppContext = appContext;
    }

    @Override
    public Context getApplicationContext() {
        return mAppContext;
    }

    /**
     * Wrap the given {@link Supplier} to become memoized.
     *
Loading