Full backup/restore now handles OBBs sensibly

OBB backup/ restore is no longer handled within the target app
process.  This is done to avoid having to require that OBB-using
apps have full read/write permission for external storage.

The new OBB backup service is a new component running in the
same app as the already-existing shared storage backup agent.
The backup infrastructure delegates backup/restore of apps'
OBB contents to this component (because the system process
may not itself read/write external storage).

From the command line, OBB backup is enabled by using new
-obb / -noobb flags with adb backup.  The default is noobb.

Finally, a couple of nit fixes:

- buffer-size mismatch between the writer and reader of chunked
  file data has been corrected; now the reading side won't be
  issuing an extra pipe read per chunk.

- bu now explicitly closes the transport socket fd after
  adopting it. This was benign but triggered a logged
  warning about leaked fds.

Bug: 6718844
Change-Id: Ie252494e2327e9ab97cf9ed87c298410a8618492
This commit is contained in:
Christopher Tate
2013-02-19 14:08:59 -08:00
parent 32884c376f
commit 46cc43c6fa
11 changed files with 418 additions and 64 deletions

View File

@@ -180,6 +180,7 @@ LOCAL_SRC_FILES += \
core/java/com/android/internal/appwidget/IAppWidgetService.aidl \
core/java/com/android/internal/appwidget/IAppWidgetHost.aidl \
core/java/com/android/internal/backup/IBackupTransport.aidl \
core/java/com/android/internal/backup/IObbBackupService.aidl \
core/java/com/android/internal/policy/IFaceLockCallback.aidl \
core/java/com/android/internal/policy/IFaceLockInterface.aidl \
core/java/com/android/internal/policy/IKeyguardShowCallback.aidl \

View File

@@ -22,6 +22,7 @@ import android.os.RemoteException;
import android.os.ServiceManager;
import android.util.Log;
import java.io.IOException;
import java.util.ArrayList;
public final class Backup {
@@ -64,6 +65,7 @@ public final class Backup {
private void doFullBackup(int socketFd) {
ArrayList<String> packages = new ArrayList<String>();
boolean saveApks = false;
boolean saveObbs = false;
boolean saveShared = false;
boolean doEverything = false;
boolean allIncludesSystem = true;
@@ -75,6 +77,10 @@ public final class Backup {
saveApks = true;
} else if ("-noapk".equals(arg)) {
saveApks = false;
} else if ("-obb".equals(arg)) {
saveObbs = true;
} else if ("-noobb".equals(arg)) {
saveObbs = false;
} else if ("-shared".equals(arg)) {
saveShared = true;
} else if ("-noshared".equals(arg)) {
@@ -104,23 +110,37 @@ public final class Backup {
return;
}
ParcelFileDescriptor fd = null;
try {
ParcelFileDescriptor fd = ParcelFileDescriptor.adoptFd(socketFd);
fd = ParcelFileDescriptor.adoptFd(socketFd);
String[] packArray = new String[packages.size()];
mBackupManager.fullBackup(fd, saveApks, saveShared, doEverything, allIncludesSystem,
packages.toArray(packArray));
mBackupManager.fullBackup(fd, saveApks, saveObbs, saveShared, doEverything,
allIncludesSystem, packages.toArray(packArray));
} catch (RemoteException e) {
Log.e(TAG, "Unable to invoke backup manager for backup");
} finally {
if (fd != null) {
try {
fd.close();
} catch (IOException e) {}
}
}
}
private void doFullRestore(int socketFd) {
// No arguments to restore
ParcelFileDescriptor fd = null;
try {
ParcelFileDescriptor fd = ParcelFileDescriptor.adoptFd(socketFd);
fd = ParcelFileDescriptor.adoptFd(socketFd);
mBackupManager.fullRestore(fd);
} catch (RemoteException e) {
Log.e(TAG, "Unable to invoke backup manager for restore");
} finally {
if (fd != null) {
try {
fd.close();
} catch (IOException e) {}
}
}
}

View File

@@ -472,6 +472,7 @@ public abstract class BackupAgent extends ContextWrapper {
File efLocation = getExternalFilesDir(null);
if (efLocation != null) {
basePath = getExternalFilesDir(null).getCanonicalPath();
mode = -1; // < 0 is a token to skip attempting a chmod()
}
}
} else {

View File

@@ -89,7 +89,7 @@ public class FullBackup {
* last modification time of the output file. if the {@code mode} parameter is
* negative then this parameter will be ignored.
* @param outFile Location within the filesystem to place the data. This must point
* to a location that is writeable by the caller, prefereably using an absolute path.
* to a location that is writeable by the caller, preferably using an absolute path.
* @throws IOException
*/
static public void restoreFile(ParcelFileDescriptor data,

View File

@@ -152,6 +152,8 @@ interface IBackupManager {
* @param fd The file descriptor to which a 'tar' file stream is to be written
* @param includeApks If <code>true</code>, the resulting tar stream will include the
* application .apk files themselves as well as their data.
* @param includeObbs If <code>true</code>, the resulting tar stream will include any
* application expansion (OBB) files themselves belonging to each application.
* @param includeShared If <code>true</code>, the resulting tar stream will include
* the contents of the device's shared storage (SD card or equivalent).
* @param allApps If <code>true</code>, the resulting tar stream will include all
@@ -164,8 +166,9 @@ interface IBackupManager {
* @param packageNames The package names of the apps whose data (and optionally .apk files)
* are to be backed up. The <code>allApps</code> parameter supersedes this.
*/
void fullBackup(in ParcelFileDescriptor fd, boolean includeApks, boolean includeShared,
boolean allApps, boolean allIncludesSystem, in String[] packageNames);
void fullBackup(in ParcelFileDescriptor fd, boolean includeApks, boolean includeObbs,
boolean includeShared, boolean allApps, boolean allIncludesSystem,
in String[] packageNames);
/**
* Restore device content from the data stream passed through the given socket. The

View File

@@ -0,0 +1,45 @@
/*
* Copyright 2013, The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.internal.backup;
import android.app.backup.IBackupManager;
import android.os.ParcelFileDescriptor;
/**
* Interface for the Backup Manager Service to communicate with a helper service that
* handles local (whole-file) backup & restore of OBB content on behalf of applications.
* This can't be done within the Backup Manager Service itself because of the restrictions
* on system-user access to external storage, and can't be left to the apps because even
* apps that do not have permission to access external storage in the usual way can still
* use OBBs.
*
* {@hide}
*/
oneway interface IObbBackupService {
/*
* Back up a package's OBB directory tree
*/
void backupObbs(in String packageName, in ParcelFileDescriptor data,
int token, in IBackupManager callbackBinder);
/*
* Restore an OBB file for the given package from the incoming stream
*/
void restoreObbFile(in String pkgName, in ParcelFileDescriptor data,
long fileSize, int type, in String path, long mode, long mtime,
int token, in IBackupManager callbackBinder);
}

View File

@@ -553,7 +553,7 @@ int write_tarfile(const String8& packageName, const String8& domain,
if (buf == NULL) {
ALOGE("Out of mem allocating transfer buffer");
err = ENOMEM;
goto cleanup;
goto done;
}
// Magic fields for the ustar file format

View File

@@ -24,5 +24,12 @@
<application android:allowClearUserData="false"
android:permission="android.permission.CONFIRM_FULL_BACKUP"
android:backupAgent="SharedStorageAgent" >
<service android:name=".ObbBackupService"
android:enabled="true"
android:exported="true">
</service>
</application>
</manifest>

View File

@@ -1 +1,2 @@
-keep class com.android.sharedstoragebackup.SharedStorageAgent
-keep class com.android.sharedstoragebackup.ObbBackupService

View File

@@ -0,0 +1,151 @@
/*
* Copyright (C) 2013 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.sharedstoragebackup;
import android.app.Service;
import android.app.backup.BackupDataOutput;
import android.app.backup.FullBackup;
import android.app.backup.IBackupManager;
import android.content.Intent;
import android.os.Environment;
import android.os.IBinder;
import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
import android.util.Log;
import java.io.File;
import java.io.FileDescriptor;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import com.android.internal.backup.IObbBackupService;
/**
* Service that the Backup Manager Services delegates OBB backup/restore operations to,
* because those require accessing external storage.
*
* {@hide}
*/
public class ObbBackupService extends Service {
static final String TAG = "ObbBackupService";
static final boolean DEBUG = true;
/**
* IObbBackupService interface implementation
*/
IObbBackupService mService = new IObbBackupService.Stub() {
/*
* Back up a package's OBB directory tree
*/
@Override
public void backupObbs(String packageName, ParcelFileDescriptor data,
int token, IBackupManager callbackBinder) {
final FileDescriptor outFd = data.getFileDescriptor();
try {
File obbDir = Environment.getExternalStorageAppObbDirectory(packageName);
if (obbDir != null) {
if (obbDir.exists()) {
ArrayList<File> obbList = allFileContents(obbDir);
if (obbList != null) {
// okay, there's at least something there
if (DEBUG) {
Log.i(TAG, obbList.size() + " files to back up");
}
final String rootPath = obbDir.getCanonicalPath();
final BackupDataOutput out = new BackupDataOutput(outFd);
for (File f : obbList) {
final String filePath = f.getCanonicalPath();
if (DEBUG) {
Log.i(TAG, "storing: " + filePath);
}
FullBackup.backupToTar(packageName, FullBackup.OBB_TREE_TOKEN, null,
rootPath, filePath, out);
}
}
}
}
} catch (IOException e) {
Log.w(TAG, "Exception backing up OBBs for " + packageName, e);
} finally {
// Send the EOD marker indicating that there is no more data
try {
FileOutputStream out = new FileOutputStream(outFd);
byte[] buf = new byte[4];
out.write(buf);
} catch (IOException e) {
Log.e(TAG, "Unable to finalize obb backup stream!");
}
try {
callbackBinder.opComplete(token);
} catch (RemoteException e) {
}
}
}
/*
* Restore an OBB file for the given package from the incoming stream
*/
@Override
public void restoreObbFile(String packageName, ParcelFileDescriptor data,
long fileSize, int type, String path, long mode, long mtime,
int token, IBackupManager callbackBinder) {
try {
File outFile = Environment.getExternalStorageAppObbDirectory(packageName);
if (outFile != null) {
outFile = new File(outFile, path);
}
// outFile is null here if we couldn't get access to external storage,
// in which case restoreFile() will discard the data cleanly and let
// us proceed with the next file segment in the stream. We pass -1
// for the file mode to suppress attempts to chmod() on shared storage.
FullBackup.restoreFile(data, fileSize, type, -1, mtime, outFile);
} catch (IOException e) {
Log.i(TAG, "Exception restoring OBB " + path, e);
} finally {
try {
callbackBinder.opComplete(token);
} catch (RemoteException e) {
}
}
}
ArrayList<File> allFileContents(File rootDir) {
final ArrayList<File> files = new ArrayList<File>();
final ArrayList<File> dirs = new ArrayList<File>();
dirs.add(rootDir);
while (!dirs.isEmpty()) {
File dir = dirs.remove(0);
File[] contents = dir.listFiles();
if (contents != null) {
for (File f : contents) {
if (f.isDirectory()) dirs.add(f);
else if (f.isFile()) files.add(f);
}
}
}
return files;
}
};
@Override
public IBinder onBind(Intent intent) {
return mService.asBinder();
}
}

View File

@@ -78,6 +78,7 @@ import android.util.StringBuilderPrinter;
import com.android.internal.backup.BackupConstants;
import com.android.internal.backup.IBackupTransport;
import com.android.internal.backup.IObbBackupService;
import com.android.internal.backup.LocalTransport;
import com.android.server.PackageManagerBackupAgent.Metadata;
@@ -363,15 +364,17 @@ class BackupManagerService extends IBackupManager.Stub {
class FullBackupParams extends FullParams {
public boolean includeApks;
public boolean includeObbs;
public boolean includeShared;
public boolean allApps;
public boolean includeSystem;
public String[] packages;
FullBackupParams(ParcelFileDescriptor output, boolean saveApks, boolean saveShared,
boolean doAllApps, boolean doSystem, String[] pkgList) {
FullBackupParams(ParcelFileDescriptor output, boolean saveApks, boolean saveObbs,
boolean saveShared, boolean doAllApps, boolean doSystem, String[] pkgList) {
fd = output;
includeApks = saveApks;
includeObbs = saveObbs;
includeShared = saveShared;
allApps = doAllApps;
includeSystem = doSystem;
@@ -550,7 +553,7 @@ class BackupManagerService extends IBackupManager.Stub {
// similar to normal backup/restore.
FullBackupParams params = (FullBackupParams)msg.obj;
PerformFullBackupTask task = new PerformFullBackupTask(params.fd,
params.observer, params.includeApks,
params.observer, params.includeApks, params.includeObbs,
params.includeShared, params.curPassword, params.encryptPassword,
params.allApps, params.includeSystem, params.packages, params.latch);
(new Thread(task)).start();
@@ -2306,13 +2309,132 @@ class BackupManagerService extends IBackupManager.Stub {
}
// ----- Full backup to a file/socket -----
// ----- Full backup/restore to a file/socket -----
class PerformFullBackupTask implements Runnable {
abstract class ObbServiceClient {
public IObbBackupService mObbService;
public void setObbBinder(IObbBackupService binder) {
mObbService = binder;
}
}
class FullBackupObbConnection implements ServiceConnection {
volatile IObbBackupService mService;
FullBackupObbConnection() {
mService = null;
}
public void establish() {
if (DEBUG) Slog.i(TAG, "Initiating bind of OBB service on " + this);
Intent obbIntent = new Intent().setComponent(new ComponentName(
"com.android.sharedstoragebackup",
"com.android.sharedstoragebackup.ObbBackupService"));
BackupManagerService.this.mContext.bindService(
obbIntent, this, Context.BIND_AUTO_CREATE);
}
public void tearDown() {
BackupManagerService.this.mContext.unbindService(this);
}
public boolean backupObbs(PackageInfo pkg, OutputStream out) {
boolean success = false;
waitForConnection();
ParcelFileDescriptor[] pipes = null;
try {
pipes = ParcelFileDescriptor.createPipe();
int token = generateToken();
prepareOperationTimeout(token, TIMEOUT_FULL_BACKUP_INTERVAL, null);
mService.backupObbs(pkg.packageName, pipes[1], token, mBackupManagerBinder);
routeSocketDataToOutput(pipes[0], out);
success = waitUntilOperationComplete(token);
} catch (Exception e) {
Slog.w(TAG, "Unable to back up OBBs for " + pkg, e);
} finally {
try {
out.flush();
if (pipes != null) {
if (pipes[0] != null) pipes[0].close();
if (pipes[1] != null) pipes[1].close();
}
} catch (IOException e) {
Slog.w(TAG, "I/O error closing down OBB backup", e);
}
}
return success;
}
public void restoreObbFile(String pkgName, ParcelFileDescriptor data,
long fileSize, int type, String path, long mode, long mtime,
int token, IBackupManager callbackBinder) {
waitForConnection();
try {
mService.restoreObbFile(pkgName, data, fileSize, type, path, mode, mtime,
token, callbackBinder);
} catch (Exception e) {
Slog.w(TAG, "Unable to restore OBBs for " + pkgName, e);
}
}
private void waitForConnection() {
synchronized (this) {
while (mService == null) {
if (DEBUG) Slog.i(TAG, "...waiting for OBB service binding...");
try {
this.wait();
} catch (InterruptedException e) { /* never interrupted */ }
}
if (DEBUG) Slog.i(TAG, "Connected to OBB service; continuing");
}
}
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
synchronized (this) {
mService = IObbBackupService.Stub.asInterface(service);
if (DEBUG) Slog.i(TAG, "OBB service connection " + mService
+ " connected on " + this);
this.notifyAll();
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
synchronized (this) {
mService = null;
if (DEBUG) Slog.i(TAG, "OBB service connection disconnected on " + this);
this.notifyAll();
}
}
}
private void routeSocketDataToOutput(ParcelFileDescriptor inPipe, OutputStream out)
throws IOException {
FileInputStream raw = new FileInputStream(inPipe.getFileDescriptor());
DataInputStream in = new DataInputStream(raw);
byte[] buffer = new byte[32 * 1024];
int chunkTotal;
while ((chunkTotal = in.readInt()) > 0) {
while (chunkTotal > 0) {
int toRead = (chunkTotal > buffer.length) ? buffer.length : chunkTotal;
int nRead = in.read(buffer, 0, toRead);
out.write(buffer, 0, nRead);
chunkTotal -= nRead;
}
}
}
class PerformFullBackupTask extends ObbServiceClient implements Runnable {
ParcelFileDescriptor mOutputFile;
DeflaterOutputStream mDeflater;
IFullBackupRestoreObserver mObserver;
boolean mIncludeApks;
boolean mIncludeObbs;
boolean mIncludeShared;
boolean mAllApps;
final boolean mIncludeSystem;
@@ -2322,6 +2444,7 @@ class BackupManagerService extends IBackupManager.Stub {
AtomicBoolean mLatchObject;
File mFilesDir;
File mManifestFile;
class FullBackupRunner implements Runnable {
PackageInfo mPackage;
@@ -2377,12 +2500,13 @@ class BackupManagerService extends IBackupManager.Stub {
}
PerformFullBackupTask(ParcelFileDescriptor fd, IFullBackupRestoreObserver observer,
boolean includeApks, boolean includeShared, String curPassword,
String encryptPassword, boolean doAllApps, boolean doSystem, String[] packages,
AtomicBoolean latch) {
boolean includeApks, boolean includeObbs, boolean includeShared,
String curPassword, String encryptPassword, boolean doAllApps,
boolean doSystem, String[] packages, AtomicBoolean latch) {
mOutputFile = fd;
mObserver = observer;
mIncludeApks = includeApks;
mIncludeObbs = includeObbs;
mIncludeShared = includeShared;
mAllApps = doAllApps;
mIncludeSystem = doSystem;
@@ -2405,9 +2529,12 @@ class BackupManagerService extends IBackupManager.Stub {
@Override
public void run() {
List<PackageInfo> packagesToBackup = new ArrayList<PackageInfo>();
Slog.i(TAG, "--- Performing full-dataset backup ---");
List<PackageInfo> packagesToBackup = new ArrayList<PackageInfo>();
FullBackupObbConnection obbConnection = new FullBackupObbConnection();
obbConnection.establish(); // we'll want this later
sendStartBackup();
// doAllApps supersedes the package set if any
@@ -2557,6 +2684,15 @@ class BackupManagerService extends IBackupManager.Stub {
for (int i = 0; i < N; i++) {
pkg = packagesToBackup.get(i);
backupOnePackage(pkg, out);
// after the app's agent runs to handle its private filesystem
// contents, back up any OBB content it has on its behalf.
if (mIncludeObbs) {
boolean obbOkay = obbConnection.backupObbs(pkg, out);
if (!obbOkay) {
throw new RuntimeException("Failure writing OBB stack for " + pkg);
}
}
}
// Done!
@@ -2581,6 +2717,7 @@ class BackupManagerService extends IBackupManager.Stub {
mLatchObject.notifyAll();
}
sendEndBackup();
obbConnection.tearDown();
if (DEBUG) Slog.d(TAG, "Full backup pass complete.");
mWakelock.release();
}
@@ -2688,20 +2825,7 @@ class BackupManagerService extends IBackupManager.Stub {
// Now pull data from the app and stuff it into the compressor
try {
FileInputStream raw = new FileInputStream(pipes[0].getFileDescriptor());
DataInputStream in = new DataInputStream(raw);
byte[] buffer = new byte[16 * 1024];
int chunkTotal;
while ((chunkTotal = in.readInt()) > 0) {
while (chunkTotal > 0) {
int toRead = (chunkTotal > buffer.length)
? buffer.length : chunkTotal;
int nRead = in.read(buffer, 0, toRead);
out.write(buffer, 0, nRead);
chunkTotal -= nRead;
}
}
routeSocketDataToOutput(pipes[0], out);
} catch (IOException e) {
Slog.i(TAG, "Caught exception reading from agent", e);
}
@@ -2900,7 +3024,7 @@ class BackupManagerService extends IBackupManager.Stub {
ACCEPT_IF_APK
}
class PerformFullRestoreTask implements Runnable {
class PerformFullRestoreTask extends ObbServiceClient implements Runnable {
ParcelFileDescriptor mInputFile;
String mCurrentPassword;
String mDecryptPassword;
@@ -2909,6 +3033,7 @@ class BackupManagerService extends IBackupManager.Stub {
IBackupAgent mAgent;
String mAgentPackage;
ApplicationInfo mTargetApp;
FullBackupObbConnection mObbConnection = null;
ParcelFileDescriptor[] mPipes = null;
long mBytes;
@@ -2937,6 +3062,7 @@ class BackupManagerService extends IBackupManager.Stub {
mAgent = null;
mAgentPackage = null;
mTargetApp = null;
mObbConnection = new FullBackupObbConnection();
// Which packages we've already wiped data on. We prepopulate this
// with a whitelist of packages known to be unclearable.
@@ -2980,6 +3106,7 @@ class BackupManagerService extends IBackupManager.Stub {
@Override
public void run() {
Slog.i(TAG, "--- Performing full-dataset restore ---");
mObbConnection.establish();
sendStartRestore();
// Are we able to restore shared-storage data?
@@ -3067,6 +3194,7 @@ class BackupManagerService extends IBackupManager.Stub {
mLatchObject.set(true);
mLatchObject.notifyAll();
}
mObbConnection.tearDown();
sendEndRestore();
Slog.d(TAG, "Full restore pass complete.");
mWakelock.release();
@@ -3319,22 +3447,30 @@ class BackupManagerService extends IBackupManager.Stub {
long toCopy = info.size;
final int token = generateToken();
try {
if (DEBUG) Slog.d(TAG, "Invoking agent to restore file "
+ info.path);
prepareOperationTimeout(token, TIMEOUT_FULL_BACKUP_INTERVAL, null);
// 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(
mAgent, info, mPipes[0], token);
new Thread(runner).start();
if (info.domain.equals(FullBackup.OBB_TREE_TOKEN)) {
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, mBackupManagerBinder);
} else {
mAgent.doRestoreFile(mPipes[0], info.size, info.type,
info.domain, info.path, info.mode, info.mtime,
token, mBackupManagerBinder);
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(
mAgent, info, mPipes[0], token);
new Thread(runner).start();
} else {
mAgent.doRestoreFile(mPipes[0], info.size, info.type,
info.domain, info.path, info.mode, info.mtime,
token, mBackupManagerBinder);
}
}
} catch (IOException e) {
// couldn't dup the socket for a process-local restore
@@ -3342,7 +3478,7 @@ class BackupManagerService extends IBackupManager.Stub {
agentSuccess = false;
okay = false;
} catch (RemoteException e) {
// whoops, remote agent went away. We'll eat the content
// 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;
@@ -3891,18 +4027,6 @@ class BackupManagerService extends IBackupManager.Stub {
slash = info.path.indexOf('/');
if (slash < 0) throw new IOException("Illegal semantic path in non-manifest " + info.path);
info.domain = info.path.substring(0, slash);
// validate that it's one of the domains we understand
if (!info.domain.equals(FullBackup.APK_TREE_TOKEN)
&& !info.domain.equals(FullBackup.DATA_TREE_TOKEN)
&& !info.domain.equals(FullBackup.DATABASE_TREE_TOKEN)
&& !info.domain.equals(FullBackup.ROOT_TREE_TOKEN)
&& !info.domain.equals(FullBackup.SHAREDPREFS_TREE_TOKEN)
&& !info.domain.equals(FullBackup.MANAGED_EXTERNAL_TREE_TOKEN)
&& !info.domain.equals(FullBackup.OBB_TREE_TOKEN)
&& !info.domain.equals(FullBackup.CACHE_TREE_TOKEN)) {
throw new IOException("Unrecognized domain " + info.domain);
}
info.path = info.path.substring(slash + 1);
}
}
@@ -4989,7 +5113,8 @@ class BackupManagerService extends IBackupManager.Stub {
// Run a *full* backup pass for the given package, writing the resulting data stream
// to the supplied file descriptor. This method is synchronous and does not return
// to the caller until the backup has been completed.
public void fullBackup(ParcelFileDescriptor fd, boolean includeApks, boolean includeShared,
public void fullBackup(ParcelFileDescriptor fd, boolean includeApks,
boolean includeObbs, boolean includeShared,
boolean doAllApps, boolean includeSystem, String[] pkgList) {
mContext.enforceCallingPermission(android.Manifest.permission.BACKUP, "fullBackup");
@@ -5020,12 +5145,12 @@ class BackupManagerService extends IBackupManager.Stub {
}
if (DEBUG) Slog.v(TAG, "Requesting full backup: apks=" + includeApks
+ " shared=" + includeShared + " all=" + doAllApps
+ " obb=" + includeObbs + " shared=" + includeShared + " all=" + doAllApps
+ " pkgs=" + pkgList);
Slog.i(TAG, "Beginning full backup...");
FullBackupParams params = new FullBackupParams(fd, includeApks, includeShared,
doAllApps, includeSystem, pkgList);
FullBackupParams params = new FullBackupParams(fd, includeApks, includeObbs,
includeShared, doAllApps, includeSystem, pkgList);
final int token = generateToken();
synchronized (mFullConfirmations) {
mFullConfirmations.put(token, params);