Loading services/backup/java/com/android/server/backup/BackupManagerService.java +191 −130 Original line number Diff line number Diff line Loading @@ -3503,12 +3503,12 @@ public class BackupManagerService { class FullBackupEngine { OutputStream mOutput; FullBackupPreflight mPreflightHook; IFullBackupRestoreObserver mObserver; IBackupAgent mAgent; File mFilesDir; File mManifestFile; File mMetadataFile; boolean mIncludeApks; PackageInfo mPkg; class FullBackupRunner implements Runnable { PackageInfo mPackage; Loading Loading @@ -3577,39 +3577,47 @@ public class BackupManagerService { } } FullBackupEngine(OutputStream output, String packageName, FullBackupPreflight preflightHook, FullBackupEngine(OutputStream output, FullBackupPreflight preflightHook, PackageInfo pkg, boolean alsoApks) { mOutput = output; mPreflightHook = preflightHook; mPkg = pkg; mIncludeApks = alsoApks; mFilesDir = new File("/data/system"); mManifestFile = new File(mFilesDir, BACKUP_MANIFEST_FILENAME); mMetadataFile = new File(mFilesDir, BACKUP_METADATA_FILENAME); } public int backupOnePackage(PackageInfo pkg) throws RemoteException { int result = BackupTransport.TRANSPORT_OK; Slog.d(TAG, "Binding to full backup agent : " + pkg.packageName); mAgent = bindToAgentSynchronous(pkg.applicationInfo, IApplicationThread.BACKUP_MODE_FULL); if (mAgent != null) { ParcelFileDescriptor[] pipes = null; try { // Call the preflight hook, if any if (mPreflightHook != null) { result = mPreflightHook.preflightFullBackup(pkg, mAgent); public int preflightCheck() throws RemoteException { if (mPreflightHook == null) { if (MORE_DEBUG) { Slog.v(TAG, "No preflight check"); } return BackupTransport.TRANSPORT_OK; } if (initializeAgent()) { int result = mPreflightHook.preflightFullBackup(mPkg, mAgent); if (MORE_DEBUG) { Slog.v(TAG, "preflight returned " + result); } return result; } else { Slog.w(TAG, "Unable to bind to full agent for " + mPkg.packageName); return BackupTransport.AGENT_ERROR; } } // If we're still good to go after preflighting, start moving data if (result == BackupTransport.TRANSPORT_OK) { public int backupOnePackage() throws RemoteException { int result = BackupTransport.AGENT_ERROR; if (initializeAgent()) { ParcelFileDescriptor[] pipes = null; try { pipes = ParcelFileDescriptor.createPipe(); ApplicationInfo app = pkg.applicationInfo; final boolean isSharedStorage = pkg.packageName.equals(SHARED_BACKUP_AGENT_PACKAGE); ApplicationInfo app = mPkg.applicationInfo; final boolean isSharedStorage = mPkg.packageName.equals(SHARED_BACKUP_AGENT_PACKAGE); final boolean sendApk = mIncludeApks && !isSharedStorage && ((app.privateFlags & ApplicationInfo.PRIVATE_FLAG_FORWARD_LOCK) == 0) Loading @@ -3617,11 +3625,11 @@ public class BackupManagerService { (app.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0); // TODO: http://b/22388012 byte[] widgetBlob = AppWidgetBackupBridge.getWidgetState(pkg.packageName, byte[] widgetBlob = AppWidgetBackupBridge.getWidgetState(mPkg.packageName, UserHandle.USER_SYSTEM); final int token = generateToken(); FullBackupRunner runner = new FullBackupRunner(pkg, mAgent, pipes[1], FullBackupRunner runner = new FullBackupRunner(mPkg, mAgent, pipes[1], token, sendApk, !isSharedStorage, widgetBlob); pipes[1].close(); // the runner has dup'd it pipes[1] = null; Loading @@ -3629,24 +3637,18 @@ public class BackupManagerService { t.start(); // Now pull data from the app and stuff it into the output try { routeSocketDataToOutput(pipes[0], mOutput); } catch (IOException e) { Slog.i(TAG, "Caught exception reading from agent", e); result = BackupTransport.AGENT_ERROR; } if (!waitUntilOperationComplete(token)) { Slog.e(TAG, "Full backup failed on package " + pkg.packageName); result = BackupTransport.AGENT_ERROR; Slog.e(TAG, "Full backup failed on package " + mPkg.packageName); } else { if (MORE_DEBUG) { Slog.d(TAG, "Full package backup success: " + pkg.packageName); } Slog.d(TAG, "Full package backup success: " + mPkg.packageName); } result = BackupTransport.TRANSPORT_OK; } } catch (IOException e) { Slog.e(TAG, "Error backing up " + pkg.packageName, e); Slog.e(TAG, "Error backing up " + mPkg.packageName, e); result = BackupTransport.AGENT_ERROR; } finally { try { Loading @@ -3662,15 +3664,14 @@ public class BackupManagerService { } } } else { Slog.w(TAG, "Unable to bind to full agent for " + pkg.packageName); result = BackupTransport.AGENT_ERROR; Slog.w(TAG, "Unable to bind to full agent for " + mPkg.packageName); } tearDown(pkg); tearDown(); return result; } public void sendQuotaExceeded(final long backupDataBytes, final long quotaBytes) { if (mAgent != null) { if (initializeAgent()) { try { mAgent.doQuotaExceeded(backupDataBytes, quotaBytes); } catch (RemoteException e) { Loading @@ -3679,6 +3680,17 @@ public class BackupManagerService { } } private boolean initializeAgent() { if (mAgent == null) { if (MORE_DEBUG) { Slog.d(TAG, "Binding to full backup agent : " + mPkg.packageName); } mAgent = bindToAgentSynchronous(mPkg.applicationInfo, IApplicationThread.BACKUP_MODE_FULL); } return mAgent != null; } private void writeApkToBackup(PackageInfo pkg, FullBackupDataOutput output) { // Forward-locked apps, system-bundled .apks, etc are filtered out before we get here // TODO: handle backing up split APKs Loading Loading @@ -3795,9 +3807,9 @@ public class BackupManagerService { destination.setLastModified(0); } private void tearDown(PackageInfo pkg) { if (pkg != null) { final ApplicationInfo app = pkg.applicationInfo; private void tearDown() { if (mPkg != null) { final ApplicationInfo app = mPkg.applicationInfo; if (app != null) { tearDownAgentAndKill(app); } Loading Loading @@ -4166,9 +4178,10 @@ public class BackupManagerService { final boolean isSharedStorage = pkg.packageName.equals(SHARED_BACKUP_AGENT_PACKAGE); mBackupEngine = new FullBackupEngine(out, pkg.packageName, null, mIncludeApks); mBackupEngine = new FullBackupEngine(out, null, pkg, mIncludeApks); sendOnBackupPackage(isSharedStorage ? "Shared storage" : pkg.packageName); mBackupEngine.backupOnePackage(pkg); // Don't need to check preflight result as there is no preflight hook. mBackupEngine.backupOnePackage(); // after the app's agent runs to handle its private filesystem // contents, back up any OBB content it has on its behalf. Loading Loading @@ -4314,12 +4327,11 @@ public class BackupManagerService { final byte[] buffer = new byte[8192]; for (int i = 0; i < N; i++) { PackageInfo currentPackage = mPackages.get(i); String packageName = currentPackage.packageName; if (DEBUG) { Slog.i(TAG, "Initiating full-data transport backup of " + currentPackage.packageName); Slog.i(TAG, "Initiating full-data transport backup of " + packageName); } EventLog.writeEvent(EventLogTags.FULL_BACKUP_PACKAGE, currentPackage.packageName); EventLog.writeEvent(EventLogTags.FULL_BACKUP_PACKAGE, packageName); transportPipes = ParcelFileDescriptor.createPipe(); Loading @@ -4335,10 +4347,9 @@ public class BackupManagerService { // Now set up the backup engine / data source end of things enginePipes = ParcelFileDescriptor.createPipe(); CountDownLatch runnerLatch = new CountDownLatch(1); SinglePackageBackupRunner backupRunner = new SinglePackageBackupRunner(enginePipes[1], currentPackage, transport, runnerLatch); transport); // The runner dup'd the pipe half, so we close it here enginePipes[1].close(); enginePipes[1] = null; Loading @@ -4354,12 +4365,16 @@ public class BackupManagerService { FileOutputStream out = new FileOutputStream( transportPipes[1].getFileDescriptor()); long totalRead = 0; final long expectedSize = backupRunner.expectedSize(); if (expectedSize < 0) { backupPackageStatus = BackupTransport.AGENT_ERROR; sendBackupOnPackageResult(mBackupObserver, currentPackage.packageName, BackupManager.ERROR_AGENT_FAILURE); final long preflightResult = backupRunner.getPreflightResultBlocking(); // Preflight result is negative if some error happened on preflight. if (preflightResult < 0) { if (MORE_DEBUG) { Slog.d(TAG, "Backup error after preflight of package " + packageName + ": " + preflightResult + ", not running backup."); } backupPackageStatus = (int) preflightResult; } else { int nRead = 0; do { if (!mKeepRunning.get()) { Loading @@ -4376,21 +4391,23 @@ public class BackupManagerService { out.write(buffer, 0, nRead); backupPackageStatus = transport.sendBackupData(nRead); totalRead += nRead; if (mBackupObserver != null && expectedSize > 0) { sendBackupOnUpdate(mBackupObserver, currentPackage.packageName, new BackupProgress(expectedSize, totalRead)); if (mBackupObserver != null && preflightResult > 0) { sendBackupOnUpdate(mBackupObserver, packageName, new BackupProgress(preflightResult, totalRead)); } } } while (nRead > 0 && backupPackageStatus == BackupTransport.TRANSPORT_OK); } while (nRead > 0 && backupPackageStatus == BackupTransport.TRANSPORT_OK); // Despite preflight succeeded, package still can hit quota on flight. if (backupPackageStatus == BackupTransport.TRANSPORT_QUOTA_EXCEEDED) { long quota = transport.getBackupQuota(currentPackage.packageName, true); if (MORE_DEBUG) { Slog.d(TAG, "Package hit quota limit " + currentPackage.packageName long quota = transport.getBackupQuota(packageName, true); Slog.w(TAG, "Package hit quota limit in-flight " + packageName + ": " + totalRead + " of " + quota); } backupRunner.sendQuotaExceeded(totalRead, quota); } } // If we've lost our running criteria, tell the transport to cancel // and roll back this (partial) backup payload; otherwise tell it Loading @@ -4409,14 +4426,23 @@ public class BackupManagerService { } } // We still could fail in backup runner thread, getting result from there. int backupRunnerResult = backupRunner.getBackupResultBlocking(); if (backupPackageStatus != BackupTransport.TRANSPORT_ERROR && backupRunnerResult != BackupTransport.TRANSPORT_OK) { // If there was an error in runner thread and // not TRANSPORT_ERROR here, overwrite it. backupPackageStatus = backupRunnerResult; } if (MORE_DEBUG) { Slog.i(TAG, "Done trying to send backup data: result=" + backupPackageStatus); } if (backupPackageStatus != BackupTransport.TRANSPORT_OK) { Slog.e(TAG, "Error " + backupPackageStatus + " backing up " + currentPackage.packageName); Slog.e(TAG, "Error " + backupPackageStatus + " backing up " + packageName); } // Also ask the transport how long it wants us to wait before Loading @@ -4431,33 +4457,36 @@ public class BackupManagerService { // Roll this package to the end of the backup queue if we're // in a queue-driven mode (regardless of success/failure) if (mUpdateSchedule) { enqueueFullBackup(currentPackage.packageName, System.currentTimeMillis()); enqueueFullBackup(packageName, System.currentTimeMillis()); } if (backupPackageStatus == BackupTransport.TRANSPORT_PACKAGE_REJECTED) { sendBackupOnPackageResult(mBackupObserver, currentPackage.packageName, sendBackupOnPackageResult(mBackupObserver, packageName, BackupManager.ERROR_TRANSPORT_PACKAGE_REJECTED); if (DEBUG) { Slog.i(TAG, "Transport rejected backup of " + currentPackage.packageName Slog.i(TAG, "Transport rejected backup of " + packageName + ", skipping"); } EventLog.writeEvent(EventLogTags.FULL_BACKUP_AGENT_FAILURE, currentPackage.packageName, "transport rejected"); EventLog.writeEvent(EventLogTags.FULL_BACKUP_AGENT_FAILURE, packageName, "transport rejected"); // Do nothing, clean up, and continue looping. } else if (backupPackageStatus == BackupTransport.TRANSPORT_QUOTA_EXCEEDED) { sendBackupOnPackageResult(mBackupObserver, currentPackage.packageName, sendBackupOnPackageResult(mBackupObserver, packageName, BackupManager.ERROR_TRANSPORT_QUOTA_EXCEEDED); if (DEBUG) { Slog.i(TAG, "Transport quota exceeded for package: " + currentPackage.packageName); } Slog.i(TAG, "Transport quota exceeded for package: " + packageName); EventLog.writeEvent(EventLogTags.FULL_BACKUP_QUOTA_EXCEEDED, currentPackage.packageName); packageName); } // Do nothing, clean up, and continue looping. } else if (backupPackageStatus == BackupTransport.AGENT_ERROR) { sendBackupOnPackageResult(mBackupObserver, packageName, BackupManager.ERROR_AGENT_FAILURE); Slog.w(TAG, "Application failure for package: " + packageName); EventLog.writeEvent(EventLogTags.BACKUP_AGENT_FAILURE, packageName); // Do nothing, clean up, and continue looping. } else if (backupPackageStatus != BackupTransport.TRANSPORT_OK) { sendBackupOnPackageResult(mBackupObserver, currentPackage.packageName, sendBackupOnPackageResult(mBackupObserver, packageName, BackupManager.ERROR_TRANSPORT_ABORTED); Slog.w(TAG, "Transport failed; aborting backup: " + backupPackageStatus); EventLog.writeEvent(EventLogTags.FULL_BACKUP_TRANSPORT_FAILURE); Loading @@ -4466,11 +4495,10 @@ public class BackupManagerService { return; } else { // Success! sendBackupOnPackageResult(mBackupObserver, currentPackage.packageName, sendBackupOnPackageResult(mBackupObserver, packageName, BackupManager.SUCCESS); EventLog.writeEvent(EventLogTags.FULL_BACKUP_SUCCESS, currentPackage.packageName); logBackupComplete(currentPackage.packageName); EventLog.writeEvent(EventLogTags.FULL_BACKUP_SUCCESS, packageName); logBackupComplete(packageName); } cleanUpPipes(transportPipes); cleanUpPipes(enginePipes); Loading Loading @@ -4621,28 +4649,41 @@ public class BackupManagerService { final ParcelFileDescriptor mOutput; final PackageInfo mTarget; final FullBackupPreflight mPreflight; final CountDownLatch mLatch; final CountDownLatch mPreflightLatch; final CountDownLatch mBackupLatch; private FullBackupEngine mEngine; private volatile int mPreflightResult; private volatile int mBackupResult; SinglePackageBackupRunner(ParcelFileDescriptor output, PackageInfo target, IBackupTransport transport, CountDownLatch latch) throws IOException { IBackupTransport transport) throws IOException { mOutput = ParcelFileDescriptor.dup(output.getFileDescriptor()); mTarget = target; mPreflight = new SinglePackageBackupPreflight(transport); mLatch = latch; mPreflightLatch = new CountDownLatch(1); mBackupLatch = new CountDownLatch(1); mPreflightResult = BackupTransport.TRANSPORT_OK; mBackupResult = BackupTransport.TRANSPORT_OK; } @Override public void run() { try { FileOutputStream out = new FileOutputStream(mOutput.getFileDescriptor()); mEngine = new FullBackupEngine(out, mTarget.packageName, mPreflight, false); mEngine.backupOnePackage(mTarget); mEngine = new FullBackupEngine(out, mPreflight, mTarget, false); try { try { mPreflightResult = mEngine.preflightCheck(); } finally { mPreflightLatch.countDown(); } // If there is no error on preflight, continue backup. if (mPreflightResult == BackupTransport.TRANSPORT_OK) { mBackupResult = mEngine.backupOnePackage(); } } catch (Exception e) { Slog.e(TAG, "Exception during full package backup of " + mTarget); Slog.e(TAG, "Exception during full package backup of " + mTarget.packageName); } finally { mLatch.countDown(); mBackupLatch.countDown(); try { mOutput.close(); } catch (IOException e) { Loading @@ -4655,8 +4696,28 @@ public class BackupManagerService { mEngine.sendQuotaExceeded(backupDataBytes, quotaBytes); } long expectedSize() { // If preflight succeeded, returns positive number - preflight size, // otherwise return negative error code. long getPreflightResultBlocking() { try { mPreflightLatch.await(); if (mPreflightResult == BackupTransport.TRANSPORT_OK) { return mPreflight.getExpectedSizeOrErrorCode(); } else { return mPreflightResult; } } catch (InterruptedException e) { return BackupTransport.AGENT_ERROR; } } int getBackupResultBlocking() { try { mBackupLatch.await(); return mBackupResult; } catch (InterruptedException e) { return BackupTransport.AGENT_ERROR; } } } } Loading Loading
services/backup/java/com/android/server/backup/BackupManagerService.java +191 −130 Original line number Diff line number Diff line Loading @@ -3503,12 +3503,12 @@ public class BackupManagerService { class FullBackupEngine { OutputStream mOutput; FullBackupPreflight mPreflightHook; IFullBackupRestoreObserver mObserver; IBackupAgent mAgent; File mFilesDir; File mManifestFile; File mMetadataFile; boolean mIncludeApks; PackageInfo mPkg; class FullBackupRunner implements Runnable { PackageInfo mPackage; Loading Loading @@ -3577,39 +3577,47 @@ public class BackupManagerService { } } FullBackupEngine(OutputStream output, String packageName, FullBackupPreflight preflightHook, FullBackupEngine(OutputStream output, FullBackupPreflight preflightHook, PackageInfo pkg, boolean alsoApks) { mOutput = output; mPreflightHook = preflightHook; mPkg = pkg; mIncludeApks = alsoApks; mFilesDir = new File("/data/system"); mManifestFile = new File(mFilesDir, BACKUP_MANIFEST_FILENAME); mMetadataFile = new File(mFilesDir, BACKUP_METADATA_FILENAME); } public int backupOnePackage(PackageInfo pkg) throws RemoteException { int result = BackupTransport.TRANSPORT_OK; Slog.d(TAG, "Binding to full backup agent : " + pkg.packageName); mAgent = bindToAgentSynchronous(pkg.applicationInfo, IApplicationThread.BACKUP_MODE_FULL); if (mAgent != null) { ParcelFileDescriptor[] pipes = null; try { // Call the preflight hook, if any if (mPreflightHook != null) { result = mPreflightHook.preflightFullBackup(pkg, mAgent); public int preflightCheck() throws RemoteException { if (mPreflightHook == null) { if (MORE_DEBUG) { Slog.v(TAG, "No preflight check"); } return BackupTransport.TRANSPORT_OK; } if (initializeAgent()) { int result = mPreflightHook.preflightFullBackup(mPkg, mAgent); if (MORE_DEBUG) { Slog.v(TAG, "preflight returned " + result); } return result; } else { Slog.w(TAG, "Unable to bind to full agent for " + mPkg.packageName); return BackupTransport.AGENT_ERROR; } } // If we're still good to go after preflighting, start moving data if (result == BackupTransport.TRANSPORT_OK) { public int backupOnePackage() throws RemoteException { int result = BackupTransport.AGENT_ERROR; if (initializeAgent()) { ParcelFileDescriptor[] pipes = null; try { pipes = ParcelFileDescriptor.createPipe(); ApplicationInfo app = pkg.applicationInfo; final boolean isSharedStorage = pkg.packageName.equals(SHARED_BACKUP_AGENT_PACKAGE); ApplicationInfo app = mPkg.applicationInfo; final boolean isSharedStorage = mPkg.packageName.equals(SHARED_BACKUP_AGENT_PACKAGE); final boolean sendApk = mIncludeApks && !isSharedStorage && ((app.privateFlags & ApplicationInfo.PRIVATE_FLAG_FORWARD_LOCK) == 0) Loading @@ -3617,11 +3625,11 @@ public class BackupManagerService { (app.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0); // TODO: http://b/22388012 byte[] widgetBlob = AppWidgetBackupBridge.getWidgetState(pkg.packageName, byte[] widgetBlob = AppWidgetBackupBridge.getWidgetState(mPkg.packageName, UserHandle.USER_SYSTEM); final int token = generateToken(); FullBackupRunner runner = new FullBackupRunner(pkg, mAgent, pipes[1], FullBackupRunner runner = new FullBackupRunner(mPkg, mAgent, pipes[1], token, sendApk, !isSharedStorage, widgetBlob); pipes[1].close(); // the runner has dup'd it pipes[1] = null; Loading @@ -3629,24 +3637,18 @@ public class BackupManagerService { t.start(); // Now pull data from the app and stuff it into the output try { routeSocketDataToOutput(pipes[0], mOutput); } catch (IOException e) { Slog.i(TAG, "Caught exception reading from agent", e); result = BackupTransport.AGENT_ERROR; } if (!waitUntilOperationComplete(token)) { Slog.e(TAG, "Full backup failed on package " + pkg.packageName); result = BackupTransport.AGENT_ERROR; Slog.e(TAG, "Full backup failed on package " + mPkg.packageName); } else { if (MORE_DEBUG) { Slog.d(TAG, "Full package backup success: " + pkg.packageName); } Slog.d(TAG, "Full package backup success: " + mPkg.packageName); } result = BackupTransport.TRANSPORT_OK; } } catch (IOException e) { Slog.e(TAG, "Error backing up " + pkg.packageName, e); Slog.e(TAG, "Error backing up " + mPkg.packageName, e); result = BackupTransport.AGENT_ERROR; } finally { try { Loading @@ -3662,15 +3664,14 @@ public class BackupManagerService { } } } else { Slog.w(TAG, "Unable to bind to full agent for " + pkg.packageName); result = BackupTransport.AGENT_ERROR; Slog.w(TAG, "Unable to bind to full agent for " + mPkg.packageName); } tearDown(pkg); tearDown(); return result; } public void sendQuotaExceeded(final long backupDataBytes, final long quotaBytes) { if (mAgent != null) { if (initializeAgent()) { try { mAgent.doQuotaExceeded(backupDataBytes, quotaBytes); } catch (RemoteException e) { Loading @@ -3679,6 +3680,17 @@ public class BackupManagerService { } } private boolean initializeAgent() { if (mAgent == null) { if (MORE_DEBUG) { Slog.d(TAG, "Binding to full backup agent : " + mPkg.packageName); } mAgent = bindToAgentSynchronous(mPkg.applicationInfo, IApplicationThread.BACKUP_MODE_FULL); } return mAgent != null; } private void writeApkToBackup(PackageInfo pkg, FullBackupDataOutput output) { // Forward-locked apps, system-bundled .apks, etc are filtered out before we get here // TODO: handle backing up split APKs Loading Loading @@ -3795,9 +3807,9 @@ public class BackupManagerService { destination.setLastModified(0); } private void tearDown(PackageInfo pkg) { if (pkg != null) { final ApplicationInfo app = pkg.applicationInfo; private void tearDown() { if (mPkg != null) { final ApplicationInfo app = mPkg.applicationInfo; if (app != null) { tearDownAgentAndKill(app); } Loading Loading @@ -4166,9 +4178,10 @@ public class BackupManagerService { final boolean isSharedStorage = pkg.packageName.equals(SHARED_BACKUP_AGENT_PACKAGE); mBackupEngine = new FullBackupEngine(out, pkg.packageName, null, mIncludeApks); mBackupEngine = new FullBackupEngine(out, null, pkg, mIncludeApks); sendOnBackupPackage(isSharedStorage ? "Shared storage" : pkg.packageName); mBackupEngine.backupOnePackage(pkg); // Don't need to check preflight result as there is no preflight hook. mBackupEngine.backupOnePackage(); // after the app's agent runs to handle its private filesystem // contents, back up any OBB content it has on its behalf. Loading Loading @@ -4314,12 +4327,11 @@ public class BackupManagerService { final byte[] buffer = new byte[8192]; for (int i = 0; i < N; i++) { PackageInfo currentPackage = mPackages.get(i); String packageName = currentPackage.packageName; if (DEBUG) { Slog.i(TAG, "Initiating full-data transport backup of " + currentPackage.packageName); Slog.i(TAG, "Initiating full-data transport backup of " + packageName); } EventLog.writeEvent(EventLogTags.FULL_BACKUP_PACKAGE, currentPackage.packageName); EventLog.writeEvent(EventLogTags.FULL_BACKUP_PACKAGE, packageName); transportPipes = ParcelFileDescriptor.createPipe(); Loading @@ -4335,10 +4347,9 @@ public class BackupManagerService { // Now set up the backup engine / data source end of things enginePipes = ParcelFileDescriptor.createPipe(); CountDownLatch runnerLatch = new CountDownLatch(1); SinglePackageBackupRunner backupRunner = new SinglePackageBackupRunner(enginePipes[1], currentPackage, transport, runnerLatch); transport); // The runner dup'd the pipe half, so we close it here enginePipes[1].close(); enginePipes[1] = null; Loading @@ -4354,12 +4365,16 @@ public class BackupManagerService { FileOutputStream out = new FileOutputStream( transportPipes[1].getFileDescriptor()); long totalRead = 0; final long expectedSize = backupRunner.expectedSize(); if (expectedSize < 0) { backupPackageStatus = BackupTransport.AGENT_ERROR; sendBackupOnPackageResult(mBackupObserver, currentPackage.packageName, BackupManager.ERROR_AGENT_FAILURE); final long preflightResult = backupRunner.getPreflightResultBlocking(); // Preflight result is negative if some error happened on preflight. if (preflightResult < 0) { if (MORE_DEBUG) { Slog.d(TAG, "Backup error after preflight of package " + packageName + ": " + preflightResult + ", not running backup."); } backupPackageStatus = (int) preflightResult; } else { int nRead = 0; do { if (!mKeepRunning.get()) { Loading @@ -4376,21 +4391,23 @@ public class BackupManagerService { out.write(buffer, 0, nRead); backupPackageStatus = transport.sendBackupData(nRead); totalRead += nRead; if (mBackupObserver != null && expectedSize > 0) { sendBackupOnUpdate(mBackupObserver, currentPackage.packageName, new BackupProgress(expectedSize, totalRead)); if (mBackupObserver != null && preflightResult > 0) { sendBackupOnUpdate(mBackupObserver, packageName, new BackupProgress(preflightResult, totalRead)); } } } while (nRead > 0 && backupPackageStatus == BackupTransport.TRANSPORT_OK); } while (nRead > 0 && backupPackageStatus == BackupTransport.TRANSPORT_OK); // Despite preflight succeeded, package still can hit quota on flight. if (backupPackageStatus == BackupTransport.TRANSPORT_QUOTA_EXCEEDED) { long quota = transport.getBackupQuota(currentPackage.packageName, true); if (MORE_DEBUG) { Slog.d(TAG, "Package hit quota limit " + currentPackage.packageName long quota = transport.getBackupQuota(packageName, true); Slog.w(TAG, "Package hit quota limit in-flight " + packageName + ": " + totalRead + " of " + quota); } backupRunner.sendQuotaExceeded(totalRead, quota); } } // If we've lost our running criteria, tell the transport to cancel // and roll back this (partial) backup payload; otherwise tell it Loading @@ -4409,14 +4426,23 @@ public class BackupManagerService { } } // We still could fail in backup runner thread, getting result from there. int backupRunnerResult = backupRunner.getBackupResultBlocking(); if (backupPackageStatus != BackupTransport.TRANSPORT_ERROR && backupRunnerResult != BackupTransport.TRANSPORT_OK) { // If there was an error in runner thread and // not TRANSPORT_ERROR here, overwrite it. backupPackageStatus = backupRunnerResult; } if (MORE_DEBUG) { Slog.i(TAG, "Done trying to send backup data: result=" + backupPackageStatus); } if (backupPackageStatus != BackupTransport.TRANSPORT_OK) { Slog.e(TAG, "Error " + backupPackageStatus + " backing up " + currentPackage.packageName); Slog.e(TAG, "Error " + backupPackageStatus + " backing up " + packageName); } // Also ask the transport how long it wants us to wait before Loading @@ -4431,33 +4457,36 @@ public class BackupManagerService { // Roll this package to the end of the backup queue if we're // in a queue-driven mode (regardless of success/failure) if (mUpdateSchedule) { enqueueFullBackup(currentPackage.packageName, System.currentTimeMillis()); enqueueFullBackup(packageName, System.currentTimeMillis()); } if (backupPackageStatus == BackupTransport.TRANSPORT_PACKAGE_REJECTED) { sendBackupOnPackageResult(mBackupObserver, currentPackage.packageName, sendBackupOnPackageResult(mBackupObserver, packageName, BackupManager.ERROR_TRANSPORT_PACKAGE_REJECTED); if (DEBUG) { Slog.i(TAG, "Transport rejected backup of " + currentPackage.packageName Slog.i(TAG, "Transport rejected backup of " + packageName + ", skipping"); } EventLog.writeEvent(EventLogTags.FULL_BACKUP_AGENT_FAILURE, currentPackage.packageName, "transport rejected"); EventLog.writeEvent(EventLogTags.FULL_BACKUP_AGENT_FAILURE, packageName, "transport rejected"); // Do nothing, clean up, and continue looping. } else if (backupPackageStatus == BackupTransport.TRANSPORT_QUOTA_EXCEEDED) { sendBackupOnPackageResult(mBackupObserver, currentPackage.packageName, sendBackupOnPackageResult(mBackupObserver, packageName, BackupManager.ERROR_TRANSPORT_QUOTA_EXCEEDED); if (DEBUG) { Slog.i(TAG, "Transport quota exceeded for package: " + currentPackage.packageName); } Slog.i(TAG, "Transport quota exceeded for package: " + packageName); EventLog.writeEvent(EventLogTags.FULL_BACKUP_QUOTA_EXCEEDED, currentPackage.packageName); packageName); } // Do nothing, clean up, and continue looping. } else if (backupPackageStatus == BackupTransport.AGENT_ERROR) { sendBackupOnPackageResult(mBackupObserver, packageName, BackupManager.ERROR_AGENT_FAILURE); Slog.w(TAG, "Application failure for package: " + packageName); EventLog.writeEvent(EventLogTags.BACKUP_AGENT_FAILURE, packageName); // Do nothing, clean up, and continue looping. } else if (backupPackageStatus != BackupTransport.TRANSPORT_OK) { sendBackupOnPackageResult(mBackupObserver, currentPackage.packageName, sendBackupOnPackageResult(mBackupObserver, packageName, BackupManager.ERROR_TRANSPORT_ABORTED); Slog.w(TAG, "Transport failed; aborting backup: " + backupPackageStatus); EventLog.writeEvent(EventLogTags.FULL_BACKUP_TRANSPORT_FAILURE); Loading @@ -4466,11 +4495,10 @@ public class BackupManagerService { return; } else { // Success! sendBackupOnPackageResult(mBackupObserver, currentPackage.packageName, sendBackupOnPackageResult(mBackupObserver, packageName, BackupManager.SUCCESS); EventLog.writeEvent(EventLogTags.FULL_BACKUP_SUCCESS, currentPackage.packageName); logBackupComplete(currentPackage.packageName); EventLog.writeEvent(EventLogTags.FULL_BACKUP_SUCCESS, packageName); logBackupComplete(packageName); } cleanUpPipes(transportPipes); cleanUpPipes(enginePipes); Loading Loading @@ -4621,28 +4649,41 @@ public class BackupManagerService { final ParcelFileDescriptor mOutput; final PackageInfo mTarget; final FullBackupPreflight mPreflight; final CountDownLatch mLatch; final CountDownLatch mPreflightLatch; final CountDownLatch mBackupLatch; private FullBackupEngine mEngine; private volatile int mPreflightResult; private volatile int mBackupResult; SinglePackageBackupRunner(ParcelFileDescriptor output, PackageInfo target, IBackupTransport transport, CountDownLatch latch) throws IOException { IBackupTransport transport) throws IOException { mOutput = ParcelFileDescriptor.dup(output.getFileDescriptor()); mTarget = target; mPreflight = new SinglePackageBackupPreflight(transport); mLatch = latch; mPreflightLatch = new CountDownLatch(1); mBackupLatch = new CountDownLatch(1); mPreflightResult = BackupTransport.TRANSPORT_OK; mBackupResult = BackupTransport.TRANSPORT_OK; } @Override public void run() { try { FileOutputStream out = new FileOutputStream(mOutput.getFileDescriptor()); mEngine = new FullBackupEngine(out, mTarget.packageName, mPreflight, false); mEngine.backupOnePackage(mTarget); mEngine = new FullBackupEngine(out, mPreflight, mTarget, false); try { try { mPreflightResult = mEngine.preflightCheck(); } finally { mPreflightLatch.countDown(); } // If there is no error on preflight, continue backup. if (mPreflightResult == BackupTransport.TRANSPORT_OK) { mBackupResult = mEngine.backupOnePackage(); } } catch (Exception e) { Slog.e(TAG, "Exception during full package backup of " + mTarget); Slog.e(TAG, "Exception during full package backup of " + mTarget.packageName); } finally { mLatch.countDown(); mBackupLatch.countDown(); try { mOutput.close(); } catch (IOException e) { Loading @@ -4655,8 +4696,28 @@ public class BackupManagerService { mEngine.sendQuotaExceeded(backupDataBytes, quotaBytes); } long expectedSize() { // If preflight succeeded, returns positive number - preflight size, // otherwise return negative error code. long getPreflightResultBlocking() { try { mPreflightLatch.await(); if (mPreflightResult == BackupTransport.TRANSPORT_OK) { return mPreflight.getExpectedSizeOrErrorCode(); } else { return mPreflightResult; } } catch (InterruptedException e) { return BackupTransport.AGENT_ERROR; } } int getBackupResultBlocking() { try { mBackupLatch.await(); return mBackupResult; } catch (InterruptedException e) { return BackupTransport.AGENT_ERROR; } } } } Loading