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

Commit a0907436 authored by Jeff Sharkey's avatar Jeff Sharkey
Browse files

PackageInstaller API refactoring.

Switch to using IntentSender for results to give installers easier
lifecycle management.  Move param and info objects to inner classes.

Bug: 17008440
Change-Id: I944cfc580325ccc07acf22e0c681a5542d6abc43
parent 82d6d337
Loading
Loading
Loading
Loading
+47 −59
Original line number Diff line number Diff line
@@ -8540,36 +8540,6 @@ package android.content.pm {
    field public int reqGlEsVersion;
  }
  public class InstallSessionInfo implements android.os.Parcelable {
    method public int describeContents();
    method public android.graphics.Bitmap getAppIcon();
    method public java.lang.CharSequence getAppLabel();
    method public java.lang.String getAppPackageName();
    method public android.content.Intent getDetailsIntent();
    method public java.lang.String getInstallerPackageName();
    method public float getProgress();
    method public int getSessionId();
    method public boolean isOpen();
    method public void writeToParcel(android.os.Parcel, int);
    field public static final android.os.Parcelable.Creator CREATOR;
  }
  public class InstallSessionParams implements android.os.Parcelable {
    ctor public InstallSessionParams(int);
    method public int describeContents();
    method public void setAppIcon(android.graphics.Bitmap);
    method public void setAppLabel(java.lang.CharSequence);
    method public void setAppPackageName(java.lang.String);
    method public void setInstallLocation(int);
    method public void setOriginatingUri(android.net.Uri);
    method public void setReferrerUri(android.net.Uri);
    method public void setSize(long);
    method public void writeToParcel(android.os.Parcel, int);
    field public static final android.os.Parcelable.Creator CREATOR;
    field public static final int MODE_FULL_INSTALL = 1; // 0x1
    field public static final int MODE_INHERIT_EXISTING = 2; // 0x2
  }
  public class InstrumentationInfo extends android.content.pm.PackageItemInfo implements android.os.Parcelable {
    ctor public InstrumentationInfo();
    ctor public InstrumentationInfo(android.content.pm.InstrumentationInfo);
@@ -8671,37 +8641,35 @@ package android.content.pm {
  public class PackageInstaller {
    method public void addSessionCallback(android.content.pm.PackageInstaller.SessionCallback);
    method public void addSessionCallback(android.content.pm.PackageInstaller.SessionCallback, android.os.Handler);
    method public int createSession(android.content.pm.InstallSessionParams) throws java.io.IOException;
    method public java.util.List<android.content.pm.InstallSessionInfo> getAllSessions();
    method public java.util.List<android.content.pm.InstallSessionInfo> getMySessions();
    method public android.content.pm.InstallSessionInfo getSessionInfo(int);
    method public int createSession(android.content.pm.PackageInstaller.SessionParams) throws java.io.IOException;
    method public java.util.List<android.content.pm.PackageInstaller.SessionInfo> getAllSessions();
    method public java.util.List<android.content.pm.PackageInstaller.SessionInfo> getMySessions();
    method public android.content.pm.PackageInstaller.SessionInfo getSessionInfo(int);
    method public android.content.pm.PackageInstaller.Session openSession(int);
    method public void removeSessionCallback(android.content.pm.PackageInstaller.SessionCallback);
    method public void uninstall(java.lang.String, android.content.pm.PackageInstaller.UninstallCallback);
    method public void uninstall(java.lang.String, android.content.IntentSender);
    field public static final java.lang.String ACTION_SESSION_DETAILS = "android.content.pm.action.SESSION_DETAILS";
    field public static final java.lang.String EXTRA_PACKAGE_NAMES = "android.content.pm.extra.PACKAGE_NAMES";
    field public static final java.lang.String EXTRA_SESSION_ID = "android.content.pm.extra.SESSION_ID";
  }
  public static abstract class PackageInstaller.CommitCallback {
    ctor public PackageInstaller.CommitCallback();
    method public abstract void onFailure(int, java.lang.String, android.os.Bundle);
    method public abstract void onSuccess();
    method public abstract void onUserActionRequired(android.content.Intent);
    field public static final java.lang.String EXTRA_PACKAGE_NAME = "android.content.pm.extra.PACKAGE_NAME";
    field public static final int FAILURE_ABORTED = 5; // 0x5
    field public static final int FAILURE_CONFLICT = 2; // 0x2
    field public static final int FAILURE_INCOMPATIBLE = 4; // 0x4
    field public static final int FAILURE_INVALID = 1; // 0x1
    field public static final int FAILURE_STORAGE = 3; // 0x3
    field public static final int FAILURE_UNKNOWN = 0; // 0x0
    field public static final java.lang.String EXTRA_STATUS = "android.content.pm.extra.STATUS";
    field public static final java.lang.String EXTRA_STATUS_MESSAGE = "android.content.pm.extra.STATUS_MESSAGE";
    field public static final int STATUS_FAILURE = 1; // 0x1
    field public static final int STATUS_FAILURE_ABORTED = 2; // 0x2
    field public static final int STATUS_FAILURE_BLOCKED = 1; // 0x1
    field public static final int STATUS_FAILURE_CONFLICT = 4; // 0x4
    field public static final int STATUS_FAILURE_INCOMPATIBLE = 6; // 0x6
    field public static final int STATUS_FAILURE_INVALID = 3; // 0x3
    field public static final int STATUS_FAILURE_STORAGE = 5; // 0x5
    field public static final int STATUS_SUCCESS = 0; // 0x0
    field public static final int STATUS_USER_ACTION_REQUIRED = -1; // 0xffffffff
  }
  public static class PackageInstaller.Session implements java.io.Closeable {
    method public void abandon();
    method public void close();
    method public void commit(android.content.pm.PackageInstaller.CommitCallback);
    method public void commit(android.content.IntentSender);
    method public void fsync(java.io.OutputStream) throws java.io.IOException;
    method public java.lang.String[] list();
    method public java.lang.String[] getNames();
    method public java.io.InputStream openRead(java.lang.String) throws java.io.IOException;
    method public java.io.OutputStream openWrite(java.lang.String, long, long) throws java.io.IOException;
    method public void setProgress(float);
@@ -8716,14 +8684,34 @@ package android.content.pm {
    method public abstract void onProgressChanged(int, float);
  }
  public static abstract class PackageInstaller.UninstallCallback {
    ctor public PackageInstaller.UninstallCallback();
    method public abstract void onFailure(int, java.lang.String, android.os.Bundle);
    method public abstract void onSuccess();
    method public abstract void onUserActionRequired(android.content.Intent);
    field public static final int FAILURE_ABORTED = 2; // 0x2
    field public static final int FAILURE_BLOCKED = 1; // 0x1
    field public static final int FAILURE_UNKNOWN = 0; // 0x0
  public static class PackageInstaller.SessionInfo implements android.os.Parcelable {
    method public int describeContents();
    method public android.graphics.Bitmap getAppIcon();
    method public java.lang.CharSequence getAppLabel();
    method public java.lang.String getAppPackageName();
    method public android.content.Intent getDetailsIntent();
    method public java.lang.String getInstallerPackageName();
    method public float getProgress();
    method public int getSessionId();
    method public boolean isOpen();
    method public void writeToParcel(android.os.Parcel, int);
    field public static final android.os.Parcelable.Creator CREATOR;
  }
  public static class PackageInstaller.SessionParams implements android.os.Parcelable {
    ctor public PackageInstaller.SessionParams(int);
    method public int describeContents();
    method public void setAppIcon(android.graphics.Bitmap);
    method public void setAppLabel(java.lang.CharSequence);
    method public void setAppPackageName(java.lang.String);
    method public void setInstallLocation(int);
    method public void setOriginatingUri(android.net.Uri);
    method public void setReferrerUri(android.net.Uri);
    method public void setSize(long);
    method public void writeToParcel(android.os.Parcel, int);
    field public static final android.os.Parcelable.Creator CREATOR;
    field public static final int MODE_FULL_INSTALL = 1; // 0x1
    field public static final int MODE_INHERIT_EXISTING = 2; // 0x2
  }
  public class PackageItemInfo {
+66 −95
Original line number Diff line number Diff line
@@ -19,21 +19,22 @@ package com.android.commands.pm;
import android.app.ActivityManager;
import android.app.ActivityManagerNative;
import android.app.IActivityManager;
import android.app.PackageDeleteObserver;
import android.app.PackageInstallObserver;
import android.content.ComponentName;
import android.content.IIntentReceiver;
import android.content.IIntentSender;
import android.content.Intent;
import android.content.IntentSender;
import android.content.pm.ApplicationInfo;
import android.content.pm.FeatureInfo;
import android.content.pm.IPackageDataObserver;
import android.content.pm.IPackageInstaller;
import android.content.pm.IPackageManager;
import android.content.pm.InstallSessionInfo;
import android.content.pm.InstallSessionParams;
import android.content.pm.InstrumentationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageInstaller;
import android.content.pm.PackageInstaller.CommitCallback;
import android.content.pm.PackageInstaller.SessionInfo;
import android.content.pm.PackageInstaller.SessionParams;
import android.content.pm.PackageItemInfo;
import android.content.pm.PackageManager;
import android.content.pm.ParceledListSlice;
@@ -74,6 +75,8 @@ import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.WeakHashMap;
import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.TimeUnit;

public final class Pm {
    private static final String TAG = "Pm";
@@ -776,36 +779,6 @@ public final class Pm {
        }
    }

    class LocalCommitCallback extends CommitCallback {
        boolean finished;
        boolean success;
        String msg;

        private void setResult(boolean success, String msg) {
            synchronized (this) {
                this.finished = true;
                this.success = success;
                this.msg = msg;
                notifyAll();
            }
        }

        @Override
        public void onUserActionRequired(Intent intent) {
            setResult(false, "Unexepected user action required!");
        }

        @Override
        public void onSuccess() {
            setResult(true, null);
        }

        @Override
        public void onFailure(int failureReason, String msg, Bundle extras) {
            setResult(false, msg);
        }
    }

    /**
     * Converts a failure code into a string by using reflection to find a matching constant
     * in PackageManager.
@@ -1007,8 +980,7 @@ public final class Pm {
    private void runInstallCreate() throws RemoteException {
        String installerPackageName = null;

        final InstallSessionParams params = new InstallSessionParams(
                InstallSessionParams.MODE_FULL_INSTALL);
        final SessionParams params = new SessionParams(SessionParams.MODE_FULL_INSTALL);
        params.installFlags = PackageManager.INSTALL_ALL_USERS;

        String opt;
@@ -1031,7 +1003,7 @@ public final class Pm {
            } else if (opt.equals("-d")) {
                params.installFlags |= PackageManager.INSTALL_ALLOW_DOWNGRADE;
            } else if (opt.equals("-p")) {
                params.mode = InstallSessionParams.MODE_INHERIT_EXISTING;
                params.mode = SessionParams.MODE_INHERIT_EXISTING;
            } else if (opt.equals("-S")) {
                params.setSize(Long.parseLong(nextOptionData()));
            } else if (opt.equals("--abi")) {
@@ -1073,7 +1045,7 @@ public final class Pm {
            }
        }

        final InstallSessionInfo info = mInstaller.getSessionInfo(sessionId);
        final SessionInfo info = mInstaller.getSessionInfo(sessionId);

        PackageInstaller.Session session = null;
        InputStream in = null;
@@ -1117,22 +1089,20 @@ public final class Pm {
        try {
            session = new PackageInstaller.Session(mInstaller.openSession(sessionId));

            final LocalCommitCallback callback = new LocalCommitCallback();
            session.commit(callback);

            synchronized (callback) {
                while (!callback.finished) {
                    try {
                        callback.wait();
                    } catch (InterruptedException e) {
                    }
                }
                if (!callback.success) {
                    throw new IllegalStateException("Failure [" + callback.msg + "]");
                }
            }
            final LocalIntentReceiver receiver = new LocalIntentReceiver();
            session.commit(receiver.getIntentSender());

            final Intent result = receiver.getResult();
            final int status = result.getIntExtra(PackageInstaller.EXTRA_STATUS,
                    PackageInstaller.STATUS_FAILURE);
            if (status == PackageInstaller.STATUS_SUCCESS) {
                System.out.println("Success");
            } else {
                Log.e(TAG, "Failure details: " + result.getExtras());
                System.out.println("Failure ["
                        + result.getStringExtra(PackageInstaller.EXTRA_STATUS_MESSAGE) + "]");
                return;
            }
        } finally {
            IoUtils.closeQuietly(session);
        }
@@ -1274,28 +1244,14 @@ public final class Pm {
        }
    }

    class LocalPackageDeleteObserver extends PackageDeleteObserver {
        boolean finished;
        boolean result;

        @Override
        public void onPackageDeleted(String name, int returnCode, String msg) {
            synchronized (this) {
                finished = true;
                result = returnCode == PackageManager.DELETE_SUCCEEDED;
                notifyAll();
            }
        }
    }

    private void runUninstall() {
        int unInstallFlags = 0;
    private void runUninstall() throws RemoteException {
        int flags = 0;
        int userId = UserHandle.USER_ALL;

        String opt;
        while ((opt=nextOption()) != null) {
            if (opt.equals("-k")) {
                unInstallFlags |= PackageManager.DELETE_KEEP_DATA;
                flags |= PackageManager.DELETE_KEEP_DATA;
            } else if (opt.equals("--user")) {
                String param = nextArg();
                if (isNumber(param)) {
@@ -1320,7 +1276,7 @@ public final class Pm {

        if (userId == UserHandle.USER_ALL) {
            userId = UserHandle.USER_OWNER;
            unInstallFlags |= PackageManager.DELETE_ALL_USERS;
            flags |= PackageManager.DELETE_ALL_USERS;
        } else {
            PackageInfo info;
            try {
@@ -1340,36 +1296,23 @@ public final class Pm {
            // user set flag so it disables rather than reverting to system
            // version of the app.
            if (isSystem) {
                unInstallFlags |= PackageManager.DELETE_SYSTEM_APP;
                flags |= PackageManager.DELETE_SYSTEM_APP;
            }
        }

        boolean result = deletePackage(pkg, unInstallFlags, userId);
        if (result) {
        final LocalIntentReceiver receiver = new LocalIntentReceiver();
        mInstaller.uninstall(pkg, flags, receiver.getIntentSender(), userId);

        final Intent result = receiver.getResult();
        final int status = result.getIntExtra(PackageInstaller.EXTRA_STATUS,
                PackageInstaller.STATUS_FAILURE);
        if (status == PackageInstaller.STATUS_SUCCESS) {
            System.out.println("Success");
        } else {
            System.out.println("Failure");
        }
    }

    private boolean deletePackage(String packageName, int flags, int userId) {
        LocalPackageDeleteObserver obs = new LocalPackageDeleteObserver();
        try {
            mInstaller.uninstall(packageName, flags, obs.getBinder(), userId);

            synchronized (obs) {
                while (!obs.finished) {
                    try {
                        obs.wait();
                    } catch (InterruptedException e) {
                    }
                }
            }
        } catch (RemoteException e) {
            System.err.println(e.toString());
            System.err.println(PM_NOT_RUNNING_ERR);
            Log.e(TAG, "Failure details: " + result.getExtras());
            System.out.println("Failure ["
                    + result.getStringExtra(PackageInstaller.EXTRA_STATUS_MESSAGE) + "]");
        }
        return obs.result;
    }

    static class ClearDataObserver extends IPackageDataObserver.Stub {
@@ -1384,7 +1327,6 @@ public final class Pm {
                notifyAll();
            }
        }

    }

    private void runClear() {
@@ -1717,6 +1659,35 @@ public final class Pm {
        throw new IllegalArgumentException("ABI " + abi + " not supported on this device");
    }

    private static class LocalIntentReceiver {
        private final SynchronousQueue<Intent> mResult = new SynchronousQueue<>();

        private IIntentSender.Stub mLocalSender = new IIntentSender.Stub() {
            @Override
            public int send(int code, Intent intent, String resolvedType,
                    IIntentReceiver finishedReceiver, String requiredPermission) {
                try {
                    mResult.offer(intent, 5, TimeUnit.SECONDS);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
                return 0;
            }
        };

        public IntentSender getIntentSender() {
            return new IntentSender((IIntentSender) mLocalSender);
        }

        public Intent getResult() {
            try {
                return mResult.poll(30, TimeUnit.SECONDS);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
    }

    private String nextOption() {
        if (mNextArg >= mArgs.length) {
            return null;
+1 −1
Original line number Diff line number Diff line
@@ -1568,7 +1568,7 @@ final class ApplicationPackageManager extends PackageManager {
        synchronized (mLock) {
            if (mInstaller == null) {
                try {
                    mInstaller = new PackageInstaller(this, mPM.getPackageInstaller(),
                    mInstaller = new PackageInstaller(mContext, this, mPM.getPackageInstaller(),
                            mContext.getPackageName(), mContext.getUserId());
                } catch (RemoteException e) {
                    throw e.rethrowAsRuntimeException();
+7 −8
Original line number Diff line number Diff line
@@ -19,23 +19,22 @@ package android.content.pm;
import android.content.pm.IPackageDeleteObserver2;
import android.content.pm.IPackageInstallerCallback;
import android.content.pm.IPackageInstallerSession;
import android.content.pm.InstallSessionInfo;
import android.content.pm.InstallSessionParams;
import android.content.pm.PackageInstaller;
import android.content.IntentSender;

/** {@hide} */
interface IPackageInstaller {
    int createSession(in InstallSessionParams params, String installerPackageName, int userId);
    int createSession(in PackageInstaller.SessionParams params, String installerPackageName, int userId);
    IPackageInstallerSession openSession(int sessionId);

    InstallSessionInfo getSessionInfo(int sessionId);
    List<InstallSessionInfo> getAllSessions(int userId);
    List<InstallSessionInfo> getMySessions(String installerPackageName, int userId);
    PackageInstaller.SessionInfo getSessionInfo(int sessionId);
    List<PackageInstaller.SessionInfo> getAllSessions(int userId);
    List<PackageInstaller.SessionInfo> getMySessions(String installerPackageName, int userId);

    void registerCallback(IPackageInstallerCallback callback, int userId);
    void unregisterCallback(IPackageInstallerCallback callback);

    void uninstall(String packageName, int flags, in IPackageDeleteObserver2 observer, int userId);
    void uninstallSplit(String packageName, String splitName, int flags, in IPackageDeleteObserver2 observer, int userId);
    void uninstall(String packageName, int flags, in IntentSender statusReceiver, int userId);

    void setPermissionsResult(int sessionId, boolean accepted);
}
+3 −2
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
package android.content.pm;

import android.content.pm.IPackageInstallObserver2;
import android.content.IntentSender;
import android.os.ParcelFileDescriptor;

/** {@hide} */
@@ -24,11 +25,11 @@ interface IPackageInstallerSession {
    void setClientProgress(float progress);
    void addClientProgress(float progress);

    String[] list();
    String[] getNames();
    ParcelFileDescriptor openWrite(String name, long offsetBytes, long lengthBytes);
    ParcelFileDescriptor openRead(String name);

    void close();
    void commit(in IPackageInstallObserver2 observer);
    void commit(in IntentSender statusReceiver);
    void abandon();
}
Loading