diff --git a/services/backup/java/com/android/server/backup/restore/AdbRestoreFinishedRunnable.java b/services/backup/java/com/android/server/backup/restore/AdbRestoreFinishedRunnable.java new file mode 100644 index 0000000000000..dc7044e450b78 --- /dev/null +++ b/services/backup/java/com/android/server/backup/restore/AdbRestoreFinishedRunnable.java @@ -0,0 +1,33 @@ +package com.android.server.backup.restore; + +import android.app.IBackupAgent; +import android.os.RemoteException; + +import com.android.server.backup.BackupManagerService; + +/** + * Runner that can be placed on a separate thread to do in-process invocation of the "restore + * finished" API asynchronously. Used by adb restore. + */ +public class AdbRestoreFinishedRunnable implements Runnable { + + private final IBackupAgent mAgent; + private final int mToken; + private final BackupManagerService mBackupManagerService; + + AdbRestoreFinishedRunnable(IBackupAgent agent, int token, + BackupManagerService backupManagerService) { + mAgent = agent; + mToken = token; + mBackupManagerService = backupManagerService; + } + + @Override + public void run() { + try { + mAgent.doRestoreFinished(mToken, mBackupManagerService.getBackupManagerBinder()); + } catch (RemoteException e) { + // never happens; this is used only for local binder calls + } + } +} diff --git a/services/backup/java/com/android/server/backup/restore/FullRestoreEngine.java b/services/backup/java/com/android/server/backup/restore/FullRestoreEngine.java index 6bc7530008378..1084f52ed36da 100644 --- a/services/backup/java/com/android/server/backup/restore/FullRestoreEngine.java +++ b/services/backup/java/com/android/server/backup/restore/FullRestoreEngine.java @@ -122,15 +122,17 @@ public class FullRestoreEngine extends RestoreEngine { // Widget blob to be restored out-of-band private byte[] mWidgetData = null; + private long mAppVersion; final int mEphemeralOpToken; private final BackupAgentTimeoutParameters mAgentTimeoutParameters; + final boolean mIsAdbRestore; public FullRestoreEngine(BackupManagerService backupManagerService, BackupRestoreTask monitorTask, IFullBackupRestoreObserver observer, IBackupManagerMonitor monitor, PackageInfo onlyPackage, boolean allowApks, - boolean allowObbs, int ephemeralOpToken) { + boolean allowObbs, int ephemeralOpToken, boolean isAdbRestore) { mBackupManagerService = backupManagerService; mEphemeralOpToken = ephemeralOpToken; mMonitorTask = monitorTask; @@ -144,6 +146,7 @@ public class FullRestoreEngine extends RestoreEngine { mAgentTimeoutParameters = Preconditions.checkNotNull( backupManagerService.getAgentTimeoutParameters(), "Timeout parameters cannot be null"); + mIsAdbRestore = isAdbRestore; } public IBackupAgent getAgent() { @@ -209,7 +212,7 @@ public class FullRestoreEngine extends RestoreEngine { } // Now we're really done tearDownPipes(); - tearDownAgent(mTargetApp); + tearDownAgent(mTargetApp, mIsAdbRestore); mTargetApp = null; mAgentPackage = null; } @@ -218,6 +221,9 @@ public class FullRestoreEngine extends RestoreEngine { if (info.path.equals(BACKUP_MANIFEST_FILENAME)) { Signature[] signatures = tarBackupReader.readAppManifestAndReturnSignatures( info); + // readAppManifestAndReturnSignatures() will have extracted the version from + // the manifest, so we save it to use in adb key-value restore later. + mAppVersion = info.version; PackageManagerInternal pmi = LocalServices.getService( PackageManagerInternal.class); RestorePolicy restorePolicy = tarBackupReader.chooseRestorePolicy( @@ -362,7 +368,9 @@ public class FullRestoreEngine extends RestoreEngine { // All set; now set up the IPC and launch the agent setUpPipes(); mAgent = mBackupManagerService.bindToAgentSynchronous(mTargetApp, - ApplicationThreadConstants.BACKUP_MODE_RESTORE_FULL); + FullBackup.KEY_VALUE_DATA_TOKEN.equals(info.domain) + ? ApplicationThreadConstants.BACKUP_MODE_INCREMENTAL + : ApplicationThreadConstants.BACKUP_MODE_RESTORE_FULL); mAgentPackage = pkg; } catch (IOException e) { // fall through to error handling @@ -419,6 +427,8 @@ public class FullRestoreEngine extends RestoreEngine { Slog.d(TAG, "Restoring key-value file for " + pkg + " : " + info.path); } + // Set the version saved from manifest entry. + info.version = mAppVersion; KeyValueAdbRestoreEngine restoreEngine = new KeyValueAdbRestoreEngine( mBackupManagerService, @@ -506,7 +516,7 @@ public class FullRestoreEngine extends RestoreEngine { mBackupManagerService.getBackupHandler().removeMessages( MSG_RESTORE_OPERATION_TIMEOUT); tearDownPipes(); - tearDownAgent(mTargetApp); + tearDownAgent(mTargetApp, false); mAgent = null; mPackagePolicies.put(pkg, RestorePolicy.IGNORE); @@ -559,7 +569,7 @@ public class FullRestoreEngine extends RestoreEngine { tearDownPipes(); setRunning(false); if (mustKillAgent) { - tearDownAgent(mTargetApp); + tearDownAgent(mTargetApp, mIsAdbRestore); } } return (info != null); @@ -588,9 +598,37 @@ public class FullRestoreEngine extends RestoreEngine { } } - private void tearDownAgent(ApplicationInfo app) { + private void tearDownAgent(ApplicationInfo app, boolean doRestoreFinished) { if (mAgent != null) { - mBackupManagerService.tearDownAgentAndKill(app); + try { + // In the adb restore case, we do restore-finished here + if (doRestoreFinished) { + final int token = mBackupManagerService.generateRandomIntegerToken(); + long fullBackupAgentTimeoutMillis = + mAgentTimeoutParameters.getFullBackupAgentTimeoutMillis(); + final AdbRestoreFinishedLatch latch = new AdbRestoreFinishedLatch( + mBackupManagerService, token); + mBackupManagerService.prepareOperationTimeout( + token, fullBackupAgentTimeoutMillis, latch, OP_TYPE_RESTORE_WAIT); + if (mTargetApp.processName.equals("system")) { + if (MORE_DEBUG) { + Slog.d(TAG, "system agent - restoreFinished on thread"); + } + Runnable runner = new AdbRestoreFinishedRunnable(mAgent, token, + mBackupManagerService); + new Thread(runner, "restore-sys-finished-runner").start(); + } else { + mAgent.doRestoreFinished(token, + mBackupManagerService.getBackupManagerBinder()); + } + + latch.await(); + } + + mBackupManagerService.tearDownAgentAndKill(app); + } catch (RemoteException e) { + Slog.d(TAG, "Lost app trying to shut down"); + } mAgent = null; } } diff --git a/services/backup/java/com/android/server/backup/restore/FullRestoreEngineThread.java b/services/backup/java/com/android/server/backup/restore/FullRestoreEngineThread.java new file mode 100644 index 0000000000000..7075608674a1f --- /dev/null +++ b/services/backup/java/com/android/server/backup/restore/FullRestoreEngineThread.java @@ -0,0 +1,63 @@ +package com.android.server.backup.restore; + +import android.os.ParcelFileDescriptor; + +import libcore.io.IoUtils; + +import java.io.FileInputStream; +import java.io.InputStream; + +class FullRestoreEngineThread implements Runnable { + + FullRestoreEngine mEngine; + InputStream mEngineStream; + private final boolean mMustKillAgent; + + FullRestoreEngineThread(FullRestoreEngine engine, ParcelFileDescriptor engineSocket) { + mEngine = engine; + engine.setRunning(true); + // We *do* want this FileInputStream to own the underlying fd, so that + // when we are finished with it, it closes this end of the pipe in a way + // that signals its other end. + mEngineStream = new FileInputStream(engineSocket.getFileDescriptor(), true); + // Tell it to be sure to leave the agent instance up after finishing + mMustKillAgent = false; + } + + //for adb restore + FullRestoreEngineThread(FullRestoreEngine engine, InputStream inputStream) { + mEngine = engine; + engine.setRunning(true); + mEngineStream = inputStream; + // philippov: in adb agent is killed after restore. + mMustKillAgent = true; + } + + public boolean isRunning() { + return mEngine.isRunning(); + } + + public int waitForResult() { + return mEngine.waitForResult(); + } + + @Override + public void run() { + try { + while (mEngine.isRunning()) { + mEngine.restoreOneFile(mEngineStream, mMustKillAgent, mEngine.mBuffer, + mEngine.mOnlyPackage, mEngine.mAllowApks, mEngine.mEphemeralOpToken, + mEngine.mMonitor); + } + } finally { + // Because mEngineStream adopted its underlying FD, this also + // closes this end of the pipe. + IoUtils.closeQuietly(mEngineStream); + } + } + + public void handleTimeout() { + IoUtils.closeQuietly(mEngineStream); + mEngine.handleTimeout(); + } +} diff --git a/services/backup/java/com/android/server/backup/restore/PerformAdbRestoreTask.java b/services/backup/java/com/android/server/backup/restore/PerformAdbRestoreTask.java index 0c99b4400dd6e..78b000d49f382 100644 --- a/services/backup/java/com/android/server/backup/restore/PerformAdbRestoreTask.java +++ b/services/backup/java/com/android/server/backup/restore/PerformAdbRestoreTask.java @@ -18,8 +18,6 @@ package com.android.server.backup.restore; import static com.android.server.backup.BackupManagerService.BACKUP_FILE_HEADER_MAGIC; import static com.android.server.backup.BackupManagerService.BACKUP_FILE_VERSION; -import static com.android.server.backup.BackupManagerService.BACKUP_MANIFEST_FILENAME; -import static com.android.server.backup.BackupManagerService.BACKUP_METADATA_FILENAME; import static com.android.server.backup.BackupManagerService.DEBUG; import static com.android.server.backup.BackupManagerService.MORE_DEBUG; import static com.android.server.backup.BackupManagerService.OP_TYPE_RESTORE_WAIT; @@ -30,15 +28,10 @@ import static com.android.server.backup.BackupPasswordManager.PBKDF_CURRENT; import static com.android.server.backup.BackupPasswordManager.PBKDF_FALLBACK; import static com.android.server.backup.internal.BackupHandler.MSG_RESTORE_OPERATION_TIMEOUT; -import android.app.ApplicationThreadConstants; + import android.app.IBackupAgent; -import android.app.backup.FullBackup; -import android.app.backup.IBackupManagerMonitor; import android.app.backup.IFullBackupRestoreObserver; import android.content.pm.ApplicationInfo; -import android.content.pm.PackageInfo; -import android.content.pm.PackageManager.NameNotFoundException; -import android.content.pm.PackageManagerInternal; import android.content.pm.Signature; import android.os.Environment; import android.os.ParcelFileDescriptor; @@ -50,18 +43,12 @@ import com.android.internal.util.Preconditions; import com.android.server.LocalServices; import com.android.server.backup.BackupAgentTimeoutParameters; import com.android.server.backup.BackupManagerService; -import com.android.server.backup.FileMetadata; -import com.android.server.backup.KeyValueAdbRestoreEngine; import com.android.server.backup.PackageManagerBackupAgent; import com.android.server.backup.fullbackup.FullBackupObbConnection; -import com.android.server.backup.utils.BytesReadListener; import com.android.server.backup.utils.FullBackupRestoreObserverUtils; import com.android.server.backup.utils.PasswordUtils; -import com.android.server.backup.utils.RestoreUtils; -import com.android.server.backup.utils.TarBackupReader; import java.io.FileInputStream; -import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.security.InvalidAlgorithmParameterException; @@ -104,31 +91,6 @@ public class PerformAdbRestoreTask implements Runnable { private long mBytes; private final BackupAgentTimeoutParameters mAgentTimeoutParameters; - // Runner that can be placed on a separate thread to do in-process invocation - // of the "restore finished" API asynchronously. Used by adb restore. - private static class RestoreFinishedRunnable implements Runnable { - - private final IBackupAgent mAgent; - private final int mToken; - private final BackupManagerService mBackupManagerService; - - RestoreFinishedRunnable(IBackupAgent agent, int token, - BackupManagerService backupManagerService) { - mAgent = agent; - mToken = token; - mBackupManagerService = backupManagerService; - } - - @Override - public void run() { - try { - mAgent.doRestoreFinished(mToken, mBackupManagerService.getBackupManagerBinder()); - } catch (RemoteException e) { - // never happens; this is used only for local binder calls - } - } - } - // possible handling states for a given package in the restore dataset private final HashMap mPackagePolicies = new HashMap<>(); @@ -199,23 +161,18 @@ public class PerformAdbRestoreTask implements Runnable { return; } - byte[] buffer = new byte[32 * 1024]; - boolean didRestore; - do { - didRestore = restoreOneFile(tarInputStream, false /* mustKillAgent */, buffer, - null /* onlyPackage */, true /* allowApks */, - mBackupManagerService.generateRandomIntegerToken(), null /* monitor */); - } while (didRestore); + FullRestoreEngine mEngine = new FullRestoreEngine(mBackupManagerService, null, + mObserver, null, null, true, true/*unused*/, 0 /*unused*/, true); + FullRestoreEngineThread mEngineThread = new FullRestoreEngineThread(mEngine, + tarInputStream); + mEngineThread.run(); if (MORE_DEBUG) { - Slog.v(TAG, "Done consuming input tarfile, total bytes=" + mBytes); + Slog.v(TAG, "Done consuming input tarfile."); } } catch (IOException e) { Slog.e(TAG, "Unable to read restore input"); } finally { - tearDownPipes(); - tearDownAgent(mTargetApp, true); - try { if (rawInStream != null) { rawInStream.close(); @@ -433,432 +390,4 @@ public class PerformAdbRestoreTask implements Runnable { return result; } - - boolean restoreOneFile(InputStream instream, boolean mustKillAgent, byte[] buffer, - PackageInfo onlyPackage, boolean allowApks, int token, IBackupManagerMonitor monitor) { - BytesReadListener bytesReadListener = new BytesReadListener() { - @Override - public void onBytesRead(long bytesRead) { - mBytes += bytesRead; - } - }; - TarBackupReader tarBackupReader = new TarBackupReader(instream, - bytesReadListener, monitor); - FileMetadata info; - try { - info = tarBackupReader.readTarHeaders(); - if (info != null) { - if (MORE_DEBUG) { - info.dump(); - } - - final String pkg = info.packageName; - if (!pkg.equals(mAgentPackage)) { - // okay, change in package; set up our various - // bookkeeping if we haven't seen it yet - if (!mPackagePolicies.containsKey(pkg)) { - mPackagePolicies.put(pkg, RestorePolicy.IGNORE); - } - - // Clean up the previous agent relationship if necessary, - // and let the observer know we're considering a new app. - if (mAgent != null) { - if (DEBUG) { - Slog.d(TAG, "Saw new package; finalizing old one"); - } - // Now we're really done - tearDownPipes(); - tearDownAgent(mTargetApp, true); - mTargetApp = null; - mAgentPackage = null; - } - } - - if (info.path.equals(BACKUP_MANIFEST_FILENAME)) { - Signature[] signatures = tarBackupReader.readAppManifestAndReturnSignatures( - info); - // readAppManifestAndReturnSignatures() will have extracted the version from - // the manifest, so we save it to use in key-value restore later. - mAppVersion = info.version; - PackageManagerInternal pmi = LocalServices.getService( - PackageManagerInternal.class); - RestorePolicy restorePolicy = tarBackupReader.chooseRestorePolicy( - mBackupManagerService.getPackageManager(), allowApks, - info, signatures, pmi); - mManifestSignatures.put(info.packageName, signatures); - mPackagePolicies.put(pkg, restorePolicy); - mPackageInstallers.put(pkg, info.installerPackageName); - // We've read only the manifest content itself at this point, - // so consume the footer before looping around to the next - // input file - tarBackupReader.skipTarPadding(info.size); - mObserver = FullBackupRestoreObserverUtils.sendOnRestorePackage(mObserver, pkg); - } else if (info.path.equals(BACKUP_METADATA_FILENAME)) { - // Metadata blobs! - tarBackupReader.readMetadata(info); - - // The following only exist because we want to keep refactoring as safe as - // possible, without changing too much. - // TODO: Refactor, so that there are no funny things like this. - // This is read during TarBackupReader.readMetadata(). - mWidgetData = tarBackupReader.getWidgetData(); - // This can be nulled during TarBackupReader.readMetadata(). - monitor = tarBackupReader.getMonitor(); - - tarBackupReader.skipTarPadding(info.size); - } else { - // Non-manifest, so it's actual file data. Is this a package - // we're ignoring? - boolean okay = true; - RestorePolicy policy = mPackagePolicies.get(pkg); - switch (policy) { - case IGNORE: - okay = false; - break; - - case ACCEPT_IF_APK: - // If we're in accept-if-apk state, then the first file we - // see MUST be the apk. - if (info.domain.equals(FullBackup.APK_TREE_TOKEN)) { - if (DEBUG) { - Slog.d(TAG, "APK file; installing"); - } - // Try to install the app. - String installerPackageName = mPackageInstallers.get(pkg); - boolean isSuccessfullyInstalled = RestoreUtils.installApk(instream, - mBackupManagerService.getContext(), - mDeleteObserver, mManifestSignatures, mPackagePolicies, - info, installerPackageName, bytesReadListener); - // good to go; promote to ACCEPT - mPackagePolicies.put(pkg, isSuccessfullyInstalled - ? RestorePolicy.ACCEPT - : RestorePolicy.IGNORE); - // At this point we've consumed this file entry - // ourselves, so just strip the tar footer and - // go on to the next file in the input stream - tarBackupReader.skipTarPadding(info.size); - return true; - } else { - // File data before (or without) the apk. We can't - // handle it coherently in this case so ignore it. - mPackagePolicies.put(pkg, RestorePolicy.IGNORE); - okay = false; - } - break; - - case ACCEPT: - if (info.domain.equals(FullBackup.APK_TREE_TOKEN)) { - if (DEBUG) { - Slog.d(TAG, "apk present but ACCEPT"); - } - // we can take the data without the apk, so we - // *want* to do so. skip the apk by declaring this - // one file not-okay without changing the restore - // policy for the package. - okay = false; - } - break; - - default: - // Something has gone dreadfully wrong when determining - // the restore policy from the manifest. Ignore the - // rest of this package's data. - Slog.e(TAG, "Invalid policy from manifest"); - okay = false; - mPackagePolicies.put(pkg, RestorePolicy.IGNORE); - break; - } - - // The path needs to be canonical - if (!isCanonicalFilePath(info.path)) { - okay = false; - } - - // If the policy is satisfied, go ahead and set up to pipe the - // data to the agent. - if (DEBUG && okay && mAgent != null) { - Slog.i(TAG, "Reusing existing agent instance"); - } - if (okay && mAgent == null) { - if (DEBUG) { - Slog.d(TAG, "Need to launch agent for " + pkg); - } - - try { - mTargetApp = - mBackupManagerService.getPackageManager().getApplicationInfo( - pkg, 0); - - // If we haven't sent any data to this app yet, we probably - // need to clear it first. Check that. - if (!mClearedPackages.contains(pkg)) { - // apps with their own backup agents are - // responsible for coherently managing a full - // restore. - if (mTargetApp.backupAgentName == null) { - if (DEBUG) { - Slog.d(TAG, - "Clearing app data preparatory to full restore"); - } - mBackupManagerService.clearApplicationDataSynchronous(pkg, true); - } else { - if (DEBUG) { - Slog.d(TAG, "backup agent (" - + mTargetApp.backupAgentName + ") => no clear"); - } - } - mClearedPackages.add(pkg); - } else { - if (DEBUG) { - Slog.d(TAG, "We've initialized this app already; no clear " - + "required"); - } - } - - // All set; now set up the IPC and launch the agent - setUpPipes(); - mAgent = mBackupManagerService.bindToAgentSynchronous(mTargetApp, - FullBackup.KEY_VALUE_DATA_TOKEN.equals(info.domain) - ? ApplicationThreadConstants.BACKUP_MODE_INCREMENTAL - : ApplicationThreadConstants.BACKUP_MODE_RESTORE_FULL); - mAgentPackage = pkg; - } catch (IOException e) { - // fall through to error handling - } catch (NameNotFoundException e) { - // fall through to error handling - } - - if (mAgent == null) { - Slog.e(TAG, "Unable to create agent for " + pkg); - okay = false; - tearDownPipes(); - mPackagePolicies.put(pkg, RestorePolicy.IGNORE); - } - } - - // Sanity check: make sure we never give data to the wrong app. This - // should never happen but a little paranoia here won't go amiss. - if (okay && !pkg.equals(mAgentPackage)) { - Slog.e(TAG, "Restoring data for " + pkg - + " but agent is for " + mAgentPackage); - okay = false; - } - - // At this point we have an agent ready to handle the full - // restore data as well as a pipe for sending data to - // that agent. Tell the agent to start reading from the - // pipe. - if (okay) { - boolean agentSuccess = true; - long toCopy = info.size; - long restoreAgentTimeoutMillis = - mAgentTimeoutParameters.getRestoreAgentTimeoutMillis(); - try { - mBackupManagerService.prepareOperationTimeout( - token, restoreAgentTimeoutMillis, null, OP_TYPE_RESTORE_WAIT); - - if (FullBackup.OBB_TREE_TOKEN.equals(info.domain)) { - if (DEBUG) { - Slog.d(TAG, "Restoring OBB file for " + pkg - + " : " + info.path); - } - mObbConnection.restoreObbFile(pkg, mPipes[0], - info.size, info.type, info.path, info.mode, - info.mtime, token, - mBackupManagerService.getBackupManagerBinder()); - } else if (FullBackup.KEY_VALUE_DATA_TOKEN.equals(info.domain)) { - if (DEBUG) { - Slog.d(TAG, "Restoring key-value file for " + pkg - + " : " + info.path); - } - // Set the version saved from manifest entry. - info.version = mAppVersion; - KeyValueAdbRestoreEngine restoreEngine = - new KeyValueAdbRestoreEngine( - mBackupManagerService, - mBackupManagerService.getDataDir(), info, mPipes[0], - mAgent, token); - new Thread(restoreEngine, "restore-key-value-runner").start(); - } else { - if (DEBUG) { - Slog.d(TAG, "Invoking agent to restore file " + info.path); - } - // fire up the app's agent listening on the socket. If - // the agent is running in the system process we can't - // just invoke it asynchronously, so we provide a thread - // for it here. - if (mTargetApp.processName.equals("system")) { - Slog.d(TAG, "system process agent - spinning a thread"); - RestoreFileRunnable runner = new RestoreFileRunnable( - mBackupManagerService, mAgent, info, mPipes[0], token); - new Thread(runner, "restore-sys-runner").start(); - } else { - mAgent.doRestoreFile(mPipes[0], info.size, info.type, - info.domain, info.path, info.mode, info.mtime, - token, mBackupManagerService.getBackupManagerBinder()); - } - } - } catch (IOException e) { - // couldn't dup the socket for a process-local restore - Slog.d(TAG, "Couldn't establish restore"); - agentSuccess = false; - okay = false; - } catch (RemoteException e) { - // whoops, remote entity went away. We'll eat the content - // ourselves, then, and not copy it over. - Slog.e(TAG, "Agent crashed during full restore"); - agentSuccess = false; - okay = false; - } - - // Copy over the data if the agent is still good - if (okay) { - boolean pipeOkay = true; - FileOutputStream pipe = new FileOutputStream( - mPipes[1].getFileDescriptor()); - while (toCopy > 0) { - int toRead = (toCopy > buffer.length) - ? buffer.length : (int) toCopy; - int nRead = instream.read(buffer, 0, toRead); - if (nRead >= 0) { - mBytes += nRead; - } - if (nRead <= 0) { - break; - } - toCopy -= nRead; - - // send it to the output pipe as long as things - // are still good - if (pipeOkay) { - try { - pipe.write(buffer, 0, nRead); - } catch (IOException e) { - Slog.e(TAG, "Failed to write to restore pipe", e); - pipeOkay = false; - } - } - } - - // done sending that file! Now we just need to consume - // the delta from info.size to the end of block. - tarBackupReader.skipTarPadding(info.size); - - // and now that we've sent it all, wait for the remote - // side to acknowledge receipt - agentSuccess = mBackupManagerService.waitUntilOperationComplete(token); - } - - // 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"); - } - mBackupManagerService.getBackupHandler().removeMessages( - MSG_RESTORE_OPERATION_TIMEOUT); - tearDownPipes(); - tearDownAgent(mTargetApp, false); - mPackagePolicies.put(pkg, RestorePolicy.IGNORE); - } - } - - // Problems setting up the agent communication, or an already- - // ignored package: skip to the next tar stream entry by - // reading and discarding this file. - if (!okay) { - if (DEBUG) { - Slog.d(TAG, "[discarding file content]"); - } - long bytesToConsume = (info.size + 511) & ~511; - while (bytesToConsume > 0) { - int toRead = (bytesToConsume > buffer.length) - ? buffer.length : (int) bytesToConsume; - long nRead = instream.read(buffer, 0, toRead); - if (nRead >= 0) { - mBytes += nRead; - } - if (nRead <= 0) { - break; - } - bytesToConsume -= nRead; - } - } - } - } - } catch (IOException e) { - if (DEBUG) { - Slog.w(TAG, "io exception on restore socket read", e); - } - // treat as EOF - info = null; - } - - return (info != null); - } - - private static boolean isCanonicalFilePath(String path) { - if (path.contains("..") || path.contains("//")) { - if (MORE_DEBUG) { - Slog.w(TAG, "Dropping invalid path " + path); - } - return false; - } - - return true; - } - - private void setUpPipes() throws IOException { - mPipes = ParcelFileDescriptor.createPipe(); - } - - private void tearDownPipes() { - if (mPipes != null) { - try { - mPipes[0].close(); - mPipes[0] = null; - mPipes[1].close(); - mPipes[1] = null; - } catch (IOException e) { - Slog.w(TAG, "Couldn't close agent pipes", e); - } - mPipes = null; - } - } - - private 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 = mBackupManagerService.generateRandomIntegerToken(); - long fullBackupAgentTimeoutMillis = - mAgentTimeoutParameters.getFullBackupAgentTimeoutMillis(); - final AdbRestoreFinishedLatch latch = new AdbRestoreFinishedLatch( - mBackupManagerService, token); - mBackupManagerService.prepareOperationTimeout( - token, fullBackupAgentTimeoutMillis, latch, OP_TYPE_RESTORE_WAIT); - if (mTargetApp.processName.equals("system")) { - if (MORE_DEBUG) { - Slog.d(TAG, "system agent - restoreFinished on thread"); - } - Runnable runner = new RestoreFinishedRunnable(mAgent, token, - mBackupManagerService); - new Thread(runner, "restore-sys-finished-runner").start(); - } else { - mAgent.doRestoreFinished(token, - mBackupManagerService.getBackupManagerBinder()); - } - - latch.await(); - } - - mBackupManagerService.tearDownAgentAndKill(app); - } catch (RemoteException e) { - Slog.d(TAG, "Lost app trying to shut down"); - } - mAgent = null; - } - } - } diff --git a/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java b/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java index 12d72d8a4637b..580f70a046b51 100644 --- a/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java +++ b/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java @@ -841,7 +841,7 @@ public class PerformUnifiedRestoreTask implements BackupRestoreTask { final String TAG = "StreamFeederThread"; FullRestoreEngine mEngine; - EngineThread mEngineThread; + FullRestoreEngineThread mEngineThread; // pipe through which we read data from the transport. [0] read, [1] write ParcelFileDescriptor[] mTransportPipes; @@ -867,8 +867,8 @@ public class PerformUnifiedRestoreTask implements BackupRestoreTask { mCurrentPackage.packageName); mEngine = new FullRestoreEngine(backupManagerService, this, null, - mMonitor, mCurrentPackage, false, false, mEphemeralOpToken); - mEngineThread = new EngineThread(mEngine, mEnginePipes[0]); + mMonitor, mCurrentPackage, false, false, mEphemeralOpToken, false); + mEngineThread = new FullRestoreEngineThread(mEngine, mEnginePipes[0]); ParcelFileDescriptor eWriteEnd = mEnginePipes[1]; ParcelFileDescriptor tReadEnd = mTransportPipes[0]; @@ -1031,50 +1031,6 @@ public class PerformUnifiedRestoreTask implements BackupRestoreTask { } } - class EngineThread implements Runnable { - - FullRestoreEngine mEngine; - FileInputStream mEngineStream; - - EngineThread(FullRestoreEngine engine, ParcelFileDescriptor engineSocket) { - mEngine = engine; - engine.setRunning(true); - // We *do* want this FileInputStream to own the underlying fd, so that - // when we are finished with it, it closes this end of the pipe in a way - // that signals its other end. - mEngineStream = new FileInputStream(engineSocket.getFileDescriptor(), true); - } - - public boolean isRunning() { - return mEngine.isRunning(); - } - - public int waitForResult() { - return mEngine.waitForResult(); - } - - @Override - public void run() { - try { - while (mEngine.isRunning()) { - // Tell it to be sure to leave the agent instance up after finishing - mEngine.restoreOneFile(mEngineStream, false, mEngine.mBuffer, - mEngine.mOnlyPackage, mEngine.mAllowApks, mEngine.mEphemeralOpToken, - mEngine.mMonitor); - } - } finally { - // Because mEngineStream adopted its underlying FD, this also - // closes this end of the pipe. - IoUtils.closeQuietly(mEngineStream); - } - } - - public void handleTimeout() { - IoUtils.closeQuietly(mEngineStream); - mEngine.handleTimeout(); - } - } - // state FINAL : tear everything down and we're done. private void finalizeRestore() { if (MORE_DEBUG) {