From e915a7e186dd82d477de3161c1bf717481c33ab3 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Wed, 17 Jun 2020 14:47:35 -0600 Subject: [PATCH] Attempt at fixing race condition during boot. We've found local evidence that on fast hardware that the MediaProvider.updateVolumes() method can be invoked while the device is still unlocking. This can cause a race condition due to the "reportUnmounted" logic in StorageManagerService.getVolumeList() which attempts to hide all volumes from apps until after the user has been unlocked. Since MediaProvider itself is the one hosting the FUSE daemon, it always needs to know the real underlying state of volumes, so this change adds special treatment to never augment the mount state when the caller is the FUSE daemon. Bug: 159189865 Test: manual Change-Id: Id86e86aa942a697877860961d20ff0d8458dbc10 --- .../android/server/StorageManagerService.java | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java index 1ce3dfe9f3a0d..63a984ccdc6f6 100644 --- a/services/core/java/com/android/server/StorageManagerService.java +++ b/services/core/java/com/android/server/StorageManagerService.java @@ -3535,6 +3535,13 @@ class StorageManagerService extends IStorageManager.Stub // point final boolean systemUserUnlocked = isSystemUnlocked(UserHandle.USER_SYSTEM); + // When the caller is the app actually hosting external storage, we + // should never attempt to augment the actual storage volume state, + // otherwise we risk confusing it with race conditions as users go + // through various unlocked states + final boolean callerIsMediaStore = UserHandle.isSameApp(Binder.getCallingUid(), + mMediaStoreAuthorityAppId); + final boolean userIsDemo; final boolean userKeyUnlocked; final boolean storagePermission; @@ -3554,6 +3561,7 @@ class StorageManagerService extends IStorageManager.Stub final ArraySet resUuids = new ArraySet<>(); synchronized (mLock) { for (int i = 0; i < mVolumes.size(); i++) { + final String volId = mVolumes.keyAt(i); final VolumeInfo vol = mVolumes.valueAt(i); switch (vol.getType()) { case VolumeInfo.TYPE_PUBLIC: @@ -3578,11 +3586,19 @@ class StorageManagerService extends IStorageManager.Stub if (!match) continue; boolean reportUnmounted = false; - if (!systemUserUnlocked) { + if (callerIsMediaStore) { + // When the caller is the app actually hosting external storage, we + // should never attempt to augment the actual storage volume state, + // otherwise we risk confusing it with race conditions as users go + // through various unlocked states + } else if (!systemUserUnlocked) { reportUnmounted = true; + Slog.w(TAG, "Reporting " + volId + " unmounted due to system locked"); } else if ((vol.getType() == VolumeInfo.TYPE_EMULATED) && !userKeyUnlocked) { reportUnmounted = true; + Slog.w(TAG, "Reporting " + volId + "unmounted due to " + userId + " locked"); } else if (!storagePermission && !realState) { + Slog.w(TAG, "Reporting " + volId + "unmounted due to missing permissions"); reportUnmounted = true; }