Merge "Binding on-demand #6: Transport attributes usage"

This commit is contained in:
Bernardo Rufino
2017-12-15 18:58:06 +00:00
committed by Android (Google) Code Review
8 changed files with 356 additions and 357 deletions

View File

@@ -25,7 +25,6 @@ import static com.android.server.backup.internal.BackupHandler.MSG_REQUEST_BACKU
import static com.android.server.backup.internal.BackupHandler.MSG_RESTORE_OPERATION_TIMEOUT;
import static com.android.server.backup.internal.BackupHandler.MSG_RESTORE_SESSION_TIMEOUT;
import static com.android.server.backup.internal.BackupHandler.MSG_RETRY_CLEAR;
import static com.android.server.backup.internal.BackupHandler.MSG_RETRY_INIT;
import static com.android.server.backup.internal.BackupHandler.MSG_RUN_ADB_BACKUP;
import static com.android.server.backup.internal.BackupHandler.MSG_RUN_ADB_RESTORE;
import static com.android.server.backup.internal.BackupHandler.MSG_RUN_CLEAR;
@@ -120,6 +119,7 @@ import com.android.server.backup.params.RestoreParams;
import com.android.server.backup.restore.ActiveRestoreSession;
import com.android.server.backup.restore.PerformUnifiedRestoreTask;
import com.android.server.backup.transport.TransportClient;
import com.android.server.backup.transport.TransportNotRegisteredException;
import com.android.server.backup.utils.AppBackupUtils;
import com.android.server.backup.utils.BackupManagerMonitorUtils;
import com.android.server.backup.utils.BackupObserverUtils;
@@ -1083,56 +1083,35 @@ public class RefactoredBackupManagerService implements BackupManagerServiceInter
return mBackupPasswordManager.backupPasswordMatches(currentPw);
}
// Maintain persistent state around whether need to do an initialize operation.
// Must be called with the queue lock held.
public void recordInitPendingLocked(boolean isPending, String transportName) {
/**
* Maintain persistent state around whether need to do an initialize operation.
* Must be called with the queue lock held.
*/
@GuardedBy("mQueueLock")
public void recordInitPendingLocked(
boolean isPending, String transportName, String transportDirName) {
if (MORE_DEBUG) {
Slog.i(TAG, "recordInitPendingLocked: " + isPending
+ " on transport " + transportName);
}
mBackupHandler.removeMessages(MSG_RETRY_INIT);
try {
IBackupTransport transport = mTransportManager.getTransportBinder(transportName);
if (transport != null) {
String transportDirName = transport.transportDirName();
File stateDir = new File(mBaseStateDir, transportDirName);
File initPendingFile = new File(stateDir, INIT_SENTINEL_FILE_NAME);
File stateDir = new File(mBaseStateDir, transportDirName);
File initPendingFile = new File(stateDir, INIT_SENTINEL_FILE_NAME);
if (isPending) {
// We need an init before we can proceed with sending backup data.
// Record that with an entry in our set of pending inits, as well as
// journaling it via creation of a sentinel file.
mPendingInits.add(transportName);
try {
(new FileOutputStream(initPendingFile)).close();
} catch (IOException ioe) {
// Something is badly wrong with our permissions; just try to move on
}
} else {
// No more initialization needed; wipe the journal and reset our state.
initPendingFile.delete();
mPendingInits.remove(transportName);
}
return; // done; don't fall through to the error case
}
} catch (Exception e) {
// transport threw when asked its name; fall through to the lookup-failed case
Slog.e(TAG, "Transport " + transportName + " failed to report name: "
+ e.getMessage());
}
// The named transport doesn't exist or threw. This operation is
// important, so we record the need for a an init and post a message
// to retry the init later.
if (isPending) {
// We need an init before we can proceed with sending backup data.
// Record that with an entry in our set of pending inits, as well as
// journaling it via creation of a sentinel file.
mPendingInits.add(transportName);
mBackupHandler.sendMessageDelayed(
mBackupHandler.obtainMessage(MSG_RETRY_INIT,
(isPending ? 1 : 0),
0,
transportName),
TRANSPORT_RETRY_INTERVAL);
try {
(new FileOutputStream(initPendingFile)).close();
} catch (IOException ioe) {
// Something is badly wrong with our permissions; just try to move on
}
} else {
// No more initialization needed; wipe the journal and reset our state.
initPendingFile.delete();
mPendingInits.remove(transportName);
}
}
@@ -1614,27 +1593,9 @@ public class RefactoredBackupManagerService implements BackupManagerServiceInter
return BackupManager.ERROR_BACKUP_NOT_ALLOWED;
}
// We're using pieces of the new binding on-demand infra-structure and the old always-bound
// infra-structure below this comment. The TransportManager.getCurrentTransportClient() line
// is using the new one and TransportManager.getCurrentTransportBinder() is using the old.
// This is weird but there is a reason.
// This is the natural place to put TransportManager.getCurrentTransportClient() because of
// the null handling below that should be the same for TransportClient.
// TransportClient.connect() would return a IBackupTransport for us (instead of using the
// old infra), but it may block and we don't want this in this thread.
// The only usage of transport in this method is for transport.transportDirName(). When the
// push-from-transport part of binding on-demand is in place we will replace the calls for
// IBackupTransport.transportDirName() with calls for
// TransportManager.transportDirName(transportName) or similar. So we'll leave the old piece
// here until we implement that.
// TODO(brufino): Remove always-bound code mTransportManager.getCurrentTransportBinder()
TransportClient transportClient =
mTransportManager.getCurrentTransportClient("BMS.requestBackup()");
IBackupTransport transport = mTransportManager.getCurrentTransportBinder();
if (transportClient == null || transport == null) {
if (transportClient != null) {
mTransportManager.disposeOfTransportClient(transportClient, "BMS.requestBackup()");
}
if (transportClient == null) {
BackupObserverUtils.sendBackupFinished(observer, BackupManager.ERROR_TRANSPORT_ABORTED);
monitor = BackupManagerMonitorUtils.monitorEvent(monitor,
BackupManagerMonitor.LOG_EVENT_ID_TRANSPORT_IS_NULL,
@@ -1679,15 +1640,7 @@ public class RefactoredBackupManagerService implements BackupManagerServiceInter
+ " k/v backups");
}
String dirName;
try {
dirName = transport.transportDirName();
} catch (Exception e) {
Slog.e(TAG, "Transport unavailable while attempting backup: " + e.getMessage());
BackupObserverUtils.sendBackupFinished(observer, BackupManager.ERROR_TRANSPORT_ABORTED);
return BackupManager.ERROR_TRANSPORT_ABORTED;
}
String dirName = transportClient.getTransportDirName();
boolean nonIncrementalBackup = (flags & BackupManager.FLAG_NON_INCREMENTAL_BACKUP) != 0;
Message msg = mBackupHandler.obtainMessage(MSG_REQUEST_BACKUP);
@@ -1998,16 +1951,17 @@ public class RefactoredBackupManagerService implements BackupManagerServiceInter
writeFullBackupScheduleAsync();
}
private boolean fullBackupAllowable(IBackupTransport transport) {
if (transport == null) {
Slog.w(TAG, "Transport not present; full data backup not performed");
private boolean fullBackupAllowable(String transportName) {
if (!mTransportManager.isTransportRegistered(transportName)) {
Slog.w(TAG, "Transport not registered; full data backup not performed");
return false;
}
// Don't proceed unless we have already established package metadata
// for the current dataset via a key/value backup pass.
try {
File stateDir = new File(mBaseStateDir, transport.transportDirName());
String transportDirName = mTransportManager.getTransportDirName(transportName);
File stateDir = new File(mBaseStateDir, transportDirName);
File pmState = new File(stateDir, PACKAGE_MANAGER_SENTINEL);
if (pmState.length() <= 0) {
if (DEBUG) {
@@ -2097,7 +2051,8 @@ public class RefactoredBackupManagerService implements BackupManagerServiceInter
headBusy = false;
if (!fullBackupAllowable(mTransportManager.getCurrentTransportBinder())) {
String transportName = mTransportManager.getCurrentTransportName();
if (!fullBackupAllowable(transportName)) {
if (MORE_DEBUG) {
Slog.i(TAG, "Preconditions not met; not running full backup");
}
@@ -2545,7 +2500,8 @@ public class RefactoredBackupManagerService implements BackupManagerServiceInter
throw new IllegalStateException("Restore supported only for the device owner");
}
if (!fullBackupAllowable(mTransportManager.getCurrentTransportBinder())) {
String transportName = mTransportManager.getCurrentTransportName();
if (!fullBackupAllowable(transportName)) {
Slog.i(TAG, "Full backup not currently possible -- key/value backup not yet run?");
} else {
if (DEBUG) {
@@ -2826,10 +2782,30 @@ public class RefactoredBackupManagerService implements BackupManagerServiceInter
if (wasEnabled && mProvisioned) {
// NOTE: we currently flush every registered transport, not just
// the currently-active one.
String[] allTransports = mTransportManager.getBoundTransportNames();
List<String> transportNames = new ArrayList<>();
List<String> transportDirNames = new ArrayList<>();
mTransportManager.forEachRegisteredTransport(
name -> {
final String dirName;
try {
dirName =
mTransportManager
.getTransportDirName(name);
} catch (TransportNotRegisteredException e) {
// Should never happen
Slog.e(TAG, "Unexpected unregistered transport", e);
return;
}
transportNames.add(name);
transportDirNames.add(dirName);
});
// build the set of transports for which we are posting an init
for (String transport : allTransports) {
recordInitPendingLocked(true, transport);
for (int i = 0; i < transportNames.size(); i++) {
recordInitPendingLocked(
true,
transportNames.get(i),
transportDirNames.get(i));
}
mAlarmManager.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(),
mRunInitIntent);
@@ -2993,7 +2969,7 @@ public class RefactoredBackupManagerService implements BackupManagerServiceInter
final long oldId = Binder.clearCallingIdentity();
try {
mTransportManager.describeTransport(
mTransportManager.updateTransportAttributes(
transportComponent,
name,
configurationIntent,
@@ -3093,23 +3069,16 @@ public class RefactoredBackupManagerService implements BackupManagerServiceInter
public Intent getConfigurationIntent(String transportName) {
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
"getConfigurationIntent");
final IBackupTransport transport = mTransportManager.getTransportBinder(transportName);
if (transport != null) {
try {
final Intent intent = transport.configurationIntent();
if (MORE_DEBUG) {
Slog.d(TAG, "getConfigurationIntent() returning config intent "
+ intent);
}
return intent;
} catch (Exception e) {
/* fall through to return null */
Slog.e(TAG, "Unable to get configuration intent from transport: " + e.getMessage());
try {
Intent intent = mTransportManager.getTransportConfigurationIntent(transportName);
if (MORE_DEBUG) {
Slog.d(TAG, "getConfigurationIntent() returning intent " + intent);
}
return intent;
} catch (TransportNotRegisteredException e) {
Slog.e(TAG, "Unable to get configuration intent from transport: " + e.getMessage());
return null;
}
return null;
}
// Supply the configuration summary string for the given transport. If the name is
@@ -3143,22 +3112,16 @@ public class RefactoredBackupManagerService implements BackupManagerServiceInter
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
"getDataManagementIntent");
final IBackupTransport transport = mTransportManager.getTransportBinder(transportName);
if (transport != null) {
try {
final Intent intent = transport.dataManagementIntent();
if (MORE_DEBUG) {
Slog.d(TAG, "getDataManagementIntent() returning intent "
+ intent);
}
return intent;
} catch (Exception e) {
/* fall through to return null */
Slog.e(TAG, "Unable to get management intent from transport: " + e.getMessage());
try {
Intent intent = mTransportManager.getTransportDataManagementIntent(transportName);
if (MORE_DEBUG) {
Slog.d(TAG, "getDataManagementIntent() returning intent " + intent);
}
return intent;
} catch (TransportNotRegisteredException e) {
Slog.e(TAG, "Unable to get management intent from transport: " + e.getMessage());
return null;
}
return null;
}
// Supply the menu label for affordances that fire the manage-data intent
@@ -3168,19 +3131,16 @@ public class RefactoredBackupManagerService implements BackupManagerServiceInter
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
"getDataManagementLabel");
final IBackupTransport transport = mTransportManager.getTransportBinder(transportName);
if (transport != null) {
try {
final String text = transport.dataManagementLabel();
if (MORE_DEBUG) Slog.d(TAG, "getDataManagementLabel() returning " + text);
return text;
} catch (Exception e) {
/* fall through to return null */
Slog.e(TAG, "Unable to get management label from transport: " + e.getMessage());
try {
String label = mTransportManager.getTransportDataManagementLabel(transportName);
if (MORE_DEBUG) {
Slog.d(TAG, "getDataManagementLabel() returning " + label);
}
return label;
} catch (TransportNotRegisteredException e) {
Slog.e(TAG, "Unable to get management label from transport: " + e.getMessage());
return null;
}
return null;
}
// Callback: a requested backup agent has been instantiated. This should only
@@ -3497,14 +3457,16 @@ public class RefactoredBackupManagerService implements BackupManagerServiceInter
pw.println("Available transports:");
final String[] transports = listAllTransports();
if (transports != null) {
for (String t : listAllTransports()) {
for (String t : transports) {
pw.println((t.equals(mTransportManager.getCurrentTransportName()) ? " * "
: " ") + t);
try {
IBackupTransport transport = mTransportManager.getTransportBinder(t);
File dir = new File(mBaseStateDir, transport.transportDirName());
File dir = new File(mBaseStateDir,
mTransportManager.getTransportDirName(t));
pw.println(" destination: " + transport.currentDestinationString());
pw.println(" intent: " + transport.configurationIntent());
pw.println(" intent: "
+ mTransportManager.getTransportConfigurationIntent(t));
for (File f : dir.listFiles()) {
pw.println(
" " + f.getName() + " - " + f.length() + " state bytes");

View File

@@ -49,12 +49,14 @@ import com.android.server.EventLogTags;
import com.android.server.backup.transport.TransportClient;
import com.android.server.backup.transport.TransportClientManager;
import com.android.server.backup.transport.TransportConnectionListener;
import com.android.server.backup.transport.TransportNotRegisteredException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Consumer;
import java.util.function.Predicate;
/**
@@ -236,6 +238,72 @@ public class TransportManager {
return getTransportBinder(mCurrentTransportName);
}
/**
* Retrieve the configuration intent of {@code transportName}.
* @throws TransportNotRegisteredException if the transport is not registered.
*/
@Nullable
public Intent getTransportConfigurationIntent(String transportName)
throws TransportNotRegisteredException {
synchronized (mTransportLock) {
return getRegisteredTransportDescriptionOrThrowLocked(transportName)
.configurationIntent;
}
}
/**
* Retrieve the data management intent of {@code transportName}.
* @throws TransportNotRegisteredException if the transport is not registered.
*/
@Nullable
public Intent getTransportDataManagementIntent(String transportName)
throws TransportNotRegisteredException {
synchronized (mTransportLock) {
return getRegisteredTransportDescriptionOrThrowLocked(transportName)
.dataManagementIntent;
}
}
/**
* Retrieve the data management label of {@code transportName}.
* @throws TransportNotRegisteredException if the transport is not registered.
*/
@Nullable
public String getTransportDataManagementLabel(String transportName)
throws TransportNotRegisteredException {
synchronized (mTransportLock) {
return getRegisteredTransportDescriptionOrThrowLocked(transportName)
.dataManagementLabel;
}
}
/**
* Retrieve the transport dir name of {@code transportName}.
* @throws TransportNotRegisteredException if the transport is not registered.
*/
public String getTransportDirName(String transportName)
throws TransportNotRegisteredException {
synchronized (mTransportLock) {
return getRegisteredTransportDescriptionOrThrowLocked(transportName)
.transportDirName;
}
}
/**
* Execute {@code transportConsumer} for each registered transport passing the transport name.
* This is called with an internal lock held, ensuring that the transport will remain registered
* while {@code transportConsumer} is being executed. Don't do heavy operations in
* {@code transportConsumer}.
*/
public void forEachRegisteredTransport(Consumer<String> transportConsumer) {
synchronized (mTransportLock) {
for (TransportDescription transportDescription
: mRegisteredTransportsDescriptionMap.values()) {
transportConsumer.accept(transportDescription.name);
}
}
}
public String getTransportName(IBackupTransport binder) {
synchronized (mTransportLock) {
for (TransportConnection conn : mValidTransports.values()) {
@@ -280,6 +348,17 @@ public class TransportManager {
return (entry == null) ? null : entry.getValue();
}
@GuardedBy("mTransportLock")
private TransportDescription getRegisteredTransportDescriptionOrThrowLocked(
String transportName) throws TransportNotRegisteredException {
TransportDescription description = getRegisteredTransportDescriptionLocked(transportName);
if (description == null) {
throw new TransportNotRegisteredException(transportName);
}
return description;
}
@GuardedBy("mTransportLock")
@Nullable
private Map.Entry<ComponentName, TransportDescription> getRegisteredTransportEntryLocked(
@@ -385,13 +464,13 @@ public class TransportManager {
* Updates given values for the transport already registered and identified with
* {@param transportComponent}. If the transport is not registered it will log and return.
*/
public void describeTransport(
public void updateTransportAttributes(
ComponentName transportComponent,
String name,
@Nullable Intent configurationIntent,
String currentDestinationString,
@Nullable Intent dataManagementIntent,
String dataManagementLabel) {
@Nullable String dataManagementLabel) {
synchronized (mTransportLock) {
TransportDescription description =
mRegisteredTransportsDescriptionMap.get(transportComponent);
@@ -766,7 +845,7 @@ public class TransportManager {
@Nullable private Intent configurationIntent;
private String currentDestinationString;
@Nullable private Intent dataManagementIntent;
private String dataManagementLabel;
@Nullable private String dataManagementLabel;
private TransportDescription(
String name,
@@ -774,7 +853,7 @@ public class TransportManager {
@Nullable Intent configurationIntent,
String currentDestinationString,
@Nullable Intent dataManagementIntent,
String dataManagementLabel) {
@Nullable String dataManagementLabel) {
this.name = name;
this.transportDirName = transportDirName;
this.configurationIntent = configurationIntent;

View File

@@ -293,16 +293,6 @@ public class BackupHandler extends Handler {
break;
}
case MSG_RETRY_INIT: {
synchronized (backupManagerService.getQueueLock()) {
backupManagerService.recordInitPendingLocked(msg.arg1 != 0, (String) msg.obj);
backupManagerService.getAlarmManager().set(AlarmManager.RTC_WAKEUP,
System.currentTimeMillis(),
backupManagerService.getRunInitIntent());
}
break;
}
case MSG_RUN_GET_RESTORE_SETS: {
// Like other async operations, this is entered with the wakelock held
RestoreSet[] sets = null;

View File

@@ -98,7 +98,8 @@ public class PerformInitializeTask implements Runnable {
transportDirName));
EventLog.writeEvent(EventLogTags.BACKUP_SUCCESS, 0, millis);
synchronized (backupManagerService.getQueueLock()) {
backupManagerService.recordInitPendingLocked(false, transportName);
backupManagerService.recordInitPendingLocked(
false, transportName, transportDirName);
}
notifyResult(transportName, BackupTransport.TRANSPORT_OK);
} else {
@@ -107,7 +108,8 @@ public class PerformInitializeTask implements Runnable {
Slog.e(TAG, "Transport error in initializeDevice()");
EventLog.writeEvent(EventLogTags.BACKUP_TRANSPORT_FAILURE, "(initialize)");
synchronized (backupManagerService.getQueueLock()) {
backupManagerService.recordInitPendingLocked(true, transportName);
backupManagerService.recordInitPendingLocked(
true, transportName, transportDirName);
}
notifyResult(transportName, status);
result = status;

View File

@@ -0,0 +1,35 @@
/*
* 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.transport;
import android.util.AndroidException;
import com.android.server.backup.TransportManager;
/**
* Exception thrown when the transport is not registered.
*
* @see TransportManager#getTransportDirName(String)
* @see TransportManager#getTransportConfigurationIntent(String)
* @see TransportManager#getTransportDataManagementIntent(String)
* @see TransportManager#getTransportDataManagementLabel(String)
*/
public class TransportNotRegisteredException extends AndroidException {
public TransportNotRegisteredException(String transportName) {
super("Transport " + transportName + " not registered");
}
}

View File

@@ -18,9 +18,13 @@ package com.android.server.backup;
import static com.google.common.truth.Truth.assertThat;
import static junit.framework.Assert.fail;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import static org.robolectric.shadow.api.Shadow.extract;
import android.annotation.Nullable;
import android.app.backup.BackupManager;
import android.content.ComponentName;
import android.content.Intent;
@@ -29,15 +33,18 @@ import android.content.pm.PackageInfo;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
import android.os.IBinder;
import android.os.RemoteException;
import android.platform.test.annotations.Presubmit;
import com.android.server.backup.testing.BackupTransportStub;
import com.android.internal.backup.IBackupTransport;
import com.android.internal.util.FunctionalUtils.ThrowingRunnable;
import com.android.server.backup.testing.ShadowBackupTransportStub;
import com.android.server.backup.testing.ShadowContextImplForBackup;
import com.android.server.backup.testing.ShadowPackageManagerForBackup;
import com.android.server.backup.testing.TransportBoundListenerStub;
import com.android.server.backup.testing.TransportReadyCallbackStub;
import com.android.server.backup.transport.TransportClient;
import com.android.server.backup.transport.TransportNotRegisteredException;
import com.android.server.testing.FrameworkRobolectricTestRunner;
import com.android.server.testing.SystemLoaderClasses;
@@ -95,15 +102,29 @@ public class TransportManagerTest {
(ShadowPackageManagerForBackup)
extract(RuntimeEnvironment.application.getPackageManager());
mTransport1 = new TransportInfo(PACKAGE_NAME, "transport1.name");
mTransport2 = new TransportInfo(PACKAGE_NAME, "transport2.name");
mTransport1 = new TransportInfo(
PACKAGE_NAME,
"transport1.name",
new Intent(),
"currentDestinationString",
new Intent(),
"dataManagementLabel");
mTransport2 = new TransportInfo(
PACKAGE_NAME,
"transport2.name",
new Intent(),
"currentDestinationString",
new Intent(),
"dataManagementLabel");
ShadowContextImplForBackup.sComponentBinderMap.put(mTransport1.componentName,
mTransport1.binder);
ShadowContextImplForBackup.sComponentBinderMap.put(mTransport2.componentName,
mTransport2.binder);
ShadowBackupTransportStub.sBinderTransportMap.put(mTransport1.binder, mTransport1.stub);
ShadowBackupTransportStub.sBinderTransportMap.put(mTransport2.binder, mTransport2.stub);
ShadowBackupTransportStub.sBinderTransportMap.put(
mTransport1.binder, mTransport1.binderInterface);
ShadowBackupTransportStub.sBinderTransportMap.put(
mTransport2.binder, mTransport2.binderInterface);
}
@After
@@ -129,8 +150,10 @@ public class TransportManagerTest {
Arrays.asList(mTransport1.componentName, mTransport2.componentName));
assertThat(transportManager.getBoundTransportNames()).asList().containsExactlyElementsIn(
Arrays.asList(mTransport1.name, mTransport2.name));
assertThat(mTransportBoundListenerStub.isCalledForTransport(mTransport1.stub)).isTrue();
assertThat(mTransportBoundListenerStub.isCalledForTransport(mTransport2.stub)).isTrue();
assertThat(mTransportBoundListenerStub.isCalledForTransport(mTransport1.binderInterface))
.isTrue();
assertThat(mTransportBoundListenerStub.isCalledForTransport(mTransport2.binderInterface))
.isTrue();
}
@Test
@@ -153,8 +176,10 @@ public class TransportManagerTest {
Collections.singleton(mTransport2.componentName));
assertThat(transportManager.getBoundTransportNames()).asList().containsExactlyElementsIn(
Collections.singleton(mTransport2.name));
assertThat(mTransportBoundListenerStub.isCalledForTransport(mTransport1.stub)).isFalse();
assertThat(mTransportBoundListenerStub.isCalledForTransport(mTransport2.stub)).isTrue();
assertThat(mTransportBoundListenerStub.isCalledForTransport(mTransport1.binderInterface))
.isFalse();
assertThat(mTransportBoundListenerStub.isCalledForTransport(mTransport2.binderInterface))
.isTrue();
}
@Test
@@ -193,8 +218,10 @@ public class TransportManagerTest {
Collections.singleton(mTransport2.componentName));
assertThat(transportManager.getBoundTransportNames()).asList().containsExactlyElementsIn(
Collections.singleton(mTransport2.name));
assertThat(mTransportBoundListenerStub.isCalledForTransport(mTransport1.stub)).isFalse();
assertThat(mTransportBoundListenerStub.isCalledForTransport(mTransport2.stub)).isTrue();
assertThat(mTransportBoundListenerStub.isCalledForTransport(mTransport1.binderInterface))
.isFalse();
assertThat(mTransportBoundListenerStub.isCalledForTransport(mTransport2.binderInterface))
.isTrue();
}
@Test
@@ -250,8 +277,10 @@ public class TransportManagerTest {
Arrays.asList(mTransport1.componentName, mTransport2.componentName));
assertThat(transportManager.getBoundTransportNames()).asList().containsExactlyElementsIn(
Arrays.asList(mTransport1.name, mTransport2.name));
assertThat(mTransportBoundListenerStub.isCalledForTransport(mTransport1.stub)).isFalse();
assertThat(mTransportBoundListenerStub.isCalledForTransport(mTransport2.stub)).isTrue();
assertThat(mTransportBoundListenerStub.isCalledForTransport(mTransport1.binderInterface))
.isFalse();
assertThat(mTransportBoundListenerStub.isCalledForTransport(mTransport2.binderInterface))
.isTrue();
}
@Test
@@ -265,8 +294,10 @@ public class TransportManagerTest {
Arrays.asList(mTransport1.componentName, mTransport2.componentName));
assertThat(transportManager.getBoundTransportNames()).asList().containsExactlyElementsIn(
Arrays.asList(mTransport1.name, mTransport2.name));
assertThat(mTransportBoundListenerStub.isCalledForTransport(mTransport1.stub)).isFalse();
assertThat(mTransportBoundListenerStub.isCalledForTransport(mTransport2.stub)).isFalse();
assertThat(mTransportBoundListenerStub.isCalledForTransport(mTransport1.binderInterface))
.isFalse();
assertThat(mTransportBoundListenerStub.isCalledForTransport(mTransport2.binderInterface))
.isFalse();
}
@Test
@@ -280,8 +311,10 @@ public class TransportManagerTest {
Arrays.asList(mTransport1.componentName, mTransport2.componentName));
assertThat(transportManager.getBoundTransportNames()).asList().containsExactlyElementsIn(
Arrays.asList(mTransport1.name, mTransport2.name));
assertThat(mTransportBoundListenerStub.isCalledForTransport(mTransport1.stub)).isFalse();
assertThat(mTransportBoundListenerStub.isCalledForTransport(mTransport2.stub)).isFalse();
assertThat(mTransportBoundListenerStub.isCalledForTransport(mTransport1.binderInterface))
.isFalse();
assertThat(mTransportBoundListenerStub.isCalledForTransport(mTransport2.binderInterface))
.isFalse();
}
@Test
@@ -295,8 +328,10 @@ public class TransportManagerTest {
Arrays.asList(mTransport1.componentName, mTransport2.componentName));
assertThat(transportManager.getBoundTransportNames()).asList().containsExactlyElementsIn(
Arrays.asList(mTransport1.name, mTransport2.name));
assertThat(mTransportBoundListenerStub.isCalledForTransport(mTransport1.stub)).isFalse();
assertThat(mTransportBoundListenerStub.isCalledForTransport(mTransport2.stub)).isTrue();
assertThat(mTransportBoundListenerStub.isCalledForTransport(mTransport1.binderInterface))
.isFalse();
assertThat(mTransportBoundListenerStub.isCalledForTransport(mTransport2.binderInterface))
.isTrue();
}
@Test
@@ -305,9 +340,9 @@ public class TransportManagerTest {
Arrays.asList(mTransport1, mTransport2), mTransport1.name);
assertThat(transportManager.getTransportBinder(mTransport1.name)).isEqualTo(
mTransport1.stub);
mTransport1.binderInterface);
assertThat(transportManager.getTransportBinder(mTransport2.name)).isEqualTo(
mTransport2.stub);
mTransport2.binderInterface);
}
@Test
@@ -326,7 +361,7 @@ public class TransportManagerTest {
assertThat(transportManager.getTransportBinder(mTransport1.name)).isNull();
assertThat(transportManager.getTransportBinder(mTransport2.name)).isEqualTo(
mTransport2.stub);
mTransport2.binderInterface);
}
@Test
@@ -356,7 +391,8 @@ public class TransportManagerTest {
TransportManager transportManager = createTransportManagerAndSetUpTransports(
Arrays.asList(mTransport1, mTransport2), mTransport1.name);
assertThat(transportManager.getCurrentTransportBinder()).isEqualTo(mTransport1.stub);
assertThat(transportManager.getCurrentTransportBinder())
.isEqualTo(mTransport1.binderInterface);
}
@Test
@@ -375,8 +411,10 @@ public class TransportManagerTest {
TransportManager transportManager = createTransportManagerAndSetUpTransports(
Arrays.asList(mTransport1, mTransport2), mTransport1.name);
assertThat(transportManager.getTransportName(mTransport1.stub)).isEqualTo(mTransport1.name);
assertThat(transportManager.getTransportName(mTransport2.stub)).isEqualTo(mTransport2.name);
assertThat(transportManager.getTransportName(mTransport1.binderInterface))
.isEqualTo(mTransport1.name);
assertThat(transportManager.getTransportName(mTransport2.binderInterface))
.isEqualTo(mTransport2.name);
}
@Test
@@ -385,8 +423,9 @@ public class TransportManagerTest {
createTransportManagerAndSetUpTransports(Collections.singletonList(mTransport2),
Collections.singletonList(mTransport1), mTransport1.name);
assertThat(transportManager.getTransportName(mTransport1.stub)).isNull();
assertThat(transportManager.getTransportName(mTransport2.stub)).isEqualTo(mTransport2.name);
assertThat(transportManager.getTransportName(mTransport1.binderInterface)).isNull();
assertThat(transportManager.getTransportName(mTransport2.binderInterface))
.isEqualTo(mTransport2.name);
}
@Test
@@ -499,7 +538,7 @@ public class TransportManagerTest {
TransportManager transportManager =
createTransportManagerAndSetUpTransports(
Arrays.asList(mTransport1, mTransport2), mTransport1.name);
transportManager.describeTransport(
transportManager.updateTransportAttributes(
mTransport1.componentName, "newName", null, "destinationString", null, null);
TransportClient transportClient =
@@ -514,7 +553,7 @@ public class TransportManagerTest {
TransportManager transportManager =
createTransportManagerAndSetUpTransports(
Arrays.asList(mTransport1, mTransport2), mTransport1.name);
transportManager.describeTransport(
transportManager.updateTransportAttributes(
mTransport1.componentName, "newName", null, "destinationString", null, null);
TransportClient transportClient =
@@ -529,7 +568,7 @@ public class TransportManagerTest {
TransportManager transportManager =
createTransportManagerAndSetUpTransports(
Arrays.asList(mTransport1, mTransport2), mTransport1.name);
transportManager.describeTransport(
transportManager.updateTransportAttributes(
mTransport1.componentName, "newName", null, "destinationString", null, null);
String transportName = transportManager.getTransportName(mTransport1.componentName);
@@ -549,6 +588,48 @@ public class TransportManagerTest {
assertThat(transportManager.isTransportRegistered(mTransport2.name)).isFalse();
}
@Test
public void getTransportAttributes_forRegisteredTransport_returnsCorrectValues()
throws Exception {
TransportManager transportManager =
createTransportManagerAndSetUpTransports(
Collections.singletonList(mTransport1),
mTransport1.name);
assertThat(transportManager.getTransportConfigurationIntent(mTransport1.name))
.isEqualTo(mTransport1.binderInterface.configurationIntent());
assertThat(transportManager.getTransportDataManagementIntent(mTransport1.name))
.isEqualTo(mTransport1.binderInterface.dataManagementIntent());
assertThat(transportManager.getTransportDataManagementLabel(mTransport1.name))
.isEqualTo(mTransport1.binderInterface.dataManagementLabel());
assertThat(transportManager.getTransportDirName(mTransport1.name))
.isEqualTo(mTransport1.binderInterface.transportDirName());
}
@Test
public void getTransportAttributes_forUnregisteredTransport_throws()
throws Exception {
TransportManager transportManager =
createTransportManagerAndSetUpTransports(
Collections.singletonList(mTransport1),
Collections.singletonList(mTransport2),
mTransport1.name);
expectThrows(
TransportNotRegisteredException.class,
() -> transportManager.getTransportConfigurationIntent(mTransport2.name));
expectThrows(
TransportNotRegisteredException.class,
() -> transportManager.getTransportDataManagementIntent(
mTransport2.name));
expectThrows(
TransportNotRegisteredException.class,
() -> transportManager.getTransportDataManagementLabel(mTransport2.name));
expectThrows(
TransportNotRegisteredException.class,
() -> transportManager.getTransportDirName(mTransport2.name));
}
private void setUpPackageWithTransports(String packageName, List<TransportInfo> transports,
int flags) throws Exception {
PackageInfo packageInfo = new PackageInfo();
@@ -616,10 +697,12 @@ public class TransportManagerTest {
assertThat(transportManager.getBoundTransportNames()).asList().containsExactlyElementsIn(
availableTransportsNames);
for (TransportInfo transport : availableTransports) {
assertThat(mTransportBoundListenerStub.isCalledForTransport(transport.stub)).isTrue();
assertThat(mTransportBoundListenerStub.isCalledForTransport(transport.binderInterface))
.isTrue();
}
for (TransportInfo transport : unavailableTransports) {
assertThat(mTransportBoundListenerStub.isCalledForTransport(transport.stub)).isFalse();
assertThat(mTransportBoundListenerStub.isCalledForTransport(transport.binderInterface))
.isFalse();
}
mTransportBoundListenerStub.resetState();
@@ -627,19 +710,46 @@ public class TransportManagerTest {
return transportManager;
}
private static <T extends Throwable> void expectThrows(
Class<T> throwableClass, ThrowingRunnable runnable) {
try {
runnable.runOrThrow();
fail("Expected to throw " + throwableClass.getSimpleName());
} catch (Throwable t) {
assertThat(t).isInstanceOf(throwableClass);
}
}
private static class TransportInfo {
public final String packageName;
public final String name;
public final ComponentName componentName;
public final BackupTransportStub stub;
public final IBackupTransport binderInterface;
public final IBinder binder;
TransportInfo(String packageName, String name) {
TransportInfo(
String packageName,
String name,
@Nullable Intent configurationIntent,
String currentDestinationString,
@Nullable Intent dataManagementIntent,
String dataManagementLabel) {
this.packageName = packageName;
this.name = name;
this.componentName = new ComponentName(packageName, name);
this.stub = new BackupTransportStub(name);
this.binder = mock(IBinder.class);
IBackupTransport transport = mock(IBackupTransport.class);
try {
when(transport.name()).thenReturn(name);
when(transport.configurationIntent()).thenReturn(configurationIntent);
when(transport.currentDestinationString()).thenReturn(currentDestinationString);
when(transport.dataManagementIntent()).thenReturn(dataManagementIntent);
when(transport.dataManagementLabel()).thenReturn(dataManagementLabel);
} catch (RemoteException e) {
// Only here to mock methods that throw RemoteException
}
this.binderInterface = transport;
}
}
}

View File

@@ -1,179 +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 android.app.backup.RestoreDescription;
import android.app.backup.RestoreSet;
import android.content.Intent;
import android.content.pm.PackageInfo;
import android.os.IBinder;
import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
import com.android.internal.backup.IBackupTransport;
/**
* Stub backup transport, doing nothing and returning default values.
*/
public class BackupTransportStub implements IBackupTransport {
private final String mName;
public BackupTransportStub(String name) {
mName = name;
}
@Override
public IBinder asBinder() {
return null;
}
@Override
public String name() throws RemoteException {
return mName;
}
@Override
public Intent configurationIntent() throws RemoteException {
return null;
}
@Override
public String currentDestinationString() throws RemoteException {
return null;
}
@Override
public Intent dataManagementIntent() throws RemoteException {
return null;
}
@Override
public String dataManagementLabel() throws RemoteException {
return null;
}
@Override
public String transportDirName() throws RemoteException {
return null;
}
@Override
public long requestBackupTime() throws RemoteException {
return 0;
}
@Override
public int initializeDevice() throws RemoteException {
return 0;
}
@Override
public int performBackup(PackageInfo packageInfo, ParcelFileDescriptor inFd, int flags)
throws RemoteException {
return 0;
}
@Override
public int clearBackupData(PackageInfo packageInfo) throws RemoteException {
return 0;
}
@Override
public int finishBackup() throws RemoteException {
return 0;
}
@Override
public RestoreSet[] getAvailableRestoreSets() throws RemoteException {
return new RestoreSet[0];
}
@Override
public long getCurrentRestoreSet() throws RemoteException {
return 0;
}
@Override
public int startRestore(long token, PackageInfo[] packages) throws RemoteException {
return 0;
}
@Override
public RestoreDescription nextRestorePackage() throws RemoteException {
return null;
}
@Override
public int getRestoreData(ParcelFileDescriptor outFd) throws RemoteException {
return 0;
}
@Override
public void finishRestore() throws RemoteException {
}
@Override
public long requestFullBackupTime() throws RemoteException {
return 0;
}
@Override
public int performFullBackup(PackageInfo targetPackage, ParcelFileDescriptor socket,
int flags)
throws RemoteException {
return 0;
}
@Override
public int checkFullBackupSize(long size) throws RemoteException {
return 0;
}
@Override
public int sendBackupData(int numBytes) throws RemoteException {
return 0;
}
@Override
public void cancelFullBackup() throws RemoteException {
}
@Override
public boolean isAppEligibleForBackup(PackageInfo targetPackage, boolean isFullBackup)
throws RemoteException {
return false;
}
@Override
public long getBackupQuota(String packageName, boolean isFullBackup)
throws RemoteException {
return 0;
}
@Override
public int getNextFullRestoreDataChunk(ParcelFileDescriptor socket) throws RemoteException {
return 0;
}
@Override
public int abortFullRestore() throws RemoteException {
return 0;
}
}

View File

@@ -117,7 +117,7 @@ public class BackupManagerServiceTest {
"dataManagementLabel");
verify(mTransportManager)
.describeTransport(
.updateTransportAttributes(
eq(TRANSPORT_COMPONENT),
eq(TRANSPORT_NAME),
eq(configurationIntent),
@@ -247,7 +247,7 @@ public class BackupManagerServiceTest {
null);
verify(mTransportManager)
.describeTransport(
.updateTransportAttributes(
eq(TRANSPORT_COMPONENT),
eq(TRANSPORT_NAME),
eq(configurationIntent),
@@ -274,7 +274,7 @@ public class BackupManagerServiceTest {
"dataManagementLabel");
verify(mTransportManager)
.describeTransport(
.updateTransportAttributes(
eq(TRANSPORT_COMPONENT),
eq(TRANSPORT_NAME),
eq(configurationIntent),