diff --git a/core/java/android/content/pm/PackageManagerInternal.java b/core/java/android/content/pm/PackageManagerInternal.java index 666508af02073..672994e791340 100644 --- a/core/java/android/content/pm/PackageManagerInternal.java +++ b/core/java/android/content/pm/PackageManagerInternal.java @@ -994,4 +994,9 @@ public abstract class PackageManagerInternal { */ public abstract void setRuntimePermissionsFingerPrint(@NonNull String fingerPrint, @UserIdInt int userId); + + /** + * Migrates legacy obb data to its new location. + */ + public abstract void migrateLegacyObbData(); } diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java index d2b992bad4623..deff7ef7d39ac 100644 --- a/services/core/java/com/android/server/StorageManagerService.java +++ b/services/core/java/com/android/server/StorageManagerService.java @@ -580,6 +580,7 @@ class StorageManagerService extends IStorageManager.Stub private static final int H_RUN_IDLE_MAINT = 11; private static final int H_ABORT_IDLE_MAINT = 12; private static final int H_BOOT_COMPLETED = 13; + private static final int H_COMPLETE_UNLOCK_USER = 14; class StorageManagerServiceHandler extends Handler { public StorageManagerServiceHandler(Looper looper) { @@ -698,7 +699,10 @@ class StorageManagerService extends IStorageManager.Stub abortIdleMaint((Runnable)msg.obj); break; } - + case H_COMPLETE_UNLOCK_USER: { + completeUnlockUser((int) msg.obj); + break; + } } } } @@ -978,6 +982,17 @@ class StorageManagerService extends IStorageManager.Stub Slog.wtf(TAG, e); } + mHandler.obtainMessage(H_COMPLETE_UNLOCK_USER, userId).sendToTarget(); + } + + private void completeUnlockUser(int userId) { + // If user 0 has completed unlock, perform a one-time migration of legacy obb data + // to its new location. This may take time depending on the size of the data to be copied + // so it's done on the StorageManager handler thread. + if (userId == 0) { + mPmInternal.migrateLegacyObbData(); + } + // Record user as started so newly mounted volumes kick off events // correctly, then synthesize events for any already-mounted volumes. synchronized (mLock) { @@ -2820,6 +2835,12 @@ class StorageManagerService extends IStorageManager.Stub } } + private boolean isSystemUnlocked(int userId) { + synchronized (mLock) { + return ArrayUtils.contains(mSystemUnlockedUsers, userId); + } + } + @Override public void prepareUserStorage(String volumeUuid, int userId, int serialNumber, int flags) { enforcePermission(android.Manifest.permission.STORAGE_INTERNAL); @@ -2996,6 +3017,11 @@ class StorageManagerService extends IStorageManager.Stub final boolean realState = (flags & StorageManager.FLAG_REAL_STATE) != 0; final boolean includeInvisible = (flags & StorageManager.FLAG_INCLUDE_INVISIBLE) != 0; + // Report all volumes as unmounted until we've recorded that user 0 has unlocked. There + // are no guarantees that callers will see a consistent view of the volume before that + // point + final boolean systemUserUnlocked = isSystemUnlocked(UserHandle.USER_SYSTEM); + final boolean userKeyUnlocked; final boolean storagePermission; final long token = Binder.clearCallingIdentity(); @@ -3031,7 +3057,9 @@ class StorageManagerService extends IStorageManager.Stub if (!match) continue; boolean reportUnmounted = false; - if ((vol.getType() == VolumeInfo.TYPE_EMULATED) && !userKeyUnlocked) { + if (!systemUserUnlocked) { + reportUnmounted = true; + } else if ((vol.getType() == VolumeInfo.TYPE_EMULATED) && !userKeyUnlocked) { reportUnmounted = true; } else if (!storagePermission && !realState) { reportUnmounted = true; diff --git a/services/core/java/com/android/server/pm/Installer.java b/services/core/java/com/android/server/pm/Installer.java index c2d5b2f86002b..adcd19e9bb5aa 100644 --- a/services/core/java/com/android/server/pm/Installer.java +++ b/services/core/java/com/android/server/pm/Installer.java @@ -121,24 +121,6 @@ public class Installer extends SystemService { } } - @Override - public void onUnlockUser(int userId) { - if (userId == 0) { - if (!checkBeforeRemote()) return; - - if (mInstalld == null) { - Slog.wtf(TAG, "Call to onUnlockUser prior to onStart."); - return; - } - - try { - mInstalld.migrateLegacyObbData(); - } catch (RemoteException re) { - Slog.wtf(TAG, "Error migrating legacy OBB data.", re); - } - } - } - private void connect() { IBinder binder = ServiceManager.getService("installd"); if (binder != null) { @@ -708,6 +690,24 @@ public class Installer extends SystemService { } } + /** + * Migrates obb data from its legacy location {@code /data/media/obb} to + * {@code /data/media/0/Android/obb}. This call is idempotent and a fast no-op if data has + * already been migrated. + * + * @throws InstallerException if an error occurs. + */ + public boolean migrateLegacyObbData() throws InstallerException { + if (!checkBeforeRemote()) return false; + + try { + mInstalld.migrateLegacyObbData(); + return true; + } catch (Exception e) { + throw InstallerException.from(e); + } + } + private static void assertValidInstructionSet(String instructionSet) throws InstallerException { for (String abi : Build.SUPPORTED_ABIS) { diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 7d5393deb3f84..ab60181019ee0 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -24963,6 +24963,15 @@ public class PackageManagerService extends IPackageManager.Stub mSettings.setRuntimePermissionsFingerPrintLPr(fingerPrint, userId); } } + + @Override + public void migrateLegacyObbData() { + try { + mInstaller.migrateLegacyObbData(); + } catch (Exception e) { + Slog.wtf(TAG, e); + } + } } @GuardedBy("mPackages")