diff options
Diffstat (limited to 'services/java/com/android/server/BackupManagerService.java')
-rw-r--r-- | services/java/com/android/server/BackupManagerService.java | 186 |
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++) { |