From d7f5fdb43bd99b3cf3ee1b48922a0593f2d0a6da Mon Sep 17 00:00:00 2001 From: Ruslan Tkhakokhov Date: Tue, 10 Dec 2019 11:15:45 +0000 Subject: [PATCH] Pass excluded keys to the backup agent in onRestore Pass the list of the keys excluded from KV restore to the backup agent to make it aware of what data has been removed (in case it has any application-level consequences) as well as the data that should be removed by the agent itself. Bug: 145126096 Test: atest CtsBackupTestCases Change-Id: I34415b149b379fb5bb67b0fbcd70ec9b9858acfe --- core/java/android/app/IBackupAgent.aidl | 13 +++++ core/java/android/app/backup/BackupAgent.java | 47 +++++++++++++++++-- .../restore/PerformUnifiedRestoreTask.java | 6 ++- 3 files changed, 61 insertions(+), 5 deletions(-) diff --git a/core/java/android/app/IBackupAgent.aidl b/core/java/android/app/IBackupAgent.aidl index d3d7c68d09924..254657e26f3a9 100644 --- a/core/java/android/app/IBackupAgent.aidl +++ b/core/java/android/app/IBackupAgent.aidl @@ -84,6 +84,19 @@ oneway interface IBackupAgent { long appVersionCode, in ParcelFileDescriptor newState, int token, IBackupManager callbackBinder); + /** + * Restore an entire data snapshot to the application and pass the list of excluded keys to the + * backup agent. + * + * @param excludedKeys List of keys to be excluded from the restore. It will be passed to the + * backup agent to make it aware of what data has been removed (in case it has any + * application-level implications) as well as the data that should be removed by the + * agent itself. + */ + void doRestoreWithExcludedKeys(in ParcelFileDescriptor data, + long appVersionCode, in ParcelFileDescriptor newState, + int token, IBackupManager callbackBinder, in List excludedKeys); + /** * Perform a "full" backup to the given file descriptor. The output file is presumed * to be a socket or other non-seekable, write-only data sink. When this method is diff --git a/core/java/android/app/backup/BackupAgent.java b/core/java/android/app/backup/BackupAgent.java index 24580b40aa298..20aa0647d261c 100644 --- a/core/java/android/app/backup/BackupAgent.java +++ b/core/java/android/app/backup/BackupAgent.java @@ -45,7 +45,10 @@ import org.xmlpull.v1.XmlPullParserException; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; +import java.util.Collections; +import java.util.HashSet; import java.util.LinkedList; +import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.CountDownLatch; @@ -326,6 +329,28 @@ public abstract class BackupAgent extends ContextWrapper { onRestore(data, (int) appVersionCode, newState); } + /** + * New version of {@link #onRestore(BackupDataInput, long, android.os.ParcelFileDescriptor)} + * that has a list of keys to be excluded from the restore. Key/value pairs for which the key + * is present in {@code excludedKeys} have already been excluded from the restore data by the + * system. The list is passed to the agent to make it aware of what data has been removed (in + * case it has any application-level consequences) as well as the data that should be removed + * by the agent itself. + * + * The default implementation calls {@link #onRestore(BackupDataInput, long, + * android.os.ParcelFileDescriptor)}. + * + * @param excludedKeys A list of keys to be excluded from restore. + * + * @hide + */ + public void onRestore(BackupDataInput data, long appVersionCode, + ParcelFileDescriptor newState, + Set excludedKeys) + throws IOException { + onRestore(data, appVersionCode, newState); + } + /** * The application is having its entire file system contents backed up. {@code data} * points to the backup destination, and the app has the opportunity to choose which @@ -1016,8 +1041,22 @@ public abstract class BackupAgent extends ContextWrapper { @Override public void doRestore(ParcelFileDescriptor data, long appVersionCode, - ParcelFileDescriptor newState, - int token, IBackupManager callbackBinder) throws RemoteException { + ParcelFileDescriptor newState, int token, IBackupManager callbackBinder) + throws RemoteException { + doRestoreInternal(data, appVersionCode, newState, token, callbackBinder, + /* excludedKeys */ null); + } + + @Override + public void doRestoreWithExcludedKeys(ParcelFileDescriptor data, long appVersionCode, + ParcelFileDescriptor newState, int token, IBackupManager callbackBinder, + List excludedKeys) throws RemoteException { + doRestoreInternal(data, appVersionCode, newState, token, callbackBinder, excludedKeys); + } + + private void doRestoreInternal(ParcelFileDescriptor data, long appVersionCode, + ParcelFileDescriptor newState, int token, IBackupManager callbackBinder, + List excludedKeys) throws RemoteException { // Ensure that we're running with the app's normal permission level long ident = Binder.clearCallingIdentity(); @@ -1029,7 +1068,9 @@ public abstract class BackupAgent extends ContextWrapper { BackupDataInput input = new BackupDataInput(data.getFileDescriptor()); try { - BackupAgent.this.onRestore(input, appVersionCode, newState); + BackupAgent.this.onRestore(input, appVersionCode, newState, + excludedKeys != null ? new HashSet<>(excludedKeys) + : Collections.emptySet()); } catch (IOException ex) { Log.d(TAG, "onRestore (" + BackupAgent.this.getClass().getName() + ") threw", ex); throw new RuntimeException(ex); diff --git a/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java b/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java index be597d7b40d68..de6a080f1330b 100644 --- a/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java +++ b/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java @@ -766,8 +766,10 @@ public class PerformUnifiedRestoreTask implements BackupRestoreTask { backupManagerService.prepareOperationTimeout( mEphemeralOpToken, restoreAgentTimeoutMillis, this, OP_TYPE_RESTORE_WAIT); startedAgentRestore = true; - mAgent.doRestore(mBackupData, appVersionCode, mNewState, - mEphemeralOpToken, backupManagerService.getBackupManagerBinder()); + mAgent.doRestoreWithExcludedKeys(mBackupData, appVersionCode, mNewState, + mEphemeralOpToken, backupManagerService.getBackupManagerBinder(), + mExcludedKeys.containsKey(packageName) + ? new ArrayList<>(mExcludedKeys.get(packageName)) : null); } catch (Exception e) { Slog.e(TAG, "Unable to call app for restore: " + packageName, e); EventLog.writeEvent(EventLogTags.RESTORE_AGENT_FAILURE,