Merge "Mount storage after unlock, fix leaving emulation."
diff --git a/core/java/android/os/storage/StorageManager.java b/core/java/android/os/storage/StorageManager.java
index db12564..7f36a98 100644
--- a/core/java/android/os/storage/StorageManager.java
+++ b/core/java/android/os/storage/StorageManager.java
@@ -1021,8 +1021,17 @@
 
     /** {@hide} */
     public static boolean isFileBasedEncryptionEnabled() {
-        return "file".equals(SystemProperties.get("ro.crypto.type", "none"))
-                || SystemProperties.getBoolean(StorageManager.PROP_EMULATE_FBE, false);
+        return isNativeFileBasedEncryptionEnabled() || isEmulatedFileBasedEncryptionEnabled();
+    }
+
+    /** {@hide} */
+    public static boolean isNativeFileBasedEncryptionEnabled() {
+        return "file".equals(SystemProperties.get("ro.crypto.type", "none"));
+    }
+
+    /** {@hide} */
+    public static boolean isEmulatedFileBasedEncryptionEnabled() {
+        return SystemProperties.getBoolean(StorageManager.PROP_EMULATE_FBE, false);
     }
 
     /** {@hide} */
diff --git a/services/core/java/com/android/server/MountService.java b/services/core/java/com/android/server/MountService.java
index 807c0d6..473eff6 100644
--- a/services/core/java/com/android/server/MountService.java
+++ b/services/core/java/com/android/server/MountService.java
@@ -57,6 +57,7 @@
 import android.os.Looper;
 import android.os.Message;
 import android.os.ParcelFileDescriptor;
+import android.os.PowerManager;
 import android.os.Process;
 import android.os.RemoteCallbackList;
 import android.os.RemoteException;
@@ -175,8 +176,8 @@
         }
 
         @Override
-        public void onStartUser(int userHandle) {
-            mMountService.onStartUser(userHandle);
+        public void onUnlockUser(int userHandle) {
+            mMountService.onUnlockUser(userHandle);
         }
 
         @Override
@@ -286,10 +287,12 @@
      */
     private final Object mLock = new Object();
 
+    /** Set of users that we know are unlocked. */
     @GuardedBy("mLock")
-    private int[] mStartedUsers = EmptyArray.INT;
+    private int[] mLocalUnlockedUsers = EmptyArray.INT;
+    /** Set of users that system knows are unlocked. */
     @GuardedBy("mLock")
-    private int[] mUnlockedUsers = EmptyArray.INT;
+    private int[] mSystemUnlockedUsers = EmptyArray.INT;
 
     /** Map from disk ID to disk */
     @GuardedBy("mLock")
@@ -834,12 +837,21 @@
     private void initIfReadyAndConnected() {
         Slog.d(TAG, "Thinking about init, mSystemReady=" + mSystemReady
                 + ", mDaemonConnected=" + mDaemonConnected);
-        if (mSystemReady && mDaemonConnected && StorageManager.isFileBasedEncryptionEnabled()) {
-            final List<UserInfo> users = mContext.getSystemService(UserManager.class)
-                    .getUsers();
+        if (mSystemReady && mDaemonConnected
+                && !StorageManager.isNativeFileBasedEncryptionEnabled()) {
+            // When booting a device without native support, make sure that our
+            // user directories are locked or unlocked based on the current
+            // emulation status.
+            final boolean initLocked = StorageManager.isEmulatedFileBasedEncryptionEnabled();
+            final List<UserInfo> users = mContext.getSystemService(UserManager.class).getUsers();
             for (UserInfo user : users) {
                 try {
-                    mCryptConnector.execute("cryptfs", "lock_user_key", user.id);
+                    if (initLocked) {
+                        mCryptConnector.execute("cryptfs", "lock_user_key", user.id);
+                    } else {
+                        mCryptConnector.execute("cryptfs", "unlock_user_key", user.id,
+                                user.serialNumber, "!");
+                    }
                 } catch (NativeDaemonConnectorException e) {
                     Slog.w(TAG, "Failed to init vold", e);
                 }
@@ -854,9 +866,9 @@
             final List<UserInfo> users = mContext.getSystemService(UserManager.class).getUsers();
             killMediaProvider(users);
 
-            final int[] startedUsers;
+            final int[] systemUnlockedUsers;
             synchronized (mLock) {
-                startedUsers = mStartedUsers;
+                systemUnlockedUsers = mSystemUnlockedUsers;
 
                 mDisks.clear();
                 mVolumes.clear();
@@ -871,7 +883,7 @@
                 for (UserInfo user : users) {
                     mConnector.execute("volume", "user_added", user.id, user.serialNumber);
                 }
-                for (int userId : startedUsers) {
+                for (int userId : systemUnlockedUsers) {
                     mConnector.execute("volume", "user_started", userId);
                 }
             } catch (NativeDaemonConnectorException e) {
@@ -880,8 +892,8 @@
         }
     }
 
-    private void onStartUser(int userId) {
-        Slog.d(TAG, "onStartUser " + userId);
+    private void onUnlockUser(int userId) {
+        Slog.d(TAG, "onUnlockUser " + userId);
 
         // We purposefully block here to make sure that user-specific
         // staging area is ready so it's ready for zygote-forked apps to
@@ -904,7 +916,7 @@
                     mCallbacks.notifyStorageStateChanged(userVol.getPath(), envState, envState);
                 }
             }
-            mStartedUsers = ArrayUtils.appendInt(mStartedUsers, userId);
+            mSystemUnlockedUsers = ArrayUtils.appendInt(mSystemUnlockedUsers, userId);
         }
     }
 
@@ -917,7 +929,7 @@
         }
 
         synchronized (mVolumes) {
-            mStartedUsers = ArrayUtils.removeInt(mStartedUsers, userId);
+            mSystemUnlockedUsers = ArrayUtils.removeInt(mSystemUnlockedUsers, userId);
         }
     }
 
@@ -1337,7 +1349,7 @@
             // Kick state changed event towards all started users. Any users
             // started after this point will trigger additional
             // user-specific broadcasts.
-            for (int userId : mStartedUsers) {
+            for (int userId : mSystemUnlockedUsers) {
                 if (vol.isVisibleForRead(userId)) {
                     final StorageVolume userVol = vol.buildStorageVolume(mContext, userId, false);
                     mHandler.obtainMessage(H_VOLUME_BROADCAST, userVol).sendToTarget();
@@ -1926,8 +1938,16 @@
         waitForReady();
 
         if ((mask & StorageManager.DEBUG_EMULATE_FBE) != 0) {
+            if (StorageManager.isNativeFileBasedEncryptionEnabled()) {
+                throw new IllegalStateException(
+                        "Emulation not available on device with native FBE");
+            }
+
             final boolean emulateFbe = (flags & StorageManager.DEBUG_EMULATE_FBE) != 0;
             SystemProperties.set(StorageManager.PROP_EMULATE_FBE, Boolean.toString(emulateFbe));
+
+            // Perform hard reboot to kick policy into place
+            mContext.getSystemService(PowerManager.class).reboot(null);
         }
 
         if ((mask & StorageManager.DEBUG_FORCE_ADOPTABLE) != 0) {
@@ -2745,7 +2765,7 @@
         }
 
         synchronized (mLock) {
-            mUnlockedUsers = ArrayUtils.appendInt(mUnlockedUsers, userId);
+            mLocalUnlockedUsers = ArrayUtils.appendInt(mLocalUnlockedUsers, userId);
         }
     }
 
@@ -2761,7 +2781,7 @@
         }
 
         synchronized (mLock) {
-            mUnlockedUsers = ArrayUtils.removeInt(mUnlockedUsers, userId);
+            mLocalUnlockedUsers = ArrayUtils.removeInt(mLocalUnlockedUsers, userId);
         }
     }
 
@@ -2769,7 +2789,7 @@
     public boolean isUserKeyUnlocked(int userId) {
         if (StorageManager.isFileBasedEncryptionEnabled()) {
             synchronized (mLock) {
-                return ArrayUtils.contains(mUnlockedUsers, userId);
+                return ArrayUtils.contains(mLocalUnlockedUsers, userId);
             }
         } else {
             return true;
@@ -2836,21 +2856,25 @@
 
     @Override
     public StorageVolume[] getVolumeList(int uid, String packageName, int flags) {
+        final int userId = UserHandle.getUserId(uid);
         final boolean forWrite = (flags & StorageManager.FLAG_FOR_WRITE) != 0;
 
-        final ArrayList<StorageVolume> res = new ArrayList<>();
+        boolean reportUnmounted = false;
         boolean foundPrimary = false;
 
-        final int userId = UserHandle.getUserId(uid);
-        final boolean reportUnmounted;
         final long identity = Binder.clearCallingIdentity();
         try {
-            reportUnmounted = !mMountServiceInternal.hasExternalStorage(
-                    uid, packageName);
+            if (!mMountServiceInternal.hasExternalStorage(uid, packageName)) {
+                reportUnmounted = true;
+            }
+            if (!isUserKeyUnlocked(userId)) {
+                reportUnmounted = true;
+            }
         } finally {
             Binder.restoreCallingIdentity(identity);
         }
 
+        final ArrayList<StorageVolume> res = new ArrayList<>();
         synchronized (mLock) {
             for (int i = 0; i < mVolumes.size(); i++) {
                 final VolumeInfo vol = mVolumes.valueAt(i);
@@ -3530,8 +3554,8 @@
             pw.println("Primary storage UUID: " + mPrimaryStorageUuid);
             pw.println("Force adoptable: " + mForceAdoptable);
             pw.println();
-            pw.println("Started users: " + Arrays.toString(mStartedUsers));
-            pw.println("Unlocked users: " + Arrays.toString(mUnlockedUsers));
+            pw.println("Local unlocked users: " + Arrays.toString(mLocalUnlockedUsers));
+            pw.println("System unlocked users: " + Arrays.toString(mSystemUnlockedUsers));
         }
 
         synchronized (mObbMounts) {