Loading services/backup/java/com/android/server/backup/TransportManager.java +1 −1 Original line number Original line Diff line number Diff line Loading @@ -177,7 +177,7 @@ public class TransportManager { } } @Nullable @Nullable String getCurrentTransportName() { public String getCurrentTransportName() { return mCurrentTransportName; return mCurrentTransportName; } } Loading services/backup/java/com/android/server/backup/internal/BackupRequest.java +19 −1 Original line number Original line Diff line number Diff line Loading @@ -16,11 +16,12 @@ package com.android.server.backup.internal; package com.android.server.backup.internal; import java.util.Objects; /** /** * Set of backup services that have pending changes. * Set of backup services that have pending changes. */ */ public class BackupRequest { public class BackupRequest { public String packageName; public String packageName; public BackupRequest(String pkgName) { public BackupRequest(String pkgName) { Loading @@ -30,4 +31,21 @@ public class BackupRequest { public String toString() { public String toString() { return "BackupRequest{pkg=" + packageName + "}"; return "BackupRequest{pkg=" + packageName + "}"; } } @Override public boolean equals(Object o) { if (this == o) { return true; } if (!(o instanceof BackupRequest)) { return false; } BackupRequest that = (BackupRequest) o; return Objects.equals(packageName, that.packageName); } @Override public int hashCode() { return Objects.hash(packageName); } } } services/robotests/src/com/android/server/backup/BackupManagerServiceTest.java +181 −30 Original line number Original line Diff line number Diff line Loading @@ -22,7 +22,9 @@ import static com.android.server.backup.testing.TransportData.d2dTransport; import static com.android.server.backup.testing.TransportData.localTransport; import static com.android.server.backup.testing.TransportData.localTransport; import static com.android.server.backup.testing.TransportTestUtils.setUpCurrentTransport; import static com.android.server.backup.testing.TransportTestUtils.setUpCurrentTransport; import static com.android.server.backup.testing.TransportTestUtils.setUpTransports; import static com.android.server.backup.testing.TransportTestUtils.setUpTransports; import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertThat; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.eq; Loading @@ -34,6 +36,7 @@ import static org.robolectric.Shadows.shadowOf; import static org.testng.Assert.expectThrows; import static org.testng.Assert.expectThrows; import android.app.backup.BackupManager; import android.app.backup.BackupManager; import android.app.backup.IBackupObserver; import android.app.backup.ISelectBackupTransportCallback; import android.app.backup.ISelectBackupTransportCallback; import android.content.ComponentName; import android.content.ComponentName; import android.content.Context; import android.content.Context; Loading @@ -43,18 +46,16 @@ import android.os.HandlerThread; import android.platform.test.annotations.Presubmit; import android.platform.test.annotations.Presubmit; import android.provider.Settings; import android.provider.Settings; import com.android.server.testing.shadows.ShadowAppBackupUtils; import com.android.server.backup.internal.BackupRequest; import com.android.server.testing.shadows.ShadowBackupPolicyEnforcer; import com.android.server.backup.testing.TransportData; import com.android.server.backup.testing.TransportData; import com.android.server.backup.testing.TransportTestUtils.TransportMock; import com.android.server.backup.testing.TransportTestUtils.TransportMock; import com.android.server.backup.transport.TransportNotRegisteredException; import com.android.server.backup.transport.TransportNotRegisteredException; import com.android.server.testing.FrameworkRobolectricTestRunner; import com.android.server.testing.FrameworkRobolectricTestRunner; import com.android.server.testing.SystemLoaderPackages; import com.android.server.testing.SystemLoaderPackages; import com.android.server.testing.shadows.ShadowAppBackupUtils; import com.android.server.testing.shadows.ShadowBackupPolicyEnforcer; import com.android.server.testing.shadows.ShadowPerformBackupTask; import java.io.File; import java.util.HashMap; import java.util.List; import java.util.Map; import org.junit.After; import org.junit.After; import org.junit.Before; import org.junit.Before; import org.junit.Test; import org.junit.Test; Loading @@ -70,6 +71,9 @@ import org.robolectric.shadows.ShadowPackageManager; import org.robolectric.shadows.ShadowSettings; import org.robolectric.shadows.ShadowSettings; import org.robolectric.shadows.ShadowSystemClock; import org.robolectric.shadows.ShadowSystemClock; import java.io.File; import java.util.List; @RunWith(FrameworkRobolectricTestRunner.class) @RunWith(FrameworkRobolectricTestRunner.class) @Config( @Config( manifest = Config.NONE, manifest = Config.NONE, Loading @@ -80,6 +84,8 @@ import org.robolectric.shadows.ShadowSystemClock; @Presubmit @Presubmit public class BackupManagerServiceTest { public class BackupManagerServiceTest { private static final String TAG = "BMSTest"; private static final String TAG = "BMSTest"; private static final String PACKAGE_1 = "some.package.1"; private static final String PACKAGE_2 = "some.package.2"; @Mock private TransportManager mTransportManager; @Mock private TransportManager mTransportManager; private HandlerThread mBackupThread; private HandlerThread mBackupThread; Loading @@ -90,6 +96,7 @@ public class BackupManagerServiceTest { private Context mContext; private Context mContext; private TransportData mTransport; private TransportData mTransport; private String mTransportName; private String mTransportName; private ShadowPackageManager mShadowPackageManager; @Before @Before public void setUp() throws Exception { public void setUp() throws Exception { Loading @@ -102,6 +109,7 @@ public class BackupManagerServiceTest { mShadowBackupLooper = shadowOf(mBackupThread.getLooper()); mShadowBackupLooper = shadowOf(mBackupThread.getLooper()); ContextWrapper context = RuntimeEnvironment.application; ContextWrapper context = RuntimeEnvironment.application; mShadowPackageManager = shadowOf(context.getPackageManager()); mContext = context; mContext = context; mShadowContext = shadowOf(context); mShadowContext = shadowOf(context); Loading Loading @@ -167,57 +175,54 @@ public class BackupManagerServiceTest { /* Tests for app eligibility */ /* Tests for app eligibility */ @Test @Test public void testIsAppEligibleForBackup_whenAppEligible() throws Exception { public void testIsAppEligibleForBackup_whenAppNotEligible() throws Exception { mShadowContext.grantPermissions(android.Manifest.permission.BACKUP); mShadowContext.grantPermissions(android.Manifest.permission.BACKUP); TransportMock transportMock = setUpCurrentTransport(mTransportManager, backupTransport()); setUpCurrentTransport(mTransportManager, mTransport); ShadowAppBackupUtils.sAppIsRunningAndEligibleForBackupWithTransport = p -> true; BackupManagerService backupManagerService = createInitializedBackupManagerService(); BackupManagerService backupManagerService = createInitializedBackupManagerService(); boolean result = backupManagerService.isAppEligibleForBackup("app.package"); boolean result = backupManagerService.isAppEligibleForBackup(PACKAGE_1); assertThat(result).isTrue(); verify(mTransportManager) assertThat(result).isFalse(); .disposeOfTransportClient(eq(transportMock.transportClient), any()); } } @Test @Test public void testIsAppEligibleForBackup_whenAppNotEligible() throws Exception { public void testIsAppEligibleForBackup_whenAppEligible() throws Exception { mShadowContext.grantPermissions(android.Manifest.permission.BACKUP); mShadowContext.grantPermissions(android.Manifest.permission.BACKUP); setUpCurrentTransport(mTransportManager, mTransport); TransportMock transportMock = setUpCurrentTransport(mTransportManager, backupTransport()); ShadowAppBackupUtils.sAppIsRunningAndEligibleForBackupWithTransport = p -> false; ShadowAppBackupUtils.setAppRunningAndEligibleForBackupWithTransport(PACKAGE_1); BackupManagerService backupManagerService = createInitializedBackupManagerService(); BackupManagerService backupManagerService = createInitializedBackupManagerService(); boolean result = backupManagerService.isAppEligibleForBackup("app.package"); boolean result = backupManagerService.isAppEligibleForBackup(PACKAGE_1); assertThat(result).isFalse(); assertThat(result).isTrue(); verify(mTransportManager) .disposeOfTransportClient(eq(transportMock.transportClient), any()); } } @Test @Test public void testIsAppEligibleForBackup_withoutPermission() throws Exception { public void testIsAppEligibleForBackup_withoutPermission() throws Exception { mShadowContext.denyPermissions(android.Manifest.permission.BACKUP); mShadowContext.denyPermissions(android.Manifest.permission.BACKUP); setUpCurrentTransport(mTransportManager, mTransport); setUpCurrentTransport(mTransportManager, mTransport); ShadowAppBackupUtils.setAppRunningAndEligibleForBackupWithTransport(PACKAGE_1); BackupManagerService backupManagerService = createInitializedBackupManagerService(); BackupManagerService backupManagerService = createInitializedBackupManagerService(); expectThrows( expectThrows( SecurityException.class, SecurityException.class, () -> backupManagerService.isAppEligibleForBackup("app.package")); () -> backupManagerService.isAppEligibleForBackup(PACKAGE_1)); } } @Test @Test public void testFilterAppsEligibleForBackup() throws Exception { public void testFilterAppsEligibleForBackup() throws Exception { mShadowContext.grantPermissions(android.Manifest.permission.BACKUP); mShadowContext.grantPermissions(android.Manifest.permission.BACKUP); TransportMock transportMock = setUpCurrentTransport(mTransportManager, mTransport); TransportMock transportMock = setUpCurrentTransport(mTransportManager, mTransport); Map<String, Boolean> packagesMap = new HashMap<>(); ShadowAppBackupUtils.setAppRunningAndEligibleForBackupWithTransport(PACKAGE_1); packagesMap.put("package.a", true); packagesMap.put("package.b", false); ShadowAppBackupUtils.sAppIsRunningAndEligibleForBackupWithTransport = packagesMap::get; BackupManagerService backupManagerService = createInitializedBackupManagerService(); BackupManagerService backupManagerService = createInitializedBackupManagerService(); String[] packages = packagesMap.keySet().toArray(new String[packagesMap.size()]); String[] filtered = backupManagerService.filterAppsEligibleForBackup(packages); String[] filtered = backupManagerService.filterAppsEligibleForBackup( new String[] {PACKAGE_1, PACKAGE_2}); assertThat(filtered).asList().containsExactly("package.a"); assertThat(filtered).asList().containsExactly(PACKAGE_1); verify(mTransportManager) verify(mTransportManager) .disposeOfTransportClient(eq(transportMock.transportClient), any()); .disposeOfTransportClient(eq(transportMock.transportClient), any()); } } Loading @@ -225,12 +230,11 @@ public class BackupManagerServiceTest { @Test @Test public void testFilterAppsEligibleForBackup_whenNoneIsEligible() throws Exception { public void testFilterAppsEligibleForBackup_whenNoneIsEligible() throws Exception { mShadowContext.grantPermissions(android.Manifest.permission.BACKUP); mShadowContext.grantPermissions(android.Manifest.permission.BACKUP); ShadowAppBackupUtils.sAppIsRunningAndEligibleForBackupWithTransport = p -> false; BackupManagerService backupManagerService = createInitializedBackupManagerService(); BackupManagerService backupManagerService = createInitializedBackupManagerService(); String[] filtered = String[] filtered = backupManagerService.filterAppsEligibleForBackup( backupManagerService.filterAppsEligibleForBackup( new String[] {"package.a", "package.b"}); new String[] {PACKAGE_1, PACKAGE_2}); assertThat(filtered).isEmpty(); assertThat(filtered).isEmpty(); } } Loading @@ -245,7 +249,7 @@ public class BackupManagerServiceTest { SecurityException.class, SecurityException.class, () -> () -> backupManagerService.filterAppsEligibleForBackup( backupManagerService.filterAppsEligibleForBackup( new String[] {"package.a", "package.b"})); new String[] {PACKAGE_1, PACKAGE_2})); } } /* Tests for select transport */ /* Tests for select transport */ Loading Loading @@ -608,6 +612,153 @@ public class BackupManagerServiceTest { "dataManagementLabel")); "dataManagementLabel")); } } /* Tests for request backup */ @Mock private IBackupObserver mObserver; private void setUpForRequestBackup(String... packages) throws Exception { mShadowContext.grantPermissions(android.Manifest.permission.BACKUP); for (String packageName : packages) { mShadowPackageManager.addPackage(packageName); ShadowAppBackupUtils.setAppRunningAndEligibleForBackupWithTransport(packageName); } setUpCurrentTransport(mTransportManager, mTransport); } private void tearDownForRequestBackup() { ShadowPerformBackupTask.reset(); } @Test public void testRequestBackup_whenPermissionDenied() throws Exception { mShadowContext.denyPermissions(android.Manifest.permission.BACKUP); BackupManagerService backupManagerService = createInitializedBackupManagerService(); expectThrows( SecurityException.class, () -> backupManagerService.requestBackup(new String[] {PACKAGE_1}, mObserver, 0)); } @Test public void testRequestBackup_whenPackagesNull() throws Exception { mShadowContext.grantPermissions(android.Manifest.permission.BACKUP); BackupManagerService backupManagerService = createInitializedBackupManagerService(); expectThrows( IllegalArgumentException.class, () -> backupManagerService.requestBackup(null, mObserver, 0)); verify(mObserver).backupFinished(BackupManager.ERROR_TRANSPORT_ABORTED); } @Test public void testRequestBackup_whenPackagesEmpty() throws Exception { mShadowContext.grantPermissions(android.Manifest.permission.BACKUP); BackupManagerService backupManagerService = createInitializedBackupManagerService(); expectThrows( IllegalArgumentException.class, () -> backupManagerService.requestBackup(new String[0], mObserver, 0)); verify(mObserver).backupFinished(BackupManager.ERROR_TRANSPORT_ABORTED); } @Test public void testRequestBackup_whenBackupDisabled() throws Exception { mShadowContext.grantPermissions(android.Manifest.permission.BACKUP); BackupManagerService backupManagerService = createInitializedBackupManagerService(); backupManagerService.setEnabled(false); int result = backupManagerService.requestBackup(new String[] {PACKAGE_1}, mObserver, 0); assertThat(result).isEqualTo(BackupManager.ERROR_BACKUP_NOT_ALLOWED); verify(mObserver).backupFinished(BackupManager.ERROR_BACKUP_NOT_ALLOWED); } @Test public void testRequestBackup_whenNotProvisioned() throws Exception { mShadowContext.grantPermissions(android.Manifest.permission.BACKUP); BackupManagerService backupManagerService = createInitializedBackupManagerService(); backupManagerService.setProvisioned(false); int result = backupManagerService.requestBackup(new String[] {PACKAGE_1}, mObserver, 0); assertThat(result).isEqualTo(BackupManager.ERROR_BACKUP_NOT_ALLOWED); verify(mObserver).backupFinished(BackupManager.ERROR_BACKUP_NOT_ALLOWED); } @Test public void testRequestBackup_whenTransportNotRegistered() throws Exception { mShadowContext.grantPermissions(android.Manifest.permission.BACKUP); setUpCurrentTransport(mTransportManager, mTransport.unregistered()); BackupManagerService backupManagerService = createInitializedBackupManagerService(); backupManagerService.setEnabled(true); backupManagerService.setProvisioned(true); int result = backupManagerService.requestBackup(new String[] {PACKAGE_1}, mObserver, 0); assertThat(result).isEqualTo(BackupManager.ERROR_TRANSPORT_ABORTED); verify(mObserver).backupFinished(BackupManager.ERROR_TRANSPORT_ABORTED); } @Test public void testRequestBackup_whenAppNotEligibleForBackup() throws Exception { mShadowContext.grantPermissions(android.Manifest.permission.BACKUP); mShadowPackageManager.addPackage(PACKAGE_1); setUpCurrentTransport(mTransportManager, mTransport); BackupManagerService backupManagerService = createInitializedBackupManagerService(); backupManagerService.setEnabled(true); backupManagerService.setProvisioned(true); // Haven't set PACKAGE_1 as eligible int result = backupManagerService.requestBackup(new String[] {PACKAGE_1}, mObserver, 0); assertThat(result).isEqualTo(BackupManager.SUCCESS); verify(mObserver).onResult(PACKAGE_1, BackupManager.ERROR_BACKUP_NOT_ALLOWED); // TODO: We probably don't need to kick-off PerformBackupTask when list is empty tearDownForRequestBackup(); } @Test @Config(shadows = ShadowPerformBackupTask.class) public void testRequestBackup_whenPackageIsKeyValue() throws Exception { setUpForRequestBackup(PACKAGE_1); BackupManagerService backupManagerService = createBackupManagerServiceForRequestBackup(); int result = backupManagerService.requestBackup(new String[] {PACKAGE_1}, mObserver, 0); mShadowBackupLooper.runToEndOfTasks(); assertThat(result).isEqualTo(BackupManager.SUCCESS); ShadowPerformBackupTask shadowTask = ShadowPerformBackupTask.getLastCreated(); assertThat(shadowTask.getQueue()).containsExactly(new BackupRequest(PACKAGE_1)); assertThat(shadowTask.getPendingFullBackups()).isEmpty(); // TODO: Assert more about PerformBackupTask tearDownForRequestBackup(); } @Test @Config(shadows = ShadowPerformBackupTask.class) public void testRequestBackup_whenPackageIsFullBackup() throws Exception { setUpForRequestBackup(PACKAGE_1); ShadowAppBackupUtils.setAppGetsFullBackup(PACKAGE_1); BackupManagerService backupManagerService = createBackupManagerServiceForRequestBackup(); int result = backupManagerService.requestBackup(new String[] {PACKAGE_1}, mObserver, 0); mShadowBackupLooper.runToEndOfTasks(); assertThat(result).isEqualTo(BackupManager.SUCCESS); ShadowPerformBackupTask shadowTask = ShadowPerformBackupTask.getLastCreated(); assertThat(shadowTask.getQueue()).isEmpty(); assertThat(shadowTask.getPendingFullBackups()).containsExactly(PACKAGE_1); // TODO: Assert more about PerformBackupTask tearDownForRequestBackup(); } private BackupManagerService createBackupManagerServiceForRequestBackup() { BackupManagerService backupManagerService = createInitializedBackupManagerService(); backupManagerService.setEnabled(true); backupManagerService.setProvisioned(true); return backupManagerService; } /* Miscellaneous tests */ /* Miscellaneous tests */ @Test @Test Loading services/robotests/src/com/android/server/backup/testing/TransportTestUtils.java +13 −2 Original line number Original line Diff line number Diff line Loading @@ -79,10 +79,21 @@ public class TransportTestUtils { /** {@code transportName} has to be in the {@link ComponentName} format (with '/') */ /** {@code transportName} has to be in the {@link ComponentName} format (with '/') */ public static TransportMock setUpCurrentTransport( public static TransportMock setUpCurrentTransport( TransportManager transportManager, TransportData transport) throws Exception { TransportManager transportManager, TransportData transport) throws Exception { TransportMock transportMock = setUpTransports(transportManager, transport).get(0); TransportMock transportMock = setUpTransport(transportManager, transport); if (transportMock.transportClient != null) { int status = transport.transportStatus; when(transportManager.getCurrentTransportName()).thenReturn(transport.transportName); if (status == TransportStatus.REGISTERED_AVAILABLE || status == TransportStatus.REGISTERED_UNAVAILABLE) { // Transport registered when(transportManager.getCurrentTransportClient(any())) when(transportManager.getCurrentTransportClient(any())) .thenReturn(transportMock.transportClient); .thenReturn(transportMock.transportClient); when(transportManager.getCurrentTransportClientOrThrow(any())) .thenReturn(transportMock.transportClient); } else { // Transport not registered when(transportManager.getCurrentTransportClient(any())).thenReturn(null); when(transportManager.getCurrentTransportClientOrThrow(any())) .thenThrow(TransportNotRegisteredException.class); } } return transportMock; return transportMock; } } Loading services/robotests/src/com/android/server/testing/shadows/ShadowAppBackupUtils.java +35 −6 Original line number Original line Diff line number Diff line Loading @@ -17,6 +17,8 @@ package com.android.server.testing.shadows; package com.android.server.testing.shadows; import android.annotation.Nullable; import android.annotation.Nullable; import android.content.pm.ApplicationInfo; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManager; import com.android.server.backup.transport.TransportClient; import com.android.server.backup.transport.TransportClient; Loading @@ -25,22 +27,49 @@ import com.android.server.backup.utils.AppBackupUtils; import org.robolectric.annotation.Implementation; import org.robolectric.annotation.Implementation; import org.robolectric.annotation.Implements; import org.robolectric.annotation.Implements; import java.util.function.Function; import java.util.HashSet; import java.util.Set; @Implements(AppBackupUtils.class) @Implements(AppBackupUtils.class) public class ShadowAppBackupUtils { public class ShadowAppBackupUtils { public static Function<String, Boolean> sAppIsRunningAndEligibleForBackupWithTransport; private static final Set<String> sAppsRunningAndEligibleForBackupWithTransport = static { new HashSet<>(); reset(); private static final Set<String> sAppsEligibleForBackup = new HashSet<>(); private static final Set<String> sAppsGetFullBackup = new HashSet<>(); public static void setAppRunningAndEligibleForBackupWithTransport(String packageName) { sAppsEligibleForBackup.add(packageName); sAppsRunningAndEligibleForBackupWithTransport.add(packageName); } public static void setAppEligibleForBackup(String packageName) { sAppsEligibleForBackup.add(packageName); } /** By default the app will be key-value. */ public static void setAppGetsFullBackup(String packageName) { sAppsGetFullBackup.add(packageName); } } @Implementation @Implementation public static boolean appIsRunningAndEligibleForBackupWithTransport( public static boolean appIsRunningAndEligibleForBackupWithTransport( @Nullable TransportClient transportClient, String packageName, PackageManager pm) { @Nullable TransportClient transportClient, String packageName, PackageManager pm) { return sAppIsRunningAndEligibleForBackupWithTransport.apply(packageName); return sAppsRunningAndEligibleForBackupWithTransport.contains(packageName); } @Implementation public static boolean appIsEligibleForBackup(ApplicationInfo app, PackageManager pm) { return sAppsEligibleForBackup.contains(app.packageName); } @Implementation public static boolean appGetsFullBackup(PackageInfo packageInfo) { return sAppsGetFullBackup.contains(packageInfo.packageName); } } public static void reset() { public static void reset() { sAppIsRunningAndEligibleForBackupWithTransport = p -> true; sAppsRunningAndEligibleForBackupWithTransport.clear(); sAppsEligibleForBackup.clear(); sAppsGetFullBackup.clear(); } } } } Loading
services/backup/java/com/android/server/backup/TransportManager.java +1 −1 Original line number Original line Diff line number Diff line Loading @@ -177,7 +177,7 @@ public class TransportManager { } } @Nullable @Nullable String getCurrentTransportName() { public String getCurrentTransportName() { return mCurrentTransportName; return mCurrentTransportName; } } Loading
services/backup/java/com/android/server/backup/internal/BackupRequest.java +19 −1 Original line number Original line Diff line number Diff line Loading @@ -16,11 +16,12 @@ package com.android.server.backup.internal; package com.android.server.backup.internal; import java.util.Objects; /** /** * Set of backup services that have pending changes. * Set of backup services that have pending changes. */ */ public class BackupRequest { public class BackupRequest { public String packageName; public String packageName; public BackupRequest(String pkgName) { public BackupRequest(String pkgName) { Loading @@ -30,4 +31,21 @@ public class BackupRequest { public String toString() { public String toString() { return "BackupRequest{pkg=" + packageName + "}"; return "BackupRequest{pkg=" + packageName + "}"; } } @Override public boolean equals(Object o) { if (this == o) { return true; } if (!(o instanceof BackupRequest)) { return false; } BackupRequest that = (BackupRequest) o; return Objects.equals(packageName, that.packageName); } @Override public int hashCode() { return Objects.hash(packageName); } } }
services/robotests/src/com/android/server/backup/BackupManagerServiceTest.java +181 −30 Original line number Original line Diff line number Diff line Loading @@ -22,7 +22,9 @@ import static com.android.server.backup.testing.TransportData.d2dTransport; import static com.android.server.backup.testing.TransportData.localTransport; import static com.android.server.backup.testing.TransportData.localTransport; import static com.android.server.backup.testing.TransportTestUtils.setUpCurrentTransport; import static com.android.server.backup.testing.TransportTestUtils.setUpCurrentTransport; import static com.android.server.backup.testing.TransportTestUtils.setUpTransports; import static com.android.server.backup.testing.TransportTestUtils.setUpTransports; import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertThat; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.eq; Loading @@ -34,6 +36,7 @@ import static org.robolectric.Shadows.shadowOf; import static org.testng.Assert.expectThrows; import static org.testng.Assert.expectThrows; import android.app.backup.BackupManager; import android.app.backup.BackupManager; import android.app.backup.IBackupObserver; import android.app.backup.ISelectBackupTransportCallback; import android.app.backup.ISelectBackupTransportCallback; import android.content.ComponentName; import android.content.ComponentName; import android.content.Context; import android.content.Context; Loading @@ -43,18 +46,16 @@ import android.os.HandlerThread; import android.platform.test.annotations.Presubmit; import android.platform.test.annotations.Presubmit; import android.provider.Settings; import android.provider.Settings; import com.android.server.testing.shadows.ShadowAppBackupUtils; import com.android.server.backup.internal.BackupRequest; import com.android.server.testing.shadows.ShadowBackupPolicyEnforcer; import com.android.server.backup.testing.TransportData; import com.android.server.backup.testing.TransportData; import com.android.server.backup.testing.TransportTestUtils.TransportMock; import com.android.server.backup.testing.TransportTestUtils.TransportMock; import com.android.server.backup.transport.TransportNotRegisteredException; import com.android.server.backup.transport.TransportNotRegisteredException; import com.android.server.testing.FrameworkRobolectricTestRunner; import com.android.server.testing.FrameworkRobolectricTestRunner; import com.android.server.testing.SystemLoaderPackages; import com.android.server.testing.SystemLoaderPackages; import com.android.server.testing.shadows.ShadowAppBackupUtils; import com.android.server.testing.shadows.ShadowBackupPolicyEnforcer; import com.android.server.testing.shadows.ShadowPerformBackupTask; import java.io.File; import java.util.HashMap; import java.util.List; import java.util.Map; import org.junit.After; import org.junit.After; import org.junit.Before; import org.junit.Before; import org.junit.Test; import org.junit.Test; Loading @@ -70,6 +71,9 @@ import org.robolectric.shadows.ShadowPackageManager; import org.robolectric.shadows.ShadowSettings; import org.robolectric.shadows.ShadowSettings; import org.robolectric.shadows.ShadowSystemClock; import org.robolectric.shadows.ShadowSystemClock; import java.io.File; import java.util.List; @RunWith(FrameworkRobolectricTestRunner.class) @RunWith(FrameworkRobolectricTestRunner.class) @Config( @Config( manifest = Config.NONE, manifest = Config.NONE, Loading @@ -80,6 +84,8 @@ import org.robolectric.shadows.ShadowSystemClock; @Presubmit @Presubmit public class BackupManagerServiceTest { public class BackupManagerServiceTest { private static final String TAG = "BMSTest"; private static final String TAG = "BMSTest"; private static final String PACKAGE_1 = "some.package.1"; private static final String PACKAGE_2 = "some.package.2"; @Mock private TransportManager mTransportManager; @Mock private TransportManager mTransportManager; private HandlerThread mBackupThread; private HandlerThread mBackupThread; Loading @@ -90,6 +96,7 @@ public class BackupManagerServiceTest { private Context mContext; private Context mContext; private TransportData mTransport; private TransportData mTransport; private String mTransportName; private String mTransportName; private ShadowPackageManager mShadowPackageManager; @Before @Before public void setUp() throws Exception { public void setUp() throws Exception { Loading @@ -102,6 +109,7 @@ public class BackupManagerServiceTest { mShadowBackupLooper = shadowOf(mBackupThread.getLooper()); mShadowBackupLooper = shadowOf(mBackupThread.getLooper()); ContextWrapper context = RuntimeEnvironment.application; ContextWrapper context = RuntimeEnvironment.application; mShadowPackageManager = shadowOf(context.getPackageManager()); mContext = context; mContext = context; mShadowContext = shadowOf(context); mShadowContext = shadowOf(context); Loading Loading @@ -167,57 +175,54 @@ public class BackupManagerServiceTest { /* Tests for app eligibility */ /* Tests for app eligibility */ @Test @Test public void testIsAppEligibleForBackup_whenAppEligible() throws Exception { public void testIsAppEligibleForBackup_whenAppNotEligible() throws Exception { mShadowContext.grantPermissions(android.Manifest.permission.BACKUP); mShadowContext.grantPermissions(android.Manifest.permission.BACKUP); TransportMock transportMock = setUpCurrentTransport(mTransportManager, backupTransport()); setUpCurrentTransport(mTransportManager, mTransport); ShadowAppBackupUtils.sAppIsRunningAndEligibleForBackupWithTransport = p -> true; BackupManagerService backupManagerService = createInitializedBackupManagerService(); BackupManagerService backupManagerService = createInitializedBackupManagerService(); boolean result = backupManagerService.isAppEligibleForBackup("app.package"); boolean result = backupManagerService.isAppEligibleForBackup(PACKAGE_1); assertThat(result).isTrue(); verify(mTransportManager) assertThat(result).isFalse(); .disposeOfTransportClient(eq(transportMock.transportClient), any()); } } @Test @Test public void testIsAppEligibleForBackup_whenAppNotEligible() throws Exception { public void testIsAppEligibleForBackup_whenAppEligible() throws Exception { mShadowContext.grantPermissions(android.Manifest.permission.BACKUP); mShadowContext.grantPermissions(android.Manifest.permission.BACKUP); setUpCurrentTransport(mTransportManager, mTransport); TransportMock transportMock = setUpCurrentTransport(mTransportManager, backupTransport()); ShadowAppBackupUtils.sAppIsRunningAndEligibleForBackupWithTransport = p -> false; ShadowAppBackupUtils.setAppRunningAndEligibleForBackupWithTransport(PACKAGE_1); BackupManagerService backupManagerService = createInitializedBackupManagerService(); BackupManagerService backupManagerService = createInitializedBackupManagerService(); boolean result = backupManagerService.isAppEligibleForBackup("app.package"); boolean result = backupManagerService.isAppEligibleForBackup(PACKAGE_1); assertThat(result).isFalse(); assertThat(result).isTrue(); verify(mTransportManager) .disposeOfTransportClient(eq(transportMock.transportClient), any()); } } @Test @Test public void testIsAppEligibleForBackup_withoutPermission() throws Exception { public void testIsAppEligibleForBackup_withoutPermission() throws Exception { mShadowContext.denyPermissions(android.Manifest.permission.BACKUP); mShadowContext.denyPermissions(android.Manifest.permission.BACKUP); setUpCurrentTransport(mTransportManager, mTransport); setUpCurrentTransport(mTransportManager, mTransport); ShadowAppBackupUtils.setAppRunningAndEligibleForBackupWithTransport(PACKAGE_1); BackupManagerService backupManagerService = createInitializedBackupManagerService(); BackupManagerService backupManagerService = createInitializedBackupManagerService(); expectThrows( expectThrows( SecurityException.class, SecurityException.class, () -> backupManagerService.isAppEligibleForBackup("app.package")); () -> backupManagerService.isAppEligibleForBackup(PACKAGE_1)); } } @Test @Test public void testFilterAppsEligibleForBackup() throws Exception { public void testFilterAppsEligibleForBackup() throws Exception { mShadowContext.grantPermissions(android.Manifest.permission.BACKUP); mShadowContext.grantPermissions(android.Manifest.permission.BACKUP); TransportMock transportMock = setUpCurrentTransport(mTransportManager, mTransport); TransportMock transportMock = setUpCurrentTransport(mTransportManager, mTransport); Map<String, Boolean> packagesMap = new HashMap<>(); ShadowAppBackupUtils.setAppRunningAndEligibleForBackupWithTransport(PACKAGE_1); packagesMap.put("package.a", true); packagesMap.put("package.b", false); ShadowAppBackupUtils.sAppIsRunningAndEligibleForBackupWithTransport = packagesMap::get; BackupManagerService backupManagerService = createInitializedBackupManagerService(); BackupManagerService backupManagerService = createInitializedBackupManagerService(); String[] packages = packagesMap.keySet().toArray(new String[packagesMap.size()]); String[] filtered = backupManagerService.filterAppsEligibleForBackup(packages); String[] filtered = backupManagerService.filterAppsEligibleForBackup( new String[] {PACKAGE_1, PACKAGE_2}); assertThat(filtered).asList().containsExactly("package.a"); assertThat(filtered).asList().containsExactly(PACKAGE_1); verify(mTransportManager) verify(mTransportManager) .disposeOfTransportClient(eq(transportMock.transportClient), any()); .disposeOfTransportClient(eq(transportMock.transportClient), any()); } } Loading @@ -225,12 +230,11 @@ public class BackupManagerServiceTest { @Test @Test public void testFilterAppsEligibleForBackup_whenNoneIsEligible() throws Exception { public void testFilterAppsEligibleForBackup_whenNoneIsEligible() throws Exception { mShadowContext.grantPermissions(android.Manifest.permission.BACKUP); mShadowContext.grantPermissions(android.Manifest.permission.BACKUP); ShadowAppBackupUtils.sAppIsRunningAndEligibleForBackupWithTransport = p -> false; BackupManagerService backupManagerService = createInitializedBackupManagerService(); BackupManagerService backupManagerService = createInitializedBackupManagerService(); String[] filtered = String[] filtered = backupManagerService.filterAppsEligibleForBackup( backupManagerService.filterAppsEligibleForBackup( new String[] {"package.a", "package.b"}); new String[] {PACKAGE_1, PACKAGE_2}); assertThat(filtered).isEmpty(); assertThat(filtered).isEmpty(); } } Loading @@ -245,7 +249,7 @@ public class BackupManagerServiceTest { SecurityException.class, SecurityException.class, () -> () -> backupManagerService.filterAppsEligibleForBackup( backupManagerService.filterAppsEligibleForBackup( new String[] {"package.a", "package.b"})); new String[] {PACKAGE_1, PACKAGE_2})); } } /* Tests for select transport */ /* Tests for select transport */ Loading Loading @@ -608,6 +612,153 @@ public class BackupManagerServiceTest { "dataManagementLabel")); "dataManagementLabel")); } } /* Tests for request backup */ @Mock private IBackupObserver mObserver; private void setUpForRequestBackup(String... packages) throws Exception { mShadowContext.grantPermissions(android.Manifest.permission.BACKUP); for (String packageName : packages) { mShadowPackageManager.addPackage(packageName); ShadowAppBackupUtils.setAppRunningAndEligibleForBackupWithTransport(packageName); } setUpCurrentTransport(mTransportManager, mTransport); } private void tearDownForRequestBackup() { ShadowPerformBackupTask.reset(); } @Test public void testRequestBackup_whenPermissionDenied() throws Exception { mShadowContext.denyPermissions(android.Manifest.permission.BACKUP); BackupManagerService backupManagerService = createInitializedBackupManagerService(); expectThrows( SecurityException.class, () -> backupManagerService.requestBackup(new String[] {PACKAGE_1}, mObserver, 0)); } @Test public void testRequestBackup_whenPackagesNull() throws Exception { mShadowContext.grantPermissions(android.Manifest.permission.BACKUP); BackupManagerService backupManagerService = createInitializedBackupManagerService(); expectThrows( IllegalArgumentException.class, () -> backupManagerService.requestBackup(null, mObserver, 0)); verify(mObserver).backupFinished(BackupManager.ERROR_TRANSPORT_ABORTED); } @Test public void testRequestBackup_whenPackagesEmpty() throws Exception { mShadowContext.grantPermissions(android.Manifest.permission.BACKUP); BackupManagerService backupManagerService = createInitializedBackupManagerService(); expectThrows( IllegalArgumentException.class, () -> backupManagerService.requestBackup(new String[0], mObserver, 0)); verify(mObserver).backupFinished(BackupManager.ERROR_TRANSPORT_ABORTED); } @Test public void testRequestBackup_whenBackupDisabled() throws Exception { mShadowContext.grantPermissions(android.Manifest.permission.BACKUP); BackupManagerService backupManagerService = createInitializedBackupManagerService(); backupManagerService.setEnabled(false); int result = backupManagerService.requestBackup(new String[] {PACKAGE_1}, mObserver, 0); assertThat(result).isEqualTo(BackupManager.ERROR_BACKUP_NOT_ALLOWED); verify(mObserver).backupFinished(BackupManager.ERROR_BACKUP_NOT_ALLOWED); } @Test public void testRequestBackup_whenNotProvisioned() throws Exception { mShadowContext.grantPermissions(android.Manifest.permission.BACKUP); BackupManagerService backupManagerService = createInitializedBackupManagerService(); backupManagerService.setProvisioned(false); int result = backupManagerService.requestBackup(new String[] {PACKAGE_1}, mObserver, 0); assertThat(result).isEqualTo(BackupManager.ERROR_BACKUP_NOT_ALLOWED); verify(mObserver).backupFinished(BackupManager.ERROR_BACKUP_NOT_ALLOWED); } @Test public void testRequestBackup_whenTransportNotRegistered() throws Exception { mShadowContext.grantPermissions(android.Manifest.permission.BACKUP); setUpCurrentTransport(mTransportManager, mTransport.unregistered()); BackupManagerService backupManagerService = createInitializedBackupManagerService(); backupManagerService.setEnabled(true); backupManagerService.setProvisioned(true); int result = backupManagerService.requestBackup(new String[] {PACKAGE_1}, mObserver, 0); assertThat(result).isEqualTo(BackupManager.ERROR_TRANSPORT_ABORTED); verify(mObserver).backupFinished(BackupManager.ERROR_TRANSPORT_ABORTED); } @Test public void testRequestBackup_whenAppNotEligibleForBackup() throws Exception { mShadowContext.grantPermissions(android.Manifest.permission.BACKUP); mShadowPackageManager.addPackage(PACKAGE_1); setUpCurrentTransport(mTransportManager, mTransport); BackupManagerService backupManagerService = createInitializedBackupManagerService(); backupManagerService.setEnabled(true); backupManagerService.setProvisioned(true); // Haven't set PACKAGE_1 as eligible int result = backupManagerService.requestBackup(new String[] {PACKAGE_1}, mObserver, 0); assertThat(result).isEqualTo(BackupManager.SUCCESS); verify(mObserver).onResult(PACKAGE_1, BackupManager.ERROR_BACKUP_NOT_ALLOWED); // TODO: We probably don't need to kick-off PerformBackupTask when list is empty tearDownForRequestBackup(); } @Test @Config(shadows = ShadowPerformBackupTask.class) public void testRequestBackup_whenPackageIsKeyValue() throws Exception { setUpForRequestBackup(PACKAGE_1); BackupManagerService backupManagerService = createBackupManagerServiceForRequestBackup(); int result = backupManagerService.requestBackup(new String[] {PACKAGE_1}, mObserver, 0); mShadowBackupLooper.runToEndOfTasks(); assertThat(result).isEqualTo(BackupManager.SUCCESS); ShadowPerformBackupTask shadowTask = ShadowPerformBackupTask.getLastCreated(); assertThat(shadowTask.getQueue()).containsExactly(new BackupRequest(PACKAGE_1)); assertThat(shadowTask.getPendingFullBackups()).isEmpty(); // TODO: Assert more about PerformBackupTask tearDownForRequestBackup(); } @Test @Config(shadows = ShadowPerformBackupTask.class) public void testRequestBackup_whenPackageIsFullBackup() throws Exception { setUpForRequestBackup(PACKAGE_1); ShadowAppBackupUtils.setAppGetsFullBackup(PACKAGE_1); BackupManagerService backupManagerService = createBackupManagerServiceForRequestBackup(); int result = backupManagerService.requestBackup(new String[] {PACKAGE_1}, mObserver, 0); mShadowBackupLooper.runToEndOfTasks(); assertThat(result).isEqualTo(BackupManager.SUCCESS); ShadowPerformBackupTask shadowTask = ShadowPerformBackupTask.getLastCreated(); assertThat(shadowTask.getQueue()).isEmpty(); assertThat(shadowTask.getPendingFullBackups()).containsExactly(PACKAGE_1); // TODO: Assert more about PerformBackupTask tearDownForRequestBackup(); } private BackupManagerService createBackupManagerServiceForRequestBackup() { BackupManagerService backupManagerService = createInitializedBackupManagerService(); backupManagerService.setEnabled(true); backupManagerService.setProvisioned(true); return backupManagerService; } /* Miscellaneous tests */ /* Miscellaneous tests */ @Test @Test Loading
services/robotests/src/com/android/server/backup/testing/TransportTestUtils.java +13 −2 Original line number Original line Diff line number Diff line Loading @@ -79,10 +79,21 @@ public class TransportTestUtils { /** {@code transportName} has to be in the {@link ComponentName} format (with '/') */ /** {@code transportName} has to be in the {@link ComponentName} format (with '/') */ public static TransportMock setUpCurrentTransport( public static TransportMock setUpCurrentTransport( TransportManager transportManager, TransportData transport) throws Exception { TransportManager transportManager, TransportData transport) throws Exception { TransportMock transportMock = setUpTransports(transportManager, transport).get(0); TransportMock transportMock = setUpTransport(transportManager, transport); if (transportMock.transportClient != null) { int status = transport.transportStatus; when(transportManager.getCurrentTransportName()).thenReturn(transport.transportName); if (status == TransportStatus.REGISTERED_AVAILABLE || status == TransportStatus.REGISTERED_UNAVAILABLE) { // Transport registered when(transportManager.getCurrentTransportClient(any())) when(transportManager.getCurrentTransportClient(any())) .thenReturn(transportMock.transportClient); .thenReturn(transportMock.transportClient); when(transportManager.getCurrentTransportClientOrThrow(any())) .thenReturn(transportMock.transportClient); } else { // Transport not registered when(transportManager.getCurrentTransportClient(any())).thenReturn(null); when(transportManager.getCurrentTransportClientOrThrow(any())) .thenThrow(TransportNotRegisteredException.class); } } return transportMock; return transportMock; } } Loading
services/robotests/src/com/android/server/testing/shadows/ShadowAppBackupUtils.java +35 −6 Original line number Original line Diff line number Diff line Loading @@ -17,6 +17,8 @@ package com.android.server.testing.shadows; package com.android.server.testing.shadows; import android.annotation.Nullable; import android.annotation.Nullable; import android.content.pm.ApplicationInfo; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManager; import com.android.server.backup.transport.TransportClient; import com.android.server.backup.transport.TransportClient; Loading @@ -25,22 +27,49 @@ import com.android.server.backup.utils.AppBackupUtils; import org.robolectric.annotation.Implementation; import org.robolectric.annotation.Implementation; import org.robolectric.annotation.Implements; import org.robolectric.annotation.Implements; import java.util.function.Function; import java.util.HashSet; import java.util.Set; @Implements(AppBackupUtils.class) @Implements(AppBackupUtils.class) public class ShadowAppBackupUtils { public class ShadowAppBackupUtils { public static Function<String, Boolean> sAppIsRunningAndEligibleForBackupWithTransport; private static final Set<String> sAppsRunningAndEligibleForBackupWithTransport = static { new HashSet<>(); reset(); private static final Set<String> sAppsEligibleForBackup = new HashSet<>(); private static final Set<String> sAppsGetFullBackup = new HashSet<>(); public static void setAppRunningAndEligibleForBackupWithTransport(String packageName) { sAppsEligibleForBackup.add(packageName); sAppsRunningAndEligibleForBackupWithTransport.add(packageName); } public static void setAppEligibleForBackup(String packageName) { sAppsEligibleForBackup.add(packageName); } /** By default the app will be key-value. */ public static void setAppGetsFullBackup(String packageName) { sAppsGetFullBackup.add(packageName); } } @Implementation @Implementation public static boolean appIsRunningAndEligibleForBackupWithTransport( public static boolean appIsRunningAndEligibleForBackupWithTransport( @Nullable TransportClient transportClient, String packageName, PackageManager pm) { @Nullable TransportClient transportClient, String packageName, PackageManager pm) { return sAppIsRunningAndEligibleForBackupWithTransport.apply(packageName); return sAppsRunningAndEligibleForBackupWithTransport.contains(packageName); } @Implementation public static boolean appIsEligibleForBackup(ApplicationInfo app, PackageManager pm) { return sAppsEligibleForBackup.contains(app.packageName); } @Implementation public static boolean appGetsFullBackup(PackageInfo packageInfo) { return sAppsGetFullBackup.contains(packageInfo.packageName); } } public static void reset() { public static void reset() { sAppIsRunningAndEligibleForBackupWithTransport = p -> true; sAppsRunningAndEligibleForBackupWithTransport.clear(); sAppsEligibleForBackup.clear(); sAppsGetFullBackup.clear(); } } } }