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

Commit 91edfc16 authored by Pavel Grafov's avatar Pavel Grafov
Browse files

Allow profile owners to protect packages.

Changed how protected packages are stored in package manager:
* previously they were stored in a map from DO package into
  a list of protected packages. This isn't expressive enough
  to allow POs: the same PO package on different users may
  protect different packages.
* now they are stored in a map from userId into a list of
  protected packages. In case when the DO sets the policy
  the userId will be UserHandle.USER_ALL, otherwise it will
  be the calling user.

Bug: 218639412
Test: atest UserControlDisabledPackagesTest
Change-Id: I2d1d33acad035610c8db365f69b7a15faa03a2d5
Merged-In: I2d1d33acad035610c8db365f69b7a15faa03a2d5
parent 9d1cf05c
Loading
Loading
Loading
Loading
+9 −6
Original line number Diff line number Diff line
@@ -14569,12 +14569,13 @@ public class DevicePolicyManager {
    }
    /**
     * Called by Device owner to disable user control over apps. User will not be able to clear
     * app data or force-stop packages.
     * Called by a device owner or a profile owner to disable user control over apps. User will not
     * be able to clear app data or force-stop packages. When called by a device owner, applies to
     * all users on the device.
     *
     * @param admin which {@link DeviceAdminReceiver} this request is associated with
     * @param packages The package names for the apps.
     * @throws SecurityException if {@code admin} is not a device owner.
     * @throws SecurityException if {@code admin} is not a device owner or a profile owner.
     */
    public void setUserControlDisabledPackages(@NonNull ComponentName admin,
            @NonNull List<String> packages) {
@@ -14589,12 +14590,14 @@ public class DevicePolicyManager {
    }
    /**
     * Returns the list of packages over which user control is disabled by the device owner.
     * Returns the list of packages over which user control is disabled by a device or profile
     * owner.
     *
     * @param admin which {@link DeviceAdminReceiver} this request is associated with
     * @throws SecurityException if {@code admin} is not a device owner.
     * @throws SecurityException if {@code admin} is not a device or profile owner.
     */
    public @NonNull List<String> getUserControlDisabledPackages(@NonNull ComponentName admin) {
    @NonNull
    public List<String> getUserControlDisabledPackages(@NonNull ComponentName admin) {
        throwIfParentInstance("getUserControlDisabledPackages");
        if (mService != null) {
            try {
+3 −3
Original line number Diff line number Diff line
@@ -371,10 +371,10 @@ public abstract class PackageManagerInternal {
            int deviceOwnerUserId, String deviceOwner, SparseArray<String> profileOwners);

    /**
     * Called by Owners to set the package names protected by the device owner.
     * Marks packages as protected for a given user or all users in case of USER_ALL.
     */
    public abstract void setDeviceOwnerProtectedPackages(
            String deviceOwnerPackageName, List<String> packageNames);
    public abstract void setOwnerProtectedPackages(
            @UserIdInt int userId, @NonNull List<String> packageNames);

    /**
     * Returns {@code true} if a given package can't be wiped. Otherwise, returns {@code false}.
+3 −4
Original line number Diff line number Diff line
@@ -352,10 +352,9 @@ abstract class PackageManagerInternalBase extends PackageManagerInternal {

    @Override
    @Deprecated
    public final void setDeviceOwnerProtectedPackages(
            String deviceOwnerPackageName, List<String> packageNames) {
        getProtectedPackages().setDeviceOwnerProtectedPackages(
                deviceOwnerPackageName, packageNames);
    public final void setOwnerProtectedPackages(
            @UserIdInt int userId, @NonNull List<String> packageNames) {
        getProtectedPackages().setOwnerProtectedPackages(userId, packageNames);
    }

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

package com.android.server.pm;

import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
import android.content.Context;
import android.os.UserHandle;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.SparseArray;

@@ -56,7 +56,7 @@ public class ProtectedPackages {

    @Nullable
    @GuardedBy("this")
    private final ArrayMap<String, Set<String>> mDeviceOwnerProtectedPackages = new ArrayMap<>();
    private final SparseArray<Set<String>> mOwnerProtectedPackages = new SparseArray<>();

    private final Context mContext;

@@ -79,13 +79,13 @@ public class ProtectedPackages {
                : profileOwnerPackages.clone();
    }

    /** Sets the protected packages for the device owner. */
    public synchronized void setDeviceOwnerProtectedPackages(
            String deviceOwnerPackageName, List<String> packageNames) {
    /** Sets packages protected by a device or profile owner. */
    public synchronized void setOwnerProtectedPackages(
            @UserIdInt int userId, @NonNull List<String> packageNames) {
        if (packageNames.isEmpty()) {
            mDeviceOwnerProtectedPackages.remove(deviceOwnerPackageName);
            mOwnerProtectedPackages.remove(userId);
        } else {
            mDeviceOwnerProtectedPackages.put(deviceOwnerPackageName, new ArraySet<>(packageNames));
            mOwnerProtectedPackages.put(userId, new ArraySet<>(packageNames));
        }
    }

@@ -123,19 +123,24 @@ public class ProtectedPackages {
     * <p>A protected package means that, apart from the package owner, no system or privileged apps
     * can modify its data or package state.
     */
    private synchronized boolean isProtectedPackage(String packageName) {
    private synchronized boolean isProtectedPackage(@UserIdInt int userId, String packageName) {
        return packageName != null && (packageName.equals(mDeviceProvisioningPackage)
                || isDeviceOwnerProtectedPackage(packageName));
                || isOwnerProtectedPackage(userId, packageName));
    }

    /** Returns {@code true} if the given package is a protected package set by any device owner. */
    private synchronized boolean isDeviceOwnerProtectedPackage(String packageName) {
        for (Set<String> protectedPackages : mDeviceOwnerProtectedPackages.values()) {
            if (protectedPackages.contains(packageName)) {
                return true;
            }
    /**
     * Returns {@code true} if the given package is a protected package set by any device or
     * profile owner.
     */
    private synchronized boolean isOwnerProtectedPackage(
            @UserIdInt int userId, String packageName) {
        return isPackageProtectedForUser(UserHandle.USER_ALL, packageName)
                || isPackageProtectedForUser(userId, packageName);
    }
        return false;

    private synchronized boolean isPackageProtectedForUser(int userId, String packageName) {
        int userIdx = mOwnerProtectedPackages.indexOfKey(userId);
        return userIdx >= 0 && mOwnerProtectedPackages.valueAt(userIdx).contains(packageName);
    }

    /**
@@ -146,7 +151,7 @@ public class ProtectedPackages {
     */
    public boolean isPackageStateProtected(@UserIdInt int userId, String packageName) {
        return hasDeviceOwnerOrProfileOwner(userId, packageName)
                || isProtectedPackage(packageName);
                || isProtectedPackage(userId, packageName);
    }

    /**
@@ -155,6 +160,6 @@ public class ProtectedPackages {
     */
    public boolean isPackageDataProtected(@UserIdInt int userId, String packageName) {
        return hasDeviceOwnerOrProfileOwner(userId, packageName)
                || isProtectedPackage(packageName);
                || isProtectedPackage(userId, packageName);
    }
}
+24 −22
Original line number Diff line number Diff line
@@ -3116,6 +3116,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
            deleteTransferOwnershipBundleLocked(metadata.userId);
        }
        updateSystemUpdateFreezePeriodsRecord(/* saveIfChanged */ true);
        pushUserControlDisabledPackagesLocked(metadata.userId);
    }
    private void maybeLogStart() {
@@ -3178,18 +3179,22 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
        startOwnerService(userId, "start-user");
    }
    // TODO(b/218639412): Once PM stores these on a per-user basis, push even empty lists to handle
    // DO/PO removal correctly.
    void pushUserControlDisabledPackagesLocked(int userId) {
        if (userId != mOwners.getDeviceOwnerUserId()) {
            return;
        }
        ActiveAdmin deviceOwner = getDeviceOwnerAdminLocked();
        if (deviceOwner == null || deviceOwner.protectedPackages == null) {
            return;
        final int targetUserId;
        final ActiveAdmin owner;
        if (getDeviceOwnerUserIdUncheckedLocked() == userId) {
            owner = getDeviceOwnerAdminLocked();
            targetUserId = UserHandle.USER_ALL;
        } else {
            owner = getProfileOwnerAdminLocked(userId);
            targetUserId = userId;
        }
        mInjector.getPackageManagerInternal().setDeviceOwnerProtectedPackages(
                deviceOwner.info.getPackageName(), deviceOwner.protectedPackages);
        List<String> protectedPackages = (owner == null || owner.protectedPackages == null)
                ? Collections.emptyList() : owner.protectedPackages;
        mInjector.binderWithCleanCallingIdentity(() ->
                mInjector.getPackageManagerInternal().setOwnerProtectedPackages(
                        targetUserId, protectedPackages));
    }
    @Override
@@ -16967,23 +16972,20 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
        Objects.requireNonNull(who, "ComponentName is null");
        Objects.requireNonNull(packages, "packages is null");
        final CallerIdentity caller = getCallerIdentity(who);
        Preconditions.checkCallAuthorization(
                isDefaultDeviceOwner(caller) || isFinancedDeviceOwner(caller));
        Preconditions.checkCallAuthorization(isDefaultDeviceOwner(caller) || isProfileOwner(caller)
                || isFinancedDeviceOwner(caller));
        checkCanExecuteOrThrowUnsafe(
                DevicePolicyManager.OPERATION_SET_USER_CONTROL_DISABLED_PACKAGES);
        synchronized (getLockObject()) {
            ActiveAdmin deviceOwner = getDeviceOwnerAdminLocked();
            if (!Objects.equals(deviceOwner.protectedPackages, packages)) {
                deviceOwner.protectedPackages = packages.isEmpty() ? null : packages;
            ActiveAdmin owner = getDeviceOrProfileOwnerAdminLocked(caller.getUserId());
            if (!Objects.equals(owner.protectedPackages, packages)) {
                owner.protectedPackages = packages.isEmpty() ? null : packages;
                saveSettingsLocked(caller.getUserId());
                pushUserControlDisabledPackagesLocked(caller.getUserId());
            }
        }
        mInjector.binderWithCleanCallingIdentity(
                () -> mInjector.getPackageManagerInternal().setDeviceOwnerProtectedPackages(
                        who.getPackageName(), packages));
        DevicePolicyEventLogger
                .createEvent(DevicePolicyEnums.SET_USER_CONTROL_DISABLED_PACKAGES)
                .setAdmin(who)
@@ -16996,11 +16998,11 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
        Objects.requireNonNull(who, "ComponentName is null");
        final CallerIdentity caller = getCallerIdentity(who);
        Preconditions.checkCallAuthorization(
                isDefaultDeviceOwner(caller) || isFinancedDeviceOwner(caller));
        Preconditions.checkCallAuthorization(isDefaultDeviceOwner(caller) || isProfileOwner(caller)
                || isFinancedDeviceOwner(caller));
        synchronized (getLockObject()) {
            ActiveAdmin deviceOwner = getDeviceOwnerAdminLocked();
            ActiveAdmin deviceOwner = getDeviceOrProfileOwnerAdminLocked(caller.getUserId());
            return deviceOwner.protectedPackages != null
                    ? deviceOwner.protectedPackages : Collections.emptyList();
        }
Loading