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/api/current.txt b/api/current.txt
index d330dad..5eb08da 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -9062,6 +9062,7 @@
     field public android.content.pm.ApplicationInfo applicationInfo;
     field public int descriptionRes;
     field public boolean enabled;
+    field public boolean encryptionAware;
     field public boolean exported;
     field public java.lang.String processName;
   }
@@ -9483,6 +9484,7 @@
     field public static final int GET_CONFIGURATIONS = 16384; // 0x4000
     field public static final int GET_DISABLED_COMPONENTS = 512; // 0x200
     field public static final int GET_DISABLED_UNTIL_USED_COMPONENTS = 32768; // 0x8000
+    field public static final int GET_ENCRYPTION_UNAWARE_COMPONENTS = 262144; // 0x40000
     field public static final int GET_GIDS = 256; // 0x100
     field public static final int GET_INSTRUMENTATION = 16; // 0x10
     field public static final int GET_INTENT_FILTERS = 32; // 0x20
diff --git a/api/system-current.txt b/api/system-current.txt
index f101856..dd2e67d 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -9322,6 +9322,7 @@
     field public android.content.pm.ApplicationInfo applicationInfo;
     field public int descriptionRes;
     field public boolean enabled;
+    field public boolean encryptionAware;
     field public boolean exported;
     field public java.lang.String processName;
   }
@@ -9780,6 +9781,7 @@
     field public static final int GET_CONFIGURATIONS = 16384; // 0x4000
     field public static final int GET_DISABLED_COMPONENTS = 512; // 0x200
     field public static final int GET_DISABLED_UNTIL_USED_COMPONENTS = 32768; // 0x8000
+    field public static final int GET_ENCRYPTION_UNAWARE_COMPONENTS = 262144; // 0x40000
     field public static final int GET_GIDS = 256; // 0x100
     field public static final int GET_INSTRUMENTATION = 16; // 0x10
     field public static final int GET_INTENT_FILTERS = 32; // 0x20
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 fcc040b..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
diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java
index 1ff13b2..9ac4ba3 100644
--- a/services/core/java/com/android/server/accounts/AccountManagerService.java
+++ b/services/core/java/com/android/server/accounts/AccountManagerService.java
@@ -980,7 +980,7 @@
             if (user.isRestricted() && (parentUserId == user.restrictedProfileParentId)) {
                 addSharedAccountAsUser(account, user.id);
                 try {
-                    if (ActivityManagerNative.getDefault().isUserRunning(user.id, false)) {
+                    if (ActivityManagerNative.getDefault().isUserRunning(user.id, 0)) {
                         mMessageHandler.sendMessage(mMessageHandler.obtainMessage(
                                 MESSAGE_COPY_SHARED_ACCOUNT, parentUserId, user.id, account));
                     }
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index befaaef..2820216 100755
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -2334,7 +2334,7 @@
                         sr.userId, sr.crashCount, sr.shortName, app.pid);
                 bringDownServiceLocked(sr);
             } else if (!allowRestart
-                    || !mAm.mUserController.isUserRunningLocked(sr.userId, false)) {
+                    || !mAm.mUserController.isUserRunningLocked(sr.userId, 0)) {
                 bringDownServiceLocked(sr);
             } else {
                 boolean canceled = scheduleServiceRestartLocked(sr, true);
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 13401cd..4998b57 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -5328,7 +5328,7 @@
                         Slog.w(TAG, "Failed trying to unstop package "
                                 + packageName + ": " + e);
                     }
-                    if (mUserController.isUserRunningLocked(user, false)) {
+                    if (mUserController.isUserRunningLocked(user, 0)) {
                         forceStopPackageLocked(packageName, pkgUid, "from pid " + callingPid);
                     }
                 }
@@ -9812,7 +9812,7 @@
 
                 // Make sure that the user who owns this provider is running.  If not,
                 // we don't want to allow it to run.
-                if (!mUserController.isUserRunningLocked(userId, false)) {
+                if (!mUserController.isUserRunningLocked(userId, 0)) {
                     Slog.w(TAG, "Unable to launch app "
                             + cpi.applicationInfo.packageName + "/"
                             + cpi.applicationInfo.uid + " for provider "
@@ -16640,7 +16640,7 @@
         // If not, we will just skip it. Make an exception for shutdown broadcasts
         // and upgrade steps.
 
-        if (userId != UserHandle.USER_ALL && !mUserController.isUserRunningLocked(userId, false)) {
+        if (userId != UserHandle.USER_ALL && !mUserController.isUserRunningLocked(userId, 0)) {
             if ((callingUid != Process.SYSTEM_UID
                     || (intent.getFlags() & Intent.FLAG_RECEIVER_BOOT_UPGRADE) == 0)
                     && !Intent.ACTION_SHUTDOWN.equals(intent.getAction())) {
@@ -19991,7 +19991,7 @@
     }
 
     @Override
-    public boolean isUserRunning(int userId, boolean orStopped) {
+    public boolean isUserRunning(int userId, int flags) {
         if (checkCallingPermission(INTERACT_ACROSS_USERS)
                 != PackageManager.PERMISSION_GRANTED) {
             String msg = "Permission Denial: isUserRunning() from pid="
@@ -20002,7 +20002,7 @@
             throw new SecurityException(msg);
         }
         synchronized (this) {
-            return mUserController.isUserRunningLocked(userId, orStopped);
+            return mUserController.isUserRunningLocked(userId, flags);
         }
     }
 
diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java
index 4085489..cbc13fe 100644
--- a/services/core/java/com/android/server/am/UserController.java
+++ b/services/core/java/com/android/server/am/UserController.java
@@ -947,14 +947,18 @@
         return mStartedUserArray;
     }
 
-    boolean isUserRunningLocked(int userId, boolean orStopped) {
+    boolean isUserRunningLocked(int userId, int flags) {
         UserState state = getStartedUserStateLocked(userId);
         if (state == null) {
             return false;
         }
-        if (orStopped) {
+        if ((flags & ActivityManager.FLAG_OR_STOPPED) != 0) {
             return true;
         }
+        if ((flags & ActivityManager.FLAG_WITH_AMNESIA) != 0) {
+            // TODO: add in amnesia lifecycle
+            return false;
+        }
         return state.mState != UserState.STATE_STOPPING
                 && state.mState != UserState.STATE_SHUTDOWN;
     }
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 11fa38c..09efefa 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -3053,15 +3053,40 @@
         }
     }
 
+    /**
+     * Augment the given flags depending on current user running state. This is
+     * purposefully done before acquiring {@link #mPackages} lock.
+     */
+    private int augmentFlagsForUser(int flags, int userId) {
+        final IActivityManager am = ActivityManagerNative.getDefault();
+        if (am == null) {
+            // We must be early in boot, so the best we can do is assume the
+            // user is fully running.
+            return flags;
+        }
+        final long token = Binder.clearCallingIdentity();
+        try {
+            if (am.isUserRunning(userId, ActivityManager.FLAG_WITH_AMNESIA)) {
+                flags |= PackageManager.FLAG_USER_RUNNING_WITH_AMNESIA;
+            }
+        } catch (RemoteException e) {
+            throw e.rethrowAsRuntimeException();
+        } finally {
+            Binder.restoreCallingIdentity(token);
+        }
+        return flags;
+    }
+
     @Override
     public ActivityInfo getActivityInfo(ComponentName component, int flags, int userId) {
         if (!sUserManager.exists(userId)) return null;
+        flags = augmentFlagsForUser(flags, userId);
         enforceCrossUserPermission(Binder.getCallingUid(), userId, false, false, "get activity info");
         synchronized (mPackages) {
             PackageParser.Activity a = mActivities.mActivities.get(component);
 
             if (DEBUG_PACKAGE_INFO) Log.v(TAG, "getActivityInfo " + component + ": " + a);
-            if (a != null && mSettings.isEnabledLPr(a.info, flags, userId)) {
+            if (a != null && mSettings.isEnabledAndVisibleLPr(a.info, flags, userId)) {
                 PackageSetting ps = mSettings.mPackages.get(component.getPackageName());
                 if (ps == null) return null;
                 return PackageParser.generateActivityInfo(a, flags, ps.readUserState(userId),
@@ -3100,12 +3125,13 @@
     @Override
     public ActivityInfo getReceiverInfo(ComponentName component, int flags, int userId) {
         if (!sUserManager.exists(userId)) return null;
+        flags = augmentFlagsForUser(flags, userId);
         enforceCrossUserPermission(Binder.getCallingUid(), userId, false, false, "get receiver info");
         synchronized (mPackages) {
             PackageParser.Activity a = mReceivers.mActivities.get(component);
             if (DEBUG_PACKAGE_INFO) Log.v(
                 TAG, "getReceiverInfo " + component + ": " + a);
-            if (a != null && mSettings.isEnabledLPr(a.info, flags, userId)) {
+            if (a != null && mSettings.isEnabledAndVisibleLPr(a.info, flags, userId)) {
                 PackageSetting ps = mSettings.mPackages.get(component.getPackageName());
                 if (ps == null) return null;
                 return PackageParser.generateActivityInfo(a, flags, ps.readUserState(userId),
@@ -3118,12 +3144,13 @@
     @Override
     public ServiceInfo getServiceInfo(ComponentName component, int flags, int userId) {
         if (!sUserManager.exists(userId)) return null;
+        flags = augmentFlagsForUser(flags, userId);
         enforceCrossUserPermission(Binder.getCallingUid(), userId, false, false, "get service info");
         synchronized (mPackages) {
             PackageParser.Service s = mServices.mServices.get(component);
             if (DEBUG_PACKAGE_INFO) Log.v(
                 TAG, "getServiceInfo " + component + ": " + s);
-            if (s != null && mSettings.isEnabledLPr(s.info, flags, userId)) {
+            if (s != null && mSettings.isEnabledAndVisibleLPr(s.info, flags, userId)) {
                 PackageSetting ps = mSettings.mPackages.get(component.getPackageName());
                 if (ps == null) return null;
                 return PackageParser.generateServiceInfo(s, flags, ps.readUserState(userId),
@@ -3136,12 +3163,13 @@
     @Override
     public ProviderInfo getProviderInfo(ComponentName component, int flags, int userId) {
         if (!sUserManager.exists(userId)) return null;
+        flags = augmentFlagsForUser(flags, userId);
         enforceCrossUserPermission(Binder.getCallingUid(), userId, false, false, "get provider info");
         synchronized (mPackages) {
             PackageParser.Provider p = mProviders.mProviders.get(component);
             if (DEBUG_PACKAGE_INFO) Log.v(
                 TAG, "getProviderInfo " + component + ": " + p);
-            if (p != null && mSettings.isEnabledLPr(p.info, flags, userId)) {
+            if (p != null && mSettings.isEnabledAndVisibleLPr(p.info, flags, userId)) {
                 PackageSetting ps = mSettings.mPackages.get(component.getPackageName());
                 if (ps == null) return null;
                 return PackageParser.generateProviderInfo(p, flags, ps.readUserState(userId),
@@ -4233,6 +4261,7 @@
     public ResolveInfo resolveIntent(Intent intent, String resolvedType,
             int flags, int userId) {
         if (!sUserManager.exists(userId)) return null;
+        flags = augmentFlagsForUser(flags, userId);
         enforceCrossUserPermission(Binder.getCallingUid(), userId, false, false, "resolve intent");
         List<ResolveInfo> query = queryIntentActivities(intent, resolvedType, flags, userId);
         return chooseBestActivity(intent, resolvedType, flags, query, userId);
@@ -4374,10 +4403,12 @@
         return null;
     }
 
+    // TODO: handle preferred activities missing while user has amnesia
     ResolveInfo findPreferredActivity(Intent intent, String resolvedType, int flags,
             List<ResolveInfo> query, int priority, boolean always,
             boolean removeMatches, boolean debug, int userId) {
         if (!sUserManager.exists(userId)) return null;
+        flags = augmentFlagsForUser(flags, userId);
         // writer
         synchronized (mPackages) {
             if (intent.getSelector() != null) {
@@ -4576,6 +4607,7 @@
     public List<ResolveInfo> queryIntentActivities(Intent intent,
             String resolvedType, int flags, int userId) {
         if (!sUserManager.exists(userId)) return Collections.emptyList();
+        flags = augmentFlagsForUser(flags, userId);
         enforceCrossUserPermission(Binder.getCallingUid(), userId, false, false, "query intent activities");
         ComponentName comp = intent.getComponent();
         if (comp == null) {
@@ -5041,6 +5073,7 @@
             Intent[] specifics, String[] specificTypes, Intent intent,
             String resolvedType, int flags, int userId) {
         if (!sUserManager.exists(userId)) return Collections.emptyList();
+        flags = augmentFlagsForUser(flags, userId);
         enforceCrossUserPermission(Binder.getCallingUid(), userId, false,
                 false, "query intent activity options");
         final String resultsAction = intent.getAction();
@@ -5213,6 +5246,7 @@
     public List<ResolveInfo> queryIntentReceivers(Intent intent, String resolvedType, int flags,
             int userId) {
         if (!sUserManager.exists(userId)) return Collections.emptyList();
+        flags = augmentFlagsForUser(flags, userId);
         ComponentName comp = intent.getComponent();
         if (comp == null) {
             if (intent.getSelector() != null) {
@@ -5248,8 +5282,9 @@
 
     @Override
     public ResolveInfo resolveService(Intent intent, String resolvedType, int flags, int userId) {
-        List<ResolveInfo> query = queryIntentServices(intent, resolvedType, flags, userId);
         if (!sUserManager.exists(userId)) return null;
+        flags = augmentFlagsForUser(flags, userId);
+        List<ResolveInfo> query = queryIntentServices(intent, resolvedType, flags, userId);
         if (query != null) {
             if (query.size() >= 1) {
                 // If there is more than one service with the same priority,
@@ -5264,6 +5299,7 @@
     public List<ResolveInfo> queryIntentServices(Intent intent, String resolvedType, int flags,
             int userId) {
         if (!sUserManager.exists(userId)) return Collections.emptyList();
+        flags = augmentFlagsForUser(flags, userId);
         ComponentName comp = intent.getComponent();
         if (comp == null) {
             if (intent.getSelector() != null) {
@@ -5301,6 +5337,7 @@
     public List<ResolveInfo> queryIntentContentProviders(
             Intent intent, String resolvedType, int flags, int userId) {
         if (!sUserManager.exists(userId)) return Collections.emptyList();
+        flags = augmentFlagsForUser(flags, userId);
         ComponentName comp = intent.getComponent();
         if (comp == null) {
             if (intent.getSelector() != null) {
@@ -5417,6 +5454,7 @@
     public ParceledListSlice<PackageInfo> getPackagesHoldingPermissions(
             String[] permissions, int flags, int userId) {
         if (!sUserManager.exists(userId)) return null;
+        flags = augmentFlagsForUser(flags, userId);
         final boolean listUninstalled = (flags & PackageManager.GET_UNINSTALLED_PACKAGES) != 0;
 
         // writer
@@ -5444,6 +5482,7 @@
     @Override
     public ParceledListSlice<ApplicationInfo> getInstalledApplications(int flags, int userId) {
         if (!sUserManager.exists(userId)) return null;
+        flags = augmentFlagsForUser(flags, userId);
         final boolean listUninstalled = (flags & PackageManager.GET_UNINSTALLED_PACKAGES) != 0;
 
         // writer
@@ -5510,6 +5549,7 @@
     @Override
     public ProviderInfo resolveContentProvider(String name, int flags, int userId) {
         if (!sUserManager.exists(userId)) return null;
+        flags = augmentFlagsForUser(flags, userId);
         // reader
         synchronized (mPackages) {
             final PackageParser.Provider provider = mProvidersByAuthority.get(name);
@@ -5517,7 +5557,7 @@
                     ? mSettings.mPackages.get(provider.owner.packageName)
                     : null;
             return ps != null
-                    && mSettings.isEnabledLPr(provider.info, flags, userId)
+                    && mSettings.isEnabledAndVisibleLPr(provider.info, flags, userId)
                     && (!mSafeMode || (provider.info.applicationInfo.flags
                             &ApplicationInfo.FLAG_SYSTEM) != 0)
                     ? PackageParser.generateProviderInfo(provider, flags,
@@ -5558,12 +5598,15 @@
     @Override
     public ParceledListSlice<ProviderInfo> queryContentProviders(String processName,
             int uid, int flags) {
+        final int userId = processName != null ? UserHandle.getUserId(uid)
+                : UserHandle.getCallingUserId();
+        if (!sUserManager.exists(userId)) return null;
+        flags = augmentFlagsForUser(flags, userId);
+
         ArrayList<ProviderInfo> finalList = null;
         // reader
         synchronized (mPackages) {
             final Iterator<PackageParser.Provider> i = mProviders.mProviders.values().iterator();
-            final int userId = processName != null ?
-                    UserHandle.getUserId(uid) : UserHandle.getCallingUserId();
             while (i.hasNext()) {
                 final PackageParser.Provider p = i.next();
                 PackageSetting ps = mSettings.mPackages.get(p.owner.packageName);
@@ -5571,7 +5614,7 @@
                         && (processName == null
                                 || (p.info.processName.equals(processName)
                                         && UserHandle.isSameApp(p.info.applicationInfo.uid, uid)))
-                        && mSettings.isEnabledLPr(p.info, flags, userId)
+                        && mSettings.isEnabledAndVisibleLPr(p.info, flags, userId)
                         && (!mSafeMode
                                 || (p.info.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0)) {
                     if (finalList == null) {
@@ -8975,7 +9018,7 @@
         protected ResolveInfo newResult(PackageParser.ActivityIntentInfo info,
                 int match, int userId) {
             if (!sUserManager.exists(userId)) return null;
-            if (!mSettings.isEnabledLPr(info.activity.info, mFlags, userId)) {
+            if (!mSettings.isEnabledAndVisibleLPr(info.activity.info, mFlags, userId)) {
                 return null;
             }
             final PackageParser.Activity activity = info.activity;
@@ -9199,7 +9242,7 @@
                 int match, int userId) {
             if (!sUserManager.exists(userId)) return null;
             final PackageParser.ServiceIntentInfo info = (PackageParser.ServiceIntentInfo)filter;
-            if (!mSettings.isEnabledLPr(info.service.info, mFlags, userId)) {
+            if (!mSettings.isEnabledAndVisibleLPr(info.service.info, mFlags, userId)) {
                 return null;
             }
             final PackageParser.Service service = info.service;
@@ -9422,7 +9465,7 @@
             if (!sUserManager.exists(userId))
                 return null;
             final PackageParser.ProviderIntentInfo info = filter;
-            if (!mSettings.isEnabledLPr(info.provider.info, mFlags, userId)) {
+            if (!mSettings.isEnabledAndVisibleLPr(info.provider.info, mFlags, userId)) {
                 return null;
             }
             final PackageParser.Provider provider = info.provider;
@@ -9761,7 +9804,7 @@
             IActivityManager am = ActivityManagerNative.getDefault();
             final boolean isSystem =
                     isSystemApp(pkgSetting) || isUpdatedSystemApp(pkgSetting);
-            if (isSystem && am.isUserRunning(userId, false)) {
+            if (isSystem && am.isUserRunning(userId, 0)) {
                 // The just-installed/enabled app is bundled on the system, so presumed
                 // to be able to run automatically without needing an explicit launch.
                 // Send it a BOOT_COMPLETED if it would ordinarily have gotten one.
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index 8b99305..de14739 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -2248,7 +2248,8 @@
 
             StringBuilder sb = new StringBuilder();
             for (final PackageSetting pkg : mPackages.values()) {
-                if (pkg.pkg == null || pkg.pkg.applicationInfo == null) {
+                if (pkg.pkg == null || pkg.pkg.applicationInfo == null
+                        || pkg.pkg.applicationInfo.dataDir == null) {
                     Slog.w(TAG, "Skipping " + pkg + " due to missing metadata");
                     continue;
                 }
@@ -3750,8 +3751,13 @@
     private String compToString(ArraySet<String> cmp) {
         return cmp != null ? Arrays.toString(cmp.toArray()) : "[]";
     }
- 
-    boolean isEnabledLPr(ComponentInfo componentInfo, int flags, int userId) {
+
+    boolean isEnabledAndVisibleLPr(ComponentInfo componentInfo, int flags, int userId) {
+        return isEnabledLPr(componentInfo, flags, userId)
+                && isVisibleLPr(componentInfo, flags);
+    }
+
+    private boolean isEnabledLPr(ComponentInfo componentInfo, int flags, int userId) {
         if ((flags&PackageManager.GET_DISABLED_COMPONENTS) != 0) {
             return true;
         }
@@ -3792,6 +3798,17 @@
         return componentInfo.enabled;
     }
 
+    private boolean isVisibleLPr(ComponentInfo componentInfo, int flags) {
+        if ((flags & PackageManager.GET_ENCRYPTION_UNAWARE_COMPONENTS) != 0) {
+            return true;
+        }
+        if ((flags & PackageManager.FLAG_USER_RUNNING_WITH_AMNESIA) != 0) {
+            // When running with amnesia, we can only run encryption-aware apps
+            return componentInfo.encryptionAware;
+        }
+        return true;
+    }
+
     String getInstallerPackageNameLPr(String packageName) {
         final PackageSetting pkg = mPackages.get(packageName);
         if (pkg == null) {
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 0fb82b3..a6a34af 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -2283,7 +2283,7 @@
         } else {
             pw.println("Users:");
             for (int i = 0; i < users.size(); i++) {
-                String running = am.isUserRunning(users.get(i).id, false) ? " running" : "";
+                String running = am.isUserRunning(users.get(i).id, 0) ? " running" : "";
                 pw.println("\t" + users.get(i).toString() + running);
             }
             return 0;