Merge changes from topic "getBackupManagerMonitor"

* changes:
  Unhide BackupTransport#getBackupManagerMonitor()
  Ask transport for a monitor during restore
  Pass agent logs to monitor after package B&R
This commit is contained in:
Sarp Misoglu
2022-11-21 10:09:11 +00:00
committed by Android (Google) Code Review
11 changed files with 186 additions and 15 deletions

View File

@@ -1470,6 +1470,7 @@ package android.app.backup {
public class BackupManagerMonitor {
ctor public BackupManagerMonitor();
method public void onEvent(android.os.Bundle);
field public static final String EXTRA_LOG_AGENT_LOGGING_RESULTS = "android.app.backup.extra.LOG_AGENT_LOGGING_RESULTS";
field public static final String EXTRA_LOG_CANCEL_ALL = "android.app.backup.extra.LOG_CANCEL_ALL";
field public static final String EXTRA_LOG_EVENT_CATEGORY = "android.app.backup.extra.LOG_EVENT_CATEGORY";
field public static final String EXTRA_LOG_EVENT_ID = "android.app.backup.extra.LOG_EVENT_ID";
@@ -1488,6 +1489,7 @@ package android.app.backup {
field public static final int LOG_EVENT_CATEGORY_AGENT = 2; // 0x2
field public static final int LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY = 3; // 0x3
field public static final int LOG_EVENT_CATEGORY_TRANSPORT = 1; // 0x1
field public static final int LOG_EVENT_ID_AGENT_LOGGING_RESULTS = 52; // 0x34
field public static final int LOG_EVENT_ID_APK_NOT_INSTALLED = 40; // 0x28
field public static final int LOG_EVENT_ID_APP_HAS_NO_AGENT = 28; // 0x1c
field public static final int LOG_EVENT_ID_BACKUP_DISABLED = 13; // 0xd
@@ -1562,6 +1564,7 @@ package android.app.backup {
method public int finishBackup();
method public void finishRestore();
method public android.app.backup.RestoreSet[] getAvailableRestoreSets();
method @Nullable public android.app.backup.BackupManagerMonitor getBackupManagerMonitor();
method public long getBackupQuota(String, boolean);
method public android.os.IBinder getBinder();
method public long getCurrentRestoreSet();

View File

@@ -129,6 +129,13 @@ public class BackupManagerMonitor {
*/
public static final String EXTRA_LOG_OLD_VERSION = "android.app.backup.extra.LOG_OLD_VERSION";
/**
* ParcelableList: when we have an event of id LOG_EVENT_ID_AGENT_LOGGING_RESULTS we send a list
* of {@link android.app.backup.BackupRestoreEventLogger.DataTypeResult}.
*/
public static final String EXTRA_LOG_AGENT_LOGGING_RESULTS =
"android.app.backup.extra.LOG_AGENT_LOGGING_RESULTS";
// TODO complete this list with all log messages. And document properly.
public static final int LOG_EVENT_ID_FULL_BACKUP_CANCEL = 4;
public static final int LOG_EVENT_ID_ILLEGAL_KEY = 5;
@@ -171,15 +178,10 @@ public class BackupManagerMonitor {
public static final int LOG_EVENT_ID_WIDGET_UNKNOWN_VERSION = 48;
public static final int LOG_EVENT_ID_NO_PACKAGES = 49;
public static final int LOG_EVENT_ID_TRANSPORT_IS_NULL = 50;
/** The transport returned {@link BackupTransport#TRANSPORT_NON_INCREMENTAL_BACKUP_REQUIRED}. */
public static final int LOG_EVENT_ID_TRANSPORT_NON_INCREMENTAL_BACKUP_REQUIRED = 51;
/**
* The transport returned {@link BackupTransport#TRANSPORT_NON_INCREMENTAL_BACKUP_REQUIRED}.
*/
public static final int LOG_EVENT_ID_TRANSPORT_NON_INCREMENTAL_BACKUP_REQUIRED = 51;
public static final int LOG_EVENT_ID_AGENT_LOGGING_RESULTS = 52;
/**
* This method will be called each time something important happens on BackupManager.

View File

@@ -661,8 +661,6 @@ public class BackupTransport {
*
* <p>Backups requested from outside the framework may pass in a monitor with the request,
* however backups initiated by the framework will call this method to retrieve one.
*
* @hide
*/
@Nullable
public BackupManagerMonitor getBackupManagerMonitor() {

View File

@@ -23,11 +23,13 @@ import static com.android.server.backup.UserBackupManagerService.BACKUP_MANIFEST
import static com.android.server.backup.UserBackupManagerService.BACKUP_METADATA_FILENAME;
import static com.android.server.backup.UserBackupManagerService.SHARED_BACKUP_AGENT_PACKAGE;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
import android.app.ApplicationThreadConstants;
import android.app.IBackupAgent;
import android.app.backup.BackupTransport;
import android.app.backup.FullBackupDataOutput;
import android.app.backup.IBackupManagerMonitor;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
@@ -42,6 +44,7 @@ import com.android.server.backup.OperationStorage.OpType;
import com.android.server.backup.UserBackupManagerService;
import com.android.server.backup.remote.RemoteCall;
import com.android.server.backup.utils.BackupEligibilityRules;
import com.android.server.backup.utils.BackupManagerMonitorUtils;
import com.android.server.backup.utils.FullBackupUtils;
import java.io.File;
@@ -60,12 +63,13 @@ public class FullBackupEngine {
private BackupRestoreTask mTimeoutMonitor;
private IBackupAgent mAgent;
private boolean mIncludeApks;
private PackageInfo mPkg;
private final PackageInfo mPkg;
private final long mQuota;
private final int mOpToken;
private final int mTransportFlags;
private final BackupAgentTimeoutParameters mAgentTimeoutParameters;
private final BackupEligibilityRules mBackupEligibilityRules;
@Nullable private final IBackupManagerMonitor mMonitor;
class FullBackupRunner implements Runnable {
private final @UserIdInt int mUserId;
@@ -193,7 +197,8 @@ public class FullBackupEngine {
long quota,
int opToken,
int transportFlags,
BackupEligibilityRules backupEligibilityRules) {
BackupEligibilityRules backupEligibilityRules,
IBackupManagerMonitor monitor) {
this.backupManagerService = backupManagerService;
mOutput = output;
mPreflightHook = preflightHook;
@@ -208,6 +213,7 @@ public class FullBackupEngine {
backupManagerService.getAgentTimeoutParameters(),
"Timeout parameters cannot be null");
mBackupEligibilityRules = backupEligibilityRules;
mMonitor = monitor;
}
public int preflightCheck() throws RemoteException {
@@ -260,6 +266,8 @@ public class FullBackupEngine {
}
result = BackupTransport.TRANSPORT_OK;
}
BackupManagerMonitorUtils.monitorAgentLoggingResults(mMonitor, mPkg, mAgent);
} catch (IOException e) {
Slog.e(TAG, "Error backing up " + mPkg.packageName + ": " + e.getMessage());
result = BackupTransport.AGENT_ERROR;

View File

@@ -420,7 +420,8 @@ public class PerformAdbBackupTask extends FullBackupTask implements BackupRestor
Long.MAX_VALUE,
mCurrentOpToken,
/*transportFlags=*/ 0,
mBackupEligibilityRules);
mBackupEligibilityRules,
/* monitor= */ null);
sendOnBackupPackage(isSharedStorage ? "Shared storage" : pkg.packageName);
// Don't need to check preflight result as there is no preflight hook.

View File

@@ -882,7 +882,8 @@ public class PerformFullTransportBackupTask extends FullBackupTask implements Ba
mQuota,
mCurrentOpToken,
mTransportFlags,
mBackupEligibilityRules);
mBackupEligibilityRules,
mMonitor);
try {
try {
if (!mIsCancelled) {

View File

@@ -68,6 +68,7 @@ import com.android.server.backup.transport.BackupTransportClient;
import com.android.server.backup.transport.TransportConnection;
import com.android.server.backup.transport.TransportNotAvailableException;
import com.android.server.backup.utils.BackupEligibilityRules;
import com.android.server.backup.utils.BackupManagerMonitorUtils;
import libcore.io.IoUtils;
@@ -697,6 +698,8 @@ public class KeyValueBackupTask implements BackupRestoreTask, Runnable {
try {
extractAgentData(mCurrentPackage);
BackupManagerMonitorUtils.monitorAgentLoggingResults(
mReporter.getMonitor(), mCurrentPackage, mAgent);
int status = sendDataToTransport(mCurrentPackage);
cleanUpAgentForTransportStatus(status);
} catch (AgentException | TaskException e) {

View File

@@ -405,6 +405,12 @@ public class PerformUnifiedRestoreTask implements BackupRestoreTask {
BackupTransportClient transport =
mTransportConnection.connectOrThrow("PerformUnifiedRestoreTask.startRestore()");
// If the requester of the restore has not passed in a monitor, we ask the transport
// for one.
if (mMonitor == null) {
mMonitor = transport.getBackupManagerMonitor();
}
mStatus = transport.startRestore(mToken, packages);
if (mStatus != BackupTransport.TRANSPORT_OK) {
Slog.e(TAG, "Transport error " + mStatus + "; no restore possible");
@@ -885,6 +891,10 @@ public class PerformUnifiedRestoreTask implements BackupRestoreTask {
OpType.RESTORE_WAIT);
mAgent.doRestoreFinished(mEphemeralOpToken,
backupManagerService.getBackupManagerBinder());
// Ask the agent for logs after doRestoreFinished() to allow it to finalize its logs.
BackupManagerMonitorUtils.monitorAgentLoggingResults(mMonitor, mCurrentPackage, mAgent);
// If we get this far, the callback or timeout will schedule the
// next restore state, so we're done
} catch (Exception e) {

View File

@@ -16,23 +16,42 @@
package com.android.server.backup.utils;
import static android.app.backup.BackupManagerMonitor.EXTRA_LOG_AGENT_LOGGING_RESULTS;
import static android.app.backup.BackupManagerMonitor.EXTRA_LOG_EVENT_PACKAGE_NAME;
import static android.app.backup.BackupManagerMonitor.LOG_EVENT_CATEGORY_AGENT;
import static android.app.backup.BackupManagerMonitor.LOG_EVENT_ID_AGENT_LOGGING_RESULTS;
import static com.android.server.backup.BackupManagerService.DEBUG;
import static com.android.server.backup.BackupManagerService.TAG;
import android.annotation.Nullable;
import android.app.IBackupAgent;
import android.app.backup.BackupManagerMonitor;
import android.app.backup.BackupRestoreEventLogger;
import android.app.backup.IBackupManagerMonitor;
import android.content.pm.PackageInfo;
import android.os.Bundle;
import android.os.RemoteException;
import android.util.Slog;
import com.android.internal.infra.AndroidFuture;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
/**
* Utility methods to communicate with BackupManagerMonitor.
*/
public class BackupManagerMonitorUtils {
/**
* Timeout for how long we wait before we give up on getting logs from a {@link IBackupAgent}.
* We expect this to be very fast since the agent immediately returns whatever logs have been
* accumulated. The timeout adds a bit more security and ensures we don't hang the B&R waiting
* for non-essential logs.
*/
private static final int AGENT_LOGGER_RESULTS_TIMEOUT_MILLIS = 500;
/**
* Notifies monitor about the event.
*
@@ -79,6 +98,48 @@ public class BackupManagerMonitorUtils {
return null;
}
/**
* Extracts logging results from the provided {@code agent} and notifies the {@code monitor}
* about them.
*
* <p>Note that this method does two separate binder calls (one to the agent and one to the
* monitor).
*
* @param monitor - implementation of {@link IBackupManagerMonitor} to notify.
* @param pkg - package the {@code agent} belongs to.
* @param agent - the {@link IBackupAgent} to retrieve logs from.
* @return {@code null} if the monitor is null. {@code monitor} if we fail to retrieve the logs
* from the {@code agent}. Otherwise, the result of {@link
* #monitorEvent(IBackupManagerMonitor, int, PackageInfo, int, Bundle)}.
*/
public static IBackupManagerMonitor monitorAgentLoggingResults(
@Nullable IBackupManagerMonitor monitor, PackageInfo pkg, IBackupAgent agent) {
if (monitor == null) {
return null;
}
try {
AndroidFuture<List<BackupRestoreEventLogger.DataTypeResult>> resultsFuture =
new AndroidFuture<>();
agent.getLoggerResults(resultsFuture);
Bundle loggerResultsBundle = new Bundle();
loggerResultsBundle.putParcelableList(
EXTRA_LOG_AGENT_LOGGING_RESULTS,
resultsFuture.get(AGENT_LOGGER_RESULTS_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS));
return BackupManagerMonitorUtils.monitorEvent(
monitor,
LOG_EVENT_ID_AGENT_LOGGING_RESULTS,
pkg,
LOG_EVENT_CATEGORY_AGENT,
loggerResultsBundle);
} catch (TimeoutException e) {
Slog.w(TAG, "Timeout while waiting to retrieve logging results from agent", e);
} catch (Exception e) {
Slog.w(TAG, "Failed to retrieve logging results from agent", e);
}
return monitor;
}
/**
* Adds given key-value pair in the bundle and returns the bundle. If bundle was null it will
* be created.

View File

@@ -77,6 +77,8 @@ import android.app.backup.BackupAgent;
import android.app.backup.BackupDataInput;
import android.app.backup.BackupDataOutput;
import android.app.backup.BackupManager;
import android.app.backup.BackupManagerMonitor;
import android.app.backup.BackupRestoreEventLogger;
import android.app.backup.BackupTransport;
import android.app.backup.IBackupCallback;
import android.app.backup.IBackupManager;
@@ -89,6 +91,7 @@ import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManagerInternal;
import android.net.Uri;
import android.os.Bundle;
import android.os.ConditionVariable;
import android.os.DeadObjectException;
import android.os.Handler;
@@ -100,6 +103,7 @@ import android.platform.test.annotations.Presubmit;
import android.util.Pair;
import com.android.internal.backup.IBackupTransport;
import com.android.internal.infra.AndroidFuture;
import com.android.server.EventLogTags;
import com.android.server.LocalServices;
import com.android.server.backup.BackupRestoreTask;
@@ -131,6 +135,7 @@ import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.ArgumentMatcher;
import org.mockito.InOrder;
import org.mockito.Mock;
@@ -1447,6 +1452,36 @@ public class KeyValueBackupTaskTest {
EventLogTags.BACKUP_PACKAGE, PACKAGE_1.packageName, Files.size(backupData));
}
@Test
public void testRunTask_whenFinishBackupSucceeds_sendsAgentLogsToMonitor() throws Exception {
TransportMock transportMock = setUpInitializedTransport(mTransport);
AgentMock agentMock = setUpAgentWithData(PACKAGE_1);
KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1);
// Mock the agent logging and returning its logs.
List<BackupRestoreEventLogger.DataTypeResult> results = new ArrayList<>();
results.add(new BackupRestoreEventLogger.DataTypeResult("testDataTypeResult"));
doAnswer(
invocation -> {
AndroidFuture<List<BackupRestoreEventLogger.DataTypeResult>> in =
invocation.getArgument(0);
in.complete(results);
return null;
})
.when(agentMock.agentBinder)
.getLoggerResults(any());
runTask(task);
ArgumentCaptor<Bundle> bundleCaptor = ArgumentCaptor.forClass(Bundle.class);
verify(mMonitor).onEvent(bundleCaptor.capture());
Bundle eventBundle = bundleCaptor.getValue();
List<BackupRestoreEventLogger.DataTypeResult> sentLoggingResults =
eventBundle.getParcelableArrayList(
BackupManagerMonitor.EXTRA_LOG_AGENT_LOGGING_RESULTS,
BackupRestoreEventLogger.DataTypeResult.class);
assertThat(sentLoggingResults.get(0).getDataType()).isEqualTo("testDataTypeResult");
}
@Test
public void testRunTask_whenFinishBackupSucceeds_notifiesCorrectly() throws Exception {
TransportMock transportMock = setUpInitializedTransport(mTransport);

View File

@@ -21,13 +21,20 @@ import static android.app.backup.BackupManagerMonitor.EXTRA_LOG_EVENT_ID;
import static android.app.backup.BackupManagerMonitor.EXTRA_LOG_EVENT_PACKAGE_LONG_VERSION;
import static android.app.backup.BackupManagerMonitor.EXTRA_LOG_EVENT_PACKAGE_NAME;
import static android.app.backup.BackupManagerMonitor.EXTRA_LOG_EVENT_PACKAGE_VERSION;
import static android.app.backup.BackupManagerMonitor.LOG_EVENT_CATEGORY_AGENT;
import static android.app.backup.BackupManagerMonitor.LOG_EVENT_ID_AGENT_LOGGING_RESULTS;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import android.app.IBackupAgent;
import android.app.backup.BackupManagerMonitor;
import android.app.backup.BackupRestoreEventLogger;
import android.app.backup.IBackupManagerMonitor;
import android.content.pm.PackageInfo;
import android.os.Bundle;
@@ -37,6 +44,8 @@ import android.platform.test.annotations.Presubmit;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
import com.android.internal.infra.AndroidFuture;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -44,6 +53,9 @@ import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import java.util.ArrayList;
import java.util.List;
@SmallTest
@Presubmit
@RunWith(AndroidJUnit4.class)
@@ -142,6 +154,44 @@ public class BackupManagerMonitorUtilsTest {
assertThat(eventBundle.getString("key2")).isEqualTo("value2");
}
@Test
public void monitorAgentLoggingResults_fillsBundleCorrectly() throws Exception {
PackageInfo packageInfo = new PackageInfo();
packageInfo.packageName = "test.package";
// Mock an agent that returns a logging result.
IBackupAgent agent = spy(IBackupAgent.class);
List<BackupRestoreEventLogger.DataTypeResult> loggingResults = new ArrayList<>();
loggingResults.add(new BackupRestoreEventLogger.DataTypeResult("testLoggingResult"));
doAnswer(
invocation -> {
AndroidFuture<List<BackupRestoreEventLogger.DataTypeResult>> in =
invocation.getArgument(0);
in.complete(loggingResults);
return null;
})
.when(agent)
.getLoggerResults(any());
IBackupManagerMonitor result =
BackupManagerMonitorUtils.monitorAgentLoggingResults(
mMonitorMock, packageInfo, agent);
assertThat(result).isEqualTo(mMonitorMock);
ArgumentCaptor<Bundle> bundleCaptor = ArgumentCaptor.forClass(Bundle.class);
verify(mMonitorMock).onEvent(bundleCaptor.capture());
Bundle eventBundle = bundleCaptor.getValue();
assertThat(eventBundle.getInt(EXTRA_LOG_EVENT_ID))
.isEqualTo(LOG_EVENT_ID_AGENT_LOGGING_RESULTS);
assertThat(eventBundle.getInt(EXTRA_LOG_EVENT_CATEGORY))
.isEqualTo(LOG_EVENT_CATEGORY_AGENT);
assertThat(eventBundle.getString(EXTRA_LOG_EVENT_PACKAGE_NAME)).isEqualTo("test.package");
List<BackupRestoreEventLogger.DataTypeResult> filledLoggingResults =
eventBundle.getParcelableArrayList(
BackupManagerMonitor.EXTRA_LOG_AGENT_LOGGING_RESULTS,
BackupRestoreEventLogger.DataTypeResult.class);
assertThat(filledLoggingResults.get(0).getDataType()).isEqualTo("testLoggingResult");
}
@Test
public void putMonitoringExtraString_bundleExists_fillsBundleCorrectly() throws Exception {
Bundle bundle = new Bundle();
@@ -204,5 +254,4 @@ public class BackupManagerMonitorUtilsTest {
assertThat(result.size()).isEqualTo(1);
assertThat(result.getBoolean("key")).isTrue();
}
}