From 38e7486d3870797f7cc6e2cd2f5b59462a66b1a6 Mon Sep 17 00:00:00 2001 From: Shreyas Basarge Date: Wed, 11 Jan 2017 17:15:58 +0000 Subject: [PATCH] Non incremental backup flag for requestBackup This cl adds a new requestBackup API to BackupManager that takes in an int flag to indicate whether the caller wants the entire key value set to be passed to the transport and not just a diff. Change-Id: Ia225797a58c4431fe742f2f116b257d006b30cd1 Bug: 33749084 Ref: go/request-backup-api-changes Test: GTS Test at ag/1774002 --- api/system-current.txt | 3 + .../src/com/android/commands/bmgr/Bmgr.java | 28 +++++-- .../android/app/backup/BackupManager.java | 44 +++++++++- .../android/app/backup/IBackupManager.aidl | 4 +- .../server/backup/BackupManagerService.java | 80 +++++++++++++------ .../com/android/server/backup/Trampoline.java | 5 +- 6 files changed, 127 insertions(+), 37 deletions(-) diff --git a/api/system-current.txt b/api/system-current.txt index 95b85d95de806..f530584f91698 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -6738,6 +6738,7 @@ package android.app.backup { method public boolean isBackupEnabled(); method public java.lang.String[] listAllTransports(); method public int requestBackup(java.lang.String[], android.app.backup.BackupObserver); + method public int requestBackup(java.lang.String[], android.app.backup.BackupObserver, int); method public int requestRestore(android.app.backup.RestoreObserver); method public java.lang.String selectBackupTransport(java.lang.String); method public void setAutoRestore(boolean); @@ -6748,6 +6749,8 @@ package android.app.backup { field public static final int ERROR_TRANSPORT_ABORTED = -1000; // 0xfffffc18 field public static final int ERROR_TRANSPORT_PACKAGE_REJECTED = -1002; // 0xfffffc16 field public static final int ERROR_TRANSPORT_QUOTA_EXCEEDED = -1005; // 0xfffffc13 + field public static final int FLAG_NON_INCREMENTAL_BACKUP = 1; // 0x1 + field public static final java.lang.String PACKAGE_MANAGER_SENTINEL = "@pm@"; field public static final int SUCCESS = 0; // 0x0 } diff --git a/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java b/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java index 5bf80765a7dec..780db5e26c35d 100644 --- a/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java +++ b/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java @@ -270,7 +270,7 @@ public final class Bmgr { } } - private void backupNowAllPackages() { + private void backupNowAllPackages(boolean nonIncrementalBackup) { int userId = UserHandle.USER_SYSTEM; IPackageManager mPm = IPackageManager.Stub.asInterface(ServiceManager.getService("package")); @@ -297,14 +297,19 @@ public final class Bmgr { System.err.println(BMGR_NOT_RUNNING_ERR); } } - backupNowPackages(packages); + backupNowPackages(packages, nonIncrementalBackup); } } - private void backupNowPackages(List packages) { + private void backupNowPackages(List packages, boolean nonIncrementalBackup) { + int flags = 0; + if (nonIncrementalBackup) { + flags |= BackupManager.FLAG_NON_INCREMENTAL_BACKUP; + } try { BackupObserver observer = new BackupObserver(); - int err = mBmgr.requestBackup(packages.toArray(new String[packages.size()]), observer); + int err = mBmgr.requestBackup(packages.toArray(new String[packages.size()]), observer, + flags); if (err == 0) { // Off and running -- wait for the backup to complete observer.waitForCompletion(); @@ -320,24 +325,31 @@ public final class Bmgr { private void doBackupNow() { String pkg; boolean backupAll = false; + boolean nonIncrementalBackup = false; ArrayList allPkgs = new ArrayList(); while ((pkg = nextArg()) != null) { if (pkg.equals("--all")) { backupAll = true; + } else if (pkg.equals("--non-incremental")) { + nonIncrementalBackup = true; + } else if (pkg.equals("--incremental")) { + nonIncrementalBackup = false; } else { allPkgs.add(pkg); } } if (backupAll) { if (allPkgs.size() == 0) { - System.out.println("Running backup for all packages."); - backupNowAllPackages(); + System.out.println("Running " + (nonIncrementalBackup ? "non-" : "") + + "incremental backup for all packages."); + backupNowAllPackages(nonIncrementalBackup); } else { System.err.println("Provide only '--all' flag or list of packages."); } } else if (allPkgs.size() > 0) { - System.out.println("Running backup for " + allPkgs.size() +" requested packages."); - backupNowPackages(allPkgs); + System.out.println("Running " + (nonIncrementalBackup ? "non-" : "") + + "incremental backup for " + allPkgs.size() +" requested packages."); + backupNowPackages(allPkgs, nonIncrementalBackup); } else { System.err.println("Provide '--all' flag or list of packages."); } diff --git a/core/java/android/app/backup/BackupManager.java b/core/java/android/app/backup/BackupManager.java index 80bc1364fa587..540683deeecb2 100644 --- a/core/java/android/app/backup/BackupManager.java +++ b/core/java/android/app/backup/BackupManager.java @@ -136,6 +136,27 @@ public class BackupManager { */ public static final String EXTRA_BACKUP_SERVICES_AVAILABLE = "backup_services_available"; + /** + * If this flag is passed to {@link #requestBackup(String[], BackupObserver, int)}, + * BackupManager will pass a blank old state to BackupAgents of requested packages. + * + * @hide + */ + @SystemApi + public static final int FLAG_NON_INCREMENTAL_BACKUP = 1; + + /** + * Use with {@link #requestBackup} to force backup of + * package meta data. Typically you do not need to explicitly request this be backed up as it is + * handled internally by the BackupManager. If you are requesting backups with + * FLAG_NON_INCREMENTAL, this package won't automatically be backed up and you have to + * explicitly request for its backup. + * + * @hide + */ + @SystemApi + public static final String PACKAGE_MANAGER_SENTINEL = "@pm@"; + private Context mContext; private static IBackupManager sService; @@ -484,13 +505,34 @@ public class BackupManager { */ @SystemApi public int requestBackup(String[] packages, BackupObserver observer) { + return requestBackup(packages, observer, 0); + } + + /** + * Request an immediate backup, providing an observer to which results of the backup operation + * will be published. The Android backup system will decide for each package whether it will + * be full app data backup or key/value-pair-based backup. + * + *

If this method returns {@link BackupManager#SUCCESS}, the OS will attempt to backup all + * provided packages using the remote transport. + * + * @param packages List of package names to backup. + * @param observer The {@link BackupObserver} to receive callbacks during the backup + * operation. Could be {@code null}. + * @param flags {@link #FLAG_NON_INCREMENTAL_BACKUP}. + * @return {@link BackupManager#SUCCESS} on success; nonzero on error. + * @throws IllegalArgumentException on null or empty {@code packages} param. + * @hide + */ + @SystemApi + public int requestBackup(String[] packages, BackupObserver observer, int flags) { checkServiceBinder(); if (sService != null) { try { BackupObserverWrapper observerWrapper = observer == null ? null : new BackupObserverWrapper(mContext, observer); - return sService.requestBackup(packages, observerWrapper); + return sService.requestBackup(packages, observerWrapper, flags); } catch (RemoteException e) { Log.e(TAG, "requestBackup() couldn't connect"); } diff --git a/core/java/android/app/backup/IBackupManager.aidl b/core/java/android/app/backup/IBackupManager.aidl index a320bbf9d178e..fe23c288c7ce8 100644 --- a/core/java/android/app/backup/IBackupManager.aidl +++ b/core/java/android/app/backup/IBackupManager.aidl @@ -357,7 +357,9 @@ interface IBackupManager { * @param observer The {@link BackupObserver} to receive callbacks during the backup * operation. * + * @param flags {@link BackupManager#FLAG_NON_INCREMENTAL_BACKUP}. + * * @return Zero on success; nonzero on error. */ - int requestBackup(in String[] packages, IBackupObserver observer); + int requestBackup(in String[] packages, IBackupObserver observer, int flags); } diff --git a/services/backup/java/com/android/server/backup/BackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java index 31ecb75c62603..7e825860ead35 100644 --- a/services/backup/java/com/android/server/backup/BackupManagerService.java +++ b/services/backup/java/com/android/server/backup/BackupManagerService.java @@ -577,15 +577,18 @@ public class BackupManagerService { public ArrayList fullPackages; public IBackupObserver observer; public boolean userInitiated; + public boolean nonIncrementalBackup; BackupParams(IBackupTransport transport, String dirName, ArrayList kvPackages, - ArrayList fullPackages, IBackupObserver observer, boolean userInitiated) { + ArrayList fullPackages, IBackupObserver observer, boolean userInitiated, + boolean nonIncrementalBackup) { this.transport = transport; this.dirName = dirName; this.kvPackages = kvPackages; this.fullPackages = fullPackages; this.observer = observer; this.userInitiated = userInitiated; + this.nonIncrementalBackup = nonIncrementalBackup; } } @@ -794,7 +797,7 @@ public class BackupManagerService { try { String dirName = transport.transportDirName(); PerformBackupTask pbt = new PerformBackupTask(transport, dirName, - queue, oldJournal, null, null, false); + queue, oldJournal, null, null, false, false /* nonIncremental */); Message pbtMessage = obtainMessage(MSG_BACKUP_RESTORE_STEP, pbt); sendMessage(pbtMessage); } catch (Exception e) { @@ -1033,7 +1036,8 @@ public class BackupManagerService { mWakelock.acquire(); PerformBackupTask pbt = new PerformBackupTask(params.transport, params.dirName, - kvQueue, null, params.observer, params.fullPackages, true); + kvQueue, null, params.observer, params.fullPackages, true, + params.nonIncrementalBackup); Message pbtMessage = obtainMessage(MSG_BACKUP_RESTORE_STEP, pbt); sendMessage(pbtMessage); break; @@ -2492,7 +2496,7 @@ public class BackupManagerService { return token; } - public int requestBackup(String[] packages, IBackupObserver observer) { + public int requestBackup(String[] packages, IBackupObserver observer, int flags) { mContext.enforceCallingPermission(android.Manifest.permission.BACKUP, "requestBackup"); if (packages == null || packages.length < 1) { @@ -2510,6 +2514,10 @@ public class BackupManagerService { ArrayList fullBackupList = new ArrayList<>(); ArrayList kvBackupList = new ArrayList<>(); for (String packageName : packages) { + if (PACKAGE_MANAGER_SENTINEL.equals(packageName)) { + kvBackupList.add(packageName); + continue; + } try { PackageInfo packageInfo = mPackageManager.getPackageInfo(packageName, PackageManager.GET_SIGNATURES); @@ -2543,9 +2551,12 @@ public class BackupManagerService { sendBackupFinished(observer, BackupManager.ERROR_TRANSPORT_ABORTED); return BackupManager.ERROR_TRANSPORT_ABORTED; } + + boolean nonIncrementalBackup = (flags & BackupManager.FLAG_NON_INCREMENTAL_BACKUP) != 0; + Message msg = mBackupHandler.obtainMessage(MSG_REQUEST_BACKUP); msg.obj = new BackupParams(transport, dirName, kvBackupList, fullBackupList, observer, - true); + true, nonIncrementalBackup); mBackupHandler.sendMessage(msg); return BackupManager.SUCCESS; } @@ -2673,17 +2684,20 @@ public class BackupManagerService { ParcelFileDescriptor mNewState; int mStatus; boolean mFinished; - boolean mUserInitiated; + final boolean mUserInitiated; + final boolean mNonIncremental; public PerformBackupTask(IBackupTransport transport, String dirName, ArrayList queue, File journal, IBackupObserver observer, - ArrayList pendingFullBackups, boolean userInitiated) { + ArrayList pendingFullBackups, boolean userInitiated, + boolean nonIncremental) { mTransport = transport; mOriginalQueue = queue; mJournal = journal; mObserver = observer; mPendingFullBackups = pendingFullBackups; mUserInitiated = userInitiated; + mNonIncremental = nonIncremental; mStateDir = new File(mBaseStateDir, dirName); @@ -2748,6 +2762,10 @@ public class BackupManagerService { // the way. mQueue = (ArrayList) mOriginalQueue.clone(); + // When the transport is forcing non-incremental key/value payloads, we send the + // metadata only if it explicitly asks for it. + boolean skipPm = mNonIncremental; + // The app metadata pseudopackage might also be represented in the // backup queue if apps have been added/removed since the last time // we performed a backup. Drop it from the working queue now that @@ -2758,6 +2776,7 @@ public class BackupManagerService { Slog.i(TAG, "Metadata in queue; eliding"); } mQueue.remove(i); + skipPm = false; break; } } @@ -2785,22 +2804,27 @@ public class BackupManagerService { } } - // The package manager doesn't have a proper etc, but since - // it's running here in the system process we can just set up its agent - // directly and use a synthetic BackupRequest. We always run this pass - // because it's cheap and this way we guarantee that we don't get out of - // step even if we're selecting among various transports at run time. - if (mStatus == BackupTransport.TRANSPORT_OK) { - PackageManagerBackupAgent pmAgent = new PackageManagerBackupAgent( - mPackageManager); - mStatus = invokeAgentForBackup(PACKAGE_MANAGER_SENTINEL, - IBackupAgent.Stub.asInterface(pmAgent.onBind()), mTransport); - addBackupTrace("PMBA invoke: " + mStatus); + if (skipPm) { + Slog.d(TAG, "Skipping backup of package metadata."); + executeNextState(BackupState.RUNNING_QUEUE); + } else { + // The package manager doesn't have a proper etc, but since + // it's running here in the system process we can just set up its agent + // directly and use a synthetic BackupRequest. We always run this pass + // because it's cheap and this way we guarantee that we don't get out of + // step even if we're selecting among various transports at run time. + if (mStatus == BackupTransport.TRANSPORT_OK) { + PackageManagerBackupAgent pmAgent = new PackageManagerBackupAgent( + mPackageManager); + mStatus = invokeAgentForBackup(PACKAGE_MANAGER_SENTINEL, + IBackupAgent.Stub.asInterface(pmAgent.onBind()), mTransport); + addBackupTrace("PMBA invoke: " + mStatus); - // Because the PMBA is a local instance, it has already executed its - // backup callback and returned. Blow away the lingering (spurious) - // pending timeout message for it. - mBackupHandler.removeMessages(MSG_TIMEOUT); + // Because the PMBA is a local instance, it has already executed its + // backup callback and returned. Blow away the lingering (spurious) + // pending timeout message for it. + mBackupHandler.removeMessages(MSG_TIMEOUT); + } } if (mStatus == BackupTransport.TRANSPORT_NOT_INITIALIZED) { @@ -3066,6 +3090,7 @@ public class BackupManagerService { if (DEBUG) Slog.d(TAG, "invokeAgentForBackup on " + packageName); addBackupTrace("invoking " + packageName); + File blankStateName = new File(mStateDir, "blank_state"); mSavedStateName = new File(mStateDir, packageName); mBackupDataName = new File(mDataDir, packageName + ".data"); mNewStateName = new File(mStateDir, packageName + ".new"); @@ -3088,9 +3113,10 @@ public class BackupManagerService { } // In a full backup, we pass a null ParcelFileDescriptor as - // the saved-state "file". This is by definition an incremental, - // so we build a saved state file to pass. - mSavedState = ParcelFileDescriptor.open(mSavedStateName, + // the saved-state "file". For key/value backups we pass the old state if + // an incremental backup is required, and a blank state otherwise. + mSavedState = ParcelFileDescriptor.open( + mNonIncremental ? blankStateName : mSavedStateName, ParcelFileDescriptor.MODE_READ_ONLY | ParcelFileDescriptor.MODE_CREATE); // Make an empty file if necessary @@ -3120,6 +3146,10 @@ public class BackupManagerService { e.toString()); agentErrorCleanup(); return BackupTransport.AGENT_ERROR; + } finally { + if (mNonIncremental) { + blankStateName.delete(); + } } // At this point the agent is off and running. The next thing to happen will diff --git a/services/backup/java/com/android/server/backup/Trampoline.java b/services/backup/java/com/android/server/backup/Trampoline.java index 312b878b284c9..d677f5ee04a8d 100644 --- a/services/backup/java/com/android/server/backup/Trampoline.java +++ b/services/backup/java/com/android/server/backup/Trampoline.java @@ -338,9 +338,10 @@ public class Trampoline extends IBackupManager.Stub { } @Override - public int requestBackup(String[] packages, IBackupObserver observer) throws RemoteException { + public int requestBackup(String[] packages, IBackupObserver observer, int flags) + throws RemoteException { BackupManagerService svc = mService; - return (svc != null) ? svc.requestBackup(packages, observer) : null; + return (svc != null) ? svc.requestBackup(packages, observer, flags) : null; } @Override