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).