summaryrefslogtreecommitdiffstats
path: root/services/java/com/android/server/BackupManagerService.java
diff options
context:
space:
mode:
Diffstat (limited to 'services/java/com/android/server/BackupManagerService.java')
-rw-r--r--services/java/com/android/server/BackupManagerService.java186
1 files changed, 134 insertions, 52 deletions
diff --git a/services/java/com/android/server/BackupManagerService.java b/services/java/com/android/server/BackupManagerService.java
index 4d5e0a6..a7b08f5 100644
--- a/services/java/com/android/server/BackupManagerService.java
+++ b/services/java/com/android/server/BackupManagerService.java
@@ -140,6 +140,8 @@ class BackupManagerService extends IBackupManager.Stub {
static final int BACKUP_FILE_VERSION = 1;
static final boolean COMPRESS_FULL_BACKUPS = true; // should be true in production
+ static final String SHARED_BACKUP_AGENT_PACKAGE = "com.android.sharedstoragebackup";
+
// How often we perform a backup pass. Privileged external callers can
// trigger an immediate pass.
private static final long BACKUP_INTERVAL = AlarmManager.INTERVAL_HOUR;
@@ -235,6 +237,10 @@ class BackupManagerService extends IBackupManager.Stub {
volatile long mLastBackupPass;
volatile long mNextBackupPass;
+ // For debugging, we maintain a progress trace of operations during backup
+ static final boolean DEBUG_BACKUP_TRACE = true;
+ final List<String> mBackupTrace = new ArrayList<String>();
+
// A similar synchronization mechanism around clearing apps' data for restore
final Object mClearDataLock = new Object();
volatile boolean mClearingData;
@@ -652,6 +658,23 @@ class BackupManagerService extends IBackupManager.Stub {
}
}
+ // ----- Debug-only backup operation trace -----
+ void addBackupTrace(String s) {
+ if (DEBUG_BACKUP_TRACE) {
+ synchronized (mBackupTrace) {
+ mBackupTrace.add(s);
+ }
+ }
+ }
+
+ void clearBackupTrace() {
+ if (DEBUG_BACKUP_TRACE) {
+ synchronized (mBackupTrace) {
+ mBackupTrace.clear();
+ }
+ }
+ }
+
// ----- Main service implementation -----
public BackupManagerService(Context context) {
@@ -1612,6 +1635,7 @@ class BackupManagerService extends IBackupManager.Stub {
mAgentConnectLock.wait(5000);
} catch (InterruptedException e) {
// just bail
+ if (DEBUG) Slog.w(TAG, "Interrupted: " + e);
return null;
}
}
@@ -1621,6 +1645,7 @@ class BackupManagerService extends IBackupManager.Stub {
Slog.w(TAG, "Timeout waiting for agent " + app);
return null;
}
+ if (DEBUG) Slog.i(TAG, "got agent " + mConnectedAgent);
agent = mConnectedAgent;
}
} catch (RemoteException e) {
@@ -1650,7 +1675,8 @@ class BackupManagerService extends IBackupManager.Stub {
synchronized(mClearDataLock) {
mClearingData = true;
try {
- mActivityManager.clearApplicationUserData(packageName, observer);
+ mActivityManager.clearApplicationUserData(packageName, observer,
+ Binder.getOrigCallingUser());
} catch (RemoteException e) {
// can't happen because the activity manager is in this process
}
@@ -1814,6 +1840,8 @@ class BackupManagerService extends IBackupManager.Stub {
mCurrentState = BackupState.INITIAL;
mFinished = false;
+
+ addBackupTrace("STATE => INITIAL");
}
// Main entry point: perform one chunk of work, updating the state as appropriate
@@ -1842,11 +1870,25 @@ class BackupManagerService extends IBackupManager.Stub {
// We're starting a backup pass. Initialize the transport and send
// the PM metadata blob if we haven't already.
void beginBackup() {
+ if (DEBUG_BACKUP_TRACE) {
+ clearBackupTrace();
+ StringBuilder b = new StringBuilder(256);
+ b.append("beginBackup: [");
+ for (BackupRequest req : mOriginalQueue) {
+ b.append(' ');
+ b.append(req.packageName);
+ }
+ b.append(" ]");
+ addBackupTrace(b.toString());
+ }
+
mStatus = BackupConstants.TRANSPORT_OK;
// Sanity check: if the queue is empty we have no work to do.
if (mOriginalQueue.isEmpty()) {
Slog.w(TAG, "Backup begun with an empty queue - nothing to do.");
+ addBackupTrace("queue empty at begin");
+ executeNextState(BackupState.FINAL);
return;
}
@@ -1859,13 +1901,17 @@ class BackupManagerService extends IBackupManager.Stub {
File pmState = new File(mStateDir, PACKAGE_MANAGER_SENTINEL);
try {
- EventLog.writeEvent(EventLogTags.BACKUP_START, mTransport.transportDirName());
+ final String transportName = mTransport.transportDirName();
+ EventLog.writeEvent(EventLogTags.BACKUP_START, transportName);
// If we haven't stored package manager metadata yet, we must init the transport.
if (mStatus == BackupConstants.TRANSPORT_OK && pmState.length() <= 0) {
Slog.i(TAG, "Initializing (wiping) backup state and transport storage");
+ addBackupTrace("initializing transport " + transportName);
resetBackupState(mStateDir); // Just to make sure.
mStatus = mTransport.initializeDevice();
+
+ addBackupTrace("transport.initializeDevice() == " + mStatus);
if (mStatus == BackupConstants.TRANSPORT_OK) {
EventLog.writeEvent(EventLogTags.BACKUP_INITIALIZE);
} else {
@@ -1884,6 +1930,7 @@ class BackupManagerService extends IBackupManager.Stub {
mPackageManager, allAgentPackages());
mStatus = invokeAgentForBackup(PACKAGE_MANAGER_SENTINEL,
IBackupAgent.Stub.asInterface(pmAgent.onBind()), mTransport);
+ addBackupTrace("PMBA invoke: " + mStatus);
}
if (mStatus == BackupConstants.TRANSPORT_NOT_INITIALIZED) {
@@ -1894,11 +1941,13 @@ class BackupManagerService extends IBackupManager.Stub {
}
} catch (Exception e) {
Slog.e(TAG, "Error in backup thread", e);
+ addBackupTrace("Exception in backup thread: " + e);
mStatus = BackupConstants.TRANSPORT_ERROR;
} finally {
// If we've succeeded so far, invokeAgentForBackup() will have run the PM
// metadata and its completion/timeout callback will continue the state
// machine chain. If it failed that won't happen; we handle that now.
+ addBackupTrace("exiting prelim: " + mStatus);
if (mStatus != BackupConstants.TRANSPORT_OK) {
// if things went wrong at this point, we need to
// restage everything and try again later.
@@ -1912,11 +1961,12 @@ class BackupManagerService extends IBackupManager.Stub {
// if that was warranted. Now we process the single next thing in the queue.
void invokeNextAgent() {
mStatus = BackupConstants.TRANSPORT_OK;
+ addBackupTrace("invoke q=" + mQueue.size());
// Sanity check that we have work to do. If not, skip to the end where
// we reestablish the wakelock invariants etc.
if (mQueue.isEmpty()) {
- Slog.e(TAG, "Running queue but it's empty!");
+ if (DEBUG) Slog.i(TAG, "queue now empty");
executeNextState(BackupState.FINAL);
return;
}
@@ -1926,6 +1976,7 @@ class BackupManagerService extends IBackupManager.Stub {
mQueue.remove(0);
Slog.d(TAG, "starting agent for backup of " + request);
+ addBackupTrace("launch agent for " + request.packageName);
// Verify that the requested app exists; it might be something that
// requested a backup but was then uninstalled. The request was
@@ -1941,6 +1992,7 @@ class BackupManagerService extends IBackupManager.Stub {
mWakelock.setWorkSource(new WorkSource(mCurrentPackage.applicationInfo.uid));
agent = bindToAgentSynchronous(mCurrentPackage.applicationInfo,
IApplicationThread.BACKUP_MODE_INCREMENTAL);
+ addBackupTrace("agent bound; a? = " + (agent != null));
if (agent != null) {
mStatus = invokeAgentForBackup(request.packageName, agent, mTransport);
// at this point we'll either get a completion callback from the
@@ -1954,14 +2006,17 @@ class BackupManagerService extends IBackupManager.Stub {
// Try for the next one.
Slog.d(TAG, "error in bind/backup", ex);
mStatus = BackupConstants.AGENT_ERROR;
+ addBackupTrace("agent SE");
}
} catch (NameNotFoundException e) {
Slog.d(TAG, "Package does not exist; skipping");
+ addBackupTrace("no such package");
+ mStatus = BackupConstants.AGENT_UNKNOWN;
} finally {
mWakelock.setWorkSource(null);
// If there was an agent error, no timeout/completion handling will occur.
- // That means we need to deal with the next state ourselves.
+ // That means we need to direct to the next state ourselves.
if (mStatus != BackupConstants.TRANSPORT_OK) {
BackupState nextState = BackupState.RUNNING_QUEUE;
@@ -1973,18 +2028,26 @@ class BackupManagerService extends IBackupManager.Stub {
dataChangedImpl(request.packageName);
mStatus = BackupConstants.TRANSPORT_OK;
if (mQueue.isEmpty()) nextState = BackupState.FINAL;
- } else if (mStatus != BackupConstants.TRANSPORT_OK) {
+ } else if (mStatus == BackupConstants.AGENT_UNKNOWN) {
+ // Failed lookup of the app, so we couldn't bring up an agent, but
+ // we're otherwise fine. Just drop it and go on to the next as usual.
+ mStatus = BackupConstants.TRANSPORT_OK;
+ } else {
// Transport-level failure means we reenqueue everything
revertAndEndBackup();
nextState = BackupState.FINAL;
}
executeNextState(nextState);
+ } else {
+ addBackupTrace("expecting completion/timeout callback");
}
}
}
void finalizeBackup() {
+ addBackupTrace("finishing");
+
// Either backup was successful, in which case we of course do not need
// this pass's journal any more; or it failed, in which case we just
// re-enqueued all of these packages in the current active journal.
@@ -1997,6 +2060,7 @@ class BackupManagerService extends IBackupManager.Stub {
// done a backup, we can now record what the current backup dataset token
// is.
if ((mCurrentToken == 0) && (mStatus == BackupConstants.TRANSPORT_OK)) {
+ addBackupTrace("success; recording token");
try {
mCurrentToken = mTransport.getCurrentRestoreSet();
} catch (RemoteException e) {} // can't happen
@@ -2012,11 +2076,13 @@ class BackupManagerService extends IBackupManager.Stub {
// Make sure we back up everything and perform the one-time init
clearMetadata();
if (DEBUG) Slog.d(TAG, "Server requires init; rerunning");
+ addBackupTrace("init required; rerunning");
backupNow();
}
}
// Only once we're entirely finished do we release the wakelock
+ clearBackupTrace();
Slog.i(TAG, "Backup pass finished.");
mWakelock.release();
}
@@ -2031,7 +2097,8 @@ class BackupManagerService extends IBackupManager.Stub {
// handler in case it doesn't get back to us.
int invokeAgentForBackup(String packageName, IBackupAgent agent,
IBackupTransport transport) {
- if (DEBUG) Slog.d(TAG, "processOneBackup doBackup() on " + packageName);
+ if (DEBUG) Slog.d(TAG, "invokeAgentForBackup on " + packageName);
+ addBackupTrace("invoking " + packageName);
mSavedStateName = new File(mStateDir, packageName);
mBackupDataName = new File(mDataDir, packageName + ".data");
@@ -2071,10 +2138,13 @@ class BackupManagerService extends IBackupManager.Stub {
ParcelFileDescriptor.MODE_TRUNCATE);
// Initiate the target's backup pass
+ addBackupTrace("setting timeout");
prepareOperationTimeout(token, TIMEOUT_BACKUP_INTERVAL, this);
+ addBackupTrace("calling agent doBackup()");
agent.doBackup(mSavedState, mBackupData, mNewState, token, mBackupManagerBinder);
} catch (Exception e) {
Slog.e(TAG, "Error invoking for backup on " + packageName);
+ addBackupTrace("exception: " + e);
EventLog.writeEvent(EventLogTags.BACKUP_AGENT_FAILURE, packageName,
e.toString());
agentErrorCleanup();
@@ -2085,6 +2155,7 @@ class BackupManagerService extends IBackupManager.Stub {
// either be a callback from the agent, at which point we'll process its data
// for transport, or a timeout. Either way the next phase will happen in
// response to the TimeoutHandler interface callbacks.
+ addBackupTrace("invoke success");
return BackupConstants.TRANSPORT_OK;
}
@@ -2096,6 +2167,7 @@ class BackupManagerService extends IBackupManager.Stub {
+ mCurrentPackage.packageName);
mBackupHandler.removeMessages(MSG_TIMEOUT);
clearAgentState();
+ addBackupTrace("operation complete");
ParcelFileDescriptor backupData = null;
mStatus = BackupConstants.TRANSPORT_OK;
@@ -2105,6 +2177,7 @@ class BackupManagerService extends IBackupManager.Stub {
if (mStatus == BackupConstants.TRANSPORT_OK) {
backupData = ParcelFileDescriptor.open(mBackupDataName,
ParcelFileDescriptor.MODE_READ_ONLY);
+ addBackupTrace("sending data to transport");
mStatus = mTransport.performBackup(mCurrentPackage, backupData);
}
@@ -2113,11 +2186,15 @@ class BackupManagerService extends IBackupManager.Stub {
// hold off on finishBackup() until the end, which implies holding off on
// renaming *all* the output state files (see below) until that happens.
+ addBackupTrace("data delivered: " + mStatus);
if (mStatus == BackupConstants.TRANSPORT_OK) {
+ addBackupTrace("finishing op on transport");
mStatus = mTransport.finishBackup();
+ addBackupTrace("finished: " + mStatus);
}
} else {
if (DEBUG) Slog.i(TAG, "no backup data written; not calling transport");
+ addBackupTrace("no data to send");
}
// After successful transport, delete the now-stale data
@@ -2165,12 +2242,14 @@ class BackupManagerService extends IBackupManager.Stub {
Slog.e(TAG, "Timeout backing up " + mCurrentPackage.packageName);
EventLog.writeEvent(EventLogTags.BACKUP_AGENT_FAILURE, mCurrentPackage.packageName,
"timeout");
+ addBackupTrace("timeout of " + mCurrentPackage.packageName);
agentErrorCleanup();
dataChangedImpl(mCurrentPackage.packageName);
}
void revertAndEndBackup() {
if (MORE_DEBUG) Slog.i(TAG, "Reverting backup queue - restaging everything");
+ addBackupTrace("transport error; reverting");
for (BackupRequest request : mOriginalQueue) {
dataChangedImpl(request.packageName);
}
@@ -2199,6 +2278,7 @@ class BackupManagerService extends IBackupManager.Stub {
// If this was a pseudopackage there's no associated Activity Manager state
if (mCurrentPackage.applicationInfo != null) {
+ addBackupTrace("unbinding " + mCurrentPackage.packageName);
try { // unbind even on timeout, just in case
mActivityManager.unbindBackupAgent(mCurrentPackage.applicationInfo);
} catch (RemoteException e) {}
@@ -2206,6 +2286,7 @@ class BackupManagerService extends IBackupManager.Stub {
}
void restartBackupAlarm() {
+ addBackupTrace("setting backup trigger");
synchronized (mQueueLock) {
try {
startBackupAlarmsLocked(mTransport.requestBackupTime());
@@ -2216,6 +2297,7 @@ class BackupManagerService extends IBackupManager.Stub {
void executeNextState(BackupState nextState) {
if (MORE_DEBUG) Slog.i(TAG, " => executing next step on "
+ this + " nextState=" + nextState);
+ addBackupTrace("executeNextState => " + nextState);
mCurrentState = nextState;
Message msg = mBackupHandler.obtainMessage(MSG_BACKUP_RESTORE_STEP, this);
mBackupHandler.sendMessage(msg);
@@ -2246,14 +2328,16 @@ class BackupManagerService extends IBackupManager.Stub {
ParcelFileDescriptor mPipe;
int mToken;
boolean mSendApk;
+ boolean mWriteManifest;
FullBackupRunner(PackageInfo pack, IBackupAgent agent, ParcelFileDescriptor pipe,
- int token, boolean sendApk) throws IOException {
+ int token, boolean sendApk, boolean writeManifest) throws IOException {
mPackage = pack;
mAgent = agent;
mPipe = ParcelFileDescriptor.dup(pipe.getFileDescriptor());
mToken = token;
mSendApk = sendApk;
+ mWriteManifest = writeManifest;
}
@Override
@@ -2262,12 +2346,14 @@ class BackupManagerService extends IBackupManager.Stub {
BackupDataOutput output = new BackupDataOutput(
mPipe.getFileDescriptor());
- if (MORE_DEBUG) Slog.d(TAG, "Writing manifest for " + mPackage.packageName);
- writeAppManifest(mPackage, mManifestFile, mSendApk);
- FullBackup.backupToTar(mPackage.packageName, null, null,
- mFilesDir.getAbsolutePath(),
- mManifestFile.getAbsolutePath(),
- output);
+ if (mWriteManifest) {
+ if (MORE_DEBUG) Slog.d(TAG, "Writing manifest for " + mPackage.packageName);
+ writeAppManifest(mPackage, mManifestFile, mSendApk);
+ FullBackup.backupToTar(mPackage.packageName, null, null,
+ mFilesDir.getAbsolutePath(),
+ mManifestFile.getAbsolutePath(),
+ output);
+ }
if (mSendApk) {
writeApkToBackup(mPackage, output);
@@ -2354,10 +2440,13 @@ class BackupManagerService extends IBackupManager.Stub {
}
}
- // Cull any packages that have indicated that backups are not permitted.
+ // Cull any packages that have indicated that backups are not permitted, as well
+ // as any explicit mention of the 'special' shared-storage agent package (we
+ // handle that one at the end).
for (int i = 0; i < packagesToBackup.size(); ) {
PackageInfo pkg = packagesToBackup.get(i);
- if ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_ALLOW_BACKUP) == 0) {
+ if ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_ALLOW_BACKUP) == 0
+ || pkg.packageName.equals(SHARED_BACKUP_AGENT_PACKAGE)) {
packagesToBackup.remove(i);
} else {
i++;
@@ -2437,6 +2526,16 @@ class BackupManagerService extends IBackupManager.Stub {
return;
}
+ // Shared storage if requested
+ if (mIncludeShared) {
+ try {
+ pkg = mPackageManager.getPackageInfo(SHARED_BACKUP_AGENT_PACKAGE, 0);
+ packagesToBackup.add(pkg);
+ } catch (NameNotFoundException e) {
+ Slog.e(TAG, "Unable to find shared-storage backup handler");
+ }
+ }
+
// Now back up the app data via the agent mechanism
int N = packagesToBackup.size();
for (int i = 0; i < N; i++) {
@@ -2444,11 +2543,6 @@ class BackupManagerService extends IBackupManager.Stub {
backupOnePackage(pkg, out);
}
- // Shared storage if requested
- if (mIncludeShared) {
- backupSharedStorage();
- }
-
// Done!
finalizeBackup(out);
} catch (RemoteException e) {
@@ -2554,19 +2648,21 @@ class BackupManagerService extends IBackupManager.Stub {
if (agent != null) {
ParcelFileDescriptor[] pipes = null;
try {
- 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.flags & ApplicationInfo.FLAG_FORWARD_LOCK) == 0)
&& ((app.flags & ApplicationInfo.FLAG_SYSTEM) == 0 ||
(app.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0);
- sendOnBackupPackage(pkg.packageName);
+ sendOnBackupPackage(isSharedStorage ? "Shared storage" : pkg.packageName);
final int token = generateToken();
FullBackupRunner runner = new FullBackupRunner(pkg, agent, pipes[1],
- token, sendApk);
+ token, sendApk, !isSharedStorage);
pipes[1].close(); // the runner has dup'd it
pipes[1] = null;
Thread t = new Thread(runner);
@@ -2641,33 +2737,6 @@ class BackupManagerService extends IBackupManager.Stub {
}
}
- private void backupSharedStorage() throws RemoteException {
- PackageInfo pkg = null;
- try {
- pkg = mPackageManager.getPackageInfo("com.android.sharedstoragebackup", 0);
- IBackupAgent agent = bindToAgentSynchronous(pkg.applicationInfo,
- IApplicationThread.BACKUP_MODE_FULL);
- if (agent != null) {
- sendOnBackupPackage("Shared storage");
-
- final int token = generateToken();
- prepareOperationTimeout(token, TIMEOUT_SHARED_BACKUP_INTERVAL, null);
- agent.doFullBackup(mOutputFile, token, mBackupManagerBinder);
- if (!waitUntilOperationComplete(token)) {
- Slog.e(TAG, "Full backup failed on shared storage");
- } else {
- if (DEBUG) Slog.d(TAG, "Full shared storage backup success");
- }
- } else {
- Slog.e(TAG, "Could not bind to shared storage backup agent");
- }
- } catch (NameNotFoundException e) {
- Slog.e(TAG, "Shared storage backup package not found");
- } finally {
- tearDown(pkg);
- }
- }
-
private void finalizeBackup(OutputStream out) {
try {
// A standard 'tar' EOF sequence: two 512-byte blocks of all zeroes.
@@ -2893,7 +2962,7 @@ class BackupManagerService extends IBackupManager.Stub {
// Are we able to restore shared-storage data?
if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
- mPackagePolicies.put("com.android.sharedstoragebackup", RestorePolicy.ACCEPT);
+ mPackagePolicies.put(SHARED_BACKUP_AGENT_PACKAGE, RestorePolicy.ACCEPT);
}
FileInputStream rawInStream = null;
@@ -3771,7 +3840,7 @@ class BackupManagerService extends IBackupManager.Stub {
info.path, 0, FullBackup.SHARED_PREFIX.length())) {
// File in shared storage. !!! TODO: implement this.
info.path = info.path.substring(FullBackup.SHARED_PREFIX.length());
- info.packageName = "com.android.sharedstoragebackup";
+ info.packageName = SHARED_BACKUP_AGENT_PACKAGE;
info.domain = FullBackup.SHARED_STORAGE_TOKEN;
if (DEBUG) Slog.i(TAG, "File in shared storage: " + info.path);
} else if (FullBackup.APPS_PREFIX.regionMatches(0,
@@ -4715,6 +4784,8 @@ class BackupManagerService extends IBackupManager.Stub {
// one already there, then overwrite it, but no harm done.
BackupRequest req = new BackupRequest(packageName);
if (mPendingBackups.put(app.packageName, req) == null) {
+ if (DEBUG) Slog.d(TAG, "Now staging backup of " + packageName);
+
// Journal this request in case of crash. The put()
// operation returned null when this package was not already
// in the set; we want to avoid touching the disk redundantly.
@@ -5736,6 +5807,17 @@ class BackupManagerService extends IBackupManager.Stub {
pw.println(" " + s);
}
+ if (DEBUG_BACKUP_TRACE) {
+ synchronized (mBackupTrace) {
+ if (!mBackupTrace.isEmpty()) {
+ pw.println("Most recent backup trace:");
+ for (String s : mBackupTrace) {
+ pw.println(" " + s);
+ }
+ }
+ }
+ }
+
int N = mBackupParticipants.size();
pw.println("Participants:");
for (int i=0; i<N; i++) {