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) {
abortIdleMaint((Runnable)msg.obj);
break;
}
-
+ case H_COMPLETE_UNLOCK_USER: {
+ completeUnlockUser((int) msg.obj);
+ break;
+ }
}
}
}
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) {
}
}
+ 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);
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();
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;
}
}
- @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) {
}
}
+ /**
+ * 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) {