Loading services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +50 −17 Original line number Original line Diff line number Diff line Loading @@ -22,6 +22,7 @@ import static android.Manifest.permission.REQUEST_PASSWORD_COMPLEXITY; import static android.accessibilityservice.AccessibilityServiceInfo.FEEDBACK_ALL_MASK; import static android.accessibilityservice.AccessibilityServiceInfo.FEEDBACK_ALL_MASK; import static android.app.ActivityManager.LOCK_TASK_MODE_NONE; import static android.app.ActivityManager.LOCK_TASK_MODE_NONE; import static android.app.admin.DeviceAdminReceiver.EXTRA_TRANSFER_OWNERSHIP_ADMIN_EXTRAS_BUNDLE; import static android.app.admin.DeviceAdminReceiver.EXTRA_TRANSFER_OWNERSHIP_ADMIN_EXTRAS_BUNDLE; import static android.app.admin.DevicePolicyManager.ACTION_CHECK_POLICY_COMPLIANCE; import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_USER; import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_USER; import static android.app.admin.DevicePolicyManager.CODE_ACCOUNTS_NOT_EMPTY; import static android.app.admin.DevicePolicyManager.CODE_ACCOUNTS_NOT_EMPTY; import static android.app.admin.DevicePolicyManager.CODE_CANNOT_ADD_MANAGED_PROFILE; import static android.app.admin.DevicePolicyManager.CODE_CANNOT_ADD_MANAGED_PROFILE; Loading Loading @@ -409,6 +410,12 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { private static final String ACTION_EXPIRED_PASSWORD_NOTIFICATION = private static final String ACTION_EXPIRED_PASSWORD_NOTIFICATION = "com.android.server.ACTION_EXPIRED_PASSWORD_NOTIFICATION"; "com.android.server.ACTION_EXPIRED_PASSWORD_NOTIFICATION"; /** Broadcast action invoked when the user taps a notification to turn the profile on. */ @VisibleForTesting static final String ACTION_TURN_PROFILE_ON_NOTIFICATION = "com.android.server.ACTION_TURN_PROFILE_ON_NOTIFICATION"; /** Broadcast action for tracking managed profile maximum time off. */ @VisibleForTesting @VisibleForTesting static final String ACTION_PROFILE_OFF_DEADLINE = static final String ACTION_PROFILE_OFF_DEADLINE = "com.android.server.ACTION_PROFILE_OFF_DEADLINE"; "com.android.server.ACTION_PROFILE_OFF_DEADLINE"; Loading Loading @@ -951,7 +958,10 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { } } if (isManagedProfile(userHandle)) { if (isManagedProfile(userHandle)) { Slog.d(LOG_TAG, "Managed profile became unlocked"); Slog.d(LOG_TAG, "Managed profile became unlocked"); updatePersonalAppsSuspension(userHandle, true /* unlocked */); if (updatePersonalAppsSuspension(userHandle, true /* unlocked */) == PERSONAL_APPS_SUSPENDED_PROFILE_TIMEOUT) { triggerPolicyComplianceCheck(userHandle); } } } } else if (Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(action)) { } else if (Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(action)) { handlePackagesChanged(null /* check all admins */, userHandle); handlePackagesChanged(null /* check all admins */, userHandle); Loading Loading @@ -982,6 +992,9 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { } else { } else { Slog.wtf(LOG_TAG, "Got deadline alarm for nonexistent profile"); Slog.wtf(LOG_TAG, "Got deadline alarm for nonexistent profile"); } } } else if (ACTION_TURN_PROFILE_ON_NOTIFICATION.equals(action)) { Slog.i(LOG_TAG, "requesting to turn on the profile: " + userHandle); mUserManager.requestQuietModeEnabled(false, UserHandle.of(userHandle)); } } } } Loading Loading @@ -2568,6 +2581,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { IntentFilter filter = new IntentFilter(); IntentFilter filter = new IntentFilter(); filter.addAction(Intent.ACTION_BOOT_COMPLETED); filter.addAction(Intent.ACTION_BOOT_COMPLETED); filter.addAction(ACTION_EXPIRED_PASSWORD_NOTIFICATION); filter.addAction(ACTION_EXPIRED_PASSWORD_NOTIFICATION); filter.addAction(ACTION_TURN_PROFILE_ON_NOTIFICATION); filter.addAction(ACTION_PROFILE_OFF_DEADLINE); filter.addAction(ACTION_PROFILE_OFF_DEADLINE); filter.addAction(Intent.ACTION_USER_ADDED); filter.addAction(Intent.ACTION_USER_ADDED); filter.addAction(Intent.ACTION_USER_REMOVED); filter.addAction(Intent.ACTION_USER_REMOVED); Loading Loading @@ -15950,14 +15964,29 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { .write(); .write(); } } /** Starts an activity to check policy compliance in the DPC. */ private void triggerPolicyComplianceCheck(int profileUserId) { final Intent intent = new Intent(ACTION_CHECK_POLICY_COMPLIANCE); synchronized (getLockObject()) { final ActiveAdmin profileOwner = getProfileOwnerAdminLocked(profileUserId); if (profileOwner == null) { Slog.wtf(LOG_TAG, "Profile owner not found for compliance check"); return; } intent.setPackage(profileOwner.info.getPackageName()); } mContext.startActivityAsUser(intent, UserHandle.of(profileUserId)); } /** /** * Checks whether personal apps should be suspended according to the policy and applies the * Checks whether personal apps should be suspended according to the policy and applies the * change if needed. * change if needed. * * * @param unlocked whether the profile is currently running unlocked. * @param unlocked whether the profile is currently running unlocked. */ */ private void updatePersonalAppsSuspension(int profileUserId, boolean unlocked) { private @PersonalAppsSuspensionReason int updatePersonalAppsSuspension( final boolean suspended; int profileUserId, boolean unlocked) { final boolean suspendedExplicitly; final int deadlineState; final int deadlineState; final String poPackage; final String poPackage; synchronized (getLockObject()) { synchronized (getLockObject()) { Loading @@ -15965,26 +15994,28 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { if (profileOwner != null) { if (profileOwner != null) { deadlineState = deadlineState = updateProfileOffDeadlineLocked(profileUserId, profileOwner, unlocked); updateProfileOffDeadlineLocked(profileUserId, profileOwner, unlocked); suspended = profileOwner.mSuspendPersonalApps suspendedExplicitly = profileOwner.mSuspendPersonalApps; || deadlineState == PROFILE_OFF_DEADLINE_REACHED; poPackage = profileOwner.info.getPackageName(); poPackage = profileOwner.info.getPackageName(); } else { } else { poPackage = null; poPackage = null; suspended = false; suspendedExplicitly = false; deadlineState = PROFILE_OFF_DEADLINE_DEFAULT; deadlineState = PROFILE_OFF_DEADLINE_DEFAULT; } } } } Slog.d(LOG_TAG, String.format("Personal apps suspended: %b, deadline state: %d", Slog.d(LOG_TAG, String.format("Personal apps suspended explicitly: %b, deadline state: %d", suspended, deadlineState)); suspendedExplicitly, deadlineState)); if (poPackage != null) { if (poPackage != null) { final int notificationState = unlocked ? PROFILE_OFF_DEADLINE_DEFAULT : deadlineState; final int notificationState = unlocked ? PROFILE_OFF_DEADLINE_DEFAULT : deadlineState; updateProfileOffDeadlineNotification(profileUserId, poPackage, notificationState); updateProfileOffDeadlineNotification(profileUserId, poPackage, notificationState); } } final boolean suspendedByTimeout = deadlineState == PROFILE_OFF_DEADLINE_REACHED; final int parentUserId = getProfileParentId(profileUserId); final int parentUserId = getProfileParentId(profileUserId); suspendPersonalAppsInternal(parentUserId, suspended); suspendPersonalAppsInternal(parentUserId, suspendedExplicitly || suspendedByTimeout); return makeSuspensionReasons(suspendedExplicitly, suspendedByTimeout); } } /** /** Loading Loading @@ -16044,8 +16075,10 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { } } final AlarmManager am = mInjector.getAlarmManager(); final AlarmManager am = mInjector.getAlarmManager(); final Intent intent = new Intent(ACTION_PROFILE_OFF_DEADLINE); intent.setPackage(mContext.getPackageName()); final PendingIntent pi = mInjector.pendingIntentGetBroadcast( final PendingIntent pi = mInjector.pendingIntentGetBroadcast( mContext, REQUEST_PROFILE_OFF_DEADLINE, new Intent(ACTION_PROFILE_OFF_DEADLINE), mContext, REQUEST_PROFILE_OFF_DEADLINE, intent, PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_UPDATE_CURRENT); PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_UPDATE_CURRENT); if (alarmTime == 0) { if (alarmTime == 0) { Loading Loading @@ -16094,23 +16127,23 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { return; return; } } final Intent intent = new Intent(DevicePolicyManager.ACTION_CHECK_POLICY_COMPLIANCE); final Intent intent = new Intent(ACTION_TURN_PROFILE_ON_NOTIFICATION); intent.setPackage(profileOwnerPackage); intent.setPackage(mContext.getPackageName()); intent.putExtra(Intent.EXTRA_USER_HANDLE, profileUserId); final PendingIntent pendingIntent = mInjector.pendingIntentGetActivityAsUser(mContext, final PendingIntent pendingIntent = mInjector.pendingIntentGetBroadcast(mContext, 0 /* requestCode */, intent, PendingIntent.FLAG_UPDATE_CURRENT, 0 /* requestCode */, intent, PendingIntent.FLAG_UPDATE_CURRENT); null /* options */, UserHandle.of(profileUserId)); // TODO(b/149075510): Only the first of the notifications should be dismissible. final String text = mContext.getString( final String text = mContext.getString( notificationState == PROFILE_OFF_DEADLINE_WARNING notificationState == PROFILE_OFF_DEADLINE_WARNING ? R.string.personal_apps_suspension_tomorrow_text ? R.string.personal_apps_suspension_tomorrow_text : R.string.personal_apps_suspension_text); : R.string.personal_apps_suspension_text); final boolean ongoing = notificationState == PROFILE_OFF_DEADLINE_REACHED; final Notification notification = final Notification notification = new Notification.Builder(mContext, SystemNotificationChannels.DEVICE_ADMIN) new Notification.Builder(mContext, SystemNotificationChannels.DEVICE_ADMIN) .setSmallIcon(android.R.drawable.stat_sys_warning) .setSmallIcon(android.R.drawable.stat_sys_warning) .setOngoing(true) .setOngoing(ongoing) .setContentTitle(mContext.getString( .setContentTitle(mContext.getString( R.string.personal_apps_suspension_title)) R.string.personal_apps_suspension_title)) .setContentText(text) .setContentText(text) services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java +263 −291 File changed.Preview size limit exceeded, changes collapsed. Show changes services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java +5 −0 Original line number Original line Diff line number Diff line Loading @@ -482,4 +482,9 @@ public class DpmMockContext extends MockContext { public int checkCallingPermission(String permission) { public int checkCallingPermission(String permission) { return spiedContext.checkCallingPermission(permission); return spiedContext.checkCallingPermission(permission); } } @Override public void startActivityAsUser(Intent intent, UserHandle userHandle) { spiedContext.startActivityAsUser(intent, userHandle); } } } Loading
services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +50 −17 Original line number Original line Diff line number Diff line Loading @@ -22,6 +22,7 @@ import static android.Manifest.permission.REQUEST_PASSWORD_COMPLEXITY; import static android.accessibilityservice.AccessibilityServiceInfo.FEEDBACK_ALL_MASK; import static android.accessibilityservice.AccessibilityServiceInfo.FEEDBACK_ALL_MASK; import static android.app.ActivityManager.LOCK_TASK_MODE_NONE; import static android.app.ActivityManager.LOCK_TASK_MODE_NONE; import static android.app.admin.DeviceAdminReceiver.EXTRA_TRANSFER_OWNERSHIP_ADMIN_EXTRAS_BUNDLE; import static android.app.admin.DeviceAdminReceiver.EXTRA_TRANSFER_OWNERSHIP_ADMIN_EXTRAS_BUNDLE; import static android.app.admin.DevicePolicyManager.ACTION_CHECK_POLICY_COMPLIANCE; import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_USER; import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_USER; import static android.app.admin.DevicePolicyManager.CODE_ACCOUNTS_NOT_EMPTY; import static android.app.admin.DevicePolicyManager.CODE_ACCOUNTS_NOT_EMPTY; import static android.app.admin.DevicePolicyManager.CODE_CANNOT_ADD_MANAGED_PROFILE; import static android.app.admin.DevicePolicyManager.CODE_CANNOT_ADD_MANAGED_PROFILE; Loading Loading @@ -409,6 +410,12 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { private static final String ACTION_EXPIRED_PASSWORD_NOTIFICATION = private static final String ACTION_EXPIRED_PASSWORD_NOTIFICATION = "com.android.server.ACTION_EXPIRED_PASSWORD_NOTIFICATION"; "com.android.server.ACTION_EXPIRED_PASSWORD_NOTIFICATION"; /** Broadcast action invoked when the user taps a notification to turn the profile on. */ @VisibleForTesting static final String ACTION_TURN_PROFILE_ON_NOTIFICATION = "com.android.server.ACTION_TURN_PROFILE_ON_NOTIFICATION"; /** Broadcast action for tracking managed profile maximum time off. */ @VisibleForTesting @VisibleForTesting static final String ACTION_PROFILE_OFF_DEADLINE = static final String ACTION_PROFILE_OFF_DEADLINE = "com.android.server.ACTION_PROFILE_OFF_DEADLINE"; "com.android.server.ACTION_PROFILE_OFF_DEADLINE"; Loading Loading @@ -951,7 +958,10 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { } } if (isManagedProfile(userHandle)) { if (isManagedProfile(userHandle)) { Slog.d(LOG_TAG, "Managed profile became unlocked"); Slog.d(LOG_TAG, "Managed profile became unlocked"); updatePersonalAppsSuspension(userHandle, true /* unlocked */); if (updatePersonalAppsSuspension(userHandle, true /* unlocked */) == PERSONAL_APPS_SUSPENDED_PROFILE_TIMEOUT) { triggerPolicyComplianceCheck(userHandle); } } } } else if (Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(action)) { } else if (Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(action)) { handlePackagesChanged(null /* check all admins */, userHandle); handlePackagesChanged(null /* check all admins */, userHandle); Loading Loading @@ -982,6 +992,9 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { } else { } else { Slog.wtf(LOG_TAG, "Got deadline alarm for nonexistent profile"); Slog.wtf(LOG_TAG, "Got deadline alarm for nonexistent profile"); } } } else if (ACTION_TURN_PROFILE_ON_NOTIFICATION.equals(action)) { Slog.i(LOG_TAG, "requesting to turn on the profile: " + userHandle); mUserManager.requestQuietModeEnabled(false, UserHandle.of(userHandle)); } } } } Loading Loading @@ -2568,6 +2581,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { IntentFilter filter = new IntentFilter(); IntentFilter filter = new IntentFilter(); filter.addAction(Intent.ACTION_BOOT_COMPLETED); filter.addAction(Intent.ACTION_BOOT_COMPLETED); filter.addAction(ACTION_EXPIRED_PASSWORD_NOTIFICATION); filter.addAction(ACTION_EXPIRED_PASSWORD_NOTIFICATION); filter.addAction(ACTION_TURN_PROFILE_ON_NOTIFICATION); filter.addAction(ACTION_PROFILE_OFF_DEADLINE); filter.addAction(ACTION_PROFILE_OFF_DEADLINE); filter.addAction(Intent.ACTION_USER_ADDED); filter.addAction(Intent.ACTION_USER_ADDED); filter.addAction(Intent.ACTION_USER_REMOVED); filter.addAction(Intent.ACTION_USER_REMOVED); Loading Loading @@ -15950,14 +15964,29 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { .write(); .write(); } } /** Starts an activity to check policy compliance in the DPC. */ private void triggerPolicyComplianceCheck(int profileUserId) { final Intent intent = new Intent(ACTION_CHECK_POLICY_COMPLIANCE); synchronized (getLockObject()) { final ActiveAdmin profileOwner = getProfileOwnerAdminLocked(profileUserId); if (profileOwner == null) { Slog.wtf(LOG_TAG, "Profile owner not found for compliance check"); return; } intent.setPackage(profileOwner.info.getPackageName()); } mContext.startActivityAsUser(intent, UserHandle.of(profileUserId)); } /** /** * Checks whether personal apps should be suspended according to the policy and applies the * Checks whether personal apps should be suspended according to the policy and applies the * change if needed. * change if needed. * * * @param unlocked whether the profile is currently running unlocked. * @param unlocked whether the profile is currently running unlocked. */ */ private void updatePersonalAppsSuspension(int profileUserId, boolean unlocked) { private @PersonalAppsSuspensionReason int updatePersonalAppsSuspension( final boolean suspended; int profileUserId, boolean unlocked) { final boolean suspendedExplicitly; final int deadlineState; final int deadlineState; final String poPackage; final String poPackage; synchronized (getLockObject()) { synchronized (getLockObject()) { Loading @@ -15965,26 +15994,28 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { if (profileOwner != null) { if (profileOwner != null) { deadlineState = deadlineState = updateProfileOffDeadlineLocked(profileUserId, profileOwner, unlocked); updateProfileOffDeadlineLocked(profileUserId, profileOwner, unlocked); suspended = profileOwner.mSuspendPersonalApps suspendedExplicitly = profileOwner.mSuspendPersonalApps; || deadlineState == PROFILE_OFF_DEADLINE_REACHED; poPackage = profileOwner.info.getPackageName(); poPackage = profileOwner.info.getPackageName(); } else { } else { poPackage = null; poPackage = null; suspended = false; suspendedExplicitly = false; deadlineState = PROFILE_OFF_DEADLINE_DEFAULT; deadlineState = PROFILE_OFF_DEADLINE_DEFAULT; } } } } Slog.d(LOG_TAG, String.format("Personal apps suspended: %b, deadline state: %d", Slog.d(LOG_TAG, String.format("Personal apps suspended explicitly: %b, deadline state: %d", suspended, deadlineState)); suspendedExplicitly, deadlineState)); if (poPackage != null) { if (poPackage != null) { final int notificationState = unlocked ? PROFILE_OFF_DEADLINE_DEFAULT : deadlineState; final int notificationState = unlocked ? PROFILE_OFF_DEADLINE_DEFAULT : deadlineState; updateProfileOffDeadlineNotification(profileUserId, poPackage, notificationState); updateProfileOffDeadlineNotification(profileUserId, poPackage, notificationState); } } final boolean suspendedByTimeout = deadlineState == PROFILE_OFF_DEADLINE_REACHED; final int parentUserId = getProfileParentId(profileUserId); final int parentUserId = getProfileParentId(profileUserId); suspendPersonalAppsInternal(parentUserId, suspended); suspendPersonalAppsInternal(parentUserId, suspendedExplicitly || suspendedByTimeout); return makeSuspensionReasons(suspendedExplicitly, suspendedByTimeout); } } /** /** Loading Loading @@ -16044,8 +16075,10 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { } } final AlarmManager am = mInjector.getAlarmManager(); final AlarmManager am = mInjector.getAlarmManager(); final Intent intent = new Intent(ACTION_PROFILE_OFF_DEADLINE); intent.setPackage(mContext.getPackageName()); final PendingIntent pi = mInjector.pendingIntentGetBroadcast( final PendingIntent pi = mInjector.pendingIntentGetBroadcast( mContext, REQUEST_PROFILE_OFF_DEADLINE, new Intent(ACTION_PROFILE_OFF_DEADLINE), mContext, REQUEST_PROFILE_OFF_DEADLINE, intent, PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_UPDATE_CURRENT); PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_UPDATE_CURRENT); if (alarmTime == 0) { if (alarmTime == 0) { Loading Loading @@ -16094,23 +16127,23 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { return; return; } } final Intent intent = new Intent(DevicePolicyManager.ACTION_CHECK_POLICY_COMPLIANCE); final Intent intent = new Intent(ACTION_TURN_PROFILE_ON_NOTIFICATION); intent.setPackage(profileOwnerPackage); intent.setPackage(mContext.getPackageName()); intent.putExtra(Intent.EXTRA_USER_HANDLE, profileUserId); final PendingIntent pendingIntent = mInjector.pendingIntentGetActivityAsUser(mContext, final PendingIntent pendingIntent = mInjector.pendingIntentGetBroadcast(mContext, 0 /* requestCode */, intent, PendingIntent.FLAG_UPDATE_CURRENT, 0 /* requestCode */, intent, PendingIntent.FLAG_UPDATE_CURRENT); null /* options */, UserHandle.of(profileUserId)); // TODO(b/149075510): Only the first of the notifications should be dismissible. final String text = mContext.getString( final String text = mContext.getString( notificationState == PROFILE_OFF_DEADLINE_WARNING notificationState == PROFILE_OFF_DEADLINE_WARNING ? R.string.personal_apps_suspension_tomorrow_text ? R.string.personal_apps_suspension_tomorrow_text : R.string.personal_apps_suspension_text); : R.string.personal_apps_suspension_text); final boolean ongoing = notificationState == PROFILE_OFF_DEADLINE_REACHED; final Notification notification = final Notification notification = new Notification.Builder(mContext, SystemNotificationChannels.DEVICE_ADMIN) new Notification.Builder(mContext, SystemNotificationChannels.DEVICE_ADMIN) .setSmallIcon(android.R.drawable.stat_sys_warning) .setSmallIcon(android.R.drawable.stat_sys_warning) .setOngoing(true) .setOngoing(ongoing) .setContentTitle(mContext.getString( .setContentTitle(mContext.getString( R.string.personal_apps_suspension_title)) R.string.personal_apps_suspension_title)) .setContentText(text) .setContentText(text)
services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java +263 −291 File changed.Preview size limit exceeded, changes collapsed. Show changes
services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java +5 −0 Original line number Original line Diff line number Diff line Loading @@ -482,4 +482,9 @@ public class DpmMockContext extends MockContext { public int checkCallingPermission(String permission) { public int checkCallingPermission(String permission) { return spiedContext.checkCallingPermission(permission); return spiedContext.checkCallingPermission(permission); } } @Override public void startActivityAsUser(Intent intent, UserHandle userHandle) { spiedContext.startActivityAsUser(intent, userHandle); } } }