Loading services/core/java/android/content/pm/PackageManagerInternal.java +13 −0 Original line number Diff line number Diff line Loading @@ -21,6 +21,7 @@ import android.annotation.IntDef; import android.annotation.LongDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SpecialUsers; import android.annotation.SystemApi; import android.annotation.UserIdInt; import android.annotation.WorkerThread; Loading Loading @@ -300,6 +301,18 @@ public abstract class PackageManagerInternal { public abstract String[] setPackagesSuspendedByAdmin( @UserIdInt int userId, @NonNull String[] packageNames, boolean suspended); /** * Unsuspends all packages that were previously suspended by a specific suspending package. * * @param suspendingPackage The package that originally requested suspension. * @param suspendingUserId The user ID that requested suspension. * @param affectedUserId The user ID for which to unsuspend the packages. */ public abstract void unsuspendForSuspendingPackage(String suspendingPackage, @UserIdInt int suspendingUserId, @SpecialUsers.CanBeALL @UserIdInt int affectedUserId); /** * Get the information describing the dialog to be shown to the user when they try to launch a * suspended application. Loading services/core/java/com/android/server/pm/PackageManagerInternalBase.java +12 −1 Original line number Diff line number Diff line Loading @@ -24,6 +24,7 @@ import static com.android.server.pm.PackageManagerService.PLATFORM_PACKAGE_NAME; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SpecialUsers; import android.annotation.UserIdInt; import android.content.ComponentName; import android.content.Context; Loading Loading @@ -700,6 +701,15 @@ abstract class PackageManagerInternalBase extends PackageManagerInternal { return snapshot().isSuspendingAnyPackages(PLATFORM_PACKAGE_NAME, suspendingUserId, userId); } @Override @Deprecated public void unsuspendForSuspendingPackage(String suspendingPackage, @UserIdInt int suspendingUserId, @SpecialUsers.CanBeALL @UserIdInt int affectedUserId) { mService.unsuspendForSuspendingPackage( snapshot(), suspendingPackage, suspendingUserId, affectedUserId); } @Override @Deprecated public final void requestChecksums(@NonNull String packageName, boolean includeSplits, Loading @@ -716,7 +726,8 @@ abstract class PackageManagerInternalBase extends PackageManagerInternal { @Deprecated public final boolean isPackageFrozen(@NonNull String packageName, int callingUid, int userId) { return snapshot().getPackageStartability(mService.getSafeMode(), packageName, callingUid, userId) return snapshot().getPackageStartability(mService.getSafeMode(), packageName, callingUid, userId) == PackageManagerService.PACKAGE_STARTABILITY_FROZEN; } Loading services/supervision/java/com/android/server/supervision/SupervisionService.java +112 −52 Original line number Diff line number Diff line Loading @@ -33,6 +33,7 @@ import android.annotation.UserIdInt; import android.app.KeyguardManager; import android.app.admin.DevicePolicyManager; import android.app.admin.DevicePolicyManagerInternal; import android.app.role.RoleManager; import android.app.supervision.ISupervisionListener; import android.app.supervision.ISupervisionManager; import android.app.supervision.SupervisionManagerInternal; Loading @@ -45,6 +46,7 @@ import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.pm.PackageManager; import android.content.pm.PackageManagerInternal; import android.content.pm.UserInfo; import android.os.Binder; import android.os.Bundle; Loading Loading @@ -165,9 +167,8 @@ public class SupervisionService extends ISupervisionManager.Stub { } /** * Creates an {@link Intent} that can be used with * {@link Context#startActivityForResult(String, Intent, int, Bundle)} to launch the activity to * verify supervision credentials. * Creates an {@link Intent} that can be used with {@link Context#startActivityForResult(String, * Intent, int, Bundle)} to launch the activity to verify supervision credentials. * * <p>A valid {@link Intent} is always returned if supervision is enabled at the time this * method is called, the launched activity still need to perform validity checks as the Loading Loading @@ -271,8 +272,8 @@ public class SupervisionService extends ISupervisionManager.Stub { SupervisionListenerRecord record = mSupervisionListeners.get(listener.asBinder()); if (record == null) { try { mSupervisionListeners.put(listener.asBinder(), new SupervisionListenerRecord(listener, userId)); mSupervisionListeners.put( listener.asBinder(), new SupervisionListenerRecord(listener, userId)); } catch (RemoteException e) { // Binder died, ignore } Loading Loading @@ -380,18 +381,20 @@ public class SupervisionService extends ISupervisionManager.Stub { mSupervisionSettings.saveUserData(); } } Binder.withCleanCallingIdentity(() -> { Binder.withCleanCallingIdentity( () -> { updateWebContentFilters(userId, enabled); dispatchSupervisionEvent(userId, listener -> listener.onSetSupervisionEnabled(userId, enabled)); dispatchSupervisionEvent( userId, listener -> listener.onSetSupervisionEnabled(userId, enabled)); if (!enabled) { clearDevicePolicies(userId, supervisionAppPackage); clearAllDevicePoliciesAndSuspendedPackages(userId); } }); } @NonNull private List<ISupervisionListener> getSupervisionAppServiceListeners(@UserIdInt int userId, private List<ISupervisionListener> getSupervisionAppServiceListeners( @UserIdInt int userId, @NonNull RemoteExceptionIgnoringConsumer<ISupervisionListener> action) { ArrayList<ISupervisionListener> listeners = new ArrayList<>(); if (!Flags.enableSupervisionAppService()) { Loading @@ -409,8 +412,10 @@ public class SupervisionService extends ISupervisionManager.Stub { } if (binder == null) { Slogf.d(SupervisionLog.TAG, "Failed to bind to SupervisionAppService for %s now", targetPackage); Slogf.d( SupervisionLog.TAG, "Failed to bind to SupervisionAppService for %s now", targetPackage); dispatchSupervisionAppServiceWhenConnected(conn, action); continue; Loading @@ -422,7 +427,8 @@ public class SupervisionService extends ISupervisionManager.Stub { return listeners; } private void dispatchSupervisionEvent(@UserIdInt int userId, private void dispatchSupervisionEvent( @UserIdInt int userId, @NonNull RemoteExceptionIgnoringConsumer<ISupervisionListener> action) { ArrayList<ISupervisionListener> listeners = new ArrayList<>(); Loading @@ -430,7 +436,8 @@ public class SupervisionService extends ISupervisionManager.Stub { listeners.addAll(getSupervisionAppServiceListeners(userId, action)); synchronized (getLockObject()) { mSupervisionListeners.forEach((binder, record) -> { mSupervisionListeners.forEach( (binder, record) -> { if (record.userId == userId || record.userId == UserHandle.USER_ALL) { listeners.add(record.listener); } Loading @@ -440,12 +447,37 @@ public class SupervisionService extends ISupervisionManager.Stub { listeners.forEach(listener -> action.accept(listener)); } private void clearDevicePolicies( @UserIdInt int userId, @Nullable String supervisionAppPackage) { private void clearAllDevicePoliciesAndSuspendedPackages(@UserIdInt int userId) { if (!Flags.enableRemovePoliciesOnSupervisionDisable()) { return; } enforcePermission(MANAGE_ROLE_HOLDERS); List<String> supervisionPackages = new ArrayList<>(); RoleManagerWrapper roleManager = mInjector.getRoleManagerWrapper(); if (roleManager != null) { supervisionPackages.addAll( roleManager.getRoleHoldersAsUser( RoleManager.ROLE_SUPERVISION, UserHandle.of(userId))); supervisionPackages.addAll( roleManager.getRoleHoldersAsUser( RoleManager.ROLE_SYSTEM_SUPERVISION, UserHandle.of(userId))); } for (String supervisionPackage : supervisionPackages) { clearDevicePoliciesAndSuspendedPackagesFor(userId, supervisionPackage); } } private void clearDevicePoliciesAndSuspendedPackagesFor(int userId, String supervisionPackage) { DevicePolicyManagerInternal dpmi = mInjector.getDpmInternal(); if (Flags.enableRemovePoliciesOnSupervisionDisable() && dpmi != null && supervisionAppPackage != null) { dpmi.removePoliciesForAdmins(supervisionAppPackage, userId); if (dpmi != null) { dpmi.removePoliciesForAdmins(supervisionPackage, userId); } PackageManagerInternal pmi = mInjector.getPackageManagerInternal(); if (pmi != null) { pmi.unsuspendForSuspendingPackage(supervisionPackage, userId, userId); } } Loading @@ -456,8 +488,8 @@ public class SupervisionService extends ISupervisionManager.Stub { AppServiceConnection.ConnectionStatusListener connectionListener = new AppServiceConnection.ConnectionStatusListener() { @Override public void onConnected(@NonNull AppServiceConnection connection, @NonNull IInterface service) { public void onConnected( @NonNull AppServiceConnection connection, @NonNull IInterface service) { try { ISupervisionListener binder = (ISupervisionListener) service; Binder.withCleanCallingIdentity(() -> action.accept(binder)); Loading Loading @@ -496,11 +528,7 @@ public class SupervisionService extends ISupervisionManager.Stub { final ContentResolver contentResolver = mInjector.context.getContentResolver(); final int value = Settings.Secure.getIntForUser(contentResolver, key, userId); if (!enabled || value != 1) { Settings.Secure.putIntForUser( contentResolver, key, value * -1, userId); Settings.Secure.putIntForUser(contentResolver, key, value * -1, userId); } } catch (Settings.SettingNotFoundException ignored) { // Ignore the exception and do not change the value as no value has been set. Loading Loading @@ -536,7 +564,9 @@ public class SupervisionService extends ISupervisionManager.Stub { */ private ComponentName getSupervisionProfileOwnerComponent() { return ComponentName.unflattenFromString( mInjector.context.getResources() mInjector .context .getResources() .getString(R.string.config_defaultSupervisionProfileOwnerComponent)); } Loading Loading @@ -570,7 +600,9 @@ public class SupervisionService extends ISupervisionManager.Stub { private AppBindingService mAppBindingService; private KeyguardManager mKeyguardManager; private PackageManager mPackageManager; private PackageManagerInternal mPackageManagerInternal; private UserManagerInternal mUserManagerInternal; private RoleManagerWrapper mRoleManagerWrapper; Injector(Context context) { this.context = context; Loading Loading @@ -612,6 +644,34 @@ public class SupervisionService extends ISupervisionManager.Stub { } return mUserManagerInternal; } PackageManagerInternal getPackageManagerInternal() { if (mPackageManagerInternal == null) { mPackageManagerInternal = LocalServices.getService(PackageManagerInternal.class); } return mPackageManagerInternal; } RoleManagerWrapper getRoleManagerWrapper() { if (mRoleManagerWrapper == null) { final Object roleManager = context.getSystemService(RoleManager.class); if (roleManager instanceof RoleManager) { mRoleManagerWrapper = new RoleManagerWrapper() { @Override public List<String> getRoleHoldersAsUser(String roleName, UserHandle user) { return ((RoleManager) roleManager).getRoleHoldersAsUser(roleName, user); } }; } else { mRoleManagerWrapper = (RoleManagerWrapper) roleManager; } } return mRoleManagerWrapper; } } public interface RoleManagerWrapper { List<String> getRoleHoldersAsUser(String roleName, UserHandle user); } /** Publishes local and binder services and allows the service to act during initialization. */ Loading services/tests/servicestests/src/com/android/server/supervision/SupervisionServiceTest.kt +67 −10 Original line number Diff line number Diff line Loading @@ -20,6 +20,7 @@ import android.app.Activity import android.app.KeyguardManager import android.app.admin.DevicePolicyManager import android.app.admin.DevicePolicyManagerInternal import android.app.role.RoleManager import android.app.supervision.ISupervisionListener import android.app.supervision.SupervisionRecoveryInfo import android.app.supervision.SupervisionRecoveryInfo.STATE_PENDING Loading @@ -30,14 +31,15 @@ import android.content.Context import android.content.ContextWrapper import android.content.Intent import android.content.IntentFilter import android.os.IBinder import android.content.pm.PackageManager import android.content.pm.PackageManagerInternal import android.content.pm.UserInfo import android.content.pm.UserInfo.FLAG_FOR_TESTING import android.content.pm.UserInfo.FLAG_FULL import android.content.pm.UserInfo.FLAG_MAIN import android.content.pm.UserInfo.FLAG_SYSTEM import android.os.Handler import android.os.IBinder import android.os.PersistableBundle import android.os.UserHandle import android.os.UserHandle.MIN_SECONDARY_USER_ID Loading @@ -56,6 +58,7 @@ import com.android.server.LocalServices import com.android.server.SystemService.TargetUser import com.android.server.pm.UserManagerInternal import com.android.server.supervision.SupervisionService.ACTION_CONFIRM_SUPERVISION_CREDENTIALS import com.android.server.supervision.SupervisionService.RoleManagerWrapper import com.google.common.truth.Truth.assertThat import java.nio.file.Files import org.junit.Before Loading Loading @@ -88,8 +91,9 @@ class SupervisionServiceTest { @Mock private lateinit var mockDpmInternal: DevicePolicyManagerInternal @Mock private lateinit var mockKeyguardManager: KeyguardManager @Mock private lateinit var mockPackageManager: PackageManager @Mock private lateinit var mockPackageManagerInternal: PackageManagerInternal @Mock private lateinit var mockUserManagerInternal: UserManagerInternal @Mock private lateinit var mockSupervisionListener: ISupervisionListener @Mock private lateinit var mockRoleManager: SupervisionService.RoleManagerWrapper private lateinit var context: Context private lateinit var lifecycle: SupervisionService.Lifecycle Loading @@ -98,7 +102,8 @@ class SupervisionServiceTest { @Before fun setUp() { context = InstrumentationRegistry.getInstrumentation().context context = SupervisionContextWrapper(context, mockKeyguardManager, mockPackageManager) context = SupervisionContextWrapper(context, mockKeyguardManager, mockPackageManager, mockRoleManager) LocalServices.removeServiceForTest(DevicePolicyManagerInternal::class.java) LocalServices.addService(DevicePolicyManagerInternal::class.java, mockDpmInternal) Loading @@ -106,6 +111,9 @@ class SupervisionServiceTest { LocalServices.removeServiceForTest(UserManagerInternal::class.java) LocalServices.addService(UserManagerInternal::class.java, mockUserManagerInternal) LocalServices.removeServiceForTest(PackageManagerInternal::class.java) LocalServices.addService(PackageManagerInternal::class.java, mockPackageManagerInternal) // Creating a temporary folder to enable access to SupervisionSettings. SupervisionSettings.getInstance() .changeDirForTesting(Files.createTempDirectory("tempSupervisionFolder").toFile()) Loading @@ -114,6 +122,7 @@ class SupervisionServiceTest { lifecycle = SupervisionService.Lifecycle(context, service) lifecycle.registerProfileOwnerListener() //TODO: b/427453821 Remove after converting SupervisionSettings from being a singleton. assertThat(service.isSupervisionEnabledForUser(USER_ID)).isFalse() } Loading Loading @@ -273,10 +282,18 @@ class SupervisionServiceTest { @Test @RequiresFlagsEnabled(Flags.FLAG_ENABLE_REMOVE_POLICIES_ON_SUPERVISION_DISABLE) fun setSupervisionEnabledForUser_removesPoliciesWhenDisabling() { for ((role, packageName) in supervisionRoleHolders) { whenever(mockRoleManager.getRoleHoldersAsUser(eq(role), any())) .thenReturn(listOf(packageName)); } service.setSupervisionEnabledForUser(USER_ID, false) assertThat(service.isSupervisionEnabledForUser(USER_ID)).isFalse() verify(mockDpmInternal).removePoliciesForAdmins(eq(systemSupervisionPackage), eq(USER_ID)) for (packageName in supervisionRoleHolders.values) { verify(mockPackageManagerInternal) .unsuspendForSuspendingPackage(eq(packageName), eq(USER_ID), eq(USER_ID)) } } @Test Loading Loading @@ -491,12 +508,16 @@ class SupervisionServiceTest { assertThat(service.mSupervisionListeners).doesNotContainKey(binder) } private fun setSupervisionEnabledForUser(expectedUserId: Int, enabled: Boolean, listeners: Map<Int, Pair<ISupervisionListener, IBinder>>) { private fun setSupervisionEnabledForUser( expectedUserId: Int, enabled: Boolean, listeners: Map<Int, Pair<ISupervisionListener, IBinder>>, ) { service.setSupervisionEnabledForUser(expectedUserId, enabled) listeners.forEach { userId, (listener, binder) -> when (userId) { expectedUserId, UserHandle.USER_ALL -> { expectedUserId, UserHandle.USER_ALL -> { verify(listener).onSetSupervisionEnabled(eq(expectedUserId), eq(enabled)) } else -> { Loading @@ -506,6 +527,34 @@ class SupervisionServiceTest { } } @Test @RequiresFlagsEnabled(Flags.FLAG_ENABLE_REMOVE_POLICIES_ON_SUPERVISION_DISABLE) fun clearPackageSuspensions_unsuspendsSupervisionPackages() { assertThat(service.isSupervisionEnabledForUser(USER_ID)).isFalse() for ((role, packageName) in supervisionRoleHolders) { whenever(mockRoleManager.getRoleHoldersAsUser(eq(role), any())) .thenReturn(listOf(packageName)); } service.setSupervisionEnabledForUser(USER_ID, false) assertThat(service.isSupervisionEnabledForUser(USER_ID)).isFalse() for (packageName in supervisionRoleHolders.values) { verify(mockPackageManagerInternal) .unsuspendForSuspendingPackage(eq(packageName), eq(USER_ID), eq(USER_ID)) } } @Test @RequiresFlagsEnabled(Flags.FLAG_ENABLE_REMOVE_POLICIES_ON_SUPERVISION_DISABLE) fun clearPackageSuspensions_noSupervisionPackages_doesNothing() { whenever(mockRoleManager.getRoleHoldersAsUser( any(), any())).thenReturn(listOf()) service.setSupervisionEnabledForUser(USER_ID, false) verify(mockPackageManagerInternal, never()).unsuspendForSuspendingPackage(any(), any(), any()) } private val systemSupervisionPackage: String get() = context.getResources().getString(R.string.config_systemSupervision) Loading Loading @@ -557,6 +606,10 @@ class SupervisionServiceTest { const val SUPERVISING_USER_ID = 10 const val USER_ICON = "user_icon" const val USER_TYPE = "fake_user_type" val supervisionRoleHolders = mapOf( RoleManager.ROLE_SYSTEM_SUPERVISION to "com.example.supervisionapp1", RoleManager.ROLE_SUPERVISION to "com.example.supervisionapp2" ) val userData: Map<Int, Int> = mapOf( USER_SYSTEM to FLAG_SYSTEM, Loading @@ -574,14 +627,18 @@ private class SupervisionContextWrapper( val context: Context, val keyguardManager: KeyguardManager, val pkgManager: PackageManager, val roleManagerWrapper: RoleManagerWrapper, ) : ContextWrapper(context) { val interceptors = mutableListOf<Pair<BroadcastReceiver, IntentFilter>>() override fun getSystemService(name: String): Any = when (name) { KEYGUARD_SERVICE -> keyguardManager override fun getSystemService(name: String): Any? { var ret = when (name) { Context.KEYGUARD_SERVICE -> keyguardManager Context.ROLE_SERVICE -> roleManagerWrapper else -> super.getSystemService(name) } return ret; } override fun getPackageManager() = pkgManager Loading Loading
services/core/java/android/content/pm/PackageManagerInternal.java +13 −0 Original line number Diff line number Diff line Loading @@ -21,6 +21,7 @@ import android.annotation.IntDef; import android.annotation.LongDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SpecialUsers; import android.annotation.SystemApi; import android.annotation.UserIdInt; import android.annotation.WorkerThread; Loading Loading @@ -300,6 +301,18 @@ public abstract class PackageManagerInternal { public abstract String[] setPackagesSuspendedByAdmin( @UserIdInt int userId, @NonNull String[] packageNames, boolean suspended); /** * Unsuspends all packages that were previously suspended by a specific suspending package. * * @param suspendingPackage The package that originally requested suspension. * @param suspendingUserId The user ID that requested suspension. * @param affectedUserId The user ID for which to unsuspend the packages. */ public abstract void unsuspendForSuspendingPackage(String suspendingPackage, @UserIdInt int suspendingUserId, @SpecialUsers.CanBeALL @UserIdInt int affectedUserId); /** * Get the information describing the dialog to be shown to the user when they try to launch a * suspended application. Loading
services/core/java/com/android/server/pm/PackageManagerInternalBase.java +12 −1 Original line number Diff line number Diff line Loading @@ -24,6 +24,7 @@ import static com.android.server.pm.PackageManagerService.PLATFORM_PACKAGE_NAME; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SpecialUsers; import android.annotation.UserIdInt; import android.content.ComponentName; import android.content.Context; Loading Loading @@ -700,6 +701,15 @@ abstract class PackageManagerInternalBase extends PackageManagerInternal { return snapshot().isSuspendingAnyPackages(PLATFORM_PACKAGE_NAME, suspendingUserId, userId); } @Override @Deprecated public void unsuspendForSuspendingPackage(String suspendingPackage, @UserIdInt int suspendingUserId, @SpecialUsers.CanBeALL @UserIdInt int affectedUserId) { mService.unsuspendForSuspendingPackage( snapshot(), suspendingPackage, suspendingUserId, affectedUserId); } @Override @Deprecated public final void requestChecksums(@NonNull String packageName, boolean includeSplits, Loading @@ -716,7 +726,8 @@ abstract class PackageManagerInternalBase extends PackageManagerInternal { @Deprecated public final boolean isPackageFrozen(@NonNull String packageName, int callingUid, int userId) { return snapshot().getPackageStartability(mService.getSafeMode(), packageName, callingUid, userId) return snapshot().getPackageStartability(mService.getSafeMode(), packageName, callingUid, userId) == PackageManagerService.PACKAGE_STARTABILITY_FROZEN; } Loading
services/supervision/java/com/android/server/supervision/SupervisionService.java +112 −52 Original line number Diff line number Diff line Loading @@ -33,6 +33,7 @@ import android.annotation.UserIdInt; import android.app.KeyguardManager; import android.app.admin.DevicePolicyManager; import android.app.admin.DevicePolicyManagerInternal; import android.app.role.RoleManager; import android.app.supervision.ISupervisionListener; import android.app.supervision.ISupervisionManager; import android.app.supervision.SupervisionManagerInternal; Loading @@ -45,6 +46,7 @@ import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.pm.PackageManager; import android.content.pm.PackageManagerInternal; import android.content.pm.UserInfo; import android.os.Binder; import android.os.Bundle; Loading Loading @@ -165,9 +167,8 @@ public class SupervisionService extends ISupervisionManager.Stub { } /** * Creates an {@link Intent} that can be used with * {@link Context#startActivityForResult(String, Intent, int, Bundle)} to launch the activity to * verify supervision credentials. * Creates an {@link Intent} that can be used with {@link Context#startActivityForResult(String, * Intent, int, Bundle)} to launch the activity to verify supervision credentials. * * <p>A valid {@link Intent} is always returned if supervision is enabled at the time this * method is called, the launched activity still need to perform validity checks as the Loading Loading @@ -271,8 +272,8 @@ public class SupervisionService extends ISupervisionManager.Stub { SupervisionListenerRecord record = mSupervisionListeners.get(listener.asBinder()); if (record == null) { try { mSupervisionListeners.put(listener.asBinder(), new SupervisionListenerRecord(listener, userId)); mSupervisionListeners.put( listener.asBinder(), new SupervisionListenerRecord(listener, userId)); } catch (RemoteException e) { // Binder died, ignore } Loading Loading @@ -380,18 +381,20 @@ public class SupervisionService extends ISupervisionManager.Stub { mSupervisionSettings.saveUserData(); } } Binder.withCleanCallingIdentity(() -> { Binder.withCleanCallingIdentity( () -> { updateWebContentFilters(userId, enabled); dispatchSupervisionEvent(userId, listener -> listener.onSetSupervisionEnabled(userId, enabled)); dispatchSupervisionEvent( userId, listener -> listener.onSetSupervisionEnabled(userId, enabled)); if (!enabled) { clearDevicePolicies(userId, supervisionAppPackage); clearAllDevicePoliciesAndSuspendedPackages(userId); } }); } @NonNull private List<ISupervisionListener> getSupervisionAppServiceListeners(@UserIdInt int userId, private List<ISupervisionListener> getSupervisionAppServiceListeners( @UserIdInt int userId, @NonNull RemoteExceptionIgnoringConsumer<ISupervisionListener> action) { ArrayList<ISupervisionListener> listeners = new ArrayList<>(); if (!Flags.enableSupervisionAppService()) { Loading @@ -409,8 +412,10 @@ public class SupervisionService extends ISupervisionManager.Stub { } if (binder == null) { Slogf.d(SupervisionLog.TAG, "Failed to bind to SupervisionAppService for %s now", targetPackage); Slogf.d( SupervisionLog.TAG, "Failed to bind to SupervisionAppService for %s now", targetPackage); dispatchSupervisionAppServiceWhenConnected(conn, action); continue; Loading @@ -422,7 +427,8 @@ public class SupervisionService extends ISupervisionManager.Stub { return listeners; } private void dispatchSupervisionEvent(@UserIdInt int userId, private void dispatchSupervisionEvent( @UserIdInt int userId, @NonNull RemoteExceptionIgnoringConsumer<ISupervisionListener> action) { ArrayList<ISupervisionListener> listeners = new ArrayList<>(); Loading @@ -430,7 +436,8 @@ public class SupervisionService extends ISupervisionManager.Stub { listeners.addAll(getSupervisionAppServiceListeners(userId, action)); synchronized (getLockObject()) { mSupervisionListeners.forEach((binder, record) -> { mSupervisionListeners.forEach( (binder, record) -> { if (record.userId == userId || record.userId == UserHandle.USER_ALL) { listeners.add(record.listener); } Loading @@ -440,12 +447,37 @@ public class SupervisionService extends ISupervisionManager.Stub { listeners.forEach(listener -> action.accept(listener)); } private void clearDevicePolicies( @UserIdInt int userId, @Nullable String supervisionAppPackage) { private void clearAllDevicePoliciesAndSuspendedPackages(@UserIdInt int userId) { if (!Flags.enableRemovePoliciesOnSupervisionDisable()) { return; } enforcePermission(MANAGE_ROLE_HOLDERS); List<String> supervisionPackages = new ArrayList<>(); RoleManagerWrapper roleManager = mInjector.getRoleManagerWrapper(); if (roleManager != null) { supervisionPackages.addAll( roleManager.getRoleHoldersAsUser( RoleManager.ROLE_SUPERVISION, UserHandle.of(userId))); supervisionPackages.addAll( roleManager.getRoleHoldersAsUser( RoleManager.ROLE_SYSTEM_SUPERVISION, UserHandle.of(userId))); } for (String supervisionPackage : supervisionPackages) { clearDevicePoliciesAndSuspendedPackagesFor(userId, supervisionPackage); } } private void clearDevicePoliciesAndSuspendedPackagesFor(int userId, String supervisionPackage) { DevicePolicyManagerInternal dpmi = mInjector.getDpmInternal(); if (Flags.enableRemovePoliciesOnSupervisionDisable() && dpmi != null && supervisionAppPackage != null) { dpmi.removePoliciesForAdmins(supervisionAppPackage, userId); if (dpmi != null) { dpmi.removePoliciesForAdmins(supervisionPackage, userId); } PackageManagerInternal pmi = mInjector.getPackageManagerInternal(); if (pmi != null) { pmi.unsuspendForSuspendingPackage(supervisionPackage, userId, userId); } } Loading @@ -456,8 +488,8 @@ public class SupervisionService extends ISupervisionManager.Stub { AppServiceConnection.ConnectionStatusListener connectionListener = new AppServiceConnection.ConnectionStatusListener() { @Override public void onConnected(@NonNull AppServiceConnection connection, @NonNull IInterface service) { public void onConnected( @NonNull AppServiceConnection connection, @NonNull IInterface service) { try { ISupervisionListener binder = (ISupervisionListener) service; Binder.withCleanCallingIdentity(() -> action.accept(binder)); Loading Loading @@ -496,11 +528,7 @@ public class SupervisionService extends ISupervisionManager.Stub { final ContentResolver contentResolver = mInjector.context.getContentResolver(); final int value = Settings.Secure.getIntForUser(contentResolver, key, userId); if (!enabled || value != 1) { Settings.Secure.putIntForUser( contentResolver, key, value * -1, userId); Settings.Secure.putIntForUser(contentResolver, key, value * -1, userId); } } catch (Settings.SettingNotFoundException ignored) { // Ignore the exception and do not change the value as no value has been set. Loading Loading @@ -536,7 +564,9 @@ public class SupervisionService extends ISupervisionManager.Stub { */ private ComponentName getSupervisionProfileOwnerComponent() { return ComponentName.unflattenFromString( mInjector.context.getResources() mInjector .context .getResources() .getString(R.string.config_defaultSupervisionProfileOwnerComponent)); } Loading Loading @@ -570,7 +600,9 @@ public class SupervisionService extends ISupervisionManager.Stub { private AppBindingService mAppBindingService; private KeyguardManager mKeyguardManager; private PackageManager mPackageManager; private PackageManagerInternal mPackageManagerInternal; private UserManagerInternal mUserManagerInternal; private RoleManagerWrapper mRoleManagerWrapper; Injector(Context context) { this.context = context; Loading Loading @@ -612,6 +644,34 @@ public class SupervisionService extends ISupervisionManager.Stub { } return mUserManagerInternal; } PackageManagerInternal getPackageManagerInternal() { if (mPackageManagerInternal == null) { mPackageManagerInternal = LocalServices.getService(PackageManagerInternal.class); } return mPackageManagerInternal; } RoleManagerWrapper getRoleManagerWrapper() { if (mRoleManagerWrapper == null) { final Object roleManager = context.getSystemService(RoleManager.class); if (roleManager instanceof RoleManager) { mRoleManagerWrapper = new RoleManagerWrapper() { @Override public List<String> getRoleHoldersAsUser(String roleName, UserHandle user) { return ((RoleManager) roleManager).getRoleHoldersAsUser(roleName, user); } }; } else { mRoleManagerWrapper = (RoleManagerWrapper) roleManager; } } return mRoleManagerWrapper; } } public interface RoleManagerWrapper { List<String> getRoleHoldersAsUser(String roleName, UserHandle user); } /** Publishes local and binder services and allows the service to act during initialization. */ Loading
services/tests/servicestests/src/com/android/server/supervision/SupervisionServiceTest.kt +67 −10 Original line number Diff line number Diff line Loading @@ -20,6 +20,7 @@ import android.app.Activity import android.app.KeyguardManager import android.app.admin.DevicePolicyManager import android.app.admin.DevicePolicyManagerInternal import android.app.role.RoleManager import android.app.supervision.ISupervisionListener import android.app.supervision.SupervisionRecoveryInfo import android.app.supervision.SupervisionRecoveryInfo.STATE_PENDING Loading @@ -30,14 +31,15 @@ import android.content.Context import android.content.ContextWrapper import android.content.Intent import android.content.IntentFilter import android.os.IBinder import android.content.pm.PackageManager import android.content.pm.PackageManagerInternal import android.content.pm.UserInfo import android.content.pm.UserInfo.FLAG_FOR_TESTING import android.content.pm.UserInfo.FLAG_FULL import android.content.pm.UserInfo.FLAG_MAIN import android.content.pm.UserInfo.FLAG_SYSTEM import android.os.Handler import android.os.IBinder import android.os.PersistableBundle import android.os.UserHandle import android.os.UserHandle.MIN_SECONDARY_USER_ID Loading @@ -56,6 +58,7 @@ import com.android.server.LocalServices import com.android.server.SystemService.TargetUser import com.android.server.pm.UserManagerInternal import com.android.server.supervision.SupervisionService.ACTION_CONFIRM_SUPERVISION_CREDENTIALS import com.android.server.supervision.SupervisionService.RoleManagerWrapper import com.google.common.truth.Truth.assertThat import java.nio.file.Files import org.junit.Before Loading Loading @@ -88,8 +91,9 @@ class SupervisionServiceTest { @Mock private lateinit var mockDpmInternal: DevicePolicyManagerInternal @Mock private lateinit var mockKeyguardManager: KeyguardManager @Mock private lateinit var mockPackageManager: PackageManager @Mock private lateinit var mockPackageManagerInternal: PackageManagerInternal @Mock private lateinit var mockUserManagerInternal: UserManagerInternal @Mock private lateinit var mockSupervisionListener: ISupervisionListener @Mock private lateinit var mockRoleManager: SupervisionService.RoleManagerWrapper private lateinit var context: Context private lateinit var lifecycle: SupervisionService.Lifecycle Loading @@ -98,7 +102,8 @@ class SupervisionServiceTest { @Before fun setUp() { context = InstrumentationRegistry.getInstrumentation().context context = SupervisionContextWrapper(context, mockKeyguardManager, mockPackageManager) context = SupervisionContextWrapper(context, mockKeyguardManager, mockPackageManager, mockRoleManager) LocalServices.removeServiceForTest(DevicePolicyManagerInternal::class.java) LocalServices.addService(DevicePolicyManagerInternal::class.java, mockDpmInternal) Loading @@ -106,6 +111,9 @@ class SupervisionServiceTest { LocalServices.removeServiceForTest(UserManagerInternal::class.java) LocalServices.addService(UserManagerInternal::class.java, mockUserManagerInternal) LocalServices.removeServiceForTest(PackageManagerInternal::class.java) LocalServices.addService(PackageManagerInternal::class.java, mockPackageManagerInternal) // Creating a temporary folder to enable access to SupervisionSettings. SupervisionSettings.getInstance() .changeDirForTesting(Files.createTempDirectory("tempSupervisionFolder").toFile()) Loading @@ -114,6 +122,7 @@ class SupervisionServiceTest { lifecycle = SupervisionService.Lifecycle(context, service) lifecycle.registerProfileOwnerListener() //TODO: b/427453821 Remove after converting SupervisionSettings from being a singleton. assertThat(service.isSupervisionEnabledForUser(USER_ID)).isFalse() } Loading Loading @@ -273,10 +282,18 @@ class SupervisionServiceTest { @Test @RequiresFlagsEnabled(Flags.FLAG_ENABLE_REMOVE_POLICIES_ON_SUPERVISION_DISABLE) fun setSupervisionEnabledForUser_removesPoliciesWhenDisabling() { for ((role, packageName) in supervisionRoleHolders) { whenever(mockRoleManager.getRoleHoldersAsUser(eq(role), any())) .thenReturn(listOf(packageName)); } service.setSupervisionEnabledForUser(USER_ID, false) assertThat(service.isSupervisionEnabledForUser(USER_ID)).isFalse() verify(mockDpmInternal).removePoliciesForAdmins(eq(systemSupervisionPackage), eq(USER_ID)) for (packageName in supervisionRoleHolders.values) { verify(mockPackageManagerInternal) .unsuspendForSuspendingPackage(eq(packageName), eq(USER_ID), eq(USER_ID)) } } @Test Loading Loading @@ -491,12 +508,16 @@ class SupervisionServiceTest { assertThat(service.mSupervisionListeners).doesNotContainKey(binder) } private fun setSupervisionEnabledForUser(expectedUserId: Int, enabled: Boolean, listeners: Map<Int, Pair<ISupervisionListener, IBinder>>) { private fun setSupervisionEnabledForUser( expectedUserId: Int, enabled: Boolean, listeners: Map<Int, Pair<ISupervisionListener, IBinder>>, ) { service.setSupervisionEnabledForUser(expectedUserId, enabled) listeners.forEach { userId, (listener, binder) -> when (userId) { expectedUserId, UserHandle.USER_ALL -> { expectedUserId, UserHandle.USER_ALL -> { verify(listener).onSetSupervisionEnabled(eq(expectedUserId), eq(enabled)) } else -> { Loading @@ -506,6 +527,34 @@ class SupervisionServiceTest { } } @Test @RequiresFlagsEnabled(Flags.FLAG_ENABLE_REMOVE_POLICIES_ON_SUPERVISION_DISABLE) fun clearPackageSuspensions_unsuspendsSupervisionPackages() { assertThat(service.isSupervisionEnabledForUser(USER_ID)).isFalse() for ((role, packageName) in supervisionRoleHolders) { whenever(mockRoleManager.getRoleHoldersAsUser(eq(role), any())) .thenReturn(listOf(packageName)); } service.setSupervisionEnabledForUser(USER_ID, false) assertThat(service.isSupervisionEnabledForUser(USER_ID)).isFalse() for (packageName in supervisionRoleHolders.values) { verify(mockPackageManagerInternal) .unsuspendForSuspendingPackage(eq(packageName), eq(USER_ID), eq(USER_ID)) } } @Test @RequiresFlagsEnabled(Flags.FLAG_ENABLE_REMOVE_POLICIES_ON_SUPERVISION_DISABLE) fun clearPackageSuspensions_noSupervisionPackages_doesNothing() { whenever(mockRoleManager.getRoleHoldersAsUser( any(), any())).thenReturn(listOf()) service.setSupervisionEnabledForUser(USER_ID, false) verify(mockPackageManagerInternal, never()).unsuspendForSuspendingPackage(any(), any(), any()) } private val systemSupervisionPackage: String get() = context.getResources().getString(R.string.config_systemSupervision) Loading Loading @@ -557,6 +606,10 @@ class SupervisionServiceTest { const val SUPERVISING_USER_ID = 10 const val USER_ICON = "user_icon" const val USER_TYPE = "fake_user_type" val supervisionRoleHolders = mapOf( RoleManager.ROLE_SYSTEM_SUPERVISION to "com.example.supervisionapp1", RoleManager.ROLE_SUPERVISION to "com.example.supervisionapp2" ) val userData: Map<Int, Int> = mapOf( USER_SYSTEM to FLAG_SYSTEM, Loading @@ -574,14 +627,18 @@ private class SupervisionContextWrapper( val context: Context, val keyguardManager: KeyguardManager, val pkgManager: PackageManager, val roleManagerWrapper: RoleManagerWrapper, ) : ContextWrapper(context) { val interceptors = mutableListOf<Pair<BroadcastReceiver, IntentFilter>>() override fun getSystemService(name: String): Any = when (name) { KEYGUARD_SERVICE -> keyguardManager override fun getSystemService(name: String): Any? { var ret = when (name) { Context.KEYGUARD_SERVICE -> keyguardManager Context.ROLE_SERVICE -> roleManagerWrapper else -> super.getSystemService(name) } return ret; } override fun getPackageManager() = pkgManager Loading