Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 04110a39 authored by Arnab Sen's avatar Arnab Sen
Browse files

SM: Remount emulated volumes on Move Storage

Whenever move storage is executed for moving media to adopted
storage from internal storage and vice-versa, the emulated
volumes that are mounted for non-current users which are
currently running in the system points to the physical storage
for the older storage location rather than the current one. This
would case data to be still stored in the older storage location
rather than the current one. This would cause media content not
to be accessible to the user.

Android maintains separate emulated volumes for each user for internal
storage as well as adopted storage. Adopted Storage has a global
private volumes on which emulated volumes are created. Whenever a
move is triggered the primary storage changes globally for the
StorageManagerService, but the emulated volumes are not mounted
correctly for the non-current users which are running in the system.
To solve this added a new method remountForRunningUsersOnMove()
which would inform vold and storaged that the non-current user has
stopped, which is similar to onCleanupUser(int) which would
remove the current emulated volume for the user and then inform
vold and storgaed that user has started which would correctly
mount the emulated volume for the user which is same as
resetIfBootedAndConnected(). This ensures that the emulated volumes
for the correct primary storage location are mounted for all the
users currently running.

Test: manual
Perform the following steps:
1. Setup the device with at least one secondary user.
2. Switch to the secondary user and switch back to
   current user.
3. Insert a SD Card and setup as Adopted
4. Complete the Move content flow.
5. Check the correct volumes are mounted by executing:
   'adb shell dumpsys mount' and check the internal path
   for the mounted emulated volumes point to adopted storage.
6. Go to Settings > Storage > 'Move Data to internal storage'.
7. Check the correct volumes are mounted by executing:
   'adb shell dumpsys mount' and check the internal path
   for the mounted emulated volumes point to internal storage.

Change-Id: Ibbc4b109ff44f0f68a05da5632a4304e8b4992ac
parent e1ee1aab
Loading
Loading
Loading
Loading
+44 −0
Original line number Original line Diff line number Diff line
@@ -736,6 +736,7 @@ class StorageManagerService extends IStorageManager.Stub
    private static final int H_VOLUME_STATE_CHANGED = 15;
    private static final int H_VOLUME_STATE_CHANGED = 15;
    private static final int H_CLOUD_MEDIA_PROVIDER_CHANGED = 16;
    private static final int H_CLOUD_MEDIA_PROVIDER_CHANGED = 16;
    private static final int H_SECURE_KEYGUARD_STATE_CHANGED = 17;
    private static final int H_SECURE_KEYGUARD_STATE_CHANGED = 17;
    private static final int H_REMOUNT_VOLUMES_ON_MOVE = 18;


    class StorageManagerServiceHandler extends Handler {
    class StorageManagerServiceHandler extends Handler {
        public StorageManagerServiceHandler(Looper looper) {
        public StorageManagerServiceHandler(Looper looper) {
@@ -883,6 +884,10 @@ class StorageManagerService extends IStorageManager.Stub
                    }
                    }
                    break;
                    break;
                }
                }
                case H_REMOUNT_VOLUMES_ON_MOVE: {
                    remountVolumesForRunningUsersOnMove();
                    break;
                }
            }
            }
        }
        }
    }
    }
@@ -1372,6 +1377,44 @@ class StorageManagerService extends IStorageManager.Stub
        }
        }
    }
    }


    /**
     * This method informs vold and storaged that the user has stopped and started whenever move
     * storage is performed. This ensures that the correct emulated volumes are mounted for the
     * users other than the current user. This solves an edge case wherein the correct emulated
     * volumes are not mounted, this will cause the media data to be still stored on internal
     * storage whereas the data should be stored in the adopted primary storage. This method stops
     * the users at vold first which will remove the old volumes which and starts the users at vold
     * which will reattach the correct volumes. This does not performs a full reset as full reset
     * clears every state from vold and SMS {@link #resetIfRebootedAndConnected} which is expensive
     * and causes instability.
     */
    private void remountVolumesForRunningUsersOnMove() {
        // Do not want to hold the lock for long
        final List<Integer> unlockedUsers = new ArrayList<>();
        synchronized (mLock) {
            for (int userId : mSystemUnlockedUsers) {
                if (userId == mCurrentUserId) continue;
                unlockedUsers.add(userId);
            }
        }
        for (Integer userId : unlockedUsers) {
            try {
                mVold.onUserStopped(userId);
                mStoraged.onUserStopped(userId);
            } catch (Exception e) {
                Slog.wtf(TAG, e);
            }
        }
        for (Integer userId : unlockedUsers) {
            try {
                mVold.onUserStarted(userId);
                mStoraged.onUserStarted(userId);
            } catch (Exception e) {
                Slog.wtf(TAG, e);
            }
        }
    }

    private boolean supportsBlockCheckpoint() throws RemoteException {
    private boolean supportsBlockCheckpoint() throws RemoteException {
        enforcePermission(android.Manifest.permission.MOUNT_FORMAT_FILESYSTEMS);
        enforcePermission(android.Manifest.permission.MOUNT_FORMAT_FILESYSTEMS);
        return mVold.supportsBlockCheckpoint();
        return mVold.supportsBlockCheckpoint();
@@ -1907,6 +1950,7 @@ class StorageManagerService extends IStorageManager.Stub


            mPrimaryStorageUuid = mMoveTargetUuid;
            mPrimaryStorageUuid = mMoveTargetUuid;
            writeSettingsLocked();
            writeSettingsLocked();
            mHandler.obtainMessage(H_REMOUNT_VOLUMES_ON_MOVE).sendToTarget();
        }
        }


        if (PackageManager.isMoveStatusFinished(status)) {
        if (PackageManager.isMoveStatusFinished(status)) {