diff options
| author | 2023-08-16 21:03:51 +0000 | |
|---|---|---|
| committer | 2023-08-16 21:03:51 +0000 | |
| commit | 0c50beefbfc5b0857c46e0c36a5ccfca050bd917 (patch) | |
| tree | 9be1c9373fa23d9a82c07226a77c4fce8ff26685 | |
| parent | c48def7c20f466e22b487fba50e4e1b446ed9da9 (diff) | |
| parent | 4afb040f11a0c46e618240f86633724c850eb7e1 (diff) | |
Merge "Adopted Storage: Prepare user storage before move" into main am: 798b1fe4e8 am: 274ba85abb am: 4afb040f11
Original change: https://android-review.googlesource.com/c/platform/frameworks/base/+/2694909
Change-Id: I8ebfcaa4d367ea92a15fe3f213f4d1dd18371e57
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
3 files changed, 67 insertions, 24 deletions
diff --git a/core/java/android/os/storage/StorageManagerInternal.java b/core/java/android/os/storage/StorageManagerInternal.java index 059bd846327c..22e8251b3f52 100644 --- a/core/java/android/os/storage/StorageManagerInternal.java +++ b/core/java/android/os/storage/StorageManagerInternal.java @@ -19,6 +19,7 @@ package android.os.storage; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.UserIdInt; +import android.content.pm.UserInfo; import android.os.IVold; import java.util.List; @@ -169,4 +170,19 @@ public abstract class StorageManagerInternal { */ public abstract void registerCloudProviderChangeListener( @NonNull CloudProviderChangeListener listener); + + /** + * Prepares user data directories before moving storage or apps. This is required as adoptable + * storage unlock is tied to the prepare user data and storage needs to be unlocked before + * performing any operations on it. This will also create user data directories before + * initiating the move operations, which essential for ensuring the directories to have correct + * SELinux labels and permissions. + * + * @param fromVolumeUuid the source volume UUID from which content needs to be transferred + * @param toVolumeUuid the destination volume UUID to which contents are to be transferred + * @param users a list of users for whom to prepare storage + */ + public abstract void prepareUserStorageForMove(String fromVolumeUuid, String toVolumeUuid, + List<UserInfo> users); + } diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java index e467dd65b371..e9cfceaf2b93 100644 --- a/services/core/java/com/android/server/StorageManagerService.java +++ b/services/core/java/com/android/server/StorageManagerService.java @@ -1289,6 +1289,16 @@ class StorageManagerService extends IStorageManager.Stub return mVold.supportsBlockCheckpoint(); } + private void prepareUserStorageForMoveInternal(String fromVolumeUuid, String toVolumeUuid, + List<UserInfo> users) throws Exception { + + final int flags = StorageManager.FLAG_STORAGE_DE | StorageManager.FLAG_STORAGE_CE; + for (UserInfo user : users) { + prepareUserStorageInternal(fromVolumeUuid, user.id, user.serialNumber, flags); + prepareUserStorageInternal(toVolumeUuid, user.id, user.serialNumber, flags); + } + } + @Override public void onAwakeStateChanged(boolean isAwake) { // Ignored @@ -2912,6 +2922,7 @@ class StorageManagerService extends IStorageManager.Stub final VolumeInfo from; final VolumeInfo to; + final List<UserInfo> users; synchronized (mLock) { if (Objects.equals(mPrimaryStorageUuid, volumeUuid)) { @@ -2925,7 +2936,7 @@ class StorageManagerService extends IStorageManager.Stub mMoveTargetUuid = volumeUuid; // We need all the users unlocked to move their primary storage - final List<UserInfo> users = mContext.getSystemService(UserManager.class).getUsers(); + users = mContext.getSystemService(UserManager.class).getUsers(); for (UserInfo user : users) { if (StorageManager.isFileEncrypted() && !isUserKeyUnlocked(user.id)) { Slog.w(TAG, "Failing move due to locked user " + user.id); @@ -2961,6 +2972,19 @@ class StorageManagerService extends IStorageManager.Stub } } + // Prepare the storage before move, this is required to unlock adoptable storage (as the + // keys are tied to prepare user data step) & also is required for the destination files to + // end up with the correct SELinux labels and encryption policies for directories + try { + prepareUserStorageForMoveInternal(mPrimaryStorageUuid, volumeUuid, users); + } catch (Exception e) { + Slog.w(TAG, "Failing move due to failure on prepare user data", e); + synchronized (mLock) { + onMoveStatusLocked(PackageManager.MOVE_FAILED_INTERNAL_ERROR); + } + return; + } + try { mVold.moveStorage(from.id, to.id, new IVoldTaskListener.Stub() { @Override @@ -4904,5 +4928,16 @@ class StorageManagerService extends IStorageManager.Stub mCloudProviderChangeListeners.add(listener); mHandler.obtainMessage(H_CLOUD_MEDIA_PROVIDER_CHANGED, listener).sendToTarget(); } + + @Override + public void prepareUserStorageForMove(String fromVolumeUuid, String toVolumeUuid, + List<UserInfo> users) { + try { + prepareUserStorageForMoveInternal(fromVolumeUuid, toVolumeUuid, users); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + } } diff --git a/services/core/java/com/android/server/pm/MovePackageHelper.java b/services/core/java/com/android/server/pm/MovePackageHelper.java index adee143691b1..481bd975fef5 100644 --- a/services/core/java/com/android/server/pm/MovePackageHelper.java +++ b/services/core/java/com/android/server/pm/MovePackageHelper.java @@ -49,8 +49,8 @@ import android.os.RemoteCallbackList; import android.os.RemoteException; import android.os.UserHandle; import android.os.storage.StorageManager; +import android.os.storage.StorageManagerInternal; import android.os.storage.VolumeInfo; -import android.text.TextUtils; import android.util.MathUtils; import android.util.Slog; import android.util.SparseIntArray; @@ -64,6 +64,7 @@ import com.android.server.pm.pkg.PackageStateInternal; import com.android.server.pm.pkg.PackageStateUtils; import java.io.File; +import java.util.ArrayList; import java.util.Objects; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; @@ -223,9 +224,7 @@ public final class MovePackageHelper { } try { - for (int index = 0; index < installedUserIds.length; index++) { - prepareUserDataForVolumeIfRequired(volumeUuid, installedUserIds[index], storage); - } + prepareUserStorageForMove(currentVolumeUuid, volumeUuid, installedUserIds); } catch (RuntimeException e) { freezer.close(); throw new PackageManagerException(MOVE_FAILED_INTERNAL_ERROR, @@ -379,27 +378,20 @@ public final class MovePackageHelper { return true; } - private void prepareUserDataForVolumeIfRequired(String volumeUuid, int userId, - StorageManager storageManager) { - if (TextUtils.isEmpty(volumeUuid) - || doesDataDirectoryExistForUser(volumeUuid, userId)) { - return; - } + private void prepareUserStorageForMove(String fromVolumeUuid, String toVolumeUuid, + int[] userIds) { if (DEBUG_INSTALL) { - Slog.d(TAG, "Preparing user directories for user u" + userId + " for UUID " - + volumeUuid); + Slog.d(TAG, "Preparing user directories before moving app, from UUID " + fromVolumeUuid + + " to UUID " + toVolumeUuid); } - final UserInfo user = mPm.mUserManager.getUserInfo(userId); - if (user == null) return; - // This call is same as StorageEventHelper#loadPrivatePackagesInner which prepares - // the storage before reconciling apps - storageManager.prepareUserStorage(volumeUuid, user.id, user.serialNumber, - StorageManager.FLAG_STORAGE_DE | StorageManager.FLAG_STORAGE_CE); - } - - private boolean doesDataDirectoryExistForUser(String uuid, int userId) { - final File userDirectoryFile = Environment.getDataUserCeDirectory(uuid, userId); - return userDirectoryFile != null && userDirectoryFile.exists(); + final StorageManagerInternal smInternal = + mPm.mInjector.getLocalService(StorageManagerInternal.class); + final ArrayList<UserInfo> users = new ArrayList<>(); + for (int userId : userIds) { + final UserInfo user = mPm.mUserManager.getUserInfo(userId); + users.add(user); + } + smInternal.prepareUserStorageForMove(fromVolumeUuid, toVolumeUuid, users); } public static class MoveCallbacks extends Handler { |