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

Commit de639f33 authored by Satoshi Niwa's avatar Satoshi Niwa
Browse files

Enable backup activation for all users in HSUM via flag

This change introduces a mechanism to enable backup and restore
functionality for all users in Headless System User Mode (HSUM)
using a new aconfig flag, without requiring individual activation files.

Flag: android.multiuser.backup_activated_for_all_users
Bug: 374830726
Bug: 406114361
Test: BackupManagerServiceTest
Change-Id: I2576dfee0d48035a2578f9c840dae63df08b98ca
parent 29c44684
Loading
Loading
Loading
Loading
+8 −0
Original line number Diff line number Diff line
@@ -480,3 +480,11 @@ flag {
     description: "Generate file for perfetto, so it can create a users table"
     bug: "391110239"
}

flag {
    name: "backup_activated_for_all_users"
    namespace: "multiuser"
    description: "Activate backup for all users in headless system user mode (HSUM)."
    bug: "374830726"
    is_fixed_read_only: true
}
+13 −6
Original line number Diff line number Diff line
@@ -348,25 +348,32 @@ public class BackupManagerService extends IBackupManager.Stub implements BackupM
        return getActivatedFileForUser(userId).exists();
    }

    /** Returns whether the user's backup is initially set to active. */
    /** Determines the default activation state for backup for the specified user ID. */
    @SuppressWarnings("AndroidFrameworkRequiresPermission")
    private boolean isDefaultBackupActiveUser(@UserIdInt int userId) {
        // In non-HSUM, the system user is the primary user and handles backup.
        if (!UserManager.isHeadlessSystemUserMode()) {
            return userId == UserHandle.USER_SYSTEM;
        }

        // In HSUM, the system user is not a real user and should not have backup activated.
        // In HSUM, returns false for the system user, as it's a headless/non-interactive user.
        if (userId == UserHandle.USER_SYSTEM) {
            return false;
        }

        UserHandle mainUser = getUserManager().getMainUser();
        if (mainUser == null) {
        // Returns false if the user is not a full user.
        if (!getUserManager().getUserInfo(userId).isFull()) {
            return false;
        }

        // In HSUM, the main user is the one whose backup should be active by default.
        return userId == mainUser.getIdentifier();
        // Returns true for the main user.
        UserHandle mainUser = getUserManager().getMainUser();
        if (mainUser != null && userId == mainUser.getIdentifier()) {
            return true;
        }

        // Returns true for any other full users if the flag is enabled.
        return android.multiuser.Flags.backupActivatedForAllUsers();
    }

    @VisibleForTesting
+66 −12
Original line number Diff line number Diff line
@@ -52,7 +52,10 @@ import android.os.Process;
import android.os.RemoteException;
import android.os.UserHandle;
import android.os.UserManager;
import android.platform.test.annotations.DisableFlags;
import android.platform.test.annotations.EnableFlags;
import android.platform.test.annotations.Presubmit;
import android.platform.test.flag.junit.SetFlagsRule;

import androidx.test.InstrumentationRegistry;
import androidx.test.ext.junit.runners.AndroidJUnit4;
@@ -64,9 +67,12 @@ import com.android.server.LocalServices;
import com.android.server.SystemService;
import com.android.server.backup.utils.RandomAccessFileUtils;

import com.google.common.truth.Expect;

import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InOrder;
@@ -88,6 +94,13 @@ public class BackupManagerServiceTest {
    private static final ComponentName TRANSPORT_COMPONENT_NAME = new ComponentName("package",
            "class");
    private static final int NON_SYSTEM_USER = UserHandle.USER_SYSTEM + 1;
    private static final int NON_SYSTEM_NON_DEFAULT_USER = NON_SYSTEM_USER + 1;

    @Rule public final Expect expect = Expect.create();

    @Rule
    public final SetFlagsRule flags =
            new SetFlagsRule(SetFlagsRule.DefaultInitValueType.DEVICE_DEFAULT);

    @Mock
    private UserBackupManagerService mSystemUserBackupManagerService;
@@ -131,6 +144,8 @@ public class BackupManagerServiceTest {
        when(mNonSystemUserBackupManagerService.getUserId()).thenReturn(NON_SYSTEM_USER);
        when(mUserManagerMock.getUserInfo(UserHandle.USER_SYSTEM)).thenReturn(mUserInfoMock);
        when(mUserManagerMock.getUserInfo(NON_SYSTEM_USER)).thenReturn(mUserInfoMock);
        when(mUserManagerMock.getUserInfo(NON_SYSTEM_NON_DEFAULT_USER)).thenReturn(mUserInfoMock);
        when(mUserInfoMock.isFull()).thenReturn(true);
        // Null main user means there is no main user on the device.
        when(mUserManagerMock.getMainUser()).thenReturn(null);

@@ -255,6 +270,45 @@ public class BackupManagerServiceTest {
        assertTrue(mService.isBackupServiceActive(NON_SYSTEM_USER));
    }

    @Test
    @DisableFlags(android.multiuser.Flags.FLAG_BACKUP_ACTIVATED_FOR_ALL_USERS)
    public void isBackupServiceActive_nonSystemUser_isNotDefault_flagDisabled_returnsFalse() {
        createBackupManagerServiceAndUnlockSystemUser();

        when(mUserInfoMock.isFull()).thenReturn(true);
        setMockMainUserAndCreateBackupManagerService(NON_SYSTEM_USER);

        // In HSUM, activation for non-default users is determined by the flag above (disabled).
        expect.that(mService.isBackupServiceActive(NON_SYSTEM_USER)).isTrue();
        expect.that(mService.isBackupServiceActive(NON_SYSTEM_NON_DEFAULT_USER)).isFalse();
    }

    @Test
    @EnableFlags(android.multiuser.Flags.FLAG_BACKUP_ACTIVATED_FOR_ALL_USERS)
    public void isBackupServiceActive_nonSystemUser_fullUser_flagEnabled_returnsTrue() {
        createBackupManagerServiceAndUnlockSystemUser();

        when(mUserInfoMock.isFull()).thenReturn(true);
        setMockMainUserAndCreateBackupManagerService(NON_SYSTEM_USER);

        // In HSUM, activation for non-default users is determined by the flag above (enabled).
        expect.that(mService.isBackupServiceActive(NON_SYSTEM_USER)).isTrue();
        expect.that(mService.isBackupServiceActive(NON_SYSTEM_NON_DEFAULT_USER)).isTrue();
    }

    @Test
    @EnableFlags(android.multiuser.Flags.FLAG_BACKUP_ACTIVATED_FOR_ALL_USERS)
    public void isBackupServiceActive_nonSystemUser_nonFullUser_flagEnabled_returnsFalse() {
        createBackupManagerServiceAndUnlockSystemUser();

        when(mUserInfoMock.isFull()).thenReturn(false);
        setMockMainUserAndCreateBackupManagerService(NON_SYSTEM_USER);

        // The flag is enabled but the users are not full users.
        expect.that(mService.isBackupServiceActive(NON_SYSTEM_USER)).isFalse();
        expect.that(mService.isBackupServiceActive(NON_SYSTEM_NON_DEFAULT_USER)).isFalse();
    }

    @Test
    public void isBackupServiceActive_nonSystemUser_isNotDefault_notActivated_returnsFalse() {
        createBackupManagerServiceAndUnlockSystemUser();
@@ -384,10 +438,10 @@ public class BackupManagerServiceTest {
    public void setBackupServiceActive_alreadyActive_ignored() {
        createBackupManagerServiceAndUnlockSystemUser();
        mService.setBackupServiceActive(UserHandle.USER_SYSTEM, true);
        assertTrue(mService.isBackupServiceActive(UserHandle.USER_SYSTEM));
        expect.that(mService.isBackupServiceActive(UserHandle.USER_SYSTEM)).isTrue();

        mService.setBackupServiceActive(UserHandle.USER_SYSTEM, true);
        assertTrue(mService.isBackupServiceActive(UserHandle.USER_SYSTEM));
        expect.that(mService.isBackupServiceActive(UserHandle.USER_SYSTEM)).isTrue();
    }

    @Test
@@ -411,11 +465,11 @@ public class BackupManagerServiceTest {
    @Test
    public void setBackupServiceActive_systemUser_makeNonActive_stopsUserService() {
        createBackupManagerServiceAndUnlockSystemUser();
        assertTrue(mService.isUserReadyForBackup(UserHandle.USER_SYSTEM));
        expect.that(mService.isUserReadyForBackup(UserHandle.USER_SYSTEM)).isTrue();

        mService.setBackupServiceActive(UserHandle.USER_SYSTEM, false);

        assertFalse(mService.isUserReadyForBackup(UserHandle.USER_SYSTEM));
        expect.that(mService.isUserReadyForBackup(UserHandle.USER_SYSTEM)).isFalse();
    }

    @Test
@@ -452,11 +506,11 @@ public class BackupManagerServiceTest {
    public void setBackupServiceActive_nonSystemUser_isDefault_makeNonActive_stopsUserService() {
        setMockMainUserAndCreateBackupManagerService(NON_SYSTEM_USER);
        simulateUserUnlocked(NON_SYSTEM_USER);
        assertTrue(mService.isUserReadyForBackup(NON_SYSTEM_USER));
        expect.that(mService.isUserReadyForBackup(NON_SYSTEM_USER)).isTrue();

        mService.setBackupServiceActive(NON_SYSTEM_USER, false);

        assertFalse(mService.isUserReadyForBackup(NON_SYSTEM_USER));
        expect.that(mService.isUserReadyForBackup(NON_SYSTEM_USER)).isFalse();
    }

    @Test
@@ -724,12 +778,12 @@ public class BackupManagerServiceTest {
        mService = new BackupManagerServiceTestable(mContextMock);
        createBackupServiceLifecycle(mContextMock, mService);
        when(mUserManagerMock.getMainUser()).thenReturn(UserHandle.of(NON_SYSTEM_USER));
        assertFalse(mService.isBackupServiceActive(NON_SYSTEM_USER));
        expect.that(mService.isBackupServiceActive(NON_SYSTEM_USER)).isFalse();

        mockHeadlessSystemUserMode(true);
        simulateUserUnlocked(UserHandle.USER_SYSTEM);

        assertTrue(mService.isBackupServiceActive(NON_SYSTEM_USER));
        expect.that(mService.isBackupServiceActive(NON_SYSTEM_USER)).isTrue();
    }

    @Test
@@ -739,12 +793,12 @@ public class BackupManagerServiceTest {
        mService = new BackupManagerServiceTestable(mContextMock);
        createBackupServiceLifecycle(mContextMock, mService);
        when(mUserManagerMock.getMainUser()).thenReturn(UserHandle.of(NON_SYSTEM_USER));
        assertFalse(mService.isBackupServiceActive(NON_SYSTEM_USER));
        expect.that(mService.isBackupServiceActive(NON_SYSTEM_USER)).isFalse();

        mockHeadlessSystemUserMode(true);
        simulateUserUnlocked(UserHandle.USER_SYSTEM);

        assertFalse(mService.isUserReadyForBackup(UserHandle.USER_SYSTEM));
        expect.that(mService.isUserReadyForBackup(UserHandle.USER_SYSTEM)).isFalse();
    }

    @Test
@@ -753,11 +807,11 @@ public class BackupManagerServiceTest {
        // BMS, which can happen for the first ever boot of a new device.
        createBackupManagerServiceAndUnlockSystemUser();
        when(mUserManagerMock.getMainUser()).thenReturn(UserHandle.of(NON_SYSTEM_USER));
        assertFalse(mService.isBackupServiceActive(NON_SYSTEM_USER));
        expect.that(mService.isBackupServiceActive(NON_SYSTEM_USER)).isFalse();

        simulateUserUnlocked(NON_SYSTEM_USER);

        assertFalse(mService.isBackupServiceActive(NON_SYSTEM_USER));
        expect.that(mService.isBackupServiceActive(NON_SYSTEM_USER)).isFalse();
    }

    private void createBackupManagerServiceAndUnlockSystemUser() {