Loading api/current.txt +4 −0 Original line number Diff line number Diff line Loading @@ -33210,6 +33210,7 @@ package android.os { method public android.os.StrictMode.VmPolicy.Builder detectAll(); method public android.os.StrictMode.VmPolicy.Builder detectCleartextNetwork(); method public android.os.StrictMode.VmPolicy.Builder detectContentUriWithoutPermission(); method public android.os.StrictMode.VmPolicy.Builder detectCredentialProtectedWhileLocked(); method public android.os.StrictMode.VmPolicy.Builder detectFileUriExposure(); method public android.os.StrictMode.VmPolicy.Builder detectImplicitDirectBoot(); method public android.os.StrictMode.VmPolicy.Builder detectLeakedClosableObjects(); Loading Loading @@ -33613,6 +33614,9 @@ package android.os.strictmode { public final class ContentUriWithoutPermissionViolation extends android.os.strictmode.Violation { } public final class CredentialProtectedWhileLockedViolation extends android.os.strictmode.Violation { } public final class CustomViolation extends android.os.strictmode.Violation { } core/java/android/app/ContextImpl.java +7 −1 Original line number Diff line number Diff line Loading @@ -80,6 +80,8 @@ import android.view.autofill.AutofillManager.AutofillClient; import com.android.internal.annotations.GuardedBy; import com.android.internal.util.Preconditions; import dalvik.system.BlockGuard; import libcore.io.Memory; import java.io.File; Loading Loading @@ -2521,7 +2523,11 @@ class ContextImpl extends Context { private File makeFilename(File base, String name) { if (name.indexOf(File.separatorChar) < 0) { return new File(base, name); final File res = new File(base, name); // We report as filesystem access here to give us the best shot at // detecting apps that will pass the path down to native code. BlockGuard.getVmPolicy().onPathAccess(res.getPath()); return res; } throw new IllegalArgumentException( "File " + name + " contains a path separator"); Loading core/java/android/os/Environment.java +2 −0 Original line number Diff line number Diff line Loading @@ -33,6 +33,8 @@ import java.util.LinkedList; public class Environment { private static final String TAG = "Environment"; // NOTE: keep credential-protected paths in sync with StrictMode.java private static final String ENV_EXTERNAL_STORAGE = "EXTERNAL_STORAGE"; private static final String ENV_ANDROID_ROOT = "ANDROID_ROOT"; private static final String ENV_ANDROID_DATA = "ANDROID_DATA"; Loading core/java/android/os/StrictMode.java +110 −0 Original line number Diff line number Diff line Loading @@ -31,8 +31,10 @@ import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.net.TrafficStats; import android.net.Uri; import android.os.storage.IStorageManager; import android.os.strictmode.CleartextNetworkViolation; import android.os.strictmode.ContentUriWithoutPermissionViolation; import android.os.strictmode.CredentialProtectedWhileLockedViolation; import android.os.strictmode.CustomViolation; import android.os.strictmode.DiskReadViolation; import android.os.strictmode.DiskWriteViolation; Loading Loading @@ -284,6 +286,8 @@ public final class StrictMode { private static final int DETECT_VM_NON_SDK_API_USAGE = 1 << 9; /** @hide */ private static final int DETECT_VM_IMPLICIT_DIRECT_BOOT = 1 << 10; /** @hide */ private static final int DETECT_VM_CREDENTIAL_PROTECTED_WHILE_LOCKED = 1 << 11; /** @hide */ private static final int DETECT_VM_ALL = 0x0000ffff; Loading Loading @@ -860,6 +864,9 @@ public final class StrictMode { detectContentUriWithoutPermission(); detectUntaggedSockets(); } if (targetSdk >= Build.VERSION_CODES.Q) { detectCredentialProtectedWhileLocked(); } // TODO: Decide whether to detect non SDK API usage beyond a certain API level. // TODO: enable detectImplicitDirectBoot() once system is less noisy Loading Loading @@ -994,6 +1001,28 @@ public final class StrictMode { return disable(DETECT_VM_IMPLICIT_DIRECT_BOOT); } /** * Detect access to filesystem paths stored in credential protected * storage areas while the user is locked. * <p> * When a user is locked, credential protected storage is * unavailable, and files stored in these locations appear to not * exist, which can result in subtle app bugs if they assume default * behaviors or empty states. Instead, apps should store data needed * while a user is locked under device protected storage areas. * * @see Context#createCredentialProtectedStorageContext() * @see Context#createDeviceProtectedStorageContext() */ public Builder detectCredentialProtectedWhileLocked() { return enable(DETECT_VM_CREDENTIAL_PROTECTED_WHILE_LOCKED); } /** @hide */ public Builder permitCredentialProtectedWhileLocked() { return disable(DETECT_VM_CREDENTIAL_PROTECTED_WHILE_LOCKED); } /** * Crashes the whole process on violation. This penalty runs at the end of all enabled * penalties so you'll still get your logging or other violations before the process Loading Loading @@ -1155,6 +1184,16 @@ public final class StrictMode { androidPolicy.setThreadPolicyMask(threadPolicyMask); } private static void setBlockGuardVmPolicy(@VmPolicyMask int vmPolicyMask) { // We only need to install BlockGuard for a small subset of VM policies vmPolicyMask &= DETECT_VM_CREDENTIAL_PROTECTED_WHILE_LOCKED; if (vmPolicyMask != 0) { BlockGuard.setVmPolicy(VM_ANDROID_POLICY); } else { BlockGuard.setVmPolicy(BlockGuard.LAX_VM_POLICY); } } // Sets up CloseGuard in Dalvik/libcore private static void setCloseGuardEnabled(boolean enabled) { if (!(CloseGuard.getReporter() instanceof AndroidCloseGuardReporter)) { Loading Loading @@ -1742,6 +1781,34 @@ public final class StrictMode { } } private static final BlockGuard.VmPolicy VM_ANDROID_POLICY = new BlockGuard.VmPolicy() { @Override public void onPathAccess(String path) { if (path == null) return; // NOTE: keep credential-protected paths in sync with Environment.java if (path.startsWith("/data/user/") || path.startsWith("/data/media/") || path.startsWith("/data/system_ce/") || path.startsWith("/data/misc_ce/") || path.startsWith("/data/vendor_ce/") || path.startsWith("/storage/emulated/")) { final int second = path.indexOf('/', 1); final int third = path.indexOf('/', second + 1); final int fourth = path.indexOf('/', third + 1); if (fourth == -1) return; try { final int userId = Integer.parseInt(path.substring(third + 1, fourth)); onCredentialProtectedPathAccess(path, userId); } catch (NumberFormatException ignored) { } } else if (path.startsWith("/data/data/")) { onCredentialProtectedPathAccess(path, UserHandle.USER_SYSTEM); } } }; /** * In the common case, as set by conditionallyEnableDebugLogging, we're just dropboxing any * violations but not showing a dialog, not loggging, and not killing the process. In these Loading Loading @@ -1909,6 +1976,8 @@ public final class StrictMode { VMRuntime.setNonSdkApiUsageConsumer(null); VMRuntime.setDedupeHiddenApiWarnings(true); } setBlockGuardVmPolicy(sVmPolicy.mask); } } Loading Loading @@ -1971,6 +2040,11 @@ public final class StrictMode { return (sVmPolicy.mask & DETECT_VM_IMPLICIT_DIRECT_BOOT) != 0; } /** @hide */ public static boolean vmCredentialProtectedWhileLockedEnabled() { return (sVmPolicy.mask & DETECT_VM_CREDENTIAL_PROTECTED_WHILE_LOCKED) != 0; } /** @hide */ public static void onSqliteObjectLeaked(String message, Throwable originStack) { onVmPolicyViolation(new SqliteObjectLeakedViolation(message, originStack)); Loading Loading @@ -2044,6 +2118,42 @@ public final class StrictMode { onVmPolicyViolation(new ImplicitDirectBootViolation()); } /** Assume locked until we hear otherwise */ private static volatile boolean sUserKeyUnlocked = false; private static boolean isUserKeyUnlocked(int userId) { final IStorageManager storage = IStorageManager.Stub .asInterface(ServiceManager.getService("mount")); if (storage != null) { try { return storage.isUserKeyUnlocked(userId); } catch (RemoteException ignored) { } } return false; } /** @hide */ private static void onCredentialProtectedPathAccess(String path, int userId) { // We can cache the unlocked state for the userId we're running as, // since any relocking of that user will always result in our // process being killed to release any CE FDs we're holding onto. if (userId == UserHandle.myUserId()) { if (sUserKeyUnlocked) { return; } else if (isUserKeyUnlocked(userId)) { sUserKeyUnlocked = true; return; } } else if (isUserKeyUnlocked(userId)) { return; } onVmPolicyViolation(new CredentialProtectedWhileLockedViolation( "Accessed credential protected path " + path + " while user " + userId + " was locked")); } // Map from VM violation fingerprint to uptime millis. private static final HashMap<Integer, Long> sLastVmViolationTime = new HashMap<>(); Loading core/java/android/os/storage/StorageManager.java +3 −0 Original line number Diff line number Diff line Loading @@ -71,6 +71,8 @@ import com.android.internal.os.RoSystemProperties; import com.android.internal.os.SomeArgs; import com.android.internal.util.Preconditions; import dalvik.system.BlockGuard; import java.io.File; import java.io.FileDescriptor; import java.io.FileNotFoundException; Loading Loading @@ -1131,6 +1133,7 @@ public class StorageManager { /** {@hide} */ public void mkdirs(File file) { BlockGuard.getVmPolicy().onPathAccess(file.getAbsolutePath()); try { mStorageManager.mkdirs(mContext.getOpPackageName(), file.getAbsolutePath()); } catch (RemoteException e) { Loading Loading
api/current.txt +4 −0 Original line number Diff line number Diff line Loading @@ -33210,6 +33210,7 @@ package android.os { method public android.os.StrictMode.VmPolicy.Builder detectAll(); method public android.os.StrictMode.VmPolicy.Builder detectCleartextNetwork(); method public android.os.StrictMode.VmPolicy.Builder detectContentUriWithoutPermission(); method public android.os.StrictMode.VmPolicy.Builder detectCredentialProtectedWhileLocked(); method public android.os.StrictMode.VmPolicy.Builder detectFileUriExposure(); method public android.os.StrictMode.VmPolicy.Builder detectImplicitDirectBoot(); method public android.os.StrictMode.VmPolicy.Builder detectLeakedClosableObjects(); Loading Loading @@ -33613,6 +33614,9 @@ package android.os.strictmode { public final class ContentUriWithoutPermissionViolation extends android.os.strictmode.Violation { } public final class CredentialProtectedWhileLockedViolation extends android.os.strictmode.Violation { } public final class CustomViolation extends android.os.strictmode.Violation { }
core/java/android/app/ContextImpl.java +7 −1 Original line number Diff line number Diff line Loading @@ -80,6 +80,8 @@ import android.view.autofill.AutofillManager.AutofillClient; import com.android.internal.annotations.GuardedBy; import com.android.internal.util.Preconditions; import dalvik.system.BlockGuard; import libcore.io.Memory; import java.io.File; Loading Loading @@ -2521,7 +2523,11 @@ class ContextImpl extends Context { private File makeFilename(File base, String name) { if (name.indexOf(File.separatorChar) < 0) { return new File(base, name); final File res = new File(base, name); // We report as filesystem access here to give us the best shot at // detecting apps that will pass the path down to native code. BlockGuard.getVmPolicy().onPathAccess(res.getPath()); return res; } throw new IllegalArgumentException( "File " + name + " contains a path separator"); Loading
core/java/android/os/Environment.java +2 −0 Original line number Diff line number Diff line Loading @@ -33,6 +33,8 @@ import java.util.LinkedList; public class Environment { private static final String TAG = "Environment"; // NOTE: keep credential-protected paths in sync with StrictMode.java private static final String ENV_EXTERNAL_STORAGE = "EXTERNAL_STORAGE"; private static final String ENV_ANDROID_ROOT = "ANDROID_ROOT"; private static final String ENV_ANDROID_DATA = "ANDROID_DATA"; Loading
core/java/android/os/StrictMode.java +110 −0 Original line number Diff line number Diff line Loading @@ -31,8 +31,10 @@ import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.net.TrafficStats; import android.net.Uri; import android.os.storage.IStorageManager; import android.os.strictmode.CleartextNetworkViolation; import android.os.strictmode.ContentUriWithoutPermissionViolation; import android.os.strictmode.CredentialProtectedWhileLockedViolation; import android.os.strictmode.CustomViolation; import android.os.strictmode.DiskReadViolation; import android.os.strictmode.DiskWriteViolation; Loading Loading @@ -284,6 +286,8 @@ public final class StrictMode { private static final int DETECT_VM_NON_SDK_API_USAGE = 1 << 9; /** @hide */ private static final int DETECT_VM_IMPLICIT_DIRECT_BOOT = 1 << 10; /** @hide */ private static final int DETECT_VM_CREDENTIAL_PROTECTED_WHILE_LOCKED = 1 << 11; /** @hide */ private static final int DETECT_VM_ALL = 0x0000ffff; Loading Loading @@ -860,6 +864,9 @@ public final class StrictMode { detectContentUriWithoutPermission(); detectUntaggedSockets(); } if (targetSdk >= Build.VERSION_CODES.Q) { detectCredentialProtectedWhileLocked(); } // TODO: Decide whether to detect non SDK API usage beyond a certain API level. // TODO: enable detectImplicitDirectBoot() once system is less noisy Loading Loading @@ -994,6 +1001,28 @@ public final class StrictMode { return disable(DETECT_VM_IMPLICIT_DIRECT_BOOT); } /** * Detect access to filesystem paths stored in credential protected * storage areas while the user is locked. * <p> * When a user is locked, credential protected storage is * unavailable, and files stored in these locations appear to not * exist, which can result in subtle app bugs if they assume default * behaviors or empty states. Instead, apps should store data needed * while a user is locked under device protected storage areas. * * @see Context#createCredentialProtectedStorageContext() * @see Context#createDeviceProtectedStorageContext() */ public Builder detectCredentialProtectedWhileLocked() { return enable(DETECT_VM_CREDENTIAL_PROTECTED_WHILE_LOCKED); } /** @hide */ public Builder permitCredentialProtectedWhileLocked() { return disable(DETECT_VM_CREDENTIAL_PROTECTED_WHILE_LOCKED); } /** * Crashes the whole process on violation. This penalty runs at the end of all enabled * penalties so you'll still get your logging or other violations before the process Loading Loading @@ -1155,6 +1184,16 @@ public final class StrictMode { androidPolicy.setThreadPolicyMask(threadPolicyMask); } private static void setBlockGuardVmPolicy(@VmPolicyMask int vmPolicyMask) { // We only need to install BlockGuard for a small subset of VM policies vmPolicyMask &= DETECT_VM_CREDENTIAL_PROTECTED_WHILE_LOCKED; if (vmPolicyMask != 0) { BlockGuard.setVmPolicy(VM_ANDROID_POLICY); } else { BlockGuard.setVmPolicy(BlockGuard.LAX_VM_POLICY); } } // Sets up CloseGuard in Dalvik/libcore private static void setCloseGuardEnabled(boolean enabled) { if (!(CloseGuard.getReporter() instanceof AndroidCloseGuardReporter)) { Loading Loading @@ -1742,6 +1781,34 @@ public final class StrictMode { } } private static final BlockGuard.VmPolicy VM_ANDROID_POLICY = new BlockGuard.VmPolicy() { @Override public void onPathAccess(String path) { if (path == null) return; // NOTE: keep credential-protected paths in sync with Environment.java if (path.startsWith("/data/user/") || path.startsWith("/data/media/") || path.startsWith("/data/system_ce/") || path.startsWith("/data/misc_ce/") || path.startsWith("/data/vendor_ce/") || path.startsWith("/storage/emulated/")) { final int second = path.indexOf('/', 1); final int third = path.indexOf('/', second + 1); final int fourth = path.indexOf('/', third + 1); if (fourth == -1) return; try { final int userId = Integer.parseInt(path.substring(third + 1, fourth)); onCredentialProtectedPathAccess(path, userId); } catch (NumberFormatException ignored) { } } else if (path.startsWith("/data/data/")) { onCredentialProtectedPathAccess(path, UserHandle.USER_SYSTEM); } } }; /** * In the common case, as set by conditionallyEnableDebugLogging, we're just dropboxing any * violations but not showing a dialog, not loggging, and not killing the process. In these Loading Loading @@ -1909,6 +1976,8 @@ public final class StrictMode { VMRuntime.setNonSdkApiUsageConsumer(null); VMRuntime.setDedupeHiddenApiWarnings(true); } setBlockGuardVmPolicy(sVmPolicy.mask); } } Loading Loading @@ -1971,6 +2040,11 @@ public final class StrictMode { return (sVmPolicy.mask & DETECT_VM_IMPLICIT_DIRECT_BOOT) != 0; } /** @hide */ public static boolean vmCredentialProtectedWhileLockedEnabled() { return (sVmPolicy.mask & DETECT_VM_CREDENTIAL_PROTECTED_WHILE_LOCKED) != 0; } /** @hide */ public static void onSqliteObjectLeaked(String message, Throwable originStack) { onVmPolicyViolation(new SqliteObjectLeakedViolation(message, originStack)); Loading Loading @@ -2044,6 +2118,42 @@ public final class StrictMode { onVmPolicyViolation(new ImplicitDirectBootViolation()); } /** Assume locked until we hear otherwise */ private static volatile boolean sUserKeyUnlocked = false; private static boolean isUserKeyUnlocked(int userId) { final IStorageManager storage = IStorageManager.Stub .asInterface(ServiceManager.getService("mount")); if (storage != null) { try { return storage.isUserKeyUnlocked(userId); } catch (RemoteException ignored) { } } return false; } /** @hide */ private static void onCredentialProtectedPathAccess(String path, int userId) { // We can cache the unlocked state for the userId we're running as, // since any relocking of that user will always result in our // process being killed to release any CE FDs we're holding onto. if (userId == UserHandle.myUserId()) { if (sUserKeyUnlocked) { return; } else if (isUserKeyUnlocked(userId)) { sUserKeyUnlocked = true; return; } } else if (isUserKeyUnlocked(userId)) { return; } onVmPolicyViolation(new CredentialProtectedWhileLockedViolation( "Accessed credential protected path " + path + " while user " + userId + " was locked")); } // Map from VM violation fingerprint to uptime millis. private static final HashMap<Integer, Long> sLastVmViolationTime = new HashMap<>(); Loading
core/java/android/os/storage/StorageManager.java +3 −0 Original line number Diff line number Diff line Loading @@ -71,6 +71,8 @@ import com.android.internal.os.RoSystemProperties; import com.android.internal.os.SomeArgs; import com.android.internal.util.Preconditions; import dalvik.system.BlockGuard; import java.io.File; import java.io.FileDescriptor; import java.io.FileNotFoundException; Loading Loading @@ -1131,6 +1133,7 @@ public class StorageManager { /** {@hide} */ public void mkdirs(File file) { BlockGuard.getVmPolicy().onPathAccess(file.getAbsolutePath()); try { mStorageManager.mkdirs(mContext.getOpPackageName(), file.getAbsolutePath()); } catch (RemoteException e) { Loading