Update direct boot related documentation.
Also hide a few APIs as requested by council. Add a method to
easily determine if a given File would already be encrypted at rest
by the OS.
Bug: 27531029
Change-Id: Icad5f1cd56411ad3ac707db85fd7449acdcc4b94
diff --git a/api/current.txt b/api/current.txt
index 889ed59..c82c04d 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -8019,8 +8019,6 @@
method public abstract java.lang.String getPackageResourcePath();
method public abstract android.content.res.Resources getResources();
method public abstract android.content.SharedPreferences getSharedPreferences(java.lang.String, int);
- method public abstract android.content.SharedPreferences getSharedPreferences(java.io.File, int);
- method public abstract java.io.File getSharedPreferencesPath(java.lang.String);
method public final java.lang.String getString(int);
method public final java.lang.String getString(int, java.lang.Object...);
method public abstract java.lang.Object getSystemService(java.lang.String);
@@ -29598,6 +29596,7 @@
method public java.lang.String getMountedObbPath(java.lang.String);
method public android.os.storage.StorageVolume getPrimaryVolume();
method public android.os.storage.StorageVolume[] getVolumeList();
+ method public boolean isEncrypted(java.io.File);
method public boolean isObbMounted(java.lang.String);
method public boolean mountObb(java.lang.String, java.lang.String, android.os.storage.OnObbStateChangeListener);
method public boolean unmountObb(java.lang.String, boolean, android.os.storage.OnObbStateChangeListener);
diff --git a/api/removed.txt b/api/removed.txt
index 9b5d3ab..36c8ce5 100644
--- a/api/removed.txt
+++ b/api/removed.txt
@@ -22,6 +22,8 @@
public abstract class Context {
method public deprecated android.content.Context createCredentialEncryptedStorageContext();
method public deprecated android.content.Context createDeviceEncryptedStorageContext();
+ method public abstract android.content.SharedPreferences getSharedPreferences(java.io.File, int);
+ method public abstract java.io.File getSharedPreferencesPath(java.lang.String);
method public deprecated boolean isCredentialEncryptedStorage();
method public deprecated boolean isDeviceEncryptedStorage();
method public deprecated boolean migrateDatabaseFrom(android.content.Context, java.lang.String);
diff --git a/api/system-current.txt b/api/system-current.txt
index ac59b39..24edfe0 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -8318,8 +8318,6 @@
method public abstract java.lang.String getPackageResourcePath();
method public abstract android.content.res.Resources getResources();
method public abstract android.content.SharedPreferences getSharedPreferences(java.lang.String, int);
- method public abstract android.content.SharedPreferences getSharedPreferences(java.io.File, int);
- method public abstract java.io.File getSharedPreferencesPath(java.lang.String);
method public final java.lang.String getString(int);
method public final java.lang.String getString(int, java.lang.Object...);
method public abstract java.lang.Object getSystemService(java.lang.String);
@@ -31910,6 +31908,7 @@
method public java.lang.String getMountedObbPath(java.lang.String);
method public android.os.storage.StorageVolume getPrimaryVolume();
method public android.os.storage.StorageVolume[] getVolumeList();
+ method public boolean isEncrypted(java.io.File);
method public boolean isObbMounted(java.lang.String);
method public boolean mountObb(java.lang.String, java.lang.String, android.os.storage.OnObbStateChangeListener);
method public boolean unmountObb(java.lang.String, boolean, android.os.storage.OnObbStateChangeListener);
diff --git a/api/system-removed.txt b/api/system-removed.txt
index 8bf59df..d48b9b3 100644
--- a/api/system-removed.txt
+++ b/api/system-removed.txt
@@ -20,6 +20,8 @@
public abstract class Context {
method public deprecated android.content.Context createCredentialEncryptedStorageContext();
method public deprecated android.content.Context createDeviceEncryptedStorageContext();
+ method public abstract android.content.SharedPreferences getSharedPreferences(java.io.File, int);
+ method public abstract java.io.File getSharedPreferencesPath(java.lang.String);
method public deprecated boolean isCredentialEncryptedStorage();
method public deprecated boolean isDeviceEncryptedStorage();
method public deprecated boolean migrateDatabaseFrom(android.content.Context, java.lang.String);
diff --git a/api/test-current.txt b/api/test-current.txt
index 908a50e..97e3b95 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -8024,8 +8024,6 @@
method public abstract java.lang.String getPackageResourcePath();
method public abstract android.content.res.Resources getResources();
method public abstract android.content.SharedPreferences getSharedPreferences(java.lang.String, int);
- method public abstract android.content.SharedPreferences getSharedPreferences(java.io.File, int);
- method public abstract java.io.File getSharedPreferencesPath(java.lang.String);
method public final java.lang.String getString(int);
method public final java.lang.String getString(int, java.lang.Object...);
method public abstract java.lang.Object getSystemService(java.lang.String);
@@ -29664,6 +29662,7 @@
method public java.lang.String getMountedObbPath(java.lang.String);
method public android.os.storage.StorageVolume getPrimaryVolume();
method public android.os.storage.StorageVolume[] getVolumeList();
+ method public boolean isEncrypted(java.io.File);
method public boolean isObbMounted(java.lang.String);
method public boolean mountObb(java.lang.String, java.lang.String, android.os.storage.OnObbStateChangeListener);
method public boolean unmountObb(java.lang.String, boolean, android.os.storage.OnObbStateChangeListener);
diff --git a/api/test-removed.txt b/api/test-removed.txt
index 9b5d3ab..36c8ce5 100644
--- a/api/test-removed.txt
+++ b/api/test-removed.txt
@@ -22,6 +22,8 @@
public abstract class Context {
method public deprecated android.content.Context createCredentialEncryptedStorageContext();
method public deprecated android.content.Context createDeviceEncryptedStorageContext();
+ method public abstract android.content.SharedPreferences getSharedPreferences(java.io.File, int);
+ method public abstract java.io.File getSharedPreferencesPath(java.lang.String);
method public deprecated boolean isCredentialEncryptedStorage();
method public deprecated boolean isDeviceEncryptedStorage();
method public deprecated boolean migrateDatabaseFrom(android.content.Context, java.lang.String);
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index ca19b9b..15cc17d 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -691,6 +691,7 @@
*
* @see #getSharedPreferencesPath(String)
* @see #MODE_PRIVATE
+ * @removed
*/
public abstract SharedPreferences getSharedPreferences(File file, int mode);
@@ -813,17 +814,16 @@
* to get a path.
* @return An absolute path to the given file.
* @see #getSharedPreferences(String, int)
+ * @removed
*/
public abstract File getSharedPreferencesPath(String name);
/**
* Returns the absolute path to the directory on the filesystem where all
- * private files belonging to this app are stored. This is the top-level
- * directory under which {@link #getFilesDir()}, {@link #getCacheDir()}, etc
- * are contained. Apps should <em>not</em> create any files or directories
- * as direct children of this directory, since it's a reserved namespace
- * belonging to the platform. Instead, use {@link #getDir(String, int)} or
- * other storage APIs.
+ * private files belonging to this app are stored. Apps should not use this
+ * path directly; they should instead use {@link #getFilesDir()},
+ * {@link #getCacheDir()}, {@link #getDir(String, int)}, or other storage
+ * APIs on this class.
* <p>
* The returned path may change over time if the calling app is moved to an
* adopted storage device, so only relative paths should be persisted.
@@ -831,7 +831,7 @@
* No additional permissions are required for the calling app to read or
* write files under the returned path.
*
- * @see #getDir(String, int)
+ * @see ApplicationInfo#dataDir
*/
public abstract File getDataDir();
@@ -4168,7 +4168,7 @@
* Return a new Context object for the current Context but whose storage
* APIs are backed by device-protected storage.
* <p>
- * When a device is encrypted, data stored in this location is encrypted
+ * On devices with direct boot, data stored in this location is encrypted
* with a key tied to the physical device, and it can be accessed
* immediately after the device has booted successfully, both
* <em>before and after</em> the user has authenticated with their
@@ -4206,7 +4206,7 @@
* storage area for apps unless
* {@link android.R.attr#defaultToDeviceProtectedStorage} was requested.
* <p>
- * When a device is encrypted, data stored in this location is encrypted
+ * On devices with direct boot, data stored in this location is encrypted
* with a key tied to user credentials, which can be accessed
* <em>only after</em> the user has entered their credentials (such as a
* lock pattern or PIN).
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 09aad3b..57ab7a2 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -23,12 +23,14 @@
import android.annotation.SystemApi;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
+import android.content.pm.ComponentInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.Rect;
import android.net.Uri;
+import android.os.Build;
import android.os.Bundle;
import android.os.IBinder;
import android.os.Parcel;
@@ -1946,31 +1948,48 @@
public static final String ACTION_ALARM_CHANGED = "android.intent.action.ALARM_CHANGED";
/**
- * Broadcast Action: This is broadcast once, after the system has finished
- * booting and the user is in a "locked" state. A user is locked when their
- * credential-encrypted private app data storage is unavailable. Once the
- * user has entered their credentials (such as a lock pattern or PIN) for
- * the first time, the {@link #ACTION_BOOT_COMPLETED} broadcast will be
- * sent.
+ * Broadcast Action: This is broadcast once, after the user has finished
+ * booting, but while still in the "locked" state. It can be used to perform
+ * application-specific initialization, such as installing alarms. You must
+ * hold the {@link android.Manifest.permission#RECEIVE_BOOT_COMPLETED}
+ * permission in order to receive this broadcast.
* <p>
- * You must hold the
- * {@link android.Manifest.permission#RECEIVE_BOOT_COMPLETED} permission in
- * order to receive this broadcast.
+ * This broadcast is sent immediately at boot by all devices (regardless of
+ * direct boot support) running {@link android.os.Build.VERSION_CODES#N} or
+ * higher. Upon receipt of this broadcast, the user is still locked and only
+ * device-protected storage can be accessed safely. If you want to access
+ * credential-protected storage, you need to wait for the user to be
+ * unlocked (typically by entering their lock pattern or PIN for the first
+ * time), after which the {@link #ACTION_USER_UNLOCKED} and
+ * {@link #ACTION_BOOT_COMPLETED} broadcasts are sent.
+ * <p>
+ * To receive this broadcast, your receiver component must be marked as
+ * being {@link ComponentInfo#directBootAware}.
* <p class="note">
* This is a protected intent that can only be sent by the system.
+ *
+ * @see Context#createDeviceProtectedStorageContext()
*/
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String ACTION_LOCKED_BOOT_COMPLETED = "android.intent.action.LOCKED_BOOT_COMPLETED";
/**
- * Broadcast Action: This is broadcast once, after the system has finished
- * booting. It can be used to perform application-specific initialization,
- * such as installing alarms. You must hold the
- * {@link android.Manifest.permission#RECEIVE_BOOT_COMPLETED} permission
- * in order to receive this broadcast.
- *
- * <p class="note">This is a protected intent that can only be sent
- * by the system.
+ * Broadcast Action: This is broadcast once, after the user has finished
+ * booting. It can be used to perform application-specific initialization,
+ * such as installing alarms. You must hold the
+ * {@link android.Manifest.permission#RECEIVE_BOOT_COMPLETED} permission in
+ * order to receive this broadcast.
+ * <p>
+ * This broadcast is sent at boot by all devices (both with and without
+ * direct boot support). Upon receipt of this broadcast, the user is
+ * unlocked and both device-protected and credential-protected storage can
+ * accessed safely.
+ * <p>
+ * If you need to run while the user is still locked (before they've entered
+ * their lock pattern or PIN for the first time), you can listen for the
+ * {@link #ACTION_LOCKED_BOOT_COMPLETED} broadcast.
+ * <p class="note">
+ * This is a protected intent that can only be sent by the system.
*/
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String ACTION_BOOT_COMPLETED = "android.intent.action.BOOT_COMPLETED";
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 1079f97..e89cbd7 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -2593,12 +2593,15 @@
public abstract Intent getLeanbackLaunchIntentForPackage(String packageName);
/**
- * Return an array of all of the secondary group-ids that have been assigned
- * to a package.
+ * Return an array of all of the POSIX secondary group IDs that have been
+ * assigned to the given package.
+ * <p>
+ * Note that the same package may have different GIDs under different
+ * {@link UserHandle} on the same device.
*
* @param packageName The full name (i.e. com.google.apps.contacts) of the
- * desired package.
- * @return Returns an int array of the assigned gids, or null if there are
+ * desired package.
+ * @return Returns an int array of the assigned GIDs, or null if there are
* none.
* @throws NameNotFoundException if a package with the given name cannot be
* found on the system.
@@ -2607,8 +2610,11 @@
throws NameNotFoundException;
/**
- * Return an array of all of the secondary group-ids that have been assigned
- * to a package.
+ * Return an array of all of the POSIX secondary group IDs that have been
+ * assigned to the given package.
+ * <p>
+ * Note that the same package may have different GIDs under different
+ * {@link UserHandle} on the same device.
*
* @param packageName The full name (i.e. com.google.apps.contacts) of the
* desired package.
@@ -2622,6 +2628,9 @@
/**
* Return the UID associated with the given package name.
+ * <p>
+ * Note that the same package will have different UIDs under different
+ * {@link UserHandle} on the same device.
*
* @param packageName The full name (i.e. com.google.apps.contacts) of the
* desired package.
@@ -2634,6 +2643,9 @@
/**
* Return the UID associated with the given package name.
+ * <p>
+ * Note that the same package will have different UIDs under different
+ * {@link UserHandle} on the same device.
*
* @param packageName The full name (i.e. com.google.apps.contacts) of the
* desired package.
@@ -2648,6 +2660,9 @@
/**
* Return the UID associated with the given package name.
+ * <p>
+ * Note that the same package will have different UIDs under different
+ * {@link UserHandle} on the same device.
*
* @param packageName The full name (i.e. com.google.apps.contacts) of the
* desired package.
diff --git a/core/java/android/os/DeadSystemException.java b/core/java/android/os/DeadSystemException.java
index 595365c..8fb53e2 100644
--- a/core/java/android/os/DeadSystemException.java
+++ b/core/java/android/os/DeadSystemException.java
@@ -18,7 +18,7 @@
/**
* The core Android system has died and is going through a runtime restart. All
- * running apps will be promptly be killed.
+ * running apps will be promptly killed.
*/
public class DeadSystemException extends DeadObjectException {
public DeadSystemException() {
diff --git a/core/java/android/os/Environment.java b/core/java/android/os/Environment.java
index 307bd2d..f6e8940 100644
--- a/core/java/android/os/Environment.java
+++ b/core/java/android/os/Environment.java
@@ -34,6 +34,7 @@
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";
+ private static final String ENV_ANDROID_EXPAND = "ANDROID_EXPAND";
private static final String ENV_ANDROID_STORAGE = "ANDROID_STORAGE";
private static final String ENV_DOWNLOAD_CACHE = "DOWNLOAD_CACHE";
private static final String ENV_OEM_ROOT = "OEM_ROOT";
@@ -54,6 +55,7 @@
private static final File DIR_ANDROID_ROOT = getDirectory(ENV_ANDROID_ROOT, "/system");
private static final File DIR_ANDROID_DATA = getDirectory(ENV_ANDROID_DATA, "/data");
+ 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_OEM_ROOT = getDirectory(ENV_OEM_ROOT, "/oem");
@@ -229,6 +231,11 @@
}
/** {@hide} */
+ public static File getExpandDirectory() {
+ return DIR_ANDROID_EXPAND;
+ }
+
+ /** {@hide} */
public static File getDataSystemDirectory() {
return new File(getDataDirectory(), "system");
}
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index 92e1862..0ff0154 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -918,11 +918,15 @@
}
/**
- * Return whether the calling user is running in an "unlocked" state. A user
- * is unlocked only after they've entered their credentials (such as a lock
- * pattern or PIN), and credential-encrypted private app data storage is
- * available. When a user is locked, only device-protected data storage is
- * available.
+ * Return whether the calling user is running in an "unlocked" state.
+ * <p>
+ * On devices with direct boot, a user is unlocked only after they've
+ * entered their credentials (such as a lock pattern or PIN). On devices
+ * without direct boot, a user is unlocked as soon as it starts.
+ * <p>
+ * When a user is locked, only device-protected data storage is available.
+ * When a user is unlocked, both device-protected and credential-protected
+ * private app data storage is available.
*
* @see Intent#ACTION_USER_UNLOCKED
* @see Context#createDeviceProtectedStorageContext()
@@ -932,11 +936,15 @@
}
/**
- * Return whether the given user is running in an "unlocked" state. A user
- * is unlocked only after they've entered their credentials (such as a lock
- * pattern or PIN), and credential-protected private app data storage is
- * available. When a user is locked, only device-protected data storage is
- * available.
+ * Return whether the given user is running in an "unlocked" state.
+ * <p>
+ * On devices with direct boot, a user is unlocked only after they've
+ * entered their credentials (such as a lock pattern or PIN). On devices
+ * without direct boot, a user is unlocked as soon as it starts.
+ * <p>
+ * When a user is locked, only device-protected data storage is available.
+ * When a user is unlocked, both device-protected and credential-protected
+ * private app data storage is available.
*
* @param user to retrieve the unlocked state for.
* @see Intent#ACTION_USER_UNLOCKED
diff --git a/core/java/android/os/storage/StorageManager.java b/core/java/android/os/storage/StorageManager.java
index 61e6b95..22aec63 100644
--- a/core/java/android/os/storage/StorageManager.java
+++ b/core/java/android/os/storage/StorageManager.java
@@ -35,6 +35,7 @@
import android.os.ServiceManager;
import android.os.SystemProperties;
import android.provider.Settings;
+import android.security.KeyStore;
import android.text.TextUtils;
import android.util.Log;
import android.util.Slog;
@@ -1025,6 +1026,20 @@
}
}
+ /**
+ * Return if data stored at the given path will be encrypted while at rest.
+ * This can help apps avoid the overhead of double-encrypting data.
+ */
+ public boolean isEncrypted(File file) {
+ if (FileUtils.contains(Environment.getDataDirectory(), file)) {
+ return isEncrypted();
+ } else if (FileUtils.contains(Environment.getExpandDirectory(), file)) {
+ return true;
+ }
+ // TODO: extend to support shared storage
+ return false;
+ }
+
/** {@hide}
* Is this device encryptable or already encrypted?
* @return true for encryptable or encrypted
diff --git a/core/java/android/preference/PreferenceManager.java b/core/java/android/preference/PreferenceManager.java
index c36680c..47dc6c3 100644
--- a/core/java/android/preference/PreferenceManager.java
+++ b/core/java/android/preference/PreferenceManager.java
@@ -362,8 +362,7 @@
* Explicitly set the storage location used internally by this class to be
* device-protected storage.
* <p>
- * <p>
- * When a device is encrypted, data stored in this location is encrypted
+ * On devices with direct boot, data stored in this location is encrypted
* with a key tied to the physical device, and it can be accessed
* immediately after the device has booted successfully, both
* <em>before and after</em> the user has authenticated with their
@@ -392,7 +391,7 @@
* credential-protected storage. This is the default storage area for apps
* unless {@code forceDeviceProtectedStorage} was requested.
* <p>
- * When a device is encrypted, data stored in this location is encrypted
+ * On devices with direct boot, data stored in this location is encrypted
* with a key tied to user credentials, which can be accessed
* <em>only after</em> the user has entered their credentials (such as a
* lock pattern or PIN).