Loading core/java/android/os/storage/StorageManagerInternal.java +16 −0 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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); } services/core/java/com/android/server/StorageManagerService.java +36 −1 Original line number Diff line number Diff line Loading @@ -1377,6 +1377,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 Loading Loading @@ -2986,6 +2996,7 @@ class StorageManagerService extends IStorageManager.Stub final VolumeInfo from; final VolumeInfo to; final List<UserInfo> users; synchronized (mLock) { if (Objects.equals(mPrimaryStorageUuid, volumeUuid)) { Loading @@ -2999,7 +3010,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); Loading Loading @@ -3035,6 +3046,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 Loading Loading @@ -5024,5 +5048,16 @@ class StorageManagerService extends IStorageManager.Stub mCloudProviderChangeListeners.add(listener); mHandler.obtainMessage(H_CLOUD_MEDIA_PROVIDER_CHANGED, listener); } @Override public void prepareUserStorageForMove(String fromVolumeUuid, String toVolumeUuid, List<UserInfo> users) { try { prepareUserStorageForMoveInternal(fromVolumeUuid, toVolumeUuid, users); } catch (Exception e) { throw new RuntimeException(e); } } } } services/core/java/com/android/server/pm/MovePackageHelper.java +16 −24 Original line number Diff line number Diff line Loading @@ -48,8 +48,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; Loading @@ -63,6 +63,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; Loading Loading @@ -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, Loading Loading @@ -380,27 +379,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 StorageManagerInternal smInternal = mPm.mInjector.getLocalService(StorageManagerInternal.class); final ArrayList<UserInfo> users = new ArrayList<>(); for (int userId : userIds) { 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); users.add(user); } private boolean doesDataDirectoryExistForUser(String uuid, int userId) { final File userDirectoryFile = Environment.getDataUserCeDirectory(uuid, userId); return userDirectoryFile != null && userDirectoryFile.exists(); smInternal.prepareUserStorageForMove(fromVolumeUuid, toVolumeUuid, users); } public static class MoveCallbacks extends Handler { Loading Loading
core/java/android/os/storage/StorageManagerInternal.java +16 −0 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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); }
services/core/java/com/android/server/StorageManagerService.java +36 −1 Original line number Diff line number Diff line Loading @@ -1377,6 +1377,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 Loading Loading @@ -2986,6 +2996,7 @@ class StorageManagerService extends IStorageManager.Stub final VolumeInfo from; final VolumeInfo to; final List<UserInfo> users; synchronized (mLock) { if (Objects.equals(mPrimaryStorageUuid, volumeUuid)) { Loading @@ -2999,7 +3010,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); Loading Loading @@ -3035,6 +3046,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 Loading Loading @@ -5024,5 +5048,16 @@ class StorageManagerService extends IStorageManager.Stub mCloudProviderChangeListeners.add(listener); mHandler.obtainMessage(H_CLOUD_MEDIA_PROVIDER_CHANGED, listener); } @Override public void prepareUserStorageForMove(String fromVolumeUuid, String toVolumeUuid, List<UserInfo> users) { try { prepareUserStorageForMoveInternal(fromVolumeUuid, toVolumeUuid, users); } catch (Exception e) { throw new RuntimeException(e); } } } }
services/core/java/com/android/server/pm/MovePackageHelper.java +16 −24 Original line number Diff line number Diff line Loading @@ -48,8 +48,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; Loading @@ -63,6 +63,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; Loading Loading @@ -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, Loading Loading @@ -380,27 +379,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 StorageManagerInternal smInternal = mPm.mInjector.getLocalService(StorageManagerInternal.class); final ArrayList<UserInfo> users = new ArrayList<>(); for (int userId : userIds) { 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); users.add(user); } private boolean doesDataDirectoryExistForUser(String uuid, int userId) { final File userDirectoryFile = Environment.getDataUserCeDirectory(uuid, userId); return userDirectoryFile != null && userDirectoryFile.exists(); smInternal.prepareUserStorageForMove(fromVolumeUuid, toVolumeUuid, users); } public static class MoveCallbacks extends Handler { Loading