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

Commit 4afb040f authored by Eric Biggers's avatar Eric Biggers Committed by Automerger Merge Worker
Browse files

Merge "Adopted Storage: Prepare user storage before move" into main am: 798b1fe4 am: 274ba85a

parents b0ff8a0f 274ba85a
Loading
Loading
Loading
Loading
+16 −0
Original line number Diff line number Diff line
@@ -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);

}
+36 −1
Original line number Diff line number Diff line
@@ -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);
            }
        }

    }
}
+15 −23
Original line number Diff line number Diff line
@@ -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 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 {