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

Commit 6c474bf7 authored by Pavel Grafov's avatar Pavel Grafov Committed by Automerger Merge Worker
Browse files

Merge "Suspend newly installed apps when personal apps are suspended" into...

Merge "Suspend newly installed apps when personal apps are suspended" into rvc-dev am: 70b1c45a am: 82625f9d

Change-Id: I994e2c289fa44fb732d3365b601d00c06732986d
parents a6908bbb 82625f9d
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -2429,7 +2429,7 @@ public class DevicePolicyManager {
            PERSONAL_APPS_SUSPENDED_PROFILE_TIMEOUT
    })
    @Retention(RetentionPolicy.SOURCE)
    public @interface PersonalAppSuspensionReason {}
    public @interface PersonalAppsSuspensionReason {}
    /**
     * Return true if the given administrator component is currently active (enabled) in the system.
@@ -11961,7 +11961,7 @@ public class DevicePolicyManager {
     *     {@link #PERSONAL_APPS_NOT_SUSPENDED} if apps are not suspended.
     * @see #setPersonalAppsSuspended
     */
    public @PersonalAppSuspensionReason int getPersonalAppsSuspendedReasons(
    public @PersonalAppsSuspensionReason int getPersonalAppsSuspendedReasons(
            @NonNull ComponentName admin) {
        throwIfParentInstance("getPersonalAppsSuspendedReasons");
        if (mService != null) {
+2 −2
Original line number Diff line number Diff line
@@ -7088,7 +7088,7 @@ public abstract class PackageManager {
     * Returns any packages in a given set of packages that cannot be suspended via a call to {@link
     * #setPackagesSuspended(String[], boolean, PersistableBundle, PersistableBundle,
     * SuspendDialogInfo) setPackagesSuspended}. The platform prevents suspending certain critical
     * packages to keep the device in a functioning state, e.g. the default dialer.
     * packages to keep the device in a functioning state, e.g. the default dialer and launcher.
     * Apps need to hold {@link Manifest.permission#SUSPEND_APPS SUSPEND_APPS} to call this API.
     *
     * <p>
@@ -7106,7 +7106,7 @@ public abstract class PackageManager {
    @RequiresPermission(Manifest.permission.SUSPEND_APPS)
    @NonNull
    public String[] getUnsuspendablePackages(@NonNull String[] packageNames) {
        throw new UnsupportedOperationException("canSuspendPackages not implemented");
        throw new UnsupportedOperationException("getUnsuspendablePackages not implemented");
    }

    /**
+39 −9
Original line number Diff line number Diff line
@@ -136,7 +136,7 @@ import android.app.admin.DevicePolicyCache;
import android.app.admin.DevicePolicyEventLogger;
import android.app.admin.DevicePolicyManager;
import android.app.admin.DevicePolicyManager.PasswordComplexity;
import android.app.admin.DevicePolicyManager.PersonalAppSuspensionReason;
import android.app.admin.DevicePolicyManager.PersonalAppsSuspensionReason;
import android.app.admin.DevicePolicyManagerInternal;
import android.app.admin.DeviceStateCache;
import android.app.admin.FactoryResetProtectionPolicy;
@@ -935,10 +935,14 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
                }
            } else if (Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(action)) {
                handlePackagesChanged(null /* check all admins */, userHandle);
            } else if (Intent.ACTION_PACKAGE_CHANGED.equals(action)
                    || (Intent.ACTION_PACKAGE_ADDED.equals(action)
                    && intent.getBooleanExtra(Intent.EXTRA_REPLACING, false))) {
            } else if (Intent.ACTION_PACKAGE_CHANGED.equals(action)) {
                handlePackagesChanged(intent.getData().getSchemeSpecificPart(), userHandle);
            } else if (Intent.ACTION_PACKAGE_ADDED.equals(action)) {
                if (intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) {
                    handlePackagesChanged(intent.getData().getSchemeSpecificPart(), userHandle);
                } else {
                    handleNewPackageInstalled(intent.getData().getSchemeSpecificPart(), userHandle);
                }
            } else if (Intent.ACTION_PACKAGE_REMOVED.equals(action)
                    && !intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) {
                handlePackagesChanged(intent.getData().getSchemeSpecificPart(), userHandle);
@@ -2028,6 +2032,26 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
        return false;
    }
    private void handleNewPackageInstalled(String packageName, int userHandle) {
        // If personal apps were suspended by the admin, suspend the newly installed one.
        if (!getUserData(userHandle).mAppsSuspended) {
            return;
        }
        final String[] packagesToSuspend = { packageName };
        // Check if package is considered not suspendable?
        if (mInjector.getPackageManager(userHandle)
                .getUnsuspendablePackages(packagesToSuspend).length != 0) {
            Slog.i(LOG_TAG, "Newly installed package is unsuspendable: " + packageName);
            return;
        }
        try {
            mIPackageManager.setPackagesSuspendedAsUser(packagesToSuspend, true /*suspend*/,
                    null, null, null, PLATFORM_PACKAGE_NAME, userHandle);
        } catch (RemoteException ignored) {
            // shouldn't happen.
        }
    }
    /**
     * Unit test will subclass it to inject mocks.
     */
@@ -2110,6 +2134,11 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
            return mContext.getPackageManager();
        }
        PackageManager getPackageManager(int userId) {
            return mContext
                    .createContextAsUser(UserHandle.of(userId), 0 /* flags */).getPackageManager();
        }
        PowerManagerInternal getPowerManagerInternal() {
            return LocalServices.getService(PowerManagerInternal.class);
        }
@@ -15650,7 +15679,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
    }
    @Override
    public @PersonalAppSuspensionReason int getPersonalAppsSuspendedReasons(ComponentName who) {
    public @PersonalAppsSuspensionReason int getPersonalAppsSuspendedReasons(ComponentName who) {
        synchronized (getLockObject()) {
            final ActiveAdmin admin = getActiveAdminForCallerLocked(who,
                    DeviceAdminInfo.USES_POLICY_ORGANIZATION_OWNED_PROFILE_OWNER,
@@ -15669,7 +15698,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
        }
    }
    private @PersonalAppSuspensionReason int makeSuspensionReasons(
    private @PersonalAppsSuspensionReason int makeSuspensionReasons(
            boolean explicit, boolean timeout) {
        int result = PERSONAL_APPS_NOT_SUSPENDED;
        if (explicit) {
@@ -15793,7 +15822,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
    }
    private void applyPersonalAppsSuspension(
            int profileUserId, @PersonalAppSuspensionReason int suspensionState) {
            int profileUserId, @PersonalAppsSuspensionReason int suspensionState) {
        final boolean suspended = getUserData(UserHandle.USER_SYSTEM).mAppsSuspended;
        final boolean shouldSuspend = suspensionState != PERSONAL_APPS_NOT_SUSPENDED;
        if (suspended != shouldSuspend) {
@@ -15813,8 +15842,9 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
        mInjector.binderWithCleanCallingIdentity(() -> {
            try {
                final String[] appsToSuspend =
                        new PersonalAppsSuspensionHelper(mContext, mInjector.getPackageManager())
                                .getPersonalAppsForSuspension(userId);
                        new PersonalAppsSuspensionHelper(
                                mContext.createContextAsUser(UserHandle.of(userId), 0 /* flags */))
                                .getPersonalAppsForSuspension();
                final String[] failedPackages = mIPackageManager.setPackagesSuspendedAsUser(
                        appsToSuspend, suspended, null, null, null, PLATFORM_PACKAGE_NAME, userId);
                if (!ArrayUtils.isEmpty(failedPackages)) {
+30 −54
Original line number Diff line number Diff line
@@ -20,7 +20,6 @@ import static android.accessibilityservice.AccessibilityServiceInfo.FEEDBACK_ALL

import android.accessibilityservice.AccessibilityServiceInfo;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
@@ -32,7 +31,7 @@ import android.os.IBinder;
import android.os.ServiceManager;
import android.provider.Settings;
import android.text.TextUtils;
import android.util.Log;
import android.util.ArraySet;
import android.util.Slog;
import android.view.accessibility.AccessibilityManager;
import android.view.accessibility.IAccessibilityManager;
@@ -43,7 +42,6 @@ import com.android.server.inputmethod.InputMethodManagerInternal;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

@@ -56,18 +54,21 @@ public class PersonalAppsSuspensionHelper {
    private final Context mContext;
    private final PackageManager mPackageManager;

    public PersonalAppsSuspensionHelper(Context context, PackageManager packageManager) {
    /**
     * @param context Context for the user whose apps should to be suspended.
     */
    public PersonalAppsSuspensionHelper(Context context) {
        mContext = context;
        mPackageManager = packageManager;
        mPackageManager = context.getPackageManager();
    }

    /**
     * @return List of packages that should be suspended to limit personal use.
     */
    String[] getPersonalAppsForSuspension(@UserIdInt int userId) {
    String[] getPersonalAppsForSuspension() {
        final List<PackageInfo> installedPackageInfos =
                mPackageManager.getInstalledPackagesAsUser(0 /* flags */, userId);
        final Set<String> result = new HashSet<>();
                mPackageManager.getInstalledPackages(0 /* flags */);
        final Set<String> result = new ArraySet<>();
        for (final PackageInfo packageInfo : installedPackageInfos) {
            final ApplicationInfo info = packageInfo.applicationInfo;
            if ((!info.isSystemApp() && !info.isUpdatedSystemApp())
@@ -77,11 +78,15 @@ public class PersonalAppsSuspensionHelper {
        }
        result.removeAll(getCriticalPackages());
        result.removeAll(getSystemLauncherPackages());
        result.removeAll(getAccessibilityServices(userId));
        result.removeAll(getInputMethodPackages(userId));
        result.remove(getActiveLauncherPackages(userId));
        result.remove(getDialerPackage(userId));
        result.remove(getSettingsPackageName(userId));
        result.removeAll(getAccessibilityServices());
        result.removeAll(getInputMethodPackages());
        result.remove(getSettingsPackageName());

        final String[] unsuspendablePackages =
                mPackageManager.getUnsuspendablePackages(result.toArray(new String[0]));
        for (final String pkg : unsuspendablePackages) {
            result.remove(pkg);
        }

        Slog.i(LOG_TAG, "Packages subject to suspension: " + String.join(",", result));
        return result.toArray(new String[0]);
@@ -104,7 +109,6 @@ public class PersonalAppsSuspensionHelper {
                final ApplicationInfo applicationInfo =
                        mPackageManager.getApplicationInfo(packageName, 0);
                if (applicationInfo.isSystemApp() || applicationInfo.isUpdatedSystemApp()) {
                    Log.d(LOG_TAG, "Not suspending system launcher package: " + packageName);
                    result.add(packageName);
                }
            } catch (PackageManager.NameNotFoundException e) {
@@ -114,81 +118,53 @@ public class PersonalAppsSuspensionHelper {
        return result;
    }

    private List<String> getAccessibilityServices(int userId) {
    private List<String> getAccessibilityServices() {
        final List<AccessibilityServiceInfo> accessibilityServiceInfos =
                getAccessibilityManagerForUser(userId)
                getAccessibilityManagerForUser(mContext.getUserId())
                        .getEnabledAccessibilityServiceList(FEEDBACK_ALL_MASK);
        final List<String> result = new ArrayList<>();
        for (final AccessibilityServiceInfo serviceInfo : accessibilityServiceInfos) {
            final ComponentName componentName =
                    ComponentName.unflattenFromString(serviceInfo.getId());
            if (componentName != null) {
                final String packageName = componentName.getPackageName();
                Slog.d(LOG_TAG, "Not suspending a11y service: " + packageName);
                result.add(packageName);
                result.add(componentName.getPackageName());
            }
        }
        return result;
    }

    private List<String> getInputMethodPackages(int userId) {
        final List<InputMethodInfo> enabledImes =
                InputMethodManagerInternal.get().getEnabledInputMethodListAsUser(userId);
    private List<String> getInputMethodPackages() {
        final List<InputMethodInfo> enabledImes = InputMethodManagerInternal.get()
                .getEnabledInputMethodListAsUser(mContext.getUserId());
        final List<String> result = new ArrayList<>();
        for (final InputMethodInfo info : enabledImes) {
            Slog.d(LOG_TAG, "Not suspending IME: " + info.getPackageName());
            result.add(info.getPackageName());
        }
        return result;
    }

    @Nullable
    private String getActiveLauncherPackages(int userId) {
        final Intent intent = new Intent(Intent.ACTION_MAIN);
        intent.addCategory(Intent.CATEGORY_HOME);
        intent.addCategory(Intent.CATEGORY_DEFAULT);
        return getPackageNameForIntent("active launcher", intent, userId);
    }

    @Nullable
    private String getSettingsPackageName(int userId) {
    private String getSettingsPackageName() {
        final Intent intent = new Intent(Settings.ACTION_SETTINGS);
        intent.addCategory(Intent.CATEGORY_DEFAULT);
        return getPackageNameForIntent("settings", intent, userId);
    }

    @Nullable
    private String getDialerPackage(int userId) {
        final Intent intent = new Intent(Intent.ACTION_DIAL);
        intent.addCategory(Intent.CATEGORY_DEFAULT);
        return getPackageNameForIntent("dialer", intent, userId);
    }

    @Nullable
    private String getPackageNameForIntent(String name, Intent intent, int userId) {
        final ResolveInfo resolveInfo =
                mPackageManager.resolveActivityAsUser(intent, /* flags= */ 0, userId);
        final ResolveInfo resolveInfo = mPackageManager.resolveActivity(intent, /* flags= */ 0);
        if (resolveInfo != null) {
            final String packageName = resolveInfo.activityInfo.packageName;
            Slog.d(LOG_TAG, "Not suspending " + name + " package: " + packageName);
            return packageName;
            return resolveInfo.activityInfo.packageName;
        }
        return null;
    }

    private List<String> getCriticalPackages() {
        final List<String> result = Arrays.asList(mContext.getResources()
        return Arrays.asList(mContext.getResources()
                .getStringArray(R.array.config_packagesExemptFromSuspension));
        Slog.d(LOG_TAG, "Not suspending critical packages: " + String.join(",", result));
        return result;
    }

    private boolean hasLauncherIntent(String packageName) {
        final Intent intentToResolve = new Intent(Intent.ACTION_MAIN);
        intentToResolve.addCategory(Intent.CATEGORY_LAUNCHER);
        intentToResolve.setPackage(packageName);
        final List<ResolveInfo> resolveInfos = mPackageManager.queryIntentActivities(
                intentToResolve, PackageManager.GET_UNINSTALLED_PACKAGES);
        final List<ResolveInfo> resolveInfos =
                mPackageManager.queryIntentActivities(intentToResolve, /* flags= */ 0);
        return resolveInfos != null && !resolveInfos.isEmpty();
    }