Merge "Expose Environment device/credential encrypted app storage directories"

This commit is contained in:
Winson Chiu
2022-12-13 01:53:11 +00:00
committed by Android (Google) Code Review
6 changed files with 115 additions and 10 deletions

View File

@@ -9703,6 +9703,8 @@ package android.os {
}
public class Environment {
method @NonNull public static java.io.File getDataCePackageDirectoryForUser(@NonNull java.util.UUID, @NonNull android.os.UserHandle, @NonNull String);
method @NonNull public static java.io.File getDataDePackageDirectoryForUser(@NonNull java.util.UUID, @NonNull android.os.UserHandle, @NonNull String);
method @NonNull public static java.util.Collection<java.io.File> getInternalMediaDirectories();
method @NonNull public static java.io.File getOdmDirectory();
method @NonNull public static java.io.File getOemDirectory();

View File

@@ -2071,7 +2071,7 @@ package android.os.storage {
public class StorageManager {
method public long computeStorageCacheBytes(@NonNull java.io.File);
method @NonNull public static java.util.UUID convert(@NonNull String);
method @NonNull public static java.util.UUID convert(@Nullable String);
method @NonNull public static String convert(@NonNull java.util.UUID);
method @Nullable public String getCloudMediaProvider();
method public boolean isAppIoBlocked(@NonNull java.util.UUID, int, int, int);

View File

@@ -18,6 +18,7 @@ package android.os;
import android.Manifest;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SuppressLint;
import android.annotation.SystemApi;
import android.annotation.TestApi;
@@ -44,6 +45,7 @@ import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Objects;
import java.util.UUID;
/**
* Provides access to environment variables.
@@ -551,12 +553,37 @@ public class Environment {
}
/** {@hide} */
public static File getDataUserCePackageDirectory(String volumeUuid, int userId,
String packageName) {
@NonNull
public static File getDataUserCePackageDirectory(@Nullable String volumeUuid, int userId,
@NonNull String packageName) {
// TODO: keep consistent with installd
return new File(getDataUserCeDirectory(volumeUuid, userId), packageName);
}
/**
* Retrieve the credential encrypted data directory for a specific package of a specific user.
* This is equivalent to {@link ApplicationInfo#credentialProtectedDataDir}, exposed because
* fetching a full {@link ApplicationInfo} instance may be expensive if all the caller needs
* is this directory.
*
* @param storageUuid The storage volume for this directory, usually retrieved from a
* {@link StorageManager} API or {@link ApplicationInfo#storageUuid}.
* @param user The user this directory is for.
* @param packageName The app this directory is for.
*
* @see ApplicationInfo#credentialProtectedDataDir
* @return A file to the directory.
*
* @hide
*/
@SystemApi
@NonNull
public static File getDataCePackageDirectoryForUser(@NonNull UUID storageUuid,
@NonNull UserHandle user, @NonNull String packageName) {
var volumeUuid = StorageManager.convert(storageUuid);
return getDataUserCePackageDirectory(volumeUuid, user.getIdentifier(), packageName);
}
/** {@hide} */
public static File getDataUserDeDirectory(String volumeUuid) {
return new File(getDataDirectory(volumeUuid), DIR_USER_DE);
@@ -568,12 +595,37 @@ public class Environment {
}
/** {@hide} */
public static File getDataUserDePackageDirectory(String volumeUuid, int userId,
String packageName) {
@NonNull
public static File getDataUserDePackageDirectory(@Nullable String volumeUuid, int userId,
@NonNull String packageName) {
// TODO: keep consistent with installd
return new File(getDataUserDeDirectory(volumeUuid, userId), packageName);
}
/**
* Retrieve the device encrypted data directory for a specific package of a specific user. This
* is equivalent to {@link ApplicationInfo#deviceProtectedDataDir}, exposed because fetching a
* full {@link ApplicationInfo} instance may be expensive if all the caller needs is this
* directory.
*
* @param storageUuid The storage volume for this directory, usually retrieved from a
* {@link StorageManager} API or {@link ApplicationInfo#storageUuid}.
* @param user The user this directory is for.
* @param packageName The app this directory is for.
*
* @see ApplicationInfo#deviceProtectedDataDir
* @return A file to the directory.
*
* @hide
*/
@SystemApi
@NonNull
public static File getDataDePackageDirectoryForUser(@NonNull UUID storageUuid,
@NonNull UserHandle user, @NonNull String packageName) {
var volumeUuid = StorageManager.convert(storageUuid);
return getDataUserDePackageDirectory(volumeUuid, user.getIdentifier(), packageName);
}
/**
* Return preloads directory.
* <p>This directory may contain pre-loaded content such as

View File

@@ -84,6 +84,15 @@
"include-filter": "android.os.cts.SharedMemoryTest"
}
]
},
{
"file_patterns": ["Environment[^/]*\\.java"],
"name": "FrameworksCoreTests",
"options": [
{
"include-filter": "android.os.EnvironmentTest"
}
]
}
],
"postsubmit": [

View File

@@ -2742,7 +2742,8 @@ public class StorageManager {
/** {@hide} */
@TestApi
public static @NonNull UUID convert(@NonNull String uuid) {
public static @NonNull UUID convert(@Nullable String uuid) {
// UUID_PRIVATE_INTERNAL is null, so this accepts nullable input
if (Objects.equals(uuid, UUID_PRIVATE_INTERNAL)) {
return UUID_DEFAULT;
} else if (Objects.equals(uuid, UUID_PRIMARY_PHYSICAL)) {

View File

@@ -22,12 +22,12 @@ import static android.os.Environment.HAS_DOWNLOADS;
import static android.os.Environment.HAS_OTHER;
import static android.os.Environment.classifyExternalStorageDirectory;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertEquals;
import android.app.AppOpsManager;
import android.content.Context;
import android.os.storage.StorageManager;
import androidx.test.InstrumentationRegistry;
import androidx.test.runner.AndroidJUnit4;
@@ -38,6 +38,9 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import java.io.File;
import java.util.ArrayList;
import java.util.UUID;
import java.util.function.BiFunction;
@RunWith(AndroidJUnit4.class)
public class EnvironmentTest {
@@ -104,4 +107,42 @@ public class EnvironmentTest {
Environment.buildPath(dir, "Taxes.pdf").createNewFile();
assertEquals(HAS_OTHER, classifyExternalStorageDirectory(dir));
}
@Test
public void testDataCePackageDirectoryForUser() {
testDataPackageDirectoryForUser(
(uuid, userHandle) -> Environment.getDataCePackageDirectoryForUser(
uuid, userHandle, getContext().getPackageName()),
(uuid, user) -> Environment.getDataUserCePackageDirectory(
uuid, user, getContext().getPackageName())
);
}
@Test
public void testDataDePackageDirectoryForUser() {
testDataPackageDirectoryForUser(
(uuid, userHandle) -> Environment.getDataDePackageDirectoryForUser(
uuid, userHandle, getContext().getPackageName()),
(uuid, user) -> Environment.getDataUserDePackageDirectory(
uuid, user, getContext().getPackageName())
);
}
private void testDataPackageDirectoryForUser(
BiFunction<UUID, UserHandle, File> publicApi,
BiFunction<String, Integer, File> hideApi) {
var uuids = new ArrayList<String>();
uuids.add(null); // Private internal
uuids.add("primary_physical");
uuids.add("system");
uuids.add("3939-3939"); // FAT Volume
uuids.add("57554103-df3e-4475-ae7a-8feba49353ac"); // Random valid UUID
var userHandle = UserHandle.of(0);
// Check that the @hide method is consistent with the public API
for (String uuid : uuids) {
assertThat(publicApi.apply(StorageManager.convert(uuid), userHandle))
.isEqualTo(hideApi.apply(uuid, 0));
}
}
}