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

Commit c68057f7 authored by Vitor Carvalho's avatar Vitor Carvalho
Browse files

Introduce a method in SupervisionService to check if a caller is the active supervision app.

Bug: 382038274
Flag: android.app.supervision.flags.deprecate_dpm_supervision_apis
Test: atest SupervisionServiceTest
Change-Id: Ie1889844123240b86ff591cdab42a09c0809079f
parent 6b2a4aa1
Loading
Loading
Loading
Loading
+20 −11
Original line number Diff line number Diff line
@@ -27,32 +27,41 @@ import android.os.PersistableBundle;
 */
public abstract class SupervisionManagerInternal {
    /**
     * Returns whether supervision is enabled for the specified user
     * Returns whether the app with given process uid is the active supervision app.
     *
     * @param userId The user to retrieve the supervision state for
     * @return whether the user is supervised
     * <p>Supervision app is considered active when supervision is enabled for the user running the
     * given process uid.
     *
     * @param uid App process uid.
     * @return Whether the app is the active supervision app.
     */
    public abstract boolean isSupervisionEnabledForUser(@UserIdInt int userId);
    public abstract boolean isActiveSupervisionApp(int uid);

    /**
     * Returns whether the supervision lock screen needs to be shown.
     * Returns whether supervision is enabled for the specified user.
     *
     * @param userId The user to retrieve the supervision state for.
     * @return Whether the user is supervised.
     */
    public abstract boolean isSupervisionEnabledForUser(@UserIdInt int userId);

    /** Returns whether the supervision lock screen needs to be shown. */
    public abstract boolean isSupervisionLockscreenEnabledForUser(@UserIdInt int userId);

    /**
     * Set whether supervision is enabled for the specified user.
     *
     * @param userId The user to set the supervision state for
     * @param enabled Whether or not the user should be supervised
     * @param userId The user to set the supervision state for.
     * @param enabled Whether or not the user should be supervised.
     */
    public abstract void setSupervisionEnabledForUser(@UserIdInt int userId, boolean enabled);

    /**
     * Sets whether the supervision lock screen should be shown for the specified user
     * Sets whether the supervision lock screen should be shown for the specified user.
     *
     * @param userId The user set the superivision state for
     * @param enabled Whether or not the superivision lock screen needs to be shown
     * @param options Optional configuration parameters for the supervision lock screen
     * @param userId The user set the superivision state for.
     * @param enabled Whether or not the superivision lock screen needs to be shown.
     * @param options Optional configuration parameters for the supervision lock screen.
     */
    public abstract void setSupervisionLockscreenEnabledForUser(
            @UserIdInt int userId, boolean enabled, @Nullable PersistableBundle options);
+8 −0
Original line number Diff line number Diff line
@@ -24,3 +24,11 @@ flag {
  description: "Flag that enables supervision when the supervision app is the profile owner"
  bug: "377261590"
}

flag {
  name: "deprecate_dpm_supervision_apis"
  is_exported: true
  namespace: "supervision"
  description: "Flag that deprecates supervision methods in DPM"
  bug: "382034839"
}
+25 −5
Original line number Diff line number Diff line
@@ -29,11 +29,13 @@ import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.content.pm.UserInfo;
import android.os.PersistableBundle;
import android.os.RemoteException;
import android.os.ResultReceiver;
import android.os.ShellCallback;
import android.os.UserHandle;
import android.util.SparseArray;

import com.android.internal.R;
@@ -63,11 +65,13 @@ public class SupervisionService extends ISupervisionManager.Stub {
    private final SparseArray<SupervisionUserData> mUserData = new SparseArray<>();

    private final DevicePolicyManagerInternal mDpmInternal;
    private final PackageManager mPackageManager;
    private final UserManagerInternal mUserManagerInternal;

    public SupervisionService(Context context) {
        mContext = context.createAttributionContext(LOG_TAG);
        mDpmInternal = LocalServices.getService(DevicePolicyManagerInternal.class);
        mPackageManager = context.getPackageManager();
        mUserManagerInternal = LocalServices.getService(UserManagerInternal.class);
        mUserManagerInternal.addUserLifecycleListener(new UserLifecycleListener());
    }
@@ -148,12 +152,13 @@ public class SupervisionService extends ISupervisionManager.Stub {
    /** Returns whether the supervision app has profile owner status. */
    private boolean isProfileOwner(@UserIdInt int userId) {
        ComponentName profileOwner = mDpmInternal.getProfileOwnerAsUser(userId);
        if (profileOwner == null) {
            return false;
        return profileOwner != null && isSupervisionAppPackage(profileOwner.getPackageName());
    }

        String configPackage = mContext.getResources().getString(R.string.config_systemSupervision);
        return profileOwner.getPackageName().equals(configPackage);
    /** Returns whether the given package name belongs to the supervision role holder. */
    private boolean isSupervisionAppPackage(String packageName) {
        return packageName.equals(
                mContext.getResources().getString(R.string.config_systemSupervision));
    }

    public static class Lifecycle extends SystemService {
@@ -210,6 +215,21 @@ public class SupervisionService extends ISupervisionManager.Stub {
    final SupervisionManagerInternal mInternal = new SupervisionManagerInternalImpl();

    private final class SupervisionManagerInternalImpl extends SupervisionManagerInternal {
        @Override
        public boolean isActiveSupervisionApp(int uid) {
            String[] packages = mPackageManager.getPackagesForUid(uid);
            if (packages == null) {
                return false;
            }
            for (var packageName : packages) {
                if (SupervisionService.this.isSupervisionAppPackage(packageName)) {
                    int userId = UserHandle.getUserId(uid);
                    return SupervisionService.this.isSupervisionEnabledForUser(userId);
                }
            }
            return false;
        }

        @Override
        public boolean isSupervisionEnabledForUser(@UserIdInt int userId) {
            return SupervisionService.this.isSupervisionEnabledForUser(userId);
+33 −2
Original line number Diff line number Diff line
@@ -26,6 +26,7 @@ import android.content.Context
import android.content.ContextWrapper
import android.content.Intent
import android.content.IntentFilter
import android.content.pm.PackageManager
import android.content.pm.UserInfo
import android.os.Handler
import android.os.PersistableBundle
@@ -59,6 +60,7 @@ class SupervisionServiceTest {
    @get:Rule val mocks: MockitoRule = MockitoJUnit.rule()

    @Mock private lateinit var mockDpmInternal: DevicePolicyManagerInternal
    @Mock private lateinit var mockPackageManager: PackageManager
    @Mock private lateinit var mockUserManagerInternal: UserManagerInternal

    private lateinit var context: Context
@@ -68,7 +70,7 @@ class SupervisionServiceTest {
    @Before
    fun setUp() {
        context = InstrumentationRegistry.getInstrumentation().context
        context = SupervisionContextWrapper(context)
        context = SupervisionContextWrapper(context, mockPackageManager)

        LocalServices.removeServiceForTest(DevicePolicyManagerInternal::class.java)
        LocalServices.addService(DevicePolicyManagerInternal::class.java, mockDpmInternal)
@@ -136,6 +138,31 @@ class SupervisionServiceTest {
        assertThat(service.isSupervisionEnabledForUser(USER_ID)).isFalse()
    }

    @Test
    fun isActiveSupervisionApp_supervisionUid_supervisionEnabled_returnsTrue() {
        whenever(mockPackageManager.getPackagesForUid(APP_UID))
            .thenReturn(arrayOf(systemSupervisionPackage))
        service.setSupervisionEnabledForUser(USER_ID, true)

        assertThat(service.mInternal.isActiveSupervisionApp(APP_UID)).isTrue()
    }

    @Test
    fun isActiveSupervisionApp_supervisionUid_supervisionNotEnabled_returnsFalse() {
        whenever(mockPackageManager.getPackagesForUid(APP_UID))
            .thenReturn(arrayOf(systemSupervisionPackage))
        service.setSupervisionEnabledForUser(USER_ID, false)

        assertThat(service.mInternal.isActiveSupervisionApp(APP_UID)).isFalse()
    }

    @Test
    fun isActiveSupervisionApp_notSupervisionUid_returnsFalse() {
        whenever(mockPackageManager.getPackagesForUid(APP_UID)).thenReturn(arrayOf())

        assertThat(service.mInternal.isActiveSupervisionApp(APP_UID)).isFalse()
    }

    @Test
    fun setSupervisionEnabledForUser() {
        assertThat(service.isSupervisionEnabledForUser(USER_ID)).isFalse()
@@ -191,6 +218,7 @@ class SupervisionServiceTest {

    private companion object {
        const val USER_ID = 100
        val APP_UID = USER_ID * UserHandle.PER_USER_RANGE
    }
}

@@ -198,9 +226,12 @@ class SupervisionServiceTest {
 * A context wrapper that allows broadcast intents to immediately invoke the receivers without
 * performing checks on the sending user.
 */
private class SupervisionContextWrapper(val context: Context) : ContextWrapper(context) {
private class SupervisionContextWrapper(val context: Context, val pkgManager: PackageManager) :
    ContextWrapper(context) {
    val interceptors = mutableListOf<Pair<BroadcastReceiver, IntentFilter>>()

    override fun getPackageManager() = pkgManager

    override fun registerReceiverForAllUsers(
        receiver: BroadcastReceiver?,
        filter: IntentFilter,