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

Commit f0600954 authored by Jeff Sharkey's avatar Jeff Sharkey Committed by Jeff Sharkey
Browse files

Logic to confirm uninstalls.

Prompt user for confirmation when caller doesn't have DELETE_PACKAGES
permission.  Also extend uninstall events to return failure codes.

Bug: 16515814
Change-Id: I15b52190ff02dbeaaf038b92364264f64c57ba89
parent cd5e3f95
Loading
Loading
Loading
Loading
+5 −2
Original line number Diff line number Diff line
@@ -8675,10 +8675,10 @@ package android.content.pm {
    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_REJECTED = 5; // 0x5
    field public static final int FAILURE_STORAGE = 3; // 0x3
    field public static final int FAILURE_UNKNOWN = 0; // 0x0
  }
@@ -8705,9 +8705,12 @@ package android.content.pm {
  public static abstract class PackageInstaller.UninstallCallback {
    ctor public PackageInstaller.UninstallCallback();
    method public abstract void onFailure(java.lang.String);
    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 class PackageItemInfo {
+30 −6
Original line number Diff line number Diff line
@@ -92,6 +92,9 @@ public class PackageInstaller {
     */
    public static final String EXTRA_SESSION_ID = "android.content.pm.extra.SESSION_ID";

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

    private final PackageManager mPm;
    private final IPackageInstaller mInstaller;
    private final int mUserId;
@@ -553,6 +556,26 @@ public class PackageInstaller {
     * Events for a specific uninstall request.
     */
    public static abstract class UninstallCallback {
        /**
         * Generic unknown failure. The system will always try to provide a more
         * specific failure reason, but in some rare cases this may be
         * delivered.
         */
        public static final int FAILURE_UNKNOWN = 0;

        /**
         * This uninstall was blocked. The package may be required for core
         * system operation, or the user may be restricted. Attempting to
         * uninstall again will have the same result.
         */
        public static final int FAILURE_BLOCKED = 1;

        /**
         * This uninstall was actively aborted. For example, the user declined
         * to uninstall. You may try to uninstall again.
         */
        public static final int FAILURE_ABORTED = 2;

        /**
         * User action is required to proceed. You can start the given intent
         * activity to involve the user and continue.
@@ -564,7 +587,7 @@ public class PackageInstaller {
        public abstract void onUserActionRequired(Intent intent);

        public abstract void onSuccess();
        public abstract void onFailure(String msg);
        public abstract void onFailure(int failureReason, String msg, Bundle extras);
    }

    /** {@hide} */
@@ -585,8 +608,9 @@ public class PackageInstaller {
            if (returnCode == PackageManager.DELETE_SUCCEEDED) {
                target.onSuccess();
            } else {
                final int failureReason = PackageManager.deleteStatusToFailureReason(returnCode);
                msg = PackageManager.deleteStatusToString(returnCode) + ": " + msg;
                target.onFailure(msg);
                target.onFailure(failureReason, msg, null);
            }
        }
    }
@@ -639,13 +663,13 @@ public class PackageInstaller {
        public static final int FAILURE_INCOMPATIBLE = 4;

        /**
         * This install session failed because it was rejected. For example, the
         * user declined requested permissions, or a package verifier rejected
         * the session.
         * This install session failed because it was actively aborted. For
         * example, the user declined requested permissions, or a verifier
         * rejected the session.
         *
         * @see PackageManager#VERIFICATION_REJECT
         */
        public static final int FAILURE_REJECTED = 5;
        public static final int FAILURE_ABORTED = 5;

        public static final String EXTRA_PACKAGE_NAME = "android.content.pm.extra.PACKAGE_NAME";

+23 −6
Original line number Diff line number Diff line
@@ -28,6 +28,7 @@ import android.content.Intent;
import android.content.IntentFilter;
import android.content.IntentSender;
import android.content.pm.PackageInstaller.CommitCallback;
import android.content.pm.PackageInstaller.UninstallCallback;
import android.content.pm.PackageParser.PackageParserException;
import android.content.res.Resources;
import android.content.res.XmlResourceParser;
@@ -771,7 +772,7 @@ public abstract class PackageManager {
    public static final int NO_NATIVE_LIBRARIES = -114;

    /** {@hide} */
    public static final int INSTALL_FAILED_REJECTED = -115;
    public static final int INSTALL_FAILED_ABORTED = -115;

    /**
     * Flag parameter for {@link #deletePackage} to indicate that you don't want to delete the
@@ -847,6 +848,9 @@ public abstract class PackageManager {
     */
    public static final int DELETE_FAILED_OWNER_BLOCKED = -4;

    /** {@hide} */
    public static final int DELETE_FAILED_ABORTED = -5;

    /**
     * Return code that is passed to the {@link IPackageMoveObserver} by
     * {@link #movePackage(android.net.Uri, IPackageMoveObserver)} when the
@@ -3833,7 +3837,7 @@ public abstract class PackageManager {
            case INSTALL_FAILED_USER_RESTRICTED: return "INSTALL_FAILED_USER_RESTRICTED";
            case INSTALL_FAILED_DUPLICATE_PERMISSION: return "INSTALL_FAILED_DUPLICATE_PERMISSION";
            case INSTALL_FAILED_NO_MATCHING_ABIS: return "INSTALL_FAILED_NO_MATCHING_ABIS";
            case INSTALL_FAILED_REJECTED: return "INSTALL_FAILED_REJECTED";
            case INSTALL_FAILED_ABORTED: return "INSTALL_FAILED_ABORTED";
            default: return Integer.toString(status);
        }
    }
@@ -3861,8 +3865,8 @@ public abstract class PackageManager {
            case INSTALL_FAILED_CONTAINER_ERROR: return CommitCallback.FAILURE_STORAGE;
            case INSTALL_FAILED_INVALID_INSTALL_LOCATION: return CommitCallback.FAILURE_STORAGE;
            case INSTALL_FAILED_MEDIA_UNAVAILABLE: return CommitCallback.FAILURE_STORAGE;
            case INSTALL_FAILED_VERIFICATION_TIMEOUT: return CommitCallback.FAILURE_REJECTED;
            case INSTALL_FAILED_VERIFICATION_FAILURE: return CommitCallback.FAILURE_REJECTED;
            case INSTALL_FAILED_VERIFICATION_TIMEOUT: return CommitCallback.FAILURE_ABORTED;
            case INSTALL_FAILED_VERIFICATION_FAILURE: return CommitCallback.FAILURE_ABORTED;
            case INSTALL_FAILED_PACKAGE_CHANGED: return CommitCallback.FAILURE_INVALID;
            case INSTALL_FAILED_UID_CHANGED: return CommitCallback.FAILURE_INVALID;
            case INSTALL_FAILED_VERSION_DOWNGRADE: return CommitCallback.FAILURE_INVALID;
@@ -3880,7 +3884,7 @@ public abstract class PackageManager {
            case INSTALL_FAILED_USER_RESTRICTED: return CommitCallback.FAILURE_INCOMPATIBLE;
            case INSTALL_FAILED_DUPLICATE_PERMISSION: return CommitCallback.FAILURE_CONFLICT;
            case INSTALL_FAILED_NO_MATCHING_ABIS: return CommitCallback.FAILURE_INCOMPATIBLE;
            case INSTALL_FAILED_REJECTED: return CommitCallback.FAILURE_REJECTED;
            case INSTALL_FAILED_ABORTED: return CommitCallback.FAILURE_ABORTED;
            default: return CommitCallback.FAILURE_UNKNOWN;
        }
    }
@@ -3893,7 +3897,20 @@ public abstract class PackageManager {
            case DELETE_FAILED_DEVICE_POLICY_MANAGER: return "DELETE_FAILED_DEVICE_POLICY_MANAGER";
            case DELETE_FAILED_USER_RESTRICTED: return "DELETE_FAILED_USER_RESTRICTED";
            case DELETE_FAILED_OWNER_BLOCKED: return "DELETE_FAILED_OWNER_BLOCKED";
            case DELETE_FAILED_ABORTED: return "DELETE_FAILED_ABORTED";
            default: return Integer.toString(status);
        }
    }

    /** {@hide} */
    public static int deleteStatusToFailureReason(int status) {
        switch (status) {
            case DELETE_FAILED_INTERNAL_ERROR: return UninstallCallback.FAILURE_UNKNOWN;
            case DELETE_FAILED_DEVICE_POLICY_MANAGER: return UninstallCallback.FAILURE_BLOCKED;
            case DELETE_FAILED_USER_RESTRICTED: return UninstallCallback.FAILURE_BLOCKED;
            case DELETE_FAILED_OWNER_BLOCKED: return UninstallCallback.FAILURE_BLOCKED;
            case DELETE_FAILED_ABORTED: return UninstallCallback.FAILURE_ABORTED;
            default: return UninstallCallback.FAILURE_UNKNOWN;
        }
    }
}
+18 −2
Original line number Diff line number Diff line
@@ -37,14 +37,17 @@ import static org.xmlpull.v1.XmlPullParser.START_TAG;
import android.app.ActivityManager;
import android.app.AppOpsManager;
import android.content.Context;
import android.content.Intent;
import android.content.pm.IPackageDeleteObserver2;
import android.content.pm.IPackageInstaller;
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.pm.PackageManager;
import android.graphics.Bitmap;
import android.net.Uri;
import android.os.Binder;
import android.os.Environment;
import android.os.FileUtils;
@@ -548,8 +551,21 @@ public class PackageInstallerService extends IPackageInstaller.Stub {
            int userId) {
        mPm.enforceCrossUserPermission(Binder.getCallingUid(), userId, true, "uninstall");

        // TODO: enforce installer of record or permission
        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DELETE_PACKAGES)
                == PackageManager.PERMISSION_GRANTED) {
            // Sweet, call straight through!
            mPm.deletePackage(packageName, observer, userId, flags);

        } else {
            // Take a short detour to confirm with user
            final Intent intent = new Intent(Intent.ACTION_UNINSTALL_PACKAGE);
            intent.setData(Uri.fromParts("package", packageName, null));
            intent.putExtra(PackageInstaller.EXTRA_CALLBACK, observer.asBinder());
            try {
                observer.onUserActionRequired(intent);
            } catch (RemoteException ignored) {
            }
        }
    }

    @Override
+3 −3
Original line number Diff line number Diff line
@@ -16,11 +16,11 @@

package com.android.server.pm;

import static android.content.pm.PackageManager.INSTALL_FAILED_ABORTED;
import static android.content.pm.PackageManager.INSTALL_FAILED_ALREADY_EXISTS;
import static android.content.pm.PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
import static android.content.pm.PackageManager.INSTALL_FAILED_INVALID_APK;
import static android.content.pm.PackageManager.INSTALL_FAILED_PACKAGE_CHANGED;
import static android.content.pm.PackageManager.INSTALL_FAILED_REJECTED;
import static android.system.OsConstants.O_CREAT;
import static android.system.OsConstants.O_RDONLY;
import static android.system.OsConstants.O_WRONLY;
@@ -577,7 +577,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
            mHandler.obtainMessage(MSG_COMMIT).sendToTarget();
        } else {
            destroyInternal();
            dispatchSessionFinished(INSTALL_FAILED_REJECTED, "User rejected permissions", null);
            dispatchSessionFinished(INSTALL_FAILED_ABORTED, "User rejected permissions", null);
        }
    }

@@ -591,7 +591,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
    @Override
    public void abandon() {
        destroyInternal();
        dispatchSessionFinished(INSTALL_FAILED_INTERNAL_ERROR, "Session was abandoned", null);
        dispatchSessionFinished(INSTALL_FAILED_ABORTED, "Session was abandoned", null);
    }

    private void dispatchSessionFinished(int returnCode, String msg, Bundle extras) {