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

Commit 0916cee3 authored by Felipe Leme's avatar Felipe Leme
Browse files

Defined workflow to notify new users when the device is managed.

When a new user is added in a deviced managed by a device owner,
DPMS will broadcast a ACTION_SHOW_NEW_USER_DISCLAIMER, whose
implementations will be responsible to notify the (human) user that
the device is managed by a device owner.

Test: manual verification on automotive
Bug: 172691310
Bug: 175057848

Change-Id: I0063a28c5df226456da5c8abcd42d63b07dc4149
parent 27de08e0
Loading
Loading
Loading
Loading
+21 −0
Original line number Diff line number Diff line
@@ -2699,6 +2699,17 @@ public class DevicePolicyManager {
        return DebugUtils.constantToString(DevicePolicyManager.class, PREFIX_OPERATION, operation);
    }
    /** @hide */
    public void resetNewUserDisclaimer() {
        if (mService != null) {
            try {
                mService.resetNewUserDisclaimer();
            } catch (RemoteException e) {
                throw e.rethrowFromSystemServer();
            }
        }
    }
    /**
     * Return true if the given administrator component is currently active (enabled) in the system.
     *
@@ -5160,6 +5171,16 @@ public class DevicePolicyManager {
    public static final String ACTION_MANAGED_USER_CREATED =
            "android.app.action.MANAGED_USER_CREATED";
    /**
     * Broadcast action: notify system that a new (Android) user was added when the device is
     * managed by a device owner, so receivers can show the proper disclaimer to the (human) user.
     *
     * @hide
     */
    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
    public static final String ACTION_SHOW_NEW_USER_DISCLAIMER =
            "android.app.action.ACTION_SHOW_NEW_USER_DISCLAIMER";
    /**
     * Widgets are enabled in keyguard
     */
+1 −0
Original line number Diff line number Diff line
@@ -252,6 +252,7 @@ interface IDevicePolicyManager {
    int stopUser(in ComponentName who, in UserHandle userHandle);
    int logoutUser(in ComponentName who);
    List<UserHandle> getSecondaryUsers(in ComponentName who);
    void resetNewUserDisclaimer();

    void enableSystemApp(in ComponentName admin, in String callerPackage, in String packageName);
    int enableSystemAppWithIntent(in ComponentName admin, in String callerPackage, in Intent intent);
+6 −0
Original line number Diff line number Diff line
@@ -53,6 +53,12 @@ abstract class BaseIDevicePolicyManager extends IDevicePolicyManager.Stub {
     * @see {@link SystemService#onUserUnlocking}
     */
    abstract void handleUnlockUser(int userId);
    /**
     * To be called by {@link DevicePolicyManagerService#Lifecycle} after a user is being unlocked.
     *
     * @see {@link SystemService#onUserUnlocked}
     */
    abstract void handleOnUserUnlocked(int userId);
    /**
     * To be called by {@link DevicePolicyManagerService#Lifecycle} when a user is being stopped.
     *
+15 −0
Original line number Diff line number Diff line
@@ -78,6 +78,12 @@ class DevicePolicyData {
    private static final String ATTR_DEVICE_PROVISIONING_CONFIG_APPLIED =
            "device-provisioning-config-applied";
    private static final String ATTR_DEVICE_PAIRED = "device-paired";
    private static final String ATTR_NEW_USER_DISCLAIMER = "new-user-disclaimer";

    // Values of ATTR_NEW_USER_DISCLAIMER
    static final String NEW_USER_DISCLAIMER_SHOWN = "shown";
    static final String NEW_USER_DISCLAIMER_NOT_NEEDED = "not_needed";
    static final String NEW_USER_DISCLAIMER_NEEDED = "needed";

    private static final String TAG = DevicePolicyManagerService.LOG_TAG;
    private static final boolean VERBOSE_LOG = false; // DO NOT SUBMIT WITH TRUE
@@ -146,6 +152,10 @@ class DevicePolicyData {
    // apps were suspended or unsuspended.
    boolean mAppsSuspended = false;

    // Whether it's necessary to show a disclaimer (that the device is managed) after the user
    // starts.
    String mNewUserDisclaimer = NEW_USER_DISCLAIMER_NOT_NEEDED;

    DevicePolicyData(@UserIdInt int userId) {
        mUserId = userId;
    }
@@ -186,6 +196,9 @@ class DevicePolicyData {
            if (policyData.mPermissionPolicy != DevicePolicyManager.PERMISSION_POLICY_PROMPT) {
                out.attributeInt(null, ATTR_PERMISSION_POLICY, policyData.mPermissionPolicy);
            }
            if (NEW_USER_DISCLAIMER_NEEDED.equals(policyData.mNewUserDisclaimer)) {
                out.attribute(null, ATTR_NEW_USER_DISCLAIMER, policyData.mNewUserDisclaimer);
            }

            // Serialize delegations.
            for (int i = 0; i < policyData.mDelegationMap.size(); ++i) {
@@ -412,6 +425,7 @@ class DevicePolicyData {
            if (permissionPolicy != -1) {
                policy.mPermissionPolicy = permissionPolicy;
            }
            policy.mNewUserDisclaimer = parser.getAttributeValue(null, ATTR_NEW_USER_DISCLAIMER);

            int outerDepth = parser.getDepth();
            policy.mLockTaskPackages.clear();
@@ -588,6 +602,7 @@ class DevicePolicyData {
        pw.print("mAppsSuspended="); pw.println(mAppsSuspended);
        pw.print("mUserSetupComplete="); pw.println(mUserSetupComplete);
        pw.print("mAffiliationIds="); pw.println(mAffiliationIds);
        pw.print("mNewUserDisclaimer="); pw.println(mNewUserDisclaimer);
        pw.decreaseIndent();
    }
}
+73 −4
Original line number Diff line number Diff line
@@ -707,6 +707,11 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
        public void onUserStopping(@NonNull TargetUser user) {
            mService.handleStopUser(user.getUserIdentifier());
        }
        @Override
        public void onUserUnlocked(@NonNull TargetUser user) {
            mService.handleOnUserUnlocked(user.getUserIdentifier());
        }
    }
    @GuardedBy("getLockObject()")
@@ -885,6 +890,14 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
        }
    }
    private final class UserLifecycleListener implements UserManagerInternal.UserLifecycleListener {
        @Override
        public void onUserCreated(UserInfo user) {
            mHandler.post(() -> handleNewUserCreated(user));
        }
    }
    private void handlePackagesChanged(@Nullable String packageName, int userHandle) {
        boolean removedAdmin = false;
        if (VERBOSE_LOG) {
@@ -1542,6 +1555,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
        mSetupContentObserver = new SetupContentObserver(mHandler);
        mUserManagerInternal.addUserRestrictionsListener(new RestrictionsListener(mContext));
        mUserManagerInternal.addUserLifecycleListener(new UserLifecycleListener());
        loadOwners();
    }
@@ -2882,6 +2896,11 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
        startOwnerService(userId, "unlock-user");
    }
    @Override
    void handleOnUserUnlocked(int userId) {
        showNewUserDisclaimerIfNecessary(userId);
    }
    @Override
    void handleStopUser(int userId) {
        stopOwnerService(userId, "stop-user");
@@ -7641,8 +7660,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
                // Sets profile owner on current foreground user since
                // the human user will complete the DO setup workflow from there.
                manageUserUnchecked(/* deviceOwner= */ admin, /* profileOwner= */ admin,
                            /* managedUser= */ currentForegroundUser,
                            /* adminExtras= */ null);
                        /* managedUser= */ currentForegroundUser, /* adminExtras= */ null,
                        /* showDisclaimer= */ false);
            }
            return true;
        }
@@ -9691,7 +9710,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
        final long id = mInjector.binderClearCallingIdentity();
        try {
            manageUserUnchecked(admin, profileOwner, userHandle, adminExtras);
            manageUserUnchecked(admin, profileOwner, userHandle, adminExtras,
                    /* showDisclaimer= */ true);
            if ((flags & DevicePolicyManager.SKIP_SETUP_WIZARD) != 0) {
                Settings.Secure.putIntForUser(mContext.getContentResolver(),
@@ -9713,7 +9733,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
    }
    private void manageUserUnchecked(ComponentName admin, ComponentName profileOwner,
            @UserIdInt int userId, PersistableBundle adminExtras) {
            @UserIdInt int userId, PersistableBundle adminExtras, boolean showDisclaimer) {
        final String adminPkg = admin.getPackageName();
        try {
            // Install the profile owner if not present.
@@ -9738,11 +9758,60 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
            DevicePolicyData policyData = getUserData(userId);
            policyData.mInitBundle = adminExtras;
            policyData.mAdminBroadcastPending = true;
            policyData.mNewUserDisclaimer = showDisclaimer
                    ? DevicePolicyData.NEW_USER_DISCLAIMER_NEEDED
                    : DevicePolicyData.NEW_USER_DISCLAIMER_NOT_NEEDED;
            saveSettingsLocked(userId);
        }
    }
    private void handleNewUserCreated(UserInfo user) {
        if (!mOwners.hasDeviceOwner()) return;
        final int userId = user.id;
        Log.i(LOG_TAG, "User " + userId + " added on DO mode; setting ShowNewUserDisclaimer");
        setShowNewUserDisclaimer(userId, DevicePolicyData.NEW_USER_DISCLAIMER_NEEDED);
    }
    @Override
    public void resetNewUserDisclaimer() {
        CallerIdentity callerIdentity = getCallerIdentity();
        canManageUsers(callerIdentity);
        setShowNewUserDisclaimer(callerIdentity.getUserId(),
                DevicePolicyData.NEW_USER_DISCLAIMER_SHOWN);
    }
    private void setShowNewUserDisclaimer(@UserIdInt int userId, String value) {
        Slog.i(LOG_TAG, "Setting new user disclaimer for user " + userId + " as " + value);
        synchronized (getLockObject()) {
            DevicePolicyData policyData = getUserData(userId);
            policyData.mNewUserDisclaimer = value;
            saveSettingsLocked(userId);
        }
    }
    private void showNewUserDisclaimerIfNecessary(@UserIdInt int userId) {
        boolean mustShow;
        synchronized (getLockObject()) {
            DevicePolicyData policyData = getUserData(userId);
            if (VERBOSE_LOG) {
                Slog.v(LOG_TAG, "showNewUserDisclaimerIfNecessary(" + userId + "): "
                        + policyData.mNewUserDisclaimer + ")");
            }
            mustShow = DevicePolicyData.NEW_USER_DISCLAIMER_NEEDED
                    .equals(policyData.mNewUserDisclaimer);
        }
        if (!mustShow) return;
        Intent intent = new Intent(DevicePolicyManager.ACTION_SHOW_NEW_USER_DISCLAIMER);
        // TODO(b/172691310): add CTS tests to make sure disclaimer is shown
        Slog.i(LOG_TAG, "Dispatching ACTION_SHOW_NEW_USER_DISCLAIMER intent");
        mContext.sendBroadcastAsUser(intent, UserHandle.of(userId));
    }
    @Override
    public boolean removeUser(ComponentName who, UserHandle userHandle) {
        Objects.requireNonNull(who, "ComponentName is null");