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

Commit a2630615 authored by Pavel Grafov's avatar Pavel Grafov
Browse files

Trigger policy check when profile turned on with apps suspended

Previously in case when the personal apps are suspended as a result
of work profile off timeout, ACTION_CHECK_POLICY_COMPLIANCE would
only be triggered if the user taps on the notificaiton. With this
change it is triggered also when the user uses any other way to
turn the profile on.

Instead of attempting to invoke policy compliance check, the
notification now turns the profile on. And once it is unlocked,
policy compliance check is triggered.

Also, made "apps suspended" notification non-dismissable.

Bug: 151439078
Bug: 149075510
Test: atest com.android.server.devicepolicy.DevicePolicyManagerTest
Change-Id: I84e5a13995af78992f22568a3a87e7d96af1a3be
parent 04ccfdfa
Loading
Loading
Loading
Loading
+50 −17
Original line number Diff line number Diff line
@@ -22,6 +22,7 @@ import static android.Manifest.permission.REQUEST_PASSWORD_COMPLEXITY;
import static android.accessibilityservice.AccessibilityServiceInfo.FEEDBACK_ALL_MASK;
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.DevicePolicyManager.ACTION_CHECK_POLICY_COMPLIANCE;
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_CANNOT_ADD_MANAGED_PROFILE;
@@ -409,6 +410,12 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
    private static final String 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
    static final String ACTION_PROFILE_OFF_DEADLINE =
            "com.android.server.ACTION_PROFILE_OFF_DEADLINE";
@@ -951,7 +958,10 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
                }
                if (isManagedProfile(userHandle)) {
                    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)) {
                handlePackagesChanged(null /* check all admins */, userHandle);
@@ -982,6 +992,9 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
                } else {
                    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));
            }
        }
@@ -2568,6 +2581,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
        IntentFilter filter = new IntentFilter();
        filter.addAction(Intent.ACTION_BOOT_COMPLETED);
        filter.addAction(ACTION_EXPIRED_PASSWORD_NOTIFICATION);
        filter.addAction(ACTION_TURN_PROFILE_ON_NOTIFICATION);
        filter.addAction(ACTION_PROFILE_OFF_DEADLINE);
        filter.addAction(Intent.ACTION_USER_ADDED);
        filter.addAction(Intent.ACTION_USER_REMOVED);
@@ -15940,14 +15954,29 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
                .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
     * change if needed.
     *
     * @param unlocked whether the profile is currently running unlocked.
     */
    private void updatePersonalAppsSuspension(int profileUserId, boolean unlocked) {
        final boolean suspended;
    private @PersonalAppsSuspensionReason int updatePersonalAppsSuspension(
            int profileUserId, boolean unlocked) {
        final boolean suspendedExplicitly;
        final int deadlineState;
        final String poPackage;
        synchronized (getLockObject()) {
@@ -15955,26 +15984,28 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
            if (profileOwner != null) {
                deadlineState =
                        updateProfileOffDeadlineLocked(profileUserId, profileOwner, unlocked);
                suspended = profileOwner.mSuspendPersonalApps
                        || deadlineState == PROFILE_OFF_DEADLINE_REACHED;
                suspendedExplicitly = profileOwner.mSuspendPersonalApps;
                poPackage = profileOwner.info.getPackageName();
            } else {
                poPackage = null;
                suspended = false;
                suspendedExplicitly = false;
                deadlineState = PROFILE_OFF_DEADLINE_DEFAULT;
            }
        }
        Slog.d(LOG_TAG, String.format("Personal apps suspended: %b, deadline state: %d",
                suspended, deadlineState));
        Slog.d(LOG_TAG, String.format("Personal apps suspended explicitly: %b, deadline state: %d",
                suspendedExplicitly, deadlineState));
        if (poPackage != null) {
            final int notificationState = unlocked ? PROFILE_OFF_DEADLINE_DEFAULT : deadlineState;
            updateProfileOffDeadlineNotification(profileUserId, poPackage, notificationState);
        }
        final boolean suspendedByTimeout = deadlineState == PROFILE_OFF_DEADLINE_REACHED;
        final int parentUserId = getProfileParentId(profileUserId);
        suspendPersonalAppsInternal(parentUserId, suspended);
        suspendPersonalAppsInternal(parentUserId, suspendedExplicitly || suspendedByTimeout);
        return makeSuspensionReasons(suspendedExplicitly, suspendedByTimeout);
    }
    /**
@@ -16034,8 +16065,10 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
        }
        final AlarmManager am = mInjector.getAlarmManager();
        final Intent intent = new Intent(ACTION_PROFILE_OFF_DEADLINE);
        intent.setPackage(mContext.getPackageName());
        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);
        if (alarmTime == 0) {
@@ -16084,23 +16117,23 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
            return;
        }
        final Intent intent = new Intent(DevicePolicyManager.ACTION_CHECK_POLICY_COMPLIANCE);
        intent.setPackage(profileOwnerPackage);
        final Intent intent = new Intent(ACTION_TURN_PROFILE_ON_NOTIFICATION);
        intent.setPackage(mContext.getPackageName());
        intent.putExtra(Intent.EXTRA_USER_HANDLE, profileUserId);
        final PendingIntent pendingIntent = mInjector.pendingIntentGetActivityAsUser(mContext,
                0 /* requestCode */, intent, PendingIntent.FLAG_UPDATE_CURRENT,
                null /* options */, UserHandle.of(profileUserId));
        final PendingIntent pendingIntent = mInjector.pendingIntentGetBroadcast(mContext,
                0 /* requestCode */, intent, PendingIntent.FLAG_UPDATE_CURRENT);
        // TODO(b/149075510): Only the first of the notifications should be dismissible.
        final String text = mContext.getString(
                notificationState == PROFILE_OFF_DEADLINE_WARNING
                ? R.string.personal_apps_suspension_tomorrow_text
                : R.string.personal_apps_suspension_text);
        final boolean ongoing = notificationState == PROFILE_OFF_DEADLINE_REACHED;
        final Notification notification =
                new Notification.Builder(mContext, SystemNotificationChannels.DEVICE_ADMIN)
                        .setSmallIcon(android.R.drawable.stat_sys_warning)
                        .setOngoing(true)
                        .setOngoing(ongoing)
                        .setContentTitle(mContext.getString(
                                R.string.personal_apps_suspension_title))
                        .setContentText(text)
+263 −291

File changed.

Preview size limit exceeded, changes collapsed.

+5 −0
Original line number Diff line number Diff line
@@ -482,4 +482,9 @@ public class DpmMockContext extends MockContext {
    public int checkCallingPermission(String permission) {
        return spiedContext.checkCallingPermission(permission);
    }

    @Override
    public void startActivityAsUser(Intent intent, UserHandle userHandle) {
        spiedContext.startActivityAsUser(intent, userHandle);
    }
}