diff options
author | Christopher Tate <ctate@google.com> | 2016-06-17 13:24:02 -0700 |
---|---|---|
committer | Christopher Tate <ctate@google.com> | 2016-06-22 13:53:41 -0700 |
commit | 5cb5e89d770f474031e4ab30fb7f24c66333590a (patch) | |
tree | 187e55259a6e10550a0e0faf29048c56acd730bc | |
parent | 0bf31c3fa6263f595022d8f3addfd4d28f70db99 (diff) |
Fix adb backup/restore
* Exclude key/value-only backup participants until we have a chance to
augment the archive format with proper handling.
* Don't back up 'stopped' apps, which would un-stop them
* Fix unspecified-user bindService/startActivity invocations
* Teach adb restore about the onRestoreFinished() lifecycle method
* Implement proper app timeout handling in the adb data flows
* Backstop wallpaper backup against rare leftover-state issues
Bug 28056941
Change-Id: Ia59c71a2c74a632a2c2a527b9b7374229c440d46
-rw-r--r-- | packages/WallpaperBackup/src/com/android/wallpaperbackup/WallpaperBackupAgent.java | 5 | ||||
-rw-r--r-- | services/backup/java/com/android/server/backup/BackupManagerService.java | 148 |
2 files changed, 141 insertions, 12 deletions
diff --git a/packages/WallpaperBackup/src/com/android/wallpaperbackup/WallpaperBackupAgent.java b/packages/WallpaperBackup/src/com/android/wallpaperbackup/WallpaperBackupAgent.java index a3ea592ebe5d..47d1493e1574 100644 --- a/packages/WallpaperBackup/src/com/android/wallpaperbackup/WallpaperBackupAgent.java +++ b/packages/WallpaperBackup/src/com/android/wallpaperbackup/WallpaperBackupAgent.java @@ -92,6 +92,11 @@ public class WallpaperBackupAgent extends BackupAgent { if (DEBUG) { Slog.v(TAG, "Wallpaper is backup-eligible; linking & writing"); } + + // In case of prior muddled state + infoStage.delete(); + imageStage.delete(); + Os.link(mWallpaperInfo.getCanonicalPath(), infoStage.getCanonicalPath()); fullBackupFile(infoStage, data); Os.link(mWallpaperFile.getCanonicalPath(), imageStage.getCanonicalPath()); diff --git a/services/backup/java/com/android/server/backup/BackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java index eea771d26a0e..e6f99c15ab66 100644 --- a/services/backup/java/com/android/server/backup/BackupManagerService.java +++ b/services/backup/java/com/android/server/backup/BackupManagerService.java @@ -725,6 +725,19 @@ public class BackupManagerService { return true; } + /* adb backup: is this app only capable of doing key/value? We say otherwise if + * the app has a backup agent and does not say fullBackupOnly, *unless* it + * is a package that we know _a priori_ explicitly supports both key/value and + * full-data backup. + */ + private static boolean appIsKeyValueOnly(PackageInfo pkg) { + if ("com.android.providers.settings".equals(pkg.packageName)) { + return false; + } + + return !appGetsFullBackup(pkg); + } + // ----- Asynchronous backup/restore handler thread ----- private class BackupHandler extends Handler { @@ -3446,8 +3459,8 @@ public class BackupManagerService { Intent obbIntent = new Intent().setComponent(new ComponentName( "com.android.sharedstoragebackup", "com.android.sharedstoragebackup.ObbBackupService")); - BackupManagerService.this.mContext.bindService( - obbIntent, this, Context.BIND_AUTO_CREATE); + BackupManagerService.this.mContext.bindServiceAsUser( + obbIntent, this, Context.BIND_AUTO_CREATE, UserHandle.SYSTEM); } public void tearDown() { @@ -3965,7 +3978,7 @@ public class BackupManagerService { } // Full backup task variant used for adb backup - class PerformAdbBackupTask extends FullBackupTask { + class PerformAdbBackupTask extends FullBackupTask implements BackupRestoreTask { FullBackupEngine mBackupEngine; final AtomicBoolean mLatch; @@ -3979,6 +3992,7 @@ public class BackupManagerService { boolean mIncludeSystem; boolean mCompress; ArrayList<String> mPackages; + PackageInfo mCurrentTarget; String mCurrentPassword; String mEncryptPassword; @@ -4009,6 +4023,9 @@ public class BackupManagerService { } else { mEncryptPassword = encryptPassword; } + if (MORE_DEBUG) { + Slog.w(TAG, "Encrypting backup with passphrase=" + mEncryptPassword); + } mCompress = doCompress; } @@ -4165,7 +4182,9 @@ public class BackupManagerService { Iterator<Entry<String, PackageInfo>> iter = packagesToBackup.entrySet().iterator(); while (iter.hasNext()) { PackageInfo pkg = iter.next().getValue(); - if (!appIsEligibleForBackup(pkg.applicationInfo)) { + if (!appIsEligibleForBackup(pkg.applicationInfo) + || appIsStopped(pkg.applicationInfo) + || appIsKeyValueOnly(pkg)) { iter.remove(); } } @@ -4267,9 +4286,11 @@ public class BackupManagerService { final boolean isSharedStorage = pkg.packageName.equals(SHARED_BACKUP_AGENT_PACKAGE); - mBackupEngine = new FullBackupEngine(out, null, pkg, mIncludeApks, null); + mBackupEngine = new FullBackupEngine(out, null, pkg, mIncludeApks, this); sendOnBackupPackage(isSharedStorage ? "Shared storage" : pkg.packageName); + // Don't need to check preflight result as there is no preflight hook. + mCurrentTarget = pkg; mBackupEngine.backupOnePackage(); // after the app's agent runs to handle its private filesystem @@ -4308,6 +4329,28 @@ public class BackupManagerService { mWakelock.release(); } } + + // BackupRestoreTask methods, used for timeout handling + @Override + public void execute() { + // Unused + } + + @Override + public void operationComplete(long result) { + // Unused + } + + @Override + public void handleTimeout() { + final PackageInfo target = mCurrentTarget; + if (DEBUG) { + Slog.w(TAG, "adb backup timeout of " + target); + } + if (target != null) { + tearDownAgentAndKill(mCurrentTarget.applicationInfo); + } + } } // Full backup task extension used for transport-oriented operation @@ -5255,7 +5298,7 @@ public class BackupManagerService { byte[] mWidgetData = null; // Runner that can be placed in a separate thread to do in-process - // invocations of the full restore API asynchronously + // invocations of the full restore API asynchronously. Used by adb restore. class RestoreFileRunnable implements Runnable { IBackupAgent mAgent; FileMetadata mInfo; @@ -6404,6 +6447,46 @@ if (MORE_DEBUG) Slog.v(TAG, " + got " + nRead + "; now wanting " + (size - soF // ***** end new engine class *** + // Used for synchronizing doRestoreFinished during adb restore + class AdbRestoreFinishedLatch implements BackupRestoreTask { + static final String TAG = "AdbRestoreFinishedLatch"; + final CountDownLatch mLatch; + + AdbRestoreFinishedLatch() { + mLatch = new CountDownLatch(1); + } + + void await() { + boolean latched = false; + try { + latched = mLatch.await(TIMEOUT_FULL_BACKUP_INTERVAL, TimeUnit.MILLISECONDS); + } catch (InterruptedException e) { + Slog.w(TAG, "Interrupted!"); + } + } + + @Override + public void execute() { + // Unused + } + + @Override + public void operationComplete(long result) { + if (MORE_DEBUG) { + Slog.w(TAG, "adb onRestoreFinished() complete"); + } + mLatch.countDown(); + } + + @Override + public void handleTimeout() { + if (DEBUG) { + Slog.w(TAG, "adb onRestoreFinished() timed out"); + } + mLatch.countDown(); + } + } + class PerformAdbRestoreTask implements Runnable { ParcelFileDescriptor mInputFile; String mCurrentPassword; @@ -6419,6 +6502,27 @@ if (MORE_DEBUG) Slog.v(TAG, " + got " + nRead + "; now wanting " + (size - soF long mBytes; + // Runner that can be placed on a separate thread to do in-process invocation + // of the "restore finished" API asynchronously. Used by adb restore. + class RestoreFinishedRunnable implements Runnable { + final IBackupAgent mAgent; + final int mToken; + + RestoreFinishedRunnable(IBackupAgent agent, int token) { + mAgent = agent; + mToken = token; + } + + @Override + public void run() { + try { + mAgent.doRestoreFinished(mToken, mBackupManagerBinder); + } catch (RemoteException e) { + // never happens; this is used only for local binder calls + } + } + } + // possible handling states for a given package in the restore dataset final HashMap<String, RestorePolicy> mPackagePolicies = new HashMap<String, RestorePolicy>(); @@ -6560,7 +6664,7 @@ if (MORE_DEBUG) Slog.v(TAG, " + got " + nRead + "; now wanting " + (size - soF Slog.e(TAG, "Unable to read restore input"); } finally { tearDownPipes(); - tearDownAgent(mTargetApp); + tearDownAgent(mTargetApp, true); try { if (rawDataIn != null) rawDataIn.close(); @@ -6714,7 +6818,7 @@ if (MORE_DEBUG) Slog.v(TAG, " + got " + nRead + "; now wanting " + (size - soF if (DEBUG) Slog.d(TAG, "Saw new package; finalizing old one"); // Now we're really done tearDownPipes(); - tearDownAgent(mTargetApp); + tearDownAgent(mTargetApp, true); mTargetApp = null; mAgentPackage = null; } @@ -6936,10 +7040,12 @@ if (MORE_DEBUG) Slog.v(TAG, " + got " + nRead + "; now wanting " + (size - soF // okay, if the remote end failed at any point, deal with // it by ignoring the rest of the restore on it if (!agentSuccess) { + if (DEBUG) { + Slog.d(TAG, "Agent failure restoring " + pkg + "; now ignoring"); + } mBackupHandler.removeMessages(MSG_TIMEOUT); tearDownPipes(); - tearDownAgent(mTargetApp); - mAgent = null; + tearDownAgent(mTargetApp, false); mPackagePolicies.put(pkg, RestorePolicy.IGNORE); } } @@ -6988,9 +7094,27 @@ if (MORE_DEBUG) Slog.v(TAG, " + got " + nRead + "; now wanting " + (size - soF } } - void tearDownAgent(ApplicationInfo app) { + void tearDownAgent(ApplicationInfo app, boolean doRestoreFinished) { if (mAgent != null) { try { + // In the adb restore case, we do restore-finished here + if (doRestoreFinished) { + final int token = generateToken(); + final AdbRestoreFinishedLatch latch = new AdbRestoreFinishedLatch(); + prepareOperationTimeout(token, TIMEOUT_FULL_BACKUP_INTERVAL, latch); + if (mTargetApp.processName.equals("system")) { + if (MORE_DEBUG) { + Slog.d(TAG, "system agent - restoreFinished on thread"); + } + Runnable runner = new RestoreFinishedRunnable(mAgent, token); + new Thread(runner, "restore-sys-finished-runner").start(); + } else { + mAgent.doRestoreFinished(token, mBackupManagerBinder); + } + + latch.await(); + } + // unbind and tidy up even on timeout or failure, just in case mActivityManager.unbindBackupAgent(app); @@ -9354,7 +9478,7 @@ if (MORE_DEBUG) Slog.v(TAG, " + got " + nRead + "; now wanting " + (size - soF "com.android.backupconfirm.BackupRestoreConfirmation"); confIntent.putExtra(FullBackup.CONF_TOKEN_INTENT_EXTRA, token); confIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - mContext.startActivity(confIntent); + mContext.startActivityAsUser(confIntent, UserHandle.SYSTEM); } catch (ActivityNotFoundException e) { return false; } |