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

Commit 107114d1 authored by Makoto Onuki's avatar Makoto Onuki Committed by Android (Google) Code Review
Browse files

Merge "Now RavenwoodEnvironment initializes resources" into main

parents 4c3118b3 0245dd29
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;
    }
}