Prepare user storage just before using it.

Wire up preparing of user-specific app storage to existing user
lifecycle hooks.  This way we're sure the storage is ready to roll
just before we start reconciling app data directories.

This also has the nice property that we only prepare storage when
we know that keys are unlocked.

Bug: 25796509
Change-Id: Ic7df9ddbcfb1e20649d11b6cf68d424e3c365ee1
diff --git a/services/core/java/com/android/server/pm/Installer.java b/services/core/java/com/android/server/pm/Installer.java
index dac89ec..c08f713 100644
--- a/services/core/java/com/android/server/pm/Installer.java
+++ b/services/core/java/com/android/server/pm/Installer.java
@@ -16,11 +16,11 @@
 
 package com.android.server.pm;
 
-import android.annotation.IntDef;
 import android.annotation.Nullable;
 import android.content.Context;
 import android.content.pm.PackageStats;
 import android.os.Build;
+import android.os.storage.StorageManager;
 import android.util.Slog;
 
 import com.android.internal.os.InstallerConnection;
@@ -29,9 +29,6 @@
 
 import dalvik.system.VMRuntime;
 
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-
 public final class Installer extends SystemService {
     private static final String TAG = "Installer";
 
@@ -52,19 +49,9 @@
     /** This is an OTA update dexopt */
     public static final int DEXOPT_OTA          = 1 << 6;
 
-    /** @hide */
-    @IntDef(flag = true, value = {
-            FLAG_DE_STORAGE,
-            FLAG_CE_STORAGE,
-    })
-    @Retention(RetentionPolicy.SOURCE)
-    public @interface StorageFlags {}
-
-    public static final int FLAG_DE_STORAGE = 1 << 0;
-    public static final int FLAG_CE_STORAGE = 1 << 1;
-
-    public static final int FLAG_CLEAR_CACHE_ONLY = 1 << 2;
-    public static final int FLAG_CLEAR_CODE_CACHE_ONLY = 1 << 3;
+    // NOTE: keep in sync with installd
+    public static final int FLAG_CLEAR_CACHE_ONLY = 1 << 8;
+    public static final int FLAG_CLEAR_CODE_CACHE_ONLY = 1 << 9;
 
     private final InstallerConnection mInstaller;
 
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 553a9a2..504ce31 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -235,7 +235,6 @@
 import com.android.server.ServiceThread;
 import com.android.server.SystemConfig;
 import com.android.server.Watchdog;
-import com.android.server.pm.Installer.StorageFlags;
 import com.android.server.pm.PermissionsState.PermissionState;
 import com.android.server.pm.Settings.DatabaseVersion;
 import com.android.server.pm.Settings.VersionInfo;
@@ -2388,9 +2387,9 @@
             // can't wait for user to start
             final int flags;
             if (StorageManager.isFileBasedEncryptionEnabled()) {
-                flags = Installer.FLAG_DE_STORAGE;
+                flags = StorageManager.FLAG_STORAGE_DE;
             } else {
-                flags = Installer.FLAG_DE_STORAGE | Installer.FLAG_CE_STORAGE;
+                flags = StorageManager.FLAG_STORAGE_DE | StorageManager.FLAG_STORAGE_CE;
             }
             reconcileAppsData(StorageManager.UUID_PRIVATE_INTERNAL, UserHandle.USER_SYSTEM, flags);
 
@@ -6860,7 +6859,7 @@
 
     private boolean removeDataDirsLI(String volumeUuid, String packageName) {
         // TODO: triage flags as part of 26466827
-        final int flags = Installer.FLAG_CE_STORAGE | Installer.FLAG_DE_STORAGE;
+        final int flags = StorageManager.FLAG_STORAGE_CE | StorageManager.FLAG_STORAGE_DE;
 
         boolean res = true;
         final int[] users = sUserManager.getUserIds();
@@ -6906,7 +6905,7 @@
 
     private void deleteCodeCacheDirsLI(String volumeUuid, String packageName) {
         // TODO: triage flags as part of 26466827
-        final int flags = Installer.FLAG_CE_STORAGE | Installer.FLAG_DE_STORAGE;
+        final int flags = StorageManager.FLAG_STORAGE_CE | StorageManager.FLAG_STORAGE_DE;
 
         final int[] users = sUserManager.getUserIds();
         for (int user : users) {
@@ -13947,7 +13946,8 @@
                 outInfo.removedUsers = new int[] {removeUser};
             }
             // TODO: triage flags as part of 26466827
-            final int installerFlags = Installer.FLAG_CE_STORAGE | Installer.FLAG_DE_STORAGE;
+            final int installerFlags = StorageManager.FLAG_STORAGE_CE
+                    | StorageManager.FLAG_STORAGE_DE;
             try {
                 mInstaller.destroyAppData(ps.volumeUuid, packageName, removeUser, installerFlags);
             } catch (InstallerException e) {
@@ -14127,7 +14127,7 @@
         // record of app. This helps users recover from UID mismatches without
         // resorting to a full data wipe.
         // TODO: triage flags as part of 26466827
-        final int flags = Installer.FLAG_CE_STORAGE | Installer.FLAG_DE_STORAGE;
+        final int flags = StorageManager.FLAG_STORAGE_CE | StorageManager.FLAG_STORAGE_DE;
         try {
             mInstaller.clearAppData(pkg.volumeUuid, packageName, userId, flags);
         } catch (InstallerException e) {
@@ -14362,7 +14362,7 @@
             return false;
         }
         // TODO: triage flags as part of 26466827
-        final int flags = Installer.FLAG_CE_STORAGE | Installer.FLAG_DE_STORAGE;
+        final int flags = StorageManager.FLAG_STORAGE_CE | StorageManager.FLAG_STORAGE_DE;
         try {
             mInstaller.clearAppData(p.volumeUuid, packageName, userId,
                     flags | Installer.FLAG_CLEAR_CACHE_ONLY);
@@ -14463,7 +14463,7 @@
         }
 
         // TODO: triage flags as part of 26466827
-        final int flags = Installer.FLAG_CE_STORAGE | Installer.FLAG_DE_STORAGE;
+        final int flags = StorageManager.FLAG_STORAGE_CE | StorageManager.FLAG_STORAGE_DE;
         try {
             mInstaller.getAppSize(p.volumeUuid, packageName, userHandle, flags, apkPath,
                     libDirRoot, publicSrcDir, asecPath, dexCodeInstructionSets, pStats);
@@ -16787,16 +16787,20 @@
         }
 
         // Reconcile app data for all started/unlocked users
+        final StorageManager sm = mContext.getSystemService(StorageManager.class);
         final UserManager um = mContext.getSystemService(UserManager.class);
         for (UserInfo user : um.getUsers()) {
+            final int flags;
             if (um.isUserUnlocked(user.id)) {
-                reconcileAppsData(volumeUuid, user.id,
-                        Installer.FLAG_DE_STORAGE | Installer.FLAG_CE_STORAGE);
+                flags = StorageManager.FLAG_STORAGE_DE | StorageManager.FLAG_STORAGE_CE;
             } else if (um.isUserRunning(user.id)) {
-                reconcileAppsData(volumeUuid, user.id, Installer.FLAG_DE_STORAGE);
+                flags = StorageManager.FLAG_STORAGE_DE;
             } else {
                 continue;
             }
+
+            sm.prepareUserStorage(volumeUuid, user.id, user.serialNumber, flags);
+            reconcileAppsData(volumeUuid, user.id, flags);
         }
 
         synchronized (mPackages) {
@@ -16905,20 +16909,6 @@
                 }
             }
         }
-
-        final StorageManager sm = mContext.getSystemService(StorageManager.class);
-        final UserManager um = mContext.getSystemService(UserManager.class);
-        for (UserInfo user : um.getUsers()) {
-            final File userDir = Environment.getDataUserDirectory(volumeUuid, user.id);
-            if (userDir.exists()) continue;
-
-            try {
-                sm.prepareUserStorage(volumeUuid, user.id, user.serialNumber, user.isEphemeral());
-                UserManagerService.enforceSerialNumber(userDir, user.serialNumber);
-            } catch (IOException e) {
-                Log.wtf(TAG, "Failed to create user directory on " + volumeUuid, e);
-            }
-        }
     }
 
     private void assertPackageKnown(String volumeUuid, String packageName)
@@ -16988,7 +16978,7 @@
      * Verifies that directories exist and that ownership and labeling is
      * correct for all installed apps on all mounted volumes.
      */
-    void reconcileAppsData(int userId, @StorageFlags int flags) {
+    void reconcileAppsData(int userId, int flags) {
         final StorageManager storage = mContext.getSystemService(StorageManager.class);
         for (VolumeInfo vol : storage.getWritablePrivateVolumes()) {
             final String volumeUuid = vol.getFsUuid();
@@ -17005,7 +16995,7 @@
      * Verifies that directories exist and that ownership and labeling is
      * correct for all installed apps.
      */
-    private void reconcileAppsData(String volumeUuid, int userId, @StorageFlags int flags) {
+    private void reconcileAppsData(String volumeUuid, int userId, int flags) {
         Slog.v(TAG, "reconcileAppsData for " + volumeUuid + " u" + userId + " 0x"
                 + Integer.toHexString(flags));
 
@@ -17016,7 +17006,7 @@
 
         // First look for stale data that doesn't belong, and check if things
         // have changed since we did our last restorecon
-        if ((flags & Installer.FLAG_CE_STORAGE) != 0) {
+        if ((flags & StorageManager.FLAG_STORAGE_CE) != 0) {
             if (!isUserKeyUnlocked(userId)) {
                 throw new RuntimeException(
                         "Yikes, someone asked us to reconcile CE storage while " + userId
@@ -17034,12 +17024,12 @@
                     logCriticalInfo(Log.WARN, "Destroying " + file + " due to: " + e);
                     synchronized (mInstallLock) {
                         destroyAppDataLI(volumeUuid, packageName, userId,
-                                Installer.FLAG_CE_STORAGE);
+                                StorageManager.FLAG_STORAGE_CE);
                     }
                 }
             }
         }
-        if ((flags & Installer.FLAG_DE_STORAGE) != 0) {
+        if ((flags & StorageManager.FLAG_STORAGE_DE) != 0) {
             restoreconNeeded |= SELinuxMMAC.isRestoreconNeeded(deDir);
 
             final File[] files = FileUtils.listFilesOrEmpty(deDir);
@@ -17051,7 +17041,7 @@
                     logCriticalInfo(Log.WARN, "Destroying " + file + " due to: " + e);
                     synchronized (mInstallLock) {
                         destroyAppDataLI(volumeUuid, packageName, userId,
-                                Installer.FLAG_DE_STORAGE);
+                                StorageManager.FLAG_STORAGE_DE);
                     }
                 }
             }
@@ -17080,10 +17070,10 @@
         }
 
         if (restoreconNeeded) {
-            if ((flags & Installer.FLAG_CE_STORAGE) != 0) {
+            if ((flags & StorageManager.FLAG_STORAGE_CE) != 0) {
                 SELinuxMMAC.setRestoreconDone(ceDir);
             }
-            if ((flags & Installer.FLAG_DE_STORAGE) != 0) {
+            if ((flags & StorageManager.FLAG_STORAGE_DE) != 0) {
                 SELinuxMMAC.setRestoreconDone(deDir);
             }
         }
@@ -17112,9 +17102,9 @@
         for (UserInfo user : um.getUsers()) {
             final int flags;
             if (um.isUserUnlocked(user.id)) {
-                flags = Installer.FLAG_DE_STORAGE | Installer.FLAG_CE_STORAGE;
+                flags = StorageManager.FLAG_STORAGE_DE | StorageManager.FLAG_STORAGE_CE;
             } else if (um.isUserRunning(user.id)) {
-                flags = Installer.FLAG_DE_STORAGE;
+                flags = StorageManager.FLAG_STORAGE_DE;
             } else {
                 continue;
             }
@@ -17135,7 +17125,7 @@
      * will try recovering system apps by wiping data; third-party app data is
      * left intact.
      */
-    private void prepareAppData(String volumeUuid, int userId, @StorageFlags int flags,
+    private void prepareAppData(String volumeUuid, int userId, int flags,
             PackageParser.Package pkg, boolean restoreconNeeded) {
         if (DEBUG_APP_DATA) {
             Slog.v(TAG, "prepareAppData for " + pkg.packageName + " u" + userId + " 0x"
@@ -17173,7 +17163,7 @@
                 restoreconAppDataLI(volumeUuid, packageName, userId, flags, appId, app.seinfo);
             }
 
-            if ((flags & Installer.FLAG_CE_STORAGE) != 0) {
+            if ((flags & StorageManager.FLAG_STORAGE_CE) != 0) {
                 // Create a native library symlink only if we have native libraries
                 // and if the native libraries are 32 bit libraries. We do not provide
                 // this symlink for 64 bit libraries.
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index bbbe693..fcb777b 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -3787,7 +3787,7 @@
                 continue;
             }
             // TODO: triage flags!
-            final int flags = Installer.FLAG_CE_STORAGE | Installer.FLAG_DE_STORAGE;
+            final int flags = StorageManager.FLAG_STORAGE_CE | StorageManager.FLAG_STORAGE_DE;
             try {
                 installer.createAppData(volumeUuids[i], names[i], userHandle, flags, appIds[i],
                         seinfos[i], targetSdkVersions[i]);
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 5f46567..3cc7b10 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -25,7 +25,6 @@
 import android.app.ActivityManagerNative;
 import android.app.IActivityManager;
 import android.app.IStopUserCallback;
-import android.app.admin.DevicePolicyManager;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
@@ -78,7 +77,9 @@
 import com.android.internal.util.XmlUtils;
 import com.android.internal.widget.LockPatternUtils;
 import com.android.server.LocalServices;
-import com.android.server.pm.Installer.StorageFlags;
+
+import libcore.io.IoUtils;
+import libcore.util.Objects;
 
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
@@ -96,9 +97,6 @@
 import java.util.ArrayList;
 import java.util.List;
 
-import libcore.io.IoUtils;
-import libcore.util.Objects;
-
 /**
  * Service for {@link UserManager}.
  *
@@ -1893,17 +1891,8 @@
             }
             final StorageManager storage = mContext.getSystemService(StorageManager.class);
             storage.createUserKey(userId, userInfo.serialNumber, userInfo.isEphemeral());
-            for (VolumeInfo vol : storage.getWritablePrivateVolumes()) {
-                final String volumeUuid = vol.getFsUuid();
-                try {
-                    final File userDir = Environment.getDataUserDirectory(volumeUuid, userId);
-                    storage.prepareUserStorage(
-                            volumeUuid, userId, userInfo.serialNumber, userInfo.isEphemeral());
-                    enforceSerialNumber(userDir, userInfo.serialNumber);
-                } catch (IOException e) {
-                    Log.wtf(LOG_TAG, "Failed to create user directory on " + volumeUuid, e);
-                }
-            }
+            prepareUserStorage(userId, userInfo.serialNumber,
+                    StorageManager.FLAG_STORAGE_DE | StorageManager.FLAG_STORAGE_CE);
             mPm.createNewUser(userId);
             userInfo.partial = false;
             synchronized (mPackagesLock) {
@@ -2466,11 +2455,24 @@
     }
 
     /**
+     * Prepare storage areas for given user on all mounted devices.
+     */
+    private void prepareUserStorage(int userId, int userSerial, int flags) {
+        final StorageManager storage = mContext.getSystemService(StorageManager.class);
+        for (VolumeInfo vol : storage.getWritablePrivateVolumes()) {
+            final String volumeUuid = vol.getFsUuid();
+            storage.prepareUserStorage(volumeUuid, userId, userSerial, flags);
+        }
+    }
+
+    /**
      * Called right before a user is started. This gives us a chance to prepare
      * app storage and apply any user restrictions.
      */
     public void onBeforeStartUser(int userId) {
-        mPm.reconcileAppsData(userId, Installer.FLAG_DE_STORAGE);
+        final int userSerial = getUserSerialNumber(userId);
+        prepareUserStorage(userId, userSerial, StorageManager.FLAG_STORAGE_DE);
+        mPm.reconcileAppsData(userId, StorageManager.FLAG_STORAGE_DE);
 
         if (userId != UserHandle.USER_SYSTEM) {
             synchronized (mRestrictionsLock) {
@@ -2484,7 +2486,9 @@
      * app storage.
      */
     public void onBeforeUnlockUser(int userId) {
-        mPm.reconcileAppsData(userId, Installer.FLAG_CE_STORAGE);
+        final int userSerial = getUserSerialNumber(userId);
+        prepareUserStorage(userId, userSerial, StorageManager.FLAG_STORAGE_CE);
+        mPm.reconcileAppsData(userId, StorageManager.FLAG_STORAGE_CE);
     }
 
     /**