summaryrefslogtreecommitdiff
path: root/services/robotests
diff options
context:
space:
mode:
authorXin Li <delphij@google.com>2020-08-31 21:21:38 -0700
committerXin Li <delphij@google.com>2020-08-31 21:21:38 -0700
commit628590d7ec80e10a3fc24b1c18a1afb55cca10a8 (patch)
tree4b1c3f52d86d7fb53afbe9e9438468588fa489f8 /services/robotests
parentb11b8ec3aec8bb42f2c07e1c5ac7942da293baa8 (diff)
parentd2d3a20624d968199353ccf6ddbae6f3ac39c9af (diff)
Merge Android R (rvc-dev-plus-aosp-without-vendor@6692709)
Bug: 166295507 Merged-In: I3d92a6de21a938f6b352ec26dc23420c0fe02b27 Change-Id: Ifdb80563ef042738778ebb8a7581a97c4e3d96e2
Diffstat (limited to 'services/robotests')
-rw-r--r--services/robotests/Android.bp3
-rw-r--r--services/robotests/backup/Android.bp2
-rw-r--r--services/robotests/backup/src/com/android/server/backup/BackupManagerServiceRoboTest.java (renamed from services/robotests/backup/src/com/android/server/backup/BackupManagerServiceTest.java)801
-rw-r--r--services/robotests/backup/src/com/android/server/backup/FullBackupJobTest.java4
-rw-r--r--services/robotests/backup/src/com/android/server/backup/KeyValueBackupJobTest.java4
-rw-r--r--services/robotests/backup/src/com/android/server/backup/UserBackupManagerServiceTest.java137
-rw-r--r--services/robotests/backup/src/com/android/server/backup/encryption/chunk/ChunkHashTest.java100
-rw-r--r--services/robotests/backup/src/com/android/server/backup/encryption/chunk/ChunkListingMapTest.java197
-rw-r--r--services/robotests/backup/src/com/android/server/backup/encryption/chunk/ChunkTest.java122
-rw-r--r--services/robotests/backup/src/com/android/server/backup/encryption/chunk/EncryptedChunkOrderingTest.java73
-rw-r--r--services/robotests/backup/src/com/android/server/backup/encryption/chunking/ByteRangeTest.java57
-rw-r--r--services/robotests/backup/src/com/android/server/backup/encryption/chunking/ChunkEncryptorTest.java157
-rw-r--r--services/robotests/backup/src/com/android/server/backup/encryption/chunking/ChunkHasherTest.java71
-rw-r--r--services/robotests/backup/src/com/android/server/backup/encryption/chunking/DiffScriptBackupWriterTest.java90
-rw-r--r--services/robotests/backup/src/com/android/server/backup/encryption/chunking/EncryptedChunkTest.java133
-rw-r--r--services/robotests/backup/src/com/android/server/backup/encryption/chunking/InlineLengthsEncryptedChunkEncoderTest.java85
-rw-r--r--services/robotests/backup/src/com/android/server/backup/encryption/chunking/LengthlessEncryptedChunkEncoderTest.java80
-rw-r--r--services/robotests/backup/src/com/android/server/backup/encryption/chunking/RawBackupWriterTest.java84
-rw-r--r--services/robotests/backup/src/com/android/server/backup/encryption/chunking/SingleStreamDiffScriptWriterTest.java128
-rw-r--r--services/robotests/backup/src/com/android/server/backup/encryption/chunking/cdc/ContentDefinedChunkerTest.java232
-rw-r--r--services/robotests/backup/src/com/android/server/backup/encryption/chunking/cdc/FingerprintMixerTest.java205
-rw-r--r--services/robotests/backup/src/com/android/server/backup/encryption/chunking/cdc/HkdfTest.java95
-rw-r--r--services/robotests/backup/src/com/android/server/backup/encryption/chunking/cdc/IsChunkBreakpointTest.java122
-rw-r--r--services/robotests/backup/src/com/android/server/backup/encryption/chunking/cdc/RabinFingerprint64Test.java132
-rw-r--r--services/robotests/backup/src/com/android/server/backup/encryption/keys/RecoverableKeyStoreSecondaryKeyManagerTest.java148
-rw-r--r--services/robotests/backup/src/com/android/server/backup/encryption/keys/RecoverableKeyStoreSecondaryKeyTest.java163
-rw-r--r--services/robotests/backup/src/com/android/server/backup/encryption/keys/TertiaryKeyGeneratorTest.java73
-rw-r--r--services/robotests/backup/src/com/android/server/backup/encryption/keys/TertiaryKeyRotationTrackerTest.java137
-rw-r--r--services/robotests/backup/src/com/android/server/backup/encryption/storage/BackupEncryptionDbTest.java55
-rw-r--r--services/robotests/backup/src/com/android/server/backup/encryption/storage/TertiaryKeysTableTest.java179
-rw-r--r--services/robotests/backup/src/com/android/server/backup/internal/SetupObserverTest.java8
-rw-r--r--services/robotests/backup/src/com/android/server/backup/keyvalue/KeyValueBackupReporterTest.java12
-rw-r--r--services/robotests/backup/src/com/android/server/backup/keyvalue/KeyValueBackupTaskTest.java133
-rw-r--r--services/robotests/backup/src/com/android/server/backup/testing/BackupManagerServiceTestUtils.java6
-rw-r--r--services/robotests/backup/src/com/android/server/backup/testing/CryptoTestUtils.java45
-rw-r--r--services/robotests/src/com/android/server/location/LocationRequestStatisticsTest.java76
-rw-r--r--services/robotests/src/com/android/server/location/gnss/GnssAntennaInfoProviderTest.java95
-rw-r--r--services/robotests/src/com/android/server/location/gnss/GnssBatchingProviderTest.java (renamed from services/robotests/src/com/android/server/location/GnssBatchingProviderTest.java)20
-rw-r--r--services/robotests/src/com/android/server/location/gnss/GnssGeofenceProviderTest.java (renamed from services/robotests/src/com/android/server/location/GnssGeofenceProviderTest.java)18
-rw-r--r--services/robotests/src/com/android/server/location/gnss/GnssMeasurementsProviderTest.java (renamed from services/robotests/src/com/android/server/location/GnssMeasurementsProviderTest.java)21
-rw-r--r--services/robotests/src/com/android/server/location/gnss/GnssNavigationMessageProviderTest.java (renamed from services/robotests/src/com/android/server/location/GnssNavigationMessageProviderTest.java)21
-rw-r--r--services/robotests/src/com/android/server/location/gnss/GnssPositionModeTest.java (renamed from services/robotests/src/com/android/server/location/GnssPositionModeTest.java)18
-rw-r--r--services/robotests/src/com/android/server/location/gnss/GnssSatelliteBlacklistHelperTest.java (renamed from services/robotests/src/com/android/server/location/GnssSatelliteBlacklistHelperTest.java)21
-rw-r--r--services/robotests/src/com/android/server/location/gnss/NtpTimeHelperTest.java (renamed from services/robotests/src/com/android/server/location/NtpTimeHelperTest.java)20
-rw-r--r--services/robotests/src/com/android/server/pm/CrossProfileAppsServiceImplRoboTest.java754
-rw-r--r--services/robotests/src/com/android/server/testing/shadows/ShadowApplicationPackageManager.java29
-rw-r--r--services/robotests/src/com/android/server/testing/shadows/ShadowCloseGuard.java5
-rw-r--r--services/robotests/src/com/android/server/testing/shadows/ShadowEnvironment.java50
-rw-r--r--services/robotests/src/com/android/server/testing/shadows/ShadowInternalRecoveryServiceException.java43
-rw-r--r--services/robotests/src/com/android/server/testing/shadows/ShadowPerformUnifiedRestoreTask.java3
-rw-r--r--services/robotests/src/com/android/server/testing/shadows/ShadowRecoveryController.java152
-rw-r--r--services/robotests/src/com/android/server/testing/shadows/ShadowSystemServiceRegistry.java48
-rw-r--r--services/robotests/src/com/android/server/testing/shadows/ShadowUserManager.java61
53 files changed, 1938 insertions, 3590 deletions
diff --git a/services/robotests/Android.bp b/services/robotests/Android.bp
index 566e61e1a14f..1ae2aec90ba3 100644
--- a/services/robotests/Android.bp
+++ b/services/robotests/Android.bp
@@ -46,6 +46,9 @@ android_robolectric_test {
"services.backup",
"testng",
],
+ static_libs: [
+ "androidx.test.ext.truth",
+ ],
instrumentation_for: "FrameworksServicesLib",
}
diff --git a/services/robotests/backup/Android.bp b/services/robotests/backup/Android.bp
index a3ccc6e9dd12..32587accf160 100644
--- a/services/robotests/backup/Android.bp
+++ b/services/robotests/backup/Android.bp
@@ -46,8 +46,10 @@ android_robolectric_test {
// Include the testing libraries
libs: [
+ "mockito-robolectric-prebuilt",
"platform-test-annotations",
"testng",
+ "truth-prebuilt",
],
instrumentation_for: "BackupFrameworksServicesLib",
diff --git a/services/robotests/backup/src/com/android/server/backup/BackupManagerServiceTest.java b/services/robotests/backup/src/com/android/server/backup/BackupManagerServiceRoboTest.java
index 0cb21d014054..a1bfcdf4bdfa 100644
--- a/services/robotests/backup/src/com/android/server/backup/BackupManagerServiceTest.java
+++ b/services/robotests/backup/src/com/android/server/backup/BackupManagerServiceRoboTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2018 The Android Open Source Project
+ * 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.
@@ -21,14 +21,17 @@ import static android.Manifest.permission.DUMP;
import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL;
import static android.Manifest.permission.PACKAGE_USAGE_STATS;
-import static com.android.server.backup.testing.BackupManagerServiceTestUtils.startBackupThread;
import static com.android.server.backup.testing.TransportData.backupTransport;
import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertEquals;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.robolectric.Shadows.shadowOf;
import static org.testng.Assert.expectThrows;
@@ -43,15 +46,19 @@ import android.content.Context;
import android.content.Intent;
import android.os.IBinder;
import android.os.ParcelFileDescriptor;
+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.backup.testing.TransportData;
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.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -60,6 +67,7 @@ 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;
import java.io.File;
@@ -68,23 +76,32 @@ import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
-/** Tests for the user-aware backup/restore system service {@link BackupManagerService}. */
+/** Tests for {@link BackupManagerService}. */
@RunWith(RobolectricTestRunner.class)
-@Config(shadows = {ShadowApplicationPackageManager.class, ShadowBinder.class})
+@Config(
+ shadows = {
+ ShadowApplicationPackageManager.class,
+ ShadowBinder.class,
+ ShadowUserManager.class,
+ ShadowEnvironment.class,
+ ShadowSystemServiceRegistry.class
+ })
@Presubmit
-public class BackupManagerServiceTest {
+public class BackupManagerServiceRoboTest {
private static final String TEST_PACKAGE = "package";
private static final String TEST_TRANSPORT = "transport";
private static final String[] ADB_TEST_PACKAGES = {TEST_PACKAGE};
- private ShadowContextWrapper mShadowContext;
private Context mContext;
+ private ShadowContextWrapper mShadowContext;
+ private ShadowUserManager mShadowUserManager;
@UserIdInt private int mUserOneId;
@UserIdInt private int mUserTwoId;
+ @Mock private UserBackupManagerService mUserSystemService;
@Mock private UserBackupManagerService mUserOneService;
@Mock private UserBackupManagerService mUserTwoService;
- /** Initialize {@link BackupManagerService}. */
+ /** Setup */
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
@@ -92,79 +109,28 @@ public class BackupManagerServiceTest {
Application application = RuntimeEnvironment.application;
mContext = application;
mShadowContext = shadowOf(application);
+ mShadowUserManager = Shadow.extract(UserManager.get(application));
mUserOneId = UserHandle.USER_SYSTEM + 1;
mUserTwoId = mUserOneId + 1;
- }
-
- /**
- * Clean up and reset state that was created for testing {@link BackupManagerService}
- * operations.
- */
- @After
- public void tearDown() throws Exception {
- ShadowBinder.reset();
- }
+ mShadowUserManager.addUser(mUserOneId, "mUserOneId", 0);
+ mShadowUserManager.addUser(mUserTwoId, "mUserTwoId", 0);
- /**
- * Test verifying that {@link BackupManagerService#MORE_DEBUG} is set to {@code false}. This is
- * specifically to prevent overloading the logs in production.
- */
- @Test
- public void testMoreDebug_isFalse() throws Exception {
- boolean moreDebug = BackupManagerService.MORE_DEBUG;
-
- assertThat(moreDebug).isFalse();
- }
-
- /** Test that the constructor does not create {@link UserBackupManagerService} instances. */
- @Test
- public void testConstructor_doesNotRegisterUsers() throws Exception {
- BackupManagerService backupManagerService = createService();
-
- assertThat(backupManagerService.getServiceUsers().size()).isEqualTo(0);
- }
-
- /** Test that the constructor handles {@code null} parameters. */
- @Test
- public void testConstructor_withNullContext_throws() throws Exception {
- expectThrows(
- NullPointerException.class,
- () ->
- new BackupManagerService(
- /* context */ null,
- new Trampoline(mContext),
- startBackupThread(null)));
- }
-
- /** Test that the constructor handles {@code null} parameters. */
- @Test
- public void testConstructor_withNullTrampoline_throws() throws Exception {
- expectThrows(
- NullPointerException.class,
- () ->
- new BackupManagerService(
- mContext, /* trampoline */ null, startBackupThread(null)));
- }
+ mShadowContext.grantPermissions(BACKUP);
+ mShadowContext.grantPermissions(INTERACT_ACROSS_USERS_FULL);
- /** Test that the constructor handles {@code null} parameters. */
- @Test
- public void testConstructor_withNullBackupThread_throws() throws Exception {
- expectThrows(
- NullPointerException.class,
- () ->
- new BackupManagerService(
- mContext, new Trampoline(mContext), /* backupThread */ null));
+ ShadowBinder.setCallingUid(Process.SYSTEM_UID);
}
/** Test that the service registers users. */
@Test
public void testStartServiceForUser_registersUser() throws Exception {
BackupManagerService backupManagerService = createService();
+ backupManagerService.setBackupServiceActive(mUserOneId, true);
backupManagerService.startServiceForUser(mUserOneId);
- SparseArray<UserBackupManagerService> serviceUsers = backupManagerService.getServiceUsers();
+ SparseArray<UserBackupManagerService> serviceUsers = backupManagerService.getUserServices();
assertThat(serviceUsers.size()).isEqualTo(1);
assertThat(serviceUsers.get(mUserOneId)).isNotNull();
}
@@ -173,10 +139,11 @@ public class BackupManagerServiceTest {
@Test
public void testStartServiceForUser_withServiceInstance_registersUser() throws Exception {
BackupManagerService backupManagerService = createService();
+ backupManagerService.setBackupServiceActive(mUserOneId, true);
backupManagerService.startServiceForUser(mUserOneId, mUserOneService);
- SparseArray<UserBackupManagerService> serviceUsers = backupManagerService.getServiceUsers();
+ SparseArray<UserBackupManagerService> serviceUsers = backupManagerService.getUserServices();
assertThat(serviceUsers.size()).isEqualTo(1);
assertThat(serviceUsers.get(mUserOneId)).isEqualTo(mUserOneService);
}
@@ -187,10 +154,11 @@ public class BackupManagerServiceTest {
BackupManagerService backupManagerService =
createServiceAndRegisterUser(mUserOneId, mUserOneService);
backupManagerService.startServiceForUser(mUserTwoId, mUserTwoService);
+ ShadowBinder.setCallingUid(Process.SYSTEM_UID);
backupManagerService.stopServiceForUser(mUserOneId);
- SparseArray<UserBackupManagerService> serviceUsers = backupManagerService.getServiceUsers();
+ SparseArray<UserBackupManagerService> serviceUsers = backupManagerService.getUserServices();
assertThat(serviceUsers.size()).isEqualTo(1);
assertThat(serviceUsers.get(mUserOneId)).isNull();
assertThat(serviceUsers.get(mUserTwoId)).isEqualTo(mUserTwoService);
@@ -201,6 +169,7 @@ public class BackupManagerServiceTest {
public void testStopServiceForUser_forRegisteredUser_tearsDownCorrectUser() throws Exception {
BackupManagerService backupManagerService =
createServiceAndRegisterUser(mUserOneId, mUserOneService);
+ backupManagerService.setBackupServiceActive(mUserTwoId, true);
backupManagerService.startServiceForUser(mUserTwoId, mUserTwoService);
backupManagerService.stopServiceForUser(mUserOneId);
@@ -213,60 +182,15 @@ public class BackupManagerServiceTest {
@Test
public void testStopServiceForUser_forUnknownUser_doesNothing() throws Exception {
BackupManagerService backupManagerService = createService();
+ backupManagerService.setBackupServiceActive(mUserOneId, true);
+ ShadowBinder.setCallingUid(Process.SYSTEM_UID);
backupManagerService.stopServiceForUser(mUserOneId);
- SparseArray<UserBackupManagerService> serviceUsers = backupManagerService.getServiceUsers();
+ SparseArray<UserBackupManagerService> serviceUsers = backupManagerService.getUserServices();
assertThat(serviceUsers.size()).isEqualTo(0);
}
- /**
- * Test that the backup services throws a {@link SecurityException} if the caller does not have
- * INTERACT_ACROSS_USERS_FULL permission and passes a different user id.
- */
- @Test
- public void testGetServiceForUser_withoutPermission_throwsSecurityExceptionForNonCallingUser() {
- BackupManagerService backupManagerService =
- createServiceAndRegisterUser(mUserOneId, mUserOneService);
- setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false);
-
- expectThrows(
- SecurityException.class,
- () ->
- backupManagerService.getServiceForUserIfCallerHasPermission(
- mUserOneId, "test"));
- }
-
- /**
- * Test that the backup services does not throw a {@link SecurityException} if the caller has
- * INTERACT_ACROSS_USERS_FULL permission and passes a different user id.
- */
- @Test
- public void testGetServiceForUserIfCallerHasPermission_withPermission_worksForNonCallingUser() {
- BackupManagerService backupManagerService =
- createServiceAndRegisterUser(mUserOneId, mUserOneService);
- setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ true);
-
- assertEquals(
- mUserOneService,
- backupManagerService.getServiceForUserIfCallerHasPermission(mUserOneId, "test"));
- }
-
- /**
- * Test that the backup services does not throw a {@link SecurityException} if the caller does
- * not have INTERACT_ACROSS_USERS_FULL permission and passes in the calling user id.
- */
- @Test
- public void testGetServiceForUserIfCallerHasPermission_withoutPermission_worksForCallingUser() {
- BackupManagerService backupManagerService =
- createServiceAndRegisterUser(mUserOneId, mUserOneService);
- setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false);
-
- assertEquals(
- mUserOneService,
- backupManagerService.getServiceForUserIfCallerHasPermission(mUserOneId, "test"));
- }
-
// ---------------------------------------------
// Backup agent tests
// ---------------------------------------------
@@ -274,8 +198,8 @@ public class BackupManagerServiceTest {
/** Test that the backup service routes methods correctly to the user that requests it. */
@Test
public void testDataChanged_onRegisteredUser_callsMethodForUser() throws Exception {
- BackupManagerService backupManagerService =
- createServiceAndRegisterUser(mUserOneId, mUserOneService);
+ BackupManagerService backupManagerService = createService();
+ registerUser(backupManagerService, mUserOneId, mUserOneService);
setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false);
backupManagerService.dataChanged(mUserOneId, TEST_PACKAGE);
@@ -286,8 +210,8 @@ public class BackupManagerServiceTest {
/** Test that the backup service does not route methods for non-registered users. */
@Test
public void testDataChanged_onUnknownUser_doesNotPropagateCall() throws Exception {
- BackupManagerService backupManagerService =
- createServiceAndRegisterUser(mUserOneId, mUserOneService);
+ BackupManagerService backupManagerService = createService();
+ registerUser(backupManagerService, mUserOneId, mUserOneService);
setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false);
backupManagerService.dataChanged(mUserTwoId, TEST_PACKAGE);
@@ -298,8 +222,8 @@ public class BackupManagerServiceTest {
/** Test that the backup service routes methods correctly to the user that requests it. */
@Test
public void testAgentConnected_onRegisteredUser_callsMethodForUser() throws Exception {
- BackupManagerService backupManagerService =
- createServiceAndRegisterUser(mUserOneId, mUserOneService);
+ BackupManagerService backupManagerService = createService();
+ registerUser(backupManagerService, mUserOneId, mUserOneService);
setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false);
IBinder agentBinder = mock(IBinder.class);
@@ -311,8 +235,8 @@ public class BackupManagerServiceTest {
/** Test that the backup service does not route methods for non-registered users. */
@Test
public void testAgentConnected_onUnknownUser_doesNotPropagateCall() throws Exception {
- BackupManagerService backupManagerService =
- createServiceAndRegisterUser(mUserOneId, mUserOneService);
+ BackupManagerService backupManagerService = createService();
+ registerUser(backupManagerService, mUserOneId, mUserOneService);
setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false);
IBinder agentBinder = mock(IBinder.class);
@@ -323,33 +247,9 @@ public class BackupManagerServiceTest {
/** Test that the backup service routes methods correctly to the user that requests it. */
@Test
- public void testAgentDisconnected_onRegisteredUser_callsMethodForUser() throws Exception {
- BackupManagerService backupManagerService =
- createServiceAndRegisterUser(mUserOneId, mUserOneService);
- setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false);
-
- backupManagerService.agentDisconnected(mUserOneId, TEST_PACKAGE);
-
- verify(mUserOneService).agentDisconnected(TEST_PACKAGE);
- }
-
- /** Test that the backup service does not route methods for non-registered users. */
- @Test
- public void testAgentDisconnected_onUnknownUser_doesNotPropagateCall() throws Exception {
- BackupManagerService backupManagerService =
- createServiceAndRegisterUser(mUserOneId, mUserOneService);
- setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false);
-
- backupManagerService.agentDisconnected(mUserTwoId, TEST_PACKAGE);
-
- verify(mUserOneService, never()).agentDisconnected(TEST_PACKAGE);
- }
-
- /** Test that the backup service routes methods correctly to the user that requests it. */
- @Test
public void testOpComplete_onRegisteredUser_callsMethodForUser() throws Exception {
- BackupManagerService backupManagerService =
- createServiceAndRegisterUser(mUserOneId, mUserOneService);
+ BackupManagerService backupManagerService = createService();
+ registerUser(backupManagerService, mUserOneId, mUserOneService);
setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false);
backupManagerService.opComplete(mUserOneId, /* token */ 0, /* result */ 0L);
@@ -360,8 +260,8 @@ public class BackupManagerServiceTest {
/** Test that the backup service does not route methods for non-registered users. */
@Test
public void testOpComplete_onUnknownUser_doesNotPropagateCall() throws Exception {
- BackupManagerService backupManagerService =
- createServiceAndRegisterUser(mUserOneId, mUserOneService);
+ BackupManagerService backupManagerService = createService();
+ registerUser(backupManagerService, mUserOneId, mUserOneService);
setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false);
backupManagerService.opComplete(mUserTwoId, /* token */ 0, /* result */ 0L);
@@ -376,8 +276,8 @@ public class BackupManagerServiceTest {
/** Test that the backup service routes methods correctly to the user that requests it. */
@Test
public void testInitializeTransports_onRegisteredUser_callsMethodForUser() throws Exception {
- BackupManagerService backupManagerService =
- createServiceAndRegisterUser(mUserOneId, mUserOneService);
+ BackupManagerService backupManagerService = createService();
+ registerUser(backupManagerService, mUserOneId, mUserOneService);
setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false);
String[] transports = {TEST_TRANSPORT};
@@ -389,8 +289,8 @@ public class BackupManagerServiceTest {
/** Test that the backup service does not route methods for non-registered users. */
@Test
public void testInitializeTransports_onUnknownUser_doesNotPropagateCall() throws Exception {
- BackupManagerService backupManagerService =
- createServiceAndRegisterUser(mUserOneId, mUserOneService);
+ BackupManagerService backupManagerService = createService();
+ registerUser(backupManagerService, mUserOneId, mUserOneService);
setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false);
String[] transports = {TEST_TRANSPORT};
@@ -402,8 +302,8 @@ public class BackupManagerServiceTest {
/** Test that the backup service routes methods correctly to the user that requests it. */
@Test
public void testClearBackupData_onRegisteredUser_callsMethodForUser() throws Exception {
- BackupManagerService backupManagerService =
- createServiceAndRegisterUser(mUserOneId, mUserOneService);
+ BackupManagerService backupManagerService = createService();
+ registerUser(backupManagerService, mUserOneId, mUserOneService);
setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false);
backupManagerService.clearBackupData(mUserOneId, TEST_TRANSPORT, TEST_PACKAGE);
@@ -414,8 +314,8 @@ public class BackupManagerServiceTest {
/** Test that the backup service does not route methods for non-registered users. */
@Test
public void testClearBackupData_onUnknownUser_doesNotPropagateCall() throws Exception {
- BackupManagerService backupManagerService =
- createServiceAndRegisterUser(mUserOneId, mUserOneService);
+ BackupManagerService backupManagerService = createService();
+ registerUser(backupManagerService, mUserOneId, mUserOneService);
setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false);
backupManagerService.clearBackupData(mUserTwoId, TEST_TRANSPORT, TEST_PACKAGE);
@@ -426,8 +326,8 @@ public class BackupManagerServiceTest {
/** Test that the backup service routes methods correctly to the user that requests it. */
@Test
public void testGetCurrentTransport_onRegisteredUser_callsMethodForUser() throws Exception {
- BackupManagerService backupManagerService =
- createServiceAndRegisterUser(mUserOneId, mUserOneService);
+ BackupManagerService backupManagerService = createService();
+ registerUser(backupManagerService, mUserOneId, mUserOneService);
setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false);
backupManagerService.getCurrentTransport(mUserOneId);
@@ -438,8 +338,8 @@ public class BackupManagerServiceTest {
/** Test that the backup service does not route methods for non-registered users. */
@Test
public void testGetCurrentTransport_onUnknownUser_doesNotPropagateCall() throws Exception {
- BackupManagerService backupManagerService =
- createServiceAndRegisterUser(mUserOneId, mUserOneService);
+ BackupManagerService backupManagerService = createService();
+ registerUser(backupManagerService, mUserOneId, mUserOneService);
setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false);
backupManagerService.getCurrentTransport(mUserTwoId);
@@ -451,8 +351,8 @@ public class BackupManagerServiceTest {
@Test
public void testGetCurrentTransportComponent_onRegisteredUser_callsMethodForUser()
throws Exception {
- BackupManagerService backupManagerService =
- createServiceAndRegisterUser(mUserOneId, mUserOneService);
+ BackupManagerService backupManagerService = createService();
+ registerUser(backupManagerService, mUserOneId, mUserOneService);
setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false);
backupManagerService.getCurrentTransportComponent(mUserOneId);
@@ -464,8 +364,8 @@ public class BackupManagerServiceTest {
@Test
public void testGetCurrentTransportComponent_onUnknownUser_doesNotPropagateCall()
throws Exception {
- BackupManagerService backupManagerService =
- createServiceAndRegisterUser(mUserOneId, mUserOneService);
+ BackupManagerService backupManagerService = createService();
+ registerUser(backupManagerService, mUserOneId, mUserOneService);
setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false);
backupManagerService.getCurrentTransportComponent(mUserTwoId);
@@ -476,8 +376,8 @@ public class BackupManagerServiceTest {
/** Test that the backup service routes methods correctly to the user that requests it. */
@Test
public void testListAllTransports_onRegisteredUser_callsMethodForUser() throws Exception {
- BackupManagerService backupManagerService =
- createServiceAndRegisterUser(mUserOneId, mUserOneService);
+ BackupManagerService backupManagerService = createService();
+ registerUser(backupManagerService, mUserOneId, mUserOneService);
setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false);
backupManagerService.listAllTransports(mUserOneId);
@@ -488,8 +388,8 @@ public class BackupManagerServiceTest {
/** Test that the backup service does not route methods for non-registered users. */
@Test
public void testListAllTransports_onUnknownUser_doesNotPropagateCall() throws Exception {
- BackupManagerService backupManagerService =
- createServiceAndRegisterUser(mUserOneId, mUserOneService);
+ BackupManagerService backupManagerService = createService();
+ registerUser(backupManagerService, mUserOneId, mUserOneService);
setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false);
backupManagerService.listAllTransports(mUserTwoId);
@@ -501,8 +401,8 @@ public class BackupManagerServiceTest {
@Test
public void testListAllTransportComponents_onRegisteredUser_callsMethodForUser()
throws Exception {
- BackupManagerService backupManagerService =
- createServiceAndRegisterUser(mUserOneId, mUserOneService);
+ BackupManagerService backupManagerService = createService();
+ registerUser(backupManagerService, mUserOneId, mUserOneService);
setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false);
backupManagerService.listAllTransportComponents(mUserOneId);
@@ -514,8 +414,8 @@ public class BackupManagerServiceTest {
@Test
public void testListAllTransportComponents_onUnknownUser_doesNotPropagateCall()
throws Exception {
- BackupManagerService backupManagerService =
- createServiceAndRegisterUser(mUserOneId, mUserOneService);
+ BackupManagerService backupManagerService = createService();
+ registerUser(backupManagerService, mUserOneId, mUserOneService);
setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false);
backupManagerService.listAllTransportComponents(mUserTwoId);
@@ -525,69 +425,9 @@ public class BackupManagerServiceTest {
/** Test that the backup service routes methods correctly to the user that requests it. */
@Test
- public void testUpdateTransportAttributes_onRegisteredUser_callsMethodForUser()
- throws Exception {
- BackupManagerService backupManagerService =
- createServiceAndRegisterUser(mUserOneId, mUserOneService);
- setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false);
- TransportData transport = backupTransport();
- Intent configurationIntent = new Intent();
- Intent dataManagementIntent = new Intent();
-
- backupManagerService.updateTransportAttributes(
- mUserOneId,
- transport.getTransportComponent(),
- transport.transportName,
- configurationIntent,
- "currentDestinationString",
- dataManagementIntent,
- "dataManagementLabel");
-
- verify(mUserOneService)
- .updateTransportAttributes(
- transport.getTransportComponent(),
- transport.transportName,
- configurationIntent,
- "currentDestinationString",
- dataManagementIntent,
- "dataManagementLabel");
- }
-
- /** Test that the backup service does not route methods for non-registered users. */
- @Test
- public void testUpdateTransportAttributes_onUnknownUser_doesNotPropagateCall()
- throws Exception {
- BackupManagerService backupManagerService =
- createServiceAndRegisterUser(mUserOneId, mUserOneService);
- setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false);
- TransportData transport = backupTransport();
- Intent configurationIntent = new Intent();
- Intent dataManagementIntent = new Intent();
-
- backupManagerService.updateTransportAttributes(
- mUserTwoId,
- transport.getTransportComponent(),
- transport.transportName,
- configurationIntent,
- "currentDestinationString",
- dataManagementIntent,
- "dataManagementLabel");
-
- verify(mUserOneService, never())
- .updateTransportAttributes(
- transport.getTransportComponent(),
- transport.transportName,
- configurationIntent,
- "currentDestinationString",
- dataManagementIntent,
- "dataManagementLabel");
- }
-
- /** Test that the backup service routes methods correctly to the user that requests it. */
- @Test
public void testSelectBackupTransport_onRegisteredUser_callsMethodForUser() throws Exception {
- BackupManagerService backupManagerService =
- createServiceAndRegisterUser(mUserOneId, mUserOneService);
+ BackupManagerService backupManagerService = createService();
+ registerUser(backupManagerService, mUserOneId, mUserOneService);
setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false);
backupManagerService.selectBackupTransport(mUserOneId, TEST_TRANSPORT);
@@ -598,8 +438,8 @@ public class BackupManagerServiceTest {
/** Test that the backup service does not route methods for non-registered users. */
@Test
public void testSelectBackupTransport_onUnknownUser_doesNotPropagateCall() throws Exception {
- BackupManagerService backupManagerService =
- createServiceAndRegisterUser(mUserOneId, mUserOneService);
+ BackupManagerService backupManagerService = createService();
+ registerUser(backupManagerService, mUserOneId, mUserOneService);
setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false);
backupManagerService.selectBackupTransport(mUserTwoId, TEST_TRANSPORT);
@@ -610,8 +450,8 @@ public class BackupManagerServiceTest {
/** Test that the backup service routes methods correctly to the user that requests it. */
@Test
public void testSelectTransportAsync_onRegisteredUser_callsMethodForUser() throws Exception {
- BackupManagerService backupManagerService =
- createServiceAndRegisterUser(mUserOneId, mUserOneService);
+ BackupManagerService backupManagerService = createService();
+ registerUser(backupManagerService, mUserOneId, mUserOneService);
setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false);
TransportData transport = backupTransport();
ISelectBackupTransportCallback callback = mock(ISelectBackupTransportCallback.class);
@@ -627,8 +467,8 @@ public class BackupManagerServiceTest {
@Test
public void testSelectBackupTransportAsync_onUnknownUser_doesNotPropagateCall()
throws Exception {
- BackupManagerService backupManagerService =
- createServiceAndRegisterUser(mUserOneId, mUserOneService);
+ BackupManagerService backupManagerService = createService();
+ registerUser(backupManagerService, mUserOneId, mUserOneService);
setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false);
TransportData transport = backupTransport();
ISelectBackupTransportCallback callback = mock(ISelectBackupTransportCallback.class);
@@ -643,8 +483,8 @@ public class BackupManagerServiceTest {
/** Test that the backup service routes methods correctly to the user that requests it. */
@Test
public void testGetConfigurationIntent_onRegisteredUser_callsMethodForUser() throws Exception {
- BackupManagerService backupManagerService =
- createServiceAndRegisterUser(mUserOneId, mUserOneService);
+ BackupManagerService backupManagerService = createService();
+ registerUser(backupManagerService, mUserOneId, mUserOneService);
setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false);
backupManagerService.getConfigurationIntent(mUserOneId, TEST_TRANSPORT);
@@ -655,8 +495,8 @@ public class BackupManagerServiceTest {
/** Test that the backup service does not route methods for non-registered users. */
@Test
public void testGetConfigurationIntent_onUnknownUser_doesNotPropagateCall() throws Exception {
- BackupManagerService backupManagerService =
- createServiceAndRegisterUser(mUserOneId, mUserOneService);
+ BackupManagerService backupManagerService = createService();
+ registerUser(backupManagerService, mUserOneId, mUserOneService);
setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false);
backupManagerService.getConfigurationIntent(mUserTwoId, TEST_TRANSPORT);
@@ -667,8 +507,8 @@ public class BackupManagerServiceTest {
/** Test that the backup service routes methods correctly to the user that requests it. */
@Test
public void testGetDestinationString_onRegisteredUser_callsMethodForUser() throws Exception {
- BackupManagerService backupManagerService =
- createServiceAndRegisterUser(mUserOneId, mUserOneService);
+ BackupManagerService backupManagerService = createService();
+ registerUser(backupManagerService, mUserOneId, mUserOneService);
setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false);
backupManagerService.getDestinationString(mUserOneId, TEST_TRANSPORT);
@@ -679,8 +519,8 @@ public class BackupManagerServiceTest {
/** Test that the backup service does not route methods for non-registered users. */
@Test
public void testGetDestinationString_onUnknownUser_doesNotPropagateCall() throws Exception {
- BackupManagerService backupManagerService =
- createServiceAndRegisterUser(mUserOneId, mUserOneService);
+ BackupManagerService backupManagerService = createService();
+ registerUser(backupManagerService, mUserOneId, mUserOneService);
setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false);
backupManagerService.getDestinationString(mUserTwoId, TEST_TRANSPORT);
@@ -691,8 +531,8 @@ public class BackupManagerServiceTest {
/** Test that the backup service routes methods correctly to the user that requests it. */
@Test
public void testGetDataManagementIntent_onRegisteredUser_callsMethodForUser() throws Exception {
- BackupManagerService backupManagerService =
- createServiceAndRegisterUser(mUserOneId, mUserOneService);
+ BackupManagerService backupManagerService = createService();
+ registerUser(backupManagerService, mUserOneId, mUserOneService);
setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false);
backupManagerService.getDataManagementIntent(mUserOneId, TEST_TRANSPORT);
@@ -703,8 +543,8 @@ public class BackupManagerServiceTest {
/** Test that the backup service does not route methods for non-registered users. */
@Test
public void testGetDataManagementIntent_onUnknownUser_doesNotPropagateCall() throws Exception {
- BackupManagerService backupManagerService =
- createServiceAndRegisterUser(mUserOneId, mUserOneService);
+ BackupManagerService backupManagerService = createService();
+ registerUser(backupManagerService, mUserOneId, mUserOneService);
setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false);
backupManagerService.getDataManagementIntent(mUserTwoId, TEST_TRANSPORT);
@@ -715,8 +555,8 @@ public class BackupManagerServiceTest {
/** Test that the backup service routes methods correctly to the user that requests it. */
@Test
public void testGetDataManagementLabel_onRegisteredUser_callsMethodForUser() throws Exception {
- BackupManagerService backupManagerService =
- createServiceAndRegisterUser(mUserOneId, mUserOneService);
+ BackupManagerService backupManagerService = createService();
+ registerUser(backupManagerService, mUserOneId, mUserOneService);
setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false);
backupManagerService.getDataManagementLabel(mUserOneId, TEST_TRANSPORT);
@@ -727,8 +567,8 @@ public class BackupManagerServiceTest {
/** Test that the backup service does not route methods for non-registered users. */
@Test
public void testGetDataManagementLabel_onUnknownUser_doesNotPropagateCall() throws Exception {
- BackupManagerService backupManagerService =
- createServiceAndRegisterUser(mUserOneId, mUserOneService);
+ BackupManagerService backupManagerService = createService();
+ registerUser(backupManagerService, mUserOneId, mUserOneService);
setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false);
backupManagerService.getDataManagementLabel(mUserTwoId, TEST_TRANSPORT);
@@ -736,17 +576,78 @@ public class BackupManagerServiceTest {
verify(mUserOneService, never()).getDataManagementLabel(TEST_TRANSPORT);
}
+ /** Test that the backup service routes methods correctly to the user that requests it. */
+ @Test
+ public void testUpdateTransportAttributes_onRegisteredUser_callsMethodForUser()
+ throws Exception {
+ BackupManagerService backupManagerService = createService();
+ registerUser(backupManagerService, mUserOneId, mUserOneService);
+ setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false);
+ TransportData transport = backupTransport();
+ Intent configurationIntent = new Intent();
+ Intent dataManagementIntent = new Intent();
+
+ backupManagerService.updateTransportAttributes(
+ mUserOneId,
+ transport.getTransportComponent(),
+ transport.transportName,
+ configurationIntent,
+ "currentDestinationString",
+ dataManagementIntent,
+ "dataManagementLabel");
+
+ verify(mUserOneService)
+ .updateTransportAttributes(
+ transport.getTransportComponent(),
+ transport.transportName,
+ configurationIntent,
+ "currentDestinationString",
+ dataManagementIntent,
+ "dataManagementLabel");
+ }
+
+ /** Test that the backup service does not route methods for non-registered users. */
+ @Test
+ public void testUpdateTransportAttributes_onUnknownUser_doesNotPropagateCall()
+ throws Exception {
+ BackupManagerService backupManagerService = createService();
+ registerUser(backupManagerService, mUserOneId, mUserOneService);
+ setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false);
+ TransportData transport = backupTransport();
+ Intent configurationIntent = new Intent();
+ Intent dataManagementIntent = new Intent();
+
+ backupManagerService.updateTransportAttributes(
+ mUserTwoId,
+ transport.getTransportComponent(),
+ transport.transportName,
+ configurationIntent,
+ "currentDestinationString",
+ dataManagementIntent,
+ "dataManagementLabel");
+
+ verify(mUserOneService, never())
+ .updateTransportAttributes(
+ transport.getTransportComponent(),
+ transport.transportName,
+ configurationIntent,
+ "currentDestinationString",
+ dataManagementIntent,
+ "dataManagementLabel");
+ }
+
// ---------------------------------------------
// Settings tests
// ---------------------------------------------
+
/**
* Test that the backup services throws a {@link SecurityException} if the caller does not have
* INTERACT_ACROSS_USERS_FULL permission and passes a different user id.
*/
@Test
public void testSetBackupEnabled_withoutPermission_throwsSecurityExceptionForNonCallingUser() {
- BackupManagerService backupManagerService =
- createServiceAndRegisterUser(mUserOneId, mUserOneService);
+ BackupManagerService backupManagerService = createService();
+ registerUser(backupManagerService, mUserOneId, mUserOneService);
setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false);
expectThrows(
@@ -760,9 +661,10 @@ public class BackupManagerServiceTest {
*/
@Test
public void testSetBackupEnabled_withPermission_propagatesForNonCallingUser() {
- BackupManagerService backupManagerService =
- createServiceAndRegisterUser(mUserOneId, mUserOneService);
- backupManagerService.startServiceForUser(mUserTwoId, mUserTwoService);
+ BackupManagerService backupManagerService = createService();
+ registerUser(backupManagerService, mUserOneId, mUserOneService);
+ registerUser(backupManagerService, mUserTwoId, mUserTwoService);
+
setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ true);
backupManagerService.setBackupEnabled(mUserTwoId, true);
@@ -773,8 +675,8 @@ public class BackupManagerServiceTest {
/** Test that the backup service routes methods correctly to the user that requests it. */
@Test
public void testSetBackupEnabled_onRegisteredUser_callsMethodForUser() throws Exception {
- BackupManagerService backupManagerService =
- createServiceAndRegisterUser(mUserOneId, mUserOneService);
+ BackupManagerService backupManagerService = createService();
+ registerUser(backupManagerService, mUserOneId, mUserOneService);
setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false);
backupManagerService.setBackupEnabled(mUserOneId, true);
@@ -785,8 +687,8 @@ public class BackupManagerServiceTest {
/** Test that the backup service does not route methods for non-registered users. */
@Test
public void testSetBackupEnabled_onUnknownUser_doesNotPropagateCall() throws Exception {
- BackupManagerService backupManagerService =
- createServiceAndRegisterUser(mUserOneId, mUserOneService);
+ BackupManagerService backupManagerService = createService();
+ registerUser(backupManagerService, mUserOneId, mUserOneService);
setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false);
backupManagerService.setBackupEnabled(mUserTwoId, true);
@@ -797,8 +699,8 @@ public class BackupManagerServiceTest {
/** Test that the backup service routes methods correctly to the user that requests it. */
@Test
public void testSetAutoRestore_onRegisteredUser_callsMethodForUser() throws Exception {
- BackupManagerService backupManagerService =
- createServiceAndRegisterUser(mUserOneId, mUserOneService);
+ BackupManagerService backupManagerService = createService();
+ registerUser(backupManagerService, mUserOneId, mUserOneService);
setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false);
backupManagerService.setAutoRestore(mUserOneId, true);
@@ -809,8 +711,8 @@ public class BackupManagerServiceTest {
/** Test that the backup service does not route methods for non-registered users. */
@Test
public void testSetAutoRestore_onUnknownUser_doesNotPropagateCall() throws Exception {
- BackupManagerService backupManagerService =
- createServiceAndRegisterUser(mUserOneId, mUserOneService);
+ BackupManagerService backupManagerService = createService();
+ registerUser(backupManagerService, mUserOneId, mUserOneService);
setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false);
backupManagerService.setAutoRestore(mUserTwoId, true);
@@ -821,8 +723,8 @@ public class BackupManagerServiceTest {
/** Test that the backup service routes methods correctly to the user that requests it. */
@Test
public void testIsBackupEnabled_onRegisteredUser_callsMethodForUser() throws Exception {
- BackupManagerService backupManagerService =
- createServiceAndRegisterUser(mUserOneId, mUserOneService);
+ BackupManagerService backupManagerService = createService();
+ registerUser(backupManagerService, mUserOneId, mUserOneService);
setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false);
backupManagerService.isBackupEnabled(mUserOneId);
@@ -833,8 +735,8 @@ public class BackupManagerServiceTest {
/** Test that the backup service does not route methods for non-registered users. */
@Test
public void testIsBackupEnabled_onUnknownUser_doesNotPropagateCall() throws Exception {
- BackupManagerService backupManagerService =
- createServiceAndRegisterUser(mUserOneId, mUserOneService);
+ BackupManagerService backupManagerService = createService();
+ registerUser(backupManagerService, mUserOneId, mUserOneService);
setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false);
backupManagerService.isBackupEnabled(mUserTwoId);
@@ -849,8 +751,8 @@ public class BackupManagerServiceTest {
/** Test that the backup service routes methods correctly to the user that requests it. */
@Test
public void testIsAppEligibleForBackup_onRegisteredUser_callsMethodForUser() throws Exception {
- BackupManagerService backupManagerService =
- createServiceAndRegisterUser(mUserOneId, mUserOneService);
+ BackupManagerService backupManagerService = createService();
+ registerUser(backupManagerService, mUserOneId, mUserOneService);
setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false);
backupManagerService.isAppEligibleForBackup(mUserOneId, TEST_PACKAGE);
@@ -861,8 +763,8 @@ public class BackupManagerServiceTest {
/** Test that the backup service does not route methods for non-registered users. */
@Test
public void testIsAppEligibleForBackup_onUnknownUser_doesNotPropagateCall() throws Exception {
- BackupManagerService backupManagerService =
- createServiceAndRegisterUser(mUserOneId, mUserOneService);
+ BackupManagerService backupManagerService = createService();
+ registerUser(backupManagerService, mUserOneId, mUserOneService);
setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false);
backupManagerService.isAppEligibleForBackup(mUserTwoId, TEST_PACKAGE);
@@ -874,8 +776,8 @@ public class BackupManagerServiceTest {
@Test
public void testFilterAppsEligibleForBackup_onRegisteredUser_callsMethodForUser()
throws Exception {
- BackupManagerService backupManagerService =
- createServiceAndRegisterUser(mUserOneId, mUserOneService);
+ BackupManagerService backupManagerService = createService();
+ registerUser(backupManagerService, mUserOneId, mUserOneService);
setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false);
String[] packages = {TEST_PACKAGE};
@@ -888,8 +790,8 @@ public class BackupManagerServiceTest {
@Test
public void testFilterAppsEligibleForBackup_onUnknownUser_doesNotPropagateCall()
throws Exception {
- BackupManagerService backupManagerService =
- createServiceAndRegisterUser(mUserOneId, mUserOneService);
+ BackupManagerService backupManagerService = createService();
+ registerUser(backupManagerService, mUserOneId, mUserOneService);
setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false);
String[] packages = {TEST_PACKAGE};
@@ -904,8 +806,8 @@ public class BackupManagerServiceTest {
*/
@Test
public void testBackupNow_withoutPermission_throwsSecurityExceptionForNonCallingUser() {
- BackupManagerService backupManagerService =
- createServiceAndRegisterUser(mUserOneId, mUserOneService);
+ BackupManagerService backupManagerService = createService();
+ registerUser(backupManagerService, mUserOneId, mUserOneService);
setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false);
expectThrows(SecurityException.class, () -> backupManagerService.backupNow(mUserTwoId));
@@ -917,9 +819,10 @@ public class BackupManagerServiceTest {
*/
@Test
public void testBackupNow_withPermission_propagatesForNonCallingUser() {
- BackupManagerService backupManagerService =
- createServiceAndRegisterUser(mUserOneId, mUserOneService);
- backupManagerService.startServiceForUser(mUserTwoId, mUserTwoService);
+ BackupManagerService backupManagerService = createService();
+ registerUser(backupManagerService, mUserOneId, mUserOneService);
+ registerUser(backupManagerService, mUserTwoId, mUserTwoService);
+
setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ true);
backupManagerService.backupNow(mUserTwoId);
@@ -930,8 +833,8 @@ public class BackupManagerServiceTest {
/** Test that the backup service routes methods correctly to the user that requests it. */
@Test
public void testBackupNow_onRegisteredUser_callsMethodForUser() throws Exception {
- BackupManagerService backupManagerService =
- createServiceAndRegisterUser(mUserOneId, mUserOneService);
+ BackupManagerService backupManagerService = createService();
+ registerUser(backupManagerService, mUserOneId, mUserOneService);
setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false);
backupManagerService.backupNow(mUserOneId);
@@ -942,8 +845,8 @@ public class BackupManagerServiceTest {
/** Test that the backup service does not route methods for non-registered users. */
@Test
public void testBackupNow_onUnknownUser_doesNotPropagateCall() throws Exception {
- BackupManagerService backupManagerService =
- createServiceAndRegisterUser(mUserOneId, mUserOneService);
+ BackupManagerService backupManagerService = createService();
+ registerUser(backupManagerService, mUserOneId, mUserOneService);
setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false);
backupManagerService.backupNow(mUserTwoId);
@@ -957,8 +860,8 @@ public class BackupManagerServiceTest {
*/
@Test
public void testRequestBackup_withoutPermission_throwsSecurityExceptionForNonCallingUser() {
- BackupManagerService backupManagerService =
- createServiceAndRegisterUser(mUserOneId, mUserOneService);
+ BackupManagerService backupManagerService = createService();
+ registerUser(backupManagerService, mUserOneId, mUserOneService);
setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false);
String[] packages = {TEST_PACKAGE};
IBackupObserver observer = mock(IBackupObserver.class);
@@ -977,9 +880,10 @@ public class BackupManagerServiceTest {
*/
@Test
public void testRequestBackup_withPermission_propagatesForNonCallingUser() {
- BackupManagerService backupManagerService =
- createServiceAndRegisterUser(mUserOneId, mUserOneService);
- backupManagerService.startServiceForUser(mUserTwoId, mUserTwoService);
+ BackupManagerService backupManagerService = createService();
+ registerUser(backupManagerService, mUserOneId, mUserOneService);
+ registerUser(backupManagerService, mUserTwoId, mUserTwoService);
+
String[] packages = {TEST_PACKAGE};
IBackupObserver observer = mock(IBackupObserver.class);
IBackupManagerMonitor monitor = mock(IBackupManagerMonitor.class);
@@ -993,8 +897,8 @@ public class BackupManagerServiceTest {
/** Test that the backup service routes methods correctly to the user that requests it. */
@Test
public void testRequestBackup_onRegisteredUser_callsMethodForUser() throws Exception {
- BackupManagerService backupManagerService =
- createServiceAndRegisterUser(mUserOneId, mUserOneService);
+ BackupManagerService backupManagerService = createService();
+ registerUser(backupManagerService, mUserOneId, mUserOneService);
String[] packages = {TEST_PACKAGE};
IBackupObserver observer = mock(IBackupObserver.class);
IBackupManagerMonitor monitor = mock(IBackupManagerMonitor.class);
@@ -1008,8 +912,8 @@ public class BackupManagerServiceTest {
/** Test that the backup service routes methods correctly to the user that requests it. */
@Test
public void testRequestBackup_onUnknownUser_doesNotPropagateCall() throws Exception {
- BackupManagerService backupManagerService =
- createServiceAndRegisterUser(mUserOneId, mUserOneService);
+ BackupManagerService backupManagerService = createService();
+ registerUser(backupManagerService, mUserOneId, mUserOneService);
String[] packages = {TEST_PACKAGE};
IBackupObserver observer = mock(IBackupObserver.class);
IBackupManagerMonitor monitor = mock(IBackupManagerMonitor.class);
@@ -1026,8 +930,8 @@ public class BackupManagerServiceTest {
*/
@Test
public void testCancelBackups_withoutPermission_throwsSecurityExceptionForNonCallingUser() {
- BackupManagerService backupManagerService =
- createServiceAndRegisterUser(mUserOneId, mUserOneService);
+ BackupManagerService backupManagerService = createService();
+ registerUser(backupManagerService, mUserOneId, mUserOneService);
setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false);
expectThrows(SecurityException.class, () -> backupManagerService.cancelBackups(mUserTwoId));
@@ -1039,9 +943,9 @@ public class BackupManagerServiceTest {
*/
@Test
public void testCancelBackups_withPermission_propagatesForNonCallingUser() {
- BackupManagerService backupManagerService =
- createServiceAndRegisterUser(mUserOneId, mUserOneService);
- backupManagerService.startServiceForUser(mUserTwoId, mUserTwoService);
+ BackupManagerService backupManagerService = createService();
+ registerUser(backupManagerService, mUserOneId, mUserOneService);
+ registerUser(backupManagerService, mUserTwoId, mUserTwoService);
setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ true);
backupManagerService.cancelBackups(mUserTwoId);
@@ -1052,8 +956,8 @@ public class BackupManagerServiceTest {
/** Test that the backup service routes methods correctly to the user that requests it. */
@Test
public void testCancelBackups_onRegisteredUser_callsMethodForUser() throws Exception {
- BackupManagerService backupManagerService =
- createServiceAndRegisterUser(mUserOneId, mUserOneService);
+ BackupManagerService backupManagerService = createService();
+ registerUser(backupManagerService, mUserOneId, mUserOneService);
setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false);
backupManagerService.cancelBackups(mUserOneId);
@@ -1064,8 +968,8 @@ public class BackupManagerServiceTest {
/** Test that the backup service does not route methods for non-registered users. */
@Test
public void testCancelBackups_onUnknownUser_doesNotPropagateCall() throws Exception {
- BackupManagerService backupManagerService =
- createServiceAndRegisterUser(mUserOneId, mUserOneService);
+ BackupManagerService backupManagerService = createService();
+ registerUser(backupManagerService, mUserOneId, mUserOneService);
setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false);
backupManagerService.cancelBackups(mUserTwoId);
@@ -1076,8 +980,8 @@ public class BackupManagerServiceTest {
/** Test that the backup service routes methods correctly to the user that requests it. */
@Test
public void testBeginFullBackup_onRegisteredUser_callsMethodForUser() throws Exception {
- BackupManagerService backupManagerService =
- createServiceAndRegisterUser(UserHandle.USER_SYSTEM, mUserOneService);
+ BackupManagerService backupManagerService = createService();
+ registerUser(backupManagerService, UserHandle.USER_SYSTEM, mUserOneService);
FullBackupJob job = new FullBackupJob();
backupManagerService.beginFullBackup(UserHandle.USER_SYSTEM, job);
@@ -1099,8 +1003,8 @@ public class BackupManagerServiceTest {
/** Test that the backup service routes methods correctly to the user that requests it. */
@Test
public void testEndFullBackup_onRegisteredUser_callsMethodForUser() throws Exception {
- BackupManagerService backupManagerService =
- createServiceAndRegisterUser(UserHandle.USER_SYSTEM, mUserOneService);
+ BackupManagerService backupManagerService = createService();
+ registerUser(backupManagerService, UserHandle.USER_SYSTEM, mUserOneService);
backupManagerService.endFullBackup(UserHandle.USER_SYSTEM);
@@ -1120,8 +1024,8 @@ public class BackupManagerServiceTest {
/** Test that the backup service routes methods correctly to the user that requests it. */
@Test
public void testFullTransportBackup_onRegisteredUser_callsMethodForUser() throws Exception {
- BackupManagerService backupManagerService =
- createServiceAndRegisterUser(mUserOneId, mUserOneService);
+ BackupManagerService backupManagerService = createService();
+ registerUser(backupManagerService, mUserOneId, mUserOneService);
setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false);
String[] packages = {TEST_PACKAGE};
@@ -1133,8 +1037,8 @@ public class BackupManagerServiceTest {
/** Test that the backup service does not route methods for non-registered users. */
@Test
public void testFullTransportBackup_onUnknownUser_doesNotPropagateCall() throws Exception {
- BackupManagerService backupManagerService =
- createServiceAndRegisterUser(mUserOneId, mUserOneService);
+ BackupManagerService backupManagerService = createService();
+ registerUser(backupManagerService, mUserOneId, mUserOneService);
setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false);
String[] packages = {TEST_PACKAGE};
@@ -1150,8 +1054,8 @@ public class BackupManagerServiceTest {
/** Test that the backup service routes methods correctly to the user that requests it. */
@Test
public void testRestoreAtInstall_onRegisteredUser_callsMethodForUser() throws Exception {
- BackupManagerService backupManagerService =
- createServiceAndRegisterUser(mUserOneId, mUserOneService);
+ BackupManagerService backupManagerService = createService();
+ registerUser(backupManagerService, mUserOneId, mUserOneService);
setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false);
backupManagerService.restoreAtInstall(mUserOneId, TEST_PACKAGE, /* token */ 0);
@@ -1162,8 +1066,8 @@ public class BackupManagerServiceTest {
/** Test that the backup service does not route methods for non-registered users. */
@Test
public void testRestoreAtInstall_onUnknownUser_doesNotPropagateCall() throws Exception {
- BackupManagerService backupManagerService =
- createServiceAndRegisterUser(mUserOneId, mUserOneService);
+ BackupManagerService backupManagerService = createService();
+ registerUser(backupManagerService, mUserOneId, mUserOneService);
setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false);
backupManagerService.restoreAtInstall(mUserTwoId, TEST_PACKAGE, /* token */ 0);
@@ -1174,8 +1078,8 @@ public class BackupManagerServiceTest {
/** Test that the backup service routes methods correctly to the user that requests it. */
@Test
public void testBeginRestoreSession_onRegisteredUser_callsMethodForUser() throws Exception {
- BackupManagerService backupManagerService =
- createServiceAndRegisterUser(mUserOneId, mUserOneService);
+ BackupManagerService backupManagerService = createService();
+ registerUser(backupManagerService, mUserOneId, mUserOneService);
setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false);
backupManagerService.beginRestoreSession(mUserOneId, TEST_PACKAGE, TEST_TRANSPORT);
@@ -1186,8 +1090,8 @@ public class BackupManagerServiceTest {
/** Test that the backup service does not route methods for non-registered users. */
@Test
public void testBeginRestoreSession_onUnknownUser_doesNotPropagateCall() throws Exception {
- BackupManagerService backupManagerService =
- createServiceAndRegisterUser(mUserOneId, mUserOneService);
+ BackupManagerService backupManagerService = createService();
+ registerUser(backupManagerService, mUserOneId, mUserOneService);
setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false);
backupManagerService.beginRestoreSession(mUserTwoId, TEST_PACKAGE, TEST_TRANSPORT);
@@ -1199,8 +1103,8 @@ public class BackupManagerServiceTest {
@Test
public void testGetAvailableRestoreToken_onRegisteredUser_callsMethodForUser()
throws Exception {
- BackupManagerService backupManagerService =
- createServiceAndRegisterUser(mUserOneId, mUserOneService);
+ BackupManagerService backupManagerService = createService();
+ registerUser(backupManagerService, mUserOneId, mUserOneService);
setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false);
backupManagerService.getAvailableRestoreToken(mUserOneId, TEST_PACKAGE);
@@ -1211,8 +1115,8 @@ public class BackupManagerServiceTest {
/** Test that the backup service does not route methods for non-registered users. */
@Test
public void testGetAvailableRestoreToken_onUnknownUser_doesNotPropagateCall() throws Exception {
- BackupManagerService backupManagerService =
- createServiceAndRegisterUser(mUserOneId, mUserOneService);
+ BackupManagerService backupManagerService = createService();
+ registerUser(backupManagerService, mUserOneId, mUserOneService);
setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false);
backupManagerService.getAvailableRestoreToken(mUserTwoId, TEST_PACKAGE);
@@ -1227,8 +1131,9 @@ public class BackupManagerServiceTest {
/** Test that the backup service routes methods correctly to the user that requests it. */
@Test
public void testSetBackupPassword_onRegisteredUser_callsMethodForUser() throws Exception {
- BackupManagerService backupManagerService =
- createServiceAndRegisterUser(UserHandle.USER_SYSTEM, mUserOneService);
+ BackupManagerService backupManagerService = createService();
+ registerUser(backupManagerService, UserHandle.USER_SYSTEM, mUserOneService);
+ ShadowBinder.setCallingUserHandle(UserHandle.of(UserHandle.USER_SYSTEM));
backupManagerService.setBackupPassword("currentPassword", "newPassword");
@@ -1248,8 +1153,9 @@ public class BackupManagerServiceTest {
/** Test that the backup service routes methods correctly to the user that requests it. */
@Test
public void testHasBackupPassword_onRegisteredUser_callsMethodForUser() throws Exception {
- BackupManagerService backupManagerService =
- createServiceAndRegisterUser(UserHandle.USER_SYSTEM, mUserOneService);
+ BackupManagerService backupManagerService = createService();
+ registerUser(backupManagerService, UserHandle.USER_SYSTEM, mUserOneService);
+ ShadowBinder.setCallingUserHandle(UserHandle.of(UserHandle.USER_SYSTEM));
backupManagerService.hasBackupPassword();
@@ -1272,8 +1178,9 @@ public class BackupManagerServiceTest {
*/
@Test
public void testAdbBackup_withoutPermission_throwsSecurityExceptionForNonCallingUser() {
- BackupManagerService backupManagerService =
- createServiceAndRegisterUser(mUserOneId, mUserOneService);
+ BackupManagerService backupManagerService = createSystemRegisteredService();
+ registerUser(backupManagerService, mUserOneId, mUserOneService);
+ registerUser(backupManagerService, mUserTwoId, mUserTwoService);
setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false);
expectThrows(
@@ -1299,9 +1206,10 @@ public class BackupManagerServiceTest {
*/
@Test
public void testAdbBackup_withPermission_propagatesForNonCallingUser() throws Exception {
- BackupManagerService backupManagerService =
- createServiceAndRegisterUser(mUserOneId, mUserOneService);
- backupManagerService.startServiceForUser(mUserTwoId, mUserTwoService);
+ BackupManagerService backupManagerService = createSystemRegisteredService();
+ registerUser(backupManagerService, mUserOneId, mUserOneService);
+ registerUser(backupManagerService, mUserTwoId, mUserTwoService);
+
ParcelFileDescriptor parcelFileDescriptor = getFileDescriptorForAdbTest();
setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ true);
@@ -1335,8 +1243,8 @@ public class BackupManagerServiceTest {
/** Test that the backup service routes methods correctly to the user that requests it. */
@Test
public void testAdbBackup_onRegisteredUser_callsMethodForUser() throws Exception {
- BackupManagerService backupManagerService =
- createServiceAndRegisterUser(mUserOneId, mUserOneService);
+ BackupManagerService backupManagerService = createSystemRegisteredService();
+ registerUser(backupManagerService, mUserOneId, mUserOneService);
ParcelFileDescriptor parcelFileDescriptor = getFileDescriptorForAdbTest();
setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false);
@@ -1370,8 +1278,8 @@ public class BackupManagerServiceTest {
/** Test that the backup service does not route methods for non-registered users. */
@Test
public void testAdbBackup_onUnknownUser_doesNotPropagateCall() throws Exception {
- BackupManagerService backupManagerService =
- createServiceAndRegisterUser(mUserOneId, mUserOneService);
+ BackupManagerService backupManagerService = createSystemRegisteredService();
+ registerUser(backupManagerService, mUserOneId, mUserOneService);
ParcelFileDescriptor parcelFileDescriptor = getFileDescriptorForAdbTest();
setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false);
@@ -1408,8 +1316,9 @@ public class BackupManagerServiceTest {
*/
@Test
public void testAdbRestore_withoutPermission_throwsSecurityExceptionForNonCallingUser() {
- BackupManagerService backupManagerService =
- createServiceAndRegisterUser(mUserOneId, mUserOneService);
+ BackupManagerService backupManagerService = createSystemRegisteredService();
+ registerUser(backupManagerService, mUserOneId, mUserOneService);
+ registerUser(backupManagerService, mUserTwoId, mUserTwoService);
setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false);
expectThrows(
@@ -1422,9 +1331,9 @@ public class BackupManagerServiceTest {
*/
@Test
public void testAdbRestore_withPermission_propagatesForNonCallingUser() throws Exception {
- BackupManagerService backupManagerService =
- createServiceAndRegisterUser(mUserOneId, mUserOneService);
- backupManagerService.startServiceForUser(mUserTwoId, mUserTwoService);
+ BackupManagerService backupManagerService = createSystemRegisteredService();
+ registerUser(backupManagerService, mUserOneId, mUserOneService);
+ registerUser(backupManagerService, mUserTwoId, mUserTwoService);
ParcelFileDescriptor parcelFileDescriptor = getFileDescriptorForAdbTest();
setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ true);
@@ -1436,8 +1345,8 @@ public class BackupManagerServiceTest {
/** Test that the backup service routes methods correctly to the user that requests it. */
@Test
public void testAdbRestore_onRegisteredUser_callsMethodForUser() throws Exception {
- BackupManagerService backupManagerService =
- createServiceAndRegisterUser(mUserOneId, mUserOneService);
+ BackupManagerService backupManagerService = createSystemRegisteredService();
+ registerUser(backupManagerService, mUserOneId, mUserOneService);
ParcelFileDescriptor parcelFileDescriptor = getFileDescriptorForAdbTest();
setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false);
@@ -1449,8 +1358,8 @@ public class BackupManagerServiceTest {
/** Test that the backup service does not route methods for non-registered users. */
@Test
public void testAdbRestore_onUnknownUser_doesNotPropagateCall() throws Exception {
- BackupManagerService backupManagerService =
- createServiceAndRegisterUser(mUserOneId, mUserOneService);
+ BackupManagerService backupManagerService = createSystemRegisteredService();
+ registerUser(backupManagerService, mUserOneId, mUserOneService);
ParcelFileDescriptor parcelFileDescriptor = getFileDescriptorForAdbTest();
setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false);
@@ -1459,12 +1368,18 @@ public class BackupManagerServiceTest {
verify(mUserOneService, never()).adbRestore(parcelFileDescriptor);
}
+ private ParcelFileDescriptor getFileDescriptorForAdbTest() throws Exception {
+ File testFile = new File(mContext.getFilesDir(), "test");
+ testFile.createNewFile();
+ return ParcelFileDescriptor.open(testFile, ParcelFileDescriptor.MODE_READ_WRITE);
+ }
+
/** Test that the backup service routes methods correctly to the user that requests it. */
@Test
public void testAcknowledgeAdbBackupOrRestore_onRegisteredUser_callsMethodForUser()
throws Exception {
- BackupManagerService backupManagerService =
- createServiceAndRegisterUser(mUserOneId, mUserOneService);
+ BackupManagerService backupManagerService = createService();
+ registerUser(backupManagerService, mUserOneId, mUserOneService);
setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false);
IFullBackupRestoreObserver observer = mock(IFullBackupRestoreObserver.class);
@@ -1489,8 +1404,8 @@ public class BackupManagerServiceTest {
@Test
public void testAcknowledgeAdbBackupOrRestore_onUnknownUser_doesNotPropagateCall()
throws Exception {
- BackupManagerService backupManagerService =
- createServiceAndRegisterUser(mUserOneId, mUserOneService);
+ BackupManagerService backupManagerService = createService();
+ registerUser(backupManagerService, mUserOneId, mUserOneService);
setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false);
IFullBackupRestoreObserver observer = mock(IFullBackupRestoreObserver.class);
@@ -1519,24 +1434,22 @@ public class BackupManagerServiceTest {
@Test
public void testDump_onRegisteredUser_callsMethodForUser() throws Exception {
grantDumpPermissions();
-
- BackupManagerService backupManagerService =
- createServiceAndRegisterUser(UserHandle.USER_SYSTEM, mUserOneService);
+ BackupManagerService backupManagerService = createSystemRegisteredService();
File testFile = createTestFile();
FileDescriptor fileDescriptor = new FileDescriptor();
PrintWriter printWriter = new PrintWriter(testFile);
String[] args = {"1", "2"};
+ ShadowBinder.setCallingUserHandle(UserHandle.of(UserHandle.USER_SYSTEM));
backupManagerService.dump(fileDescriptor, printWriter, args);
- verify(mUserOneService).dump(fileDescriptor, printWriter, args);
+ verify(mUserSystemService).dump(fileDescriptor, printWriter, args);
}
/** Test that the backup service does not route methods for non-registered users. */
@Test
public void testDump_onUnknownUser_doesNotPropagateCall() throws Exception {
grantDumpPermissions();
-
BackupManagerService backupManagerService = createService();
File testFile = createTestFile();
FileDescriptor fileDescriptor = new FileDescriptor();
@@ -1552,9 +1465,8 @@ public class BackupManagerServiceTest {
@Test
public void testDump_users_dumpsListOfRegisteredUsers() {
grantDumpPermissions();
-
- BackupManagerService backupManagerService = createServiceAndRegisterUser(mUserOneId,
- mUserOneService);
+ BackupManagerService backupManagerService = createSystemRegisteredService();
+ registerUser(backupManagerService, mUserOneId, mUserOneService);
StringWriter out = new StringWriter();
PrintWriter writer = new PrintWriter(out);
String[] args = {"users"};
@@ -1563,31 +1475,162 @@ public class BackupManagerServiceTest {
writer.flush();
assertEquals(
- String.format("%s %d\n", BackupManagerService.DUMP_RUNNING_USERS_MESSAGE,
- mUserOneId),
+ String.format("%s %d %d\n", BackupManagerService.DUMP_RUNNING_USERS_MESSAGE,
+ UserHandle.USER_SYSTEM, mUserOneId),
out.toString());
}
+ private File createTestFile() throws IOException {
+ File testFile = new File(mContext.getFilesDir(), "test");
+ testFile.createNewFile();
+ return testFile;
+ }
+
private void grantDumpPermissions() {
mShadowContext.grantPermissions(DUMP);
mShadowContext.grantPermissions(PACKAGE_USAGE_STATS);
}
- private File createTestFile() throws IOException {
- File testFile = new File(mContext.getFilesDir(), "test");
- testFile.createNewFile();
- return testFile;
+ /**
+ * Test that the backup services throws a {@link SecurityException} if the caller does not have
+ * INTERACT_ACROSS_USERS_FULL permission and passes a different user id.
+ */
+ @Test
+ public void testGetServiceForUser_withoutPermission_throwsSecurityExceptionForNonCallingUser() {
+ BackupManagerService backupManagerService = createService();
+ registerUser(backupManagerService, mUserOneId, mUserOneService);
+ setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false);
+
+ expectThrows(
+ SecurityException.class,
+ () ->
+ backupManagerService.getServiceForUserIfCallerHasPermission(
+ mUserOneId, "test"));
+ }
+
+ /**
+ * Test that the backup services does not throw a {@link SecurityException} if the caller has
+ * INTERACT_ACROSS_USERS_FULL permission and passes a different user id.
+ */
+ @Test
+ public void testGetServiceForUserIfCallerHasPermission_withPermission_worksForNonCallingUser() {
+ BackupManagerService backupManagerService = createService();
+ registerUser(backupManagerService, mUserOneId, mUserOneService);
+ setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ true);
+
+ assertEquals(
+ mUserOneService,
+ backupManagerService.getServiceForUserIfCallerHasPermission(mUserOneId, "test"));
+ }
+
+ /**
+ * Test that the backup services does not throw a {@link SecurityException} if the caller does
+ * not have INTERACT_ACROSS_USERS_FULL permission and passes in the calling user id.
+ */
+ @Test
+ public void testGetServiceForUserIfCallerHasPermission_withoutPermission_worksForCallingUser() {
+ BackupManagerService backupManagerService = createService();
+ registerUser(backupManagerService, mUserOneId, mUserOneService);
+ setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false);
+
+ assertEquals(
+ mUserOneService,
+ backupManagerService.getServiceForUserIfCallerHasPermission(mUserOneId, "test"));
+ }
+
+ /**
+ * Test verifying that {@link BackupManagerService#MORE_DEBUG} is set to {@code false}. This is
+ * specifically to prevent overloading the logs in production.
+ */
+ @Test
+ public void testMoreDebug_isFalse() throws Exception {
+ boolean moreDebug = BackupManagerService.MORE_DEBUG;
+
+ assertThat(moreDebug).isFalse();
+ }
+
+ /** Test that the constructor handles {@code null} parameters. */
+ @Test
+ public void testConstructor_withNullContext_throws() throws Exception {
+ expectThrows(
+ NullPointerException.class,
+ () ->
+ new BackupManagerService(
+ /* context */ null,
+ new SparseArray<>()));
+ }
+
+ /** Test that the constructor does not create {@link UserBackupManagerService} instances. */
+ @Test
+ public void testConstructor_doesNotRegisterUsers() throws Exception {
+ BackupManagerService backupManagerService = createService();
+
+ assertThat(backupManagerService.getUserServices().size()).isEqualTo(0);
+ }
+
+ // ---------------------------------------------
+ // Lifecycle tests
+ // ---------------------------------------------
+
+ /** testOnStart_publishesService */
+ @Test
+ public void testOnStart_publishesService() {
+ BackupManagerService backupManagerService = mock(BackupManagerService.class);
+ BackupManagerService.Lifecycle lifecycle =
+ spy(new BackupManagerService.Lifecycle(mContext, backupManagerService));
+ doNothing().when(lifecycle).publishService(anyString(), any());
+
+ lifecycle.onStart();
+
+ verify(lifecycle).publishService(Context.BACKUP_SERVICE, backupManagerService);
+ }
+
+ /** testOnUnlockUser_forwards */
+ @Test
+ public void testOnUnlockUser_forwards() {
+ BackupManagerService backupManagerService = mock(BackupManagerService.class);
+ BackupManagerService.Lifecycle lifecycle =
+ new BackupManagerService.Lifecycle(mContext, backupManagerService);
+
+ lifecycle.onUnlockUser(UserHandle.USER_SYSTEM);
+
+ verify(backupManagerService).onUnlockUser(UserHandle.USER_SYSTEM);
+ }
+
+ /** testOnStopUser_forwards */
+ @Test
+ public void testOnStopUser_forwards() {
+ BackupManagerService backupManagerService = mock(BackupManagerService.class);
+ BackupManagerService.Lifecycle lifecycle =
+ new BackupManagerService.Lifecycle(mContext, backupManagerService);
+
+ lifecycle.onStopUser(UserHandle.USER_SYSTEM);
+
+ verify(backupManagerService).onStopUser(UserHandle.USER_SYSTEM);
}
private BackupManagerService createService() {
- mShadowContext.grantPermissions(BACKUP);
- return new BackupManagerService(
- mContext, new Trampoline(mContext), startBackupThread(null));
+ return new BackupManagerService(mContext);
+ }
+
+ private BackupManagerService createSystemRegisteredService() {
+ BackupManagerService backupManagerService = createService();
+ registerUser(backupManagerService, UserHandle.USER_SYSTEM, mUserSystemService);
+ return backupManagerService;
+ }
+
+ private void registerUser(
+ BackupManagerService backupManagerService,
+ int userId,
+ UserBackupManagerService userBackupManagerService) {
+ backupManagerService.setBackupServiceActive(userId, true);
+ backupManagerService.startServiceForUser(userId, userBackupManagerService);
}
private BackupManagerService createServiceAndRegisterUser(
int userId, UserBackupManagerService userBackupManagerService) {
BackupManagerService backupManagerService = createService();
+ backupManagerService.setBackupServiceActive(userBackupManagerService.getUserId(), true);
backupManagerService.startServiceForUser(userId, userBackupManagerService);
return backupManagerService;
}
@@ -1606,10 +1649,4 @@ public class BackupManagerServiceTest {
mShadowContext.denyPermissions(INTERACT_ACROSS_USERS_FULL);
}
}
-
- private ParcelFileDescriptor getFileDescriptorForAdbTest() throws Exception {
- File testFile = new File(mContext.getFilesDir(), "test");
- testFile.createNewFile();
- return ParcelFileDescriptor.open(testFile, ParcelFileDescriptor.MODE_READ_WRITE);
- }
}
diff --git a/services/robotests/backup/src/com/android/server/backup/FullBackupJobTest.java b/services/robotests/backup/src/com/android/server/backup/FullBackupJobTest.java
index 9a78d0b3f456..dbc0da707477 100644
--- a/services/robotests/backup/src/com/android/server/backup/FullBackupJobTest.java
+++ b/services/robotests/backup/src/com/android/server/backup/FullBackupJobTest.java
@@ -25,6 +25,8 @@ import android.os.Handler;
import android.os.UserHandle;
import android.platform.test.annotations.Presubmit;
+import com.android.server.testing.shadows.ShadowSystemServiceRegistry;
+
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
@@ -36,7 +38,7 @@ import org.robolectric.annotation.Config;
import org.robolectric.shadows.ShadowJobScheduler;
@RunWith(RobolectricTestRunner.class)
-@Config(shadows = {ShadowJobScheduler.class})
+@Config(shadows = {ShadowJobScheduler.class, ShadowSystemServiceRegistry.class})
@Presubmit
public class FullBackupJobTest {
private Context mContext;
diff --git a/services/robotests/backup/src/com/android/server/backup/KeyValueBackupJobTest.java b/services/robotests/backup/src/com/android/server/backup/KeyValueBackupJobTest.java
index 8d9e44fbf1ad..1c5fac28de3c 100644
--- a/services/robotests/backup/src/com/android/server/backup/KeyValueBackupJobTest.java
+++ b/services/robotests/backup/src/com/android/server/backup/KeyValueBackupJobTest.java
@@ -24,14 +24,18 @@ import android.os.Handler;
import android.os.UserHandle;
import android.platform.test.annotations.Presubmit;
+import com.android.server.testing.shadows.ShadowSystemServiceRegistry;
+
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Config;
@RunWith(RobolectricTestRunner.class)
+@Config(shadows = {ShadowSystemServiceRegistry.class})
@Presubmit
public class KeyValueBackupJobTest {
private Context mContext;
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 74fe81c6f68e..dfe75ed50cd4 100644
--- a/services/robotests/backup/src/com/android/server/backup/UserBackupManagerServiceTest.java
+++ b/services/robotests/backup/src/com/android/server/backup/UserBackupManagerServiceTest.java
@@ -30,10 +30,13 @@ import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static org.robolectric.Shadows.shadowOf;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertTrue;
import static org.testng.Assert.expectThrows;
import android.app.backup.BackupManager;
@@ -63,6 +66,7 @@ import com.android.server.testing.shadows.ShadowApplicationPackageManager;
import com.android.server.testing.shadows.ShadowBinder;
import com.android.server.testing.shadows.ShadowKeyValueBackupJob;
import com.android.server.testing.shadows.ShadowKeyValueBackupTask;
+import com.android.server.testing.shadows.ShadowSystemServiceRegistry;
import org.junit.After;
import org.junit.Before;
@@ -80,7 +84,12 @@ import org.robolectric.shadows.ShadowLooper;
import org.robolectric.shadows.ShadowPackageManager;
import java.io.File;
+import java.io.FileDescriptor;
import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.util.ArrayList;
+import java.util.Arrays;
import java.util.List;
/**
@@ -88,12 +97,18 @@ import java.util.List;
* UserBackupManagerService} that performs operations for its target user.
*/
@RunWith(RobolectricTestRunner.class)
-@Config(shadows = {ShadowAppBackupUtils.class, ShadowApplicationPackageManager.class})
+@Config(
+ shadows = {
+ ShadowAppBackupUtils.class,
+ ShadowApplicationPackageManager.class,
+ ShadowSystemServiceRegistry.class
+ })
@Presubmit
public class UserBackupManagerServiceTest {
private static final String TAG = "BMSTest";
private static final String PACKAGE_1 = "some.package.1";
private static final String PACKAGE_2 = "some.package.2";
+ private static final String USER_FACING_PACKAGE = "user.facing.package";
private static final int USER_ID = 10;
@Mock private TransportManager mTransportManager;
@@ -510,6 +525,23 @@ public class UserBackupManagerServiceTest {
expectThrows(SecurityException.class, backupManagerService::getCurrentTransportComponent);
}
+ /**
+ * Test verifying that {@link UserBackupManagerService#excludeKeysFromRestore(String, List)}
+ * throws a {@link SecurityException} if the caller does not have backup permission.
+ */
+ @Test
+ public void testExcludeKeysFromRestore_withoutPermission() throws Exception {
+ mShadowContext.denyPermissions(android.Manifest.permission.BACKUP);
+ UserBackupManagerService backupManagerService = createUserBackupManagerServiceAndRunTasks();
+
+ expectThrows(
+ SecurityException.class,
+ () ->
+ backupManagerService.excludeKeysFromRestore(
+ PACKAGE_1,
+ new ArrayList<String>(){}));
+ }
+
/* Tests for updating transport attributes */
private static final int PACKAGE_UID = 10;
@@ -999,7 +1031,7 @@ public class UserBackupManagerServiceTest {
UserBackupManagerService.createAndInitializeService(
USER_ID,
mContext,
- new Trampoline(mContext),
+ new BackupManagerService(mContext),
mBackupThread,
mBaseStateDir,
mDataDir,
@@ -1020,7 +1052,7 @@ public class UserBackupManagerServiceTest {
UserBackupManagerService.createAndInitializeService(
USER_ID,
mContext,
- new Trampoline(mContext),
+ new BackupManagerService(mContext),
mBackupThread,
mBaseStateDir,
mDataDir,
@@ -1039,7 +1071,7 @@ public class UserBackupManagerServiceTest {
UserBackupManagerService.createAndInitializeService(
USER_ID,
/* context */ null,
- new Trampoline(mContext),
+ new BackupManagerService(mContext),
mBackupThread,
mBaseStateDir,
mDataDir,
@@ -1071,7 +1103,7 @@ public class UserBackupManagerServiceTest {
UserBackupManagerService.createAndInitializeService(
USER_ID,
mContext,
- new Trampoline(mContext),
+ new BackupManagerService(mContext),
/* backupThread */ null,
mBaseStateDir,
mDataDir,
@@ -1087,7 +1119,7 @@ public class UserBackupManagerServiceTest {
UserBackupManagerService.createAndInitializeService(
USER_ID,
mContext,
- new Trampoline(mContext),
+ new BackupManagerService(mContext),
mBackupThread,
/* baseStateDir */ null,
mDataDir,
@@ -1096,8 +1128,8 @@ public class UserBackupManagerServiceTest {
/**
* Test checking non-null argument on {@link
- * UserBackupManagerService#createAndInitializeService(int, Context, Trampoline, HandlerThread,
- * File, File, TransportManager)}.
+ * UserBackupManagerService#createAndInitializeService(int, Context, BackupManagerService,
+ * HandlerThread, File, File, TransportManager)}.
*/
@Test
public void testCreateAndInitializeService_withNullDataDir_throws() {
@@ -1107,7 +1139,7 @@ public class UserBackupManagerServiceTest {
UserBackupManagerService.createAndInitializeService(
USER_ID,
mContext,
- new Trampoline(mContext),
+ new BackupManagerService(mContext),
mBackupThread,
mBaseStateDir,
/* dataDir */ null,
@@ -1116,8 +1148,8 @@ public class UserBackupManagerServiceTest {
/**
* Test checking non-null argument on {@link
- * UserBackupManagerService#createAndInitializeService(int, Context, Trampoline, HandlerThread,
- * File, File, TransportManager)}.
+ * UserBackupManagerService#createAndInitializeService(int, Context, BackupManagerService,
+ * HandlerThread, File, File, TransportManager)}.
*/
@Test
public void testCreateAndInitializeService_withNullTransportManager_throws() {
@@ -1127,7 +1159,7 @@ public class UserBackupManagerServiceTest {
UserBackupManagerService.createAndInitializeService(
USER_ID,
mContext,
- new Trampoline(mContext),
+ new BackupManagerService(mContext),
mBackupThread,
mBaseStateDir,
mDataDir,
@@ -1145,7 +1177,7 @@ public class UserBackupManagerServiceTest {
UserBackupManagerService service = UserBackupManagerService.createAndInitializeService(
USER_ID,
contextSpy,
- new Trampoline(mContext),
+ new BackupManagerService(mContext),
mBackupThread,
mBaseStateDir,
mDataDir,
@@ -1159,6 +1191,47 @@ public class UserBackupManagerServiceTest {
eq(packageTrackingReceiver), eq(UserHandle.of(USER_ID)), any(), any(), any());
}
+ @Test
+ public void testFilterUserFacingPackages_shouldSkipUserFacing_filtersUserFacing() {
+ List<PackageInfo> packages = Arrays.asList(getPackageInfo(USER_FACING_PACKAGE),
+ getPackageInfo(PACKAGE_1));
+ UserBackupManagerService backupManagerService = spy(
+ createUserBackupManagerServiceAndRunTasks());
+ when(backupManagerService.shouldSkipUserFacingData()).thenReturn(true);
+ when(backupManagerService.shouldSkipPackage(eq(USER_FACING_PACKAGE))).thenReturn(true);
+
+ List<PackageInfo> filteredPackages = backupManagerService.filterUserFacingPackages(
+ packages);
+
+ assertFalse(containsPackage(filteredPackages, USER_FACING_PACKAGE));
+ assertTrue(containsPackage(filteredPackages, PACKAGE_1));
+ }
+
+ @Test
+ public void testFilterUserFacingPackages_shouldNotSkipUserFacing_doesNotFilterUserFacing() {
+ List<PackageInfo> packages = Arrays.asList(getPackageInfo(USER_FACING_PACKAGE),
+ getPackageInfo(PACKAGE_1));
+ UserBackupManagerService backupManagerService = spy(
+ createUserBackupManagerServiceAndRunTasks());
+ when(backupManagerService.shouldSkipUserFacingData()).thenReturn(false);
+ when(backupManagerService.shouldSkipPackage(eq(USER_FACING_PACKAGE))).thenReturn(true);
+
+ List<PackageInfo> filteredPackages = backupManagerService.filterUserFacingPackages(
+ packages);
+
+ assertTrue(containsPackage(filteredPackages, USER_FACING_PACKAGE));
+ assertTrue(containsPackage(filteredPackages, PACKAGE_1));
+ }
+
+ private static boolean containsPackage(List<PackageInfo> packages, String targetPackage) {
+ for (PackageInfo packageInfo : packages) {
+ if (targetPackage.equals(packageInfo.packageName)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
private UserBackupManagerService createUserBackupManagerServiceAndRunTasks() {
return BackupManagerServiceTestUtils.createUserBackupManagerServiceAndRunTasks(
USER_ID, mContext, mBackupThread, mBaseStateDir, mDataDir, mTransportManager);
@@ -1232,13 +1305,49 @@ public class UserBackupManagerServiceTest {
assertThat(service.getAncestralSerialNumber()).isEqualTo(testSerialNumber2);
}
+ /**
+ * Test that {@link UserBackupManagerService#dump()} for system user does not prefix dump with
+ * "User 0:".
+ */
+ @Test
+ public void testDump_forSystemUser_DoesNotHaveUserPrefix() throws Exception {
+ mShadowContext.grantPermissions(android.Manifest.permission.BACKUP);
+ UserBackupManagerService service =
+ BackupManagerServiceTestUtils.createUserBackupManagerServiceAndRunTasks(
+ UserHandle.USER_SYSTEM,
+ mContext,
+ mBackupThread,
+ mBaseStateDir,
+ mDataDir,
+ mTransportManager);
+
+ StringWriter dump = new StringWriter();
+ service.dump(new FileDescriptor(), new PrintWriter(dump), new String[0]);
+
+ assertThat(dump.toString()).startsWith("Backup Manager is ");
+ }
+
+ /**
+ * Test that {@link UserBackupManagerService#dump()} for non-system user prefixes dump with
+ * "User <userid>:".
+ */
+ @Test
+ public void testDump_forNonSystemUser_HasUserPrefix() throws Exception {
+ mShadowContext.grantPermissions(android.Manifest.permission.BACKUP);
+ UserBackupManagerService service = createUserBackupManagerServiceAndRunTasks();
+
+ StringWriter dump = new StringWriter();
+ service.dump(new FileDescriptor(), new PrintWriter(dump), new String[0]);
+
+ assertThat(dump.toString()).startsWith("User " + USER_ID + ":" + "Backup Manager is ");
+ }
+
private File createTestFile() throws IOException {
File testFile = new File(mContext.getFilesDir(), "test");
testFile.createNewFile();
return testFile;
}
-
/**
* We can't mock the void method {@link #schedule(Context, long, BackupManagerConstants)} so we
* extend {@link ShadowKeyValueBackupJob} and throw an exception at the end of the method.
diff --git a/services/robotests/backup/src/com/android/server/backup/encryption/chunk/ChunkHashTest.java b/services/robotests/backup/src/com/android/server/backup/encryption/chunk/ChunkHashTest.java
deleted file mode 100644
index 3f57240bc0e9..000000000000
--- a/services/robotests/backup/src/com/android/server/backup/encryption/chunk/ChunkHashTest.java
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- * Copyright (C) 2018 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.encryption.chunk;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import android.platform.test.annotations.Presubmit;
-
-import com.google.common.primitives.Bytes;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.robolectric.RobolectricTestRunner;
-
-import java.util.Arrays;
-
-@RunWith(RobolectricTestRunner.class)
-@Presubmit
-public class ChunkHashTest {
- private static final int HASH_LENGTH_BYTES = 256 / 8;
- private static final byte[] TEST_HASH_1 = Arrays.copyOf(new byte[] {1}, HASH_LENGTH_BYTES);
- private static final byte[] TEST_HASH_2 = Arrays.copyOf(new byte[] {2}, HASH_LENGTH_BYTES);
-
- @Test
- public void testGetHash_returnsHash() {
- ChunkHash chunkHash = new ChunkHash(TEST_HASH_1);
-
- byte[] hash = chunkHash.getHash();
-
- assertThat(hash).asList().containsExactlyElementsIn(Bytes.asList(TEST_HASH_1)).inOrder();
- }
-
- @Test
- public void testEquals() {
- ChunkHash chunkHash1 = new ChunkHash(TEST_HASH_1);
- ChunkHash equalChunkHash1 = new ChunkHash(TEST_HASH_1);
- ChunkHash chunkHash2 = new ChunkHash(TEST_HASH_2);
-
- assertThat(chunkHash1).isEqualTo(equalChunkHash1);
- assertThat(chunkHash1).isNotEqualTo(chunkHash2);
- }
-
- @Test
- public void testHashCode() {
- ChunkHash chunkHash1 = new ChunkHash(TEST_HASH_1);
- ChunkHash equalChunkHash1 = new ChunkHash(TEST_HASH_1);
- ChunkHash chunkHash2 = new ChunkHash(TEST_HASH_2);
-
- int hash1 = chunkHash1.hashCode();
- int equalHash1 = equalChunkHash1.hashCode();
- int hash2 = chunkHash2.hashCode();
-
- assertThat(hash1).isEqualTo(equalHash1);
- assertThat(hash1).isNotEqualTo(hash2);
- }
-
- @Test
- public void testCompareTo_whenEqual_returnsZero() {
- ChunkHash chunkHash = new ChunkHash(TEST_HASH_1);
- ChunkHash equalChunkHash = new ChunkHash(TEST_HASH_1);
-
- int result = chunkHash.compareTo(equalChunkHash);
-
- assertThat(result).isEqualTo(0);
- }
-
- @Test
- public void testCompareTo_whenArgumentGreater_returnsNegative() {
- ChunkHash chunkHash1 = new ChunkHash(TEST_HASH_1);
- ChunkHash chunkHash2 = new ChunkHash(TEST_HASH_2);
-
- int result = chunkHash1.compareTo(chunkHash2);
-
- assertThat(result).isLessThan(0);
- }
-
- @Test
- public void testCompareTo_whenArgumentSmaller_returnsPositive() {
- ChunkHash chunkHash1 = new ChunkHash(TEST_HASH_1);
- ChunkHash chunkHash2 = new ChunkHash(TEST_HASH_2);
-
- int result = chunkHash2.compareTo(chunkHash1);
-
- assertThat(result).isGreaterThan(0);
- }
-}
diff --git a/services/robotests/backup/src/com/android/server/backup/encryption/chunk/ChunkListingMapTest.java b/services/robotests/backup/src/com/android/server/backup/encryption/chunk/ChunkListingMapTest.java
deleted file mode 100644
index 24e5573b891d..000000000000
--- a/services/robotests/backup/src/com/android/server/backup/encryption/chunk/ChunkListingMapTest.java
+++ /dev/null
@@ -1,197 +0,0 @@
-/*
- * 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.encryption.chunk;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import android.platform.test.annotations.Presubmit;
-import android.util.proto.ProtoInputStream;
-import android.util.proto.ProtoOutputStream;
-
-import com.android.internal.util.Preconditions;
-
-import com.google.common.base.Charsets;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.robolectric.RobolectricTestRunner;
-
-import java.io.ByteArrayInputStream;
-import java.util.Arrays;
-
-@RunWith(RobolectricTestRunner.class)
-@Presubmit
-public class ChunkListingMapTest {
- private static final String CHUNK_A = "CHUNK_A";
- private static final String CHUNK_B = "CHUNK_B";
- private static final String CHUNK_C = "CHUNK_C";
-
- private static final int CHUNK_A_LENGTH = 256;
- private static final int CHUNK_B_LENGTH = 1024;
- private static final int CHUNK_C_LENGTH = 4055;
-
- private ChunkHash mChunkHashA;
- private ChunkHash mChunkHashB;
- private ChunkHash mChunkHashC;
-
- @Before
- public void setUp() throws Exception {
- mChunkHashA = getHash(CHUNK_A);
- mChunkHashB = getHash(CHUNK_B);
- mChunkHashC = getHash(CHUNK_C);
- }
-
- @Test
- public void testHasChunk_whenChunkInListing_returnsTrue() throws Exception {
- byte[] chunkListingProto =
- createChunkListingProto(
- new ChunkHash[] {mChunkHashA, mChunkHashB, mChunkHashC},
- new int[] {CHUNK_A_LENGTH, CHUNK_B_LENGTH, CHUNK_C_LENGTH});
- ChunkListingMap chunkListingMap =
- ChunkListingMap.readFromProto(
- new ProtoInputStream(new ByteArrayInputStream(chunkListingProto)));
-
- boolean chunkAInList = chunkListingMap.hasChunk(mChunkHashA);
- boolean chunkBInList = chunkListingMap.hasChunk(mChunkHashB);
- boolean chunkCInList = chunkListingMap.hasChunk(mChunkHashC);
-
- assertThat(chunkAInList).isTrue();
- assertThat(chunkBInList).isTrue();
- assertThat(chunkCInList).isTrue();
- }
-
- @Test
- public void testHasChunk_whenChunkNotInListing_returnsFalse() throws Exception {
- byte[] chunkListingProto =
- createChunkListingProto(
- new ChunkHash[] {mChunkHashA, mChunkHashB},
- new int[] {CHUNK_A_LENGTH, CHUNK_B_LENGTH});
- ChunkListingMap chunkListingMap =
- ChunkListingMap.readFromProto(
- new ProtoInputStream(new ByteArrayInputStream(chunkListingProto)));
- ChunkHash chunkHashEmpty = getHash("");
-
- boolean chunkCInList = chunkListingMap.hasChunk(mChunkHashC);
- boolean emptyChunkInList = chunkListingMap.hasChunk(chunkHashEmpty);
-
- assertThat(chunkCInList).isFalse();
- assertThat(emptyChunkInList).isFalse();
- }
-
- @Test
- public void testGetChunkEntry_returnsEntryWithCorrectLength() throws Exception {
- byte[] chunkListingProto =
- createChunkListingProto(
- new ChunkHash[] {mChunkHashA, mChunkHashB, mChunkHashC},
- new int[] {CHUNK_A_LENGTH, CHUNK_B_LENGTH, CHUNK_C_LENGTH});
- ChunkListingMap chunkListingMap =
- ChunkListingMap.readFromProto(
- new ProtoInputStream(new ByteArrayInputStream(chunkListingProto)));
-
- ChunkListingMap.Entry entryA = chunkListingMap.getChunkEntry(mChunkHashA);
- ChunkListingMap.Entry entryB = chunkListingMap.getChunkEntry(mChunkHashB);
- ChunkListingMap.Entry entryC = chunkListingMap.getChunkEntry(mChunkHashC);
-
- assertThat(entryA.getLength()).isEqualTo(CHUNK_A_LENGTH);
- assertThat(entryB.getLength()).isEqualTo(CHUNK_B_LENGTH);
- assertThat(entryC.getLength()).isEqualTo(CHUNK_C_LENGTH);
- }
-
- @Test
- public void testGetChunkEntry_returnsEntryWithCorrectStart() throws Exception {
- byte[] chunkListingProto =
- createChunkListingProto(
- new ChunkHash[] {mChunkHashA, mChunkHashB, mChunkHashC},
- new int[] {CHUNK_A_LENGTH, CHUNK_B_LENGTH, CHUNK_C_LENGTH});
- ChunkListingMap chunkListingMap =
- ChunkListingMap.readFromProto(
- new ProtoInputStream(new ByteArrayInputStream(chunkListingProto)));
-
- ChunkListingMap.Entry entryA = chunkListingMap.getChunkEntry(mChunkHashA);
- ChunkListingMap.Entry entryB = chunkListingMap.getChunkEntry(mChunkHashB);
- ChunkListingMap.Entry entryC = chunkListingMap.getChunkEntry(mChunkHashC);
-
- assertThat(entryA.getStart()).isEqualTo(0);
- assertThat(entryB.getStart()).isEqualTo(CHUNK_A_LENGTH);
- assertThat(entryC.getStart()).isEqualTo(CHUNK_A_LENGTH + CHUNK_B_LENGTH);
- }
-
- @Test
- public void testGetChunkEntry_returnsNullForNonExistentChunk() throws Exception {
- byte[] chunkListingProto =
- createChunkListingProto(
- new ChunkHash[] {mChunkHashA, mChunkHashB},
- new int[] {CHUNK_A_LENGTH, CHUNK_B_LENGTH});
- ChunkListingMap chunkListingMap =
- ChunkListingMap.readFromProto(
- new ProtoInputStream(new ByteArrayInputStream(chunkListingProto)));
-
- ChunkListingMap.Entry chunkEntryNonexistentChunk =
- chunkListingMap.getChunkEntry(mChunkHashC);
-
- assertThat(chunkEntryNonexistentChunk).isNull();
- }
-
- @Test
- public void testReadFromProto_whenEmptyProto_returnsChunkListingMapWith0Chunks()
- throws Exception {
- ProtoInputStream emptyProto = new ProtoInputStream(new ByteArrayInputStream(new byte[] {}));
-
- ChunkListingMap chunkListingMap = ChunkListingMap.readFromProto(emptyProto);
-
- assertThat(chunkListingMap.getChunkCount()).isEqualTo(0);
- }
-
- @Test
- public void testReadFromProto_returnsChunkListingWithCorrectSize() throws Exception {
- byte[] chunkListingProto =
- createChunkListingProto(
- new ChunkHash[] {mChunkHashA, mChunkHashB, mChunkHashC},
- new int[] {CHUNK_A_LENGTH, CHUNK_B_LENGTH, CHUNK_C_LENGTH});
-
- ChunkListingMap chunkListingMap =
- ChunkListingMap.readFromProto(
- new ProtoInputStream(new ByteArrayInputStream(chunkListingProto)));
-
- assertThat(chunkListingMap.getChunkCount()).isEqualTo(3);
- }
-
- private byte[] createChunkListingProto(ChunkHash[] hashes, int[] lengths) {
- Preconditions.checkArgument(hashes.length == lengths.length);
- ProtoOutputStream outputStream = new ProtoOutputStream();
-
- for (int i = 0; i < hashes.length; ++i) {
- writeToProtoOutputStream(outputStream, hashes[i], lengths[i]);
- }
- outputStream.flush();
-
- return outputStream.getBytes();
- }
-
- private void writeToProtoOutputStream(ProtoOutputStream out, ChunkHash chunkHash, int length) {
- long token = out.start(ChunksMetadataProto.ChunkListing.CHUNKS);
- out.write(ChunksMetadataProto.Chunk.HASH, chunkHash.getHash());
- out.write(ChunksMetadataProto.Chunk.LENGTH, length);
- out.end(token);
- }
-
- private ChunkHash getHash(String name) {
- return new ChunkHash(
- Arrays.copyOf(name.getBytes(Charsets.UTF_8), ChunkHash.HASH_LENGTH_BYTES));
- }
-}
diff --git a/services/robotests/backup/src/com/android/server/backup/encryption/chunk/ChunkTest.java b/services/robotests/backup/src/com/android/server/backup/encryption/chunk/ChunkTest.java
deleted file mode 100644
index 17c9a86169be..000000000000
--- a/services/robotests/backup/src/com/android/server/backup/encryption/chunk/ChunkTest.java
+++ /dev/null
@@ -1,122 +0,0 @@
-/*
- * Copyright (C) 2018 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.encryption.chunk;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import android.platform.test.annotations.Presubmit;
-import android.util.proto.ProtoInputStream;
-import android.util.proto.ProtoOutputStream;
-
-import com.google.common.base.Charsets;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.robolectric.RobolectricTestRunner;
-
-import java.io.ByteArrayInputStream;
-import java.util.Arrays;
-
-@RunWith(RobolectricTestRunner.class)
-@Presubmit
-public class ChunkTest {
- private static final String CHUNK_A = "CHUNK_A";
- private static final int CHUNK_A_LENGTH = 256;
-
- private ChunkHash mChunkHashA;
-
- @Before
- public void setUp() throws Exception {
- mChunkHashA = getHash(CHUNK_A);
- }
-
- @Test
- public void testReadFromProto_readsCorrectly() throws Exception {
- ProtoOutputStream out = new ProtoOutputStream();
- out.write(ChunksMetadataProto.Chunk.HASH, mChunkHashA.getHash());
- out.write(ChunksMetadataProto.Chunk.LENGTH, CHUNK_A_LENGTH);
- out.flush();
- byte[] protoBytes = out.getBytes();
-
- Chunk chunk =
- Chunk.readFromProto(new ProtoInputStream(new ByteArrayInputStream(protoBytes)));
-
- assertThat(chunk.getHash()).isEqualTo(mChunkHashA.getHash());
- assertThat(chunk.getLength()).isEqualTo(CHUNK_A_LENGTH);
- }
-
- @Test
- public void testReadFromProto_whenFieldsWrittenInReversedOrder_readsCorrectly()
- throws Exception {
- ProtoOutputStream out = new ProtoOutputStream();
- // Write fields of Chunk proto in reverse order.
- out.write(ChunksMetadataProto.Chunk.LENGTH, CHUNK_A_LENGTH);
- out.write(ChunksMetadataProto.Chunk.HASH, mChunkHashA.getHash());
- out.flush();
- byte[] protoBytes = out.getBytes();
-
- Chunk chunk =
- Chunk.readFromProto(new ProtoInputStream(new ByteArrayInputStream(protoBytes)));
-
- assertThat(chunk.getHash()).isEqualTo(mChunkHashA.getHash());
- assertThat(chunk.getLength()).isEqualTo(CHUNK_A_LENGTH);
- }
-
- @Test
- public void testReadFromProto_whenEmptyProto_returnsEmptyHash() throws Exception {
- ProtoInputStream emptyProto = new ProtoInputStream(new ByteArrayInputStream(new byte[] {}));
-
- Chunk chunk = Chunk.readFromProto(emptyProto);
-
- assertThat(chunk.getHash()).asList().hasSize(0);
- assertThat(chunk.getLength()).isEqualTo(0);
- }
-
- @Test
- public void testReadFromProto_whenOnlyHashSet_returnsChunkWithOnlyHash() throws Exception {
- ProtoOutputStream out = new ProtoOutputStream();
- out.write(ChunksMetadataProto.Chunk.HASH, mChunkHashA.getHash());
- out.flush();
- byte[] protoBytes = out.getBytes();
-
- Chunk chunk =
- Chunk.readFromProto(new ProtoInputStream(new ByteArrayInputStream(protoBytes)));
-
- assertThat(chunk.getHash()).isEqualTo(mChunkHashA.getHash());
- assertThat(chunk.getLength()).isEqualTo(0);
- }
-
- @Test
- public void testReadFromProto_whenOnlyLengthSet_returnsChunkWithOnlyLength() throws Exception {
- ProtoOutputStream out = new ProtoOutputStream();
- out.write(ChunksMetadataProto.Chunk.LENGTH, CHUNK_A_LENGTH);
- out.flush();
- byte[] protoBytes = out.getBytes();
-
- Chunk chunk =
- Chunk.readFromProto(new ProtoInputStream(new ByteArrayInputStream(protoBytes)));
-
- assertThat(chunk.getHash()).isEqualTo(new byte[] {});
- assertThat(chunk.getLength()).isEqualTo(CHUNK_A_LENGTH);
- }
-
- private ChunkHash getHash(String name) {
- return new ChunkHash(
- Arrays.copyOf(name.getBytes(Charsets.UTF_8), ChunkHash.HASH_LENGTH_BYTES));
- }
-}
diff --git a/services/robotests/backup/src/com/android/server/backup/encryption/chunk/EncryptedChunkOrderingTest.java b/services/robotests/backup/src/com/android/server/backup/encryption/chunk/EncryptedChunkOrderingTest.java
deleted file mode 100644
index 0bf14174e5c3..000000000000
--- a/services/robotests/backup/src/com/android/server/backup/encryption/chunk/EncryptedChunkOrderingTest.java
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * Copyright (C) 2018 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.encryption.chunk;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import android.platform.test.annotations.Presubmit;
-
-import com.google.common.primitives.Bytes;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.robolectric.RobolectricTestRunner;
-
-@RunWith(RobolectricTestRunner.class)
-@Presubmit
-public class EncryptedChunkOrderingTest {
- private static final byte[] TEST_BYTE_ARRAY_1 = new byte[] {1, 2, 3, 4, 5};
- private static final byte[] TEST_BYTE_ARRAY_2 = new byte[] {5, 4, 3, 2, 1};
-
- @Test
- public void testEncryptedChunkOrdering_returnsValue() {
- EncryptedChunkOrdering encryptedChunkOrdering =
- EncryptedChunkOrdering.create(TEST_BYTE_ARRAY_1);
-
- byte[] bytes = encryptedChunkOrdering.encryptedChunkOrdering();
-
- assertThat(bytes)
- .asList()
- .containsExactlyElementsIn(Bytes.asList(TEST_BYTE_ARRAY_1))
- .inOrder();
- }
-
- @Test
- public void testEquals() {
- EncryptedChunkOrdering chunkOrdering1 = EncryptedChunkOrdering.create(TEST_BYTE_ARRAY_1);
- EncryptedChunkOrdering equalChunkOrdering1 =
- EncryptedChunkOrdering.create(TEST_BYTE_ARRAY_1);
- EncryptedChunkOrdering chunkOrdering2 = EncryptedChunkOrdering.create(TEST_BYTE_ARRAY_2);
-
- assertThat(chunkOrdering1).isEqualTo(equalChunkOrdering1);
- assertThat(chunkOrdering1).isNotEqualTo(chunkOrdering2);
- }
-
- @Test
- public void testHashCode() {
- EncryptedChunkOrdering chunkOrdering1 = EncryptedChunkOrdering.create(TEST_BYTE_ARRAY_1);
- EncryptedChunkOrdering equalChunkOrdering1 =
- EncryptedChunkOrdering.create(TEST_BYTE_ARRAY_1);
- EncryptedChunkOrdering chunkOrdering2 = EncryptedChunkOrdering.create(TEST_BYTE_ARRAY_2);
-
- int hash1 = chunkOrdering1.hashCode();
- int equalHash1 = equalChunkOrdering1.hashCode();
- int hash2 = chunkOrdering2.hashCode();
-
- assertThat(hash1).isEqualTo(equalHash1);
- assertThat(hash1).isNotEqualTo(hash2);
- }
-}
diff --git a/services/robotests/backup/src/com/android/server/backup/encryption/chunking/ByteRangeTest.java b/services/robotests/backup/src/com/android/server/backup/encryption/chunking/ByteRangeTest.java
deleted file mode 100644
index 8df08262c9fa..000000000000
--- a/services/robotests/backup/src/com/android/server/backup/encryption/chunking/ByteRangeTest.java
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright (C) 2018 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.encryption.chunking;
-
-import static org.junit.Assert.assertEquals;
-import static org.testng.Assert.assertThrows;
-
-import android.platform.test.annotations.Presubmit;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.robolectric.RobolectricTestRunner;
-
-/** Tests for {@link ByteRange}. */
-@RunWith(RobolectricTestRunner.class)
-@Presubmit
-public class ByteRangeTest {
- @Test
- public void getLength_includesEnd() throws Exception {
- ByteRange byteRange = new ByteRange(5, 10);
-
- int length = byteRange.getLength();
-
- assertEquals(6, length);
- }
-
- @Test
- public void constructor_rejectsNegativeStart() {
- assertThrows(IllegalArgumentException.class, () -> new ByteRange(-1, 10));
- }
-
- @Test
- public void constructor_rejectsEndBeforeStart() {
- assertThrows(IllegalArgumentException.class, () -> new ByteRange(10, 9));
- }
-
- @Test
- public void extend_withZeroLength_throwsException() {
- ByteRange byteRange = new ByteRange(5, 10);
-
- assertThrows(IllegalArgumentException.class, () -> byteRange.extend(0));
- }
-}
diff --git a/services/robotests/backup/src/com/android/server/backup/encryption/chunking/ChunkEncryptorTest.java b/services/robotests/backup/src/com/android/server/backup/encryption/chunking/ChunkEncryptorTest.java
deleted file mode 100644
index d0e5fb335da9..000000000000
--- a/services/robotests/backup/src/com/android/server/backup/encryption/chunking/ChunkEncryptorTest.java
+++ /dev/null
@@ -1,157 +0,0 @@
-/*
- * Copyright (C) 2018 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.encryption.chunking;
-
-import static com.android.server.backup.testing.CryptoTestUtils.generateAesKey;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.Mockito.doAnswer;
-import static org.mockito.Mockito.mock;
-
-import static java.nio.charset.StandardCharsets.UTF_8;
-
-import android.platform.test.annotations.Presubmit;
-
-import com.android.server.backup.encryption.chunk.ChunkHash;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.invocation.InvocationOnMock;
-import org.mockito.stubbing.Answer;
-import org.robolectric.RobolectricTestRunner;
-
-import java.security.SecureRandom;
-
-import javax.crypto.Cipher;
-import javax.crypto.Mac;
-import javax.crypto.SecretKey;
-import javax.crypto.spec.GCMParameterSpec;
-
-@RunWith(RobolectricTestRunner.class)
-@Presubmit
-public class ChunkEncryptorTest {
- private static final String MAC_ALGORITHM = "HmacSHA256";
- private static final String CIPHER_ALGORITHM = "AES/GCM/NoPadding";
- private static final int GCM_NONCE_LENGTH_BYTES = 12;
- private static final int GCM_TAG_LENGTH_BYTES = 16;
- private static final String CHUNK_PLAINTEXT =
- "A little Learning is a dang'rous Thing;\n"
- + "Drink deep, or taste not the Pierian Spring:\n"
- + "There shallow Draughts intoxicate the Brain,\n"
- + "And drinking largely sobers us again.";
- private static final byte[] PLAINTEXT_BYTES = CHUNK_PLAINTEXT.getBytes(UTF_8);
- private static final byte[] NONCE_1 = "0123456789abc".getBytes(UTF_8);
- private static final byte[] NONCE_2 = "123456789abcd".getBytes(UTF_8);
-
- private static final byte[][] NONCES = new byte[][] {NONCE_1, NONCE_2};
-
- @Mock private SecureRandom mSecureRandomMock;
- private SecretKey mSecretKey;
- private ChunkHash mPlaintextHash;
- private ChunkEncryptor mChunkEncryptor;
-
- @Before
- public void setUp() throws Exception {
- mSecretKey = generateAesKey();
- ChunkHasher chunkHasher = new ChunkHasher(mSecretKey);
- mPlaintextHash = chunkHasher.computeHash(PLAINTEXT_BYTES);
- mSecureRandomMock = mock(SecureRandom.class);
- mChunkEncryptor = new ChunkEncryptor(mSecretKey, mSecureRandomMock);
-
- // Return NONCE_1, then NONCE_2 for invocations of mSecureRandomMock.nextBytes().
- doAnswer(
- new Answer<Void>() {
- private int mInvocation = 0;
-
- @Override
- public Void answer(InvocationOnMock invocation) {
- byte[] nonceDestination = invocation.getArgument(0);
- System.arraycopy(
- NONCES[this.mInvocation],
- 0,
- nonceDestination,
- 0,
- GCM_NONCE_LENGTH_BYTES);
- this.mInvocation++;
- return null;
- }
- })
- .when(mSecureRandomMock)
- .nextBytes(any(byte[].class));
- }
-
- @Test
- public void encrypt_withHash_resultContainsHashAsKey() throws Exception {
- EncryptedChunk chunk = mChunkEncryptor.encrypt(mPlaintextHash, PLAINTEXT_BYTES);
-
- assertThat(chunk.key()).isEqualTo(mPlaintextHash);
- }
-
- @Test
- public void encrypt_generatesHmacOfPlaintext() throws Exception {
- EncryptedChunk chunk = mChunkEncryptor.encrypt(mPlaintextHash, PLAINTEXT_BYTES);
-
- byte[] generatedHash = chunk.key().getHash();
- Mac mac = Mac.getInstance(MAC_ALGORITHM);
- mac.init(mSecretKey);
- byte[] plaintextHmac = mac.doFinal(PLAINTEXT_BYTES);
- assertThat(generatedHash).isEqualTo(plaintextHmac);
- }
-
- @Test
- public void encrypt_whenInvokedAgain_generatesNewNonce() throws Exception {
- EncryptedChunk chunk1 = mChunkEncryptor.encrypt(mPlaintextHash, PLAINTEXT_BYTES);
-
- EncryptedChunk chunk2 = mChunkEncryptor.encrypt(mPlaintextHash, PLAINTEXT_BYTES);
-
- assertThat(chunk1.nonce()).isNotEqualTo(chunk2.nonce());
- }
-
- @Test
- public void encrypt_whenInvokedAgain_generatesNewCiphertext() throws Exception {
- EncryptedChunk chunk1 = mChunkEncryptor.encrypt(mPlaintextHash, PLAINTEXT_BYTES);
-
- EncryptedChunk chunk2 = mChunkEncryptor.encrypt(mPlaintextHash, PLAINTEXT_BYTES);
-
- assertThat(chunk1.encryptedBytes()).isNotEqualTo(chunk2.encryptedBytes());
- }
-
- @Test
- public void encrypt_generates12ByteNonce() throws Exception {
- EncryptedChunk encryptedChunk = mChunkEncryptor.encrypt(mPlaintextHash, PLAINTEXT_BYTES);
-
- byte[] nonce = encryptedChunk.nonce();
- assertThat(nonce).hasLength(GCM_NONCE_LENGTH_BYTES);
- }
-
- @Test
- public void encrypt_decryptedResultCorrespondsToPlaintext() throws Exception {
- EncryptedChunk chunk = mChunkEncryptor.encrypt(mPlaintextHash, PLAINTEXT_BYTES);
-
- Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
- cipher.init(
- Cipher.DECRYPT_MODE,
- mSecretKey,
- new GCMParameterSpec(GCM_TAG_LENGTH_BYTES * 8, chunk.nonce()));
- byte[] decrypted = cipher.doFinal(chunk.encryptedBytes());
- assertThat(decrypted).isEqualTo(PLAINTEXT_BYTES);
- }
-}
diff --git a/services/robotests/backup/src/com/android/server/backup/encryption/chunking/ChunkHasherTest.java b/services/robotests/backup/src/com/android/server/backup/encryption/chunking/ChunkHasherTest.java
deleted file mode 100644
index 2bbbf2857146..000000000000
--- a/services/robotests/backup/src/com/android/server/backup/encryption/chunking/ChunkHasherTest.java
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * Copyright (C) 2018 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.encryption.chunking;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import android.platform.test.annotations.Presubmit;
-
-import com.android.server.backup.encryption.chunk.ChunkHash;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.robolectric.RobolectricTestRunner;
-
-import javax.crypto.Mac;
-import javax.crypto.SecretKey;
-import javax.crypto.spec.SecretKeySpec;
-
-@RunWith(RobolectricTestRunner.class)
-@Presubmit
-public class ChunkHasherTest {
- private static final String KEY_ALGORITHM = "AES";
- private static final String MAC_ALGORITHM = "HmacSHA256";
-
- private static final byte[] TEST_KEY = {100, 120};
- private static final byte[] TEST_DATA = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13};
-
- private SecretKey mSecretKey;
- private ChunkHasher mChunkHasher;
-
- @Before
- public void setUp() throws Exception {
- mSecretKey = new SecretKeySpec(TEST_KEY, KEY_ALGORITHM);
- mChunkHasher = new ChunkHasher(mSecretKey);
- }
-
- @Test
- public void computeHash_returnsHmacForData() throws Exception {
- ChunkHash chunkHash = mChunkHasher.computeHash(TEST_DATA);
-
- byte[] hash = chunkHash.getHash();
- Mac mac = Mac.getInstance(MAC_ALGORITHM);
- mac.init(mSecretKey);
- byte[] expectedHash = mac.doFinal(TEST_DATA);
- assertThat(hash).isEqualTo(expectedHash);
- }
-
- @Test
- public void computeHash_generates256BitHmac() throws Exception {
- int expectedLength = 256 / Byte.SIZE;
-
- byte[] hash = mChunkHasher.computeHash(TEST_DATA).getHash();
-
- assertThat(hash).hasLength(expectedLength);
- }
-}
diff --git a/services/robotests/backup/src/com/android/server/backup/encryption/chunking/DiffScriptBackupWriterTest.java b/services/robotests/backup/src/com/android/server/backup/encryption/chunking/DiffScriptBackupWriterTest.java
deleted file mode 100644
index 2af6f2bee8ff..000000000000
--- a/services/robotests/backup/src/com/android/server/backup/encryption/chunking/DiffScriptBackupWriterTest.java
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * Copyright (C) 2018 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.encryption.chunking;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.mockito.Mockito.atLeastOnce;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
-
-import android.platform.test.annotations.Presubmit;
-
-import com.google.common.primitives.Bytes;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.ArgumentCaptor;
-import org.mockito.Captor;
-import org.mockito.Mock;
-import org.robolectric.RobolectricTestRunner;
-
-import java.io.IOException;
-
-/** Tests for {@link DiffScriptBackupWriter}. */
-@RunWith(RobolectricTestRunner.class)
-@Presubmit
-public class DiffScriptBackupWriterTest {
- private static final byte[] TEST_BYTES = {1, 2, 3, 4, 5, 6, 7, 8, 9};
-
- @Captor private ArgumentCaptor<Byte> mBytesCaptor;
- @Mock private SingleStreamDiffScriptWriter mDiffScriptWriter;
- private BackupWriter mBackupWriter;
-
- @Before
- public void setUp() {
- mDiffScriptWriter = mock(SingleStreamDiffScriptWriter.class);
- mBackupWriter = new DiffScriptBackupWriter(mDiffScriptWriter);
- mBytesCaptor = ArgumentCaptor.forClass(Byte.class);
- }
-
- @Test
- public void writeBytes_writesBytesToWriter() throws Exception {
- mBackupWriter.writeBytes(TEST_BYTES);
-
- verify(mDiffScriptWriter, atLeastOnce()).writeByte(mBytesCaptor.capture());
- assertThat(mBytesCaptor.getAllValues())
- .containsExactlyElementsIn(Bytes.asList(TEST_BYTES))
- .inOrder();
- }
-
- @Test
- public void writeChunk_writesChunkToWriter() throws Exception {
- mBackupWriter.writeChunk(0, 10);
-
- verify(mDiffScriptWriter).writeChunk(0, 10);
- }
-
- @Test
- public void getBytesWritten_returnsTotalSum() throws Exception {
- mBackupWriter.writeBytes(TEST_BYTES);
- mBackupWriter.writeBytes(TEST_BYTES);
- mBackupWriter.writeChunk(/*start=*/ 0, /*length=*/ 10);
-
- long bytesWritten = mBackupWriter.getBytesWritten();
-
- assertThat(bytesWritten).isEqualTo(2 * TEST_BYTES.length + 10);
- }
-
- @Test
- public void flush_flushesWriter() throws IOException {
- mBackupWriter.flush();
-
- verify(mDiffScriptWriter).flush();
- }
-}
diff --git a/services/robotests/backup/src/com/android/server/backup/encryption/chunking/EncryptedChunkTest.java b/services/robotests/backup/src/com/android/server/backup/encryption/chunking/EncryptedChunkTest.java
deleted file mode 100644
index 8e801a133909..000000000000
--- a/services/robotests/backup/src/com/android/server/backup/encryption/chunking/EncryptedChunkTest.java
+++ /dev/null
@@ -1,133 +0,0 @@
-/*
- * Copyright (C) 2018 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.encryption.chunking;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.testng.Assert.assertThrows;
-
-import android.platform.test.annotations.Presubmit;
-
-import com.android.server.backup.encryption.chunk.ChunkHash;
-
-import com.google.common.primitives.Bytes;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.robolectric.RobolectricTestRunner;
-
-import java.util.Arrays;
-
-@RunWith(RobolectricTestRunner.class)
-@Presubmit
-public class EncryptedChunkTest {
- private static final byte[] CHUNK_HASH_1_BYTES =
- Arrays.copyOf(new byte[] {1}, ChunkHash.HASH_LENGTH_BYTES);
- private static final byte[] NONCE_1 =
- Arrays.copyOf(new byte[] {2}, EncryptedChunk.NONCE_LENGTH_BYTES);
- private static final byte[] ENCRYPTED_BYTES_1 =
- Arrays.copyOf(new byte[] {3}, EncryptedChunk.KEY_LENGTH_BYTES);
-
- private static final byte[] CHUNK_HASH_2_BYTES =
- Arrays.copyOf(new byte[] {4}, ChunkHash.HASH_LENGTH_BYTES);
- private static final byte[] NONCE_2 =
- Arrays.copyOf(new byte[] {5}, EncryptedChunk.NONCE_LENGTH_BYTES);
- private static final byte[] ENCRYPTED_BYTES_2 =
- Arrays.copyOf(new byte[] {6}, EncryptedChunk.KEY_LENGTH_BYTES);
-
- @Test
- public void testCreate_withIncorrectLength_throwsException() {
- ChunkHash chunkHash = new ChunkHash(CHUNK_HASH_1_BYTES);
- byte[] shortNonce = Arrays.copyOf(new byte[] {2}, EncryptedChunk.NONCE_LENGTH_BYTES - 1);
-
- assertThrows(
- IllegalArgumentException.class,
- () -> EncryptedChunk.create(chunkHash, shortNonce, ENCRYPTED_BYTES_1));
- }
-
- @Test
- public void testEncryptedBytes_forNewlyCreatedObject_returnsCorrectValue() {
- ChunkHash chunkHash = new ChunkHash(CHUNK_HASH_1_BYTES);
- EncryptedChunk encryptedChunk =
- EncryptedChunk.create(chunkHash, NONCE_1, ENCRYPTED_BYTES_1);
-
- byte[] returnedBytes = encryptedChunk.encryptedBytes();
-
- assertThat(returnedBytes)
- .asList()
- .containsExactlyElementsIn(Bytes.asList(ENCRYPTED_BYTES_1))
- .inOrder();
- }
-
- @Test
- public void testKey_forNewlyCreatedObject_returnsCorrectValue() {
- ChunkHash chunkHash = new ChunkHash(CHUNK_HASH_1_BYTES);
- EncryptedChunk encryptedChunk =
- EncryptedChunk.create(chunkHash, NONCE_1, ENCRYPTED_BYTES_1);
-
- ChunkHash returnedKey = encryptedChunk.key();
-
- assertThat(returnedKey).isEqualTo(chunkHash);
- }
-
- @Test
- public void testNonce_forNewlycreatedObject_returnCorrectValue() {
- ChunkHash chunkHash = new ChunkHash(CHUNK_HASH_1_BYTES);
- EncryptedChunk encryptedChunk =
- EncryptedChunk.create(chunkHash, NONCE_1, ENCRYPTED_BYTES_1);
-
- byte[] returnedNonce = encryptedChunk.nonce();
-
- assertThat(returnedNonce).asList().containsExactlyElementsIn(Bytes.asList(NONCE_1));
- }
-
- @Test
- public void testEquals() {
- ChunkHash chunkHash1 = new ChunkHash(CHUNK_HASH_1_BYTES);
- ChunkHash equalChunkHash1 = new ChunkHash(CHUNK_HASH_1_BYTES);
- ChunkHash chunkHash2 = new ChunkHash(CHUNK_HASH_2_BYTES);
- EncryptedChunk encryptedChunk1 =
- EncryptedChunk.create(chunkHash1, NONCE_1, ENCRYPTED_BYTES_1);
- EncryptedChunk equalEncryptedChunk1 =
- EncryptedChunk.create(equalChunkHash1, NONCE_1, ENCRYPTED_BYTES_1);
- EncryptedChunk encryptedChunk2 =
- EncryptedChunk.create(chunkHash2, NONCE_2, ENCRYPTED_BYTES_2);
-
- assertThat(encryptedChunk1).isEqualTo(equalEncryptedChunk1);
- assertThat(encryptedChunk1).isNotEqualTo(encryptedChunk2);
- }
-
- @Test
- public void testHashCode() {
- ChunkHash chunkHash1 = new ChunkHash(CHUNK_HASH_1_BYTES);
- ChunkHash equalChunkHash1 = new ChunkHash(CHUNK_HASH_1_BYTES);
- ChunkHash chunkHash2 = new ChunkHash(CHUNK_HASH_2_BYTES);
- EncryptedChunk encryptedChunk1 =
- EncryptedChunk.create(chunkHash1, NONCE_1, ENCRYPTED_BYTES_1);
- EncryptedChunk equalEncryptedChunk1 =
- EncryptedChunk.create(equalChunkHash1, NONCE_1, ENCRYPTED_BYTES_1);
- EncryptedChunk encryptedChunk2 =
- EncryptedChunk.create(chunkHash2, NONCE_2, ENCRYPTED_BYTES_2);
-
- int hash1 = encryptedChunk1.hashCode();
- int equalHash1 = equalEncryptedChunk1.hashCode();
- int hash2 = encryptedChunk2.hashCode();
-
- assertThat(hash1).isEqualTo(equalHash1);
- assertThat(hash1).isNotEqualTo(hash2);
- }
-}
diff --git a/services/robotests/backup/src/com/android/server/backup/encryption/chunking/InlineLengthsEncryptedChunkEncoderTest.java b/services/robotests/backup/src/com/android/server/backup/encryption/chunking/InlineLengthsEncryptedChunkEncoderTest.java
deleted file mode 100644
index 2f872beacd17..000000000000
--- a/services/robotests/backup/src/com/android/server/backup/encryption/chunking/InlineLengthsEncryptedChunkEncoderTest.java
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * Copyright (C) 2018 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.encryption.chunking;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.mockito.Mockito.inOrder;
-import static org.mockito.Mockito.mock;
-
-import android.platform.test.annotations.Presubmit;
-
-import com.android.server.backup.encryption.chunk.ChunkHash;
-import com.android.server.backup.encryption.chunk.ChunksMetadataProto;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.InOrder;
-import org.mockito.Mock;
-import org.robolectric.RobolectricTestRunner;
-
-import java.util.Arrays;
-
-@RunWith(RobolectricTestRunner.class)
-@Presubmit
-public class InlineLengthsEncryptedChunkEncoderTest {
-
- private static final byte[] TEST_NONCE =
- Arrays.copyOf(new byte[] {1}, EncryptedChunk.NONCE_LENGTH_BYTES);
- private static final byte[] TEST_KEY_DATA =
- Arrays.copyOf(new byte[] {2}, EncryptedChunk.KEY_LENGTH_BYTES);
- private static final byte[] TEST_DATA = {5, 4, 5, 7, 10, 12, 1, 2, 9};
-
- @Mock private BackupWriter mMockBackupWriter;
- private ChunkHash mTestKey;
- private EncryptedChunk mTestChunk;
- private EncryptedChunkEncoder mEncoder;
-
- @Before
- public void setUp() throws Exception {
- mMockBackupWriter = mock(BackupWriter.class);
- mTestKey = new ChunkHash(TEST_KEY_DATA);
- mTestChunk = EncryptedChunk.create(mTestKey, TEST_NONCE, TEST_DATA);
- mEncoder = new InlineLengthsEncryptedChunkEncoder();
- }
-
- @Test
- public void writeChunkToWriter_writesLengthThenNonceThenData() throws Exception {
- mEncoder.writeChunkToWriter(mMockBackupWriter, mTestChunk);
-
- InOrder inOrder = inOrder(mMockBackupWriter);
- inOrder.verify(mMockBackupWriter)
- .writeBytes(
- InlineLengthsEncryptedChunkEncoder.toByteArray(
- TEST_NONCE.length + TEST_DATA.length));
- inOrder.verify(mMockBackupWriter).writeBytes(TEST_NONCE);
- inOrder.verify(mMockBackupWriter).writeBytes(TEST_DATA);
- }
-
- @Test
- public void getEncodedLengthOfChunk_returnsSumOfNonceAndDataLengths() {
- int encodedLength = mEncoder.getEncodedLengthOfChunk(mTestChunk);
-
- assertThat(encodedLength).isEqualTo(Integer.BYTES + TEST_NONCE.length + TEST_DATA.length);
- }
-
- @Test
- public void getChunkOrderingType_returnsExplicitStartsType() {
- assertThat(mEncoder.getChunkOrderingType()).isEqualTo(ChunksMetadataProto.INLINE_LENGTHS);
- }
-}
diff --git a/services/robotests/backup/src/com/android/server/backup/encryption/chunking/LengthlessEncryptedChunkEncoderTest.java b/services/robotests/backup/src/com/android/server/backup/encryption/chunking/LengthlessEncryptedChunkEncoderTest.java
deleted file mode 100644
index 978bddb7301a..000000000000
--- a/services/robotests/backup/src/com/android/server/backup/encryption/chunking/LengthlessEncryptedChunkEncoderTest.java
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * Copyright (C) 2018 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.encryption.chunking;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.mockito.Mockito.inOrder;
-import static org.mockito.Mockito.mock;
-
-import android.platform.test.annotations.Presubmit;
-
-import com.android.server.backup.encryption.chunk.ChunkHash;
-import com.android.server.backup.encryption.chunk.ChunksMetadataProto;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.InOrder;
-import org.mockito.Mock;
-import org.robolectric.RobolectricTestRunner;
-
-import java.util.Arrays;
-
-@RunWith(RobolectricTestRunner.class)
-@Presubmit
-public class LengthlessEncryptedChunkEncoderTest {
- private static final byte[] TEST_NONCE =
- Arrays.copyOf(new byte[] {1}, EncryptedChunk.NONCE_LENGTH_BYTES);
- private static final byte[] TEST_KEY_DATA =
- Arrays.copyOf(new byte[] {2}, EncryptedChunk.KEY_LENGTH_BYTES);
- private static final byte[] TEST_DATA = {5, 4, 5, 7, 10, 12, 1, 2, 9};
-
- @Mock private BackupWriter mMockBackupWriter;
- private ChunkHash mTestKey;
- private EncryptedChunk mTestChunk;
- private EncryptedChunkEncoder mEncoder;
-
- @Before
- public void setUp() throws Exception {
- mMockBackupWriter = mock(BackupWriter.class);
- mTestKey = new ChunkHash(TEST_KEY_DATA);
- mTestChunk = EncryptedChunk.create(mTestKey, TEST_NONCE, TEST_DATA);
- mEncoder = new LengthlessEncryptedChunkEncoder();
- }
-
- @Test
- public void writeChunkToWriter_writesNonceThenData() throws Exception {
- mEncoder.writeChunkToWriter(mMockBackupWriter, mTestChunk);
-
- InOrder inOrder = inOrder(mMockBackupWriter);
- inOrder.verify(mMockBackupWriter).writeBytes(TEST_NONCE);
- inOrder.verify(mMockBackupWriter).writeBytes(TEST_DATA);
- }
-
- @Test
- public void getEncodedLengthOfChunk_returnsSumOfNonceAndDataLengths() {
- int encodedLength = mEncoder.getEncodedLengthOfChunk(mTestChunk);
-
- assertThat(encodedLength).isEqualTo(TEST_NONCE.length + TEST_DATA.length);
- }
-
- @Test
- public void getChunkOrderingType_returnsExplicitStartsType() {
- assertThat(mEncoder.getChunkOrderingType()).isEqualTo(ChunksMetadataProto.EXPLICIT_STARTS);
- }
-}
diff --git a/services/robotests/backup/src/com/android/server/backup/encryption/chunking/RawBackupWriterTest.java b/services/robotests/backup/src/com/android/server/backup/encryption/chunking/RawBackupWriterTest.java
deleted file mode 100644
index 19ef8fb339ba..000000000000
--- a/services/robotests/backup/src/com/android/server/backup/encryption/chunking/RawBackupWriterTest.java
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * Copyright (C) 2018 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.encryption.chunking;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
-import static org.testng.Assert.assertThrows;
-
-import android.platform.test.annotations.Presubmit;
-
-import com.google.common.primitives.Bytes;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.robolectric.RobolectricTestRunner;
-
-import java.io.ByteArrayOutputStream;
-
-@RunWith(RobolectricTestRunner.class)
-@Presubmit
-public class RawBackupWriterTest {
- private static final byte[] TEST_BYTES = {1, 2, 3, 4, 5, 6};
-
- private BackupWriter mWriter;
- private ByteArrayOutputStream mOutput;
-
- @Before
- public void setUp() {
- mOutput = new ByteArrayOutputStream();
- mWriter = new RawBackupWriter(mOutput);
- }
-
- @Test
- public void writeBytes_writesToOutputStream() throws Exception {
- mWriter.writeBytes(TEST_BYTES);
-
- assertThat(mOutput.toByteArray())
- .asList()
- .containsExactlyElementsIn(Bytes.asList(TEST_BYTES))
- .inOrder();
- }
-
- @Test
- public void writeChunk_throwsUnsupportedOperationException() throws Exception {
- assertThrows(UnsupportedOperationException.class, () -> mWriter.writeChunk(0, 0));
- }
-
- @Test
- public void getBytesWritten_returnsTotalSum() throws Exception {
- mWriter.writeBytes(TEST_BYTES);
- mWriter.writeBytes(TEST_BYTES);
-
- long bytesWritten = mWriter.getBytesWritten();
-
- assertThat(bytesWritten).isEqualTo(2 * TEST_BYTES.length);
- }
-
- @Test
- public void flush_flushesOutputStream() throws Exception {
- mOutput = mock(ByteArrayOutputStream.class);
- mWriter = new RawBackupWriter(mOutput);
-
- mWriter.flush();
-
- verify(mOutput).flush();
- }
-}
diff --git a/services/robotests/backup/src/com/android/server/backup/encryption/chunking/SingleStreamDiffScriptWriterTest.java b/services/robotests/backup/src/com/android/server/backup/encryption/chunking/SingleStreamDiffScriptWriterTest.java
deleted file mode 100644
index 73baf80a2c70..000000000000
--- a/services/robotests/backup/src/com/android/server/backup/encryption/chunking/SingleStreamDiffScriptWriterTest.java
+++ /dev/null
@@ -1,128 +0,0 @@
-/*
- * Copyright (C) 2018 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.encryption.chunking;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
-import static org.testng.Assert.assertThrows;
-
-import android.platform.test.annotations.Presubmit;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.robolectric.RobolectricTestRunner;
-
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.util.Locale;
-
-/** Tests for {@link SingleStreamDiffScriptWriter}. */
-@RunWith(RobolectricTestRunner.class)
-@Presubmit
-public class SingleStreamDiffScriptWriterTest {
- private static final int MAX_CHUNK_SIZE_IN_BYTES = 256;
- /** By default this Locale does not use Arabic numbers for %d formatting. */
- private static final Locale HINDI = new Locale("hi", "IN");
-
- private Locale mDefaultLocale;
- private ByteArrayOutputStream mOutputStream;
- private SingleStreamDiffScriptWriter mDiffScriptWriter;
-
- @Before
- public void setUp() {
- mDefaultLocale = Locale.getDefault();
- mOutputStream = new ByteArrayOutputStream();
- mDiffScriptWriter =
- new SingleStreamDiffScriptWriter(mOutputStream, MAX_CHUNK_SIZE_IN_BYTES);
- }
-
- @After
- public void tearDown() {
- Locale.setDefault(mDefaultLocale);
- }
-
- @Test
- public void writeChunk_withNegativeStart_throwsException() {
- assertThrows(
- IllegalArgumentException.class,
- () -> mDiffScriptWriter.writeChunk(-1, 50));
- }
-
- @Test
- public void writeChunk_withZeroLength_throwsException() {
- assertThrows(
- IllegalArgumentException.class,
- () -> mDiffScriptWriter.writeChunk(0, 0));
- }
-
- @Test
- public void writeChunk_withExistingBytesInBuffer_writesBufferFirst()
- throws IOException {
- String testString = "abcd";
- writeStringAsBytesToWriter(testString, mDiffScriptWriter);
-
- mDiffScriptWriter.writeChunk(0, 20);
- mDiffScriptWriter.flush();
-
- // Expected format: length of abcd, newline, abcd, newline, chunk start - chunk end
- assertThat(mOutputStream.toString("UTF-8")).isEqualTo(
- String.format("%d\n%s\n%d-%d\n", testString.length(), testString, 0, 19));
- }
-
- @Test
- public void writeChunk_overlappingPreviousChunk_combinesChunks() throws IOException {
- mDiffScriptWriter.writeChunk(3, 4);
-
- mDiffScriptWriter.writeChunk(7, 5);
- mDiffScriptWriter.flush();
-
- assertThat(mOutputStream.toString("UTF-8")).isEqualTo(String.format("3-11\n"));
- }
-
- @Test
- public void writeChunk_formatsByteIndexesUsingArabicNumbers() throws Exception {
- Locale.setDefault(HINDI);
-
- mDiffScriptWriter.writeChunk(0, 12345);
- mDiffScriptWriter.flush();
-
- assertThat(mOutputStream.toString("UTF-8")).isEqualTo("0-12344\n");
- }
-
- @Test
- public void flush_flushesOutputStream() throws IOException {
- ByteArrayOutputStream mockOutputStream = mock(ByteArrayOutputStream.class);
- SingleStreamDiffScriptWriter diffScriptWriter =
- new SingleStreamDiffScriptWriter(mockOutputStream, MAX_CHUNK_SIZE_IN_BYTES);
-
- diffScriptWriter.flush();
-
- verify(mockOutputStream).flush();
- }
-
- private void writeStringAsBytesToWriter(String string, SingleStreamDiffScriptWriter writer)
- throws IOException {
- byte[] bytes = string.getBytes("UTF-8");
- for (int i = 0; i < bytes.length; i++) {
- writer.writeByte(bytes[i]);
- }
- }
-}
diff --git a/services/robotests/backup/src/com/android/server/backup/encryption/chunking/cdc/ContentDefinedChunkerTest.java b/services/robotests/backup/src/com/android/server/backup/encryption/chunking/cdc/ContentDefinedChunkerTest.java
deleted file mode 100644
index 77b734785424..000000000000
--- a/services/robotests/backup/src/com/android/server/backup/encryption/chunking/cdc/ContentDefinedChunkerTest.java
+++ /dev/null
@@ -1,232 +0,0 @@
-/*
- * Copyright (C) 2018 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.encryption.chunking.cdc;
-
-import static com.android.server.backup.testing.CryptoTestUtils.generateAesKey;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.testng.Assert.assertThrows;
-
-import static java.nio.charset.StandardCharsets.UTF_8;
-
-import android.platform.test.annotations.Presubmit;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.robolectric.RobolectricTestRunner;
-
-import java.io.ByteArrayInputStream;
-import java.io.InputStream;
-import java.security.GeneralSecurityException;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Random;
-
-import javax.crypto.SecretKey;
-
-/** Tests for {@link ContentDefinedChunker}. */
-@RunWith(RobolectricTestRunner.class)
-@Presubmit
-public class ContentDefinedChunkerTest {
- private static final int WINDOW_SIZE_BYTES = 31;
- private static final int MIN_SIZE_BYTES = 40;
- private static final int MAX_SIZE_BYTES = 300;
- private static final String CHUNK_BOUNDARY = "<----------BOUNDARY----------->";
- private static final byte[] CHUNK_BOUNDARY_BYTES = CHUNK_BOUNDARY.getBytes(UTF_8);
- private static final String CHUNK_1 = "This is the first chunk";
- private static final String CHUNK_2 = "And this is the second chunk";
- private static final String CHUNK_3 = "And finally here is the third chunk";
- private static final String SMALL_CHUNK = "12345678";
-
- private FingerprintMixer mFingerprintMixer;
- private RabinFingerprint64 mRabinFingerprint64;
- private ContentDefinedChunker mChunker;
-
- /** Set up a {@link ContentDefinedChunker} and dependencies for use in the tests. */
- @Before
- public void setUp() throws Exception {
- SecretKey secretKey = generateAesKey();
- byte[] salt = new byte[FingerprintMixer.SALT_LENGTH_BYTES];
- Random random = new Random();
- random.nextBytes(salt);
- mFingerprintMixer = new FingerprintMixer(secretKey, salt);
-
- mRabinFingerprint64 = new RabinFingerprint64();
- long chunkBoundaryFingerprint = calculateFingerprint(CHUNK_BOUNDARY_BYTES);
- mChunker =
- new ContentDefinedChunker(
- MIN_SIZE_BYTES,
- MAX_SIZE_BYTES,
- mRabinFingerprint64,
- mFingerprintMixer,
- (fingerprint) -> fingerprint == chunkBoundaryFingerprint);
- }
-
- /**
- * Creating a {@link ContentDefinedChunker} with a minimum chunk size that is smaller than the
- * window size should throw an {@link IllegalArgumentException}.
- */
- @Test
- public void create_withMinChunkSizeSmallerThanWindowSize_throwsIllegalArgumentException() {
- assertThrows(
- IllegalArgumentException.class,
- () ->
- new ContentDefinedChunker(
- WINDOW_SIZE_BYTES - 1,
- MAX_SIZE_BYTES,
- mRabinFingerprint64,
- mFingerprintMixer,
- null));
- }
-
- /**
- * Creating a {@link ContentDefinedChunker} with a maximum chunk size that is smaller than the
- * minimum chunk size should throw an {@link IllegalArgumentException}.
- */
- @Test
- public void create_withMaxChunkSizeSmallerThanMinChunkSize_throwsIllegalArgumentException() {
- assertThrows(
- IllegalArgumentException.class,
- () ->
- new ContentDefinedChunker(
- MIN_SIZE_BYTES,
- MIN_SIZE_BYTES - 1,
- mRabinFingerprint64,
- mFingerprintMixer,
- null));
- }
-
- /**
- * {@link ContentDefinedChunker#chunkify(InputStream, Chunker.ChunkConsumer)} should split the
- * input stream across chunk boundaries by default.
- */
- @Test
- public void chunkify_withLargeChunks_splitsIntoChunksAcrossBoundaries() throws Exception {
- byte[] input =
- (CHUNK_1 + CHUNK_BOUNDARY + CHUNK_2 + CHUNK_BOUNDARY + CHUNK_3).getBytes(UTF_8);
- ByteArrayInputStream inputStream = new ByteArrayInputStream(input);
- ArrayList<String> result = new ArrayList<>();
-
- mChunker.chunkify(inputStream, (chunk) -> result.add(new String(chunk, UTF_8)));
-
- assertThat(result)
- .containsExactly(CHUNK_1 + CHUNK_BOUNDARY, CHUNK_2 + CHUNK_BOUNDARY, CHUNK_3)
- .inOrder();
- }
-
- /** Chunks should be combined across boundaries until they reach the minimum chunk size. */
- @Test
- public void chunkify_withSmallChunks_combinesChunksUntilMinSize() throws Exception {
- byte[] input =
- (SMALL_CHUNK + CHUNK_BOUNDARY + CHUNK_2 + CHUNK_BOUNDARY + CHUNK_3).getBytes(UTF_8);
- ByteArrayInputStream inputStream = new ByteArrayInputStream(input);
- ArrayList<String> result = new ArrayList<>();
-
- mChunker.chunkify(inputStream, (chunk) -> result.add(new String(chunk, UTF_8)));
-
- assertThat(result)
- .containsExactly(SMALL_CHUNK + CHUNK_BOUNDARY + CHUNK_2 + CHUNK_BOUNDARY, CHUNK_3)
- .inOrder();
- assertThat(result.get(0).length()).isAtLeast(MIN_SIZE_BYTES);
- }
-
- /** Chunks can not be larger than the maximum chunk size. */
- @Test
- public void chunkify_doesNotProduceChunksLargerThanMaxSize() throws Exception {
- byte[] largeInput = new byte[MAX_SIZE_BYTES * 10];
- Arrays.fill(largeInput, "a".getBytes(UTF_8)[0]);
- ByteArrayInputStream inputStream = new ByteArrayInputStream(largeInput);
- ArrayList<String> result = new ArrayList<>();
-
- mChunker.chunkify(inputStream, (chunk) -> result.add(new String(chunk, UTF_8)));
-
- byte[] expectedChunkBytes = new byte[MAX_SIZE_BYTES];
- Arrays.fill(expectedChunkBytes, "a".getBytes(UTF_8)[0]);
- String expectedChunk = new String(expectedChunkBytes, UTF_8);
- assertThat(result)
- .containsExactly(
- expectedChunk,
- expectedChunk,
- expectedChunk,
- expectedChunk,
- expectedChunk,
- expectedChunk,
- expectedChunk,
- expectedChunk,
- expectedChunk,
- expectedChunk)
- .inOrder();
- }
-
- /**
- * If the input stream signals zero availablility, {@link
- * ContentDefinedChunker#chunkify(InputStream, Chunker.ChunkConsumer)} should still work.
- */
- @Test
- public void chunkify_withInputStreamReturningZeroAvailability_returnsChunks() throws Exception {
- byte[] input = (SMALL_CHUNK + CHUNK_BOUNDARY + CHUNK_2).getBytes(UTF_8);
- ZeroAvailabilityInputStream zeroAvailabilityInputStream =
- new ZeroAvailabilityInputStream(input);
- ArrayList<String> result = new ArrayList<>();
-
- mChunker.chunkify(
- zeroAvailabilityInputStream, (chunk) -> result.add(new String(chunk, UTF_8)));
-
- assertThat(result).containsExactly(SMALL_CHUNK + CHUNK_BOUNDARY + CHUNK_2).inOrder();
- }
-
- /**
- * {@link ContentDefinedChunker#chunkify(InputStream, Chunker.ChunkConsumer)} should rethrow any
- * exception thrown by its consumer.
- */
- @Test
- public void chunkify_whenConsumerThrowsException_rethrowsException() throws Exception {
- ByteArrayInputStream inputStream = new ByteArrayInputStream(new byte[] {1});
-
- assertThrows(
- GeneralSecurityException.class,
- () ->
- mChunker.chunkify(
- inputStream,
- (chunk) -> {
- throw new GeneralSecurityException();
- }));
- }
-
- private long calculateFingerprint(byte[] bytes) {
- long fingerprint = 0;
- for (byte inByte : bytes) {
- fingerprint =
- mRabinFingerprint64.computeFingerprint64(
- /*inChar=*/ inByte, /*outChar=*/ (byte) 0, fingerprint);
- }
- return mFingerprintMixer.mix(fingerprint);
- }
-
- private static class ZeroAvailabilityInputStream extends ByteArrayInputStream {
- ZeroAvailabilityInputStream(byte[] wrapped) {
- super(wrapped);
- }
-
- @Override
- public synchronized int available() {
- return 0;
- }
- }
-}
diff --git a/services/robotests/backup/src/com/android/server/backup/encryption/chunking/cdc/FingerprintMixerTest.java b/services/robotests/backup/src/com/android/server/backup/encryption/chunking/cdc/FingerprintMixerTest.java
deleted file mode 100644
index 936b5dca033d..000000000000
--- a/services/robotests/backup/src/com/android/server/backup/encryption/chunking/cdc/FingerprintMixerTest.java
+++ /dev/null
@@ -1,205 +0,0 @@
-/*
- * Copyright (C) 2018 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.encryption.chunking.cdc;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.testng.Assert.assertThrows;
-
-import android.platform.test.annotations.Presubmit;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.robolectric.RobolectricTestRunner;
-
-import java.security.InvalidKeyException;
-import java.security.Key;
-import java.util.HashSet;
-import java.util.Random;
-
-import javax.crypto.SecretKey;
-import javax.crypto.spec.SecretKeySpec;
-
-/** Tests for {@link FingerprintMixer}. */
-@RunWith(RobolectricTestRunner.class)
-@Presubmit
-public class FingerprintMixerTest {
- private static final String KEY_ALGORITHM = "AES";
- private static final int SEED = 42;
- private static final int SALT_LENGTH_BYTES = 256 / 8;
- private static final int KEY_SIZE_BITS = 256;
-
- private Random mSeededRandom;
- private FingerprintMixer mFingerprintMixer;
-
- /** Set up a {@link FingerprintMixer} with deterministic key and salt generation. */
- @Before
- public void setUp() throws Exception {
- // Seed so that the tests are deterministic.
- mSeededRandom = new Random(SEED);
- mFingerprintMixer = new FingerprintMixer(randomKey(), randomSalt());
- }
-
- /**
- * Construcing a {@link FingerprintMixer} with a salt that is too small should throw an {@link
- * IllegalArgumentException}.
- */
- @Test
- public void create_withIncorrectSaltSize_throwsIllegalArgumentException() {
- byte[] tooSmallSalt = new byte[SALT_LENGTH_BYTES - 1];
-
- assertThrows(
- IllegalArgumentException.class,
- () -> new FingerprintMixer(randomKey(), tooSmallSalt));
- }
-
- /**
- * Constructing a {@link FingerprintMixer} with a secret key that can't be encoded should throw
- * an {@link InvalidKeyException}.
- */
- @Test
- public void create_withUnencodableSecretKey_throwsInvalidKeyException() {
- byte[] keyBytes = new byte[KEY_SIZE_BITS / 8];
- UnencodableSecretKeySpec keySpec =
- new UnencodableSecretKeySpec(keyBytes, 0, keyBytes.length, KEY_ALGORITHM);
-
- assertThrows(InvalidKeyException.class, () -> new FingerprintMixer(keySpec, randomSalt()));
- }
-
- /**
- * {@link FingerprintMixer#getAddend()} should not return the same addend for two different
- * keys.
- */
- @Test
- public void getAddend_withDifferentKey_returnsDifferentResult() throws Exception {
- int iterations = 100_000;
- HashSet<Long> returnedAddends = new HashSet<>();
- byte[] salt = randomSalt();
-
- for (int i = 0; i < iterations; i++) {
- FingerprintMixer fingerprintMixer = new FingerprintMixer(randomKey(), salt);
- long addend = fingerprintMixer.getAddend();
- returnedAddends.add(addend);
- }
-
- assertThat(returnedAddends).containsNoDuplicates();
- }
-
- /**
- * {@link FingerprintMixer#getMultiplicand()} should not return the same multiplicand for two
- * different keys.
- */
- @Test
- public void getMultiplicand_withDifferentKey_returnsDifferentResult() throws Exception {
- int iterations = 100_000;
- HashSet<Long> returnedMultiplicands = new HashSet<>();
- byte[] salt = randomSalt();
-
- for (int i = 0; i < iterations; i++) {
- FingerprintMixer fingerprintMixer = new FingerprintMixer(randomKey(), salt);
- long multiplicand = fingerprintMixer.getMultiplicand();
- returnedMultiplicands.add(multiplicand);
- }
-
- assertThat(returnedMultiplicands).containsNoDuplicates();
- }
-
- /** The multiplicant returned by {@link FingerprintMixer} should always be odd. */
- @Test
- public void getMultiplicand_isOdd() throws Exception {
- int iterations = 100_000;
-
- for (int i = 0; i < iterations; i++) {
- FingerprintMixer fingerprintMixer = new FingerprintMixer(randomKey(), randomSalt());
-
- long multiplicand = fingerprintMixer.getMultiplicand();
-
- assertThat(isOdd(multiplicand)).isTrue();
- }
- }
-
- /** {@link FingerprintMixer#mix(long)} should have a random distribution. */
- @Test
- public void mix_randomlyDistributesBits() throws Exception {
- int iterations = 100_000;
- float tolerance = 0.1f;
- int[] totals = new int[64];
-
- for (int i = 0; i < iterations; i++) {
- long n = mFingerprintMixer.mix(mSeededRandom.nextLong());
- for (int j = 0; j < 64; j++) {
- int bit = (int) (n >> j & 1);
- totals[j] += bit;
- }
- }
-
- for (int i = 0; i < 64; i++) {
- float mean = ((float) totals[i]) / iterations;
- float diff = Math.abs(mean - 0.5f);
- assertThat(diff).isLessThan(tolerance);
- }
- }
-
- /**
- * {@link FingerprintMixer#mix(long)} should always produce a number that's different from the
- * input.
- */
- @Test
- public void mix_doesNotProduceSameNumberAsInput() {
- int iterations = 100_000;
-
- for (int i = 0; i < iterations; i++) {
- assertThat(mFingerprintMixer.mix(i)).isNotEqualTo(i);
- }
- }
-
- private byte[] randomSalt() {
- byte[] salt = new byte[SALT_LENGTH_BYTES];
- mSeededRandom.nextBytes(salt);
- return salt;
- }
-
- /**
- * Not a secure way of generating keys. We want to deterministically generate the same keys for
- * each test run, though, to ensure the test is deterministic.
- */
- private SecretKey randomKey() {
- byte[] keyBytes = new byte[KEY_SIZE_BITS / 8];
- mSeededRandom.nextBytes(keyBytes);
- return new SecretKeySpec(keyBytes, 0, keyBytes.length, KEY_ALGORITHM);
- }
-
- private static boolean isOdd(long n) {
- return Math.abs(n % 2) == 1;
- }
-
- /**
- * Subclass of {@link SecretKeySpec} that does not provide an encoded version. As per its
- * contract in {@link Key}, that means {@code getEncoded()} always returns null.
- */
- private class UnencodableSecretKeySpec extends SecretKeySpec {
- UnencodableSecretKeySpec(byte[] key, int offset, int len, String algorithm) {
- super(key, offset, len, algorithm);
- }
-
- @Override
- public byte[] getEncoded() {
- return null;
- }
- }
-}
diff --git a/services/robotests/backup/src/com/android/server/backup/encryption/chunking/cdc/HkdfTest.java b/services/robotests/backup/src/com/android/server/backup/encryption/chunking/cdc/HkdfTest.java
deleted file mode 100644
index 549437454e9c..000000000000
--- a/services/robotests/backup/src/com/android/server/backup/encryption/chunking/cdc/HkdfTest.java
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * Copyright (C) 2018 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.encryption.chunking.cdc;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.testng.Assert.assertThrows;
-
-import android.platform.test.annotations.Presubmit;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.robolectric.RobolectricTestRunner;
-
-/** Tests for {@link Hkdf}. */
-@RunWith(RobolectricTestRunner.class)
-@Presubmit
-public class HkdfTest {
- /** HKDF Test Case 1 IKM from RFC 5869 */
- private static final byte[] HKDF_CASE1_IKM = {
- 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
- 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
- 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
- 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
- 0x0b, 0x0b
- };
-
- /** HKDF Test Case 1 salt from RFC 5869 */
- private static final byte[] HKDF_CASE1_SALT = {
- 0x00, 0x01, 0x02, 0x03, 0x04,
- 0x05, 0x06, 0x07, 0x08, 0x09,
- 0x0a, 0x0b, 0x0c
- };
-
- /** HKDF Test Case 1 info from RFC 5869 */
- private static final byte[] HKDF_CASE1_INFO = {
- (byte) 0xf0, (byte) 0xf1, (byte) 0xf2, (byte) 0xf3, (byte) 0xf4,
- (byte) 0xf5, (byte) 0xf6, (byte) 0xf7, (byte) 0xf8, (byte) 0xf9
- };
-
- /** First 32 bytes of HKDF Test Case 1 OKM (output) from RFC 5869 */
- private static final byte[] HKDF_CASE1_OKM = {
- (byte) 0x3c, (byte) 0xb2, (byte) 0x5f, (byte) 0x25, (byte) 0xfa,
- (byte) 0xac, (byte) 0xd5, (byte) 0x7a, (byte) 0x90, (byte) 0x43,
- (byte) 0x4f, (byte) 0x64, (byte) 0xd0, (byte) 0x36, (byte) 0x2f,
- (byte) 0x2a, (byte) 0x2d, (byte) 0x2d, (byte) 0x0a, (byte) 0x90,
- (byte) 0xcf, (byte) 0x1a, (byte) 0x5a, (byte) 0x4c, (byte) 0x5d,
- (byte) 0xb0, (byte) 0x2d, (byte) 0x56, (byte) 0xec, (byte) 0xc4,
- (byte) 0xc5, (byte) 0xbf
- };
-
- /** Test the example from RFC 5869. */
- @Test
- public void hkdf_derivesKeyMaterial() throws Exception {
- byte[] result = Hkdf.hkdf(HKDF_CASE1_IKM, HKDF_CASE1_SALT, HKDF_CASE1_INFO);
-
- assertThat(result).isEqualTo(HKDF_CASE1_OKM);
- }
-
- /** Providing a key that is null should throw a {@link java.lang.NullPointerException}. */
- @Test
- public void hkdf_withNullKey_throwsNullPointerException() throws Exception {
- assertThrows(
- NullPointerException.class,
- () -> Hkdf.hkdf(null, HKDF_CASE1_SALT, HKDF_CASE1_INFO));
- }
-
- /** Providing a salt that is null should throw a {@link java.lang.NullPointerException}. */
- @Test
- public void hkdf_withNullSalt_throwsNullPointerException() throws Exception {
- assertThrows(
- NullPointerException.class, () -> Hkdf.hkdf(HKDF_CASE1_IKM, null, HKDF_CASE1_INFO));
- }
-
- /** Providing data that is null should throw a {@link java.lang.NullPointerException}. */
- @Test
- public void hkdf_withNullData_throwsNullPointerException() throws Exception {
- assertThrows(
- NullPointerException.class, () -> Hkdf.hkdf(HKDF_CASE1_IKM, HKDF_CASE1_SALT, null));
- }
-}
diff --git a/services/robotests/backup/src/com/android/server/backup/encryption/chunking/cdc/IsChunkBreakpointTest.java b/services/robotests/backup/src/com/android/server/backup/encryption/chunking/cdc/IsChunkBreakpointTest.java
deleted file mode 100644
index 277dc372e73c..000000000000
--- a/services/robotests/backup/src/com/android/server/backup/encryption/chunking/cdc/IsChunkBreakpointTest.java
+++ /dev/null
@@ -1,122 +0,0 @@
-/*
- * Copyright (C) 2018 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.encryption.chunking.cdc;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.testng.Assert.assertThrows;
-
-import android.platform.test.annotations.Presubmit;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.robolectric.RobolectricTestRunner;
-
-import java.util.Random;
-
-/** Tests for {@link IsChunkBreakpoint}. */
-@RunWith(RobolectricTestRunner.class)
-@Presubmit
-public class IsChunkBreakpointTest {
- private static final int RANDOM_SEED = 42;
- private static final double TOLERANCE = 0.01;
- private static final int NUMBER_OF_TESTS = 10000;
- private static final int BITS_PER_LONG = 64;
-
- private Random mRandom;
-
- /** Make sure that tests are deterministic. */
- @Before
- public void setUp() {
- mRandom = new Random(RANDOM_SEED);
- }
-
- /**
- * Providing a negative average number of trials should throw an {@link
- * IllegalArgumentException}.
- */
- @Test
- public void create_withNegativeAverageNumberOfTrials_throwsIllegalArgumentException() {
- assertThrows(IllegalArgumentException.class, () -> new IsChunkBreakpoint(-1));
- }
-
- // Note: the following three tests are compute-intensive, so be cautious adding more.
-
- /**
- * If the provided average number of trials is zero, a breakpoint should be expected after one
- * trial on average.
- */
- @Test
- public void
- isBreakpoint_withZeroAverageNumberOfTrials_isTrueOnAverageAfterOneTrial() {
- assertExpectedTrials(new IsChunkBreakpoint(0), /*expectedTrials=*/ 1);
- }
-
- /**
- * If the provided average number of trials is 512, a breakpoint should be expected after 512
- * trials on average.
- */
- @Test
- public void
- isBreakpoint_with512AverageNumberOfTrials_isTrueOnAverageAfter512Trials() {
- assertExpectedTrials(new IsChunkBreakpoint(512), /*expectedTrials=*/ 512);
- }
-
- /**
- * If the provided average number of trials is 1024, a breakpoint should be expected after 1024
- * trials on average.
- */
- @Test
- public void
- isBreakpoint_with1024AverageNumberOfTrials_isTrueOnAverageAfter1024Trials() {
- assertExpectedTrials(new IsChunkBreakpoint(1024), /*expectedTrials=*/ 1024);
- }
-
- /** The number of leading zeros should be the logarithm of the average number of trials. */
- @Test
- public void getLeadingZeros_squaredIsAverageNumberOfTrials() {
- for (int i = 0; i < BITS_PER_LONG; i++) {
- long averageNumberOfTrials = (long) Math.pow(2, i);
-
- int leadingZeros = new IsChunkBreakpoint(averageNumberOfTrials).getLeadingZeros();
-
- assertThat(leadingZeros).isEqualTo(i);
- }
- }
-
- private void assertExpectedTrials(IsChunkBreakpoint isChunkBreakpoint, long expectedTrials) {
- long sum = 0;
- for (int i = 0; i < NUMBER_OF_TESTS; i++) {
- sum += numberOfTrialsTillBreakpoint(isChunkBreakpoint);
- }
- long averageTrials = sum / NUMBER_OF_TESTS;
- assertThat((double) Math.abs(averageTrials - expectedTrials))
- .isLessThan(TOLERANCE * expectedTrials);
- }
-
- private int numberOfTrialsTillBreakpoint(IsChunkBreakpoint isChunkBreakpoint) {
- int trials = 0;
-
- while (true) {
- trials++;
- if (isChunkBreakpoint.isBreakpoint(mRandom.nextLong())) {
- return trials;
- }
- }
- }
-}
diff --git a/services/robotests/backup/src/com/android/server/backup/encryption/chunking/cdc/RabinFingerprint64Test.java b/services/robotests/backup/src/com/android/server/backup/encryption/chunking/cdc/RabinFingerprint64Test.java
deleted file mode 100644
index 729580cf5101..000000000000
--- a/services/robotests/backup/src/com/android/server/backup/encryption/chunking/cdc/RabinFingerprint64Test.java
+++ /dev/null
@@ -1,132 +0,0 @@
-/*
- * Copyright (C) 2018 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.encryption.chunking.cdc;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static java.nio.charset.StandardCharsets.UTF_8;
-
-import android.platform.test.annotations.Presubmit;
-
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableSet;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.robolectric.RobolectricTestRunner;
-
-/** Tests for {@link RabinFingerprint64}. */
-@RunWith(RobolectricTestRunner.class)
-@Presubmit
-public class RabinFingerprint64Test {
- private static final int WINDOW_SIZE = 31;
- private static final ImmutableList<String> TEST_STRINGS =
- ImmutableList.of(
- "ervHTtChYXO6eXivYqThlyyzqkbRaOR",
- "IxaVunH9ZC3qneWfhj1GkBH4ys9CYqz",
- "wZRVjlE1p976icCFPX9pibk4PEBvjSH",
- "pHIVaT8x8If9D6s9croksgNmJpmGYWI");
-
- private final RabinFingerprint64 mRabinFingerprint64 = new RabinFingerprint64();
-
- /**
- * No matter where in the input buffer a string occurs, {@link
- * RabinFingerprint64#computeFingerprint64(byte, byte, long)} should return the same
- * fingerprint.
- */
- @Test
- public void computeFingerprint64_forSameWindow_returnsSameFingerprint() {
- long fingerprint1 =
- computeFingerprintAtPosition(getBytes(TEST_STRINGS.get(0)), WINDOW_SIZE - 1);
- long fingerprint2 =
- computeFingerprintAtPosition(
- getBytes(TEST_STRINGS.get(1), TEST_STRINGS.get(0)), WINDOW_SIZE * 2 - 1);
- long fingerprint3 =
- computeFingerprintAtPosition(
- getBytes(TEST_STRINGS.get(2), TEST_STRINGS.get(3), TEST_STRINGS.get(0)),
- WINDOW_SIZE * 3 - 1);
- String stub = "abc";
- long fingerprint4 =
- computeFingerprintAtPosition(
- getBytes(stub, TEST_STRINGS.get(0)), WINDOW_SIZE + stub.length() - 1);
-
- // Assert that all fingerprints are exactly the same
- assertThat(ImmutableSet.of(fingerprint1, fingerprint2, fingerprint3, fingerprint4))
- .hasSize(1);
- }
-
- /** The computed fingerprint should be different for different inputs. */
- @Test
- public void computeFingerprint64_withDifferentInput_returnsDifferentFingerprint() {
- long fingerprint1 = computeFingerprintOf(TEST_STRINGS.get(0));
- long fingerprint2 = computeFingerprintOf(TEST_STRINGS.get(1));
- long fingerprint3 = computeFingerprintOf(TEST_STRINGS.get(2));
- long fingerprint4 = computeFingerprintOf(TEST_STRINGS.get(3));
-
- assertThat(ImmutableList.of(fingerprint1, fingerprint2, fingerprint3, fingerprint4))
- .containsNoDuplicates();
- }
-
- /**
- * An input with the same characters in a different order should return a different fingerprint.
- */
- @Test
- public void computeFingerprint64_withSameInputInDifferentOrder_returnsDifferentFingerprint() {
- long fingerprint1 = computeFingerprintOf("abcdefghijklmnopqrstuvwxyz12345");
- long fingerprint2 = computeFingerprintOf("54321zyxwvutsrqponmlkjihgfedcba");
- long fingerprint3 = computeFingerprintOf("4bcdefghijklmnopqrstuvwxyz123a5");
- long fingerprint4 = computeFingerprintOf("bacdefghijklmnopqrstuvwxyz12345");
-
- assertThat(ImmutableList.of(fingerprint1, fingerprint2, fingerprint3, fingerprint4))
- .containsNoDuplicates();
- }
-
- /** UTF-8 bytes of all the given strings in order. */
- private byte[] getBytes(String... strings) {
- StringBuilder sb = new StringBuilder();
- for (String s : strings) {
- sb.append(s);
- }
- return sb.toString().getBytes(UTF_8);
- }
-
- /**
- * The Rabin fingerprint of a window of bytes ending at {@code position} in the {@code bytes}
- * array.
- */
- private long computeFingerprintAtPosition(byte[] bytes, int position) {
- assertThat(position).isAtMost(bytes.length - 1);
- long fingerprint = 0;
- for (int i = 0; i <= position; i++) {
- byte outChar;
- if (i >= WINDOW_SIZE) {
- outChar = bytes[i - WINDOW_SIZE];
- } else {
- outChar = (byte) 0;
- }
- fingerprint =
- mRabinFingerprint64.computeFingerprint64(
- /*inChar=*/ bytes[i], outChar, fingerprint);
- }
- return fingerprint;
- }
-
- private long computeFingerprintOf(String s) {
- assertThat(s.length()).isEqualTo(WINDOW_SIZE);
- return computeFingerprintAtPosition(s.getBytes(UTF_8), WINDOW_SIZE - 1);
- }
-}
diff --git a/services/robotests/backup/src/com/android/server/backup/encryption/keys/RecoverableKeyStoreSecondaryKeyManagerTest.java b/services/robotests/backup/src/com/android/server/backup/encryption/keys/RecoverableKeyStoreSecondaryKeyManagerTest.java
deleted file mode 100644
index 5342efa18a97..000000000000
--- a/services/robotests/backup/src/com/android/server/backup/encryption/keys/RecoverableKeyStoreSecondaryKeyManagerTest.java
+++ /dev/null
@@ -1,148 +0,0 @@
-/*
- * Copyright (C) 2018 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.encryption.keys;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.testng.Assert.assertThrows;
-
-import android.content.Context;
-import android.platform.test.annotations.Presubmit;
-import android.security.keystore.recovery.InternalRecoveryServiceException;
-import android.security.keystore.recovery.RecoveryController;
-
-import com.android.server.testing.shadows.ShadowInternalRecoveryServiceException;
-import com.android.server.testing.shadows.ShadowRecoveryController;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.robolectric.RobolectricTestRunner;
-import org.robolectric.RuntimeEnvironment;
-import org.robolectric.annotation.Config;
-
-import java.security.SecureRandom;
-import java.util.Optional;
-
-/** Tests for {@link RecoverableKeyStoreSecondaryKeyManager}. */
-@RunWith(RobolectricTestRunner.class)
-@Presubmit
-@Config(shadows = {ShadowRecoveryController.class, ShadowInternalRecoveryServiceException.class})
-public class RecoverableKeyStoreSecondaryKeyManagerTest {
- private static final String BACKUP_KEY_ALIAS_PREFIX =
- "com.android.server.backup/recoverablekeystore/";
- private static final int BITS_PER_BYTE = 8;
- private static final int BACKUP_KEY_SUFFIX_LENGTH_BYTES = 128 / BITS_PER_BYTE;
- private static final int HEX_PER_BYTE = 2;
- private static final int BACKUP_KEY_ALIAS_LENGTH =
- BACKUP_KEY_ALIAS_PREFIX.length() + BACKUP_KEY_SUFFIX_LENGTH_BYTES * HEX_PER_BYTE;
- private static final String NONEXISTENT_KEY_ALIAS = "NONEXISTENT_KEY_ALIAS";
-
- private RecoverableKeyStoreSecondaryKeyManager mRecoverableKeyStoreSecondaryKeyManager;
- private Context mContext;
-
- /** Create a new {@link RecoverableKeyStoreSecondaryKeyManager} to use in tests. */
- @Before
- public void setUp() throws Exception {
- mContext = RuntimeEnvironment.application;
-
- mRecoverableKeyStoreSecondaryKeyManager =
- new RecoverableKeyStoreSecondaryKeyManager(
- RecoveryController.getInstance(mContext), new SecureRandom());
- }
-
- /** Reset the {@link ShadowRecoveryController}. */
- @After
- public void tearDown() throws Exception {
- ShadowRecoveryController.reset();
- }
-
- /** The generated key should always have the prefix {@code BACKUP_KEY_ALIAS_PREFIX}. */
- @Test
- public void generate_generatesKeyWithExpectedPrefix() throws Exception {
- RecoverableKeyStoreSecondaryKey key = mRecoverableKeyStoreSecondaryKeyManager.generate();
-
- assertThat(key.getAlias()).startsWith(BACKUP_KEY_ALIAS_PREFIX);
- }
-
- /** The generated key should always have length {@code BACKUP_KEY_ALIAS_LENGTH}. */
- @Test
- public void generate_generatesKeyWithExpectedLength() throws Exception {
- RecoverableKeyStoreSecondaryKey key = mRecoverableKeyStoreSecondaryKeyManager.generate();
-
- assertThat(key.getAlias()).hasLength(BACKUP_KEY_ALIAS_LENGTH);
- }
-
- /** Ensure that hidden API exceptions are rethrown when generating keys. */
- @Test
- public void generate_encounteringHiddenApiException_rethrowsException() {
- ShadowRecoveryController.setThrowsInternalError(true);
-
- assertThrows(
- InternalRecoveryServiceException.class,
- mRecoverableKeyStoreSecondaryKeyManager::generate);
- }
-
- /** Ensure that retrieved keys correspond to those generated earlier. */
- @Test
- public void get_getsKeyGeneratedByController() throws Exception {
- RecoverableKeyStoreSecondaryKey key = mRecoverableKeyStoreSecondaryKeyManager.generate();
-
- Optional<RecoverableKeyStoreSecondaryKey> retrievedKey =
- mRecoverableKeyStoreSecondaryKeyManager.get(key.getAlias());
-
- assertThat(retrievedKey.isPresent()).isTrue();
- assertThat(retrievedKey.get().getAlias()).isEqualTo(key.getAlias());
- assertThat(retrievedKey.get().getSecretKey()).isEqualTo(key.getSecretKey());
- }
-
- /**
- * Ensure that a call to {@link RecoverableKeyStoreSecondaryKeyManager#get(java.lang.String)}
- * for nonexistent aliases returns an emtpy {@link Optional}.
- */
- @Test
- public void get_forNonExistentKey_returnsEmptyOptional() throws Exception {
- Optional<RecoverableKeyStoreSecondaryKey> retrievedKey =
- mRecoverableKeyStoreSecondaryKeyManager.get(NONEXISTENT_KEY_ALIAS);
-
- assertThat(retrievedKey.isPresent()).isFalse();
- }
-
- /**
- * Ensure that exceptions occurring during {@link
- * RecoverableKeyStoreSecondaryKeyManager#get(java.lang.String)} are not rethrown.
- */
- @Test
- public void get_encounteringInternalException_doesNotPropagateException() throws Exception {
- ShadowRecoveryController.setThrowsInternalError(true);
-
- // Should not throw exception
- mRecoverableKeyStoreSecondaryKeyManager.get(NONEXISTENT_KEY_ALIAS);
- }
-
- /** Ensure that keys are correctly removed from the store. */
- @Test
- public void remove_removesKeyFromRecoverableStore() throws Exception {
- RecoverableKeyStoreSecondaryKey key = mRecoverableKeyStoreSecondaryKeyManager.generate();
-
- mRecoverableKeyStoreSecondaryKeyManager.remove(key.getAlias());
-
- assertThat(RecoveryController.getInstance(mContext).getAliases())
- .doesNotContain(key.getAlias());
- }
-}
diff --git a/services/robotests/backup/src/com/android/server/backup/encryption/keys/RecoverableKeyStoreSecondaryKeyTest.java b/services/robotests/backup/src/com/android/server/backup/encryption/keys/RecoverableKeyStoreSecondaryKeyTest.java
deleted file mode 100644
index 89977f82c145..000000000000
--- a/services/robotests/backup/src/com/android/server/backup/encryption/keys/RecoverableKeyStoreSecondaryKeyTest.java
+++ /dev/null
@@ -1,163 +0,0 @@
-/*
- * Copyright (C) 2018 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.encryption.keys;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.testng.Assert.assertThrows;
-
-import android.content.Context;
-import android.platform.test.annotations.Presubmit;
-import android.security.keystore.recovery.RecoveryController;
-
-import com.android.server.backup.encryption.keys.RecoverableKeyStoreSecondaryKey.Status;
-import com.android.server.backup.testing.CryptoTestUtils;
-import com.android.server.testing.shadows.ShadowInternalRecoveryServiceException;
-import com.android.server.testing.shadows.ShadowRecoveryController;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.robolectric.RobolectricTestRunner;
-import org.robolectric.RuntimeEnvironment;
-import org.robolectric.annotation.Config;
-
-import javax.crypto.SecretKey;
-
-/** Tests for {@link RecoverableKeyStoreSecondaryKey}. */
-@RunWith(RobolectricTestRunner.class)
-@Presubmit
-@Config(shadows = {ShadowRecoveryController.class, ShadowInternalRecoveryServiceException.class})
-public class RecoverableKeyStoreSecondaryKeyTest {
- private static final String TEST_ALIAS = "test";
- private static final int NONEXISTENT_STATUS_CODE = 42;
-
- private RecoverableKeyStoreSecondaryKey mSecondaryKey;
- private SecretKey mGeneratedSecretKey;
- private Context mContext;
-
- /** Instantiate a {@link RecoverableKeyStoreSecondaryKey} to use in tests. */
- @Before
- public void setUp() throws Exception {
- mContext = RuntimeEnvironment.application;
- mGeneratedSecretKey = CryptoTestUtils.generateAesKey();
- mSecondaryKey = new RecoverableKeyStoreSecondaryKey(TEST_ALIAS, mGeneratedSecretKey);
- }
-
- /** Reset the {@link ShadowRecoveryController}. */
- @After
- public void tearDown() throws Exception {
- ShadowRecoveryController.reset();
- }
-
- /**
- * Checks that {@link RecoverableKeyStoreSecondaryKey#getAlias()} returns the value supplied in
- * the constructor.
- */
- @Test
- public void getAlias() {
- String alias = mSecondaryKey.getAlias();
-
- assertThat(alias).isEqualTo(TEST_ALIAS);
- }
-
- /**
- * Checks that {@link RecoverableKeyStoreSecondaryKey#getSecretKey()} returns the value supplied
- * in the constructor.
- */
- @Test
- public void getSecretKey() {
- SecretKey secretKey = mSecondaryKey.getSecretKey();
-
- assertThat(secretKey).isEqualTo(mGeneratedSecretKey);
- }
-
- /**
- * Checks that passing a secret key that is null to the constructor throws an exception.
- */
- @Test
- public void constructor_withNullSecretKey_throwsNullPointerException() {
- assertThrows(
- NullPointerException.class,
- () -> new RecoverableKeyStoreSecondaryKey(TEST_ALIAS, null));
- }
-
- /**
- * Checks that passing an alias that is null to the constructor throws an exception.
- */
- @Test
- public void constructor_withNullAlias_throwsNullPointerException() {
- assertThrows(
- NullPointerException.class,
- () -> new RecoverableKeyStoreSecondaryKey(null, mGeneratedSecretKey));
- }
-
- /** Checks that the synced status is returned correctly. */
- @Test
- public void getStatus_whenSynced_returnsSynced() throws Exception {
- setStatus(RecoveryController.RECOVERY_STATUS_SYNCED);
-
- int status = mSecondaryKey.getStatus(mContext);
-
- assertThat(status).isEqualTo(Status.SYNCED);
- }
-
- /** Checks that the in progress sync status is returned correctly. */
- @Test
- public void getStatus_whenNotSynced_returnsNotSynced() throws Exception {
- setStatus(RecoveryController.RECOVERY_STATUS_SYNC_IN_PROGRESS);
-
- int status = mSecondaryKey.getStatus(mContext);
-
- assertThat(status).isEqualTo(Status.NOT_SYNCED);
- }
-
- /** Checks that the failure status is returned correctly. */
- @Test
- public void getStatus_onPermanentFailure_returnsDestroyed() throws Exception {
- setStatus(RecoveryController.RECOVERY_STATUS_PERMANENT_FAILURE);
-
- int status = mSecondaryKey.getStatus(mContext);
-
- assertThat(status).isEqualTo(Status.DESTROYED);
- }
-
- /** Checks that an unknown status results in {@code NOT_SYNCED} being returned. */
- @Test
- public void getStatus_forUnknownStatusCode_returnsNotSynced() throws Exception {
- setStatus(NONEXISTENT_STATUS_CODE);
-
- int status = mSecondaryKey.getStatus(mContext);
-
- assertThat(status).isEqualTo(Status.NOT_SYNCED);
- }
-
- /** Checks that an internal error results in {@code NOT_SYNCED} being returned. */
- @Test
- public void getStatus_onInternalError_returnsNotSynced() throws Exception {
- ShadowRecoveryController.setThrowsInternalError(true);
-
- int status = mSecondaryKey.getStatus(mContext);
-
- assertThat(status).isEqualTo(Status.NOT_SYNCED);
- }
-
- private void setStatus(int status) throws Exception {
- ShadowRecoveryController.setRecoveryStatus(TEST_ALIAS, status);
- }
-}
diff --git a/services/robotests/backup/src/com/android/server/backup/encryption/keys/TertiaryKeyGeneratorTest.java b/services/robotests/backup/src/com/android/server/backup/encryption/keys/TertiaryKeyGeneratorTest.java
deleted file mode 100644
index 48216f8d7aca..000000000000
--- a/services/robotests/backup/src/com/android/server/backup/encryption/keys/TertiaryKeyGeneratorTest.java
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * Copyright (C) 2018 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.encryption.keys;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import android.platform.test.annotations.Presubmit;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.robolectric.RobolectricTestRunner;
-
-import java.security.SecureRandom;
-
-import javax.crypto.SecretKey;
-
-/** Tests for {@link TertiaryKeyGenerator}. */
-@RunWith(RobolectricTestRunner.class)
-@Presubmit
-public class TertiaryKeyGeneratorTest {
- private static final String KEY_ALGORITHM = "AES";
- private static final int KEY_SIZE_BITS = 256;
-
- private TertiaryKeyGenerator mTertiaryKeyGenerator;
-
- /** Instantiate a new {@link TertiaryKeyGenerator} for use in tests. */
- @Before
- public void setUp() {
- mTertiaryKeyGenerator = new TertiaryKeyGenerator(new SecureRandom());
- }
-
- /** Generated keys should be AES keys. */
- @Test
- public void generate_generatesAESKeys() {
- SecretKey secretKey = mTertiaryKeyGenerator.generate();
-
- assertThat(secretKey.getAlgorithm()).isEqualTo(KEY_ALGORITHM);
- }
-
- /** Generated keys should be 256 bits in size. */
- @Test
- public void generate_generates256BitKeys() {
- SecretKey secretKey = mTertiaryKeyGenerator.generate();
-
- assertThat(secretKey.getEncoded()).hasLength(KEY_SIZE_BITS / 8);
- }
-
- /**
- * Subsequent calls to {@link TertiaryKeyGenerator#generate()} should generate different keys.
- */
- @Test
- public void generate_generatesNewKeys() {
- SecretKey key1 = mTertiaryKeyGenerator.generate();
- SecretKey key2 = mTertiaryKeyGenerator.generate();
-
- assertThat(key1).isNotEqualTo(key2);
- }
-}
diff --git a/services/robotests/backup/src/com/android/server/backup/encryption/keys/TertiaryKeyRotationTrackerTest.java b/services/robotests/backup/src/com/android/server/backup/encryption/keys/TertiaryKeyRotationTrackerTest.java
deleted file mode 100644
index 49bb410ceb65..000000000000
--- a/services/robotests/backup/src/com/android/server/backup/encryption/keys/TertiaryKeyRotationTrackerTest.java
+++ /dev/null
@@ -1,137 +0,0 @@
-/*
- * Copyright (C) 2018 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.encryption.keys;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import android.platform.test.annotations.Presubmit;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.robolectric.RobolectricTestRunner;
-import org.robolectric.RuntimeEnvironment;
-
-/** Tests for {@link TertiaryKeyRotationTracker}. */
-@RunWith(RobolectricTestRunner.class)
-@Presubmit
-public class TertiaryKeyRotationTrackerTest {
- private static final String PACKAGE_1 = "com.package.one";
- private static final int NUMBER_OF_BACKUPS_BEFORE_ROTATION = 31;
-
- private TertiaryKeyRotationTracker mTertiaryKeyRotationTracker;
-
- /** Instantiate a {@link TertiaryKeyRotationTracker} for use in tests. */
- @Before
- public void setUp() {
- mTertiaryKeyRotationTracker = newInstance();
- }
-
- /** New packages should not be due for key rotation. */
- @Test
- public void isKeyRotationDue_forNewPackage_isFalse() {
- // Simulate a new package by not calling simulateBackups(). As a result, PACKAGE_1 hasn't
- // been seen by mTertiaryKeyRotationTracker before.
- boolean keyRotationDue = mTertiaryKeyRotationTracker.isKeyRotationDue(PACKAGE_1);
-
- assertThat(keyRotationDue).isFalse();
- }
-
- /**
- * Key rotation should not be due after less than {@code NUMBER_OF_BACKUPS_BEFORE_ROTATION}
- * backups.
- */
- @Test
- public void isKeyRotationDue_afterLessThanRotationAmountBackups_isFalse() {
- simulateBackups(PACKAGE_1, NUMBER_OF_BACKUPS_BEFORE_ROTATION - 1);
-
- boolean keyRotationDue = mTertiaryKeyRotationTracker.isKeyRotationDue(PACKAGE_1);
-
- assertThat(keyRotationDue).isFalse();
- }
-
- /** Key rotation should be due after {@code NUMBER_OF_BACKUPS_BEFORE_ROTATION} backups. */
- @Test
- public void isKeyRotationDue_afterRotationAmountBackups_isTrue() {
- simulateBackups(PACKAGE_1, NUMBER_OF_BACKUPS_BEFORE_ROTATION);
-
- boolean keyRotationDue = mTertiaryKeyRotationTracker.isKeyRotationDue(PACKAGE_1);
-
- assertThat(keyRotationDue).isTrue();
- }
-
- /**
- * A call to {@link TertiaryKeyRotationTracker#resetCountdown(String)} should make sure no key
- * rotation is due.
- */
- @Test
- public void resetCountdown_makesKeyRotationNotDue() {
- simulateBackups(PACKAGE_1, NUMBER_OF_BACKUPS_BEFORE_ROTATION);
-
- mTertiaryKeyRotationTracker.resetCountdown(PACKAGE_1);
-
- assertThat(mTertiaryKeyRotationTracker.isKeyRotationDue(PACKAGE_1)).isFalse();
- }
-
- /**
- * New instances of {@link TertiaryKeyRotationTracker} should read state about the number of
- * backups from disk.
- */
- @Test
- public void isKeyRotationDue_forNewInstance_readsStateFromDisk() {
- simulateBackups(PACKAGE_1, NUMBER_OF_BACKUPS_BEFORE_ROTATION);
-
- boolean keyRotationDueForNewInstance = newInstance().isKeyRotationDue(PACKAGE_1);
-
- assertThat(keyRotationDueForNewInstance).isTrue();
- }
-
- /**
- * A call to {@link TertiaryKeyRotationTracker#markAllForRotation()} should mark all previously
- * seen packages for rotation.
- */
- @Test
- public void markAllForRotation_marksSeenPackagesForKeyRotation() {
- simulateBackups(PACKAGE_1, /*numberOfBackups=*/ 1);
-
- mTertiaryKeyRotationTracker.markAllForRotation();
-
- assertThat(mTertiaryKeyRotationTracker.isKeyRotationDue(PACKAGE_1)).isTrue();
- }
-
- /**
- * A call to {@link TertiaryKeyRotationTracker#markAllForRotation()} should not mark any new
- * packages for rotation.
- */
- @Test
- public void markAllForRotation_doesNotMarkUnseenPackages() {
- mTertiaryKeyRotationTracker.markAllForRotation();
-
- assertThat(mTertiaryKeyRotationTracker.isKeyRotationDue(PACKAGE_1)).isFalse();
- }
-
- private void simulateBackups(String packageName, int numberOfBackups) {
- while (numberOfBackups > 0) {
- mTertiaryKeyRotationTracker.recordBackup(packageName);
- numberOfBackups--;
- }
- }
-
- private static TertiaryKeyRotationTracker newInstance() {
- return TertiaryKeyRotationTracker.getInstance(RuntimeEnvironment.application);
- }
-}
diff --git a/services/robotests/backup/src/com/android/server/backup/encryption/storage/BackupEncryptionDbTest.java b/services/robotests/backup/src/com/android/server/backup/encryption/storage/BackupEncryptionDbTest.java
deleted file mode 100644
index 87f21bfa59c2..000000000000
--- a/services/robotests/backup/src/com/android/server/backup/encryption/storage/BackupEncryptionDbTest.java
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Copyright (C) 2018 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.encryption.storage;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import android.platform.test.annotations.Presubmit;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.robolectric.RobolectricTestRunner;
-import org.robolectric.RuntimeEnvironment;
-
-/** Tests for {@link BackupEncryptionDb}. */
-@RunWith(RobolectricTestRunner.class)
-@Presubmit
-public class BackupEncryptionDbTest {
- private BackupEncryptionDb mBackupEncryptionDb;
-
- /** Creates an empty {@link BackupEncryptionDb} */
- @Before
- public void setUp() {
- mBackupEncryptionDb = BackupEncryptionDb.newInstance(RuntimeEnvironment.application);
- }
-
- /**
- * Tests that the tertiary keys table gets cleared when calling {@link
- * BackupEncryptionDb#clear()}.
- */
- @Test
- public void clear_withNonEmptyTertiaryKeysTable_clearsTertiaryKeysTable() throws Exception {
- String secondaryKeyAlias = "secondaryKeyAlias";
- TertiaryKeysTable tertiaryKeysTable = mBackupEncryptionDb.getTertiaryKeysTable();
- tertiaryKeysTable.addKey(new TertiaryKey(secondaryKeyAlias, "packageName", new byte[0]));
-
- mBackupEncryptionDb.clear();
-
- assertThat(tertiaryKeysTable.getAllKeys(secondaryKeyAlias)).isEmpty();
- }
-}
diff --git a/services/robotests/backup/src/com/android/server/backup/encryption/storage/TertiaryKeysTableTest.java b/services/robotests/backup/src/com/android/server/backup/encryption/storage/TertiaryKeysTableTest.java
deleted file mode 100644
index 319ec89f445e..000000000000
--- a/services/robotests/backup/src/com/android/server/backup/encryption/storage/TertiaryKeysTableTest.java
+++ /dev/null
@@ -1,179 +0,0 @@
-/*
- * Copyright (C) 2018 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.encryption.storage;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import android.platform.test.annotations.Presubmit;
-
-import com.android.server.backup.testing.CryptoTestUtils;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.robolectric.RobolectricTestRunner;
-import org.robolectric.RuntimeEnvironment;
-
-import java.util.Map;
-import java.util.Optional;
-
-/** Tests for {@link TertiaryKeysTable}. */
-@RunWith(RobolectricTestRunner.class)
-@Presubmit
-public class TertiaryKeysTableTest {
- private static final int KEY_SIZE_BYTES = 32;
- private static final String SECONDARY_ALIAS = "phoebe";
- private static final String PACKAGE_NAME = "generic.package.name";
-
- private TertiaryKeysTable mTertiaryKeysTable;
-
- /** Creates an empty {@link BackupEncryptionDb}. */
- @Before
- public void setUp() {
- mTertiaryKeysTable =
- BackupEncryptionDb.newInstance(RuntimeEnvironment.application)
- .getTertiaryKeysTable();
- }
-
- /** Tests that new {@link TertiaryKey}s get successfully added to the database. */
- @Test
- public void addKey_onEmptyDatabase_putsKeyInDb() throws Exception {
- byte[] key = generateRandomKey();
- TertiaryKey keyToInsert = new TertiaryKey(SECONDARY_ALIAS, PACKAGE_NAME, key);
-
- long result = mTertiaryKeysTable.addKey(keyToInsert);
-
- assertThat(result).isNotEqualTo(-1);
- Optional<TertiaryKey> maybeKeyInDb =
- mTertiaryKeysTable.getKey(SECONDARY_ALIAS, PACKAGE_NAME);
- assertThat(maybeKeyInDb.isPresent()).isTrue();
- TertiaryKey keyInDb = maybeKeyInDb.get();
- assertTertiaryKeysEqual(keyInDb, keyToInsert);
- }
-
- /** Tests that keys replace older keys with the same secondary alias and package name. */
- @Test
- public void addKey_havingSameSecondaryAliasAndPackageName_replacesOldKey() throws Exception {
- mTertiaryKeysTable.addKey(
- new TertiaryKey(SECONDARY_ALIAS, PACKAGE_NAME, generateRandomKey()));
- byte[] newKey = generateRandomKey();
-
- long result =
- mTertiaryKeysTable.addKey(new TertiaryKey(SECONDARY_ALIAS, PACKAGE_NAME, newKey));
-
- assertThat(result).isNotEqualTo(-1);
- TertiaryKey keyInDb = mTertiaryKeysTable.getKey(SECONDARY_ALIAS, PACKAGE_NAME).get();
- assertThat(keyInDb.getWrappedKeyBytes()).isEqualTo(newKey);
- }
-
- /**
- * Tests that keys do not replace older keys with the same package name but a different alias.
- */
- @Test
- public void addKey_havingSamePackageNameButDifferentAlias_doesNotReplaceOldKey()
- throws Exception {
- String alias2 = "karl";
- TertiaryKey key1 = generateTertiaryKey(SECONDARY_ALIAS, PACKAGE_NAME);
- TertiaryKey key2 = generateTertiaryKey(alias2, PACKAGE_NAME);
-
- long primaryKey1 = mTertiaryKeysTable.addKey(key1);
- long primaryKey2 = mTertiaryKeysTable.addKey(key2);
-
- assertThat(primaryKey1).isNotEqualTo(primaryKey2);
- assertThat(mTertiaryKeysTable.getKey(SECONDARY_ALIAS, PACKAGE_NAME).isPresent()).isTrue();
- assertTertiaryKeysEqual(
- mTertiaryKeysTable.getKey(SECONDARY_ALIAS, PACKAGE_NAME).get(), key1);
- assertThat(mTertiaryKeysTable.getKey(alias2, PACKAGE_NAME).isPresent()).isTrue();
- assertTertiaryKeysEqual(mTertiaryKeysTable.getKey(alias2, PACKAGE_NAME).get(), key2);
- }
-
- /**
- * Tests that {@link TertiaryKeysTable#getKey(String, String)} returns an empty {@link Optional}
- * for a missing key.
- */
- @Test
- public void getKey_forMissingKey_returnsEmptyOptional() throws Exception {
- Optional<TertiaryKey> key = mTertiaryKeysTable.getKey(SECONDARY_ALIAS, PACKAGE_NAME);
-
- assertThat(key.isPresent()).isFalse();
- }
-
- /**
- * Tests that {@link TertiaryKeysTable#getAllKeys(String)} returns an empty map when no keys
- * with the secondary alias exist.
- */
- @Test
- public void getAllKeys_withNoKeysForAlias_returnsEmptyMap() throws Exception {
- assertThat(mTertiaryKeysTable.getAllKeys(SECONDARY_ALIAS)).isEmpty();
- }
-
- /**
- * Tests that {@link TertiaryKeysTable#getAllKeys(String)} returns all keys corresponding to the
- * provided secondary alias.
- */
- @Test
- public void getAllKeys_withMatchingKeys_returnsAllKeysWrappedWithSecondary() throws Exception {
- TertiaryKey key1 = generateTertiaryKey(SECONDARY_ALIAS, PACKAGE_NAME);
- mTertiaryKeysTable.addKey(key1);
- String package2 = "generic.package.two";
- TertiaryKey key2 = generateTertiaryKey(SECONDARY_ALIAS, package2);
- mTertiaryKeysTable.addKey(key2);
- String package3 = "generic.package.three";
- TertiaryKey key3 = generateTertiaryKey(SECONDARY_ALIAS, package3);
- mTertiaryKeysTable.addKey(key3);
-
- Map<String, TertiaryKey> keysByPackageName = mTertiaryKeysTable.getAllKeys(SECONDARY_ALIAS);
-
- assertThat(keysByPackageName).hasSize(3);
- assertThat(keysByPackageName).containsKey(PACKAGE_NAME);
- assertTertiaryKeysEqual(keysByPackageName.get(PACKAGE_NAME), key1);
- assertThat(keysByPackageName).containsKey(package2);
- assertTertiaryKeysEqual(keysByPackageName.get(package2), key2);
- assertThat(keysByPackageName).containsKey(package3);
- assertTertiaryKeysEqual(keysByPackageName.get(package3), key3);
- }
-
- /**
- * Tests that {@link TertiaryKeysTable#getAllKeys(String)} does not return any keys wrapped with
- * another alias.
- */
- @Test
- public void getAllKeys_withMatchingKeys_doesNotReturnKeysWrappedWithOtherAlias()
- throws Exception {
- mTertiaryKeysTable.addKey(generateTertiaryKey(SECONDARY_ALIAS, PACKAGE_NAME));
- mTertiaryKeysTable.addKey(generateTertiaryKey("somekey", "generic.package.two"));
-
- Map<String, TertiaryKey> keysByPackageName = mTertiaryKeysTable.getAllKeys(SECONDARY_ALIAS);
-
- assertThat(keysByPackageName).hasSize(1);
- assertThat(keysByPackageName).containsKey(PACKAGE_NAME);
- }
-
- private void assertTertiaryKeysEqual(TertiaryKey a, TertiaryKey b) {
- assertThat(a.getSecondaryKeyAlias()).isEqualTo(b.getSecondaryKeyAlias());
- assertThat(a.getPackageName()).isEqualTo(b.getPackageName());
- assertThat(a.getWrappedKeyBytes()).isEqualTo(b.getWrappedKeyBytes());
- }
-
- private TertiaryKey generateTertiaryKey(String alias, String packageName) {
- return new TertiaryKey(alias, packageName, generateRandomKey());
- }
-
- private byte[] generateRandomKey() {
- return CryptoTestUtils.generateRandomBytes(KEY_SIZE_BYTES);
- }
-}
diff --git a/services/robotests/backup/src/com/android/server/backup/internal/SetupObserverTest.java b/services/robotests/backup/src/com/android/server/backup/internal/SetupObserverTest.java
index 44e9e6aecacd..e49425b00322 100644
--- a/services/robotests/backup/src/com/android/server/backup/internal/SetupObserverTest.java
+++ b/services/robotests/backup/src/com/android/server/backup/internal/SetupObserverTest.java
@@ -32,6 +32,7 @@ import com.android.server.backup.TransportManager;
import com.android.server.backup.UserBackupManagerService;
import com.android.server.backup.testing.BackupManagerServiceTestUtils;
import com.android.server.testing.shadows.ShadowApplicationPackageManager;
+import com.android.server.testing.shadows.ShadowSystemServiceRegistry;
import org.junit.Before;
import org.junit.Test;
@@ -51,7 +52,12 @@ import java.io.File;
* UserBackupManagerService}.
*/
@RunWith(RobolectricTestRunner.class)
-@Config(shadows = {ShadowApplicationPackageManager.class, ShadowJobScheduler.class})
+@Config(
+ shadows = {
+ ShadowApplicationPackageManager.class,
+ ShadowJobScheduler.class,
+ ShadowSystemServiceRegistry.class
+ })
@Presubmit
public class SetupObserverTest {
private static final String TAG = "SetupObserverTest";
diff --git a/services/robotests/backup/src/com/android/server/backup/keyvalue/KeyValueBackupReporterTest.java b/services/robotests/backup/src/com/android/server/backup/keyvalue/KeyValueBackupReporterTest.java
index a1b8a9520524..14b4dc3dc7d0 100644
--- a/services/robotests/backup/src/com/android/server/backup/keyvalue/KeyValueBackupReporterTest.java
+++ b/services/robotests/backup/src/com/android/server/backup/keyvalue/KeyValueBackupReporterTest.java
@@ -77,4 +77,16 @@ public class KeyValueBackupReporterTest {
assertThat(observer).isEqualTo(mObserver);
}
+
+ /**
+ * Ensure that EventLog is called when logging the transport uninitialised issue.
+ */
+ @Test
+ public void testOnTransportNotInitialized_callsEventLog() {
+ ShadowEventLog.setUp();
+
+ mReporter.onTransportNotInitialized("transport");
+
+ assertThat(ShadowEventLog.getEntries().size()).isEqualTo(1);
+ }
}
diff --git a/services/robotests/backup/src/com/android/server/backup/keyvalue/KeyValueBackupTaskTest.java b/services/robotests/backup/src/com/android/server/backup/keyvalue/KeyValueBackupTaskTest.java
index 1d082c735d09..ec56e1ebc8e0 100644
--- a/services/robotests/backup/src/com/android/server/backup/keyvalue/KeyValueBackupTaskTest.java
+++ b/services/robotests/backup/src/com/android/server/backup/keyvalue/KeyValueBackupTaskTest.java
@@ -120,6 +120,7 @@ import com.android.server.testing.shadows.ShadowApplicationPackageManager;
import com.android.server.testing.shadows.ShadowBackupDataInput;
import com.android.server.testing.shadows.ShadowBackupDataOutput;
import com.android.server.testing.shadows.ShadowEventLog;
+import com.android.server.testing.shadows.ShadowSystemServiceRegistry;
import com.google.common.truth.IterableSubject;
@@ -130,6 +131,7 @@ import org.junit.runner.RunWith;
import org.mockito.ArgumentMatcher;
import org.mockito.InOrder;
import org.mockito.Mock;
+import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
@@ -163,10 +165,11 @@ import java.util.stream.Stream;
ShadowBackupDataInput.class,
ShadowBackupDataOutput.class,
ShadowEventLog.class,
- ShadowQueuedWork.class
+ ShadowQueuedWork.class,
+ ShadowSystemServiceRegistry.class
})
@Presubmit
-public class KeyValueBackupTaskTest {
+public class KeyValueBackupTaskTest {
private static final PackageData PACKAGE_1 = keyValuePackage(1);
private static final PackageData PACKAGE_2 = keyValuePackage(2);
private static final String BACKUP_AGENT_SHARED_PREFS_SYNCHRONIZER_CLASS =
@@ -225,8 +228,9 @@ public class KeyValueBackupTaskTest {
// Needed to be able to use a real BMS instead of a mock
setUpBinderCallerAndApplicationAsSystem(mApplication);
mBackupManagerService =
- spy(createUserBackupManagerServiceAndRunTasks(
- USER_ID, mContext, mBaseStateDir, mDataDir, mTransportManager));
+ spy(
+ createUserBackupManagerServiceAndRunTasks(
+ USER_ID, mContext, mBaseStateDir, mDataDir, mTransportManager));
setUpBackupManagerServiceBasics(
mBackupManagerService,
mApplication,
@@ -334,9 +338,7 @@ public class KeyValueBackupTaskTest {
.isEqualTo("packageState".getBytes());
}
- /**
- * Do not update backup token if the backup queue was empty
- */
+ /** Do not update backup token if the backup queue was empty */
@Test
public void testRunTask_whenQueueEmptyOnFirstBackup_doesNotUpdateCurrentToken()
throws Exception {
@@ -712,7 +714,7 @@ public class KeyValueBackupTaskTest {
// Verify has set work source and hasn't unset yet.
verify(mBackupManagerService)
.setWorkSource(
- argThat(workSource -> workSource.get(0) == PACKAGE_1.uid));
+ argThat(workSource -> workSource.getUid(0) == PACKAGE_1.uid));
verify(mBackupManagerService, never()).setWorkSource(null);
});
KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1);
@@ -724,8 +726,8 @@ public class KeyValueBackupTaskTest {
}
/**
- * Agent unavailable means {@link UserBackupManagerService#bindToAgentSynchronous(ApplicationInfo,
- * int)} returns {@code null}.
+ * Agent unavailable means {@link
+ * UserBackupManagerService#bindToAgentSynchronous(ApplicationInfo, int)} returns {@code null}.
*
* @see #setUpAgent(PackageData)
*/
@@ -758,8 +760,8 @@ public class KeyValueBackupTaskTest {
runTask(task);
- assertThat(Files.readAllBytes(getStateFile(mTransport, PACKAGE_1))).isEqualTo(
- "newState".getBytes());
+ assertThat(Files.readAllBytes(getStateFile(mTransport, PACKAGE_1)))
+ .isEqualTo("newState".getBytes());
}
@Test
@@ -794,7 +796,8 @@ public class KeyValueBackupTaskTest {
}
@Test
- public void testRunTask_whenNonIncrementalAndBindToAgentThrowsSecurityException() throws Exception {
+ public void testRunTask_whenNonIncrementalAndBindToAgentThrowsSecurityException()
+ throws Exception {
TransportMock transportMock = setUpInitializedTransport(mTransport);
setUpAgent(PACKAGE_1);
doThrow(SecurityException.class)
@@ -1664,7 +1667,7 @@ public class KeyValueBackupTaskTest {
runTask(task);
verify(mReporter).onPackageBackupTransportFailure(PACKAGE_1.packageName);
- verify(mReporter).onTransportNotInitialized();
+ verify(mReporter).onTransportNotInitialized(mTransport.transportName);
verify(mReporter).onBackupFinished(BackupManager.ERROR_TRANSPORT_ABORTED);
}
@@ -1681,7 +1684,7 @@ public class KeyValueBackupTaskTest {
runTask(task);
verify(mReporter).onPackageBackupTransportFailure(PM_PACKAGE.packageName);
- verify(mReporter).onTransportNotInitialized();
+ verify(mReporter).onTransportNotInitialized(mTransport.transportName);
verify(mReporter).onBackupFinished(BackupManager.ERROR_TRANSPORT_ABORTED);
}
@@ -1770,9 +1773,10 @@ public class KeyValueBackupTaskTest {
TransportMock transportMock = setUpInitializedTransport(mTransport);
when(transportMock.transport.performBackup(any(), any(), anyInt()))
.thenReturn(BackupTransport.TRANSPORT_NOT_INITIALIZED);
- // First one is in startTask(), second is the one we want.
+ // First one is in startTask(), second is in finishTask(), the third is the one we want.
when(transportMock.transport.name())
.thenReturn(mTransport.transportName)
+ .thenReturn(mTransport.transportName)
.thenThrow(DeadObjectException.class);
setUpAgentWithData(PACKAGE_1);
KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1);
@@ -2320,9 +2324,7 @@ public class KeyValueBackupTaskTest {
expectThrows(IllegalArgumentException.class, () -> task.handleCancel(false));
}
- /**
- * Do not update backup token if no data was moved.
- */
+ /** Do not update backup token if no data was moved. */
@Test
public void testRunTask_whenNoDataToBackupOnFirstBackup_doesNotUpdateCurrentToken()
throws Exception {
@@ -2338,6 +2340,85 @@ public class KeyValueBackupTaskTest {
assertThat(mBackupManagerService.getCurrentToken()).isEqualTo(0L);
}
+ /** Do not inform transport of an empty backup if the app hasn't backed up before */
+ @Test
+ public void testRunTask_whenNoDataToBackupOnFirstBackup_doesNotTellTransportOfBackup()
+ throws Exception {
+ TransportMock transportMock = setUpInitializedTransport(mTransport);
+ mBackupManagerService.setCurrentToken(0L);
+ when(transportMock.transport.getCurrentRestoreSet()).thenReturn(1234L);
+ setUpAgent(PACKAGE_1);
+ KeyValueBackupTask task = createKeyValueBackupTask(transportMock, true, PACKAGE_1);
+
+ runTask(task);
+
+ verify(transportMock.transport, never())
+ .performBackup(
+ argThat(packageInfo(PACKAGE_1)), any(ParcelFileDescriptor.class), anyInt());
+ }
+
+ /** Let the transport know if there are no changes for a KV backed-up package. */
+ @Test
+ public void testRunTask_whenBackupHasCompletedAndThenNoDataChanges_transportGetsNotified()
+ throws Exception {
+ TransportMock transportMock = setUpInitializedTransport(mTransport);
+ when(transportMock.transport.getCurrentRestoreSet()).thenReturn(1234L);
+ when(transportMock.transport.isAppEligibleForBackup(
+ argThat(packageInfo(PACKAGE_1)), eq(false)))
+ .thenReturn(true);
+ when(transportMock.transport.isAppEligibleForBackup(
+ argThat(packageInfo(PACKAGE_2)), eq(false)))
+ .thenReturn(true);
+ setUpAgentWithData(PACKAGE_1);
+ setUpAgentWithData(PACKAGE_2);
+
+ PackageInfo endSentinel = new PackageInfo();
+ endSentinel.packageName = KeyValueBackupTask.NO_DATA_END_SENTINEL;
+
+ // Perform First Backup run, which should backup both packages
+ KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1, PACKAGE_2);
+ runTask(task);
+ InOrder order = Mockito.inOrder(transportMock.transport);
+ order.verify(transportMock.transport)
+ .performBackup(
+ argThat(packageInfo(PACKAGE_1)),
+ any(),
+ eq(BackupTransport.FLAG_NON_INCREMENTAL));
+ order.verify(transportMock.transport).finishBackup();
+ order.verify(transportMock.transport)
+ .performBackup(
+ argThat(packageInfo(PACKAGE_2)),
+ any(),
+ eq(BackupTransport.FLAG_NON_INCREMENTAL));
+ order.verify(transportMock.transport).finishBackup();
+
+ // Run again with new data for package 1, but nothing new for package 2
+ task = createKeyValueBackupTask(transportMock, PACKAGE_1);
+ runTask(task);
+
+ // Now for the second run we performed one incremental backup (package 1) and
+ // made one "no change" call (package 2) before sending the end sentinel.
+ order.verify(transportMock.transport)
+ .performBackup(
+ argThat(packageInfo(PACKAGE_1)),
+ any(),
+ eq(BackupTransport.FLAG_INCREMENTAL));
+ order.verify(transportMock.transport).finishBackup();
+ order.verify(transportMock.transport)
+ .performBackup(
+ argThat(packageInfo(PACKAGE_2)),
+ any(),
+ eq(BackupTransport.FLAG_DATA_NOT_CHANGED));
+ order.verify(transportMock.transport).finishBackup();
+ order.verify(transportMock.transport)
+ .performBackup(
+ argThat(packageInfo(endSentinel)),
+ any(),
+ eq(BackupTransport.FLAG_DATA_NOT_CHANGED));
+ order.verify(transportMock.transport).finishBackup();
+ order.verifyNoMoreInteractions();
+ }
+
private void runTask(KeyValueBackupTask task) {
// Pretend we are not on the main-thread to prevent RemoteCall from complaining
mShadowMainLooper.setCurrentThread(false);
@@ -2575,6 +2656,20 @@ public class KeyValueBackupTaskTest {
packageInfo != null && packageData.packageName.equals(packageInfo.packageName);
}
+ /** Matches {@link PackageInfo} whose package name is {@code packageData.packageName}. */
+ private static ArgumentMatcher<PackageInfo> packageInfo(PackageInfo packageData) {
+ // We have to test for packageInfo nulity because of Mockito's own stubbing with argThat().
+ // E.g. if you do:
+ //
+ // 1. when(object.method(argThat(str -> str.equals("foo")))).thenReturn(0)
+ // 2. when(object.method(argThat(str -> str.equals("bar")))).thenReturn(2)
+ //
+ // The second line will throw NPE because it will call lambda 1 with null, since argThat()
+ // returns null. So we guard against that by checking for null.
+ return packageInfo ->
+ packageInfo != null && packageInfo.packageName.equals(packageInfo.packageName);
+ }
+
/** Matches {@link ApplicationInfo} whose package name is {@code packageData.packageName}. */
private static ArgumentMatcher<ApplicationInfo> applicationInfo(PackageData packageData) {
return applicationInfo ->
diff --git a/services/robotests/backup/src/com/android/server/backup/testing/BackupManagerServiceTestUtils.java b/services/robotests/backup/src/com/android/server/backup/testing/BackupManagerServiceTestUtils.java
index 392d182328a5..77b5b61b8f01 100644
--- a/services/robotests/backup/src/com/android/server/backup/testing/BackupManagerServiceTestUtils.java
+++ b/services/robotests/backup/src/com/android/server/backup/testing/BackupManagerServiceTestUtils.java
@@ -37,7 +37,7 @@ import android.os.Process;
import android.util.Log;
import com.android.server.backup.BackupAgentTimeoutParameters;
-import com.android.server.backup.Trampoline;
+import com.android.server.backup.BackupManagerService;
import com.android.server.backup.TransportManager;
import com.android.server.backup.UserBackupManagerService;
@@ -89,7 +89,7 @@ public class BackupManagerServiceTestUtils {
UserBackupManagerService.createAndInitializeService(
userId,
context,
- new Trampoline(context),
+ new BackupManagerService(context),
backupThread,
baseStateDir,
dataDir,
@@ -166,7 +166,7 @@ public class BackupManagerServiceTestUtils {
PowerManager powerManager =
(PowerManager) application.getSystemService(Context.POWER_SERVICE);
return new UserBackupManagerService.BackupWakeLock(
- powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "*backup*"));
+ powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "*backup*"), 0);
}
/**
diff --git a/services/robotests/backup/src/com/android/server/backup/testing/CryptoTestUtils.java b/services/robotests/backup/src/com/android/server/backup/testing/CryptoTestUtils.java
deleted file mode 100644
index 0428796f51fa..000000000000
--- a/services/robotests/backup/src/com/android/server/backup/testing/CryptoTestUtils.java
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright (C) 2018 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.testing;
-
-import java.security.NoSuchAlgorithmException;
-import java.util.Random;
-
-import javax.crypto.KeyGenerator;
-import javax.crypto.SecretKey;
-
-/** Helpers for crypto code tests. */
-public class CryptoTestUtils {
- private static final String KEY_ALGORITHM = "AES";
- private static final int KEY_SIZE_BITS = 256;
-
- private CryptoTestUtils() {}
-
- public static SecretKey generateAesKey() throws NoSuchAlgorithmException {
- KeyGenerator keyGenerator = KeyGenerator.getInstance(KEY_ALGORITHM);
- keyGenerator.init(KEY_SIZE_BITS);
- return keyGenerator.generateKey();
- }
-
- /** Generates a byte array of size {@code n} containing random bytes. */
- public static byte[] generateRandomBytes(int n) {
- byte[] bytes = new byte[n];
- Random random = new Random();
- random.nextBytes(bytes);
- return bytes;
- }
-}
diff --git a/services/robotests/src/com/android/server/location/LocationRequestStatisticsTest.java b/services/robotests/src/com/android/server/location/LocationRequestStatisticsTest.java
new file mode 100644
index 000000000000..2d0fe5875301
--- /dev/null
+++ b/services/robotests/src/com/android/server/location/LocationRequestStatisticsTest.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2020 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.location;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.platform.test.annotations.Presubmit;
+
+import com.android.internal.util.IndentingPrintWriter;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.RobolectricTestRunner;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+
+/**
+ * Unit tests for {@link LocationRequestStatistics}.
+ */
+@RunWith(RobolectricTestRunner.class)
+@Presubmit
+public class LocationRequestStatisticsTest {
+ private static final String FEATURE_ID = "featureId";
+
+ /**
+ * Check adding and removing requests & strings
+ */
+ @Test
+ public void testRequestSummary() {
+ LocationRequestStatistics.RequestSummary summary =
+ new LocationRequestStatistics.RequestSummary(
+ "com.example", FEATURE_ID, "gps", 1000);
+ StringWriter stringWriter = new StringWriter();
+ summary.dump(new IndentingPrintWriter(new PrintWriter(stringWriter), " "), 1234);
+ assertThat(stringWriter.toString()).startsWith("At");
+
+ StringWriter stringWriterRemove = new StringWriter();
+ summary = new LocationRequestStatistics.RequestSummary(
+ "com.example", "gps", FEATURE_ID,
+ LocationRequestStatistics.RequestSummary.REQUEST_ENDED_INTERVAL);
+ summary.dump(new IndentingPrintWriter(new PrintWriter(stringWriterRemove), " "), 2345);
+ assertThat(stringWriterRemove.toString()).contains("-");
+ assertThat(stringWriterRemove.toString()).contains(FEATURE_ID);
+ }
+
+ /**
+ * Check summary list size capping
+ */
+ @Test
+ public void testSummaryList() {
+ LocationRequestStatistics statistics = new LocationRequestStatistics();
+ statistics.history.addRequest("com.example", FEATURE_ID, "gps", 1000);
+ assertThat(statistics.history.mList.size()).isEqualTo(1);
+ // Try (not) to overflow
+ for (int i = 0; i < LocationRequestStatistics.RequestSummaryLimitedHistory.MAX_SIZE; i++) {
+ statistics.history.addRequest("com.example", FEATURE_ID, "gps", 1000);
+ }
+ assertThat(statistics.history.mList.size()).isEqualTo(
+ LocationRequestStatistics.RequestSummaryLimitedHistory.MAX_SIZE);
+ }
+}
diff --git a/services/robotests/src/com/android/server/location/gnss/GnssAntennaInfoProviderTest.java b/services/robotests/src/com/android/server/location/gnss/GnssAntennaInfoProviderTest.java
new file mode 100644
index 000000000000..d8acd6ea6948
--- /dev/null
+++ b/services/robotests/src/com/android/server/location/gnss/GnssAntennaInfoProviderTest.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2020 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.location.gnss;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.os.Handler;
+import android.os.Looper;
+import android.platform.test.annotations.Presubmit;
+
+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;
+
+/**
+ * Unit tests for {@link GnssAntennaInfoProvider}.
+ */
+@RunWith(RobolectricTestRunner.class)
+@Presubmit
+public class GnssAntennaInfoProviderTest {
+ @Mock
+ private GnssAntennaInfoProvider.GnssAntennaInfoProviderNative
+ mMockNative;
+ private GnssAntennaInfoProvider mTestProvider;
+
+ /** Setup. */
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ when(mMockNative.startAntennaInfoListening()).thenReturn(true);
+ when(mMockNative.stopAntennaInfoListening()).thenReturn(true);
+
+ mTestProvider = new GnssAntennaInfoProvider(RuntimeEnvironment.application,
+ new Handler(Looper.myLooper()), mMockNative) {
+ @Override
+ public boolean isGpsEnabled() {
+ return true;
+ }
+ };
+ }
+
+ /**
+ * Test that registerWithService calls the native startAntennaInfoListening method.
+ */
+ @Test
+ public void register_nativeStarted() {
+ mTestProvider.registerWithService();
+ verify(mMockNative, times(1)).startAntennaInfoListening();
+ }
+
+ /**
+ * Test that unregisterFromService calls the native stopAntennaInfoListening method.
+ */
+ @Test
+ public void unregister_nativeStopped() {
+ mTestProvider.registerWithService();
+ mTestProvider.unregisterFromService();
+ verify(mMockNative, times(1)).stopAntennaInfoListening();
+ }
+
+ /**
+ * Test that GnssAntennaInfoProvider.isAntennaInfoSupported() returns the result of the
+ * native isAntennaInfoSupported method.
+ */
+ @Test
+ public void isSupported_nativeIsSupported() {
+ when(mMockNative.isAntennaInfoSupported()).thenReturn(true);
+ assertThat(mTestProvider.isAvailableInPlatform()).isTrue();
+
+ when(mMockNative.isAntennaInfoSupported()).thenReturn(false);
+ assertThat(mTestProvider.isAvailableInPlatform()).isFalse();
+ }
+}
diff --git a/services/robotests/src/com/android/server/location/GnssBatchingProviderTest.java b/services/robotests/src/com/android/server/location/gnss/GnssBatchingProviderTest.java
index d58c3f73b8e8..25d6aa4dae29 100644
--- a/services/robotests/src/com/android/server/location/GnssBatchingProviderTest.java
+++ b/services/robotests/src/com/android/server/location/gnss/GnssBatchingProviderTest.java
@@ -1,4 +1,20 @@
-package com.android.server.location;
+/*
+ * Copyright (C) 2020 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.location.gnss;
import static com.google.common.truth.Truth.assertThat;
@@ -11,7 +27,7 @@ import static org.mockito.Mockito.when;
import android.platform.test.annotations.Presubmit;
-import com.android.server.location.GnssBatchingProvider.GnssBatchingProviderNative;
+import com.android.server.location.gnss.GnssBatchingProvider.GnssBatchingProviderNative;
import org.junit.Before;
import org.junit.Test;
diff --git a/services/robotests/src/com/android/server/location/GnssGeofenceProviderTest.java b/services/robotests/src/com/android/server/location/gnss/GnssGeofenceProviderTest.java
index 30c73368da15..4a533aac01db 100644
--- a/services/robotests/src/com/android/server/location/GnssGeofenceProviderTest.java
+++ b/services/robotests/src/com/android/server/location/gnss/GnssGeofenceProviderTest.java
@@ -1,4 +1,20 @@
-package com.android.server.location;
+/*
+ * Copyright (C) 2020 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.location.gnss;
import static org.mockito.ArgumentMatchers.anyDouble;
import static org.mockito.ArgumentMatchers.anyInt;
diff --git a/services/robotests/src/com/android/server/location/GnssMeasurementsProviderTest.java b/services/robotests/src/com/android/server/location/gnss/GnssMeasurementsProviderTest.java
index b349b67dab0c..e7d9ef810e51 100644
--- a/services/robotests/src/com/android/server/location/GnssMeasurementsProviderTest.java
+++ b/services/robotests/src/com/android/server/location/gnss/GnssMeasurementsProviderTest.java
@@ -1,4 +1,20 @@
-package com.android.server.location;
+/*
+ * Copyright (C) 2020 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.location.gnss;
import static com.google.common.truth.Truth.assertThat;
@@ -26,7 +42,8 @@ import org.robolectric.RuntimeEnvironment;
@Presubmit
public class GnssMeasurementsProviderTest {
@Mock
- private GnssMeasurementsProvider.GnssMeasurementProviderNative mMockNative;
+ private GnssMeasurementsProvider.GnssMeasurementProviderNative
+ mMockNative;
private GnssMeasurementsProvider mTestProvider;
@Before
diff --git a/services/robotests/src/com/android/server/location/GnssNavigationMessageProviderTest.java b/services/robotests/src/com/android/server/location/gnss/GnssNavigationMessageProviderTest.java
index aa2a96e6fad4..c21db73fb56c 100644
--- a/services/robotests/src/com/android/server/location/GnssNavigationMessageProviderTest.java
+++ b/services/robotests/src/com/android/server/location/gnss/GnssNavigationMessageProviderTest.java
@@ -1,4 +1,20 @@
-package com.android.server.location;
+/*
+ * Copyright (C) 2020 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.location.gnss;
import static com.google.common.truth.Truth.assertThat;
@@ -25,7 +41,8 @@ import org.robolectric.RuntimeEnvironment;
@Presubmit
public class GnssNavigationMessageProviderTest {
@Mock
- private GnssNavigationMessageProvider.GnssNavigationMessageProviderNative mMockNative;
+ private GnssNavigationMessageProvider.GnssNavigationMessageProviderNative
+ mMockNative;
private GnssNavigationMessageProvider mTestProvider;
@Before
diff --git a/services/robotests/src/com/android/server/location/GnssPositionModeTest.java b/services/robotests/src/com/android/server/location/gnss/GnssPositionModeTest.java
index f37f50e76ae5..7117ff95b401 100644
--- a/services/robotests/src/com/android/server/location/GnssPositionModeTest.java
+++ b/services/robotests/src/com/android/server/location/gnss/GnssPositionModeTest.java
@@ -1,4 +1,20 @@
-package com.android.server.location;
+/*
+ * Copyright (C) 2020 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.location.gnss;
import static com.google.common.truth.Truth.assertThat;
diff --git a/services/robotests/src/com/android/server/location/GnssSatelliteBlacklistHelperTest.java b/services/robotests/src/com/android/server/location/gnss/GnssSatelliteBlacklistHelperTest.java
index ba4a753e4813..7c73a2f92f71 100644
--- a/services/robotests/src/com/android/server/location/GnssSatelliteBlacklistHelperTest.java
+++ b/services/robotests/src/com/android/server/location/gnss/GnssSatelliteBlacklistHelperTest.java
@@ -1,4 +1,20 @@
-package com.android.server.location;
+/*
+ * Copyright (C) 2020 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.location.gnss;
import static com.google.common.truth.Truth.assertThat;
@@ -35,7 +51,8 @@ public class GnssSatelliteBlacklistHelperTest {
private ContentResolver mContentResolver;
@Mock
- private GnssSatelliteBlacklistHelper.GnssSatelliteBlacklistCallback mCallback;
+ private GnssSatelliteBlacklistHelper.GnssSatelliteBlacklistCallback
+ mCallback;
@Before
public void setUp() {
diff --git a/services/robotests/src/com/android/server/location/NtpTimeHelperTest.java b/services/robotests/src/com/android/server/location/gnss/NtpTimeHelperTest.java
index 9c5d4ad6ceeb..9b59aaddc4d4 100644
--- a/services/robotests/src/com/android/server/location/NtpTimeHelperTest.java
+++ b/services/robotests/src/com/android/server/location/gnss/NtpTimeHelperTest.java
@@ -1,4 +1,20 @@
-package com.android.server.location;
+/*
+ * Copyright (C) 2020 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.location.gnss;
import static com.google.common.truth.Truth.assertThat;
@@ -10,7 +26,7 @@ import android.os.SystemClock;
import android.platform.test.annotations.Presubmit;
import android.util.NtpTrustedTime;
-import com.android.server.location.NtpTimeHelper.InjectNtpTimeCallback;
+import com.android.server.location.gnss.NtpTimeHelper.InjectNtpTimeCallback;
import org.junit.Before;
import org.junit.Test;
diff --git a/services/robotests/src/com/android/server/pm/CrossProfileAppsServiceImplRoboTest.java b/services/robotests/src/com/android/server/pm/CrossProfileAppsServiceImplRoboTest.java
new file mode 100644
index 000000000000..4b25890e5fdb
--- /dev/null
+++ b/services/robotests/src/com/android/server/pm/CrossProfileAppsServiceImplRoboTest.java
@@ -0,0 +1,754 @@
+/*
+ * Copyright (C) 2020 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.pm;
+
+import static android.app.AppOpsManager.MODE_ALLOWED;
+import static android.app.AppOpsManager.MODE_DEFAULT;
+import static android.app.AppOpsManager.OP_INTERACT_ACROSS_PROFILES;
+import static android.content.Intent.FLAG_RECEIVER_FOREGROUND;
+import static android.content.Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND;
+import static android.content.Intent.FLAG_RECEIVER_REGISTERED_ONLY;
+import static android.content.pm.CrossProfileApps.ACTION_CAN_INTERACT_ACROSS_PROFILES_CHANGED;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.junit.Assert.fail;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.when;
+import static org.robolectric.Shadows.shadowOf;
+
+import android.Manifest;
+import android.annotation.UserIdInt;
+import android.app.ActivityManagerInternal;
+import android.app.AppOpsManager;
+import android.app.AppOpsManager.Mode;
+import android.app.admin.DevicePolicyManager;
+import android.app.admin.DevicePolicyManagerInternal;
+import android.content.ComponentName;
+import android.content.ContextWrapper;
+import android.content.Intent;
+import android.content.pm.ActivityInfo;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.IPackageManager;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManagerInternal;
+import android.content.pm.PermissionInfo;
+import android.content.pm.ResolveInfo;
+import android.os.Process;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.platform.test.annotations.Presubmit;
+
+import androidx.test.core.app.ApplicationProvider;
+
+import com.android.internal.util.FunctionalUtils.ThrowingRunnable;
+import com.android.internal.util.FunctionalUtils.ThrowingSupplier;
+import com.android.server.LocalServices;
+import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.parsing.pkg.PackageImpl;
+import com.android.server.pm.parsing.pkg.ParsedPackage;
+import com.android.server.testing.shadows.ShadowApplicationPackageManager;
+import com.android.server.testing.shadows.ShadowUserManager;
+import com.android.server.wm.ActivityTaskManagerInternal;
+
+import com.google.android.collect.Lists;
+
+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.annotation.Config;
+import org.robolectric.shadow.api.Shadow;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/** Unit tests for {@link CrossProfileAppsServiceImpl}. */
+@RunWith(RobolectricTestRunner.class)
+@Presubmit
+@Config(shadows = {ShadowUserManager.class, ShadowApplicationPackageManager.class})
+public class CrossProfileAppsServiceImplRoboTest {
+ private static final int CALLING_UID = 1111;
+ private static final int CALLING_PID = 1000;
+ private static final String CROSS_PROFILE_APP_PACKAGE_NAME =
+ "com.android.server.pm.crossprofileappsserviceimplrobotest.crossprofileapp";
+ private static final int PERSONAL_PROFILE_USER_ID = 0;
+ private static final int PERSONAL_PROFILE_UID = 2222;
+ private static final int WORK_PROFILE_USER_ID = 10;
+ private static final int WORK_PROFILE_UID = 3333;
+ private static final int OTHER_PROFILE_WITHOUT_CROSS_PROFILE_APP_USER_ID = 20;
+ private static final int OUTSIDE_PROFILE_GROUP_USER_ID = 30;
+
+ private final ContextWrapper mContext = ApplicationProvider.getApplicationContext();
+ private final UserManager mUserManager = mContext.getSystemService(UserManager.class);
+ private final AppOpsManager mAppOpsManager = mContext.getSystemService(AppOpsManager.class);
+ private final PackageManager mPackageManager = mContext.getPackageManager();
+ private final TestInjector mInjector = new TestInjector();
+ private final CrossProfileAppsServiceImpl mCrossProfileAppsServiceImpl =
+ new CrossProfileAppsServiceImpl(mContext, mInjector);
+ private final Map<UserHandle, Set<Intent>> mSentUserBroadcasts = new HashMap<>();
+ private final Map<Integer, List<ApplicationInfo>> installedApplications = new HashMap<>();
+ private final Set<Integer> mKilledUids = new HashSet<>();
+
+ @Mock private PackageManagerInternal mPackageManagerInternal;
+ @Mock private IPackageManager mIPackageManager;
+ @Mock private DevicePolicyManagerInternal mDevicePolicyManagerInternal;
+
+ @Before
+ public void initializeMocks() throws Exception {
+ MockitoAnnotations.initMocks(this);
+ initializeInstalledApplicationsMock();
+ mockCrossProfileAppInstalledAndEnabledOnEachProfile();
+ mockCrossProfileAppRequestsInteractAcrossProfiles();
+ mockCrossProfileAppRegistersBroadcastReceiver();
+ mockCrossProfileAppWhitelisted();
+ }
+
+ private void initializeInstalledApplicationsMock() {
+ when(mPackageManagerInternal.getInstalledApplications(anyInt(), anyInt(), eq(CALLING_UID)))
+ .thenAnswer(invocation -> installedApplications.get(invocation.getArgument(1)));
+ }
+
+ private void mockCrossProfileAppInstalledAndEnabledOnEachProfile() {
+ // They are enabled by default, so we simply have to ensure that a package info with an
+ // application info is returned.
+ final PackageInfo packageInfo = buildTestPackageInfo();
+ mockCrossProfileAppInstalledOnProfile(
+ packageInfo, PERSONAL_PROFILE_USER_ID, PERSONAL_PROFILE_UID);
+ mockCrossProfileAppInstalledOnProfile(packageInfo, WORK_PROFILE_USER_ID, WORK_PROFILE_UID);
+ }
+
+ private void mockCrossProfileAppInstalledOnProfile(
+ PackageInfo packageInfo, @UserIdInt int userId, int uid) {
+ when(mPackageManagerInternal.getPackageInfo(
+ eq(CROSS_PROFILE_APP_PACKAGE_NAME),
+ /* flags= */ anyInt(),
+ /* filterCallingUid= */ anyInt(),
+ eq(userId)))
+ .thenReturn(packageInfo);
+ when(mPackageManagerInternal.getPackage(uid))
+ .thenReturn(((ParsedPackage) PackageImpl.forTesting(CROSS_PROFILE_APP_PACKAGE_NAME)
+ .hideAsParsed()).hideAsFinal());
+ installedApplications.putIfAbsent(userId, new ArrayList<>());
+ installedApplications.get(userId).add(packageInfo.applicationInfo);
+ }
+
+ private PackageInfo buildTestPackageInfo() {
+ PackageInfo packageInfo = new PackageInfo();
+ packageInfo.applicationInfo = new ApplicationInfo();
+ packageInfo.applicationInfo.packageName = CROSS_PROFILE_APP_PACKAGE_NAME;
+ return packageInfo;
+ }
+
+ private void mockCrossProfileAppRequestsInteractAcrossProfiles() throws Exception {
+ final String permissionName = Manifest.permission.INTERACT_ACROSS_PROFILES;
+ when(mIPackageManager.getAppOpPermissionPackages(permissionName))
+ .thenReturn(new String[] {CROSS_PROFILE_APP_PACKAGE_NAME});
+ }
+
+ private void mockCrossProfileAppRegistersBroadcastReceiver() {
+ final ShadowApplicationPackageManager shadowApplicationPackageManager =
+ Shadow.extract(mPackageManager);
+ final Intent baseIntent =
+ new Intent(ACTION_CAN_INTERACT_ACROSS_PROFILES_CHANGED)
+ .setPackage(CROSS_PROFILE_APP_PACKAGE_NAME);
+ final Intent manifestIntent =
+ new Intent(baseIntent)
+ .setFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND
+ | Intent.FLAG_RECEIVER_FOREGROUND);
+ final Intent registeredIntent =
+ new Intent(baseIntent).setFlags(FLAG_RECEIVER_REGISTERED_ONLY);
+ final List<ResolveInfo> resolveInfos = Lists.newArrayList(buildTestResolveInfo());
+ shadowApplicationPackageManager.setResolveInfosForIntent(manifestIntent, resolveInfos);
+ shadowApplicationPackageManager.setResolveInfosForIntent(registeredIntent, resolveInfos);
+ }
+
+ private ResolveInfo buildTestResolveInfo() {
+ final ResolveInfo resolveInfo = new ResolveInfo();
+ resolveInfo.activityInfo = new ActivityInfo();
+ resolveInfo.activityInfo.packageName = CROSS_PROFILE_APP_PACKAGE_NAME;
+ resolveInfo.activityInfo.name = CROSS_PROFILE_APP_PACKAGE_NAME + ".Receiver";
+ return resolveInfo;
+ }
+
+ private void mockCrossProfileAppWhitelisted() {
+ when(mDevicePolicyManagerInternal.getAllCrossProfilePackages())
+ .thenReturn(Lists.newArrayList(CROSS_PROFILE_APP_PACKAGE_NAME));
+ }
+
+ @Before
+ public void setUpCrossProfileAppUidsAndPackageNames() {
+ ShadowApplicationPackageManager.setPackageUidAsUser(
+ CROSS_PROFILE_APP_PACKAGE_NAME, PERSONAL_PROFILE_UID, PERSONAL_PROFILE_USER_ID);
+ ShadowApplicationPackageManager.setPackageUidAsUser(
+ CROSS_PROFILE_APP_PACKAGE_NAME, WORK_PROFILE_UID, WORK_PROFILE_USER_ID);
+ when(mPackageManagerInternal.getPackageUidInternal(
+ CROSS_PROFILE_APP_PACKAGE_NAME, /* flags= */ 0, PERSONAL_PROFILE_USER_ID))
+ .thenReturn(PERSONAL_PROFILE_UID);
+ when(mPackageManagerInternal.getPackageUidInternal(
+ CROSS_PROFILE_APP_PACKAGE_NAME, /* flags= */ 0, WORK_PROFILE_USER_ID))
+ .thenReturn(WORK_PROFILE_UID);
+ }
+
+ @Before
+ public void grantPermissions() {
+ grantPermissions(
+ Manifest.permission.MANAGE_APP_OPS_MODES,
+ Manifest.permission.UPDATE_APP_OPS_STATS,
+ Manifest.permission.CONFIGURE_INTERACT_ACROSS_PROFILES,
+ Manifest.permission.INTERACT_ACROSS_USERS,
+ Manifest.permission.INTERACT_ACROSS_USERS_FULL);
+ }
+
+ @Before
+ public void setUpProfiles() {
+ final ShadowUserManager shadowUserManager = Shadow.extract(mUserManager);
+ shadowUserManager.addProfileIds(
+ PERSONAL_PROFILE_USER_ID,
+ WORK_PROFILE_USER_ID,
+ OTHER_PROFILE_WITHOUT_CROSS_PROFILE_APP_USER_ID);
+ shadowUserManager.addProfileIds(OUTSIDE_PROFILE_GROUP_USER_ID);
+ }
+
+ @Before
+ public void setInteractAcrossProfilesAppOpDefault() {
+ // It seems to be necessary to provide the shadow with the default already specified in
+ // AppOpsManager.
+ final int defaultMode = AppOpsManager.opToDefaultMode(OP_INTERACT_ACROSS_PROFILES);
+ explicitlySetInteractAcrossProfilesAppOp(PERSONAL_PROFILE_UID, defaultMode);
+ explicitlySetInteractAcrossProfilesAppOp(WORK_PROFILE_UID, defaultMode);
+ }
+
+ @Test
+ public void setInteractAcrossProfilesAppOp_noPermissions_throwsSecurityException() {
+ denyPermissions(
+ Manifest.permission.MANAGE_APP_OPS_MODES,
+ Manifest.permission.UPDATE_APP_OPS_STATS,
+ Manifest.permission.CONFIGURE_INTERACT_ACROSS_PROFILES,
+ Manifest.permission.INTERACT_ACROSS_USERS,
+ Manifest.permission.INTERACT_ACROSS_USERS_FULL);
+ try {
+ mCrossProfileAppsServiceImpl.setInteractAcrossProfilesAppOp(
+ CROSS_PROFILE_APP_PACKAGE_NAME, MODE_ALLOWED);
+ fail();
+ } catch (SecurityException expected) {}
+ }
+
+ @Test
+ public void setInteractAcrossProfilesAppOp_missingInteractAcrossUsersAndFull_throwsSecurityException() {
+ denyPermissions(
+ Manifest.permission.INTERACT_ACROSS_USERS,
+ Manifest.permission.INTERACT_ACROSS_USERS_FULL);
+ grantPermissions(Manifest.permission.CONFIGURE_INTERACT_ACROSS_PROFILES);
+ try {
+ mCrossProfileAppsServiceImpl.setInteractAcrossProfilesAppOp(
+ CROSS_PROFILE_APP_PACKAGE_NAME, MODE_ALLOWED);
+ fail();
+ } catch (SecurityException expected) {}
+ }
+
+ @Test
+ public void setInteractAcrossProfilesAppOp_setsAppOp() {
+ mCrossProfileAppsServiceImpl.setInteractAcrossProfilesAppOp(
+ CROSS_PROFILE_APP_PACKAGE_NAME, MODE_ALLOWED);
+ assertThat(getCrossProfileAppOp()).isEqualTo(MODE_ALLOWED);
+ }
+
+ @Test
+ public void setInteractAcrossProfilesAppOp_configureInteractAcrossProfilesPermissionWithoutAppOpsPermissions_setsAppOp() {
+ denyPermissions(
+ Manifest.permission.MANAGE_APP_OPS_MODES,
+ Manifest.permission.UPDATE_APP_OPS_STATS);
+ grantPermissions(
+ Manifest.permission.CONFIGURE_INTERACT_ACROSS_PROFILES,
+ Manifest.permission.INTERACT_ACROSS_USERS);
+
+ mCrossProfileAppsServiceImpl.setInteractAcrossProfilesAppOp(
+ CROSS_PROFILE_APP_PACKAGE_NAME, MODE_ALLOWED);
+
+ assertThat(getCrossProfileAppOp()).isEqualTo(MODE_ALLOWED);
+ }
+
+ @Test
+ public void setInteractAcrossProfilesAppOp_appOpsPermissionsWithoutConfigureInteractAcrossProfilesPermission_setsAppOp() {
+ denyPermissions(Manifest.permission.CONFIGURE_INTERACT_ACROSS_PROFILES);
+ grantPermissions(
+ Manifest.permission.MANAGE_APP_OPS_MODES,
+ Manifest.permission.UPDATE_APP_OPS_STATS,
+ Manifest.permission.INTERACT_ACROSS_USERS);
+
+ mCrossProfileAppsServiceImpl.setInteractAcrossProfilesAppOp(
+ CROSS_PROFILE_APP_PACKAGE_NAME, MODE_ALLOWED);
+
+ assertThat(getCrossProfileAppOp()).isEqualTo(MODE_ALLOWED);
+ }
+
+ @Test
+ public void setInteractAcrossProfilesAppOp_setsAppOpWithUsersAndWithoutFull() {
+ denyPermissions(Manifest.permission.INTERACT_ACROSS_USERS_FULL);
+ grantPermissions(Manifest.permission.INTERACT_ACROSS_USERS);
+ mCrossProfileAppsServiceImpl.setInteractAcrossProfilesAppOp(
+ CROSS_PROFILE_APP_PACKAGE_NAME, MODE_ALLOWED);
+ assertThat(getCrossProfileAppOp()).isEqualTo(MODE_ALLOWED);
+ }
+
+ @Test
+ public void setInteractAcrossProfilesAppOp_setsAppOpWithFullAndWithoutUsers() {
+ denyPermissions(Manifest.permission.INTERACT_ACROSS_USERS);
+ grantPermissions(Manifest.permission.INTERACT_ACROSS_USERS_FULL);
+ mCrossProfileAppsServiceImpl.setInteractAcrossProfilesAppOp(
+ CROSS_PROFILE_APP_PACKAGE_NAME, MODE_ALLOWED);
+ assertThat(getCrossProfileAppOp()).isEqualTo(MODE_ALLOWED);
+ }
+
+ @Test
+ public void setInteractAcrossProfilesAppOp_setsAppOpOnOtherProfile() {
+ mCrossProfileAppsServiceImpl.setInteractAcrossProfilesAppOp(
+ CROSS_PROFILE_APP_PACKAGE_NAME, MODE_ALLOWED);
+ assertThat(getCrossProfileAppOp(WORK_PROFILE_UID)).isEqualTo(MODE_ALLOWED);
+ }
+
+ @Test
+ public void setInteractAcrossProfilesAppOp_sendsBroadcast() {
+ mCrossProfileAppsServiceImpl.setInteractAcrossProfilesAppOp(
+ CROSS_PROFILE_APP_PACKAGE_NAME, MODE_ALLOWED);
+ assertThat(receivedCanInteractAcrossProfilesChangedBroadcast()).isTrue();
+ }
+
+ @Test
+ public void setInteractAcrossProfilesAppOp_sendsBroadcastToOtherProfile() {
+ mCrossProfileAppsServiceImpl.setInteractAcrossProfilesAppOp(
+ CROSS_PROFILE_APP_PACKAGE_NAME, MODE_ALLOWED);
+ assertThat(receivedCanInteractAcrossProfilesChangedBroadcast(WORK_PROFILE_USER_ID))
+ .isTrue();
+ }
+
+ @Test
+ public void setInteractAcrossProfilesAppOp_doesNotSendBroadcastToProfileWithoutPackage() {
+ mCrossProfileAppsServiceImpl.setInteractAcrossProfilesAppOp(
+ CROSS_PROFILE_APP_PACKAGE_NAME, MODE_ALLOWED);
+ assertThat(receivedCanInteractAcrossProfilesChangedBroadcast(
+ OTHER_PROFILE_WITHOUT_CROSS_PROFILE_APP_USER_ID))
+ .isFalse();
+ }
+
+ @Test
+ public void setInteractAcrossProfilesAppOp_toSameAsCurrent_doesNotSendBroadcast() {
+ explicitlySetInteractAcrossProfilesAppOp(MODE_ALLOWED);
+ mCrossProfileAppsServiceImpl.setInteractAcrossProfilesAppOp(
+ CROSS_PROFILE_APP_PACKAGE_NAME, MODE_ALLOWED);
+ assertThat(receivedCanInteractAcrossProfilesChangedBroadcast()).isFalse();
+ }
+
+ @Test
+ public void setInteractAcrossProfilesAppOp_toAllowed_whenNotAbleToRequest_doesNotSet() {
+ mockCrossProfileAppNotWhitelisted();
+ mCrossProfileAppsServiceImpl.setInteractAcrossProfilesAppOp(
+ CROSS_PROFILE_APP_PACKAGE_NAME, MODE_ALLOWED);
+ assertThat(getCrossProfileAppOp()).isNotEqualTo(MODE_ALLOWED);
+ }
+
+ @Test
+ public void setInteractAcrossProfilesAppOp_toAllowed_whenNotAbleToRequest_doesNotSendBroadcast() {
+ mockCrossProfileAppNotWhitelisted();
+ mCrossProfileAppsServiceImpl.setInteractAcrossProfilesAppOp(
+ CROSS_PROFILE_APP_PACKAGE_NAME, MODE_ALLOWED);
+ assertThat(receivedCanInteractAcrossProfilesChangedBroadcast()).isFalse();
+ }
+
+ @Test
+ public void setInteractAcrossProfilesAppOp_withoutCrossProfileAttribute_manifestReceiversDoNotGetBroadcast() {
+ declareCrossProfileAttributeOnCrossProfileApp(false);
+ mCrossProfileAppsServiceImpl.setInteractAcrossProfilesAppOp(
+ CROSS_PROFILE_APP_PACKAGE_NAME, MODE_ALLOWED);
+ assertThat(receivedManifestCanInteractAcrossProfilesChangedBroadcast()).isFalse();
+ }
+
+ @Test
+ public void setInteractAcrossProfilesAppOp_withCrossProfileAttribute_manifestReceiversGetBroadcast() {
+ declareCrossProfileAttributeOnCrossProfileApp(true);
+ mCrossProfileAppsServiceImpl.setInteractAcrossProfilesAppOp(
+ CROSS_PROFILE_APP_PACKAGE_NAME, MODE_ALLOWED);
+ assertThat(receivedManifestCanInteractAcrossProfilesChangedBroadcast()).isTrue();
+ }
+
+ @Test
+ public void setInteractAcrossProfilesAppOp_toAllowed_doesNotKillApp() {
+ mCrossProfileAppsServiceImpl.setInteractAcrossProfilesAppOp(
+ CROSS_PROFILE_APP_PACKAGE_NAME, MODE_ALLOWED);
+ assertThat(mKilledUids).isEmpty();
+ }
+
+ @Test
+ public void setInteractAcrossProfilesAppOp_toDisallowed_killsAppsInBothProfiles() {
+ shadowOf(mPackageManager).addPermissionInfo(createCrossProfilesPermissionInfo());
+ mCrossProfileAppsServiceImpl.setInteractAcrossProfilesAppOp(
+ CROSS_PROFILE_APP_PACKAGE_NAME, MODE_ALLOWED);
+
+ mCrossProfileAppsServiceImpl.setInteractAcrossProfilesAppOp(
+ CROSS_PROFILE_APP_PACKAGE_NAME, MODE_DEFAULT);
+
+ assertThat(mKilledUids).contains(WORK_PROFILE_UID);
+ assertThat(mKilledUids).contains(PERSONAL_PROFILE_UID);
+ }
+
+ private PermissionInfo createCrossProfilesPermissionInfo() {
+ PermissionInfo permissionInfo = new PermissionInfo();
+ permissionInfo.name = Manifest.permission.INTERACT_ACROSS_PROFILES;
+ permissionInfo.protectionLevel = PermissionInfo.PROTECTION_FLAG_APPOP;
+ return permissionInfo;
+ }
+
+ @Test
+ public void canConfigureInteractAcrossProfiles_packageNotInstalledInProfile_returnsFalse() {
+ mockUninstallCrossProfileAppFromWorkProfile();
+ assertThat(mCrossProfileAppsServiceImpl
+ .canConfigureInteractAcrossProfiles(CROSS_PROFILE_APP_PACKAGE_NAME))
+ .isFalse();
+ }
+
+ private void mockUninstallCrossProfileAppFromWorkProfile() {
+ when(mPackageManagerInternal.getPackageInfo(
+ eq(CROSS_PROFILE_APP_PACKAGE_NAME),
+ /* flags= */ anyInt(),
+ /* filterCallingUid= */ anyInt(),
+ eq(WORK_PROFILE_USER_ID)))
+ .thenReturn(null);
+ when(mPackageManagerInternal.getPackage(WORK_PROFILE_UID)).thenReturn(null);
+ }
+
+ @Test
+ public void canConfigureInteractAcrossProfiles_packageDoesNotRequestInteractAcrossProfiles_returnsFalse()
+ throws Exception {
+ mockCrossProfileAppDoesNotRequestInteractAcrossProfiles();
+ assertThat(mCrossProfileAppsServiceImpl
+ .canConfigureInteractAcrossProfiles(CROSS_PROFILE_APP_PACKAGE_NAME))
+ .isFalse();
+ }
+
+ private void mockCrossProfileAppDoesNotRequestInteractAcrossProfiles() throws Exception {
+ final String permissionName = Manifest.permission.INTERACT_ACROSS_PROFILES;
+ when(mIPackageManager.getAppOpPermissionPackages(permissionName))
+ .thenReturn(new String[] {});
+ }
+
+ @Test
+ public void canConfigureInteractAcrossProfiles_packageNotWhitelisted_returnsFalse() {
+ mockCrossProfileAppNotWhitelisted();
+ assertThat(mCrossProfileAppsServiceImpl
+ .canConfigureInteractAcrossProfiles(CROSS_PROFILE_APP_PACKAGE_NAME))
+ .isFalse();
+ }
+
+ @Test
+ public void canConfigureInteractAcrossProfiles_returnsTrue() {
+ assertThat(mCrossProfileAppsServiceImpl
+ .canConfigureInteractAcrossProfiles(CROSS_PROFILE_APP_PACKAGE_NAME))
+ .isTrue();
+ }
+
+ @Test
+ public void canUserAttemptToConfigureInteractAcrossProfiles_packageNotInstalledInProfile_returnsTrue() {
+ mockUninstallCrossProfileAppFromWorkProfile();
+ assertThat(mCrossProfileAppsServiceImpl
+ .canUserAttemptToConfigureInteractAcrossProfiles(CROSS_PROFILE_APP_PACKAGE_NAME))
+ .isTrue();
+ }
+
+ @Test
+ public void canUserAttemptToConfigureInteractAcrossProfiles_packageDoesNotRequestInteractAcrossProfiles_returnsFalse()
+ throws Exception {
+ mockCrossProfileAppDoesNotRequestInteractAcrossProfiles();
+ assertThat(mCrossProfileAppsServiceImpl
+ .canUserAttemptToConfigureInteractAcrossProfiles(CROSS_PROFILE_APP_PACKAGE_NAME))
+ .isFalse();
+ }
+
+ @Test
+ public void canUserAttemptToConfigureInteractAcrossProfiles_packageNotWhitelisted_returnsTrue() {
+ mockCrossProfileAppNotWhitelisted();
+ assertThat(mCrossProfileAppsServiceImpl
+ .canUserAttemptToConfigureInteractAcrossProfiles(CROSS_PROFILE_APP_PACKAGE_NAME))
+ .isTrue();
+ }
+
+ @Test
+ public void canUserAttemptToConfigureInteractAcrossProfiles_platformSignedAppWithAutomaticPermission_returnsFalse() {
+ mockCrossProfileAppNotWhitelistedByOem();
+ shadowOf(mContext).grantPermissions(
+ Process.myPid(),
+ PERSONAL_PROFILE_UID,
+ Manifest.permission.INTERACT_ACROSS_PROFILES);
+
+ assertThat(mCrossProfileAppsServiceImpl
+ .canUserAttemptToConfigureInteractAcrossProfiles(CROSS_PROFILE_APP_PACKAGE_NAME))
+ .isFalse();
+ }
+
+ @Test
+ public void canUserAttemptToConfigureInteractAcrossProfiles_profileOwnerWorkProfile_returnsFalse() {
+ when(mDevicePolicyManagerInternal.getProfileOwnerAsUser(WORK_PROFILE_USER_ID))
+ .thenReturn(buildCrossProfileComponentName());
+ assertThat(mCrossProfileAppsServiceImpl
+ .canUserAttemptToConfigureInteractAcrossProfiles(CROSS_PROFILE_APP_PACKAGE_NAME))
+ .isFalse();
+ }
+
+ @Test
+ public void canUserAttemptToConfigureInteractAcrossProfiles_profileOwnerOtherProfile_returnsFalse() {
+ // Normally, the DPC would not be a profile owner of the personal profile, but for the
+ // purposes of this test, it is just a profile owner of any profile within the profile
+ // group.
+ when(mDevicePolicyManagerInternal.getProfileOwnerAsUser(PERSONAL_PROFILE_USER_ID))
+ .thenReturn(buildCrossProfileComponentName());
+ assertThat(mCrossProfileAppsServiceImpl
+ .canUserAttemptToConfigureInteractAcrossProfiles(CROSS_PROFILE_APP_PACKAGE_NAME))
+ .isFalse();
+ }
+
+ @Test
+ public void canUserAttemptToConfigureInteractAcrossProfiles_profileOwnerOutsideProfileGroup_returnsTrue() {
+ when(mDevicePolicyManagerInternal.getProfileOwnerAsUser(OUTSIDE_PROFILE_GROUP_USER_ID))
+ .thenReturn(buildCrossProfileComponentName());
+ assertThat(mCrossProfileAppsServiceImpl
+ .canUserAttemptToConfigureInteractAcrossProfiles(CROSS_PROFILE_APP_PACKAGE_NAME))
+ .isTrue();
+ }
+
+ @Test
+ public void canUserAttemptToConfigureInteractAcrossProfiles_returnsTrue() {
+ assertThat(mCrossProfileAppsServiceImpl
+ .canUserAttemptToConfigureInteractAcrossProfiles(CROSS_PROFILE_APP_PACKAGE_NAME))
+ .isTrue();
+ }
+
+ @Test
+ public void clearInteractAcrossProfilesAppOps() {
+ explicitlySetInteractAcrossProfilesAppOp(MODE_ALLOWED);
+ mCrossProfileAppsServiceImpl.clearInteractAcrossProfilesAppOps();
+ assertThat(getCrossProfileAppOp()).isEqualTo(MODE_DEFAULT);
+ }
+
+ private void explicitlySetInteractAcrossProfilesAppOp(@Mode int mode) {
+ explicitlySetInteractAcrossProfilesAppOp(PERSONAL_PROFILE_UID, mode);
+ }
+
+ private void explicitlySetInteractAcrossProfilesAppOp(int uid, @Mode int mode) {
+ shadowOf(mAppOpsManager).setMode(
+ OP_INTERACT_ACROSS_PROFILES, uid, CROSS_PROFILE_APP_PACKAGE_NAME, mode);
+ }
+
+ private void grantPermissions(String... permissions) {
+ shadowOf(mContext).grantPermissions(Process.myPid(), CALLING_UID, permissions);
+ }
+
+ private void denyPermissions(String... permissions) {
+ shadowOf(mContext).denyPermissions(Process.myPid(), CALLING_UID, permissions);
+ }
+
+ private @Mode int getCrossProfileAppOp() {
+ return getCrossProfileAppOp(PERSONAL_PROFILE_UID);
+ }
+
+ private @Mode int getCrossProfileAppOp(int uid) {
+ return mAppOpsManager.unsafeCheckOpNoThrow(
+ AppOpsManager.permissionToOp(Manifest.permission.INTERACT_ACROSS_PROFILES),
+ uid,
+ CROSS_PROFILE_APP_PACKAGE_NAME);
+ }
+
+ private boolean receivedCanInteractAcrossProfilesChangedBroadcast() {
+ return receivedCanInteractAcrossProfilesChangedBroadcast(PERSONAL_PROFILE_USER_ID);
+ }
+
+ private boolean receivedCanInteractAcrossProfilesChangedBroadcast(@UserIdInt int userId) {
+ final UserHandle userHandle = UserHandle.of(userId);
+ if (!mSentUserBroadcasts.containsKey(userHandle)) {
+ return false;
+ }
+ return mSentUserBroadcasts.get(userHandle)
+ .stream()
+ .anyMatch(this::isBroadcastCanInteractAcrossProfilesChanged);
+ }
+
+ private boolean isBroadcastCanInteractAcrossProfilesChanged(Intent intent) {
+ return intent.getAction().equals(ACTION_CAN_INTERACT_ACROSS_PROFILES_CHANGED)
+ && CROSS_PROFILE_APP_PACKAGE_NAME.equals(intent.getPackage());
+ }
+
+ private void mockCrossProfileAndroidPackage(AndroidPackage androidPackage) {
+ when(mPackageManagerInternal.getPackage(CROSS_PROFILE_APP_PACKAGE_NAME))
+ .thenReturn(androidPackage);
+ when(mPackageManagerInternal.getPackage(PERSONAL_PROFILE_UID)).thenReturn(androidPackage);
+ when(mPackageManagerInternal.getPackage(WORK_PROFILE_UID)).thenReturn(androidPackage);
+ }
+
+ private void mockCrossProfileAppNotWhitelisted() {
+ when(mDevicePolicyManagerInternal.getAllCrossProfilePackages())
+ .thenReturn(new ArrayList<>());
+ }
+
+ private void mockCrossProfileAppNotWhitelistedByOem() {
+ when(mDevicePolicyManagerInternal.getDefaultCrossProfilePackages())
+ .thenReturn(new ArrayList<>());
+ }
+
+ private boolean receivedManifestCanInteractAcrossProfilesChangedBroadcast() {
+ final UserHandle userHandle = UserHandle.of(PERSONAL_PROFILE_USER_ID);
+ if (!mSentUserBroadcasts.containsKey(userHandle)) {
+ return false;
+ }
+ return mSentUserBroadcasts.get(userHandle)
+ .stream()
+ .anyMatch(this::isBroadcastManifestCanInteractAcrossProfilesChanged);
+ }
+
+ private boolean isBroadcastManifestCanInteractAcrossProfilesChanged(Intent intent) {
+ return isBroadcastCanInteractAcrossProfilesChanged(intent)
+ && (intent.getFlags() & FLAG_RECEIVER_REGISTERED_ONLY) == 0
+ && (intent.getFlags() & FLAG_RECEIVER_INCLUDE_BACKGROUND) != 0
+ && (intent.getFlags() & FLAG_RECEIVER_FOREGROUND) != 0
+ && intent.getComponent() != null
+ && intent.getComponent().getPackageName().equals(CROSS_PROFILE_APP_PACKAGE_NAME);
+ }
+
+ private void declareCrossProfileAttributeOnCrossProfileApp(boolean value) {
+ mockCrossProfileAndroidPackage(
+ ((ParsedPackage) PackageImpl.forTesting(CROSS_PROFILE_APP_PACKAGE_NAME)
+ .setCrossProfile(value)
+ .hideAsParsed()).hideAsFinal());
+ }
+
+ private ComponentName buildCrossProfileComponentName() {
+ return new ComponentName(CROSS_PROFILE_APP_PACKAGE_NAME, "testClassName");
+ }
+
+ private class TestInjector implements CrossProfileAppsServiceImpl.Injector {
+
+ @Override
+ public int getCallingUid() {
+ return CALLING_UID;
+ }
+
+ @Override
+ public int getCallingPid() {
+ return CALLING_PID;
+ }
+
+ @Override
+ public @UserIdInt int getCallingUserId() {
+ return PERSONAL_PROFILE_USER_ID;
+ }
+
+ @Override
+ public UserHandle getCallingUserHandle() {
+ return UserHandle.of(getCallingUserId());
+ }
+
+ @Override
+ public long clearCallingIdentity() {
+ return 0;
+ }
+
+ @Override
+ public void restoreCallingIdentity(long token) {}
+
+ @Override
+ public void withCleanCallingIdentity(ThrowingRunnable action) {
+ action.run();
+ }
+
+ @Override
+ public <T> T withCleanCallingIdentity(ThrowingSupplier<T> action) {
+ return action.get();
+ }
+
+ @Override
+ public UserManager getUserManager() {
+ return mUserManager;
+ }
+
+ @Override
+ public PackageManagerInternal getPackageManagerInternal() {
+ return mPackageManagerInternal;
+ }
+
+ @Override
+ public PackageManager getPackageManager() {
+ return mPackageManager;
+ }
+
+ @Override
+ public AppOpsManager getAppOpsManager() {
+ return mAppOpsManager;
+ }
+
+ @Override
+ public ActivityManagerInternal getActivityManagerInternal() {
+ return LocalServices.getService(ActivityManagerInternal.class);
+ }
+
+ @Override
+ public ActivityTaskManagerInternal getActivityTaskManagerInternal() {
+ return LocalServices.getService(ActivityTaskManagerInternal.class);
+ }
+
+ @Override
+ public IPackageManager getIPackageManager() {
+ return mIPackageManager;
+ }
+
+ @Override
+ public DevicePolicyManagerInternal getDevicePolicyManagerInternal() {
+ return mDevicePolicyManagerInternal;
+ }
+
+ @Override
+ public void sendBroadcastAsUser(Intent intent, UserHandle user) {
+ // Robolectric's shadows do not currently support sendBroadcastAsUser.
+ final Set<Intent> broadcasts =
+ mSentUserBroadcasts.containsKey(user)
+ ? mSentUserBroadcasts.get(user)
+ : new HashSet<>();
+ broadcasts.add(intent);
+ mSentUserBroadcasts.put(user, broadcasts);
+ mContext.sendBroadcastAsUser(intent, user);
+ }
+
+ @Override
+ public int checkComponentPermission(
+ String permission, int uid, int owningUid, boolean exported) {
+ // ActivityManager#checkComponentPermission calls through to
+ // AppGlobals.getPackageManager()#checkUidPermission, which calls through to
+ // ShadowActivityThread with Robolectric. This method is currently not supported there.
+ return mContext.checkPermission(permission, Process.myPid(), uid);
+ }
+
+ @Override
+ public void killUid(int uid) {
+ mKilledUids.add(uid);
+ }
+ }
+}
diff --git a/services/robotests/src/com/android/server/testing/shadows/ShadowApplicationPackageManager.java b/services/robotests/src/com/android/server/testing/shadows/ShadowApplicationPackageManager.java
index ab121eddff06..aea36e555ad7 100644
--- a/services/robotests/src/com/android/server/testing/shadows/ShadowApplicationPackageManager.java
+++ b/services/robotests/src/com/android/server/testing/shadows/ShadowApplicationPackageManager.java
@@ -19,13 +19,17 @@ package com.android.server.testing.shadows;
import static android.content.pm.PackageManager.NameNotFoundException;
import android.app.ApplicationPackageManager;
+import android.content.Intent;
import android.content.pm.PackageInfo;
+import android.content.pm.ResolveInfo;
+import android.os.UserHandle;
import android.util.ArrayMap;
import org.robolectric.annotation.Implements;
import org.robolectric.annotation.Resetter;
import java.util.ArrayList;
+import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -39,6 +43,7 @@ public class ShadowApplicationPackageManager
private static final Map<String, PackageInfo> sPackageInfos = new ArrayMap<>();
private static final List<PackageInfo> sInstalledPackages = new ArrayList<>();
private static final Map<String, Integer> sPackageUids = new ArrayMap<>();
+ private static final Map<Integer, Map<String, Integer>> sUserPackageUids = new ArrayMap<>();
/**
* Registers the package {@code packageName} to be returned when invoking {@link
@@ -58,6 +63,19 @@ public class ShadowApplicationPackageManager
sPackageUids.put(packageName, packageUid);
}
+ /**
+ * Sets the package uid {@code packageUid} for the package {@code packageName} to be returned
+ * when invoking {@link ApplicationPackageManager#getPackageUidAsUser(String, int, int)}.
+ */
+ public static void setPackageUidAsUser(String packageName, int packageUid, int userId) {
+ final Map<String, Integer> userPackageUids =
+ sUserPackageUids.containsKey(userId)
+ ? sUserPackageUids.get(userId)
+ : new HashMap<>();
+ userPackageUids.put(packageName, packageUid);
+ sUserPackageUids.put(userId, userPackageUids);
+ }
+
@Override
protected PackageInfo getPackageInfoAsUser(String packageName, int flags, int userId)
throws NameNotFoundException {
@@ -75,12 +93,23 @@ public class ShadowApplicationPackageManager
@Override
protected int getPackageUidAsUser(String packageName, int flags, int userId)
throws NameNotFoundException {
+ if (sUserPackageUids.containsKey(userId)
+ && sUserPackageUids.get(userId).containsKey(packageName)) {
+ return sUserPackageUids.get(userId).get(packageName);
+ }
if (!sPackageUids.containsKey(packageName)) {
throw new NameNotFoundException(packageName);
}
return sPackageUids.get(packageName);
}
+ @Override
+ protected List<ResolveInfo> queryBroadcastReceiversAsUser(
+ Intent intent, int flags, UserHandle userHandle) {
+ // Currently does not handle multi-user.
+ return queryBroadcastReceivers(intent, flags);
+ }
+
/** Clear package state. */
@Resetter
public static void reset() {
diff --git a/services/robotests/src/com/android/server/testing/shadows/ShadowCloseGuard.java b/services/robotests/src/com/android/server/testing/shadows/ShadowCloseGuard.java
index c9984bf07059..4055dfc08f90 100644
--- a/services/robotests/src/com/android/server/testing/shadows/ShadowCloseGuard.java
+++ b/services/robotests/src/com/android/server/testing/shadows/ShadowCloseGuard.java
@@ -44,5 +44,10 @@ public class ShadowCloseGuard {
public void report(String message, Throwable allocationSite) {
mReports += 1;
}
+
+ @Override
+ public void report(String message) {
+ mReports += 1;
+ }
}
}
diff --git a/services/robotests/src/com/android/server/testing/shadows/ShadowEnvironment.java b/services/robotests/src/com/android/server/testing/shadows/ShadowEnvironment.java
new file mode 100644
index 000000000000..577b0824e775
--- /dev/null
+++ b/services/robotests/src/com/android/server/testing/shadows/ShadowEnvironment.java
@@ -0,0 +1,50 @@
+/*
+ * 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.testing.shadows;
+
+import android.annotation.Nullable;
+import android.os.Environment;
+
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Implementation;
+import org.robolectric.annotation.Implements;
+import org.robolectric.annotation.Resetter;
+
+import java.io.File;
+import java.nio.file.Path;
+
+/** Implementation mimics {@link org.robolectric.shadows.ShadowEnvironment}. */
+@Implements(Environment.class)
+public class ShadowEnvironment extends org.robolectric.shadows.ShadowEnvironment {
+ @Nullable private static Path sDataDirectory;
+
+ /** @see Environment#getDataDirectory() */
+ @Implementation
+ public static File getDataDirectory() {
+ if (sDataDirectory == null) {
+ sDataDirectory = RuntimeEnvironment.getTempDirectory().create("data");
+ }
+ return sDataDirectory.toFile();
+ }
+
+ /** Resets static state. */
+ @Resetter
+ public static void reset() {
+ org.robolectric.shadows.ShadowEnvironment.reset();
+ sDataDirectory = null;
+ }
+}
diff --git a/services/robotests/src/com/android/server/testing/shadows/ShadowInternalRecoveryServiceException.java b/services/robotests/src/com/android/server/testing/shadows/ShadowInternalRecoveryServiceException.java
deleted file mode 100644
index 9c06d81ce550..000000000000
--- a/services/robotests/src/com/android/server/testing/shadows/ShadowInternalRecoveryServiceException.java
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright (C) 2018 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.testing.shadows;
-
-import android.security.keystore.recovery.InternalRecoveryServiceException;
-
-import org.robolectric.annotation.Implementation;
-import org.robolectric.annotation.Implements;
-
-/** Shadow {@link InternalRecoveryServiceException}. */
-@Implements(InternalRecoveryServiceException.class)
-public class ShadowInternalRecoveryServiceException {
- private String mMessage;
-
- @Implementation
- public void __constructor__(String message) {
- mMessage = message;
- }
-
- @Implementation
- public void __constructor__(String message, Throwable cause) {
- mMessage = message;
- }
-
- @Implementation
- public String getMessage() {
- return mMessage;
- }
-}
diff --git a/services/robotests/src/com/android/server/testing/shadows/ShadowPerformUnifiedRestoreTask.java b/services/robotests/src/com/android/server/testing/shadows/ShadowPerformUnifiedRestoreTask.java
index 2cebbebfbaf4..8daef5fad032 100644
--- a/services/robotests/src/com/android/server/testing/shadows/ShadowPerformUnifiedRestoreTask.java
+++ b/services/robotests/src/com/android/server/testing/shadows/ShadowPerformUnifiedRestoreTask.java
@@ -29,6 +29,9 @@ import com.android.server.backup.transport.TransportClient;
import org.robolectric.annotation.Implementation;
import org.robolectric.annotation.Implements;
+import java.util.Map;
+import java.util.Set;
+
@Implements(PerformUnifiedRestoreTask.class)
public class ShadowPerformUnifiedRestoreTask {
@Nullable private static ShadowPerformUnifiedRestoreTask sLastShadow;
diff --git a/services/robotests/src/com/android/server/testing/shadows/ShadowRecoveryController.java b/services/robotests/src/com/android/server/testing/shadows/ShadowRecoveryController.java
deleted file mode 100644
index 7dad8a4e3ff3..000000000000
--- a/services/robotests/src/com/android/server/testing/shadows/ShadowRecoveryController.java
+++ /dev/null
@@ -1,152 +0,0 @@
-/*
- * Copyright (C) 2018 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.testing.shadows;
-
-import android.content.Context;
-import android.security.keystore.recovery.InternalRecoveryServiceException;
-import android.security.keystore.recovery.LockScreenRequiredException;
-import android.security.keystore.recovery.RecoveryController;
-
-import com.google.common.collect.ImmutableList;
-
-import org.robolectric.annotation.Implementation;
-import org.robolectric.annotation.Implements;
-import org.robolectric.annotation.Resetter;
-
-import java.lang.reflect.Constructor;
-import java.security.Key;
-import java.security.NoSuchAlgorithmException;
-import java.security.UnrecoverableKeyException;
-import java.util.HashMap;
-import java.util.List;
-
-import javax.crypto.KeyGenerator;
-
-/**
- * Shadow of {@link RecoveryController}.
- *
- * <p>Instead of generating keys via the {@link RecoveryController}, this shadow generates them in
- * memory.
- */
-@Implements(RecoveryController.class)
-public class ShadowRecoveryController {
- private static final String KEY_GENERATOR_ALGORITHM = "AES";
- private static final int KEY_SIZE_BITS = 256;
-
- private static boolean sIsSupported = true;
- private static boolean sThrowsInternalError = false;
- private static HashMap<String, Key> sKeysByAlias = new HashMap<>();
- private static HashMap<String, Integer> sKeyStatusesByAlias = new HashMap<>();
-
- @Implementation
- public void __constructor__() {
- // do not throw
- }
-
- @Implementation
- public static RecoveryController getInstance(Context context) {
- // Call non-public constructor.
- try {
- Constructor<RecoveryController> constructor = RecoveryController.class.getConstructor();
- return constructor.newInstance();
- } catch (Exception e) {
- throw new RuntimeException(e);
- }
- }
-
- @Implementation
- public static boolean isRecoverableKeyStoreEnabled(Context context) {
- return sIsSupported;
- }
-
- @Implementation
- public Key generateKey(String alias)
- throws InternalRecoveryServiceException, LockScreenRequiredException {
- maybeThrowError();
- KeyGenerator keyGenerator;
- try {
- keyGenerator = KeyGenerator.getInstance(KEY_GENERATOR_ALGORITHM);
- } catch (NoSuchAlgorithmException e) {
- // Should never happen
- throw new RuntimeException(e);
- }
-
- keyGenerator.init(KEY_SIZE_BITS);
- Key key = keyGenerator.generateKey();
- sKeysByAlias.put(alias, key);
- sKeyStatusesByAlias.put(alias, RecoveryController.RECOVERY_STATUS_SYNC_IN_PROGRESS);
- return key;
- }
-
- @Implementation
- public Key getKey(String alias)
- throws InternalRecoveryServiceException, UnrecoverableKeyException {
- return sKeysByAlias.get(alias);
- }
-
- @Implementation
- public void removeKey(String alias) throws InternalRecoveryServiceException {
- sKeyStatusesByAlias.remove(alias);
- sKeysByAlias.remove(alias);
- }
-
- @Implementation
- public int getRecoveryStatus(String alias) throws InternalRecoveryServiceException {
- maybeThrowError();
- return sKeyStatusesByAlias.getOrDefault(
- alias, RecoveryController.RECOVERY_STATUS_PERMANENT_FAILURE);
- }
-
- @Implementation
- public List<String> getAliases() throws InternalRecoveryServiceException {
- return ImmutableList.copyOf(sKeyStatusesByAlias.keySet());
- }
-
- private static void maybeThrowError() throws InternalRecoveryServiceException {
- if (sThrowsInternalError) {
- throw new InternalRecoveryServiceException("test error");
- }
- }
-
- /** Sets the recovery status of the key with {@code alias} to {@code status}. */
- public static void setRecoveryStatus(String alias, int status) {
- sKeyStatusesByAlias.put(alias, status);
- }
-
- /** Sets all existing keys to being synced. */
- public static void syncAllKeys() {
- for (String alias : sKeysByAlias.keySet()) {
- sKeyStatusesByAlias.put(alias, RecoveryController.RECOVERY_STATUS_SYNCED);
- }
- }
-
- public static void setThrowsInternalError(boolean throwsInternalError) {
- ShadowRecoveryController.sThrowsInternalError = throwsInternalError;
- }
-
- public static void setIsSupported(boolean isSupported) {
- ShadowRecoveryController.sIsSupported = isSupported;
- }
-
- @Resetter
- public static void reset() {
- sIsSupported = true;
- sThrowsInternalError = false;
- sKeysByAlias.clear();
- sKeyStatusesByAlias.clear();
- }
-}
diff --git a/services/robotests/src/com/android/server/testing/shadows/ShadowSystemServiceRegistry.java b/services/robotests/src/com/android/server/testing/shadows/ShadowSystemServiceRegistry.java
new file mode 100644
index 000000000000..c59798fc92fc
--- /dev/null
+++ b/services/robotests/src/com/android/server/testing/shadows/ShadowSystemServiceRegistry.java
@@ -0,0 +1,48 @@
+/*
+ * 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.testing.shadows;
+
+import android.app.SystemServiceRegistry;
+import android.app.job.JobSchedulerFrameworkInitializer;
+
+import org.robolectric.annotation.Implementation;
+import org.robolectric.annotation.Implements;
+import org.robolectric.util.ReflectionHelpers;
+
+/**
+ * Shadow of {@link SystemServiceRegistry}
+ *
+ * <p>JobSchedulerFrameworkInitializer contains a static initializer registering JobScheduler as a
+ * system service. We need to make sure the initializer is run before the tests that use
+ * JobScheduler. And we're putting this on the static initializer of SystemServiceRegistry since
+ * other services are registered here.
+ */
+@Implements(className = "android.app.SystemServiceRegistry")
+public class ShadowSystemServiceRegistry {
+ @Implementation
+ protected static void __staticInitializer__() {
+ // Make sure the static init in the real class is still executed.
+ ReflectionHelpers.callStaticMethod(SystemServiceRegistry.class, "__staticInitializer__");
+ try {
+ Class.forName(JobSchedulerFrameworkInitializer.class.getCanonicalName());
+ } catch (ClassNotFoundException e) {
+ // Rethrowing as an unchecked exception because checked exceptions are not allowed in
+ // static blocks.
+ throw new ExceptionInInitializerError(e);
+ }
+ }
+}
diff --git a/services/robotests/src/com/android/server/testing/shadows/ShadowUserManager.java b/services/robotests/src/com/android/server/testing/shadows/ShadowUserManager.java
new file mode 100644
index 000000000000..a9e4ee521f90
--- /dev/null
+++ b/services/robotests/src/com/android/server/testing/shadows/ShadowUserManager.java
@@ -0,0 +1,61 @@
+/*
+ * 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.testing.shadows;
+
+import android.annotation.NonNull;
+import android.annotation.UserIdInt;
+import android.os.UserManager;
+
+import org.robolectric.annotation.Implementation;
+import org.robolectric.annotation.Implements;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+/** Shadow for {@link UserManager}. */
+@Implements(UserManager.class)
+public class ShadowUserManager extends org.robolectric.shadows.ShadowUserManager {
+ private final Map<Integer, Set<Integer>> profileIds = new HashMap<>();
+
+ /** @see UserManager#isUserUnlocked() */
+ @Implementation
+ public boolean isUserUnlocked(@UserIdInt int userId) {
+ return false;
+ }
+
+ /** @see UserManager#getProfileIds(int, boolean) () */
+ @Implementation
+ @NonNull
+ public int[] getProfileIds(@UserIdInt int userId, boolean enabledOnly) {
+ // Currently, enabledOnly is ignored.
+ if (!profileIds.containsKey(userId)) {
+ return new int[] {userId};
+ }
+ return profileIds.get(userId).stream().mapToInt(Number::intValue).toArray();
+ }
+
+ /** Add a collection of profile IDs, all within the same profile group. */
+ public void addProfileIds(@UserIdInt int... userIds) {
+ final Set<Integer> profileGroup = new HashSet<>();
+ for (int userId : userIds) {
+ profileGroup.add(userId);
+ profileIds.put(userId, profileGroup);
+ }
+ }
+}