Merge "Binding on-demand #10: Remove permanent binding and add registration"
This commit is contained in:
committed by
Android (Google) Code Review
commit
931abbc249
@@ -207,6 +207,10 @@ public class RefactoredBackupManagerService implements BackupManagerServiceInter
|
||||
public static final String BACKUP_FINISHED_ACTION = "android.intent.action.BACKUP_FINISHED";
|
||||
public static final String BACKUP_FINISHED_PACKAGE_EXTRA = "packageName";
|
||||
|
||||
// Time delay for initialization operations that can be delayed so as not to consume too much CPU
|
||||
// on bring-up and increase time-to-UI.
|
||||
private static final long INITIALIZATION_DELAY_MILLIS = 3000;
|
||||
|
||||
// Timeout interval for deciding that a bind or clear-data has taken too long
|
||||
private static final long TIMEOUT_INTERVAL = 10 * 1000;
|
||||
|
||||
@@ -282,6 +286,9 @@ public class RefactoredBackupManagerService implements BackupManagerServiceInter
|
||||
|
||||
private final BackupPasswordManager mBackupPasswordManager;
|
||||
|
||||
// Time when we post the transport registration operation
|
||||
private final long mRegisterTransportsRequestedTime;
|
||||
|
||||
@GuardedBy("mPendingRestores")
|
||||
private boolean mIsRestoreInProgress;
|
||||
@GuardedBy("mPendingRestores")
|
||||
@@ -735,6 +742,9 @@ public class RefactoredBackupManagerService implements BackupManagerServiceInter
|
||||
// Set up our transport options and initialize the default transport
|
||||
SystemConfig systemConfig = SystemConfig.getInstance();
|
||||
Set<ComponentName> transportWhitelist = systemConfig.getBackupTransportWhitelist();
|
||||
if (transportWhitelist == null) {
|
||||
transportWhitelist = Collections.emptySet();
|
||||
}
|
||||
|
||||
String transport =
|
||||
Settings.Secure.getString(
|
||||
@@ -749,8 +759,7 @@ public class RefactoredBackupManagerService implements BackupManagerServiceInter
|
||||
new TransportManager(
|
||||
context,
|
||||
transportWhitelist,
|
||||
transport,
|
||||
backupThread.getLooper());
|
||||
transport);
|
||||
|
||||
// If encrypted file systems is enabled or disabled, this call will return the
|
||||
// correct directory.
|
||||
@@ -852,12 +861,14 @@ public class RefactoredBackupManagerService implements BackupManagerServiceInter
|
||||
}
|
||||
|
||||
mTransportManager = transportManager;
|
||||
mTransportManager.setTransportBoundListener(mTransportBoundListener);
|
||||
mTransportManager.registerAllTransports();
|
||||
mTransportManager.setOnTransportRegisteredListener(this::onTransportRegistered);
|
||||
mRegisterTransportsRequestedTime = SystemClock.elapsedRealtime();
|
||||
mBackupHandler.postDelayed(
|
||||
mTransportManager::registerTransports, INITIALIZATION_DELAY_MILLIS);
|
||||
|
||||
// Now that we know about valid backup participants, parse any
|
||||
// leftover journal files into the pending backup set
|
||||
mBackupHandler.post(this::parseLeftoverJournals);
|
||||
// Now that we know about valid backup participants, parse any leftover journal files into
|
||||
// the pending backup set
|
||||
mBackupHandler.postDelayed(this::parseLeftoverJournals, INITIALIZATION_DELAY_MILLIS);
|
||||
|
||||
// Power management
|
||||
mWakelock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "*backup*");
|
||||
@@ -1151,39 +1162,28 @@ public class RefactoredBackupManagerService implements BackupManagerServiceInter
|
||||
}
|
||||
}
|
||||
|
||||
private TransportManager.TransportBoundListener mTransportBoundListener =
|
||||
new TransportManager.TransportBoundListener() {
|
||||
@Override
|
||||
public boolean onTransportBound(IBackupTransport transport) {
|
||||
// If the init sentinel file exists, we need to be sure to perform the init
|
||||
// as soon as practical. We also create the state directory at registration
|
||||
// time to ensure it's present from the outset.
|
||||
String name = null;
|
||||
try {
|
||||
name = transport.name();
|
||||
String transportDirName = transport.transportDirName();
|
||||
File stateDir = new File(mBaseStateDir, transportDirName);
|
||||
stateDir.mkdirs();
|
||||
private void onTransportRegistered(String transportName, String transportDirName) {
|
||||
if (DEBUG) {
|
||||
long timeMs = SystemClock.elapsedRealtime() - mRegisterTransportsRequestedTime;
|
||||
Slog.d(TAG, "Transport " + transportName + " registered " + timeMs
|
||||
+ "ms after first request (delay = " + INITIALIZATION_DELAY_MILLIS + "ms)");
|
||||
}
|
||||
|
||||
File initSentinel = new File(stateDir, INIT_SENTINEL_FILE_NAME);
|
||||
if (initSentinel.exists()) {
|
||||
synchronized (mQueueLock) {
|
||||
mPendingInits.add(name);
|
||||
File stateDir = new File(mBaseStateDir, transportDirName);
|
||||
stateDir.mkdirs();
|
||||
|
||||
// TODO: pick a better starting time than now + 1 minute
|
||||
long delay = 1000 * 60; // one minute, in milliseconds
|
||||
mAlarmManager.set(AlarmManager.RTC_WAKEUP,
|
||||
System.currentTimeMillis() + delay, mRunInitIntent);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
// the transport threw when asked its file naming prefs; declare it invalid
|
||||
Slog.w(TAG, "Failed to regiser transport: " + name);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
};
|
||||
File initSentinel = new File(stateDir, INIT_SENTINEL_FILE_NAME);
|
||||
if (initSentinel.exists()) {
|
||||
synchronized (mQueueLock) {
|
||||
mPendingInits.add(transportName);
|
||||
|
||||
// TODO: pick a better starting time than now + 1 minute
|
||||
long delay = 1000 * 60; // one minute, in milliseconds
|
||||
mAlarmManager.set(AlarmManager.RTC_WAKEUP,
|
||||
System.currentTimeMillis() + delay, mRunInitIntent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ----- Track installation/removal of packages -----
|
||||
private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
|
||||
@@ -2891,14 +2891,14 @@ public class RefactoredBackupManagerService implements BackupManagerServiceInter
|
||||
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
|
||||
"listAllTransports");
|
||||
|
||||
return mTransportManager.getBoundTransportNames();
|
||||
return mTransportManager.getRegisteredTransportNames();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ComponentName[] listAllTransportComponents() {
|
||||
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
|
||||
"listAllTransportComponents");
|
||||
return mTransportManager.getAllTransportComponents();
|
||||
return mTransportManager.getRegisteredTransportComponents();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -3003,6 +3003,8 @@ public class RefactoredBackupManagerService implements BackupManagerServiceInter
|
||||
|
||||
/** Selects transport {@code transportName} and returns previous selected transport. */
|
||||
@Override
|
||||
@Deprecated
|
||||
@Nullable
|
||||
public String selectBackupTransport(String transportName) {
|
||||
mContext.enforceCallingOrSelfPermission(
|
||||
android.Manifest.permission.BACKUP, "selectBackupTransport");
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* 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.transport;
|
||||
|
||||
import com.android.server.backup.TransportManager;
|
||||
|
||||
/**
|
||||
* Listener called when a transport is registered with the {@link TransportManager}. Can be set
|
||||
* using {@link TransportManager#setOnTransportRegisteredListener(OnTransportRegisteredListener)}.
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface OnTransportRegisteredListener {
|
||||
/**
|
||||
* Called when a transport is successfully registered.
|
||||
* @param transportName The name of the transport.
|
||||
* @param transportDirName The dir name of the transport.
|
||||
*/
|
||||
public void onTransportRegistered(String transportName, String transportDirName);
|
||||
}
|
||||
@@ -236,7 +236,7 @@ public class TransportClient {
|
||||
mBindIntent,
|
||||
mConnection,
|
||||
Context.BIND_AUTO_CREATE,
|
||||
TransportManager.createSystemUserHandle());
|
||||
UserHandle.SYSTEM);
|
||||
if (hasBound) {
|
||||
// We don't need to set a time-out because we are guaranteed to get a call
|
||||
// back in ServiceConnection, either an onServiceConnected() or
|
||||
|
||||
@@ -16,7 +16,11 @@
|
||||
|
||||
package com.android.server.backup;
|
||||
|
||||
import static com.android.server.backup.testing.TransportTestUtils.TRANSPORT_NAMES;
|
||||
import static com.android.server.backup.testing.TransportData.backupTransport;
|
||||
import static com.android.server.backup.testing.TransportData.d2dTransport;
|
||||
import static com.android.server.backup.testing.TransportData.localTransport;
|
||||
import static com.android.server.backup.testing.TransportTestUtils.setUpCurrentTransport;
|
||||
import static com.android.server.backup.testing.TransportTestUtils.setUpTransports;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
@@ -24,6 +28,7 @@ import static org.mockito.ArgumentMatchers.any;
|
||||
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.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
import static org.robolectric.Shadows.shadowOf;
|
||||
@@ -39,8 +44,8 @@ import android.platform.test.annotations.Presubmit;
|
||||
import android.provider.Settings;
|
||||
|
||||
import com.android.server.backup.testing.ShadowAppBackupUtils;
|
||||
import com.android.server.backup.testing.TransportTestUtils;
|
||||
import com.android.server.backup.testing.TransportTestUtils.TransportData;
|
||||
import com.android.server.backup.testing.TransportData;
|
||||
import com.android.server.backup.testing.TransportTestUtils.TransportMock;
|
||||
import com.android.server.backup.transport.TransportNotRegisteredException;
|
||||
import com.android.server.testing.FrameworkRobolectricTestRunner;
|
||||
import com.android.server.testing.SystemLoaderClasses;
|
||||
@@ -57,10 +62,10 @@ import org.robolectric.shadows.ShadowContextWrapper;
|
||||
import org.robolectric.shadows.ShadowLog;
|
||||
import org.robolectric.shadows.ShadowLooper;
|
||||
import org.robolectric.shadows.ShadowSettings;
|
||||
import org.robolectric.shadows.ShadowSystemClock;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@RunWith(FrameworkRobolectricTestRunner.class)
|
||||
@@ -73,22 +78,24 @@ import java.util.Map;
|
||||
@Presubmit
|
||||
public class BackupManagerServiceRoboTest {
|
||||
private static final String TAG = "BMSTest";
|
||||
private static final String TRANSPORT_NAME =
|
||||
"com.google.android.gms/.backup.BackupTransportService";
|
||||
|
||||
@Mock private TransportManager mTransportManager;
|
||||
private HandlerThread mBackupThread;
|
||||
private ShadowLooper mShadowBackupLooper;
|
||||
private File mBaseStateDir;
|
||||
private File mDataDir;
|
||||
private RefactoredBackupManagerService mBackupManagerService;
|
||||
private ShadowContextWrapper mShadowContext;
|
||||
private Context mContext;
|
||||
private TransportData mTransport;
|
||||
private String mTransportName;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
|
||||
mTransport = backupTransport();
|
||||
mTransportName = mTransport.transportName;
|
||||
|
||||
mBackupThread = new HandlerThread("backup-test");
|
||||
mBackupThread.setUncaughtExceptionHandler(
|
||||
(t, e) -> ShadowLog.e(TAG, "Uncaught exception in test thread " + t.getName(), e));
|
||||
@@ -102,15 +109,6 @@ public class BackupManagerServiceRoboTest {
|
||||
File cacheDir = mContext.getCacheDir();
|
||||
mBaseStateDir = new File(cacheDir, "base_state_dir");
|
||||
mDataDir = new File(cacheDir, "data_dir");
|
||||
|
||||
mBackupManagerService =
|
||||
new RefactoredBackupManagerService(
|
||||
mContext,
|
||||
new Trampoline(mContext),
|
||||
mBackupThread,
|
||||
mBaseStateDir,
|
||||
mDataDir,
|
||||
mTransportManager);
|
||||
}
|
||||
|
||||
@After
|
||||
@@ -124,10 +122,12 @@ public class BackupManagerServiceRoboTest {
|
||||
@Test
|
||||
public void testDestinationString() throws Exception {
|
||||
mShadowContext.grantPermissions(android.Manifest.permission.BACKUP);
|
||||
when(mTransportManager.getTransportCurrentDestinationString(eq(TRANSPORT_NAME)))
|
||||
when(mTransportManager.getTransportCurrentDestinationString(eq(mTransportName)))
|
||||
.thenReturn("destinationString");
|
||||
RefactoredBackupManagerService backupManagerService =
|
||||
createInitializedBackupManagerService();
|
||||
|
||||
String destination = mBackupManagerService.getDestinationString(TRANSPORT_NAME);
|
||||
String destination = backupManagerService.getDestinationString(mTransportName);
|
||||
|
||||
assertThat(destination).isEqualTo("destinationString");
|
||||
}
|
||||
@@ -135,10 +135,12 @@ public class BackupManagerServiceRoboTest {
|
||||
@Test
|
||||
public void testDestinationString_whenTransportNotRegistered() throws Exception {
|
||||
mShadowContext.grantPermissions(android.Manifest.permission.BACKUP);
|
||||
when(mTransportManager.getTransportCurrentDestinationString(eq(TRANSPORT_NAME)))
|
||||
when(mTransportManager.getTransportCurrentDestinationString(eq(mTransportName)))
|
||||
.thenThrow(TransportNotRegisteredException.class);
|
||||
RefactoredBackupManagerService backupManagerService =
|
||||
createInitializedBackupManagerService();
|
||||
|
||||
String destination = mBackupManagerService.getDestinationString(TRANSPORT_NAME);
|
||||
String destination = backupManagerService.getDestinationString(mTransportName);
|
||||
|
||||
assertThat(destination).isNull();
|
||||
}
|
||||
@@ -146,12 +148,14 @@ public class BackupManagerServiceRoboTest {
|
||||
@Test
|
||||
public void testDestinationString_withoutPermission() throws Exception {
|
||||
mShadowContext.denyPermissions(android.Manifest.permission.BACKUP);
|
||||
when(mTransportManager.getTransportCurrentDestinationString(eq(TRANSPORT_NAME)))
|
||||
when(mTransportManager.getTransportCurrentDestinationString(eq(mTransportName)))
|
||||
.thenThrow(TransportNotRegisteredException.class);
|
||||
RefactoredBackupManagerService backupManagerService =
|
||||
createInitializedBackupManagerService();
|
||||
|
||||
expectThrows(
|
||||
SecurityException.class,
|
||||
() -> mBackupManagerService.getDestinationString(TRANSPORT_NAME));
|
||||
() -> backupManagerService.getDestinationString(mTransportName));
|
||||
}
|
||||
|
||||
/* Tests for app eligibility */
|
||||
@@ -159,24 +163,28 @@ public class BackupManagerServiceRoboTest {
|
||||
@Test
|
||||
public void testIsAppEligibleForBackup_whenAppEligible() throws Exception {
|
||||
mShadowContext.grantPermissions(android.Manifest.permission.BACKUP);
|
||||
TransportData transport =
|
||||
TransportTestUtils.setUpCurrentTransport(mTransportManager, TRANSPORT_NAME);
|
||||
TransportMock transportMock = setUpCurrentTransport(mTransportManager, backupTransport());
|
||||
ShadowAppBackupUtils.sAppIsRunningAndEligibleForBackupWithTransport = p -> true;
|
||||
RefactoredBackupManagerService backupManagerService =
|
||||
createInitializedBackupManagerService();
|
||||
|
||||
boolean result = mBackupManagerService.isAppEligibleForBackup("app.package");
|
||||
boolean result = backupManagerService.isAppEligibleForBackup("app.package");
|
||||
|
||||
assertThat(result).isTrue();
|
||||
|
||||
verify(mTransportManager)
|
||||
.disposeOfTransportClient(eq(transport.transportClientMock), any());
|
||||
.disposeOfTransportClient(eq(transportMock.transportClient), any());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsAppEligibleForBackup_whenAppNotEligible() throws Exception {
|
||||
mShadowContext.grantPermissions(android.Manifest.permission.BACKUP);
|
||||
TransportTestUtils.setUpCurrentTransport(mTransportManager, TRANSPORT_NAME);
|
||||
setUpCurrentTransport(mTransportManager, mTransport);
|
||||
ShadowAppBackupUtils.sAppIsRunningAndEligibleForBackupWithTransport = p -> false;
|
||||
RefactoredBackupManagerService backupManagerService =
|
||||
createInitializedBackupManagerService();
|
||||
|
||||
boolean result = mBackupManagerService.isAppEligibleForBackup("app.package");
|
||||
boolean result = backupManagerService.isAppEligibleForBackup("app.package");
|
||||
|
||||
assertThat(result).isFalse();
|
||||
}
|
||||
@@ -184,38 +192,43 @@ public class BackupManagerServiceRoboTest {
|
||||
@Test
|
||||
public void testIsAppEligibleForBackup_withoutPermission() throws Exception {
|
||||
mShadowContext.denyPermissions(android.Manifest.permission.BACKUP);
|
||||
TransportTestUtils.setUpCurrentTransport(mTransportManager, TRANSPORT_NAME);
|
||||
setUpCurrentTransport(mTransportManager, mTransport);
|
||||
RefactoredBackupManagerService backupManagerService =
|
||||
createInitializedBackupManagerService();
|
||||
|
||||
expectThrows(
|
||||
SecurityException.class,
|
||||
() -> mBackupManagerService.isAppEligibleForBackup("app.package"));
|
||||
() -> backupManagerService.isAppEligibleForBackup("app.package"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFilterAppsEligibleForBackup() throws Exception {
|
||||
mShadowContext.grantPermissions(android.Manifest.permission.BACKUP);
|
||||
TransportData transport =
|
||||
TransportTestUtils.setUpCurrentTransport(mTransportManager, TRANSPORT_NAME);
|
||||
TransportMock transportMock = setUpCurrentTransport(mTransportManager, mTransport);
|
||||
Map<String, Boolean> packagesMap = new HashMap<>();
|
||||
packagesMap.put("package.a", true);
|
||||
packagesMap.put("package.b", false);
|
||||
ShadowAppBackupUtils.sAppIsRunningAndEligibleForBackupWithTransport = packagesMap::get;
|
||||
RefactoredBackupManagerService backupManagerService =
|
||||
createInitializedBackupManagerService();
|
||||
String[] packages = packagesMap.keySet().toArray(new String[packagesMap.size()]);
|
||||
|
||||
String[] filtered = mBackupManagerService.filterAppsEligibleForBackup(packages);
|
||||
String[] filtered = backupManagerService.filterAppsEligibleForBackup(packages);
|
||||
|
||||
assertThat(filtered).asList().containsExactly("package.a");
|
||||
verify(mTransportManager)
|
||||
.disposeOfTransportClient(eq(transport.transportClientMock), any());
|
||||
.disposeOfTransportClient(eq(transportMock.transportClient), any());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFilterAppsEligibleForBackup_whenNoneIsEligible() throws Exception {
|
||||
mShadowContext.grantPermissions(android.Manifest.permission.BACKUP);
|
||||
ShadowAppBackupUtils.sAppIsRunningAndEligibleForBackupWithTransport = p -> false;
|
||||
RefactoredBackupManagerService backupManagerService =
|
||||
createInitializedBackupManagerService();
|
||||
|
||||
String[] filtered =
|
||||
mBackupManagerService.filterAppsEligibleForBackup(
|
||||
backupManagerService.filterAppsEligibleForBackup(
|
||||
new String[] {"package.a", "package.b"});
|
||||
|
||||
assertThat(filtered).isEmpty();
|
||||
@@ -224,12 +237,14 @@ public class BackupManagerServiceRoboTest {
|
||||
@Test
|
||||
public void testFilterAppsEligibleForBackup_withoutPermission() throws Exception {
|
||||
mShadowContext.denyPermissions(android.Manifest.permission.BACKUP);
|
||||
TransportTestUtils.setUpCurrentTransport(mTransportManager, TRANSPORT_NAME);
|
||||
setUpCurrentTransport(mTransportManager, mTransport);
|
||||
RefactoredBackupManagerService backupManagerService =
|
||||
createInitializedBackupManagerService();
|
||||
|
||||
expectThrows(
|
||||
SecurityException.class,
|
||||
() ->
|
||||
mBackupManagerService.filterAppsEligibleForBackup(
|
||||
backupManagerService.filterAppsEligibleForBackup(
|
||||
new String[] {"package.a", "package.b"}));
|
||||
}
|
||||
|
||||
@@ -238,14 +253,12 @@ public class BackupManagerServiceRoboTest {
|
||||
private TransportData mNewTransport;
|
||||
private TransportData mOldTransport;
|
||||
private ComponentName mNewTransportComponent;
|
||||
private ISelectBackupTransportCallback mCallback;
|
||||
|
||||
private void setUpForSelectTransport() throws Exception {
|
||||
List<TransportData> transports =
|
||||
TransportTestUtils.setUpTransports(mTransportManager, TRANSPORT_NAMES);
|
||||
mNewTransport = transports.get(0);
|
||||
mNewTransportComponent = mNewTransport.transportClientMock.getTransportComponent();
|
||||
mOldTransport = transports.get(1);
|
||||
mNewTransport = backupTransport();
|
||||
mNewTransportComponent = mNewTransport.getTransportComponent();
|
||||
mOldTransport = d2dTransport();
|
||||
setUpTransports(mTransportManager, mNewTransport, mOldTransport, localTransport());
|
||||
when(mTransportManager.selectTransport(eq(mNewTransport.transportName)))
|
||||
.thenReturn(mOldTransport.transportName);
|
||||
}
|
||||
@@ -254,9 +267,11 @@ public class BackupManagerServiceRoboTest {
|
||||
public void testSelectBackupTransport() throws Exception {
|
||||
setUpForSelectTransport();
|
||||
mShadowContext.grantPermissions(android.Manifest.permission.BACKUP);
|
||||
RefactoredBackupManagerService backupManagerService =
|
||||
createInitializedBackupManagerService();
|
||||
|
||||
String oldTransport =
|
||||
mBackupManagerService.selectBackupTransport(mNewTransport.transportName);
|
||||
backupManagerService.selectBackupTransport(mNewTransport.transportName);
|
||||
|
||||
assertThat(getSettingsTransport()).isEqualTo(mNewTransport.transportName);
|
||||
assertThat(oldTransport).isEqualTo(mOldTransport.transportName);
|
||||
@@ -266,10 +281,12 @@ public class BackupManagerServiceRoboTest {
|
||||
public void testSelectBackupTransport_withoutPermission() throws Exception {
|
||||
setUpForSelectTransport();
|
||||
mShadowContext.denyPermissions(android.Manifest.permission.BACKUP);
|
||||
RefactoredBackupManagerService backupManagerService =
|
||||
createInitializedBackupManagerService();
|
||||
|
||||
expectThrows(
|
||||
SecurityException.class,
|
||||
() -> mBackupManagerService.selectBackupTransport(mNewTransport.transportName));
|
||||
() -> backupManagerService.selectBackupTransport(mNewTransport.transportName));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -278,9 +295,11 @@ public class BackupManagerServiceRoboTest {
|
||||
mShadowContext.grantPermissions(android.Manifest.permission.BACKUP);
|
||||
when(mTransportManager.registerAndSelectTransport(eq(mNewTransportComponent)))
|
||||
.thenReturn(BackupManager.SUCCESS);
|
||||
RefactoredBackupManagerService backupManagerService =
|
||||
createInitializedBackupManagerService();
|
||||
ISelectBackupTransportCallback callback = mock(ISelectBackupTransportCallback.class);
|
||||
|
||||
mBackupManagerService.selectBackupTransportAsync(mNewTransportComponent, callback);
|
||||
backupManagerService.selectBackupTransportAsync(mNewTransportComponent, callback);
|
||||
|
||||
mShadowBackupLooper.runToEndOfTasks();
|
||||
assertThat(getSettingsTransport()).isEqualTo(mNewTransport.transportName);
|
||||
@@ -293,9 +312,11 @@ public class BackupManagerServiceRoboTest {
|
||||
mShadowContext.grantPermissions(android.Manifest.permission.BACKUP);
|
||||
when(mTransportManager.registerAndSelectTransport(eq(mNewTransportComponent)))
|
||||
.thenReturn(BackupManager.ERROR_TRANSPORT_UNAVAILABLE);
|
||||
RefactoredBackupManagerService backupManagerService =
|
||||
createInitializedBackupManagerService();
|
||||
ISelectBackupTransportCallback callback = mock(ISelectBackupTransportCallback.class);
|
||||
|
||||
mBackupManagerService.selectBackupTransportAsync(mNewTransportComponent, callback);
|
||||
backupManagerService.selectBackupTransportAsync(mNewTransportComponent, callback);
|
||||
|
||||
mShadowBackupLooper.runToEndOfTasks();
|
||||
assertThat(getSettingsTransport()).isNotEqualTo(mNewTransport.transportName);
|
||||
@@ -304,19 +325,19 @@ public class BackupManagerServiceRoboTest {
|
||||
|
||||
@Test
|
||||
public void testSelectBackupTransportAsync_whenTransportGetsUnregistered() throws Exception {
|
||||
TransportTestUtils.setUpTransports(
|
||||
mTransportManager, new TransportData(TRANSPORT_NAME, null, null));
|
||||
ComponentName newTransportComponent =
|
||||
TransportTestUtils.transportComponentName(TRANSPORT_NAME);
|
||||
setUpTransports(mTransportManager, mTransport.unregistered());
|
||||
ComponentName newTransportComponent = mTransport.getTransportComponent();
|
||||
mShadowContext.grantPermissions(android.Manifest.permission.BACKUP);
|
||||
when(mTransportManager.registerAndSelectTransport(eq(newTransportComponent)))
|
||||
.thenReturn(BackupManager.SUCCESS);
|
||||
RefactoredBackupManagerService backupManagerService =
|
||||
createInitializedBackupManagerService();
|
||||
ISelectBackupTransportCallback callback = mock(ISelectBackupTransportCallback.class);
|
||||
|
||||
mBackupManagerService.selectBackupTransportAsync(newTransportComponent, callback);
|
||||
backupManagerService.selectBackupTransportAsync(newTransportComponent, callback);
|
||||
|
||||
mShadowBackupLooper.runToEndOfTasks();
|
||||
assertThat(getSettingsTransport()).isNotEqualTo(TRANSPORT_NAME);
|
||||
assertThat(getSettingsTransport()).isNotEqualTo(mTransportName);
|
||||
verify(callback).onFailure(anyInt());
|
||||
}
|
||||
|
||||
@@ -324,13 +345,14 @@ public class BackupManagerServiceRoboTest {
|
||||
public void testSelectBackupTransportAsync_withoutPermission() throws Exception {
|
||||
setUpForSelectTransport();
|
||||
mShadowContext.denyPermissions(android.Manifest.permission.BACKUP);
|
||||
ComponentName newTransportComponent =
|
||||
mNewTransport.transportClientMock.getTransportComponent();
|
||||
RefactoredBackupManagerService backupManagerService =
|
||||
createInitializedBackupManagerService();
|
||||
ComponentName newTransportComponent = mNewTransport.getTransportComponent();
|
||||
|
||||
expectThrows(
|
||||
SecurityException.class,
|
||||
() ->
|
||||
mBackupManagerService.selectBackupTransportAsync(
|
||||
backupManagerService.selectBackupTransportAsync(
|
||||
newTransportComponent, mock(ISelectBackupTransportCallback.class)));
|
||||
}
|
||||
|
||||
@@ -338,4 +360,55 @@ public class BackupManagerServiceRoboTest {
|
||||
return ShadowSettings.ShadowSecure.getString(
|
||||
mContext.getContentResolver(), Settings.Secure.BACKUP_TRANSPORT);
|
||||
}
|
||||
|
||||
/* Miscellaneous tests */
|
||||
|
||||
@Test
|
||||
public void testConstructor_postRegisterTransports() {
|
||||
mShadowContext.grantPermissions(android.Manifest.permission.BACKUP);
|
||||
|
||||
createBackupManagerService();
|
||||
|
||||
mShadowBackupLooper.runToEndOfTasks();
|
||||
verify(mTransportManager).registerTransports();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConstructor_doesNotRegisterTransportsSynchronously() {
|
||||
mShadowContext.grantPermissions(android.Manifest.permission.BACKUP);
|
||||
|
||||
createBackupManagerService();
|
||||
|
||||
// Operations posted to mBackupThread only run with mShadowBackupLooper.runToEndOfTasks()
|
||||
verify(mTransportManager, never()).registerTransports();
|
||||
}
|
||||
|
||||
private RefactoredBackupManagerService createBackupManagerService() {
|
||||
return new RefactoredBackupManagerService(
|
||||
mContext,
|
||||
new Trampoline(mContext),
|
||||
mBackupThread,
|
||||
mBaseStateDir,
|
||||
mDataDir,
|
||||
mTransportManager);
|
||||
}
|
||||
|
||||
private RefactoredBackupManagerService createInitializedBackupManagerService() {
|
||||
RefactoredBackupManagerService backupManagerService =
|
||||
new RefactoredBackupManagerService(
|
||||
mContext,
|
||||
new Trampoline(mContext),
|
||||
mBackupThread,
|
||||
mBaseStateDir,
|
||||
mDataDir,
|
||||
mTransportManager);
|
||||
mShadowBackupLooper.runToEndOfTasks();
|
||||
// Handler instances have their own clock, so advancing looper (with runToEndOfTasks())
|
||||
// above does NOT advance the handlers' clock, hence whenever a handler post messages with
|
||||
// specific time to the looper the time of those messages will be before the looper's time.
|
||||
// To fix this we advance SystemClock as well since that is from where the handlers read
|
||||
// time.
|
||||
ShadowSystemClock.setCurrentTimeMillis(mShadowBackupLooper.getScheduler().getCurrentTime());
|
||||
return backupManagerService;
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -19,8 +19,10 @@ package com.android.server.backup.internal;
|
||||
import static android.app.backup.BackupTransport.TRANSPORT_ERROR;
|
||||
import static android.app.backup.BackupTransport.TRANSPORT_OK;
|
||||
|
||||
import static com.android.server.backup.testing.TransportTestUtils.TRANSPORT_NAME;
|
||||
import static com.android.server.backup.testing.TransportTestUtils.TRANSPORT_NAMES;
|
||||
import static com.android.server.backup.testing.TransportData.backupTransport;
|
||||
import static com.android.server.backup.testing.TransportData.d2dTransport;
|
||||
import static com.android.server.backup.testing.TransportData.localTransport;
|
||||
import static com.android.server.backup.testing.TransportTestUtils.setUpTransports;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
@@ -28,7 +30,6 @@ import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyInt;
|
||||
import static org.mockito.ArgumentMatchers.anyLong;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
@@ -44,7 +45,8 @@ import com.android.internal.backup.IBackupTransport;
|
||||
import com.android.server.backup.RefactoredBackupManagerService;
|
||||
import com.android.server.backup.TransportManager;
|
||||
import com.android.server.backup.testing.TransportTestUtils;
|
||||
import com.android.server.backup.testing.TransportTestUtils.TransportData;
|
||||
import com.android.server.backup.testing.TransportData;
|
||||
import com.android.server.backup.testing.TransportTestUtils.TransportMock;
|
||||
import com.android.server.backup.transport.TransportClient;
|
||||
import com.android.server.testing.FrameworkRobolectricTestRunner;
|
||||
import com.android.server.testing.SystemLoaderClasses;
|
||||
@@ -58,7 +60,10 @@ import org.robolectric.RuntimeEnvironment;
|
||||
import org.robolectric.annotation.Config;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Arrays;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
@RunWith(FrameworkRobolectricTestRunner.class)
|
||||
@Config(manifest = Config.NONE, sdk = 26)
|
||||
@@ -68,16 +73,21 @@ public class PerformInitializeTaskTest {
|
||||
@Mock private RefactoredBackupManagerService mBackupManagerService;
|
||||
@Mock private TransportManager mTransportManager;
|
||||
@Mock private OnTaskFinishedListener mListener;
|
||||
@Mock private IBackupTransport mTransport;
|
||||
@Mock private IBackupTransport mTransportBinder;
|
||||
@Mock private IBackupObserver mObserver;
|
||||
@Mock private AlarmManager mAlarmManager;
|
||||
@Mock private PendingIntent mRunInitIntent;
|
||||
private File mBaseStateDir;
|
||||
private TransportData mTransport;
|
||||
private String mTransportName;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
|
||||
mTransport = backupTransport();
|
||||
mTransportName = mTransport.transportName;
|
||||
|
||||
Application context = RuntimeEnvironment.application;
|
||||
mBaseStateDir = new File(context.getCacheDir(), "base_state_dir");
|
||||
assertThat(mBaseStateDir.mkdir()).isTrue();
|
||||
@@ -88,82 +98,76 @@ public class PerformInitializeTaskTest {
|
||||
|
||||
@Test
|
||||
public void testRun_callsTransportCorrectly() throws Exception {
|
||||
setUpTransport(TRANSPORT_NAME);
|
||||
configureTransport(mTransport, TRANSPORT_OK, TRANSPORT_OK);
|
||||
PerformInitializeTask performInitializeTask = createPerformInitializeTask(TRANSPORT_NAME);
|
||||
setUpTransport(mTransport);
|
||||
configureTransport(mTransportBinder, TRANSPORT_OK, TRANSPORT_OK);
|
||||
PerformInitializeTask performInitializeTask = createPerformInitializeTask(mTransportName);
|
||||
|
||||
performInitializeTask.run();
|
||||
|
||||
verify(mTransport).initializeDevice();
|
||||
verify(mTransport).finishBackup();
|
||||
verify(mTransportBinder).initializeDevice();
|
||||
verify(mTransportBinder).finishBackup();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRun_callsBackupManagerCorrectly() throws Exception {
|
||||
setUpTransport(TRANSPORT_NAME);
|
||||
configureTransport(mTransport, TRANSPORT_OK, TRANSPORT_OK);
|
||||
PerformInitializeTask performInitializeTask = createPerformInitializeTask(TRANSPORT_NAME);
|
||||
setUpTransport(mTransport);
|
||||
configureTransport(mTransportBinder, TRANSPORT_OK, TRANSPORT_OK);
|
||||
PerformInitializeTask performInitializeTask = createPerformInitializeTask(mTransportName);
|
||||
|
||||
performInitializeTask.run();
|
||||
|
||||
verify(mBackupManagerService)
|
||||
.recordInitPending(
|
||||
false, TRANSPORT_NAME, TransportTestUtils.transportDirName(TRANSPORT_NAME));
|
||||
.recordInitPending(false, mTransportName, mTransport.transportDirName);
|
||||
verify(mBackupManagerService)
|
||||
.resetBackupState(
|
||||
eq(
|
||||
new File(
|
||||
mBaseStateDir,
|
||||
TransportTestUtils.transportDirName(TRANSPORT_NAME))));
|
||||
.resetBackupState(eq(new File(mBaseStateDir, mTransport.transportDirName)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRun_callsObserverAndListenerCorrectly() throws Exception {
|
||||
setUpTransport(TRANSPORT_NAME);
|
||||
configureTransport(mTransport, TRANSPORT_OK, TRANSPORT_OK);
|
||||
PerformInitializeTask performInitializeTask = createPerformInitializeTask(TRANSPORT_NAME);
|
||||
setUpTransport(mTransport);
|
||||
configureTransport(mTransportBinder, TRANSPORT_OK, TRANSPORT_OK);
|
||||
PerformInitializeTask performInitializeTask = createPerformInitializeTask(mTransportName);
|
||||
|
||||
performInitializeTask.run();
|
||||
|
||||
verify(mObserver).onResult(eq(TRANSPORT_NAME), eq(TRANSPORT_OK));
|
||||
verify(mObserver).onResult(eq(mTransportName), eq(TRANSPORT_OK));
|
||||
verify(mObserver).backupFinished(eq(TRANSPORT_OK));
|
||||
verify(mListener).onFinished(any());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRun_whenInitializeDeviceFails() throws Exception {
|
||||
setUpTransport(TRANSPORT_NAME);
|
||||
configureTransport(mTransport, TRANSPORT_ERROR, 0);
|
||||
PerformInitializeTask performInitializeTask = createPerformInitializeTask(TRANSPORT_NAME);
|
||||
setUpTransport(mTransport);
|
||||
configureTransport(mTransportBinder, TRANSPORT_ERROR, 0);
|
||||
PerformInitializeTask performInitializeTask = createPerformInitializeTask(mTransportName);
|
||||
|
||||
performInitializeTask.run();
|
||||
|
||||
verify(mTransport).initializeDevice();
|
||||
verify(mTransport, never()).finishBackup();
|
||||
verify(mTransportBinder).initializeDevice();
|
||||
verify(mTransportBinder, never()).finishBackup();
|
||||
verify(mBackupManagerService)
|
||||
.recordInitPending(
|
||||
true, TRANSPORT_NAME, TransportTestUtils.transportDirName(TRANSPORT_NAME));
|
||||
.recordInitPending(true, mTransportName, mTransport.transportDirName);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRun_whenInitializeDeviceFails_callsObserverAndListenerCorrectly()
|
||||
throws Exception {
|
||||
setUpTransport(TRANSPORT_NAME);
|
||||
configureTransport(mTransport, TRANSPORT_ERROR, 0);
|
||||
PerformInitializeTask performInitializeTask = createPerformInitializeTask(TRANSPORT_NAME);
|
||||
setUpTransport(mTransport);
|
||||
configureTransport(mTransportBinder, TRANSPORT_ERROR, 0);
|
||||
PerformInitializeTask performInitializeTask = createPerformInitializeTask(mTransportName);
|
||||
|
||||
performInitializeTask.run();
|
||||
|
||||
verify(mObserver).onResult(eq(TRANSPORT_NAME), eq(TRANSPORT_ERROR));
|
||||
verify(mObserver).onResult(eq(mTransportName), eq(TRANSPORT_ERROR));
|
||||
verify(mObserver).backupFinished(eq(TRANSPORT_ERROR));
|
||||
verify(mListener).onFinished(any());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRun_whenInitializeDeviceFails_schedulesAlarm() throws Exception {
|
||||
setUpTransport(TRANSPORT_NAME);
|
||||
configureTransport(mTransport, TRANSPORT_ERROR, 0);
|
||||
PerformInitializeTask performInitializeTask = createPerformInitializeTask(TRANSPORT_NAME);
|
||||
setUpTransport(mTransport);
|
||||
configureTransport(mTransportBinder, TRANSPORT_ERROR, 0);
|
||||
PerformInitializeTask performInitializeTask = createPerformInitializeTask(mTransportName);
|
||||
|
||||
performInitializeTask.run();
|
||||
|
||||
@@ -172,37 +176,36 @@ public class PerformInitializeTaskTest {
|
||||
|
||||
@Test
|
||||
public void testRun_whenFinishBackupFails() throws Exception {
|
||||
setUpTransport(TRANSPORT_NAME);
|
||||
configureTransport(mTransport, TRANSPORT_OK, TRANSPORT_ERROR);
|
||||
PerformInitializeTask performInitializeTask = createPerformInitializeTask(TRANSPORT_NAME);
|
||||
setUpTransport(mTransport);
|
||||
configureTransport(mTransportBinder, TRANSPORT_OK, TRANSPORT_ERROR);
|
||||
PerformInitializeTask performInitializeTask = createPerformInitializeTask(mTransportName);
|
||||
|
||||
performInitializeTask.run();
|
||||
|
||||
verify(mTransport).initializeDevice();
|
||||
verify(mTransport).finishBackup();
|
||||
verify(mTransportBinder).initializeDevice();
|
||||
verify(mTransportBinder).finishBackup();
|
||||
verify(mBackupManagerService)
|
||||
.recordInitPending(
|
||||
true, TRANSPORT_NAME, TransportTestUtils.transportDirName(TRANSPORT_NAME));
|
||||
.recordInitPending(true, mTransportName, mTransport.transportDirName);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRun_whenFinishBackupFails_callsObserverAndListenerCorrectly() throws Exception {
|
||||
setUpTransport(TRANSPORT_NAME);
|
||||
configureTransport(mTransport, TRANSPORT_OK, TRANSPORT_ERROR);
|
||||
PerformInitializeTask performInitializeTask = createPerformInitializeTask(TRANSPORT_NAME);
|
||||
setUpTransport(mTransport);
|
||||
configureTransport(mTransportBinder, TRANSPORT_OK, TRANSPORT_ERROR);
|
||||
PerformInitializeTask performInitializeTask = createPerformInitializeTask(mTransportName);
|
||||
|
||||
performInitializeTask.run();
|
||||
|
||||
verify(mObserver).onResult(eq(TRANSPORT_NAME), eq(TRANSPORT_ERROR));
|
||||
verify(mObserver).onResult(eq(mTransportName), eq(TRANSPORT_ERROR));
|
||||
verify(mObserver).backupFinished(eq(TRANSPORT_ERROR));
|
||||
verify(mListener).onFinished(any());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRun_whenFinishBackupFails_schedulesAlarm() throws Exception {
|
||||
setUpTransport(TRANSPORT_NAME);
|
||||
configureTransport(mTransport, TRANSPORT_OK, TRANSPORT_ERROR);
|
||||
PerformInitializeTask performInitializeTask = createPerformInitializeTask(TRANSPORT_NAME);
|
||||
setUpTransport(mTransport);
|
||||
configureTransport(mTransportBinder, TRANSPORT_OK, TRANSPORT_ERROR);
|
||||
PerformInitializeTask performInitializeTask = createPerformInitializeTask(mTransportName);
|
||||
|
||||
performInitializeTask.run();
|
||||
|
||||
@@ -211,64 +214,76 @@ public class PerformInitializeTaskTest {
|
||||
|
||||
@Test
|
||||
public void testRun_whenOnlyOneTransportFails() throws Exception {
|
||||
List<TransportData> transports =
|
||||
TransportTestUtils.setUpTransports(
|
||||
mTransportManager, TRANSPORT_NAMES[0], TRANSPORT_NAMES[1]);
|
||||
configureTransport(transports.get(0).transportMock, TRANSPORT_ERROR, 0);
|
||||
configureTransport(transports.get(1).transportMock, TRANSPORT_OK, TRANSPORT_OK);
|
||||
TransportData transport1 = backupTransport();
|
||||
TransportData transport2 = d2dTransport();
|
||||
List<TransportMock> transportMocks =
|
||||
setUpTransports(mTransportManager, transport1, transport2);
|
||||
configureTransport(transportMocks.get(0).transport, TRANSPORT_ERROR, 0);
|
||||
configureTransport(transportMocks.get(1).transport, TRANSPORT_OK, TRANSPORT_OK);
|
||||
PerformInitializeTask performInitializeTask =
|
||||
createPerformInitializeTask(TRANSPORT_NAMES[0], TRANSPORT_NAMES[1]);
|
||||
createPerformInitializeTask(transport1.transportName, transport2.transportName);
|
||||
|
||||
performInitializeTask.run();
|
||||
|
||||
verify(transports.get(1).transportMock).initializeDevice();
|
||||
verify(mObserver).onResult(eq(TRANSPORT_NAMES[0]), eq(TRANSPORT_ERROR));
|
||||
verify(mObserver).onResult(eq(TRANSPORT_NAMES[1]), eq(TRANSPORT_OK));
|
||||
verify(transportMocks.get(1).transport).initializeDevice();
|
||||
verify(mObserver).onResult(eq(transport1.transportName), eq(TRANSPORT_ERROR));
|
||||
verify(mObserver).onResult(eq(transport2.transportName), eq(TRANSPORT_OK));
|
||||
verify(mObserver).backupFinished(eq(TRANSPORT_ERROR));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRun_withMultipleTransports() throws Exception {
|
||||
List<TransportData> transports =
|
||||
TransportTestUtils.setUpTransports(mTransportManager, TRANSPORT_NAMES);
|
||||
configureTransport(transports.get(0).transportMock, TRANSPORT_OK, TRANSPORT_OK);
|
||||
configureTransport(transports.get(1).transportMock, TRANSPORT_OK, TRANSPORT_OK);
|
||||
configureTransport(transports.get(2).transportMock, TRANSPORT_OK, TRANSPORT_OK);
|
||||
PerformInitializeTask performInitializeTask = createPerformInitializeTask(TRANSPORT_NAMES);
|
||||
List<TransportMock> transportMocks =
|
||||
setUpTransports(
|
||||
mTransportManager, backupTransport(), d2dTransport(), localTransport());
|
||||
configureTransport(transportMocks.get(0).transport, TRANSPORT_OK, TRANSPORT_OK);
|
||||
configureTransport(transportMocks.get(1).transport, TRANSPORT_OK, TRANSPORT_OK);
|
||||
configureTransport(transportMocks.get(2).transport, TRANSPORT_OK, TRANSPORT_OK);
|
||||
String[] transportNames =
|
||||
Stream.of(new TransportData[] {backupTransport(), d2dTransport(), localTransport()})
|
||||
.map(t -> t.transportName)
|
||||
.toArray(String[]::new);
|
||||
PerformInitializeTask performInitializeTask = createPerformInitializeTask(transportNames);
|
||||
|
||||
performInitializeTask.run();
|
||||
|
||||
for (TransportData transport : transports) {
|
||||
Iterator<TransportData> transportsIterator =
|
||||
Arrays.asList(
|
||||
new TransportData[] {
|
||||
backupTransport(), d2dTransport(), localTransport()
|
||||
})
|
||||
.iterator();
|
||||
for (TransportMock transportMock : transportMocks) {
|
||||
TransportData transport = transportsIterator.next();
|
||||
verify(mTransportManager).getTransportClient(eq(transport.transportName), any());
|
||||
verify(mTransportManager)
|
||||
.disposeOfTransportClient(eq(transport.transportClientMock), any());
|
||||
.disposeOfTransportClient(eq(transportMock.transportClient), any());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRun_whenOnlyOneTransportFails_disposesAllTransports() throws Exception {
|
||||
List<TransportData> transports =
|
||||
TransportTestUtils.setUpTransports(
|
||||
mTransportManager, TRANSPORT_NAMES[0], TRANSPORT_NAMES[1]);
|
||||
configureTransport(transports.get(0).transportMock, TRANSPORT_ERROR, 0);
|
||||
configureTransport(transports.get(1).transportMock, TRANSPORT_OK, TRANSPORT_OK);
|
||||
TransportData transport1 = backupTransport();
|
||||
TransportData transport2 = d2dTransport();
|
||||
List<TransportMock> transportMocks =
|
||||
setUpTransports(mTransportManager, transport1, transport2);
|
||||
configureTransport(transportMocks.get(0).transport, TRANSPORT_ERROR, 0);
|
||||
configureTransport(transportMocks.get(1).transport, TRANSPORT_OK, TRANSPORT_OK);
|
||||
PerformInitializeTask performInitializeTask =
|
||||
createPerformInitializeTask(TRANSPORT_NAMES[0], TRANSPORT_NAMES[1]);
|
||||
createPerformInitializeTask(transport1.transportName, transport2.transportName);
|
||||
|
||||
performInitializeTask.run();
|
||||
|
||||
verify(mTransportManager)
|
||||
.disposeOfTransportClient(eq(transports.get(0).transportClientMock), any());
|
||||
.disposeOfTransportClient(eq(transportMocks.get(0).transportClient), any());
|
||||
verify(mTransportManager)
|
||||
.disposeOfTransportClient(eq(transports.get(1).transportClientMock), any());
|
||||
.disposeOfTransportClient(eq(transportMocks.get(1).transportClient), any());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRun_whenTransportNotRegistered() throws Exception {
|
||||
TransportTestUtils.setUpTransports(
|
||||
mTransportManager, new TransportData(TRANSPORT_NAME, null, null));
|
||||
|
||||
PerformInitializeTask performInitializeTask = createPerformInitializeTask(TRANSPORT_NAME);
|
||||
setUpTransports(mTransportManager, mTransport.unregistered());
|
||||
PerformInitializeTask performInitializeTask = createPerformInitializeTask(mTransportName);
|
||||
|
||||
performInitializeTask.run();
|
||||
|
||||
@@ -279,16 +294,15 @@ public class PerformInitializeTaskTest {
|
||||
|
||||
@Test
|
||||
public void testRun_whenOnlyOneTransportNotRegistered() throws Exception {
|
||||
List<TransportData> transports =
|
||||
TransportTestUtils.setUpTransports(
|
||||
mTransportManager,
|
||||
new TransportData(TRANSPORT_NAMES[0], null, null),
|
||||
new TransportData(TRANSPORT_NAMES[1]));
|
||||
String registeredTransportName = transports.get(1).transportName;
|
||||
IBackupTransport registeredTransport = transports.get(1).transportMock;
|
||||
TransportClient registeredTransportClient = transports.get(1).transportClientMock;
|
||||
TransportData transport1 = backupTransport().unregistered();
|
||||
TransportData transport2 = d2dTransport();
|
||||
List<TransportMock> transportMocks =
|
||||
setUpTransports(mTransportManager, transport1, transport2);
|
||||
String registeredTransportName = transport2.transportName;
|
||||
IBackupTransport registeredTransport = transportMocks.get(1).transport;
|
||||
TransportClient registeredTransportClient = transportMocks.get(1).transportClient;
|
||||
PerformInitializeTask performInitializeTask =
|
||||
createPerformInitializeTask(TRANSPORT_NAMES[0], TRANSPORT_NAMES[1]);
|
||||
createPerformInitializeTask(transport1.transportName, transport2.transportName);
|
||||
|
||||
performInitializeTask.run();
|
||||
|
||||
@@ -299,25 +313,24 @@ public class PerformInitializeTaskTest {
|
||||
|
||||
@Test
|
||||
public void testRun_whenTransportNotAvailable() throws Exception {
|
||||
TransportClient transportClient = mock(TransportClient.class);
|
||||
TransportTestUtils.setUpTransports(
|
||||
mTransportManager, new TransportData(TRANSPORT_NAME, null, transportClient));
|
||||
PerformInitializeTask performInitializeTask = createPerformInitializeTask(TRANSPORT_NAME);
|
||||
TransportMock transportMock = setUpTransport(mTransport.unavailable());
|
||||
PerformInitializeTask performInitializeTask = createPerformInitializeTask(mTransportName);
|
||||
|
||||
performInitializeTask.run();
|
||||
|
||||
verify(mTransportManager).disposeOfTransportClient(eq(transportClient), any());
|
||||
verify(mTransportManager)
|
||||
.disposeOfTransportClient(eq(transportMock.transportClient), any());
|
||||
verify(mObserver).backupFinished(eq(TRANSPORT_ERROR));
|
||||
verify(mListener).onFinished(any());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRun_whenTransportThrowsDeadObjectException() throws Exception {
|
||||
TransportClient transportClient = mock(TransportClient.class);
|
||||
TransportTestUtils.setUpTransports(
|
||||
mTransportManager, new TransportData(TRANSPORT_NAME, mTransport, transportClient));
|
||||
when(mTransport.initializeDevice()).thenThrow(DeadObjectException.class);
|
||||
PerformInitializeTask performInitializeTask = createPerformInitializeTask(TRANSPORT_NAME);
|
||||
TransportMock transportMock = setUpTransport(mTransport);
|
||||
IBackupTransport transport = transportMock.transport;
|
||||
TransportClient transportClient = transportMock.transportClient;
|
||||
when(transport.initializeDevice()).thenThrow(DeadObjectException.class);
|
||||
PerformInitializeTask performInitializeTask = createPerformInitializeTask(mTransportName);
|
||||
|
||||
performInitializeTask.run();
|
||||
|
||||
@@ -343,9 +356,10 @@ public class PerformInitializeTaskTest {
|
||||
when(transportMock.finishBackup()).thenReturn(finishBackupStatus);
|
||||
}
|
||||
|
||||
private void setUpTransport(String transportName) throws Exception {
|
||||
TransportTestUtils.setUpTransport(
|
||||
mTransportManager,
|
||||
new TransportData(transportName, mTransport, mock(TransportClient.class)));
|
||||
private TransportMock setUpTransport(TransportData transport) throws Exception {
|
||||
TransportMock transportMock =
|
||||
TransportTestUtils.setUpTransport(mTransportManager, transport);
|
||||
mTransportBinder = transportMock.transport;
|
||||
return transportMock;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* 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 com.android.internal.util.FunctionalUtils.ThrowingRunnable;
|
||||
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
public class TestUtils {
|
||||
/**
|
||||
* Calls {@link Runnable#run()} and returns if no exception is thrown. Otherwise, if the
|
||||
* exception is unchecked, rethrow it; if it's checked wrap in a {@link RuntimeException} and
|
||||
* throw.
|
||||
*
|
||||
* <p><b>Warning:</b>DON'T use this outside tests. A wrapped checked exception is just a failure
|
||||
* in a test.
|
||||
*/
|
||||
public static void uncheck(ThrowingRunnable runnable) {
|
||||
try {
|
||||
runnable.runOrThrow();
|
||||
} catch (Exception e) {
|
||||
throw wrapIfChecked(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls {@link Callable#call()} and returns the value if no exception is thrown. Otherwise, if
|
||||
* the exception is unchecked, rethrow it; if it's checked wrap in a {@link RuntimeException}
|
||||
* and throw.
|
||||
*
|
||||
* <p><b>Warning:</b>DON'T use this outside tests. A wrapped checked exception is just a failure
|
||||
* in a test.
|
||||
*/
|
||||
public static <T> T uncheck(Callable<T> callable) {
|
||||
try {
|
||||
return callable.call();
|
||||
} catch (Exception e) {
|
||||
throw wrapIfChecked(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrap {@code e} in a {@link RuntimeException} only if it's not one already, in which case it's
|
||||
* returned.
|
||||
*/
|
||||
public static RuntimeException wrapIfChecked(Exception e) {
|
||||
if (e instanceof RuntimeException) {
|
||||
return (RuntimeException) e;
|
||||
}
|
||||
return new RuntimeException(e);
|
||||
}
|
||||
|
||||
private TestUtils() {}
|
||||
}
|
||||
@@ -1,64 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2017 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 com.android.internal.backup.IBackupTransport;
|
||||
import com.android.server.backup.TransportManager;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Stub implementation of TransportBoundListener, which returns given result and can tell whether
|
||||
* it was called for given transport.
|
||||
*/
|
||||
public class TransportBoundListenerStub implements
|
||||
TransportManager.TransportBoundListener {
|
||||
private boolean mAlwaysReturnSuccess;
|
||||
private Set<IBackupTransport> mTransportsCalledFor = new HashSet<>();
|
||||
|
||||
public TransportBoundListenerStub(boolean alwaysReturnSuccess) {
|
||||
this.mAlwaysReturnSuccess = alwaysReturnSuccess;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onTransportBound(IBackupTransport binder) {
|
||||
mTransportsCalledFor.add(binder);
|
||||
return mAlwaysReturnSuccess;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the listener was called for the specified transport at least once.
|
||||
*/
|
||||
public boolean isCalledForTransport(IBackupTransport binder) {
|
||||
return mTransportsCalledFor.contains(binder);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the listener was called at least once.
|
||||
*/
|
||||
public boolean isCalled() {
|
||||
return !mTransportsCalledFor.isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets listener calls.
|
||||
*/
|
||||
public void resetState() {
|
||||
mTransportsCalledFor.clear();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,149 @@
|
||||
/*
|
||||
* 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 android.annotation.Nullable;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Intent;
|
||||
|
||||
public class TransportData {
|
||||
// No constants since new Intent() can't be called in static context because of Robolectric
|
||||
public static TransportData backupTransport() {
|
||||
return new TransportData(
|
||||
"com.google.android.gms/.backup.BackupTransportService",
|
||||
"com.google.android.gms/.backup.BackupTransportService",
|
||||
"com.google.android.gms.backup.BackupTransportService",
|
||||
new Intent(),
|
||||
"user@gmail.com",
|
||||
new Intent(),
|
||||
"Google Account");
|
||||
}
|
||||
|
||||
public static TransportData d2dTransport() {
|
||||
return new TransportData(
|
||||
"com.google.android.gms/.backup.migrate.service.D2dTransport",
|
||||
"com.google.android.gms/.backup.component.D2dTransportService",
|
||||
"d2dMigrateTransport",
|
||||
null,
|
||||
"Moving data to new device",
|
||||
null,
|
||||
"");
|
||||
}
|
||||
|
||||
public static TransportData localTransport() {
|
||||
return new TransportData(
|
||||
"android/com.android.internal.backup.LocalTransport",
|
||||
"android/com.android.internal.backup.LocalTransportService",
|
||||
"com.android.internal.backup.LocalTransport",
|
||||
null,
|
||||
"Backing up to debug-only private cache",
|
||||
null,
|
||||
"");
|
||||
}
|
||||
|
||||
public static TransportData genericTransport(String packageName, String className) {
|
||||
return new TransportData(
|
||||
packageName + "/." + className,
|
||||
packageName + "/." + className + "Service",
|
||||
packageName + "." + className,
|
||||
new Intent(),
|
||||
"currentDestinationString",
|
||||
new Intent(),
|
||||
"dataManagementLabel");
|
||||
}
|
||||
|
||||
@TransportTestUtils.TransportStatus
|
||||
public int transportStatus;
|
||||
public final String transportName;
|
||||
private final String transportComponentShort;
|
||||
@Nullable
|
||||
public String transportDirName;
|
||||
@Nullable public Intent configurationIntent;
|
||||
@Nullable public String currentDestinationString;
|
||||
@Nullable public Intent dataManagementIntent;
|
||||
@Nullable public String dataManagementLabel;
|
||||
|
||||
private TransportData(
|
||||
@TransportTestUtils.TransportStatus int transportStatus,
|
||||
String transportName,
|
||||
String transportComponentShort,
|
||||
String transportDirName,
|
||||
Intent configurationIntent,
|
||||
String currentDestinationString,
|
||||
Intent dataManagementIntent,
|
||||
String dataManagementLabel) {
|
||||
this.transportStatus = transportStatus;
|
||||
this.transportName = transportName;
|
||||
this.transportComponentShort = transportComponentShort;
|
||||
this.transportDirName = transportDirName;
|
||||
this.configurationIntent = configurationIntent;
|
||||
this.currentDestinationString = currentDestinationString;
|
||||
this.dataManagementIntent = dataManagementIntent;
|
||||
this.dataManagementLabel = dataManagementLabel;
|
||||
}
|
||||
|
||||
public TransportData(
|
||||
String transportName,
|
||||
String transportComponentShort,
|
||||
String transportDirName,
|
||||
Intent configurationIntent,
|
||||
String currentDestinationString,
|
||||
Intent dataManagementIntent,
|
||||
String dataManagementLabel) {
|
||||
this(
|
||||
TransportTestUtils.TransportStatus.REGISTERED_AVAILABLE,
|
||||
transportName,
|
||||
transportComponentShort,
|
||||
transportDirName,
|
||||
configurationIntent,
|
||||
currentDestinationString,
|
||||
dataManagementIntent,
|
||||
dataManagementLabel);
|
||||
}
|
||||
|
||||
/**
|
||||
* Not field because otherwise we'd have to call ComponentName::new in static context and
|
||||
* Robolectric does not like this.
|
||||
*/
|
||||
public ComponentName getTransportComponent() {
|
||||
return ComponentName.unflattenFromString(transportComponentShort);
|
||||
}
|
||||
|
||||
public TransportData unavailable() {
|
||||
return new TransportData(
|
||||
TransportTestUtils.TransportStatus.REGISTERED_UNAVAILABLE,
|
||||
transportName,
|
||||
transportComponentShort,
|
||||
transportDirName,
|
||||
configurationIntent,
|
||||
currentDestinationString,
|
||||
dataManagementIntent,
|
||||
dataManagementLabel);
|
||||
}
|
||||
|
||||
public TransportData unregistered() {
|
||||
return new TransportData(
|
||||
TransportTestUtils.TransportStatus.UNREGISTERED,
|
||||
transportName,
|
||||
transportComponentShort,
|
||||
transportDirName,
|
||||
configurationIntent,
|
||||
currentDestinationString,
|
||||
dataManagementIntent,
|
||||
dataManagementLabel);
|
||||
}
|
||||
}
|
||||
@@ -16,13 +16,23 @@
|
||||
|
||||
package com.android.server.backup.testing;
|
||||
|
||||
import static com.android.server.backup.testing.TestUtils.uncheck;
|
||||
|
||||
import static org.junit.Assert.fail;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import static java.util.stream.Collectors.toList;
|
||||
|
||||
import android.annotation.Nullable;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.ResolveInfo;
|
||||
import android.content.pm.ServiceInfo;
|
||||
import android.os.RemoteException;
|
||||
import android.support.annotation.IntDef;
|
||||
|
||||
import com.android.internal.backup.IBackupTransport;
|
||||
import com.android.server.backup.TransportManager;
|
||||
@@ -30,85 +40,82 @@ import com.android.server.backup.transport.TransportClient;
|
||||
import com.android.server.backup.transport.TransportNotAvailableException;
|
||||
import com.android.server.backup.transport.TransportNotRegisteredException;
|
||||
|
||||
import java.util.Arrays;
|
||||
import org.robolectric.shadows.ShadowPackageManager;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public class TransportTestUtils {
|
||||
public static final String[] TRANSPORT_NAMES = {
|
||||
"android/com.android.internal.backup.LocalTransport",
|
||||
"com.google.android.gms/.backup.migrate.service.D2dTransport",
|
||||
"com.google.android.gms/.backup.BackupTransportService"
|
||||
};
|
||||
/**
|
||||
* Differently from {@link #setUpTransports(TransportManager, TransportData...)}, which
|
||||
* configures {@link TransportManager}, this is meant to mock the environment for a real
|
||||
* TransportManager.
|
||||
*/
|
||||
public static void setUpTransportsForTransportManager(
|
||||
ShadowPackageManager shadowPackageManager, TransportData... transports)
|
||||
throws Exception {
|
||||
for (TransportData transport : transports) {
|
||||
ComponentName transportComponent = transport.getTransportComponent();
|
||||
String packageName = transportComponent.getPackageName();
|
||||
ResolveInfo resolveInfo = resolveInfo(transportComponent);
|
||||
shadowPackageManager.addResolveInfoForIntent(transportIntent(), resolveInfo);
|
||||
shadowPackageManager.addResolveInfoForIntent(
|
||||
transportIntent().setPackage(packageName), resolveInfo);
|
||||
}
|
||||
}
|
||||
|
||||
public static final String TRANSPORT_NAME = TRANSPORT_NAMES[0];
|
||||
private static Intent transportIntent() {
|
||||
return new Intent(TransportManager.SERVICE_ACTION_TRANSPORT_HOST);
|
||||
}
|
||||
|
||||
/** {@code transportName} has to be in the {@link ComponentName} format (with '/') */
|
||||
public static TransportData setUpCurrentTransport(
|
||||
TransportManager transportManager, String transportName) throws Exception {
|
||||
TransportData transport = setUpTransports(transportManager, transportName).get(0);
|
||||
when(transportManager.getCurrentTransportClient(any()))
|
||||
.thenReturn(transport.transportClientMock);
|
||||
return transport;
|
||||
private static ResolveInfo resolveInfo(ComponentName transportComponent) {
|
||||
ResolveInfo resolveInfo = new ResolveInfo();
|
||||
resolveInfo.serviceInfo = new ServiceInfo();
|
||||
resolveInfo.serviceInfo.packageName = transportComponent.getPackageName();
|
||||
resolveInfo.serviceInfo.name = transportComponent.getClassName();
|
||||
return resolveInfo;
|
||||
}
|
||||
|
||||
/** {@code transportName} has to be in the {@link ComponentName} format (with '/') */
|
||||
public static List<TransportData> setUpTransports(
|
||||
TransportManager transportManager, String... transportNames) throws Exception {
|
||||
return setUpTransports(
|
||||
transportManager,
|
||||
Arrays.stream(transportNames)
|
||||
.map(TransportData::new)
|
||||
.toArray(TransportData[]::new));
|
||||
public static TransportMock setUpCurrentTransport(
|
||||
TransportManager transportManager, TransportData transport) throws Exception {
|
||||
TransportMock transportMock = setUpTransports(transportManager, transport).get(0);
|
||||
if (transportMock.transportClient != null) {
|
||||
when(transportManager.getCurrentTransportClient(any()))
|
||||
.thenReturn(transportMock.transportClient);
|
||||
}
|
||||
return transportMock;
|
||||
}
|
||||
|
||||
/** @see #setUpTransport(TransportManager, TransportData) */
|
||||
public static List<TransportData> setUpTransports(
|
||||
public static List<TransportMock> setUpTransports(
|
||||
TransportManager transportManager, TransportData... transports) throws Exception {
|
||||
for (TransportData transport : transports) {
|
||||
setUpTransport(transportManager, transport);
|
||||
}
|
||||
return Arrays.asList(transports);
|
||||
return Stream.of(transports)
|
||||
.map(transport -> uncheck(() -> setUpTransport(transportManager, transport)))
|
||||
.collect(toList());
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures transport according to {@link TransportData}:
|
||||
*
|
||||
* <ul>
|
||||
* <li>{@link TransportData#transportMock} {@code null} means transport not available.
|
||||
* <li>{@link TransportData#transportClientMock} {@code null} means transport not registered.
|
||||
* </ul>
|
||||
*/
|
||||
public static void setUpTransport(TransportManager transportManager, TransportData transport)
|
||||
throws Exception {
|
||||
public static TransportMock setUpTransport(
|
||||
TransportManager transportManager, TransportData transport) throws Exception {
|
||||
int status = transport.transportStatus;
|
||||
String transportName = transport.transportName;
|
||||
String transportDirName = transportDirName(transportName);
|
||||
ComponentName transportComponent = transportComponentName(transportName);
|
||||
IBackupTransport transportMock = transport.transportMock;
|
||||
TransportClient transportClientMock = transport.transportClientMock;
|
||||
ComponentName transportComponent = transport.getTransportComponent();
|
||||
String transportDirName = transport.transportDirName;
|
||||
|
||||
if (transportClientMock != null) {
|
||||
TransportMock transportMock = mockTransport(transport);
|
||||
if (status == TransportStatus.REGISTERED_AVAILABLE
|
||||
|| status == TransportStatus.REGISTERED_UNAVAILABLE) {
|
||||
// Transport registered
|
||||
when(transportManager.getTransportClient(eq(transportName), any()))
|
||||
.thenReturn(transportClientMock);
|
||||
.thenReturn(transportMock.transportClient);
|
||||
when(transportManager.getTransportClientOrThrow(eq(transportName), any()))
|
||||
.thenReturn(transportClientMock);
|
||||
.thenReturn(transportMock.transportClient);
|
||||
when(transportManager.getTransportName(transportComponent)).thenReturn(transportName);
|
||||
when(transportManager.getTransportDirName(eq(transportName)))
|
||||
.thenReturn(transportDirName);
|
||||
when(transportManager.getTransportDirName(eq(transportComponent)))
|
||||
.thenReturn(transportDirName);
|
||||
when(transportClientMock.getTransportComponent()).thenReturn(transportComponent);
|
||||
|
||||
if (transportMock != null) {
|
||||
// Transport registered and available
|
||||
when(transportClientMock.connectOrThrow(any())).thenReturn(transportMock);
|
||||
when(transportMock.name()).thenReturn(transportName);
|
||||
when(transportMock.transportDirName()).thenReturn(transportDirName);
|
||||
} else {
|
||||
// Transport registered but unavailable
|
||||
when(transportClientMock.connectOrThrow(any()))
|
||||
.thenThrow(TransportNotAvailableException.class);
|
||||
}
|
||||
// TODO: Mock rest of description methods
|
||||
} else {
|
||||
// Transport not registered
|
||||
when(transportManager.getTransportClient(eq(transportName), any())).thenReturn(null);
|
||||
@@ -121,34 +128,73 @@ public class TransportTestUtils {
|
||||
when(transportManager.getTransportDirName(eq(transportComponent)))
|
||||
.thenThrow(TransportNotRegisteredException.class);
|
||||
}
|
||||
return transportMock;
|
||||
}
|
||||
|
||||
/** {@code transportName} has to be in the {@link ComponentName} format (with '/') */
|
||||
public static ComponentName transportComponentName(String transportName) {
|
||||
return ComponentName.unflattenFromString(transportName);
|
||||
}
|
||||
public static TransportMock mockTransport(TransportData transport) throws Exception {
|
||||
final TransportClient transportClientMock;
|
||||
int status = transport.transportStatus;
|
||||
ComponentName transportComponent = transport.getTransportComponent();
|
||||
if (status == TransportStatus.REGISTERED_AVAILABLE
|
||||
|| status == TransportStatus.REGISTERED_UNAVAILABLE) {
|
||||
// Transport registered
|
||||
transportClientMock = mock(TransportClient.class);
|
||||
when(transportClientMock.getTransportComponent()).thenReturn(transportComponent);
|
||||
if (status == TransportStatus.REGISTERED_AVAILABLE) {
|
||||
// Transport registered and available
|
||||
IBackupTransport transportMock = mockTransportBinder(transport);
|
||||
when(transportClientMock.connectOrThrow(any())).thenReturn(transportMock);
|
||||
|
||||
public static String transportDirName(String transportName) {
|
||||
return transportName + "_dir_name";
|
||||
}
|
||||
return new TransportMock(transportClientMock, transportMock);
|
||||
} else {
|
||||
// Transport registered but unavailable
|
||||
when(transportClientMock.connectOrThrow(any()))
|
||||
.thenThrow(TransportNotAvailableException.class);
|
||||
|
||||
public static class TransportData {
|
||||
public final String transportName;
|
||||
@Nullable public final IBackupTransport transportMock;
|
||||
@Nullable public final TransportClient transportClientMock;
|
||||
|
||||
public TransportData(
|
||||
String transportName,
|
||||
@Nullable IBackupTransport transportMock,
|
||||
@Nullable TransportClient transportClientMock) {
|
||||
this.transportName = transportName;
|
||||
this.transportMock = transportMock;
|
||||
this.transportClientMock = transportClientMock;
|
||||
return new TransportMock(transportClientMock, null);
|
||||
}
|
||||
} else {
|
||||
// Transport not registered
|
||||
return new TransportMock(null, null);
|
||||
}
|
||||
}
|
||||
|
||||
public TransportData(String transportName) {
|
||||
this(transportName, mock(IBackupTransport.class), mock(TransportClient.class));
|
||||
private static IBackupTransport mockTransportBinder(TransportData transport) throws Exception {
|
||||
IBackupTransport transportBinder = mock(IBackupTransport.class);
|
||||
try {
|
||||
when(transportBinder.name()).thenReturn(transport.transportName);
|
||||
when(transportBinder.transportDirName()).thenReturn(transport.transportDirName);
|
||||
when(transportBinder.configurationIntent()).thenReturn(transport.configurationIntent);
|
||||
when(transportBinder.currentDestinationString())
|
||||
.thenReturn(transport.currentDestinationString);
|
||||
when(transportBinder.dataManagementIntent()).thenReturn(transport.dataManagementIntent);
|
||||
when(transportBinder.dataManagementLabel()).thenReturn(transport.dataManagementLabel);
|
||||
} catch (RemoteException e) {
|
||||
fail("RemoteException?");
|
||||
}
|
||||
return transportBinder;
|
||||
}
|
||||
|
||||
public static class TransportMock {
|
||||
@Nullable public final TransportClient transportClient;
|
||||
@Nullable public final IBackupTransport transport;
|
||||
|
||||
private TransportMock(
|
||||
@Nullable TransportClient transportClient, @Nullable IBackupTransport transport) {
|
||||
this.transportClient = transportClient;
|
||||
this.transport = transport;
|
||||
}
|
||||
}
|
||||
|
||||
@IntDef({
|
||||
TransportStatus.REGISTERED_AVAILABLE,
|
||||
TransportStatus.REGISTERED_UNAVAILABLE,
|
||||
TransportStatus.UNREGISTERED
|
||||
})
|
||||
public @interface TransportStatus {
|
||||
int REGISTERED_AVAILABLE = 0;
|
||||
int REGISTERED_UNAVAILABLE = 1;
|
||||
int UNREGISTERED = 2;
|
||||
}
|
||||
|
||||
private TransportTestUtils() {}
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* 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.Intent;
|
||||
import android.content.ServiceConnection;
|
||||
import android.os.UserHandle;
|
||||
|
||||
import org.robolectric.annotation.Implementation;
|
||||
import org.robolectric.annotation.Implements;
|
||||
import org.robolectric.shadows.ShadowContextImpl;
|
||||
|
||||
@Implements(className = ShadowContextImpl.CLASS_NAME, inheritImplementationMethods = true)
|
||||
public class FrameworkShadowContextImpl extends ShadowContextImpl {
|
||||
@Implementation
|
||||
public boolean bindServiceAsUser(
|
||||
Intent service,
|
||||
ServiceConnection connection,
|
||||
int flags,
|
||||
UserHandle user) {
|
||||
return bindService(service, connection, flags);
|
||||
}
|
||||
}
|
||||
@@ -14,22 +14,18 @@
|
||||
* limitations under the License
|
||||
*/
|
||||
|
||||
package com.android.server.backup.testing;
|
||||
package com.android.server.testing.shadows;
|
||||
|
||||
import android.app.ApplicationPackageManager;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.ResolveInfo;
|
||||
|
||||
import java.util.List;
|
||||
import org.robolectric.annotation.Implements;
|
||||
import org.robolectric.shadows.ShadowApplicationPackageManager;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Implementation of PackageManager for Robolectric which handles queryIntentServicesAsUser().
|
||||
*/
|
||||
/** Extension of ShadowApplicationPackageManager */
|
||||
@Implements(value = ApplicationPackageManager.class, inheritImplementationMethods = true)
|
||||
public class ShadowPackageManagerForBackup extends ShadowApplicationPackageManager {
|
||||
public class FrameworkShadowPackageManager extends ShadowApplicationPackageManager {
|
||||
@Override
|
||||
public List<ResolveInfo> queryIntentServicesAsUser(Intent intent, int flags, int userId) {
|
||||
return queryIntentServices(intent, flags);
|
||||
@@ -96,7 +96,7 @@ public class BackupManagerServiceTest {
|
||||
createBackupManagerService();
|
||||
|
||||
verify(mTransportManager)
|
||||
.setTransportBoundListener(any(TransportManager.TransportBoundListener.class));
|
||||
.setOnTransportRegisteredListener(any());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
Reference in New Issue
Block a user