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

Commit d8c3b151 authored by Jeff Sharkey's avatar Jeff Sharkey Committed by Android (Google) Code Review
Browse files

Merge "Package and storage movement callbacks."

parents f2ae3a8e 620b32b3
Loading
Loading
Loading
Loading
+15 −30
Original line number Diff line number Diff line
@@ -51,9 +51,11 @@ import android.os.Bundle;
import android.os.IUserManager;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SystemClock;
import android.os.UserHandle;
import android.os.UserManager;
import android.text.TextUtils;
import android.text.format.DateUtils;
import android.util.Log;

import libcore.io.IoUtils;
@@ -1283,20 +1285,6 @@ public final class Pm {
        }
    }

    class LocalPackageMoveObserver extends IPackageMoveObserver.Stub {
        boolean finished;
        int returnCode;

        @Override
        public void packageMoved(String packageName, int returnCode) throws RemoteException {
            synchronized (this) {
                this.finished = true;
                this.returnCode = returnCode;
                notifyAll();
            }
        }
    }

    public int runMove() {
        final String packageName = nextArg();
        String volumeUuid = nextArg();
@@ -1304,25 +1292,22 @@ public final class Pm {
            volumeUuid = null;
        }

        final LocalPackageMoveObserver obs = new LocalPackageMoveObserver();
        try {
            mPm.movePackageAndData(packageName, volumeUuid, obs);
            final int moveId = mPm.movePackage(packageName, volumeUuid);

            synchronized (obs) {
                while (!obs.finished) {
                    try {
                        obs.wait();
                    } catch (InterruptedException e) {
                    }
            int status = mPm.getMoveStatus(moveId);
            while (!PackageManager.isMoveStatusFinished(status)) {
                SystemClock.sleep(DateUtils.SECOND_IN_MILLIS);
                status = mPm.getMoveStatus(moveId);
            }
                if (obs.returnCode == PackageManager.MOVE_SUCCEEDED) {

            if (status == PackageManager.MOVE_SUCCEEDED) {
                System.out.println("Success");
                return 0;
            } else {
                    System.err.println("Failure [" + obs.returnCode + "]");
                System.err.println("Failure [" + status + "]");
                return 1;
            }
            }
        } catch (RemoteException e) {
            throw e.rethrowAsRuntimeException();
        }
+174 −27
Original line number Diff line number Diff line
@@ -62,6 +62,9 @@ import android.graphics.Rect;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.os.Process;
import android.os.RemoteException;
import android.os.SystemProperties;
@@ -81,7 +84,9 @@ import com.android.internal.util.UserIcons;

import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Objects;

/*package*/
final class ApplicationPackageManager extends PackageManager {
@@ -98,6 +103,9 @@ final class ApplicationPackageManager extends PackageManager {
    @GuardedBy("mLock")
    private PackageInstaller mInstaller;

    @GuardedBy("mDelegates")
    private final ArrayList<MoveCallbackDelegate> mDelegates = new ArrayList<>();

    UserManager getUserManager() {
        synchronized (mLock) {
            if (mUserManager == null) {
@@ -1410,57 +1418,100 @@ final class ApplicationPackageManager extends PackageManager {
    }

    @Override
    public void movePackage(String packageName, IPackageMoveObserver observer, int flags) {
    public String getInstallerPackageName(String packageName) {
        try {
            return mPM.getInstallerPackageName(packageName);
        } catch (RemoteException e) {
            // Should never happen!
        }
        return null;
    }

    @Override
    public int getMoveStatus(int moveId) {
        try {
            return mPM.getMoveStatus(moveId);
        } catch (RemoteException e) {
            throw e.rethrowAsRuntimeException();
        }
    }

    @Override
    public void registerMoveCallback(MoveCallback callback, Handler handler) {
        synchronized (mDelegates) {
            final MoveCallbackDelegate delegate = new MoveCallbackDelegate(callback,
                    handler.getLooper());
            try {
                mPM.registerMoveCallback(delegate);
            } catch (RemoteException e) {
                throw e.rethrowAsRuntimeException();
            }
            mDelegates.add(delegate);
        }
    }

    @Override
    public void unregisterMoveCallback(MoveCallback callback) {
        synchronized (mDelegates) {
            for (Iterator<MoveCallbackDelegate> i = mDelegates.iterator(); i.hasNext();) {
                final MoveCallbackDelegate delegate = i.next();
                if (delegate.mCallback == callback) {
                    try {
            mPM.movePackage(packageName, observer, flags);
                        mPM.unregisterMoveCallback(delegate);
                    } catch (RemoteException e) {
                        throw e.rethrowAsRuntimeException();
                    }
                    i.remove();
                }
            }
        }
    }

    @Override
    public void movePackageAndData(String packageName, String volumeUuid,
            IPackageMoveObserver observer) {
    public int movePackage(String packageName, VolumeInfo vol) {
        try {
            mPM.movePackageAndData(packageName, volumeUuid, observer);
            final String volumeUuid;
            if (VolumeInfo.ID_PRIVATE_INTERNAL.equals(vol.id)) {
                volumeUuid = StorageManager.UUID_PRIVATE_INTERNAL;
            } else if (vol.isPrimaryPhysical()) {
                volumeUuid = StorageManager.UUID_PRIMARY_PHYSICAL;
            } else {
                volumeUuid = Preconditions.checkNotNull(vol.fsUuid);
            }

            return mPM.movePackage(packageName, volumeUuid);
        } catch (RemoteException e) {
            throw e.rethrowAsRuntimeException();
        }
    }

    @Override
    public @NonNull VolumeInfo getApplicationCurrentVolume(ApplicationInfo app) {
    public @Nullable VolumeInfo getPackageCurrentVolume(ApplicationInfo app) {
        final StorageManager storage = mContext.getSystemService(StorageManager.class);
        if (app.isInternal()) {
            return Preconditions.checkNotNull(
                    storage.findVolumeById(VolumeInfo.ID_PRIVATE_INTERNAL));
            return storage.findVolumeById(VolumeInfo.ID_PRIVATE_INTERNAL);
        } else if (app.isExternalAsec()) {
            final List<VolumeInfo> vols = storage.getVolumes();
            for (VolumeInfo vol : vols) {
                if ((vol.getType() == VolumeInfo.TYPE_PUBLIC) && vol.isPrimary()) {
                    return vol;
                }
            }
            throw new IllegalStateException("Failed to find primary public volume");
            return storage.getPrimaryPhysicalVolume();
        } else {
            return Preconditions.checkNotNull(storage.findVolumeByUuid(app.volumeUuid));
            return storage.findVolumeByUuid(app.volumeUuid);
        }
    }

    @Override
    public @NonNull List<VolumeInfo> getApplicationCandidateVolumes(ApplicationInfo app) {
    public @NonNull List<VolumeInfo> getPackageCandidateVolumes(ApplicationInfo app) {
        final StorageManager storage = mContext.getSystemService(StorageManager.class);
        final VolumeInfo currentVol = getPackageCurrentVolume(app);
        final List<VolumeInfo> vols = storage.getVolumes();
        final List<VolumeInfo> candidates = new ArrayList<>();
        for (VolumeInfo vol : vols) {
            if (isCandidateVolume(app, vol)) {
            if (Objects.equals(vol, currentVol) || isPackageCandidateVolume(app, vol)) {
                candidates.add(vol);
            }
        }
        return candidates;
    }

    private static boolean isCandidateVolume(ApplicationInfo app, VolumeInfo vol) {
    private static boolean isPackageCandidateVolume(ApplicationInfo app, VolumeInfo vol) {
        // Private internal is always an option
        if (VolumeInfo.ID_PRIVATE_INTERNAL.equals(vol.getId())) {
            return true;
@@ -1473,10 +1524,14 @@ final class ApplicationPackageManager extends PackageManager {
            return false;
        }

        // Moving into an ASEC on public primary is only an option when app is
        // internal, or already in ASEC
        if ((vol.getType() == VolumeInfo.TYPE_PUBLIC) && vol.isPrimary()) {
            return app.isInternal() || app.isExternalAsec();
        // Gotta be able to write there
        if (!vol.isMountedWritable()) {
            return false;
        }

        // Moving into an ASEC on public primary is only option internal
        if (vol.isPrimaryPhysical()) {
            return app.isInternal();
        }

        // Otherwise we can move to any private volume
@@ -1484,13 +1539,66 @@ final class ApplicationPackageManager extends PackageManager {
    }

    @Override
    public String getInstallerPackageName(String packageName) {
    public int movePrimaryStorage(VolumeInfo vol) {
        try {
            return mPM.getInstallerPackageName(packageName);
            final String volumeUuid;
            if (VolumeInfo.ID_PRIVATE_INTERNAL.equals(vol.id)) {
                volumeUuid = StorageManager.UUID_PRIVATE_INTERNAL;
            } else if (vol.isPrimaryPhysical()) {
                volumeUuid = StorageManager.UUID_PRIMARY_PHYSICAL;
            } else {
                volumeUuid = Preconditions.checkNotNull(vol.fsUuid);
            }

            return mPM.movePrimaryStorage(volumeUuid);
        } catch (RemoteException e) {
            // Should never happen!
            throw e.rethrowAsRuntimeException();
        }
        return null;
    }

    public @Nullable VolumeInfo getPrimaryStorageCurrentVolume() {
        final StorageManager storage = mContext.getSystemService(StorageManager.class);
        final String volumeUuid = storage.getPrimaryStorageUuid();
        if (Objects.equals(StorageManager.UUID_PRIVATE_INTERNAL, volumeUuid)) {
            return storage.findVolumeById(VolumeInfo.ID_PRIVATE_INTERNAL);
        } else if (Objects.equals(StorageManager.UUID_PRIMARY_PHYSICAL, volumeUuid)) {
            return storage.getPrimaryPhysicalVolume();
        } else {
            return storage.findVolumeByUuid(volumeUuid);
        }
    }

    public @NonNull List<VolumeInfo> getPrimaryStorageCandidateVolumes() {
        final StorageManager storage = mContext.getSystemService(StorageManager.class);
        final VolumeInfo currentVol = getPrimaryStorageCurrentVolume();
        final List<VolumeInfo> vols = storage.getVolumes();
        final List<VolumeInfo> candidates = new ArrayList<>();
        for (VolumeInfo vol : vols) {
            if (Objects.equals(vol, currentVol) || isPrimaryStorageCandidateVolume(vol)) {
                candidates.add(vol);
            }
        }
        return candidates;
    }

    private static boolean isPrimaryStorageCandidateVolume(VolumeInfo vol) {
        // Private internal is always an option
        if (VolumeInfo.ID_PRIVATE_INTERNAL.equals(vol.getId())) {
            return true;
        }

        // Gotta be able to write there
        if (!vol.isMountedWritable()) {
            return false;
        }

        // We can move to public volumes on legacy devices
        if ((vol.getType() == VolumeInfo.TYPE_PUBLIC) && vol.getDisk().isDefaultPrimary()) {
            return true;
        }

        // Otherwise we can move to any private volume
        return (vol.getType() == VolumeInfo.TYPE_PRIVATE);
    }

    @Override
@@ -1941,6 +2049,45 @@ final class ApplicationPackageManager extends PackageManager {
        return null;
    }

    /** {@hide} */
    private static class MoveCallbackDelegate extends IPackageMoveObserver.Stub implements
            Handler.Callback {
        private static final int MSG_STARTED = 1;
        private static final int MSG_STATUS_CHANGED = 2;

        final MoveCallback mCallback;
        final Handler mHandler;

        public MoveCallbackDelegate(MoveCallback callback, Looper looper) {
            mCallback = callback;
            mHandler = new Handler(looper, this);
        }

        @Override
        public boolean handleMessage(Message msg) {
            final int moveId = msg.arg1;
            switch (msg.what) {
                case MSG_STARTED:
                    mCallback.onStarted(moveId, (String) msg.obj);
                    return true;
                case MSG_STATUS_CHANGED:
                    mCallback.onStatusChanged(moveId, msg.arg2, (long) msg.obj);
                    return true;
            }
            return false;
        }

        @Override
        public void onStarted(int moveId, String title) {
            mHandler.obtainMessage(MSG_STARTED, moveId, 0, title).sendToTarget();
        }

        @Override
        public void onStatusChanged(int moveId, int status, long estMillis) {
            mHandler.obtainMessage(MSG_STATUS_CHANGED, moveId, status, estMillis).sendToTarget();
        }
    }

    private final ContextImpl mContext;
    private final IPackageManager mPM;

+7 −3
Original line number Diff line number Diff line
@@ -50,7 +50,6 @@ import android.net.Uri;
import android.os.Bundle;
import android.os.ParcelFileDescriptor;
import android.content.IntentSender;
import com.android.internal.os.IResultReceiver;

/**
 *  See {@link PackageManager} for documentation on most of the APIs
@@ -431,8 +430,13 @@ interface IPackageManager {

    PackageCleanItem nextPackageToClean(in PackageCleanItem lastPackage);

    void movePackage(String packageName, IPackageMoveObserver observer, int flags);
    void movePackageAndData(String packageName, String volumeUuid, IPackageMoveObserver observer);
    int getMoveStatus(int moveId);

    void registerMoveCallback(in IPackageMoveObserver callback);
    void unregisterMoveCallback(in IPackageMoveObserver callback);

    int movePackage(in String packageName, in String volumeUuid);
    int movePrimaryStorage(in String volumeUuid);

    boolean addPermissionAsync(in PermissionInfo info);

+2 −2
Original line number Diff line number Diff line
@@ -22,6 +22,6 @@ package android.content.pm;
 * @hide
 */
oneway interface IPackageMoveObserver {
    void packageMoved(in String packageName, int returnCode);
    void onStarted(int moveId, String title);
    void onStatusChanged(int moveId, int status, long estMillis);
}
+38 −6
Original line number Diff line number Diff line
@@ -42,6 +42,7 @@ import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.RemoteException;
import android.os.UserHandle;
import android.os.storage.VolumeInfo;
@@ -875,7 +876,8 @@ public abstract class PackageManager {
     *
     * @hide
     */
    public static final int MOVE_SUCCEEDED = 1;
    public static final int MOVE_SUCCEEDED = -100;

    /**
     * Error code that is passed to the {@link IPackageMoveObserver} by
     * {@link #movePackage(android.net.Uri, IPackageMoveObserver)}
@@ -941,6 +943,7 @@ public abstract class PackageManager {
     * been installed on external media.
     * @hide
     */
    @Deprecated
    public static final int MOVE_INTERNAL = 0x00000001;

    /**
@@ -948,8 +951,12 @@ public abstract class PackageManager {
     * the package should be moved to external media.
     * @hide
     */
    @Deprecated
    public static final int MOVE_EXTERNAL_MEDIA = 0x00000002;

    /** {@hide} */
    public static final String EXTRA_MOVE_ID = "android.content.pm.extra.MOVE_ID";

    /**
     * Usable by the required verifier as the {@code verificationCode} argument
     * for {@link PackageManager#verifyPendingInstall} to indicate that it will
@@ -4183,17 +4190,42 @@ public abstract class PackageManager {
     * @hide
     */
    @Deprecated
    public abstract void movePackage(String packageName, IPackageMoveObserver observer, int flags);
    public void movePackage(String packageName, IPackageMoveObserver observer, int flags) {
        throw new UnsupportedOperationException();
    }

    /** {@hide} */
    public abstract void movePackageAndData(String packageName, String volumeUuid,
            IPackageMoveObserver observer);
    public static boolean isMoveStatusFinished(int status) {
        return (status < 0 || status > 100);
    }

    /** {@hide} */
    public static abstract class MoveCallback {
        public abstract void onStarted(int moveId, String title);
        public abstract void onStatusChanged(int moveId, int status, long estMillis);
    }

    /** {@hide} */
    public abstract @Nullable VolumeInfo getApplicationCurrentVolume(ApplicationInfo app);
    public abstract int getMoveStatus(int moveId);

    /** {@hide} */
    public abstract @NonNull List<VolumeInfo> getApplicationCandidateVolumes(ApplicationInfo app);
    public abstract void registerMoveCallback(MoveCallback callback, Handler handler);
    /** {@hide} */
    public abstract void unregisterMoveCallback(MoveCallback callback);

    /** {@hide} */
    public abstract int movePackage(String packageName, VolumeInfo vol);
    /** {@hide} */
    public abstract @Nullable VolumeInfo getPackageCurrentVolume(ApplicationInfo app);
    /** {@hide} */
    public abstract @NonNull List<VolumeInfo> getPackageCandidateVolumes(ApplicationInfo app);

    /** {@hide} */
    public abstract int movePrimaryStorage(VolumeInfo vol);
    /** {@hide} */
    public abstract @Nullable VolumeInfo getPrimaryStorageCurrentVolume();
    /** {@hide} */
    public abstract @NonNull List<VolumeInfo> getPrimaryStorageCandidateVolumes();

    /**
     * Returns the device identity that verifiers can use to associate their scheme to a particular
Loading