Loading core/java/android/os/Environment.java +123 −51 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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"; Loading Loading @@ -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"); Loading Loading @@ -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(); } Loading Loading @@ -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)); } /** Loading @@ -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)); } Loading @@ -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); } } Loading @@ -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); } } Loading @@ -408,7 +459,7 @@ public class Environment { /** {@hide} */ @UnsupportedAppUsage public static File getDataSystemDirectory() { return new File(getDataDirectory(), "system"); return newFilePrep(getDataDirectory(), "system"); } /** Loading @@ -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. Loading @@ -426,7 +477,7 @@ public class Environment { */ @Deprecated public static @NonNull File getDataSystemDeDirectory() { return buildPath(getDataDirectory(), "system_de"); return buildPathPrep(getDataDirectory(), "system_de"); } /** Loading @@ -434,7 +485,7 @@ public class Environment { * {@hide} */ public static File getDataSystemCeDirectory() { return buildPath(getDataDirectory(), "system_ce"); return buildPathPrep(getDataDirectory(), "system_ce"); } /** Loading @@ -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)); } /** Loading @@ -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} */ Loading @@ -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); } /** Loading Loading @@ -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} */ Loading @@ -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); } /** Loading Loading @@ -647,7 +698,7 @@ public class Environment { * {@hide} */ public static File getDataPreloadsDirectory() { return new File(getDataDirectory(), "preloads"); return newFilePrep(getDataDirectory(), "preloads"); } /** Loading @@ -655,7 +706,7 @@ public class Environment { * {@hide} */ public static File getDataPreloadsDemoDirectory() { return new File(getDataPreloadsDirectory(), "demo"); return newFilePrep(getDataPreloadsDirectory(), "demo"); } /** Loading @@ -663,7 +714,7 @@ public class Environment { * {@hide} */ public static File getDataPreloadsAppsDirectory() { return new File(getDataPreloadsDirectory(), "apps"); return newFilePrep(getDataPreloadsDirectory(), "apps"); } /** Loading @@ -671,7 +722,7 @@ public class Environment { * {@hide} */ public static File getDataPreloadsMediaDirectory() { return new File(getDataPreloadsDirectory(), "media"); return newFilePrep(getDataPreloadsDirectory(), "media"); } /** Loading @@ -680,7 +731,7 @@ public class Environment { * {@hide} */ public static File getDataPreloadsFileCacheDirectory(String packageName) { return new File(getDataPreloadsFileCacheDirectory(), packageName); return newFilePrep(getDataPreloadsFileCacheDirectory(), packageName); } /** Loading @@ -689,7 +740,7 @@ public class Environment { * {@hide} */ public static File getDataPreloadsFileCacheDirectory() { return new File(getDataPreloadsDirectory(), "file_cache"); return newFilePrep(getDataPreloadsDirectory(), "file_cache"); } /** Loading @@ -697,7 +748,7 @@ public class Environment { * {@hide} */ public static File getPackageCacheDirectory() { return new File(getDataSystemDirectory(), "package_cache"); return newFilePrep(getDataSystemDirectory(), "package_cache"); } /** Loading @@ -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; } Loading Loading @@ -789,6 +840,7 @@ public class Environment { * @see #getExternalStorageState() * @see #isExternalStorageRemovable() */ @RavenwoodThrow(blockedBy = StorageManager.class) public static File getExternalStorageDirectory() { throwIfUserRequired(); return sCurrentUser.getExternalDirs()[0]; Loading @@ -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); } /** Loading Loading @@ -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); Loading @@ -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); } Loading @@ -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) { Loading @@ -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); Loading @@ -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) { Loading @@ -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); Loading @@ -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) { Loading @@ -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); Loading @@ -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; Loading Loading @@ -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; Loading @@ -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); Loading @@ -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()); Loading @@ -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} */ Loading Loading @@ -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 Loading core/java/android/os/Environment_ravenwood.java 0 → 100644 +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; } } core/tests/coretests/src/android/os/EnvironmentTest.java +218 −7 File changed.Preview size limit exceeded, changes collapsed. Show changes ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodContext.java +1 −2 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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, Loading ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodDriver.java +10 −0 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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; Loading Loading @@ -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. */ Loading Loading @@ -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 Loading
core/java/android/os/Environment.java +123 −51 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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"; Loading Loading @@ -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"); Loading Loading @@ -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(); } Loading Loading @@ -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)); } /** Loading @@ -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)); } Loading @@ -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); } } Loading @@ -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); } } Loading @@ -408,7 +459,7 @@ public class Environment { /** {@hide} */ @UnsupportedAppUsage public static File getDataSystemDirectory() { return new File(getDataDirectory(), "system"); return newFilePrep(getDataDirectory(), "system"); } /** Loading @@ -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. Loading @@ -426,7 +477,7 @@ public class Environment { */ @Deprecated public static @NonNull File getDataSystemDeDirectory() { return buildPath(getDataDirectory(), "system_de"); return buildPathPrep(getDataDirectory(), "system_de"); } /** Loading @@ -434,7 +485,7 @@ public class Environment { * {@hide} */ public static File getDataSystemCeDirectory() { return buildPath(getDataDirectory(), "system_ce"); return buildPathPrep(getDataDirectory(), "system_ce"); } /** Loading @@ -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)); } /** Loading @@ -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} */ Loading @@ -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); } /** Loading Loading @@ -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} */ Loading @@ -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); } /** Loading Loading @@ -647,7 +698,7 @@ public class Environment { * {@hide} */ public static File getDataPreloadsDirectory() { return new File(getDataDirectory(), "preloads"); return newFilePrep(getDataDirectory(), "preloads"); } /** Loading @@ -655,7 +706,7 @@ public class Environment { * {@hide} */ public static File getDataPreloadsDemoDirectory() { return new File(getDataPreloadsDirectory(), "demo"); return newFilePrep(getDataPreloadsDirectory(), "demo"); } /** Loading @@ -663,7 +714,7 @@ public class Environment { * {@hide} */ public static File getDataPreloadsAppsDirectory() { return new File(getDataPreloadsDirectory(), "apps"); return newFilePrep(getDataPreloadsDirectory(), "apps"); } /** Loading @@ -671,7 +722,7 @@ public class Environment { * {@hide} */ public static File getDataPreloadsMediaDirectory() { return new File(getDataPreloadsDirectory(), "media"); return newFilePrep(getDataPreloadsDirectory(), "media"); } /** Loading @@ -680,7 +731,7 @@ public class Environment { * {@hide} */ public static File getDataPreloadsFileCacheDirectory(String packageName) { return new File(getDataPreloadsFileCacheDirectory(), packageName); return newFilePrep(getDataPreloadsFileCacheDirectory(), packageName); } /** Loading @@ -689,7 +740,7 @@ public class Environment { * {@hide} */ public static File getDataPreloadsFileCacheDirectory() { return new File(getDataPreloadsDirectory(), "file_cache"); return newFilePrep(getDataPreloadsDirectory(), "file_cache"); } /** Loading @@ -697,7 +748,7 @@ public class Environment { * {@hide} */ public static File getPackageCacheDirectory() { return new File(getDataSystemDirectory(), "package_cache"); return newFilePrep(getDataSystemDirectory(), "package_cache"); } /** Loading @@ -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; } Loading Loading @@ -789,6 +840,7 @@ public class Environment { * @see #getExternalStorageState() * @see #isExternalStorageRemovable() */ @RavenwoodThrow(blockedBy = StorageManager.class) public static File getExternalStorageDirectory() { throwIfUserRequired(); return sCurrentUser.getExternalDirs()[0]; Loading @@ -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); } /** Loading Loading @@ -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); Loading @@ -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); } Loading @@ -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) { Loading @@ -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); Loading @@ -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) { Loading @@ -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); Loading @@ -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) { Loading @@ -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); Loading @@ -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; Loading Loading @@ -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; Loading @@ -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); Loading @@ -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()); Loading @@ -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} */ Loading Loading @@ -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 Loading
core/java/android/os/Environment_ravenwood.java 0 → 100644 +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; } }
core/tests/coretests/src/android/os/EnvironmentTest.java +218 −7 File changed.Preview size limit exceeded, changes collapsed. Show changes
ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodContext.java +1 −2 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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, Loading
ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodDriver.java +10 −0 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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; Loading Loading @@ -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. */ Loading Loading @@ -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