[Multi-user] Make each user have their own backup thread

The original backup thread is now only used by Trampoline and BMS for
general non-user specific operations. Each UserBMS instance has its own
'backup-[user id]' thread to allow for parallelism between users. When a
user is stopped, we quit this thread.

Bug: 121305979
Test: 1) atest RunBackupFrameworksServicesRoboTests
2) Start system user -> verify backup-0 thread created;
Start secondary user -> verify backup-10 thread created;
Stop secondary user -> verify backup-10 thread stopped;
Verify work posted to the thread is executed (register transports, bmgr
backupnow, etc.)

Change-Id: Iaa37fb3e2eb442653e27565ca13a88a0582efa9d
diff --git a/services/backup/java/com/android/server/backup/BackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java
index 8b07db7..6bd3990 100644
--- a/services/backup/java/com/android/server/backup/BackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/BackupManagerService.java
@@ -127,7 +127,7 @@
     protected void startServiceForUser(int userId) {
         UserBackupManagerService userBackupManagerService =
                 UserBackupManagerService.createAndInitializeService(
-                        userId, mContext, mTrampoline, mBackupThread, mTransportWhitelist);
+                        userId, mContext, mTrampoline, mTransportWhitelist);
         startServiceForUser(userId, userBackupManagerService);
     }
 
@@ -152,7 +152,11 @@
     /** Stops the backup service for user {@code userId} when the user is stopped. */
     @VisibleForTesting
     protected void stopServiceForUser(int userId) {
-        mServiceUsers.remove(userId);
+        UserBackupManagerService userBackupManagerService = mServiceUsers.removeReturnOld(userId);
+
+        if (userBackupManagerService != null) {
+            userBackupManagerService.tearDownService();
+        }
     }
 
     SparseArray<UserBackupManagerService> getServiceUsers() {
diff --git a/services/backup/java/com/android/server/backup/UserBackupManagerService.java b/services/backup/java/com/android/server/backup/UserBackupManagerService.java
index 6425508..b669019 100644
--- a/services/backup/java/com/android/server/backup/UserBackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/UserBackupManagerService.java
@@ -245,6 +245,7 @@
     private final @UserIdInt int mUserId;
     private final BackupAgentTimeoutParameters mAgentTimeoutParameters;
     private final TransportManager mTransportManager;
+    private final HandlerThread mUserBackupThread;
 
     private Context mContext;
     private PackageManager mPackageManager;
@@ -371,7 +372,6 @@
             @UserIdInt int userId,
             Context context,
             Trampoline trampoline,
-            HandlerThread backupThread,
             Set<ComponentName> transportWhitelist) {
         String currentTransport =
                 Settings.Secure.getString(
@@ -389,8 +389,21 @@
         File baseStateDir = UserBackupManagerFiles.getBaseStateDir(userId);
         File dataDir = UserBackupManagerFiles.getDataDir(userId);
 
+        HandlerThread userBackupThread =
+                new HandlerThread("backup-" + userId, Process.THREAD_PRIORITY_BACKGROUND);
+        userBackupThread.start();
+        if (DEBUG) {
+            Slog.d(TAG, "Started thread " + userBackupThread.getName() + " for user " + userId);
+        }
+
         return createAndInitializeService(
-                userId, context, trampoline, backupThread, baseStateDir, dataDir, transportManager);
+                userId,
+                context,
+                trampoline,
+                userBackupThread,
+                baseStateDir,
+                dataDir,
+                transportManager);
     }
 
     /**
@@ -399,7 +412,7 @@
      * @param userId The user which this service is for.
      * @param context The system server context.
      * @param trampoline A reference to the proxy to {@link BackupManagerService}.
-     * @param backupThread The thread running backup/restore operations for the user.
+     * @param userBackupThread The thread running backup/restore operations for the user.
      * @param baseStateDir The directory we store the user's persistent bookkeeping data.
      * @param dataDir The directory we store the user's temporary staging data.
      * @param transportManager The {@link TransportManager} responsible for handling the user's
@@ -410,19 +423,25 @@
             @UserIdInt int userId,
             Context context,
             Trampoline trampoline,
-            HandlerThread backupThread,
+            HandlerThread userBackupThread,
             File baseStateDir,
             File dataDir,
             TransportManager transportManager) {
         return new UserBackupManagerService(
-                userId, context, trampoline, backupThread, baseStateDir, dataDir, transportManager);
+                userId,
+                context,
+                trampoline,
+                userBackupThread,
+                baseStateDir,
+                dataDir,
+                transportManager);
     }
 
     private UserBackupManagerService(
             @UserIdInt int userId,
             Context context,
             Trampoline parent,
-            HandlerThread backupThread,
+            HandlerThread userBackupThread,
             File baseStateDir,
             File dataDir,
             TransportManager transportManager) {
@@ -443,9 +462,9 @@
                 BackupAgentTimeoutParameters(Handler.getMain(), mContext.getContentResolver());
         mAgentTimeoutParameters.start();
 
-        // spin up the backup/restore handler thread
-        checkNotNull(backupThread, "backupThread cannot be null");
-        mBackupHandler = new BackupHandler(this, backupThread.getLooper());
+        checkNotNull(userBackupThread, "userBackupThread cannot be null");
+        mUserBackupThread = userBackupThread;
+        mBackupHandler = new BackupHandler(this, userBackupThread.getLooper());
 
         // Set up our bookkeeping
         final ContentResolver resolver = context.getContentResolver();
@@ -526,6 +545,11 @@
         mWakelock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "*backup*");
     }
 
+    /** Cleans up state when the user of this service is stopped. */
+    void tearDownService() {
+        mUserBackupThread.quit();
+    }
+
     public BackupManagerConstants getConstants() {
         return mConstants;
     }
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 b8723c5..b682def 100644
--- a/services/robotests/backup/src/com/android/server/backup/BackupManagerServiceTest.java
+++ b/services/robotests/backup/src/com/android/server/backup/BackupManagerServiceTest.java
@@ -27,6 +27,7 @@
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
 import static org.robolectric.Shadows.shadowOf;
 import static org.testng.Assert.expectThrows;
 
@@ -192,6 +193,19 @@
 
     /** Test that the service unregisters users when stopped. */
     @Test
+    public void testStopServiceForUser_forRegisteredUser_tearsDownCorrectUser() throws Exception {
+        BackupManagerService backupManagerService =
+                createServiceAndRegisterUser(mUserOneId, mUserOneService);
+        backupManagerService.startServiceForUser(mUserTwoId, mUserTwoService);
+
+        backupManagerService.stopServiceForUser(mUserOneId);
+
+        verify(mUserOneService).tearDownService();
+        verifyNoMoreInteractions(mUserTwoService);
+    }
+
+    /** Test that the service unregisters users when stopped. */
+    @Test
     public void testStopServiceForUser_forUnknownUser_doesNothing() throws Exception {
         BackupManagerService backupManagerService = createService();
 
diff --git a/services/robotests/backup/src/com/android/server/backup/UserBackupManagerServiceTest.java b/services/robotests/backup/src/com/android/server/backup/UserBackupManagerServiceTest.java
index bb60c27..c65830d 100644
--- a/services/robotests/backup/src/com/android/server/backup/UserBackupManagerServiceTest.java
+++ b/services/robotests/backup/src/com/android/server/backup/UserBackupManagerServiceTest.java
@@ -970,9 +970,8 @@
     }
 
     /**
-     * Test verifying that {@link UserBackupManagerService#createAndInitializeService(Context,
-     * Trampoline, HandlerThread, File, File, TransportManager)} posts a transport registration task
-     * to the backup thread.
+     * Test verifying that creating a new instance posts a transport registration task to the backup
+     * thread.
      */
     @Test
     public void testCreateAndInitializeService_postRegisterTransports() {
@@ -992,9 +991,8 @@
     }
 
     /**
-     * Test verifying that {@link UserBackupManagerService#createAndInitializeService(Context,
-     * Trampoline, HandlerThread, File, File, TransportManager)} does not directly register
-     * transports on the main thread.
+     * Test verifying that creating a new instance does not directly register transports on the main
+     * thread.
      */
     @Test
     public void testCreateAndInitializeService_doesNotRegisterTransportsSynchronously() {
@@ -1013,11 +1011,7 @@
         verify(mTransportManager, never()).registerTransports();
     }
 
-    /**
-     * Test checking non-null argument on {@link
-     * UserBackupManagerService#createAndInitializeService(Context, Trampoline, HandlerThread, File,
-     * File, TransportManager)}.
-     */
+    /** Test checking non-null argument on instance creation. */
     @Test
     public void testCreateAndInitializeService_withNullContext_throws() {
         expectThrows(
@@ -1033,11 +1027,7 @@
                                 mTransportManager));
     }
 
-    /**
-     * Test checking non-null argument on {@link
-     * UserBackupManagerService#createAndInitializeService(Context, Trampoline, HandlerThread, File,
-     * File, TransportManager)}.
-     */
+    /** Test checking non-null argument on instance creation. */
     @Test
     public void testCreateAndInitializeService_withNullTrampoline_throws() {
         expectThrows(
@@ -1053,11 +1043,7 @@
                                 mTransportManager));
     }
 
-    /**
-     * Test checking non-null argument on {@link
-     * UserBackupManagerService#createAndInitializeService(Context, Trampoline, HandlerThread, File,
-     * File, TransportManager)}.
-     */
+    /** Test checking non-null argument on instance creation. */
     @Test
     public void testCreateAndInitializeService_withNullBackupThread_throws() {
         expectThrows(
@@ -1073,11 +1059,7 @@
                                 mTransportManager));
     }
 
-    /**
-     * Test checking non-null argument on {@link
-     * UserBackupManagerService#createAndInitializeService(Context, Trampoline, HandlerThread, File,
-     * File, TransportManager)}.
-     */
+    /** Test checking non-null argument on instance creation. */
     @Test
     public void testCreateAndInitializeService_withNullStateDir_throws() {
         expectThrows(