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

Commit 5a501824 authored by Vitor Carvalho's avatar Vitor Carvalho Committed by Android (Google) Code Review
Browse files

Merge "Update DPMS to ensure that supervision is enabled in SupervisionService...

Merge "Update DPMS to ensure that supervision is enabled in SupervisionService when it detects that the supervision component has profile owner status on start." into main
parents d3f17bc8 ca8cd83a
Loading
Loading
Loading
Loading
+8 −0
Original line number Diff line number Diff line
@@ -34,6 +34,14 @@ public abstract class SupervisionManagerInternal {
     */
    public abstract boolean isSupervisionEnabledForUser(@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
     */
    public abstract void setSupervisionEnabledForUser(@UserIdInt int userId, boolean enabled);

    /**
     * Sets whether the supervision lock screen should be shown for the specified user
     *
+47 −11
Original line number Diff line number Diff line
@@ -19,7 +19,9 @@ package com.android.server.supervision;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
import android.app.admin.DevicePolicyManagerInternal;
import android.app.supervision.ISupervisionManager;
import android.content.ComponentName;
import android.content.Context;
import android.content.pm.UserInfo;
import android.os.Bundle;
@@ -28,19 +30,19 @@ import android.os.ResultReceiver;
import android.os.ShellCallback;
import android.util.SparseArray;

import com.android.internal.R;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.DumpUtils;
import com.android.internal.util.IndentingPrintWriter;
import com.android.server.LocalServices;
import com.android.server.SystemService;
import com.android.server.SystemService.TargetUser;
import com.android.server.pm.UserManagerInternal;

import java.io.FileDescriptor;
import java.io.PrintWriter;

/**
 * Service for handling system supervision.
 */
/** Service for handling system supervision. */
public class SupervisionService extends ISupervisionManager.Stub {
    private static final String LOG_TAG = "SupervisionService";

@@ -52,14 +54,25 @@ public class SupervisionService extends ISupervisionManager.Stub {
    @GuardedBy("getLockObject()")
    private final SparseArray<SupervisionUserData> mUserData = new SparseArray<>();

    private final DevicePolicyManagerInternal mDpmInternal;
    private final UserManagerInternal mUserManagerInternal;

    public SupervisionService(Context context) {
        mContext = context.createAttributionContext(LOG_TAG);
        mDpmInternal = LocalServices.getService(DevicePolicyManagerInternal.class);
        mUserManagerInternal = LocalServices.getService(UserManagerInternal.class);
        mUserManagerInternal.addUserLifecycleListener(new UserLifecycleListener());
    }

    void syncStateWithDevicePolicyManager(TargetUser user) {
        if (user.isPreCreated()) return;

        // Ensure that supervision is enabled when supervision app is the profile owner.
        if (android.app.admin.flags.Flags.enableSupervisionServiceSync() && isProfileOwner(user)) {
            setSupervisionEnabledForUser(user.getUserIdentifier(), true);
        }
    }

    @Override
    public boolean isSupervisionEnabledForUser(@UserIdInt int userId) {
        synchronized (getLockObject()) {
@@ -74,14 +87,15 @@ public class SupervisionService extends ISupervisionManager.Stub {
            @Nullable FileDescriptor err,
            @NonNull String[] args,
            @Nullable ShellCallback callback,
            @NonNull ResultReceiver resultReceiver) throws RemoteException {
            @NonNull ResultReceiver resultReceiver)
            throws RemoteException {
        new SupervisionServiceShellCommand(this)
                .exec(this, in, out, err, args, callback, resultReceiver);
    }

    @Override
    protected void dump(@NonNull FileDescriptor fd,
            @NonNull PrintWriter printWriter, @Nullable String[] args) {
    protected void dump(
            @NonNull FileDescriptor fd, @NonNull PrintWriter printWriter, @Nullable String[] args) {
        if (!DumpUtils.checkDumpPermission(mContext, LOG_TAG, printWriter)) return;

        try (var pw = new IndentingPrintWriter(printWriter, "  ")) {
@@ -120,6 +134,17 @@ public class SupervisionService extends ISupervisionManager.Stub {
        }
    }

    /** Returns whether the supervision app has profile owner status. */
    private boolean isProfileOwner(TargetUser user) {
        ComponentName profileOwner = mDpmInternal.getProfileOwnerAsUser(user.getUserIdentifier());
        if (profileOwner == null) {
            return false;
        }

        String configPackage = mContext.getResources().getString(R.string.config_systemSupervision);
        return profileOwner.getPackageName().equals(configPackage);
    }

    public static class Lifecycle extends SystemService {
        private final SupervisionService mSupervisionService;

@@ -133,13 +158,24 @@ public class SupervisionService extends ISupervisionManager.Stub {
            publishLocalService(SupervisionManagerInternal.class, mSupervisionService.mInternal);
            publishBinderService(Context.SUPERVISION_SERVICE, mSupervisionService);
        }

        @Override
        public void onUserStarting(@NonNull TargetUser user) {
            mSupervisionService.syncStateWithDevicePolicyManager(user);
        }
    }

    final SupervisionManagerInternal mInternal = new SupervisionManagerInternal() {
    final SupervisionManagerInternal mInternal = new SupervisionManagerInternalImpl();

    private final class SupervisionManagerInternalImpl extends SupervisionManagerInternal {
        @Override
        public boolean isSupervisionEnabledForUser(@UserIdInt int userId) {
            synchronized (getLockObject()) {
                return getUserDataLocked(userId).supervisionEnabled;
            return SupervisionService.this.isSupervisionEnabledForUser(userId);
        }

        @Override
        public void setSupervisionEnabledForUser(@UserIdInt int userId, boolean enabled) {
            SupervisionService.this.setSupervisionEnabledForUser(userId, enabled);
        }

        @Override
@@ -151,7 +187,7 @@ public class SupervisionService extends ISupervisionManager.Stub {
                data.supervisionLockScreenOptions = options;
            }
        }
    };
    }

    private final class UserLifecycleListener implements UserManagerInternal.UserLifecycleListener {
        @Override
+82 −14
Original line number Diff line number Diff line
@@ -16,12 +16,20 @@

package com.android.server.supervision

import android.app.admin.DevicePolicyManagerInternal
import android.content.ComponentName
import android.content.Context
import android.content.pm.UserInfo
import android.os.Bundle
import android.platform.test.annotations.RequiresFlagsEnabled
import android.platform.test.flag.junit.DeviceFlagsValueProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.platform.app.InstrumentationRegistry
import com.android.internal.R
import com.android.server.LocalServices
import com.android.server.SystemService.TargetUser
import com.android.server.pm.UserManagerInternal
import com.google.common.truth.Truth.assertThat
import androidx.test.platform.app.InstrumentationRegistry
import org.junit.Before
import org.junit.Rule
import org.junit.Test
@@ -29,11 +37,12 @@ import org.junit.runner.RunWith
import org.mockito.Mock
import org.mockito.junit.MockitoJUnit
import org.mockito.junit.MockitoRule
import org.mockito.kotlin.whenever

/**
 * Unit tests for {@link SupervisionService}.
 * <p/>
 * Run with <code>atest SupervisionServiceTest</code>.
 * Unit tests for [SupervisionService].
 *
 * Run with `atest SupervisionServiceTest`.
 */
@RunWith(AndroidJUnit4::class)
class SupervisionServiceTest {
@@ -41,18 +50,21 @@ class SupervisionServiceTest {
        const val USER_ID = 100
    }

    private lateinit var service: SupervisionService
    @get:Rule val mocks: MockitoRule = MockitoJUnit.rule()
    @get:Rule val checkFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule()

    @Rule
    @JvmField
    val mocks: MockitoRule = MockitoJUnit.rule()
    @Mock private lateinit var mockDpmInternal: DevicePolicyManagerInternal
    @Mock private lateinit var mockUserManagerInternal: UserManagerInternal

    @Mock
    private lateinit var mockUserManagerInternal: UserManagerInternal
    private lateinit var context: Context
    private lateinit var service: SupervisionService

    @Before
    fun setup() {
        val context = InstrumentationRegistry.getInstrumentation().context
    fun setUp() {
        context = InstrumentationRegistry.getInstrumentation().context

        LocalServices.removeServiceForTest(DevicePolicyManagerInternal::class.java)
        LocalServices.addService(DevicePolicyManagerInternal::class.java, mockDpmInternal)

        LocalServices.removeServiceForTest(UserManagerInternal::class.java)
        LocalServices.addService(UserManagerInternal::class.java, mockUserManagerInternal)
@@ -61,7 +73,46 @@ class SupervisionServiceTest {
    }

    @Test
    fun testSetSupervisionEnabledForUser() {
    @RequiresFlagsEnabled(android.app.admin.flags.Flags.FLAG_ENABLE_SUPERVISION_SERVICE_SYNC)
    fun syncStateWithDevicePolicyManager_supervisionAppIsProfileOwner_enablesSupervision() {
        val supervisionPackageName =
            context.getResources().getString(R.string.config_systemSupervision)

        whenever(mockDpmInternal.getProfileOwnerAsUser(USER_ID))
            .thenReturn(ComponentName(supervisionPackageName, "MainActivity"))

        service.syncStateWithDevicePolicyManager(newTargetUser(USER_ID))

        assertThat(service.isSupervisionEnabledForUser(USER_ID)).isTrue()
    }

    @Test
    @RequiresFlagsEnabled(android.app.admin.flags.Flags.FLAG_ENABLE_SUPERVISION_SERVICE_SYNC)
    fun syncStateWithDevicePolicyManager_userPreCreated_doesNotEnableSupervision() {
        val supervisionPackageName =
            context.getResources().getString(R.string.config_systemSupervision)

        whenever(mockDpmInternal.getProfileOwnerAsUser(USER_ID))
            .thenReturn(ComponentName(supervisionPackageName, "MainActivity"))

        service.syncStateWithDevicePolicyManager(newTargetUser(USER_ID, preCreated = true))

        assertThat(service.isSupervisionEnabledForUser(USER_ID)).isFalse()
    }

    @Test
    @RequiresFlagsEnabled(android.app.admin.flags.Flags.FLAG_ENABLE_SUPERVISION_SERVICE_SYNC)
    fun syncStateWithDevicePolicyManager_supervisionAppIsNotProfileOwner_doesNotEnableSupervision() {
        whenever(mockDpmInternal.getProfileOwnerAsUser(USER_ID))
            .thenReturn(ComponentName("other.package", "MainActivity"))

        service.syncStateWithDevicePolicyManager(newTargetUser(USER_ID))

        assertThat(service.isSupervisionEnabledForUser(USER_ID)).isFalse()
    }

    @Test
    fun setSupervisionEnabledForUser() {
        assertThat(service.isSupervisionEnabledForUser(USER_ID)).isFalse()

        service.setSupervisionEnabledForUser(USER_ID, true)
@@ -72,7 +123,18 @@ class SupervisionServiceTest {
    }

    @Test
    fun testSetSupervisionLockscreenEnabledForUser() {
    fun supervisionEnabledForUser_internal() {
        assertThat(service.isSupervisionEnabledForUser(USER_ID)).isFalse()

        service.mInternal.setSupervisionEnabledForUser(USER_ID, true)
        assertThat(service.isSupervisionEnabledForUser(USER_ID)).isTrue()

        service.mInternal.setSupervisionEnabledForUser(USER_ID, false)
        assertThat(service.isSupervisionEnabledForUser(USER_ID)).isFalse()
    }

    @Test
    fun setSupervisionLockscreenEnabledForUser() {
        var userData = service.getUserDataLocked(USER_ID)
        assertThat(userData.supervisionLockScreenEnabled).isFalse()
        assertThat(userData.supervisionLockScreenOptions).isNull()
@@ -87,4 +149,10 @@ class SupervisionServiceTest {
        assertThat(userData.supervisionLockScreenEnabled).isFalse()
        assertThat(userData.supervisionLockScreenOptions).isNull()
    }

    private fun newTargetUser(userId: Int, preCreated: Boolean = false): TargetUser {
        val userInfo = UserInfo(userId, /* name= */ "tempUser", /* flags= */ 0)
        userInfo.preCreated = preCreated
        return TargetUser(userInfo)
    }
}