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

Commit c9892805 authored by Sarp Misoglu's avatar Sarp Misoglu
Browse files

Update the default backup user after onUserUnlocking if necessary

On the first ever boot of a HSUM device, UserManager will create the main user after BackupManagerService is created. If that happens the default user will stay as 0 until the device is rebooted. To prevent this we need to update the default user as soon as it's guaranteed that the main user is created (if one is to be created), which is when the first user unlocks.

Bug: 266098768
Test: atest BackupManagerServiceTest
  atest BackupFrameworksServicesRoboTests
  manually by doing a factory reset and then checking backup is active for the main user via `adb shell bmgr --user 10 activate`
Change-Id: Ic14e7357b468c27d206a57f9e7148d918f747c1d
parent 15ea9319
Loading
Loading
Loading
Loading
+59 −21
Original line number Diff line number Diff line
@@ -158,19 +158,19 @@ public class BackupManagerService extends IBackupManager.Stub {
    /**
     * The user that the backup is activated by default for.
     *
     * If there is a {@link UserManager#getMainUser()}, this will be that user. If not, it will be
     * {@link UserHandle#USER_SYSTEM}.
     * <p>If there is a {@link UserManager#getMainUser()}, this will be that user. If not, it will
     * be {@link UserHandle#USER_SYSTEM}.
     *
     * <p>Note: on the first ever boot of a new device, this might change once the first user is
     * unlocked. See {@link #updateDefaultBackupUserIdIfNeeded()}.
     *
     * @see #isBackupActivatedForUser(int)
     */
    @UserIdInt private final int mDefaultBackupUserId;
    @UserIdInt private int mDefaultBackupUserId;

    public BackupManagerService(Context context) {
        this(context, new SparseArray<>());
    }
    private boolean mHasFirstUserUnlockedSinceBoot = false;

    @VisibleForTesting
    BackupManagerService(Context context, SparseArray<UserBackupManagerService> userServices) {
    public BackupManagerService(Context context) {
        mContext = context;
        mGlobalDisable = isBackupDisabled();
        HandlerThread handlerThread =
@@ -178,7 +178,7 @@ public class BackupManagerService extends IBackupManager.Stub {
        handlerThread.start();
        mHandler = new Handler(handlerThread.getLooper());
        mUserManager = UserManager.get(context);
        mUserServices = userServices;
        mUserServices = new SparseArray<>();
        Set<ComponentName> transportWhitelist =
                SystemConfig.getInstance().getBackupTransportWhitelist();
        mTransportWhitelist = (transportWhitelist == null) ? emptySet() : transportWhitelist;
@@ -186,6 +186,9 @@ public class BackupManagerService extends IBackupManager.Stub {
                mUserRemovedReceiver, new IntentFilter(Intent.ACTION_USER_REMOVED));
        UserHandle mainUser = getUserManager().getMainUser();
        mDefaultBackupUserId = mainUser == null ? UserHandle.USER_SYSTEM : mainUser.getIdentifier();
        if (DEBUG) {
            Slog.d(TAG, "Default backup user id = " + mDefaultBackupUserId);
        }
    }

    // TODO: Remove this when we implement DI by injecting in the construtor.
@@ -360,17 +363,6 @@ public class BackupManagerService extends IBackupManager.Stub {
        mHandler.post(runnable);
    }

    /**
     * Called from {@link BackupManagerService.Lifecycle} when a user {@code userId} is unlocked.
     * Starts the backup service for this user if backup is active for this user. Offloads work onto
     * the handler thread {@link #mHandlerThread} to keep unlock time low since backup is not
     * essential for device functioning.
     */
    @VisibleForTesting
    void onUnlockUser(int userId) {
        postToHandler(() -> startServiceForUser(userId));
    }

    /**
     * Starts the backup service for user {@code userId} by creating a new instance of {@link
     * UserBackupManagerService} and registering it with this service.
@@ -1687,7 +1679,15 @@ public class BackupManagerService extends IBackupManager.Stub {

        @Override
        public void onUserUnlocking(@NonNull TargetUser user) {
            sInstance.onUnlockUser(user.getUserIdentifier());
            // Starts the backup service for this user if backup is active for this user. Offloads
            // work onto the handler thread {@link #mHandlerThread} to keep unlock time low since
            // backup is not essential for device functioning.
            sInstance.postToHandler(
                    () -> {
                        sInstance.updateDefaultBackupUserIdIfNeeded();
                        sInstance.startServiceForUser(user.getUserIdentifier());
                        sInstance.mHasFirstUserUnlockedSinceBoot = true;
                    });
        }

        @Override
@@ -1700,4 +1700,42 @@ public class BackupManagerService extends IBackupManager.Stub {
            publishBinderService(name, service);
        }
    }

    /**
     * On the first ever boot of a new device, the 'main' user might not exist for a short period of
     * time and be created after {@link BackupManagerService} is created. In this case the {@link
     * #mDefaultBackupUserId} will be the system user initially, but we need to change it to the
     * newly created {@link UserManager#getMainUser()} later.
     *
     * <p>{@link Lifecycle#onUserUnlocking(SystemService.TargetUser)} (for any user) is the earliest
     * point where we know that a main user (if there is going to be one) is created.
     */
    private void updateDefaultBackupUserIdIfNeeded() {
        // The default user can only change before any user unlocks since boot, and it will only
        // change from the system user to a non-system user.
        if (mHasFirstUserUnlockedSinceBoot || mDefaultBackupUserId != UserHandle.USER_SYSTEM) {
            return;
        }

        UserHandle mainUser = getUserManager().getMainUser();
        if (mainUser == null) {
            return;
        }

        if (mDefaultBackupUserId != mainUser.getIdentifier()) {
            int oldDefaultBackupUserId = mDefaultBackupUserId;
            mDefaultBackupUserId = mainUser.getIdentifier();
            // We don't expect the service to be started for the old default user but we attempt to
            // stop its service to be safe.
            if (!isBackupActivatedForUser(oldDefaultBackupUserId)) {
                stopServiceForUser(oldDefaultBackupUserId);
            }
            Slog.i(
                    TAG,
                    "Default backup user changed from "
                            + oldDefaultBackupUserId
                            + " to "
                            + mDefaultBackupUserId);
        }
    }
}
+1 −17
Original line number Diff line number Diff line
@@ -1584,11 +1584,7 @@ public class BackupManagerServiceRoboTest {
    @Test
    public void testConstructor_withNullContext_throws() throws Exception {
        expectThrows(
                NullPointerException.class,
                () ->
                        new BackupManagerService(
                                /* context */ null,
                                new SparseArray<>()));
                NullPointerException.class, () -> new BackupManagerService(/* context */ null));
    }

    /** Test that the constructor does not create {@link UserBackupManagerService} instances. */
@@ -1616,18 +1612,6 @@ public class BackupManagerServiceRoboTest {
        verify(lifecycle).publishService(Context.BACKUP_SERVICE, backupManagerService);
    }

    /** testOnUnlockUser_forwards */
    @Test
    public void testOnUnlockUser_forwards() {
        BackupManagerService backupManagerService = mock(BackupManagerService.class);
        BackupManagerService.Lifecycle lifecycle =
                new BackupManagerService.Lifecycle(mContext, backupManagerService);

        lifecycle.onUserUnlocking(new TargetUser(new UserInfo(UserHandle.USER_SYSTEM, null, 0)));

        verify(backupManagerService).onUnlockUser(UserHandle.USER_SYSTEM);
    }

    /** testOnStopUser_forwards */
    @Test
    public void testOnStopUser_forwards() {
+122 −36

File changed.

Preview size limit exceeded, changes collapsed.