More APIs for encryption-aware apps.

Apps can mark manifest components as being encryption-aware, which
means they can safely be run before the credential encrypted storage
is available.

Start adding filtering logic so that we only return these components
when a user is running "with amnesia."  That is to say, only device
encrypted storage is available, so the user is running but with only
partial knowledge of its data.

To avoid calling into ActivityManager with the PackageManager lock
held, we quickly determine user state and splice the state into the
flags for later per-component evaluation.

Bug: 22358539
Change-Id: Idc56ec29f1ef04da8963e004314d7f5e47400997
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index b809baa..ac54960 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -2952,6 +2952,11 @@
         }
     }
 
+    /** {@hide} */
+    public static final int FLAG_OR_STOPPED = 1 << 0;
+    /** {@hide} */
+    public static final int FLAG_WITH_AMNESIA = 1 << 1;
+
     /**
      * Return whether the given user is actively running.  This means that
      * the user is in the "started" state, not "stopped" -- it is currently
@@ -2963,7 +2968,7 @@
      */
     public boolean isUserRunning(int userid) {
         try {
-            return ActivityManagerNative.getDefault().isUserRunning(userid, false);
+            return ActivityManagerNative.getDefault().isUserRunning(userid, 0);
         } catch (RemoteException e) {
             return false;
         }
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index 2ac6cf9..4449e4f 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -1984,8 +1984,8 @@
         case IS_USER_RUNNING_TRANSACTION: {
             data.enforceInterface(IActivityManager.descriptor);
             int userid = data.readInt();
-            boolean orStopping = data.readInt() != 0;
-            boolean result = isUserRunning(userid, orStopping);
+            int _flags = data.readInt();
+            boolean result = isUserRunning(userid, _flags);
             reply.writeNoException();
             reply.writeInt(result ? 1 : 0);
             return true;
@@ -5265,12 +5265,12 @@
         return userInfo;
     }
 
-    public boolean isUserRunning(int userid, boolean orStopping) throws RemoteException {
+    public boolean isUserRunning(int userid, int flags) throws RemoteException {
         Parcel data = Parcel.obtain();
         Parcel reply = Parcel.obtain();
         data.writeInterfaceToken(IActivityManager.descriptor);
         data.writeInt(userid);
-        data.writeInt(orStopping ? 1 : 0);
+        data.writeInt(flags);
         mRemote.transact(IS_USER_RUNNING_TRANSACTION, data, reply, 0);
         reply.readException();
         boolean result = reply.readInt() != 0;
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index fcc040b3..b69a480 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -392,7 +392,7 @@
     public boolean startUserInBackground(int userid) throws RemoteException;
     public int stopUser(int userid, IStopUserCallback callback) throws RemoteException;
     public UserInfo getCurrentUser() throws RemoteException;
-    public boolean isUserRunning(int userid, boolean orStopping) throws RemoteException;
+    public boolean isUserRunning(int userid, int flags) throws RemoteException;
     public int[] getRunningUserIds() throws RemoteException;
 
     public boolean removeTask(int taskId) throws RemoteException;
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index 6bc2ac3..52c2f9b 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -466,7 +466,7 @@
      *
      * @hide
      */
-    public static final int PRIVATE_FLAG_DEVICE_ENCRYPTED = 1 << 5;
+    public static final int PRIVATE_FLAG_FORCE_DEVICE_ENCRYPTED = 1 << 5;
 
     /**
      * Private/hidden flags. See {@code PRIVATE_FLAG_...} constants.
@@ -963,7 +963,7 @@
                 .getDataUserCredentialEncryptedPackageDirectory(volumeUuid, userId, packageName)
                 .getAbsolutePath();
 
-        if ((privateFlags & PRIVATE_FLAG_DEVICE_ENCRYPTED) != 0) {
+        if ((privateFlags & PRIVATE_FLAG_FORCE_DEVICE_ENCRYPTED) != 0) {
             dataDir = deviceEncryptedDataDir;
         } else {
             dataDir = credentialEncryptedDataDir;
diff --git a/core/java/android/content/pm/ComponentInfo.java b/core/java/android/content/pm/ComponentInfo.java
index f27fc2a..ad7ebe5 100644
--- a/core/java/android/content/pm/ComponentInfo.java
+++ b/core/java/android/content/pm/ComponentInfo.java
@@ -63,7 +63,14 @@
      * &lt;provider&gt; tag.
      */
     public boolean exported = false;
-    
+
+    /**
+     * Indicate if this component is aware of encryption lifecycle, and can be
+     * safely run before the user has entered their credentials (such as a lock
+     * pattern or PIN).
+     */
+    public boolean encryptionAware = false;
+
     public ComponentInfo() {
     }
 
@@ -74,6 +81,7 @@
         descriptionRes = orig.descriptionRes;
         enabled = orig.enabled;
         exported = orig.exported;
+        encryptionAware = orig.encryptionAware;
     }
 
     @Override public CharSequence loadLabel(PackageManager pm) {
@@ -143,7 +151,7 @@
     protected void dumpFront(Printer pw, String prefix) {
         super.dumpFront(pw, prefix);
         pw.println(prefix + "enabled=" + enabled + " exported=" + exported
-                + " processName=" + processName);
+                + " encryptionAware=" + encryptionAware + " processName=" + processName);
         if (descriptionRes != 0) {
             pw.println(prefix + "description=" + descriptionRes);
         }
@@ -171,6 +179,7 @@
         dest.writeInt(descriptionRes);
         dest.writeInt(enabled ? 1 : 0);
         dest.writeInt(exported ? 1 : 0);
+        dest.writeInt(encryptionAware ? 1 : 0);
     }
     
     protected ComponentInfo(Parcel source) {
@@ -183,6 +192,7 @@
         descriptionRes = source.readInt();
         enabled = (source.readInt() != 0);
         exported = (source.readInt() != 0);
+        encryptionAware = (source.readInt() != 0);
     }
     
     /**
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index c57fc89..566de4e 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -234,6 +234,24 @@
     public static final int MATCH_ALL = 0x00020000;
 
     /**
+     * {@link PackageInfo} flag: include components which aren't encryption
+     * aware in the returned info, regardless of the current user state.
+     */
+    public static final int GET_ENCRYPTION_UNAWARE_COMPONENTS = 0x00040000;
+
+    /**
+     * {@link PackageInfo} flag: return components as if the given user is
+     * running with amnesia. This typically limits the component to only those
+     * marked as {@link ComponentInfo#encryptionAware}, unless
+     * {@link #GET_ENCRYPTION_UNAWARE_COMPONENTS} is also specified.
+     * <p>
+     * This flag is for internal use only.
+     *
+     * @hide
+     */
+    public static final int FLAG_USER_RUNNING_WITH_AMNESIA = 0x00080000;
+
+    /**
      * Flag for {@link addCrossProfileIntentFilter}: if this flag is set:
      * when resolving an intent that matches the {@link CrossProfileIntentFilter}, the current
      * profile will be skipped.
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 20e76d6..f176d89 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -2632,6 +2632,11 @@
             ai.flags |= ApplicationInfo.FLAG_EXTRACT_NATIVE_LIBS;
         }
 
+        if (sa.getBoolean(R.styleable.AndroidManifestApplication_forceDeviceEncrypted, false)
+                && (flags & PARSE_IS_SYSTEM) != 0) {
+            ai.privateFlags |= ApplicationInfo.PRIVATE_FLAG_FORCE_DEVICE_ENCRYPTED;
+        }
+
         String str;
         str = sa.getNonConfigurationString(
                 com.android.internal.R.styleable.AndroidManifestApplication_permission, 0);
@@ -3229,6 +3234,9 @@
 
             a.info.lockTaskLaunchMode =
                     sa.getInt(R.styleable.AndroidManifestActivity_lockTaskMode, 0);
+
+            a.info.encryptionAware = sa.getBoolean(
+                    R.styleable.AndroidManifestActivity_encryptionAware, false);
         } else {
             a.info.launchMode = ActivityInfo.LAUNCH_MULTIPLE;
             a.info.configChanges = 0;
@@ -3243,6 +3251,9 @@
                     setExported = true;
                 }
             }
+
+            a.info.encryptionAware = sa.getBoolean(
+                    R.styleable.AndroidManifestActivity_encryptionAware, false);
         }
 
         sa.recycle();
@@ -3643,6 +3654,9 @@
             }
         }
 
+        p.info.encryptionAware = sa.getBoolean(
+                R.styleable.AndroidManifestProvider_encryptionAware, false);
+
         sa.recycle();
 
         if ((owner.applicationInfo.privateFlags&ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE)
@@ -3923,6 +3937,9 @@
             }
         }
 
+        s.info.encryptionAware = sa.getBoolean(
+                R.styleable.AndroidManifestService_encryptionAware, false);
+
         sa.recycle();
 
         if ((owner.applicationInfo.privateFlags&ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE)
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index e892349..aff90b7 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -718,7 +718,7 @@
     public boolean isUserRunning(UserHandle user) {
         try {
             return ActivityManagerNative.getDefault().isUserRunning(
-                    user.getIdentifier(), false);
+                    user.getIdentifier(), 0);
         } catch (RemoteException e) {
             return false;
         }
@@ -733,8 +733,9 @@
      */
     public boolean isUserRunningOrStopping(UserHandle user) {
         try {
+            // TODO: reconcile stopped vs stopping?
             return ActivityManagerNative.getDefault().isUserRunning(
-                    user.getIdentifier(), true);
+                    user.getIdentifier(), ActivityManager.FLAG_OR_STOPPED);
         } catch (RemoteException e) {
             return false;
         }
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index 07ac471..184f2ab 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -571,6 +571,11 @@
          single integer, with higher numbers considered to be better. -->
     <attr name="priority" format="integer" />
 
+    <!-- Indicate if this component is aware of encryption lifecycle, and can be
+         safely run before the user has entered their credentials (such as a lock
+         pattern or PIN). -->
+    <attr name="encryptionAware" format="boolean" />
+
     <!-- Specify how an activity should be launched.  See the
          <a href="{@docRoot}guide/topics/fundamentals/tasks-and-back-stack.html">Tasks and Back
          Stack</a> document for important information on how these options impact
@@ -1277,6 +1282,7 @@
         <attr name="usesCleartextTraffic" />
         <attr name="multiArch" />
         <attr name="extractNativeLibs" />
+        <attr name="forceDeviceEncrypted" format="boolean" />
     </declare-styleable>
     <!-- The <code>permission</code> tag declares a security permission that can be
          used to control access from other packages to specific components or
@@ -1652,6 +1658,7 @@
         <attr name="enabled" />
         <attr name="exported" />
         <attr name="singleUser" />
+        <attr name="encryptionAware" />
     </declare-styleable>
 
     <!-- Attributes that can be supplied in an AndroidManifest.xml
@@ -1735,6 +1742,7 @@
              with it is through the Service API (binding and starting). -->
         <attr name="isolatedProcess" format="boolean" />
         <attr name="singleUser" />
+        <attr name="encryptionAware" />
     </declare-styleable>
 
     <!-- The <code>receiver</code> tag declares an
@@ -1770,6 +1778,7 @@
         <attr name="enabled" />
         <attr name="exported" />
         <attr name="singleUser" />
+        <attr name="encryptionAware" />
     </declare-styleable>
 
     <!-- The <code>activity</code> tag declares an
@@ -1842,6 +1851,7 @@
         <attr name="supportsPictureInPicture" />
         <attr name="lockTaskMode" />
         <attr name="showForAllUsers" />
+        <attr name="encryptionAware" />
     </declare-styleable>
 
     <!-- The <code>activity-alias</code> tag declares a new