summaryrefslogtreecommitdiffstats
path: root/services/java/com/android/server/BackupManagerService.java
diff options
context:
space:
mode:
Diffstat (limited to 'services/java/com/android/server/BackupManagerService.java')
-rw-r--r--services/java/com/android/server/BackupManagerService.java181
1 files changed, 154 insertions, 27 deletions
diff --git a/services/java/com/android/server/BackupManagerService.java b/services/java/com/android/server/BackupManagerService.java
index 3aa1239..786f2fa 100644
--- a/services/java/com/android/server/BackupManagerService.java
+++ b/services/java/com/android/server/BackupManagerService.java
@@ -23,6 +23,7 @@ import android.app.IActivityManager;
import android.app.IApplicationThread;
import android.app.IBackupAgent;
import android.app.PendingIntent;
+import android.app.backup.BackupAgent;
import android.app.backup.BackupDataOutput;
import android.app.backup.FullBackup;
import android.app.backup.RestoreSet;
@@ -64,6 +65,7 @@ import android.os.SystemClock;
import android.os.WorkSource;
import android.provider.Settings;
import android.util.EventLog;
+import android.util.Log;
import android.util.Slog;
import android.util.SparseArray;
import android.util.SparseIntArray;
@@ -222,6 +224,7 @@ class BackupManagerService extends IBackupManager.Stub {
public PackageInfo pkgInfo;
public int pmToken; // in post-install restore, the PM's token for this transaction
public boolean needFullBackup;
+ public String[] filterSet;
RestoreParams(IBackupTransport _transport, IRestoreObserver _obs,
long _token, PackageInfo _pkg, int _pmToken, boolean _needFullBackup) {
@@ -231,6 +234,7 @@ class BackupManagerService extends IBackupManager.Stub {
pkgInfo = _pkg;
pmToken = _pmToken;
needFullBackup = _needFullBackup;
+ filterSet = null;
}
RestoreParams(IBackupTransport _transport, IRestoreObserver _obs, long _token,
@@ -241,6 +245,18 @@ class BackupManagerService extends IBackupManager.Stub {
pkgInfo = null;
pmToken = 0;
needFullBackup = _needFullBackup;
+ filterSet = null;
+ }
+
+ RestoreParams(IBackupTransport _transport, IRestoreObserver _obs, long _token,
+ String[] _filterSet, boolean _needFullBackup) {
+ transport = _transport;
+ observer = _obs;
+ token = _token;
+ pkgInfo = null;
+ pmToken = 0;
+ needFullBackup = _needFullBackup;
+ filterSet = _filterSet;
}
}
@@ -402,7 +418,7 @@ class BackupManagerService extends IBackupManager.Stub {
Slog.d(TAG, "MSG_RUN_RESTORE observer=" + params.observer);
(new PerformRestoreTask(params.transport, params.observer,
params.token, params.pkgInfo, params.pmToken,
- params.needFullBackup)).run();
+ params.needFullBackup, params.filterSet)).run();
break;
}
@@ -1587,8 +1603,7 @@ class BackupManagerService extends IBackupManager.Stub {
// Initiate the target's backup pass
prepareOperationTimeout(token, TIMEOUT_BACKUP_INTERVAL);
- agent.doBackup(savedState, backupData, newState, false,
- token, mBackupManagerBinder);
+ agent.doBackup(savedState, backupData, newState, token, mBackupManagerBinder);
boolean success = waitUntilOperationComplete(token);
if (!success) {
@@ -1764,30 +1779,31 @@ class BackupManagerService extends IBackupManager.Stub {
if (agent != null) {
try {
ApplicationInfo app = pkg.applicationInfo;
- boolean sendApk = mIncludeApks
+ final boolean sendApk = mIncludeApks
&& ((app.flags & ApplicationInfo.FLAG_FORWARD_LOCK) == 0)
&& ((app.flags & ApplicationInfo.FLAG_SYSTEM) == 0 ||
(app.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0);
sendOnBackupPackage(pkg.packageName);
- {
- BackupDataOutput output = new BackupDataOutput(
- mOutputFile.getFileDescriptor());
+ BackupDataOutput output = new BackupDataOutput(
+ mOutputFile.getFileDescriptor());
- if (DEBUG) Slog.d(TAG, "Writing manifest for " + pkg.packageName);
- writeAppManifest(pkg, mManifestFile, sendApk);
- FullBackup.backupToTar(pkg.packageName, null, null,
- mFilesDir.getAbsolutePath(),
- mManifestFile.getAbsolutePath(),
- output);
+ if (DEBUG) Slog.d(TAG, "Writing manifest for " + pkg.packageName);
+ writeAppManifest(pkg, mManifestFile, sendApk);
+ FullBackup.backupToTar(pkg.packageName, null, null,
+ mFilesDir.getAbsolutePath(),
+ mManifestFile.getAbsolutePath(),
+ output);
+
+ if (sendApk) {
+ writeApkToBackup(pkg, output);
}
- if (DEBUG) Slog.d(TAG, "Calling doBackup()");
+ if (DEBUG) Slog.d(TAG, "Calling doFullBackup()");
final int token = generateToken();
prepareOperationTimeout(token, TIMEOUT_FULL_BACKUP_INTERVAL);
- agent.doBackup(null, mOutputFile, null, sendApk,
- token, mBackupManagerBinder);
+ agent.doFullBackup(mOutputFile, token, mBackupManagerBinder);
if (!waitUntilOperationComplete(token)) {
Slog.e(TAG, "Full backup failed on package " + pkg.packageName);
} else {
@@ -1802,6 +1818,29 @@ class BackupManagerService extends IBackupManager.Stub {
tearDown(pkg);
}
+ private void writeApkToBackup(PackageInfo pkg, BackupDataOutput output) {
+ // Forward-locked apps, system-bundled .apks, etc are filtered out before we get here
+ final String appSourceDir = pkg.applicationInfo.sourceDir;
+ final String apkDir = new File(appSourceDir).getParent();
+ FullBackup.backupToTar(pkg.packageName, FullBackup.APK_TREE_TOKEN, null,
+ apkDir, appSourceDir, output);
+
+ // Save associated .obb content if it exists and we did save the apk
+ // check for .obb and save those too
+ final File obbDir = Environment.getExternalStorageAppObbDirectory(pkg.packageName);
+ if (obbDir != null) {
+ if (DEBUG) Log.i(TAG, "obb dir: " + obbDir.getAbsolutePath());
+ File[] obbFiles = obbDir.listFiles();
+ if (obbFiles != null) {
+ final String obbDirName = obbDir.getAbsolutePath();
+ for (File obb : obbFiles) {
+ FullBackup.backupToTar(pkg.packageName, FullBackup.OBB_TREE_TOKEN, null,
+ obbDirName, obb.getAbsolutePath(), output);
+ }
+ }
+ }
+ }
+
private void backupSharedStorage() throws RemoteException {
PackageInfo pkg = null;
try {
@@ -1813,7 +1852,7 @@ class BackupManagerService extends IBackupManager.Stub {
final int token = generateToken();
prepareOperationTimeout(token, TIMEOUT_SHARED_BACKUP_INTERVAL);
- agent.doBackup(null, mOutputFile, null, false, token, mBackupManagerBinder);
+ agent.doFullBackup(mOutputFile, token, mBackupManagerBinder);
if (!waitUntilOperationComplete(token)) {
Slog.e(TAG, "Full backup failed on shared storage");
} else {
@@ -1933,7 +1972,7 @@ class BackupManagerService extends IBackupManager.Stub {
static class FileMetadata {
String packageName; // name of the owning app
String installerPackageName; // name of the market-type app that installed the owner
- int type; // e.g. FullBackup.TYPE_DIRECTORY
+ int type; // e.g. BackupAgent.TYPE_DIRECTORY
String domain; // e.g. FullBackup.DATABASE_TREE_TOKEN
String path; // subpath within the semantic domain
long mode; // e.g. 0666 (actually int)
@@ -2182,15 +2221,15 @@ class BackupManagerService extends IBackupManager.Stub {
// 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 full backup agents are
+ // apps with their own backup agents are
// responsible for coherently managing a full
// restore.
- if (mTargetApp.fullBackupAgentName == null) {
+ if (mTargetApp.backupAgentName == null) {
if (DEBUG) Slog.d(TAG, "Clearing app data preparatory to full restore");
clearApplicationDataSynchronous(pkg);
} else {
- if (DEBUG) Slog.d(TAG, "full backup agent ("
- + mTargetApp.fullBackupAgentName + ") => no clear");
+ if (DEBUG) Slog.d(TAG, "backup agent ("
+ + mTargetApp.backupAgentName + ") => no clear");
}
mClearedPackages.add(pkg);
} else {
@@ -2686,7 +2725,7 @@ class BackupManagerService extends IBackupManager.Stub {
StringBuilder b = new StringBuilder(128);
// mode string
- b.append((info.type == FullBackup.TYPE_DIRECTORY) ? 'd' : '-');
+ b.append((info.type == BackupAgent.TYPE_DIRECTORY) ? 'd' : '-');
b.append(((info.mode & 0400) != 0) ? 'r' : '-');
b.append(((info.mode & 0200) != 0) ? 'w' : '-');
b.append(((info.mode & 0100) != 0) ? 'x' : '-');
@@ -2746,9 +2785,9 @@ class BackupManagerService extends IBackupManager.Stub {
}
switch (typeChar) {
- case '0': info.type = FullBackup.TYPE_FILE; break;
+ case '0': info.type = BackupAgent.TYPE_FILE; break;
case '5': {
- info.type = FullBackup.TYPE_DIRECTORY;
+ info.type = BackupAgent.TYPE_DIRECTORY;
if (info.size != 0) {
Slog.w(TAG, "Directory entry with nonzero size in header");
info.size = 0;
@@ -2995,6 +3034,7 @@ class BackupManagerService extends IBackupManager.Stub {
private File mStateDir;
private int mPmToken;
private boolean mNeedFullBackup;
+ private HashSet<String> mFilterSet;
class RestoreRequest {
public PackageInfo app;
@@ -3008,7 +3048,7 @@ class BackupManagerService extends IBackupManager.Stub {
PerformRestoreTask(IBackupTransport transport, IRestoreObserver observer,
long restoreSetToken, PackageInfo targetPackage, int pmToken,
- boolean needFullBackup) {
+ boolean needFullBackup, String[] filterSet) {
mTransport = transport;
mObserver = observer;
mToken = restoreSetToken;
@@ -3016,6 +3056,15 @@ class BackupManagerService extends IBackupManager.Stub {
mPmToken = pmToken;
mNeedFullBackup = needFullBackup;
+ if (filterSet != null) {
+ mFilterSet = new HashSet<String>();
+ for (String pkg : filterSet) {
+ mFilterSet.add(pkg);
+ }
+ } else {
+ mFilterSet = null;
+ }
+
try {
mStateDir = new File(mBaseStateDir, transport.transportDirName());
} catch (RemoteException e) {
@@ -3027,7 +3076,8 @@ class BackupManagerService extends IBackupManager.Stub {
long startRealtime = SystemClock.elapsedRealtime();
if (DEBUG) Slog.v(TAG, "Beginning restore process mTransport=" + mTransport
+ " mObserver=" + mObserver + " mToken=" + Long.toHexString(mToken)
- + " mTargetPackage=" + mTargetPackage + " mPmToken=" + mPmToken);
+ + " mTargetPackage=" + mTargetPackage + " mFilterSet=" + mFilterSet
+ + " mPmToken=" + mPmToken);
PackageManagerBackupAgent pmAgent = null;
int error = -1; // assume error
@@ -3046,6 +3096,22 @@ class BackupManagerService extends IBackupManager.Stub {
List<PackageInfo> agentPackages = allAgentPackages();
if (mTargetPackage == null) {
+ // if there's a filter set, strip out anything that isn't
+ // present before proceeding
+ if (mFilterSet != null) {
+ for (int i = agentPackages.size() - 1; i >= 0; i--) {
+ final PackageInfo pkg = agentPackages.get(i);
+ if (! mFilterSet.contains(pkg.packageName)) {
+ agentPackages.remove(i);
+ }
+ }
+ if (DEBUG) {
+ Slog.i(TAG, "Post-filter package set for restore:");
+ for (PackageInfo p : agentPackages) {
+ Slog.i(TAG, " " + p);
+ }
+ }
+ }
restorePackages.addAll(agentPackages);
} else {
// Just one package to attempt restore of
@@ -4241,6 +4307,67 @@ class BackupManagerService extends IBackupManager.Stub {
return -1;
}
+ public synchronized int restoreSome(long token, IRestoreObserver observer,
+ String[] packages) {
+ mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
+ "performRestore");
+
+ if (DEBUG) {
+ StringBuilder b = new StringBuilder(128);
+ b.append("restoreSome token=");
+ b.append(Long.toHexString(token));
+ b.append(" observer=");
+ b.append(observer.toString());
+ b.append(" packages=");
+ if (packages == null) {
+ b.append("null");
+ } else {
+ b.append('{');
+ boolean first = true;
+ for (String s : packages) {
+ if (!first) {
+ b.append(", ");
+ } else first = false;
+ b.append(s);
+ }
+ b.append('}');
+ }
+ Slog.d(TAG, b.toString());
+ }
+
+ if (mEnded) {
+ throw new IllegalStateException("Restore session already ended");
+ }
+
+ if (mRestoreTransport == null || mRestoreSets == null) {
+ Slog.e(TAG, "Ignoring restoreAll() with no restore set");
+ return -1;
+ }
+
+ if (mPackageName != null) {
+ Slog.e(TAG, "Ignoring restoreAll() on single-package session");
+ return -1;
+ }
+
+ synchronized (mQueueLock) {
+ for (int i = 0; i < mRestoreSets.length; i++) {
+ if (token == mRestoreSets[i].token) {
+ long oldId = Binder.clearCallingIdentity();
+ mWakelock.acquire();
+ Message msg = mBackupHandler.obtainMessage(MSG_RUN_RESTORE);
+ msg.obj = new RestoreParams(mRestoreTransport, observer, token,
+ packages, true);
+ mBackupHandler.sendMessage(msg);
+ Binder.restoreCallingIdentity(oldId);
+ return 0;
+ }
+ }
+ }
+
+ Slog.w(TAG, "Restore token " + Long.toHexString(token) + " not found");
+ return -1;
+ }
+
public synchronized int restorePackage(String packageName, IRestoreObserver observer) {
if (DEBUG) Slog.v(TAG, "restorePackage pkg=" + packageName + " obs=" + observer);