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

Commit a6f16f03 authored by Omar Eissa's avatar Omar Eissa Committed by Alex Buynytskyy
Browse files

Introduce QUARANTINED state

Detailed proposals are at go/quarantined-when-not-in-use and go/disabled-until-launched-u

+block broadcasts
+force stop packages on suspension+quarantine

Test: Used command `pm suspend-quarantine <app_name>`.
Tested locally on device for basic functionality of putting apps
in and out of this state, and verifying some bindings and behaviors like
apps continuing to appear on launcher. More thorough testing to follow.
Test: atest DevicePolicyManagerServiceMigrationTest SuspendPackageHelperTest PackageManagerSettingsTests
Bug: 269127435

Change-Id: Ifd9e8fb460a6184142c7c6d45189d19ec9de52c2
parent 1d59911f
Loading
Loading
Loading
Loading
+11 −2
Original line number Diff line number Diff line
@@ -2872,16 +2872,25 @@ public class ApplicationPackageManager extends PackageManager {
        final SuspendDialogInfo dialogInfo = !TextUtils.isEmpty(dialogMessage)
                ? new SuspendDialogInfo.Builder().setMessage(dialogMessage).build()
                : null;
        return setPackagesSuspended(packageNames, suspended, appExtras, launcherExtras, dialogInfo);
        return setPackagesSuspended(packageNames, suspended, appExtras, launcherExtras,
                dialogInfo, 0);
    }

    @Override
    public String[] setPackagesSuspended(String[] packageNames, boolean suspended,
            PersistableBundle appExtras, PersistableBundle launcherExtras,
            SuspendDialogInfo dialogInfo) {
        return setPackagesSuspended(packageNames, suspended, appExtras, launcherExtras,
                dialogInfo, 0);
    }

    @Override
    public String[] setPackagesSuspended(String[] packageNames, boolean suspended,
            PersistableBundle appExtras, PersistableBundle launcherExtras,
            SuspendDialogInfo dialogInfo, int flags) {
        try {
            return mPM.setPackagesSuspendedAsUser(packageNames, suspended, appExtras,
                    launcherExtras, dialogInfo, mContext.getOpPackageName(),
                    launcherExtras, dialogInfo, flags, mContext.getOpPackageName(),
                    getUserId());
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
+8 −0
Original line number Diff line number Diff line
@@ -323,6 +323,7 @@ public abstract class Context {
            // Make sure no flag uses the sign bit (most significant bit) of the long integer,
            // to avoid future confusion.
            BIND_BYPASS_USER_NETWORK_RESTRICTIONS,
            BIND_FILTER_OUT_QUARANTINED_COMPONENTS,
    })
    @Retention(RetentionPolicy.SOURCE)
    public @interface BindServiceFlagsLongBits {}
@@ -697,6 +698,13 @@ public abstract class Context {
     */
    public static final long BIND_BYPASS_USER_NETWORK_RESTRICTIONS = 0x1_0000_0000L;

    /**
     * Flag for {@link #bindService}.
     *
     * @hide
     */
    public static final long BIND_FILTER_OUT_QUARANTINED_COMPONENTS = 0x2_0000_0000L;


    /**
     * These bind flags reduce the strength of the binding such that we shouldn't
+9 −0
Original line number Diff line number Diff line
@@ -6382,6 +6382,15 @@ public class Intent implements Parcelable, Cloneable {
    public static final String EXTRA_CHANGED_UID_LIST =
            "android.intent.extra.changed_uid_list";
    /**
     * This field is part of
     * {@link android.content.Intent#ACTION_PACKAGES_SUSPENDED},
     * and only present if the packages were quarantined.
     * @hide
     */
    public static final String EXTRA_QUARANTINED =
            "android.intent.extra.quarantined";
    /**
     * An integer denoting a bitwise combination of restrictions set on distracting packages via
     * {@link PackageManager#setDistractingPackageRestrictions(String[], int)}
+1 −1
Original line number Diff line number Diff line
@@ -298,7 +298,7 @@ interface IPackageManager {

    String[] setPackagesSuspendedAsUser(in String[] packageNames, boolean suspended,
            in PersistableBundle appExtras, in PersistableBundle launcherExtras,
            in SuspendDialogInfo dialogInfo, String callingPackage, int userId);
            in SuspendDialogInfo dialogInfo, int flags, String callingPackage, int userId);

    String[] getUnsuspendablePackagesForUser(in String[] packageNames, int userId);

+84 −2
Original line number Diff line number Diff line
@@ -834,6 +834,7 @@ public abstract class PackageManager {
            GET_DISABLED_COMPONENTS,
            GET_DISABLED_UNTIL_USED_COMPONENTS,
            GET_UNINSTALLED_PACKAGES,
            FILTER_OUT_QUARANTINED_COMPONENTS,
    })
    @Retention(RetentionPolicy.SOURCE)
    public @interface ComponentInfoFlagsBits {}
@@ -857,7 +858,8 @@ public abstract class PackageManager {
            GET_DISABLED_COMPONENTS,
            GET_DISABLED_UNTIL_USED_COMPONENTS,
            GET_UNINSTALLED_PACKAGES,
            MATCH_CLONE_PROFILE
            MATCH_CLONE_PROFILE,
            FILTER_OUT_QUARANTINED_COMPONENTS,
    })
    @Retention(RetentionPolicy.SOURCE)
    public @interface ResolveInfoFlagsBits {}
@@ -1232,6 +1234,11 @@ public abstract class PackageManager {
     */
    public static final long GET_ATTRIBUTIONS_LONG = 0x80000000L;

    /**
     * @hide
     */
    public static final long FILTER_OUT_QUARANTINED_COMPONENTS = 0x100000000L;

    /**
     * Flag for {@link #addCrossProfileIntentFilter}: if this flag is set: when
     * resolving an intent that matches the {@code CrossProfileIntentFilter},
@@ -1685,7 +1692,7 @@ public abstract class PackageManager {
    /** @hide */
    @IntDef(flag = true, value = {
            DONT_KILL_APP,
            SYNCHRONOUS
            SYNCHRONOUS,
    })
    @Retention(RetentionPolicy.SOURCE)
    public @interface EnabledFlags {}
@@ -1707,6 +1714,24 @@ public abstract class PackageManager {
     */
    public static final int SYNCHRONOUS = 0x00000002;

    /** @hide */
    @IntDef(flag = true, value = {
            FLAG_SUSPEND_QUARANTINED,
    })
    @Retention(RetentionPolicy.SOURCE)
    public @interface SuspendedFlags {}

    /**
     * Flag parameter {@link #setPackagesSuspended(String[], boolean, PersistableBundle,
     * PersistableBundle, android.content.pm.SuspendDialogInfo, int)}:
     * Apps in this state not only appear suspended for all user visible purposes (eg, Launcher,
     * ShareSheet), but also individual components of the app can behave as disabled depending on
     * the importance of the calling app.
     *
     * @hide
     */
    public static final int FLAG_SUSPEND_QUARANTINED = 0x00000001;

    /** @hide */
    @IntDef(prefix = { "INSTALL_REASON_" }, value = {
            INSTALL_REASON_UNKNOWN,
@@ -9653,6 +9678,63 @@ public abstract class PackageManager {
        throw new UnsupportedOperationException("setPackagesSuspended not implemented");
    }

    /**
     * Puts the given packages in a suspended state, where attempts at starting activities are
     * denied.
     *
     * <p>The suspended application's notifications and all of its windows will be hidden, any
     * of its started activities will be stopped and it won't be able to ring the device.
     * It doesn't remove the data or the actual package file.
     *
     * <p>When the user tries to launch a suspended app, a system dialog alerting them that the app
     * is suspended will be shown instead.
     * The caller can optionally customize the dialog by passing a {@link SuspendDialogInfo} object
     * to this API. This dialog will have a button that starts the
     * {@link Intent#ACTION_SHOW_SUSPENDED_APP_DETAILS} intent if the suspending app declares an
     * activity which handles this action.
     *
     * <p>The packages being suspended must already be installed. If a package is uninstalled, it
     * will no longer be suspended.
     *
     * <p>Optionally, the suspending app can provide extra information in the form of
     * {@link PersistableBundle} objects to be shared with the apps being suspended and the
     * launcher to support customization that they might need to handle the suspended state.
     *
     * <p>The caller must hold {@link Manifest.permission#SUSPEND_APPS} to use this API except for
     * device owner and profile owner.
     *
     * @param packageNames The names of the packages to set the suspended status.
     * @param suspended If set to {@code true}, the packages will be suspended, if set to
     * {@code false}, the packages will be unsuspended.
     * @param appExtras An optional {@link PersistableBundle} that the suspending app can provide
     *                  which will be shared with the apps being suspended. Ignored if
     *                  {@code suspended} is false.
     * @param launcherExtras An optional {@link PersistableBundle} that the suspending app can
     *                       provide which will be shared with the launcher. Ignored if
     *                       {@code suspended} is false.
     * @param dialogInfo An optional {@link SuspendDialogInfo} object describing the dialog that
     *                   should be shown to the user when they try to launch a suspended app.
     *                   Ignored if {@code suspended} is false.
     * @param flags Optional behavior flags.
     *
     * @return an array of package names for which the suspended status could not be set as
     * requested in this method. Returns {@code null} if {@code packageNames} was {@code null}.
     *
     * @see #isPackageSuspended
     * @see SuspendDialogInfo
     * @see SuspendDialogInfo.Builder
     * @see Intent#ACTION_SHOW_SUSPENDED_APP_DETAILS
     *
     * @hide
     */
    @RequiresPermission(value=Manifest.permission.SUSPEND_APPS, conditional=true)
    @Nullable
    public String[] setPackagesSuspended(@Nullable String[] packageNames, boolean suspended,
            @Nullable PersistableBundle appExtras, @Nullable PersistableBundle launcherExtras,
            @Nullable SuspendDialogInfo dialogInfo, @SuspendedFlags int flags) {
        throw new UnsupportedOperationException("setPackagesSuspended not implemented");
    }

    /**
     * Returns any packages in a given set of packages that cannot be suspended via a call to {@link
     * #setPackagesSuspended(String[], boolean, PersistableBundle, PersistableBundle,
Loading