More file-based encryption work.

Add new "am unlock-user" command so we can trigger changes from the
command line.

Move FBE check to static method so it can safely be called early
during boot before the mount service is ready.  Move FBE emulation
to persisted system property, and start reading/writing that value.

Change default permission grants to ignore current encryption-aware
flags, since many of the target apps aren't crypto aware.

Always prepare package data directories, which is how we create the
new "user_de" paths during boot.

Bug: 22358539
Change-Id: I6f58ea2d34b3a466d3775d614f8a13de92272621
diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java
index d6fced6..e04f138 100644
--- a/services/core/java/com/android/server/am/UserController.java
+++ b/services/core/java/com/android/server/am/UserController.java
@@ -66,6 +66,7 @@
 import android.util.SparseIntArray;
 
 import com.android.internal.R;
+import com.android.internal.annotations.GuardedBy;
 import com.android.internal.util.ArrayUtils;
 import com.android.server.pm.UserManagerService;
 
@@ -99,7 +100,9 @@
     /**
      * Which users have been started, so are allowed to run code.
      */
+    @GuardedBy("mService")
     private final SparseArray<UserState> mStartedUsers = new SparseArray<>();
+
     /**
      * LRU list of history of current users.  Most recently current is at the end.
      */
@@ -415,7 +418,7 @@
 
     private void updateUserUnlockedState(UserState uss) {
         final IMountService mountService = IMountService.Stub
-                .asInterface(ServiceManager.getService(Context.STORAGE_SERVICE));
+                .asInterface(ServiceManager.getService("mount"));
         if (mountService != null) {
             try {
                 uss.unlocked = mountService.isUserKeyUnlocked(uss.mHandle.getIdentifier());
@@ -424,7 +427,7 @@
             }
         } else {
             // System isn't fully booted yet, so guess based on property
-            uss.unlocked = !SystemProperties.getBoolean(StorageManager.PROP_HAS_FBE, false);
+            uss.unlocked = !StorageManager.isFileBasedEncryptionEnabled();
         }
     }
 
@@ -606,6 +609,35 @@
         return result;
     }
 
+    boolean unlockUser(final int userId, byte[] token) {
+        if (mService.checkCallingPermission(INTERACT_ACROSS_USERS_FULL)
+                != PackageManager.PERMISSION_GRANTED) {
+            String msg = "Permission Denial: unlockUser() from pid="
+                    + Binder.getCallingPid()
+                    + ", uid=" + Binder.getCallingUid()
+                    + " requires " + INTERACT_ACROSS_USERS_FULL;
+            Slog.w(TAG, msg);
+            throw new SecurityException(msg);
+        }
+
+        final UserInfo userInfo = getUserInfo(userId);
+        final IMountService mountService = IMountService.Stub
+                .asInterface(ServiceManager.getService("mount"));
+        try {
+            mountService.unlockUserKey(userId, userInfo.serialNumber, token);
+        } catch (RemoteException e) {
+            Slog.w(TAG, "Failed to unlock: " + e.getMessage());
+            throw e.rethrowAsRuntimeException();
+        }
+
+        synchronized (mService) {
+            final UserState uss = mStartedUsers.get(userId);
+            updateUserUnlockedState(uss);
+        }
+
+        return true;
+    }
+
     void showUserSwitchDialog(int userId, String userName) {
         // The dialog will show and then initiate the user switch by calling startUserInForeground
         Dialog d = new UserSwitchingDialog(mService, mService.mContext, userId, userName,