[Multi-User] Unregister stopped users in BMS
Adds a handler for system service callbacks when a user is stopped. This
currently only unregisters the user in bookkeeping but will be used in
the future for cleanup work such as cancelling scheduled jobs, etc.
Bug: 120212806
Test: 1) atest RunBackupFrameworksServicesRoboTests
2) atest TrampolineTest
3) Enable multi user + register user -> service started for user; stop
user -> user is unregistered
Change-Id: Ic712da646f961b9bb02c7d77d964a13345eca7ec
diff --git a/services/backup/java/com/android/server/backup/BackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java
index f702d0f..7049744 100644
--- a/services/backup/java/com/android/server/backup/BackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/BackupManagerService.java
@@ -124,6 +124,10 @@
}
}
+ // ---------------------------------------------
+ // USER LIFECYCLE CALLBACKS
+ // ---------------------------------------------
+
/**
* Starts the backup service for user {@code userId} by creating a new instance of {@link
* UserBackupManagerService} and registering it with this service.
@@ -153,6 +157,12 @@
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
}
+ /** Stops the backup service for user {@code userId} when the user is stopped. */
+ @VisibleForTesting
+ protected void stopServiceForUser(int userId) {
+ mServiceUsers.remove(userId);
+ }
+
SparseArray<UserBackupManagerService> getServiceUsers() {
return mServiceUsers;
}
@@ -820,5 +830,10 @@
}
sInstance.unlockUser(userId);
}
+
+ @Override
+ public void onStopUser(int userId) {
+ sInstance.stopUser(userId);
+ }
}
}
diff --git a/services/backup/java/com/android/server/backup/Trampoline.java b/services/backup/java/com/android/server/backup/Trampoline.java
index e295c53a..8eb5207 100644
--- a/services/backup/java/com/android/server/backup/Trampoline.java
+++ b/services/backup/java/com/android/server/backup/Trampoline.java
@@ -198,6 +198,26 @@
}
/**
+ * Called from {@link BackupManagerService.Lifecycle} when a user {@code userId} is stopped.
+ * Offloads work onto the handler thread {@link #mHandlerThread} to keep stopping time low.
+ */
+ void stopUser(int userId) {
+ if (userId != UserHandle.USER_SYSTEM && !isMultiUserEnabled()) {
+ Slog.i(TAG, "Multi-user disabled, cannot stop service for user: " + userId);
+ return;
+ }
+
+ postToHandler(
+ () -> {
+ BackupManagerService service = mService;
+ if (service != null) {
+ Slog.i(TAG, "Stopping service for user: " + userId);
+ service.stopServiceForUser(userId);
+ }
+ });
+ }
+
+ /**
* Only privileged callers should be changing the backup state. This method only acts on {@link
* UserHandle#USER_SYSTEM} and is a no-op if passed non-system users. Deactivating backup in the
* system user also deactivates backup in all users.
diff --git a/services/robotests/backup/src/com/android/server/backup/BackupManagerServiceTest.java b/services/robotests/backup/src/com/android/server/backup/BackupManagerServiceTest.java
index b253e0a..b8723c5 100644
--- a/services/robotests/backup/src/com/android/server/backup/BackupManagerServiceTest.java
+++ b/services/robotests/backup/src/com/android/server/backup/BackupManagerServiceTest.java
@@ -175,6 +175,32 @@
assertThat(serviceUsers.get(mUserOneId)).isEqualTo(mUserOneService);
}
+ /** Test that the service unregisters users when stopped. */
+ @Test
+ public void testStopServiceForUser_forRegisteredUser_unregistersCorrectUser() throws Exception {
+ BackupManagerService backupManagerService =
+ createServiceAndRegisterUser(mUserOneId, mUserOneService);
+ backupManagerService.startServiceForUser(mUserTwoId, mUserTwoService);
+
+ backupManagerService.stopServiceForUser(mUserOneId);
+
+ SparseArray<UserBackupManagerService> serviceUsers = backupManagerService.getServiceUsers();
+ assertThat(serviceUsers.size()).isEqualTo(1);
+ assertThat(serviceUsers.get(mUserOneId)).isNull();
+ assertThat(serviceUsers.get(mUserTwoId)).isEqualTo(mUserTwoService);
+ }
+
+ /** Test that the service unregisters users when stopped. */
+ @Test
+ public void testStopServiceForUser_forUnknownUser_doesNothing() throws Exception {
+ BackupManagerService backupManagerService = createService();
+
+ backupManagerService.stopServiceForUser(mUserOneId);
+
+ SparseArray<UserBackupManagerService> serviceUsers = backupManagerService.getServiceUsers();
+ assertThat(serviceUsers.size()).isEqualTo(0);
+ }
+
/**
* Test that the backup services throws a {@link SecurityException} if the caller does not have
* INTERACT_ACROSS_USERS_FULL permission and passes a different user id.
diff --git a/services/tests/servicestests/src/com/android/server/backup/TrampolineTest.java b/services/tests/servicestests/src/com/android/server/backup/TrampolineTest.java
index 1f37722..e02a30d 100644
--- a/services/tests/servicestests/src/com/android/server/backup/TrampolineTest.java
+++ b/services/tests/servicestests/src/com/android/server/backup/TrampolineTest.java
@@ -163,6 +163,36 @@
}
@Test
+ public void stopUser_whenMultiUserSettingDisabled_callsBackupManagerServiceForSystemUser() {
+ Settings.Global.putInt(mContentResolver, Settings.Global.BACKUP_MULTI_USER_ENABLED, 0);
+ mTrampoline.initializeService();
+
+ mTrampoline.stopUser(UserHandle.USER_SYSTEM);
+
+ verify(mBackupManagerServiceMock).stopServiceForUser(UserHandle.USER_SYSTEM);
+ }
+
+ @Test
+ public void stopUser_whenMultiUserSettingDisabled_isIgnoredForNonSystemUser() {
+ Settings.Global.putInt(mContentResolver, Settings.Global.BACKUP_MULTI_USER_ENABLED, 0);
+ mTrampoline.initializeService();
+
+ mTrampoline.stopUser(10);
+
+ verify(mBackupManagerServiceMock, never()).stopServiceForUser(10);
+ }
+
+ @Test
+ public void stopUser_whenMultiUserSettingEnabled_callsBackupManagerServiceForNonSystemUser() {
+ Settings.Global.putInt(mContentResolver, Settings.Global.BACKUP_MULTI_USER_ENABLED, 1);
+ mTrampoline.initializeService();
+
+ mTrampoline.stopUser(10);
+
+ verify(mBackupManagerServiceMock).stopServiceForUser(10);
+ }
+
+ @Test
public void initializeService_successfullyInitializesBackupService() {
mTrampoline.initializeService();