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

Commit fbbfb0c2 authored by Makoto Onuki's avatar Makoto Onuki
Browse files

Support Environment APIs

Bug: 362475922
Flag: TEST_ONLY
Test: $ANDROID_BUILD_TOP/frameworks/base/ravenwood/scripts/run-ravenwood-tests.sh -s
Change-Id: I810731e51ba05a5c2efde0a7e968b6f4d23cbce1
parent 6b368988
Loading
Loading
Loading
Loading
+123 −51
Original line number Diff line number Diff line
@@ -36,6 +36,10 @@ import android.content.pm.PackageManager;
import android.os.storage.StorageManager;
import android.os.storage.StorageVolume;
import android.provider.MediaStore;
import android.ravenwood.annotation.RavenwoodKeepWholeClass;
import android.ravenwood.annotation.RavenwoodRedirect;
import android.ravenwood.annotation.RavenwoodRedirectionClass;
import android.ravenwood.annotation.RavenwoodThrow;
import android.text.TextUtils;
import android.util.Log;

@@ -51,6 +55,8 @@ import java.util.UUID;
/**
 * Provides access to environment variables.
 */
@RavenwoodKeepWholeClass
@RavenwoodRedirectionClass("Environment_ravenwood")
public class Environment {
    private static final String TAG = "Environment";

@@ -99,11 +105,11 @@ public class Environment {

    private static final File DIR_ANDROID_ROOT = getDirectory(ENV_ANDROID_ROOT, "/system");
    private static final String DIR_ANDROID_DATA_PATH = getDirectoryPath(ENV_ANDROID_DATA, "/data");
    private static final File DIR_ANDROID_DATA = new File(DIR_ANDROID_DATA_PATH);
    private static final File DIR_ANDROID_DATA = newFilePrep(DIR_ANDROID_DATA_PATH);
    private static final File DIR_ANDROID_EXPAND = getDirectory(ENV_ANDROID_EXPAND, "/mnt/expand");
    private static final File DIR_ANDROID_STORAGE = getDirectory(ENV_ANDROID_STORAGE, "/storage");
    private static final File DIR_DOWNLOAD_CACHE = getDirectory(ENV_DOWNLOAD_CACHE, "/cache");
    private static final File DIR_METADATA = new File("/metadata");
    private static final File DIR_METADATA = newFilePrep("/metadata");
    private static final File DIR_OEM_ROOT = getDirectory(ENV_OEM_ROOT, "/oem");
    private static final File DIR_ODM_ROOT = getDirectory(ENV_ODM_ROOT, "/odm");
    private static final File DIR_VENDOR_ROOT = getDirectory(ENV_VENDOR_ROOT, "/vendor");
@@ -162,6 +168,51 @@ public class Environment {
    private static Boolean sLegacyStorageAppOp;
    private static Boolean sNoIsolatedStorageAppOp;

    /**
     * On a real device, it's a no-op, but on ravenwood, it'll remap the path such that
     * it'll work on the Ravenwood environment, and also create the directory.
     *
     * We use it on Ravenwood because Ravenwood has no "installd" or anything that'd create the
     * directories for us. OTOH, we can't just create the directories on the device side
     * because we need to set the correct owners/permissions on them, which we can't do here.
     */
    @RavenwoodRedirect
    private static File prep(File dir) {
        return dir;
    }

    /** Same as {@link #prep(File)} */
    @RavenwoodRedirect
    private static String prep(String dir) {
        return dir;
    }

    /**
     * Same as prep(new File(...)).
     * Must only be used when the path is known to be a directory, not file.
     */
    private static File newFilePrep(String path) {
        return prep(new File(path));
    }

    /** See {@link #newFilePrep(String)} */
    private static File newFilePrep(String path, String subdir) {
        return prep(new File(path, subdir));
    }

    /** See {@link #newFilePrep(String)} */
    private static File newFilePrep(File path, String subdir) {
        return prep(new File(path, subdir));
    }

    /**
     * On a real device, it's just {@link System#getenv()}, but on Ravenwood, we use a java prop.
     */
    @RavenwoodRedirect(comment = "Use java props on Ravenwood")
    private static String getEnvPath(String variableName) {
        return System.getenv(variableName);
    }

    static {
        initForCurrentUser();
    }
@@ -346,7 +397,7 @@ public class Environment {
     */
    @Deprecated
    public static File getUserSystemDirectory(int userId) {
        return new File(new File(getDataSystemDirectory(), "users"), Integer.toString(userId));
        return newFilePrep(new File(getDataSystemDirectory(), "users"), Integer.toString(userId));
    }

    /**
@@ -363,7 +414,7 @@ public class Environment {
     */
    @Deprecated
    public static File getUserConfigDirectory(int userId) {
        return new File(new File(new File(
        return newFilePrep(new File(new File(
                getDataDirectory(), "misc"), "user"), Integer.toString(userId));
    }

@@ -387,7 +438,7 @@ public class Environment {
        if (TextUtils.isEmpty(volumeUuid)) {
            return DIR_ANDROID_DATA;
        } else {
            return new File("/mnt/expand/" + volumeUuid);
            return newFilePrep("/mnt/expand/" + volumeUuid);
        }
    }

@@ -396,7 +447,7 @@ public class Environment {
        if (TextUtils.isEmpty(volumeUuid)) {
            return DIR_ANDROID_DATA_PATH;
        } else {
            return getExpandDirectory().getAbsolutePath() + File.separator + volumeUuid;
            return prep(getExpandDirectory().getAbsolutePath() + File.separator + volumeUuid);
        }
    }

@@ -408,7 +459,7 @@ public class Environment {
    /** {@hide} */
    @UnsupportedAppUsage
    public static File getDataSystemDirectory() {
        return new File(getDataDirectory(), "system");
        return newFilePrep(getDataDirectory(), "system");
    }

    /**
@@ -418,7 +469,7 @@ public class Environment {
    @SystemApi
    @FlaggedApi(android.crashrecovery.flags.Flags.FLAG_ENABLE_CRASHRECOVERY)
    public static @NonNull File getDataSystemDeviceProtectedDirectory() {
        return buildPath(getDataDirectory(), "system_de");
        return buildPathPrep(getDataDirectory(), "system_de");
    }

    /** Use {@link #getDataSystemDeviceProtectedDirectory()} instead.
@@ -426,7 +477,7 @@ public class Environment {
     */
    @Deprecated
    public static @NonNull File getDataSystemDeDirectory() {
        return buildPath(getDataDirectory(), "system_de");
        return buildPathPrep(getDataDirectory(), "system_de");
    }

    /**
@@ -434,7 +485,7 @@ public class Environment {
     * {@hide}
     */
    public static File getDataSystemCeDirectory() {
        return buildPath(getDataDirectory(), "system_ce");
        return buildPathPrep(getDataDirectory(), "system_ce");
    }

    /**
@@ -454,7 +505,7 @@ public class Environment {
     * @hide
     */
    public static File getDataSystemCeDirectory(int userId) {
        return buildPath(getDataDirectory(), "system_ce", String.valueOf(userId));
        return buildPathPrep(getDataDirectory(), "system_ce", String.valueOf(userId));
    }

    /**
@@ -474,95 +525,95 @@ public class Environment {
     * @hide
     */
    public static File getDataSystemDeDirectory(int userId) {
        return buildPath(getDataDirectory(), "system_de", String.valueOf(userId));
        return buildPathPrep(getDataDirectory(), "system_de", String.valueOf(userId));
    }

    /** {@hide} */
    public static File getDataMiscDirectory() {
        return new File(getDataDirectory(), "misc");
        return newFilePrep(getDataDirectory(), "misc");
    }

    /** {@hide} */
    public static File getDataMiscCeDirectory() {
        return buildPath(getDataDirectory(), "misc_ce");
        return buildPathPrep(getDataDirectory(), "misc_ce");
    }

    /** {@hide} */
    public static File getDataMiscCeDirectory(int userId) {
        return buildPath(getDataDirectory(), "misc_ce", String.valueOf(userId));
        return buildPathPrep(getDataDirectory(), "misc_ce", String.valueOf(userId));
    }

    /** {@hide} */
    private static File getDataMiscCeDirectory(String volumeUuid, int userId) {
        return buildPath(getDataDirectory(volumeUuid), "misc_ce", String.valueOf(userId));
        return buildPathPrep(getDataDirectory(volumeUuid), "misc_ce", String.valueOf(userId));
    }

    /** {@hide} */
    public static File getDataMiscCeSharedSdkSandboxDirectory(String volumeUuid, int userId,
            String packageName) {
        return buildPath(getDataMiscCeDirectory(volumeUuid, userId), "sdksandbox",
        return buildPathPrep(getDataMiscCeDirectory(volumeUuid, userId), "sdksandbox",
                packageName, "shared");
    }

    /** {@hide} */
    public static File getDataMiscDeDirectory(int userId) {
        return buildPath(getDataDirectory(), "misc_de", String.valueOf(userId));
        return buildPathPrep(getDataDirectory(), "misc_de", String.valueOf(userId));
    }

    /** {@hide} */
    private static File getDataMiscDeDirectory(String volumeUuid, int userId) {
        return buildPath(getDataDirectory(volumeUuid), "misc_de", String.valueOf(userId));
        return buildPathPrep(getDataDirectory(volumeUuid), "misc_de", String.valueOf(userId));
    }

    /** {@hide} */
    public static File getDataMiscDeSharedSdkSandboxDirectory(String volumeUuid, int userId,
            String packageName) {
        return buildPath(getDataMiscDeDirectory(volumeUuid, userId), "sdksandbox",
        return buildPathPrep(getDataMiscDeDirectory(volumeUuid, userId), "sdksandbox",
                packageName, "shared");
    }

    private static File getDataProfilesDeDirectory(int userId) {
        return buildPath(getDataDirectory(), "misc", "profiles", "cur", String.valueOf(userId));
        return buildPathPrep(getDataDirectory(), "misc", "profiles", "cur", String.valueOf(userId));
    }

    /** {@hide} */
    public static File getDataVendorCeDirectory(int userId) {
        return buildPath(getDataDirectory(), "vendor_ce", String.valueOf(userId));
        return buildPathPrep(getDataDirectory(), "vendor_ce", String.valueOf(userId));
    }

    /** {@hide} */
    public static File getDataVendorDeDirectory(int userId) {
        return buildPath(getDataDirectory(), "vendor_de", String.valueOf(userId));
        return buildPathPrep(getDataDirectory(), "vendor_de", String.valueOf(userId));
    }

    /** {@hide} */
    public static File getDataRefProfilesDePackageDirectory(String packageName) {
        return buildPath(getDataDirectory(), "misc", "profiles", "ref", packageName);
        return buildPathPrep(getDataDirectory(), "misc", "profiles", "ref", packageName);
    }

    /** {@hide} */
    public static File getDataProfilesDePackageDirectory(int userId, String packageName) {
        return buildPath(getDataProfilesDeDirectory(userId), packageName);
        return buildPathPrep(getDataProfilesDeDirectory(userId), packageName);
    }

    /** {@hide} */
    public static File getDataAppDirectory(String volumeUuid) {
        return new File(getDataDirectory(volumeUuid), "app");
        return newFilePrep(getDataDirectory(volumeUuid), "app");
    }

    /** {@hide} */
    public static File getDataStagingDirectory(String volumeUuid) {
        return new File(getDataDirectory(volumeUuid), "app-staging");
        return newFilePrep(getDataDirectory(volumeUuid), "app-staging");
    }

    /** {@hide} */
    public static File getDataUserCeDirectory(String volumeUuid) {
        return new File(getDataDirectory(volumeUuid), DIR_USER_CE);
        return newFilePrep(getDataDirectory(volumeUuid), DIR_USER_CE);
    }

    /** {@hide} */
    public static File getDataUserCeDirectory(String volumeUuid, int userId) {
        return new File(getDataUserCeDirectory(volumeUuid), String.valueOf(userId));
        return newFilePrep(getDataUserCeDirectory(volumeUuid), String.valueOf(userId));
    }

    /** {@hide} */
@@ -570,7 +621,7 @@ public class Environment {
    public static File getDataUserCePackageDirectory(@Nullable String volumeUuid, int userId,
            @NonNull String packageName) {
        // TODO: keep consistent with installd
        return new File(getDataUserCeDirectory(volumeUuid, userId), packageName);
        return newFilePrep(getDataUserCeDirectory(volumeUuid, userId), packageName);
    }

    /**
@@ -599,12 +650,12 @@ public class Environment {

    /** {@hide} */
    public static File getDataUserDeDirectory(String volumeUuid) {
        return new File(getDataDirectory(volumeUuid), DIR_USER_DE);
        return newFilePrep(getDataDirectory(volumeUuid), DIR_USER_DE);
    }

    /** {@hide} */
    public static File getDataUserDeDirectory(String volumeUuid, int userId) {
        return new File(getDataUserDeDirectory(volumeUuid), String.valueOf(userId));
        return newFilePrep(getDataUserDeDirectory(volumeUuid), String.valueOf(userId));
    }

    /** {@hide} */
@@ -612,7 +663,7 @@ public class Environment {
    public static File getDataUserDePackageDirectory(@Nullable String volumeUuid, int userId,
            @NonNull String packageName) {
        // TODO: keep consistent with installd
        return new File(getDataUserDeDirectory(volumeUuid, userId), packageName);
        return newFilePrep(getDataUserDeDirectory(volumeUuid, userId), packageName);
    }

    /**
@@ -647,7 +698,7 @@ public class Environment {
     * {@hide}
     */
    public static File getDataPreloadsDirectory() {
        return new File(getDataDirectory(), "preloads");
        return newFilePrep(getDataDirectory(), "preloads");
    }

    /**
@@ -655,7 +706,7 @@ public class Environment {
     * {@hide}
     */
    public static File getDataPreloadsDemoDirectory() {
        return new File(getDataPreloadsDirectory(), "demo");
        return newFilePrep(getDataPreloadsDirectory(), "demo");
    }

    /**
@@ -663,7 +714,7 @@ public class Environment {
     * {@hide}
     */
    public static File getDataPreloadsAppsDirectory() {
        return new File(getDataPreloadsDirectory(), "apps");
        return newFilePrep(getDataPreloadsDirectory(), "apps");
    }

    /**
@@ -671,7 +722,7 @@ public class Environment {
     * {@hide}
     */
    public static File getDataPreloadsMediaDirectory() {
        return new File(getDataPreloadsDirectory(), "media");
        return newFilePrep(getDataPreloadsDirectory(), "media");
    }

    /**
@@ -680,7 +731,7 @@ public class Environment {
     * {@hide}
     */
    public static File getDataPreloadsFileCacheDirectory(String packageName) {
        return new File(getDataPreloadsFileCacheDirectory(), packageName);
        return newFilePrep(getDataPreloadsFileCacheDirectory(), packageName);
    }

    /**
@@ -689,7 +740,7 @@ public class Environment {
     * {@hide}
     */
    public static File getDataPreloadsFileCacheDirectory() {
        return new File(getDataPreloadsDirectory(), "file_cache");
        return newFilePrep(getDataPreloadsDirectory(), "file_cache");
    }

    /**
@@ -697,7 +748,7 @@ public class Environment {
     * {@hide}
     */
    public static File getPackageCacheDirectory() {
        return new File(getDataSystemDirectory(), "package_cache");
        return newFilePrep(getDataSystemDirectory(), "package_cache");
    }

    /**
@@ -710,9 +761,9 @@ public class Environment {
    @SystemApi
    public static @NonNull Collection<File> getInternalMediaDirectories() {
        final ArrayList<File> res = new ArrayList<>();
        addCanonicalFile(res, new File(Environment.getRootDirectory(), "media"));
        addCanonicalFile(res, new File(Environment.getOemDirectory(), "media"));
        addCanonicalFile(res, new File(Environment.getProductDirectory(), "media"));
        addCanonicalFile(res, newFilePrep(Environment.getRootDirectory(), "media"));
        addCanonicalFile(res, newFilePrep(Environment.getOemDirectory(), "media"));
        addCanonicalFile(res, newFilePrep(Environment.getProductDirectory(), "media"));
        return res;
    }

@@ -789,6 +840,7 @@ public class Environment {
     * @see #getExternalStorageState()
     * @see #isExternalStorageRemovable()
     */
    @RavenwoodThrow(blockedBy = StorageManager.class)
    public static File getExternalStorageDirectory() {
        throwIfUserRequired();
        return sCurrentUser.getExternalDirs()[0];
@@ -796,14 +848,16 @@ public class Environment {

    /** {@hide} */
    @UnsupportedAppUsage
    @RavenwoodThrow(reason = "not supporting env var based API for now")
    public static File getLegacyExternalStorageDirectory() {
        return new File(System.getenv(ENV_EXTERNAL_STORAGE));
        return newFilePrep(getEnvPath(ENV_EXTERNAL_STORAGE));
    }

    /** {@hide} */
    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
    @RavenwoodThrow(reason = "not supporting env var based API for now")
    public static File getLegacyExternalStorageObbDirectory() {
        return buildPath(getLegacyExternalStorageDirectory(), DIR_ANDROID, DIR_OBB);
        return buildPathPrep(getLegacyExternalStorageDirectory(), DIR_ANDROID, DIR_OBB);
    }

    /**
@@ -1288,6 +1342,7 @@ public class Environment {
     *         {@link #MEDIA_MOUNTED_READ_ONLY}, {@link #MEDIA_SHARED},
     *         {@link #MEDIA_BAD_REMOVAL}, or {@link #MEDIA_UNMOUNTABLE}.
     */
    @RavenwoodThrow(blockedBy = StorageManager.class)
    public static String getExternalStorageState() {
        final File externalDir = sCurrentUser.getExternalDirs()[0];
        return getExternalStorageState(externalDir);
@@ -1297,6 +1352,7 @@ public class Environment {
     * @deprecated use {@link #getExternalStorageState(File)}
     */
    @Deprecated
    @RavenwoodThrow(blockedBy = StorageManager.class)
    public static String getStorageState(File path) {
        return getExternalStorageState(path);
    }
@@ -1311,6 +1367,7 @@ public class Environment {
     *         {@link #MEDIA_MOUNTED_READ_ONLY}, {@link #MEDIA_SHARED},
     *         {@link #MEDIA_BAD_REMOVAL}, or {@link #MEDIA_UNMOUNTABLE}.
     */
    @RavenwoodThrow(blockedBy = StorageManager.class)
    public static String getExternalStorageState(File path) {
        final StorageVolume volume = StorageManager.getStorageVolume(path, UserHandle.myUserId());
        if (volume != null) {
@@ -1328,6 +1385,7 @@ public class Environment {
     *         or false if the storage device is built in and cannot be
     *         physically removed.
     */
    @RavenwoodThrow(blockedBy = StorageManager.class)
    public static boolean isExternalStorageRemovable() {
        final File externalDir = sCurrentUser.getExternalDirs()[0];
        return isExternalStorageRemovable(externalDir);
@@ -1343,6 +1401,7 @@ public class Environment {
     * @throws IllegalArgumentException if the path is not a valid storage
     *             device.
     */
    @RavenwoodThrow(blockedBy = StorageManager.class)
    public static boolean isExternalStorageRemovable(@NonNull File path) {
        final StorageVolume volume = StorageManager.getStorageVolume(path, UserHandle.myUserId());
        if (volume != null) {
@@ -1366,6 +1425,7 @@ public class Environment {
     * @see DevicePolicyManager#setStorageEncryption(android.content.ComponentName,
     *      boolean)
     */
    @RavenwoodThrow(blockedBy = StorageManager.class)
    public static boolean isExternalStorageEmulated() {
        final File externalDir = sCurrentUser.getExternalDirs()[0];
        return isExternalStorageEmulated(externalDir);
@@ -1386,6 +1446,7 @@ public class Environment {
     * @throws IllegalArgumentException if the path is not a valid storage
     *             device.
     */
    @RavenwoodThrow(blockedBy = StorageManager.class)
    public static boolean isExternalStorageEmulated(@NonNull File path) {
        final StorageVolume volume = StorageManager.getStorageVolume(path, UserHandle.myUserId());
        if (volume != null) {
@@ -1407,6 +1468,7 @@ public class Environment {
     * Non-legacy apps can continue to discover and read media belonging to
     * other apps via {@link android.provider.MediaStore}.
     */
    @RavenwoodThrow(blockedBy = StorageManager.class)
    public static boolean isExternalStorageLegacy() {
        final File externalDir = sCurrentUser.getExternalDirs()[0];
        return isExternalStorageLegacy(externalDir);
@@ -1427,6 +1489,7 @@ public class Environment {
     * @throws IllegalArgumentException if the path is not a valid storage
     * device.
     */
    @RavenwoodThrow(blockedBy = StorageManager.class)
    public static boolean isExternalStorageLegacy(@NonNull File path) {
        final Context context = AppGlobals.getInitialApplication();
        final int uid = context.getApplicationInfo().uid;
@@ -1488,11 +1551,13 @@ public class Environment {
        return sNoIsolatedStorageAppOp;
    }

    @RavenwoodThrow(blockedBy = StorageManager.class)
    private static boolean isScopedStorageEnforced(boolean defaultScopedStorage,
            boolean forceEnableScopedStorage) {
        return defaultScopedStorage && forceEnableScopedStorage;
    }

    @RavenwoodThrow(blockedBy = StorageManager.class)
    private static boolean isScopedStorageDisabled(boolean defaultScopedStorage,
            boolean forceEnableScopedStorage) {
        return !defaultScopedStorage && !forceEnableScopedStorage;
@@ -1506,6 +1571,7 @@ public class Environment {
     * <p>To request access, use
     * {@link android.provider.Settings#ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION}.
     */
    @RavenwoodThrow(blockedBy = AppOpsManager.class)
    public static boolean isExternalStorageManager() {
        final File externalDir = sCurrentUser.getExternalDirs()[0];
        return isExternalStorageManager(externalDir);
@@ -1518,6 +1584,7 @@ public class Environment {
     * <p>To request access, use
     * {@link android.provider.Settings#ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION}.
     */
    @RavenwoodThrow(blockedBy = AppOpsManager.class)
    public static boolean isExternalStorageManager(@NonNull File path) {
        final Context context = Objects.requireNonNull(AppGlobals.getInitialApplication());
        String packageName = Objects.requireNonNull(context.getPackageName());
@@ -1542,15 +1609,15 @@ public class Environment {
        }
    }

    static File getDirectory(String variableName, String defaultPath) {
        String path = System.getenv(variableName);
        return path == null ? new File(defaultPath) : new File(path);
    private static File getDirectory(String variableName, String defaultPath) {
        return new File(getDirectoryPath(variableName, defaultPath));
    }

    @NonNull
    static String getDirectoryPath(@NonNull String variableName, @NonNull String defaultPath) {
        String path = System.getenv(variableName);
        return path == null ? defaultPath : path;
    private static String getDirectoryPath(
            @NonNull String variableName, @NonNull String defaultPath) {
        String path = getEnvPath(variableName);
        return prep(path == null ? defaultPath : path);
    }

    /** {@hide} */
@@ -1594,9 +1661,14 @@ public class Environment {
                cur = new File(cur, segment);
            }
        }
        // buildPath may be used for a filepath too, so we can't just always do mkdirs on it.
        return cur;
    }

    private static File buildPathPrep(File base, String... segments) {
        return prep(buildPath(base, segments));
    }

    /**
     * If the given path exists on emulated external storage, return the
     * translated backing path hosted on internal storage. This bypasses any
+84 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2025 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.os;

import android.util.Log;

import com.android.ravenwood.common.RavenwoodCommonUtils;

import java.io.File;
import java.util.Objects;

/**
 * Ravenwood redirect target class from {@link Environment}.
 */
public class Environment_ravenwood {
    private static final String TAG = "Environment_ravenwood";

    private static final boolean VERBOSE = RavenwoodCommonUtils.RAVENWOOD_VERBOSE_LOGGING;

    private Environment_ravenwood() {
    }

    private static volatile File sRootDir;

    /** Called by ravenwood to initialize it. */
    public static void init(File rootDir) {
        sRootDir = Objects.requireNonNull(rootDir);
    }

    /** Redirected from the corresponding {@link Environment} method. */
    static String getEnvPath(String variableName) {
        return System.getProperty("ravenwood.env." + variableName);
    }

    /** Redirected from the corresponding {@link Environment} method. */
    static File prep(File path) {
        prep(path.getAbsolutePath());
        return path;
    }

    /** Redirected from the corresponding {@link Environment} method. */
    static String prep(String path) {
        if (path != null) {
            path = translateAbsolutePathForRavenwood(path);
            if (VERBOSE) {
                Log.v(TAG, "mkdirs: " + path);
            }
            new File(path).mkdirs();
        }
        return path;
    }

    private static String translateAbsolutePathForRavenwood(String path) {
        if (!path.startsWith("/")) {
            throw new RuntimeException(
                    "Path doesn't start with a '/'. Actual=" + path);
        }
        var root = Objects.requireNonNull(sRootDir);
        if (path.startsWith(root.toString())) {
            if (VERBOSE) {
                Log.v(TAG, "translate: " + path + " is already translated");
            }
            return path;
        }
        var ret = new File(root, path).getAbsolutePath();
        if (VERBOSE) {
            Log.v(TAG, "translate: " + path + " -> " + ret);
        }
        return ret;
    }
}
+218 −7

File changed.

Preview size limit exceeded, changes collapsed.

+1 −2
Original line number Diff line number Diff line
@@ -46,7 +46,6 @@ import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.file.Files;
import java.util.concurrent.Executor;
import java.util.function.Supplier;

@@ -89,7 +88,7 @@ public class RavenwoodContext extends RavenwoodBaseContext {
        mMainThread = mainThread;
        mResourcesSupplier = resourcesSupplier;

        mDataDir = Files.createTempDirectory(mPackageName).toFile();
        mDataDir = RavenwoodDriver.sAppDataDir;

        // Services provided by a typical shipping device
        registerService(ClipboardManager.class,
+10 −0
Original line number Diff line number Diff line
@@ -51,6 +51,7 @@ import android.os.Binder;
import android.os.Build;
import android.os.Build.VERSION_CODES;
import android.os.Bundle;
import android.os.Environment_ravenwood;
import android.os.HandlerThread;
import android.os.Looper;
import android.os.Looper_ravenwood;
@@ -84,6 +85,7 @@ import org.junit.runner.Description;
import java.io.File;
import java.io.IOException;
import java.io.PrintStream;
import java.nio.file.Files;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Locale;
@@ -230,6 +232,9 @@ public class RavenwoodDriver {
    private static final long sCallingIdentity =
            packBinderIdentityToken(false, FIRST_APPLICATION_UID, sMyPid);

    static volatile File sRootDir;
    static volatile File sAppDataDir;

    /**
     * Initialize the global environment.
     */
@@ -349,6 +354,11 @@ public class RavenwoodDriver {

        assertMockitoVersion();

        sRootDir = Files.createTempDirectory("ravenwood-root-dir-").toFile();
        sAppDataDir = new File(sRootDir, "data/app/appdatadir/");
        sAppDataDir.mkdirs();
        Environment_ravenwood.init(sRootDir);

        Log.i(TAG, "TargetPackageName=" + sTargetPackageName);
        Log.i(TAG, "TestPackageName=" + sTestPackageName);
        Log.i(TAG, "TargetSdkLevel=" + sTargetSdkLevel);
Loading