Loading services/backup/java/com/android/server/backup/BackupManagerService.java +8 −49 Original line number Diff line number Diff line Loading @@ -38,7 +38,6 @@ import android.content.pm.PackageManager; import android.os.Binder; import android.os.IBinder; import android.os.ParcelFileDescriptor; import android.os.Trace; import android.os.UserHandle; import android.os.UserManager; import android.util.Slog; Loading @@ -50,7 +49,6 @@ import com.android.server.SystemService; import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.Set; /** * Definition of the system service that performs backup/restore operations. Loading @@ -70,14 +68,17 @@ public class BackupManagerService { private final Context mContext; private final Trampoline mTrampoline; // Keeps track of all unlocked users registered with this service. Indexed by user id. private final SparseArray<UserBackupManagerService> mServiceUsers = new SparseArray<>(); private final SparseArray<UserBackupManagerService> mServiceUsers; /** Instantiate a new instance of {@link BackupManagerService}. */ public BackupManagerService(Context context, Trampoline trampoline) { public BackupManagerService( Context context, Trampoline trampoline, SparseArray<UserBackupManagerService> userServices) { mContext = checkNotNull(context); mTrampoline = checkNotNull(trampoline); // TODO(b/135661048): Remove mServiceUsers = userServices; } /** Loading @@ -98,48 +99,6 @@ public class BackupManagerService { // 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. */ @VisibleForTesting protected void startServiceForUser(int userId, Set<ComponentName> transportWhitelist) { if (mServiceUsers.get(userId) != null) { Slog.i(TAG, "userId " + userId + " already started, so not starting again"); return; } UserBackupManagerService userBackupManagerService = UserBackupManagerService.createAndInitializeService( userId, mContext, mTrampoline, transportWhitelist); startServiceForUser(userId, userBackupManagerService); } /** * Starts the backup service for user {@code userId} by registering its instance of {@link * UserBackupManagerService} with this service and setting enabled state. */ void startServiceForUser(int userId, UserBackupManagerService userBackupManagerService) { mServiceUsers.put(userId, userBackupManagerService); Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "backup enable"); userBackupManagerService.initializeBackupEnableState(); 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) { UserBackupManagerService userBackupManagerService = mServiceUsers.removeReturnOld(userId); if (userBackupManagerService != null) { userBackupManagerService.tearDownService(); KeyValueBackupJob.cancel(userId, mContext); FullBackupJob.cancel(userId, mContext); } } boolean isAbleToServeUser(int userId) { return getUserServices().get(UserHandle.USER_SYSTEM) != null && getUserServices().get(userId) != null; Loading Loading @@ -453,7 +412,7 @@ public class BackupManagerService { } for (int userId : userIds) { UserBackupManagerService userBackupManagerService = getUserServices().get(userId); UserBackupManagerService userBackupManagerService = mServiceUsers.get(userId); if (userBackupManagerService != null) { if (userBackupManagerService.getAncestralSerialNumber() == ancestralSerialNumber) { return UserHandle.of(userId); Loading services/backup/java/com/android/server/backup/Trampoline.java +66 −5 Original line number Diff line number Diff line Loading @@ -46,9 +46,11 @@ import android.os.ParcelFileDescriptor; import android.os.Process; import android.os.RemoteException; import android.os.SystemProperties; import android.os.Trace; import android.os.UserHandle; import android.os.UserManager; import android.util.Slog; import android.util.SparseArray; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; Loading Loading @@ -127,6 +129,9 @@ public class Trampoline extends IBackupManager.Stub { private final Handler mHandler; private final Set<ComponentName> mTransportWhitelist; /** Keeps track of all unlocked users registered with this service. Indexed by user id. */ private final SparseArray<UserBackupManagerService> mUserServices; private final BroadcastReceiver mUserRemovedReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { Loading @@ -140,6 +145,11 @@ public class Trampoline extends IBackupManager.Stub { }; public Trampoline(Context context) { this(context, new SparseArray<>()); } @VisibleForTesting Trampoline(Context context, SparseArray<UserBackupManagerService> userServices) { mContext = context; mGlobalDisable = isBackupDisabled(); HandlerThread handlerThread = Loading @@ -147,7 +157,8 @@ public class Trampoline extends IBackupManager.Stub { handlerThread.start(); mHandler = new Handler(handlerThread.getLooper()); mUserManager = UserManager.get(context); mService = new BackupManagerService(mContext, this); mUserServices = userServices; mService = new BackupManagerService(mContext, this, mUserServices); Set<ComponentName> transportWhitelist = SystemConfig.getInstance().getBackupTransportWhitelist(); mTransportWhitelist = (transportWhitelist == null) ? emptySet() : transportWhitelist; Loading Loading @@ -297,7 +308,12 @@ public class Trampoline extends IBackupManager.Stub { postToHandler(() -> startServiceForUser(userId)); } private void startServiceForUser(int userId) { /** * Starts the backup service for user {@code userId} by creating a new instance of {@link * UserBackupManagerService} and registering it with this service. */ @VisibleForTesting void startServiceForUser(int userId) { // We know that the user is unlocked here because it is called from setBackupServiceActive // and unlockUser which have these guarantees. So we can check if the file exists. if (mGlobalDisable) { Loading @@ -308,8 +324,53 @@ public class Trampoline extends IBackupManager.Stub { Slog.i(TAG, "Backup not activated for user " + userId); return; } if (mUserServices.get(userId) != null) { Slog.i(TAG, "userId " + userId + " already started, so not starting again"); return; } Slog.i(TAG, "Starting service for user: " + userId); mService.startServiceForUser(userId, mTransportWhitelist); UserBackupManagerService userBackupManagerService = UserBackupManagerService.createAndInitializeService( userId, mContext, this, mTransportWhitelist); startServiceForUser(userId, userBackupManagerService); } /** * Starts the backup service for user {@code userId} by registering its instance of {@link * UserBackupManagerService} with this service and setting enabled state. */ void startServiceForUser(int userId, UserBackupManagerService userBackupManagerService) { mUserServices.put(userId, userBackupManagerService); Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "backup enable"); userBackupManagerService.initializeBackupEnableState(); 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) { UserBackupManagerService userBackupManagerService = mUserServices.removeReturnOld(userId); if (userBackupManagerService != null) { userBackupManagerService.tearDownService(); KeyValueBackupJob.cancel(userId, mContext); FullBackupJob.cancel(userId, mContext); } } /** * Returns a list of users currently unlocked that have a {@link UserBackupManagerService} * registered. * * Warning: Do NOT modify returned object as it's used inside. * * TODO: Return a copy or only expose read-only information through other means. */ @VisibleForTesting SparseArray<UserBackupManagerService> getUserServices() { return mUserServices; } /** Loading @@ -321,7 +382,7 @@ public class Trampoline extends IBackupManager.Stub { () -> { if (!mGlobalDisable) { Slog.i(TAG, "Stopping service for user: " + userId); mService.stopServiceForUser(userId); stopServiceForUser(userId); } }); } Loading @@ -329,7 +390,7 @@ public class Trampoline extends IBackupManager.Stub { /** Returns {@link UserBackupManagerService} for user {@code userId}. */ @Nullable public UserBackupManagerService getUserService(int userId) { return mService.getUserServices().get(userId); return mUserServices.get(userId); } /** Loading services/backup/java/com/android/server/backup/UserBackupManagerService.java +2 −1 Original line number Diff line number Diff line Loading @@ -649,7 +649,8 @@ public class UserBackupManagerService { } /** Cleans up state when the user of this service is stopped. */ void tearDownService() { @VisibleForTesting protected void tearDownService() { mAgentTimeoutParameters.stop(); mConstants.stop(); mContext.getContentResolver().unregisterContentObserver(mSetupObserver); Loading services/robotests/backup/src/com/android/server/backup/BackupManagerServiceTest.java +208 −252 File changed.Preview size limit exceeded, changes collapsed. Show changes services/robotests/backup/src/com/android/server/backup/TrampolineRoboTest.java 0 → 100644 +175 −0 Original line number Diff line number Diff line /* * Copyright (C) 2019 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.server.backup; import static android.Manifest.permission.BACKUP; import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL; import static com.google.common.truth.Truth.assertThat; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import static org.robolectric.Shadows.shadowOf; import android.annotation.UserIdInt; import android.app.Application; import android.content.Context; import android.os.Process; import android.os.UserHandle; import android.os.UserManager; import android.platform.test.annotations.Presubmit; import android.util.SparseArray; import com.android.server.testing.shadows.ShadowApplicationPackageManager; import com.android.server.testing.shadows.ShadowBinder; import com.android.server.testing.shadows.ShadowEnvironment; import com.android.server.testing.shadows.ShadowSystemServiceRegistry; import com.android.server.testing.shadows.ShadowUserManager; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.robolectric.RobolectricTestRunner; import org.robolectric.RuntimeEnvironment; import org.robolectric.annotation.Config; import org.robolectric.shadow.api.Shadow; import org.robolectric.shadows.ShadowContextWrapper; /** Tests for {@link com.android.server.backup.Trampoline}. */ @RunWith(RobolectricTestRunner.class) @Config( shadows = { ShadowApplicationPackageManager.class, ShadowBinder.class, ShadowUserManager.class, ShadowEnvironment.class, ShadowSystemServiceRegistry.class }) @Presubmit public class TrampolineRoboTest { private Context mContext; private ShadowContextWrapper mShadowContext; private ShadowUserManager mShadowUserManager; @UserIdInt private int mUserOneId; @UserIdInt private int mUserTwoId; @Mock private UserBackupManagerService mUserOneService; @Mock private UserBackupManagerService mUserTwoService; /** Setup */ @Before public void setUp() throws Exception { MockitoAnnotations.initMocks(this); Application application = RuntimeEnvironment.application; mContext = application; mShadowContext = shadowOf(application); mShadowUserManager = Shadow.extract(UserManager.get(application)); mUserOneId = UserHandle.USER_SYSTEM + 1; mUserTwoId = mUserOneId + 1; mShadowUserManager.addUser(mUserOneId, "mUserOneId", 0); mShadowUserManager.addUser(mUserTwoId, "mUserTwoId", 0); mShadowContext.grantPermissions(BACKUP); mShadowContext.grantPermissions(INTERACT_ACROSS_USERS_FULL); ShadowBinder.setCallingUid(Process.SYSTEM_UID); } /** Test that the service registers users. */ @Test public void testStartServiceForUser_registersUser() throws Exception { Trampoline backupManagerService = createService(); backupManagerService.setBackupServiceActive(mUserOneId, true); backupManagerService.startServiceForUser(mUserOneId); SparseArray<UserBackupManagerService> serviceUsers = backupManagerService.getUserServices(); assertThat(serviceUsers.size()).isEqualTo(1); assertThat(serviceUsers.get(mUserOneId)).isNotNull(); } /** Test that the service registers users. */ @Test public void testStartServiceForUser_withServiceInstance_registersUser() throws Exception { Trampoline backupManagerService = createService(); backupManagerService.setBackupServiceActive(mUserOneId, true); backupManagerService.startServiceForUser(mUserOneId, mUserOneService); SparseArray<UserBackupManagerService> serviceUsers = backupManagerService.getUserServices(); assertThat(serviceUsers.size()).isEqualTo(1); assertThat(serviceUsers.get(mUserOneId)).isEqualTo(mUserOneService); } /** Test that the service unregisters users when stopped. */ @Test public void testStopServiceForUser_forRegisteredUser_unregistersCorrectUser() throws Exception { Trampoline backupManagerService = createServiceAndRegisterUser(mUserOneId, mUserOneService); backupManagerService.startServiceForUser(mUserTwoId, mUserTwoService); ShadowBinder.setCallingUid(Process.SYSTEM_UID); backupManagerService.stopServiceForUser(mUserOneId); SparseArray<UserBackupManagerService> serviceUsers = backupManagerService.getUserServices(); 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_forRegisteredUser_tearsDownCorrectUser() throws Exception { Trampoline backupManagerService = createServiceAndRegisterUser(mUserOneId, mUserOneService); backupManagerService.setBackupServiceActive(mUserTwoId, true); backupManagerService.startServiceForUser(mUserTwoId, mUserTwoService); backupManagerService.stopServiceForUser(mUserOneId); verify(mUserOneService).tearDownService(); verify(mUserTwoService, never()).tearDownService(); } /** Test that the service unregisters users when stopped. */ @Test public void testStopServiceForUser_forUnknownUser_doesNothing() throws Exception { Trampoline backupManagerService = createService(); backupManagerService.setBackupServiceActive(mUserOneId, true); ShadowBinder.setCallingUid(Process.SYSTEM_UID); backupManagerService.stopServiceForUser(mUserOneId); SparseArray<UserBackupManagerService> serviceUsers = backupManagerService.getUserServices(); assertThat(serviceUsers.size()).isEqualTo(0); } private Trampoline createService() { return new Trampoline(mContext); } private Trampoline createServiceAndRegisterUser( int userId, UserBackupManagerService userBackupManagerService) { Trampoline backupManagerService = createService(); backupManagerService.setBackupServiceActive(userBackupManagerService.getUserId(), true); backupManagerService.startServiceForUser(userId, userBackupManagerService); return backupManagerService; } } Loading
services/backup/java/com/android/server/backup/BackupManagerService.java +8 −49 Original line number Diff line number Diff line Loading @@ -38,7 +38,6 @@ import android.content.pm.PackageManager; import android.os.Binder; import android.os.IBinder; import android.os.ParcelFileDescriptor; import android.os.Trace; import android.os.UserHandle; import android.os.UserManager; import android.util.Slog; Loading @@ -50,7 +49,6 @@ import com.android.server.SystemService; import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.Set; /** * Definition of the system service that performs backup/restore operations. Loading @@ -70,14 +68,17 @@ public class BackupManagerService { private final Context mContext; private final Trampoline mTrampoline; // Keeps track of all unlocked users registered with this service. Indexed by user id. private final SparseArray<UserBackupManagerService> mServiceUsers = new SparseArray<>(); private final SparseArray<UserBackupManagerService> mServiceUsers; /** Instantiate a new instance of {@link BackupManagerService}. */ public BackupManagerService(Context context, Trampoline trampoline) { public BackupManagerService( Context context, Trampoline trampoline, SparseArray<UserBackupManagerService> userServices) { mContext = checkNotNull(context); mTrampoline = checkNotNull(trampoline); // TODO(b/135661048): Remove mServiceUsers = userServices; } /** Loading @@ -98,48 +99,6 @@ public class BackupManagerService { // 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. */ @VisibleForTesting protected void startServiceForUser(int userId, Set<ComponentName> transportWhitelist) { if (mServiceUsers.get(userId) != null) { Slog.i(TAG, "userId " + userId + " already started, so not starting again"); return; } UserBackupManagerService userBackupManagerService = UserBackupManagerService.createAndInitializeService( userId, mContext, mTrampoline, transportWhitelist); startServiceForUser(userId, userBackupManagerService); } /** * Starts the backup service for user {@code userId} by registering its instance of {@link * UserBackupManagerService} with this service and setting enabled state. */ void startServiceForUser(int userId, UserBackupManagerService userBackupManagerService) { mServiceUsers.put(userId, userBackupManagerService); Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "backup enable"); userBackupManagerService.initializeBackupEnableState(); 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) { UserBackupManagerService userBackupManagerService = mServiceUsers.removeReturnOld(userId); if (userBackupManagerService != null) { userBackupManagerService.tearDownService(); KeyValueBackupJob.cancel(userId, mContext); FullBackupJob.cancel(userId, mContext); } } boolean isAbleToServeUser(int userId) { return getUserServices().get(UserHandle.USER_SYSTEM) != null && getUserServices().get(userId) != null; Loading Loading @@ -453,7 +412,7 @@ public class BackupManagerService { } for (int userId : userIds) { UserBackupManagerService userBackupManagerService = getUserServices().get(userId); UserBackupManagerService userBackupManagerService = mServiceUsers.get(userId); if (userBackupManagerService != null) { if (userBackupManagerService.getAncestralSerialNumber() == ancestralSerialNumber) { return UserHandle.of(userId); Loading
services/backup/java/com/android/server/backup/Trampoline.java +66 −5 Original line number Diff line number Diff line Loading @@ -46,9 +46,11 @@ import android.os.ParcelFileDescriptor; import android.os.Process; import android.os.RemoteException; import android.os.SystemProperties; import android.os.Trace; import android.os.UserHandle; import android.os.UserManager; import android.util.Slog; import android.util.SparseArray; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; Loading Loading @@ -127,6 +129,9 @@ public class Trampoline extends IBackupManager.Stub { private final Handler mHandler; private final Set<ComponentName> mTransportWhitelist; /** Keeps track of all unlocked users registered with this service. Indexed by user id. */ private final SparseArray<UserBackupManagerService> mUserServices; private final BroadcastReceiver mUserRemovedReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { Loading @@ -140,6 +145,11 @@ public class Trampoline extends IBackupManager.Stub { }; public Trampoline(Context context) { this(context, new SparseArray<>()); } @VisibleForTesting Trampoline(Context context, SparseArray<UserBackupManagerService> userServices) { mContext = context; mGlobalDisable = isBackupDisabled(); HandlerThread handlerThread = Loading @@ -147,7 +157,8 @@ public class Trampoline extends IBackupManager.Stub { handlerThread.start(); mHandler = new Handler(handlerThread.getLooper()); mUserManager = UserManager.get(context); mService = new BackupManagerService(mContext, this); mUserServices = userServices; mService = new BackupManagerService(mContext, this, mUserServices); Set<ComponentName> transportWhitelist = SystemConfig.getInstance().getBackupTransportWhitelist(); mTransportWhitelist = (transportWhitelist == null) ? emptySet() : transportWhitelist; Loading Loading @@ -297,7 +308,12 @@ public class Trampoline extends IBackupManager.Stub { postToHandler(() -> startServiceForUser(userId)); } private void startServiceForUser(int userId) { /** * Starts the backup service for user {@code userId} by creating a new instance of {@link * UserBackupManagerService} and registering it with this service. */ @VisibleForTesting void startServiceForUser(int userId) { // We know that the user is unlocked here because it is called from setBackupServiceActive // and unlockUser which have these guarantees. So we can check if the file exists. if (mGlobalDisable) { Loading @@ -308,8 +324,53 @@ public class Trampoline extends IBackupManager.Stub { Slog.i(TAG, "Backup not activated for user " + userId); return; } if (mUserServices.get(userId) != null) { Slog.i(TAG, "userId " + userId + " already started, so not starting again"); return; } Slog.i(TAG, "Starting service for user: " + userId); mService.startServiceForUser(userId, mTransportWhitelist); UserBackupManagerService userBackupManagerService = UserBackupManagerService.createAndInitializeService( userId, mContext, this, mTransportWhitelist); startServiceForUser(userId, userBackupManagerService); } /** * Starts the backup service for user {@code userId} by registering its instance of {@link * UserBackupManagerService} with this service and setting enabled state. */ void startServiceForUser(int userId, UserBackupManagerService userBackupManagerService) { mUserServices.put(userId, userBackupManagerService); Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "backup enable"); userBackupManagerService.initializeBackupEnableState(); 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) { UserBackupManagerService userBackupManagerService = mUserServices.removeReturnOld(userId); if (userBackupManagerService != null) { userBackupManagerService.tearDownService(); KeyValueBackupJob.cancel(userId, mContext); FullBackupJob.cancel(userId, mContext); } } /** * Returns a list of users currently unlocked that have a {@link UserBackupManagerService} * registered. * * Warning: Do NOT modify returned object as it's used inside. * * TODO: Return a copy or only expose read-only information through other means. */ @VisibleForTesting SparseArray<UserBackupManagerService> getUserServices() { return mUserServices; } /** Loading @@ -321,7 +382,7 @@ public class Trampoline extends IBackupManager.Stub { () -> { if (!mGlobalDisable) { Slog.i(TAG, "Stopping service for user: " + userId); mService.stopServiceForUser(userId); stopServiceForUser(userId); } }); } Loading @@ -329,7 +390,7 @@ public class Trampoline extends IBackupManager.Stub { /** Returns {@link UserBackupManagerService} for user {@code userId}. */ @Nullable public UserBackupManagerService getUserService(int userId) { return mService.getUserServices().get(userId); return mUserServices.get(userId); } /** Loading
services/backup/java/com/android/server/backup/UserBackupManagerService.java +2 −1 Original line number Diff line number Diff line Loading @@ -649,7 +649,8 @@ public class UserBackupManagerService { } /** Cleans up state when the user of this service is stopped. */ void tearDownService() { @VisibleForTesting protected void tearDownService() { mAgentTimeoutParameters.stop(); mConstants.stop(); mContext.getContentResolver().unregisterContentObserver(mSetupObserver); Loading
services/robotests/backup/src/com/android/server/backup/BackupManagerServiceTest.java +208 −252 File changed.Preview size limit exceeded, changes collapsed. Show changes
services/robotests/backup/src/com/android/server/backup/TrampolineRoboTest.java 0 → 100644 +175 −0 Original line number Diff line number Diff line /* * Copyright (C) 2019 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.server.backup; import static android.Manifest.permission.BACKUP; import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL; import static com.google.common.truth.Truth.assertThat; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import static org.robolectric.Shadows.shadowOf; import android.annotation.UserIdInt; import android.app.Application; import android.content.Context; import android.os.Process; import android.os.UserHandle; import android.os.UserManager; import android.platform.test.annotations.Presubmit; import android.util.SparseArray; import com.android.server.testing.shadows.ShadowApplicationPackageManager; import com.android.server.testing.shadows.ShadowBinder; import com.android.server.testing.shadows.ShadowEnvironment; import com.android.server.testing.shadows.ShadowSystemServiceRegistry; import com.android.server.testing.shadows.ShadowUserManager; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.robolectric.RobolectricTestRunner; import org.robolectric.RuntimeEnvironment; import org.robolectric.annotation.Config; import org.robolectric.shadow.api.Shadow; import org.robolectric.shadows.ShadowContextWrapper; /** Tests for {@link com.android.server.backup.Trampoline}. */ @RunWith(RobolectricTestRunner.class) @Config( shadows = { ShadowApplicationPackageManager.class, ShadowBinder.class, ShadowUserManager.class, ShadowEnvironment.class, ShadowSystemServiceRegistry.class }) @Presubmit public class TrampolineRoboTest { private Context mContext; private ShadowContextWrapper mShadowContext; private ShadowUserManager mShadowUserManager; @UserIdInt private int mUserOneId; @UserIdInt private int mUserTwoId; @Mock private UserBackupManagerService mUserOneService; @Mock private UserBackupManagerService mUserTwoService; /** Setup */ @Before public void setUp() throws Exception { MockitoAnnotations.initMocks(this); Application application = RuntimeEnvironment.application; mContext = application; mShadowContext = shadowOf(application); mShadowUserManager = Shadow.extract(UserManager.get(application)); mUserOneId = UserHandle.USER_SYSTEM + 1; mUserTwoId = mUserOneId + 1; mShadowUserManager.addUser(mUserOneId, "mUserOneId", 0); mShadowUserManager.addUser(mUserTwoId, "mUserTwoId", 0); mShadowContext.grantPermissions(BACKUP); mShadowContext.grantPermissions(INTERACT_ACROSS_USERS_FULL); ShadowBinder.setCallingUid(Process.SYSTEM_UID); } /** Test that the service registers users. */ @Test public void testStartServiceForUser_registersUser() throws Exception { Trampoline backupManagerService = createService(); backupManagerService.setBackupServiceActive(mUserOneId, true); backupManagerService.startServiceForUser(mUserOneId); SparseArray<UserBackupManagerService> serviceUsers = backupManagerService.getUserServices(); assertThat(serviceUsers.size()).isEqualTo(1); assertThat(serviceUsers.get(mUserOneId)).isNotNull(); } /** Test that the service registers users. */ @Test public void testStartServiceForUser_withServiceInstance_registersUser() throws Exception { Trampoline backupManagerService = createService(); backupManagerService.setBackupServiceActive(mUserOneId, true); backupManagerService.startServiceForUser(mUserOneId, mUserOneService); SparseArray<UserBackupManagerService> serviceUsers = backupManagerService.getUserServices(); assertThat(serviceUsers.size()).isEqualTo(1); assertThat(serviceUsers.get(mUserOneId)).isEqualTo(mUserOneService); } /** Test that the service unregisters users when stopped. */ @Test public void testStopServiceForUser_forRegisteredUser_unregistersCorrectUser() throws Exception { Trampoline backupManagerService = createServiceAndRegisterUser(mUserOneId, mUserOneService); backupManagerService.startServiceForUser(mUserTwoId, mUserTwoService); ShadowBinder.setCallingUid(Process.SYSTEM_UID); backupManagerService.stopServiceForUser(mUserOneId); SparseArray<UserBackupManagerService> serviceUsers = backupManagerService.getUserServices(); 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_forRegisteredUser_tearsDownCorrectUser() throws Exception { Trampoline backupManagerService = createServiceAndRegisterUser(mUserOneId, mUserOneService); backupManagerService.setBackupServiceActive(mUserTwoId, true); backupManagerService.startServiceForUser(mUserTwoId, mUserTwoService); backupManagerService.stopServiceForUser(mUserOneId); verify(mUserOneService).tearDownService(); verify(mUserTwoService, never()).tearDownService(); } /** Test that the service unregisters users when stopped. */ @Test public void testStopServiceForUser_forUnknownUser_doesNothing() throws Exception { Trampoline backupManagerService = createService(); backupManagerService.setBackupServiceActive(mUserOneId, true); ShadowBinder.setCallingUid(Process.SYSTEM_UID); backupManagerService.stopServiceForUser(mUserOneId); SparseArray<UserBackupManagerService> serviceUsers = backupManagerService.getUserServices(); assertThat(serviceUsers.size()).isEqualTo(0); } private Trampoline createService() { return new Trampoline(mContext); } private Trampoline createServiceAndRegisterUser( int userId, UserBackupManagerService userBackupManagerService) { Trampoline backupManagerService = createService(); backupManagerService.setBackupServiceActive(userBackupManagerService.getUserId(), true); backupManagerService.startServiceForUser(userId, userBackupManagerService); return backupManagerService; } }