summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Android.mk1
-rw-r--r--cmds/bu/src/com/android/commands/bu/Backup.java28
-rw-r--r--core/java/android/app/backup/BackupAgent.java1
-rw-r--r--core/java/android/app/backup/FullBackup.java2
-rw-r--r--core/java/android/app/backup/IBackupManager.aidl7
-rw-r--r--core/java/com/android/internal/backup/IObbBackupService.aidl45
-rw-r--r--libs/androidfw/BackupHelpers.cpp2
-rw-r--r--packages/SharedStorageBackup/AndroidManifest.xml7
-rw-r--r--packages/SharedStorageBackup/proguard.flags1
-rw-r--r--packages/SharedStorageBackup/src/com/android/sharedstoragebackup/ObbBackupService.java151
-rw-r--r--services/java/com/android/server/BackupManagerService.java235
11 files changed, 417 insertions, 63 deletions
diff --git a/Android.mk b/Android.mk
index 43791c7..104293c 100644
--- a/Android.mk
+++ b/Android.mk
@@ -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/os/IDropBoxManagerService.aidl \
diff --git a/cmds/bu/src/com/android/commands/bu/Backup.java b/cmds/bu/src/com/android/commands/bu/Backup.java
index 046ccca..73fd660 100644
--- a/cmds/bu/src/com/android/commands/bu/Backup.java
+++ b/cmds/bu/src/com/android/commands/bu/Backup.java
@@ -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) {}
+ }
}
}
diff --git a/core/java/android/app/backup/BackupAgent.java b/core/java/android/app/backup/BackupAgent.java
index 44aa06f..3425765 100644
--- a/core/java/android/app/backup/BackupAgent.java
+++ b/core/java/android/app/backup/BackupAgent.java
@@ -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 {
diff --git a/core/java/android/app/backup/FullBackup.java b/core/java/android/app/backup/FullBackup.java
index 2fe08f3..cb0737e 100644
--- a/core/java/android/app/backup/FullBackup.java
+++ b/core/java/android/app/backup/FullBackup.java
@@ -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,
diff --git a/core/java/android/app/backup/IBackupManager.aidl b/core/java/android/app/backup/IBackupManager.aidl
index acdd0b5..bb4f5f1 100644
--- a/core/java/android/app/backup/IBackupManager.aidl
+++ b/core/java/android/app/backup/IBackupManager.aidl
@@ -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
diff --git a/core/java/com/android/internal/backup/IObbBackupService.aidl b/core/java/com/android/internal/backup/IObbBackupService.aidl
new file mode 100644
index 0000000..426dbc4
--- /dev/null
+++ b/core/java/com/android/internal/backup/IObbBackupService.aidl
@@ -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);
+}
diff --git a/libs/androidfw/BackupHelpers.cpp b/libs/androidfw/BackupHelpers.cpp
index dcf41b7..b8d3f48 100644
--- a/libs/androidfw/BackupHelpers.cpp
+++ b/libs/androidfw/BackupHelpers.cpp
@@ -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
diff --git a/packages/SharedStorageBackup/AndroidManifest.xml b/packages/SharedStorageBackup/AndroidManifest.xml
index fc21df3..b8df88e 100644
--- a/packages/SharedStorageBackup/AndroidManifest.xml
+++ b/packages/SharedStorageBackup/AndroidManifest.xml
@@ -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>
diff --git a/packages/SharedStorageBackup/proguard.flags b/packages/SharedStorageBackup/proguard.flags
index f43cb81..6a66a47 100644
--- a/packages/SharedStorageBackup/proguard.flags
+++ b/packages/SharedStorageBackup/proguard.flags
@@ -1 +1,2 @@
-keep class com.android.sharedstoragebackup.SharedStorageAgent
+-keep class com.android.sharedstoragebackup.ObbBackupService
diff --git a/packages/SharedStorageBackup/src/com/android/sharedstoragebackup/ObbBackupService.java b/packages/SharedStorageBackup/src/com/android/sharedstoragebackup/ObbBackupService.java
new file mode 100644
index 0000000..7ebe096
--- /dev/null
+++ b/packages/SharedStorageBackup/src/com/android/sharedstoragebackup/ObbBackupService.java
@@ -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();
+ }
+}
diff --git a/services/java/com/android/server/BackupManagerService.java b/services/java/com/android/server/BackupManagerService.java
index 401a25f..328b503 100644
--- a/services/java/com/android/server/BackupManagerService.java
+++ b/services/java/com/android/server/BackupManagerService.java
@@ -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() {
+ Slog.i(TAG, "--- Performing full-dataset backup ---");
+
List<PackageInfo> packagesToBackup = new ArrayList<PackageInfo>();
+ FullBackupObbConnection obbConnection = new FullBackupObbConnection();
+ obbConnection.establish(); // we'll want this later
- Slog.i(TAG, "--- Performing full-dataset backup ---");
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);