[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
This commit is contained in:
@@ -127,7 +127,7 @@ public class BackupManagerService {
|
||||
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 @@ public class BackupManagerService {
|
||||
/** 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() {
|
||||
|
||||
@@ -245,6 +245,7 @@ public class UserBackupManagerService {
|
||||
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 @@ public class UserBackupManagerService {
|
||||
@UserIdInt int userId,
|
||||
Context context,
|
||||
Trampoline trampoline,
|
||||
HandlerThread backupThread,
|
||||
Set<ComponentName> transportWhitelist) {
|
||||
String currentTransport =
|
||||
Settings.Secure.getString(
|
||||
@@ -389,8 +389,21 @@ public class UserBackupManagerService {
|
||||
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 @@ public class UserBackupManagerService {
|
||||
* @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 @@ public class UserBackupManagerService {
|
||||
@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 @@ public class UserBackupManagerService {
|
||||
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 @@ public class UserBackupManagerService {
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -27,6 +27,7 @@ import static org.junit.Assert.assertEquals;
|
||||
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;
|
||||
|
||||
@@ -190,6 +191,19 @@ public class BackupManagerServiceTest {
|
||||
assertThat(serviceUsers.get(mUserTwoId)).isEqualTo(mUserTwoService);
|
||||
}
|
||||
|
||||
/** 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 {
|
||||
|
||||
@@ -970,9 +970,8 @@ public class UserBackupManagerServiceTest {
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 @@ public class UserBackupManagerServiceTest {
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 @@ public class UserBackupManagerServiceTest {
|
||||
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 @@ public class UserBackupManagerServiceTest {
|
||||
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 @@ public class UserBackupManagerServiceTest {
|
||||
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 @@ public class UserBackupManagerServiceTest {
|
||||
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(
|
||||
|
||||
Reference in New Issue
Block a user