summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Sergey Poromov <poromov@google.com> 2016-02-17 13:46:00 +0000
committer Android (Google) Code Review <android-gerrit@google.com> 2016-02-17 13:46:01 +0000
commit570c939e489ec091449d12fe2a179dbce6e8e89b (patch)
tree052ea418a681c2f414bba20c06e5378f96f0112d
parente979ccb595427159afd1fb292ba8b36d7943bf87 (diff)
parentcd8c13fc4e165cb67016b01fe77dbcd8309211b1 (diff)
Merge "Synchronize results from runner thread to main full backup thread." into nyc-dev
-rw-r--r--services/backup/java/com/android/server/backup/BackupManagerService.java321
1 files changed, 191 insertions, 130 deletions
diff --git a/services/backup/java/com/android/server/backup/BackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java
index f8bf59d29f48..eaee1d3e0602 100644
--- a/services/backup/java/com/android/server/backup/BackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/BackupManagerService.java
@@ -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;
@@ -3520,8 +3520,8 @@ public class BackupManagerService {
boolean mWriteManifest;
FullBackupRunner(PackageInfo pack, IBackupAgent agent, ParcelFileDescriptor pipe,
- int token, boolean sendApk, boolean writeManifest, byte[] widgetData)
- throws IOException {
+ int token, boolean sendApk, boolean writeManifest, byte[] widgetData)
+ throws IOException {
mPackage = pack;
mWidgetData = widgetData;
mAgent = agent;
@@ -3577,76 +3577,78 @@ public class BackupManagerService {
}
}
- FullBackupEngine(OutputStream output, String packageName, FullBackupPreflight preflightHook,
- boolean alsoApks) {
+ 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);
+ 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;
+ }
+ }
- mAgent = bindToAgentSynchronous(pkg.applicationInfo,
- IApplicationThread.BACKUP_MODE_FULL);
- if (mAgent != null) {
+ public int backupOnePackage() throws RemoteException {
+ int result = BackupTransport.AGENT_ERROR;
+
+ if (initializeAgent()) {
ParcelFileDescriptor[] pipes = null;
try {
- // Call the preflight hook, if any
- if (mPreflightHook != null) {
- result = mPreflightHook.preflightFullBackup(pkg, mAgent);
- if (MORE_DEBUG) {
- Slog.v(TAG, "preflight returned " + result);
- }
- }
-
- // If we're still good to go after preflighting, start moving data
- if (result == BackupTransport.TRANSPORT_OK) {
- pipes = ParcelFileDescriptor.createPipe();
+ pipes = ParcelFileDescriptor.createPipe();
- ApplicationInfo app = pkg.applicationInfo;
- final boolean isSharedStorage = pkg.packageName.equals(SHARED_BACKUP_AGENT_PACKAGE);
- final boolean sendApk = mIncludeApks
- && !isSharedStorage
- && ((app.privateFlags & ApplicationInfo.PRIVATE_FLAG_FORWARD_LOCK) == 0)
- && ((app.flags & ApplicationInfo.FLAG_SYSTEM) == 0 ||
- (app.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0);
+ 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)
+ && ((app.flags & ApplicationInfo.FLAG_SYSTEM) == 0 ||
+ (app.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0);
- // TODO: http://b/22388012
- byte[] widgetBlob = AppWidgetBackupBridge.getWidgetState(pkg.packageName,
- UserHandle.USER_SYSTEM);
+ // TODO: http://b/22388012
+ byte[] widgetBlob = AppWidgetBackupBridge.getWidgetState(mPkg.packageName,
+ UserHandle.USER_SYSTEM);
- final int token = generateToken();
- FullBackupRunner runner = new FullBackupRunner(pkg, mAgent, pipes[1],
- token, sendApk, !isSharedStorage, widgetBlob);
- pipes[1].close(); // the runner has dup'd it
- pipes[1] = null;
- Thread t = new Thread(runner, "app-data-runner");
- t.start();
+ final int token = generateToken();
+ FullBackupRunner runner = new FullBackupRunner(mPkg, mAgent, pipes[1],
+ token, sendApk, !isSharedStorage, widgetBlob);
+ pipes[1].close(); // the runner has dup'd it
+ pipes[1] = null;
+ Thread t = new Thread(runner, "app-data-runner");
+ 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;
- }
+ // Now pull data from the app and stuff it into the output
+ routeSocketDataToOutput(pipes[0], mOutput);
- if (!waitUntilOperationComplete(token)) {
- Slog.e(TAG, "Full backup failed on package " + pkg.packageName);
- result = BackupTransport.AGENT_ERROR;
- } else {
- if (MORE_DEBUG) {
- Slog.d(TAG, "Full package backup success: " + pkg.packageName);
- }
+ if (!waitUntilOperationComplete(token)) {
+ Slog.e(TAG, "Full backup failed on package " + mPkg.packageName);
+ } else {
+ if (MORE_DEBUG) {
+ 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 {
@@ -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) {
@@ -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
@@ -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);
}
@@ -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.
@@ -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();
@@ -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;
@@ -4354,44 +4365,50 @@ 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);
- }
- int nRead = 0;
- do {
- if (!mKeepRunning.get()) {
- if (DEBUG_SCHEDULING) {
- Slog.i(TAG, "Full backup task told to stop");
- }
- break;
- }
- nRead = in.read(buffer);
+ final long preflightResult = backupRunner.getPreflightResultBlocking();
+ // Preflight result is negative if some error happened on preflight.
+ if (preflightResult < 0) {
if (MORE_DEBUG) {
- Slog.v(TAG, "in.read(buffer) from app: " + nRead);
+ Slog.d(TAG, "Backup error after preflight of package "
+ + packageName + ": " + preflightResult
+ + ", not running backup.");
}
- if (nRead > 0) {
- out.write(buffer, 0, nRead);
- backupPackageStatus = transport.sendBackupData(nRead);
- totalRead += nRead;
- if (mBackupObserver != null && expectedSize > 0) {
- sendBackupOnUpdate(mBackupObserver, currentPackage.packageName,
- new BackupProgress(expectedSize, totalRead));
+ backupPackageStatus = (int) preflightResult;
+ } else {
+ int nRead = 0;
+ do {
+ if (!mKeepRunning.get()) {
+ if (DEBUG_SCHEDULING) {
+ Slog.i(TAG, "Full backup task told to stop");
+ }
+ break;
}
- }
- } while (nRead > 0 && backupPackageStatus == BackupTransport.TRANSPORT_OK);
+ nRead = in.read(buffer);
+ if (MORE_DEBUG) {
+ Slog.v(TAG, "in.read(buffer) from app: " + nRead);
+ }
+ if (nRead > 0) {
+ out.write(buffer, 0, nRead);
+ backupPackageStatus = transport.sendBackupData(nRead);
+ totalRead += nRead;
+ if (mBackupObserver != null && preflightResult > 0) {
+ sendBackupOnUpdate(mBackupObserver, packageName,
+ new BackupProgress(preflightResult, totalRead));
+ }
+ }
+ } while (nRead > 0
+ && backupPackageStatus == BackupTransport.TRANSPORT_OK);
- 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
+ // Despite preflight succeeded, package still can hit quota on flight.
+ if (backupPackageStatus == BackupTransport.TRANSPORT_QUOTA_EXCEEDED) {
+ long quota = transport.getBackupQuota(packageName, true);
+ Slog.w(TAG, "Package hit quota limit in-flight " + packageName
+ ": " + totalRead + " of " + quota);
+ backupRunner.sendQuotaExceeded(totalRead, 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
// that we've reached the clean finish state.
@@ -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
@@ -4431,34 +4457,37 @@ 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,
+ packageName);
}
- EventLog.writeEvent(EventLogTags.FULL_BACKUP_QUOTA_EXCEEDED,
- currentPackage.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,
- BackupManager.ERROR_TRANSPORT_ABORTED);
+ sendBackupOnPackageResult(mBackupObserver, packageName,
+ BackupManager.ERROR_TRANSPORT_ABORTED);
Slog.w(TAG, "Transport failed; aborting backup: " + backupPackageStatus);
EventLog.writeEvent(EventLogTags.FULL_BACKUP_TRANSPORT_FAILURE);
// Abort entire backup pass.
@@ -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);
@@ -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() {
+ FileOutputStream out = new FileOutputStream(mOutput.getFileDescriptor());
+ mEngine = new FullBackupEngine(out, mPreflight, mTarget, false);
try {
- FileOutputStream out = new FileOutputStream(mOutput.getFileDescriptor());
- mEngine = new FullBackupEngine(out, mTarget.packageName,
- mPreflight, false);
- mEngine.backupOnePackage(mTarget);
+ 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) {
@@ -4655,8 +4696,28 @@ public class BackupManagerService {
mEngine.sendQuotaExceeded(backupDataBytes, quotaBytes);
}
- long expectedSize() {
- return mPreflight.getExpectedSizeOrErrorCode();
+ // 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;
+ }
}
}
}