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

Commit 0245dd29 authored by Makoto Onuki's avatar Makoto Onuki
Browse files

Now RavenwoodEnvironment initializes resources

Bug: 292141694
Flag: TEST_ONLY
Test: $ANDROID_BUILD_TOP/frameworks/base/ravenwood/scripts/run-ravenwood-tests.sh -s
Change-Id: I9b45c47ba81a0cb4a6d2fc59f7c9ba6ee2b769a2
parent 0d483c9e
Loading
Loading
Loading
Loading
+0 −7
Original line number Diff line number Diff line
@@ -53,13 +53,6 @@ public class RavenwoodInternalUtils {

    public static final String RAVENWOOD_SYSPROP = "ro.is_on_ravenwood";

    public static final String RAVENWOOD_RESOURCE_APK = "ravenwood-res-apks/ravenwood-res.apk";
    public static final String RAVENWOOD_INST_RESOURCE_APK =
            "ravenwood-res-apks/ravenwood-inst-res.apk";

    public static final String RAVENWOOD_EMPTY_RESOURCES_APK =
            "ravenwood-data/ravenwood-empty-res.apk";

    /**
     * @return if we're running on Ravenwood.
     */
+4 −14
Original line number Diff line number Diff line
@@ -16,8 +16,6 @@

package android.platform.test.ravenwood;

import static com.android.ravenwood.common.RavenwoodInternalUtils.RAVENWOOD_RESOURCE_APK;

import android.app.Application;
import android.content.ClipboardManager;
import android.content.Context;
@@ -63,8 +61,6 @@ public class RavenwoodContext extends RavenwoodBaseContext {
    private final ArrayMap<Class<?>, String> mClassToName = new ArrayMap<>();
    private final ArrayMap<String, Supplier<?>> mNameToFactory = new ArrayMap<>();

    private final Supplier<Resources> mResourcesSupplier;

    private Application mAppContext;

    @GuardedBy("mLock")
@@ -82,11 +78,9 @@ public class RavenwoodContext extends RavenwoodBaseContext {
        mNameToFactory.put(serviceName, serviceSupplier);
    }

    public RavenwoodContext(String packageName, HandlerThread mainThread,
            Supplier<Resources> resourcesSupplier) throws IOException {
    public RavenwoodContext(String packageName, HandlerThread mainThread) throws IOException {
        mPackageName = packageName;
        mMainThread = mainThread;
        mResourcesSupplier = resourcesSupplier;

        // Services provided by a typical shipping device
        registerService(ClipboardManager.class,
@@ -266,12 +260,7 @@ public class RavenwoodContext extends RavenwoodBaseContext {

    @Override
    public Resources getResources() {
        synchronized (mLock) {
            if (mResources == null) {
                mResources = mResourcesSupplier.get();
            }
            return mResources;
        }
        return RavenwoodEnvironment.getInstance().loadResources(getPackageName());
    }

    @Override
@@ -298,7 +287,8 @@ public class RavenwoodContext extends RavenwoodBaseContext {

    @Override
    public String getPackageResourcePath() {
        return new File(RAVENWOOD_RESOURCE_APK).getAbsolutePath();
        return RavenwoodEnvironment.getInstance()
                .getResourcesApkFile(this.getPackageName()).getAbsolutePath();
    }

    final void attachApplicationContext(Application appContext) {
+3 −63
Original line number Diff line number Diff line
@@ -21,16 +21,11 @@ import static android.os.UserHandle.SYSTEM;

import static com.android.modules.utils.ravenwood.RavenwoodHelper.RavenwoodInternal.RAVENWOOD_RUNTIME_PATH_JAVA_SYSPROP;
import static com.android.ravenwood.common.RavenwoodInternalUtils.ANDROID_PACKAGE_NAME;
import static com.android.ravenwood.common.RavenwoodInternalUtils.RAVENWOOD_EMPTY_RESOURCES_APK;
import static com.android.ravenwood.common.RavenwoodInternalUtils.RAVENWOOD_INST_RESOURCE_APK;
import static com.android.ravenwood.common.RavenwoodInternalUtils.RAVENWOOD_RESOURCE_APK;
import static com.android.ravenwood.common.RavenwoodInternalUtils.getRavenwoodRuntimePath;
import static com.android.ravenwood.common.RavenwoodInternalUtils.parseNullableInt;
import static com.android.ravenwood.common.RavenwoodInternalUtils.withDefault;

import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertThrows;
import static org.junit.Assert.assertTrue;

import android.annotation.Nullable;
import android.app.ActivityManager;
@@ -40,7 +35,6 @@ import android.app.Application;
import android.app.Application_ravenwood;
import android.app.IUiAutomationConnection;
import android.app.Instrumentation;
import android.app.ResourcesManager;
import android.app.UiAutomation;
import android.app.UiAutomation_ravenwood;
import android.content.Context;
@@ -65,7 +59,6 @@ import android.system.ErrnoException;
import android.system.Os;
import android.util.Log;
import android.util.Log_ravenwood;
import android.view.DisplayAdjustments;

import androidx.test.platform.app.InstrumentationRegistry;

@@ -94,7 +87,6 @@ import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Supplier;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

@@ -357,29 +349,10 @@ public class RavenwoodDriver {

        final boolean isSelfInstrumenting = env.isSelfInstrumenting();

        // 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);
            };
        }

        sInstContext = new RavenwoodContext(
                env.getInstPackageName(), env.getMainThread(), instResourcesLoader);
                env.getInstPackageName(), env.getMainThread());
        sTargetContext = new RavenwoodContext(
                env.getTargetPackageName(), env.getMainThread(), targetResourcesLoader);
                env.getTargetPackageName(), env.getMainThread());

        // Set up app context. App context is always created for the target app.
        var application = new Application();
@@ -398,10 +371,8 @@ public class RavenwoodDriver {
        // the difference doesn't matter at least for now, so we just use the target context.
        ActivityThread_ravenwood.init(application, sTargetContext);

        final Supplier<Resources> systemResourcesLoader = () -> loadResources(null);

        var systemServerContext = new RavenwoodContext(
                ANDROID_PACKAGE_NAME, env.getMainThread(), systemResourcesLoader);
                ANDROID_PACKAGE_NAME, env.getMainThread());

        var uiAutomation = new UiAutomation(sInstContext, new IUiAutomationConnection.Default());

@@ -557,37 +528,6 @@ public class RavenwoodDriver {
        AppCompatCallbacks.install(disabledChanges, loggableChanges, false);
    }

    /**
     * Load {@link Resources} from an APK, with cache.
     */
    private static Resources loadResources(@Nullable File apkPath) {
        var cached = sCachedResources.get(apkPath);
        if (cached != null) {
            return cached;
        }

        var fileToLoad = apkPath != null ? apkPath :
                new File(getRavenwoodRuntimePath() + 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(),
                RavenwoodDriver.class.getClassLoader(), null);

        assertNotNull(ret);

        sCachedResources.put(apkPath, ret);
        return ret;
    }

    /**
     * Return if an exception is benign and okay to continue running the remaining tests.
     */
+80 −4
Original line number Diff line number Diff line
@@ -15,13 +15,19 @@
 */
package android.platform.test.ravenwood;

import static org.junit.Assert.assertNotNull;

import android.annotation.NonNull;
import android.app.ResourcesManager;
import android.content.res.Resources;
import android.os.HandlerThread;
import android.os.Looper;
import android.util.Log;
import android.view.DisplayAdjustments;

import com.android.internal.annotations.GuardedBy;
import com.android.ravenwood.RavenwoodVmState;
import com.android.ravenwood.common.RavenwoodInternalUtils;

import java.io.File;
import java.io.IOException;
@@ -35,10 +41,6 @@ import java.util.concurrent.atomic.AtomicReference;
 * A singleton class that prepares and manages various app/process lifecycle related states.
 *
 * It's also responsible for initializing {@link RavenwoodVmState}.
 *
 * TODO: Move more of app/process lifecycle related initialization to this class. For example,
 * resource loading should probably move here, and have Context use it to get resources, just like
 * how we handle the app data directories.
 */
public class RavenwoodEnvironment {
    public static final String TAG = "RavenwoodEnvironment";
@@ -52,6 +54,15 @@ public class RavenwoodEnvironment {
        return Objects.requireNonNull(sInstance.get(), "Instance not set!");
    }

    private static final File RAVENWOOD_TARGET_RESOURCE_APK =
            new File("ravenwood-res-apks/ravenwood-res.apk");
    private static final File RAVENWOOD_INST_RESOURCE_APK =
            new File("ravenwood-res-apks/ravenwood-inst-res.apk");

    private static final File RAVENWOOD_EMPTY_RESOURCES_APK =
            new File(RavenwoodInternalUtils.getRavenwoodRuntimePath(),
                    "/ravenwood-data/ravenwood-empty-res.apk");

    private final Object mLock = new Object();

    private final int mUid;
@@ -79,6 +90,9 @@ public class RavenwoodEnvironment {
    @GuardedBy("mLock")
    private final Map<String, File> mAppDataDirs = new HashMap<>();

    @GuardedBy("mLock")
    private final Map<String, Resources> mPackagesToResources = new HashMap<>();

    public RavenwoodEnvironment(
            int uid,
            int pid,
@@ -221,4 +235,66 @@ public class RavenwoodEnvironment {
            return dir;
        }
    }

    /**
     * Get the resources for a given package's resources.
     *
     * @param packageName package name, or "android" to load the system resources.
     */
    public Resources loadResources(@NonNull String packageName) {
        synchronized (mLock) {
            final var cached = mPackagesToResources.get(packageName);
            if (cached != null) {
                return cached;
            }
            final var loaded = loadResourcesInnerLocked(packageName);
            mPackagesToResources.put(packageName, loaded);
            return loaded;
        }
    }

    @GuardedBy("mLock")
    private Resources loadResourcesInnerLocked(@NonNull String packageName) {
        final var apk = getResourcesApkFile(packageName);
        final var emptyPaths = new String[0];

        ResourcesManager.getInstance().initializeApplicationPaths(
                apk.getAbsolutePath(), emptyPaths);

        final var ret = ResourcesManager.getInstance().getResources(null, apk.getAbsolutePath(),
                emptyPaths, emptyPaths, emptyPaths,
                emptyPaths, null, null,
                new DisplayAdjustments().getCompatibilityInfo(),
                RavenwoodDriver.class.getClassLoader(), null);

        assertNotNull(ret);
        return ret;
    }

    /**
     * Get the resource APK file for a given package's resources.
     * @param packageName package name, or "android" to load the system resources.
     */
    public File getResourcesApkFile(@NonNull String packageName) {
        if (packageName.equals(getTargetPackageName())) {
            if (RAVENWOOD_TARGET_RESOURCE_APK.exists()) {
                return RAVENWOOD_TARGET_RESOURCE_APK;
            }
            // fall-through and use the default resources.

        } else if (packageName.equals(getInstPackageName())) {
            if (RAVENWOOD_INST_RESOURCE_APK.exists()) {
                return RAVENWOOD_INST_RESOURCE_APK;
            }
            // fall-through and use the default resources.


        } else if (packageName.equals(RavenwoodInternalUtils.ANDROID_PACKAGE_NAME)) {
            // fall-through and use the default resources.

        } else {
            throw new RuntimeException("Unknown package name: " + packageName);
        }
        return RAVENWOOD_EMPTY_RESOURCES_APK;
    }
}