Loading services/backup/java/com/android/server/backup/BackupManagerService.java +68 −25 Original line number Diff line number Diff line Loading @@ -500,9 +500,18 @@ public class BackupManagerService extends IBackupManager.Stub implements BackupM } /** * Sets the active state of the backup service for a given user. * * This method is the entry point for activating or deactivating the backup service. It * enforces the necessary permissions and then delegates to helper methods to handle the logic. * If the call is for the system user, it acts as a global toggle for all users. * * Only privileged callers should be changing the backup state. Deactivating backup in the * system user also deactivates backup in all users. We are not guaranteed that {@code userId} * is unlocked at this point yet, so handle both cases. * * @param userId The user for whom to change the backup service's state. * @param makeActive {@code true} to activate the service, {@code false} to deactivate it. */ public void setBackupServiceActive(@UserIdInt int userId, boolean makeActive) { enforceSetBackupServiceActiveAllowedForUser(userId); Loading Loading @@ -531,19 +540,26 @@ public class BackupManagerService extends IBackupManager.Stub implements BackupM } synchronized (mLock) { Slog.i(TAG, "Making backup " + (makeActive ? "" : "in") + "active"); Slog.i(TAG, "Making backup " + (makeActive ? "" : "in") + "active for user " + userId); if (makeActive) { handleBackupActivationLocked(userId); } else { handleBackupDeactivationLocked(userId); } } } @GuardedBy("mLock") private void handleBackupActivationLocked(@UserIdInt int userId) { try { activateBackupForUserLocked(userId); } catch (IOException e) { Slog.e(TAG, "Unable to persist backup service activity"); } // If the user is unlocked, we can start the backup service for it. Otherwise we // will start the service when the user is unlocked as part of its unlock callback. // Enabling for a single user. if (userId != UserHandle.USER_SYSTEM) { if (mUserManagerInternal.isUserUnlocked(userId)) { // Clear calling identity as initialization enforces the system identity but we // can be coming from shell. final long oldId = Binder.clearCallingIdentity(); try { startServiceForUser(userId); Loading @@ -551,17 +567,44 @@ public class BackupManagerService extends IBackupManager.Stub implements BackupM Binder.restoreCallingIdentity(oldId); } } } else { return; } // Globally enabling. Start services for all running users. final long oldId = Binder.clearCallingIdentity(); try { List<UserInfo> users = mUserManagerInternal.getUsers(/* excludeDying */ true); for (UserInfo user : users) { if (mUserManagerInternal.isUserRunning(user.id)) { startServiceForUser(user.id); } } } finally { Binder.restoreCallingIdentity(oldId); } } @GuardedBy("mLock") private void handleBackupDeactivationLocked(@UserIdInt int userId) { try { //TODO(b/121198006): what if this throws an exception? deactivateBackupForUserLocked(userId); } catch (IOException e) { Slog.e(TAG, "Unable to persist backup service inactivity"); } //TODO(b/121198006): loop through active users that have work profile and // stop them as well. // Disabling for a single user. if (userId != UserHandle.USER_SYSTEM) { onStopUser(userId); return; } // Globally disabling. Stop services for all running users. int[] userIdsToStop = new int[mUserServices.size()]; for (int i = 0; i < mUserServices.size(); i++) { userIdsToStop[i] = mUserServices.keyAt(i); } for (int userToStop : userIdsToStop) { onStopUser(userToStop); } } Loading services/tests/mockingservicestests/src/com/android/server/backup/BackupManagerServiceTest.java +26 −0 Original line number Diff line number Diff line Loading @@ -85,6 +85,7 @@ import java.io.File; import java.io.FileDescriptor; import java.io.PrintWriter; import java.io.Writer; import java.util.Arrays; import java.util.concurrent.CompletableFuture; import java.util.concurrent.TimeUnit; Loading Loading @@ -575,6 +576,31 @@ public class BackupManagerServiceTest { assertFalse(getFakeActivatedFileForUser(NON_SYSTEM_USER).exists()); } @Test public void setBackupServiceActive_globallyToggled_restartsUserService() { // Start with a non-system user's backup service running. createBackupManagerServiceAndUnlockSystemUser(); mService.setBackupServiceActive(NON_SYSTEM_USER, true); simulateUserUnlocked(NON_SYSTEM_USER); assertTrue(mService.isUserReadyForBackup(NON_SYSTEM_USER)); // Mock the running users for the global toggle. UserInfo systemUserInfo = new UserInfo(UserHandle.USER_SYSTEM, "system", 0); UserInfo nonSystemUserInfo = new UserInfo(NON_SYSTEM_USER, "non-system", 0); when(mUserManagerInternalMock.getUsers(true)) .thenReturn(Arrays.asList(systemUserInfo, nonSystemUserInfo)); when(mUserManagerInternalMock.isUserRunning(UserHandle.USER_SYSTEM)).thenReturn(true); when(mUserManagerInternalMock.isUserRunning(NON_SYSTEM_USER)).thenReturn(true); // Disable backup globally. This should stop the user's service. mService.setBackupServiceActive(UserHandle.USER_SYSTEM, false); assertFalse(mService.isUserReadyForBackup(NON_SYSTEM_USER)); // Re-enable backup globally. This should restart the user's service. mService.setBackupServiceActive(UserHandle.USER_SYSTEM, true); assertTrue(mService.isUserReadyForBackup(NON_SYSTEM_USER)); } @Test public void setBackupServiceActive_forOneNonSystemUser_doesNotActivateForAllNonSystemUsers() { createBackupManagerServiceAndUnlockSystemUser(); Loading Loading
services/backup/java/com/android/server/backup/BackupManagerService.java +68 −25 Original line number Diff line number Diff line Loading @@ -500,9 +500,18 @@ public class BackupManagerService extends IBackupManager.Stub implements BackupM } /** * Sets the active state of the backup service for a given user. * * This method is the entry point for activating or deactivating the backup service. It * enforces the necessary permissions and then delegates to helper methods to handle the logic. * If the call is for the system user, it acts as a global toggle for all users. * * Only privileged callers should be changing the backup state. Deactivating backup in the * system user also deactivates backup in all users. We are not guaranteed that {@code userId} * is unlocked at this point yet, so handle both cases. * * @param userId The user for whom to change the backup service's state. * @param makeActive {@code true} to activate the service, {@code false} to deactivate it. */ public void setBackupServiceActive(@UserIdInt int userId, boolean makeActive) { enforceSetBackupServiceActiveAllowedForUser(userId); Loading Loading @@ -531,19 +540,26 @@ public class BackupManagerService extends IBackupManager.Stub implements BackupM } synchronized (mLock) { Slog.i(TAG, "Making backup " + (makeActive ? "" : "in") + "active"); Slog.i(TAG, "Making backup " + (makeActive ? "" : "in") + "active for user " + userId); if (makeActive) { handleBackupActivationLocked(userId); } else { handleBackupDeactivationLocked(userId); } } } @GuardedBy("mLock") private void handleBackupActivationLocked(@UserIdInt int userId) { try { activateBackupForUserLocked(userId); } catch (IOException e) { Slog.e(TAG, "Unable to persist backup service activity"); } // If the user is unlocked, we can start the backup service for it. Otherwise we // will start the service when the user is unlocked as part of its unlock callback. // Enabling for a single user. if (userId != UserHandle.USER_SYSTEM) { if (mUserManagerInternal.isUserUnlocked(userId)) { // Clear calling identity as initialization enforces the system identity but we // can be coming from shell. final long oldId = Binder.clearCallingIdentity(); try { startServiceForUser(userId); Loading @@ -551,17 +567,44 @@ public class BackupManagerService extends IBackupManager.Stub implements BackupM Binder.restoreCallingIdentity(oldId); } } } else { return; } // Globally enabling. Start services for all running users. final long oldId = Binder.clearCallingIdentity(); try { List<UserInfo> users = mUserManagerInternal.getUsers(/* excludeDying */ true); for (UserInfo user : users) { if (mUserManagerInternal.isUserRunning(user.id)) { startServiceForUser(user.id); } } } finally { Binder.restoreCallingIdentity(oldId); } } @GuardedBy("mLock") private void handleBackupDeactivationLocked(@UserIdInt int userId) { try { //TODO(b/121198006): what if this throws an exception? deactivateBackupForUserLocked(userId); } catch (IOException e) { Slog.e(TAG, "Unable to persist backup service inactivity"); } //TODO(b/121198006): loop through active users that have work profile and // stop them as well. // Disabling for a single user. if (userId != UserHandle.USER_SYSTEM) { onStopUser(userId); return; } // Globally disabling. Stop services for all running users. int[] userIdsToStop = new int[mUserServices.size()]; for (int i = 0; i < mUserServices.size(); i++) { userIdsToStop[i] = mUserServices.keyAt(i); } for (int userToStop : userIdsToStop) { onStopUser(userToStop); } } Loading
services/tests/mockingservicestests/src/com/android/server/backup/BackupManagerServiceTest.java +26 −0 Original line number Diff line number Diff line Loading @@ -85,6 +85,7 @@ import java.io.File; import java.io.FileDescriptor; import java.io.PrintWriter; import java.io.Writer; import java.util.Arrays; import java.util.concurrent.CompletableFuture; import java.util.concurrent.TimeUnit; Loading Loading @@ -575,6 +576,31 @@ public class BackupManagerServiceTest { assertFalse(getFakeActivatedFileForUser(NON_SYSTEM_USER).exists()); } @Test public void setBackupServiceActive_globallyToggled_restartsUserService() { // Start with a non-system user's backup service running. createBackupManagerServiceAndUnlockSystemUser(); mService.setBackupServiceActive(NON_SYSTEM_USER, true); simulateUserUnlocked(NON_SYSTEM_USER); assertTrue(mService.isUserReadyForBackup(NON_SYSTEM_USER)); // Mock the running users for the global toggle. UserInfo systemUserInfo = new UserInfo(UserHandle.USER_SYSTEM, "system", 0); UserInfo nonSystemUserInfo = new UserInfo(NON_SYSTEM_USER, "non-system", 0); when(mUserManagerInternalMock.getUsers(true)) .thenReturn(Arrays.asList(systemUserInfo, nonSystemUserInfo)); when(mUserManagerInternalMock.isUserRunning(UserHandle.USER_SYSTEM)).thenReturn(true); when(mUserManagerInternalMock.isUserRunning(NON_SYSTEM_USER)).thenReturn(true); // Disable backup globally. This should stop the user's service. mService.setBackupServiceActive(UserHandle.USER_SYSTEM, false); assertFalse(mService.isUserReadyForBackup(NON_SYSTEM_USER)); // Re-enable backup globally. This should restart the user's service. mService.setBackupServiceActive(UserHandle.USER_SYSTEM, true); assertTrue(mService.isUserReadyForBackup(NON_SYSTEM_USER)); } @Test public void setBackupServiceActive_forOneNonSystemUser_doesNotActivateForAllNonSystemUsers() { createBackupManagerServiceAndUnlockSystemUser(); Loading