summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--core/java/android/app/backup/BackupAgent.java1
-rw-r--r--core/java/android/app/backup/FullBackup.java7
-rw-r--r--core/java/android/app/backup/FullBackupAgent.java26
-rw-r--r--core/java/android/content/pm/PackageParser.java3
-rw-r--r--core/jni/android_app_backup_FullBackup.cpp2
-rw-r--r--libs/utils/BackupHelpers.cpp4
-rw-r--r--packages/SharedStorageBackup/Android.mk33
-rw-r--r--packages/SharedStorageBackup/AndroidManifest.xml29
-rw-r--r--packages/SharedStorageBackup/proguard.flags1
-rw-r--r--packages/SharedStorageBackup/src/com/android/sharedstoragebackup/SharedStorageAgent.java93
-rw-r--r--services/java/com/android/server/BackupManagerService.java172
-rw-r--r--services/java/com/android/server/SystemBackupAgent.java2
12 files changed, 288 insertions, 85 deletions
diff --git a/core/java/android/app/backup/BackupAgent.java b/core/java/android/app/backup/BackupAgent.java
index 17f8adb..63f3258 100644
--- a/core/java/android/app/backup/BackupAgent.java
+++ b/core/java/android/app/backup/BackupAgent.java
@@ -278,7 +278,6 @@ public abstract class BackupAgent extends ContextWrapper {
int token, IBackupManager callbackBinder) throws RemoteException {
long ident = Binder.clearCallingIdentity();
try {
-Log.d(TAG, "doRestoreFile() => onRestoreFile()");
BackupAgent.this.onRestoreFile(data, size, type, domain, path, mode, mtime);
} catch (IOException e) {
throw new RuntimeException(e);
diff --git a/core/java/android/app/backup/FullBackup.java b/core/java/android/app/backup/FullBackup.java
index dfb0dd7..3b70e19 100644
--- a/core/java/android/app/backup/FullBackup.java
+++ b/core/java/android/app/backup/FullBackup.java
@@ -46,7 +46,7 @@ public class FullBackup {
public static final String SHARED_STORAGE_TOKEN = "shared";
public static final String APPS_PREFIX = "apps/";
- public static final String SHARED_PREFIX = "shared/";
+ public static final String SHARED_PREFIX = SHARED_STORAGE_TOKEN + "/";
public static final String FULL_BACKUP_INTENT_ACTION = "fullback";
public static final String FULL_RESTORE_INTENT_ACTION = "fullrest";
@@ -61,7 +61,8 @@ public class FullBackup {
String linkdomain, String rootpath, String path, BackupDataOutput output);
static public void restoreToFile(ParcelFileDescriptor data,
- long size, int type, long mode, long mtime, File outFile) throws IOException {
+ long size, int type, long mode, long mtime, File outFile,
+ boolean doChmod) throws IOException {
if (type == FullBackup.TYPE_DIRECTORY) {
// Canonically a directory has no associated content, so we don't need to read
// anything from the pipe in this case. Just create the directory here and
@@ -116,7 +117,7 @@ public class FullBackup {
}
// Now twiddle the state to match the backup, assuming all went well
- if (outFile != null) {
+ if (doChmod && outFile != null) {
try {
Libcore.os.chmod(outFile.getPath(), (int)mode);
} catch (ErrnoException e) {
diff --git a/core/java/android/app/backup/FullBackupAgent.java b/core/java/android/app/backup/FullBackupAgent.java
index 4dca593..df1c363 100644
--- a/core/java/android/app/backup/FullBackupAgent.java
+++ b/core/java/android/app/backup/FullBackupAgent.java
@@ -28,8 +28,6 @@ import libcore.io.OsConstants;
import libcore.io.StructStat;
import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileOutputStream;
import java.io.IOException;
import java.util.HashSet;
import java.util.LinkedList;
@@ -84,9 +82,10 @@ public class FullBackupAgent extends BackupAgent {
@Override
public void onBackup(ParcelFileDescriptor oldState, BackupDataOutput data,
- ParcelFileDescriptor newState) {
+ ParcelFileDescriptor newState) throws IOException {
// Filters, the scan queue, and the set of resulting entities
HashSet<String> filterSet = new HashSet<String>();
+ String packageName = getPackageName();
// Okay, start with the app's root tree, but exclude all of the canonical subdirs
if (mLibDir != null) {
@@ -96,25 +95,28 @@ public class FullBackupAgent extends BackupAgent {
filterSet.add(mDatabaseDir);
filterSet.add(mSharedPrefsDir);
filterSet.add(mFilesDir);
- processTree(FullBackup.ROOT_TREE_TOKEN, mMainDir, filterSet, data);
+ processTree(packageName, FullBackup.ROOT_TREE_TOKEN, mMainDir, filterSet, data);
// Now do the same for the files dir, db dir, and shared prefs dir
filterSet.add(mMainDir);
filterSet.remove(mFilesDir);
- processTree(FullBackup.DATA_TREE_TOKEN, mFilesDir, filterSet, data);
+ processTree(packageName, FullBackup.DATA_TREE_TOKEN, mFilesDir, filterSet, data);
filterSet.add(mFilesDir);
filterSet.remove(mDatabaseDir);
- processTree(FullBackup.DATABASE_TREE_TOKEN, mDatabaseDir, filterSet, data);
+ processTree(packageName, FullBackup.DATABASE_TREE_TOKEN, mDatabaseDir, filterSet, data);
filterSet.add(mDatabaseDir);
filterSet.remove(mSharedPrefsDir);
- processTree(FullBackup.SHAREDPREFS_TREE_TOKEN, mSharedPrefsDir, filterSet, data);
+ processTree(packageName, FullBackup.SHAREDPREFS_TREE_TOKEN, mSharedPrefsDir, filterSet, data);
}
- private void processTree(String domain, String rootPath,
+ // Scan the dir tree (if it actually exists) and process each entry we find. If the
+ // 'excludes' parameter is non-null, it is consulted each time a new file system entity
+ // is visited to see whether that entity (and its subtree, if appropriate) should be
+ // omitted from the backup process.
+ protected void processTree(String packageName, String domain, String rootPath,
HashSet<String> excludes, BackupDataOutput data) {
- // Scan the dir tree (if it actually exists) and process each entry we find
File rootFile = new File(rootPath);
if (rootFile.exists()) {
LinkedList<File> scanQueue = new LinkedList<File>();
@@ -125,7 +127,7 @@ public class FullBackupAgent extends BackupAgent {
String filePath = file.getAbsolutePath();
// prune this subtree?
- if (excludes.contains(filePath)) {
+ if (excludes != null && excludes.contains(filePath)) {
continue;
}
@@ -149,7 +151,7 @@ public class FullBackupAgent extends BackupAgent {
}
// Finally, back this file up before proceeding
- FullBackup.backupToTar(getPackageName(), domain, null, rootPath, filePath, data);
+ FullBackup.backupToTar(packageName, domain, null, rootPath, filePath, data);
}
}
}
@@ -218,6 +220,6 @@ public class FullBackupAgent extends BackupAgent {
if (DEBUG) Log.i(TAG, "[" + domain + " : " + relpath + "] mapped to " + outFile.getPath());
// Now that we've figured out where the data goes, send it on its way
- FullBackup.restoreToFile(data, size, type, mode, mtime, outFile);
+ FullBackup.restoreToFile(data, size, type, mode, mtime, outFile, true);
}
}
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 09fede0..31ad6e9 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -1517,11 +1517,12 @@ public class PackageParser {
}
}
+ // fullBackupAgent is explicitly handled even if allowBackup is false
name = sa.getNonConfigurationString(
com.android.internal.R.styleable.AndroidManifestApplication_fullBackupAgent, 0);
if (name != null) {
ai.fullBackupAgentName = buildClassName(pkgName, name, outError);
- if (true) {
+ if (false) {
Log.v(TAG, "android:fullBackupAgent=" + ai.fullBackupAgentName
+ " from " + pkgName + "+" + name);
}
diff --git a/core/jni/android_app_backup_FullBackup.cpp b/core/jni/android_app_backup_FullBackup.cpp
index ecfe5ff..b36fa3e 100644
--- a/core/jni/android_app_backup_FullBackup.cpp
+++ b/core/jni/android_app_backup_FullBackup.cpp
@@ -73,6 +73,8 @@ static struct {
static int backupToTar(JNIEnv* env, jobject clazz, jstring packageNameObj,
jstring domainObj, jstring linkdomain,
jstring rootpathObj, jstring pathObj, jobject dataOutputObj) {
+ int ret;
+
// Extract the various strings, allowing for null object pointers
const char* packagenamechars = env->GetStringUTFChars(packageNameObj, NULL);
const char* rootchars = env->GetStringUTFChars(rootpathObj, NULL);
diff --git a/libs/utils/BackupHelpers.cpp b/libs/utils/BackupHelpers.cpp
index f933199..b433fd3 100644
--- a/libs/utils/BackupHelpers.cpp
+++ b/libs/utils/BackupHelpers.cpp
@@ -503,10 +503,10 @@ int write_tarfile(const String8& packageName, const String8& domain,
needExtended = true;
}
- // Non-7bit-clean path also means needing pax extended format
+ // Non-7bit-clean path or embedded spaces also mean needing pax extended format
if (!needExtended) {
for (size_t i = 0; i < filepath.length(); i++) {
- if ((filepath[i] & 0x80) != 0) {
+ if ((filepath[i] & 0x80) != 0 || filepath[i] == ' ') {
needExtended = true;
break;
}
diff --git a/packages/SharedStorageBackup/Android.mk b/packages/SharedStorageBackup/Android.mk
new file mode 100644
index 0000000..1d4f4da
--- /dev/null
+++ b/packages/SharedStorageBackup/Android.mk
@@ -0,0 +1,33 @@
+#
+# Copyright (C) 2011 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.
+#
+
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_PROGUARD_FLAG_FILES := proguard.flags
+
+LOCAL_PACKAGE_NAME := SharedStorageBackup
+LOCAL_CERTIFICATE := platform
+
+include $(BUILD_PACKAGE)
+
+########################
+include $(call all-makefiles-under,$(LOCAL_PATH))
+
diff --git a/packages/SharedStorageBackup/AndroidManifest.xml b/packages/SharedStorageBackup/AndroidManifest.xml
new file mode 100644
index 0000000..258059c
--- /dev/null
+++ b/packages/SharedStorageBackup/AndroidManifest.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+** Copyright 2011, 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.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.sharedstoragebackup" >
+
+ <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+ <uses-permission android:name="android.permission.WRITE_MEDIA_STORAGE" />
+
+ <application android:allowClearUserData="false"
+ android:permission="android.permission.CONFIRM_FULL_BACKUP"
+ android:fullBackupAgent=".SharedStorageAgent"
+ android:allowBackup="false" >
+ </application>
+</manifest>
diff --git a/packages/SharedStorageBackup/proguard.flags b/packages/SharedStorageBackup/proguard.flags
new file mode 100644
index 0000000..f43cb81
--- /dev/null
+++ b/packages/SharedStorageBackup/proguard.flags
@@ -0,0 +1 @@
+-keep class com.android.sharedstoragebackup.SharedStorageAgent
diff --git a/packages/SharedStorageBackup/src/com/android/sharedstoragebackup/SharedStorageAgent.java b/packages/SharedStorageBackup/src/com/android/sharedstoragebackup/SharedStorageAgent.java
new file mode 100644
index 0000000..b02ca2e
--- /dev/null
+++ b/packages/SharedStorageBackup/src/com/android/sharedstoragebackup/SharedStorageAgent.java
@@ -0,0 +1,93 @@
+package com.android.sharedstoragebackup;
+
+import android.app.backup.FullBackup;
+import android.app.backup.FullBackupAgent;
+import android.app.backup.BackupDataInput;
+import android.app.backup.BackupDataOutput;
+import android.content.Context;
+import android.os.Environment;
+import android.os.ParcelFileDescriptor;
+import android.os.storage.StorageManager;
+import android.os.storage.StorageVolume;
+import android.util.Slog;
+
+import java.io.File;
+import java.io.IOException;
+
+public class SharedStorageAgent extends FullBackupAgent {
+ static final String TAG = "SharedStorageAgent";
+ static final boolean DEBUG = true;
+
+ StorageVolume[] mVolumes;
+
+ @Override
+ public void onCreate() {
+ StorageManager mgr = (StorageManager) getSystemService(Context.STORAGE_SERVICE);
+ if (mgr != null) {
+ mVolumes = mgr.getVolumeList();
+ } else {
+ Slog.e(TAG, "Unable to access Storage Manager");
+ }
+ }
+
+ @Override
+ public void onBackup(ParcelFileDescriptor oldState, BackupDataOutput data,
+ ParcelFileDescriptor newState) throws IOException {
+ // If there are shared-storage volumes available, run the inherited directory-
+ // hierarchy backup process on them. By convention in the Storage Manager, the
+ // "primary" shared storage volume is first in the list.
+ if (mVolumes != null) {
+ for (int i = 0; i < mVolumes.length; i++) {
+ StorageVolume v = mVolumes[i];
+ // Express the contents of volume N this way in the tar stream:
+ // shared/N/path/to/file
+ // The restore will then extract to the given volume
+ String domain = FullBackup.SHARED_PREFIX + i;
+ processTree(null, domain, v.getPath(), null, data);
+ }
+ }
+ }
+
+ /**
+ * Incremental onRestore() implementation is not used.
+ */
+ @Override
+ public void onRestore(BackupDataInput data, int appVersionCode, ParcelFileDescriptor newState)
+ throws IOException {
+ }
+
+ /**
+ * Full restore of one file to shared storage
+ */
+ @Override
+ public void onRestoreFile(ParcelFileDescriptor data, long size,
+ int type, String domain, String relpath, long mode, long mtime)
+ throws IOException {
+ Slog.d(TAG, "Shared restore: [ " + domain + " : " + relpath + "]");
+
+ File outFile = null;
+
+ // The file path must be in the semantic form [number]/path/to/file...
+ int slash = relpath.indexOf('/');
+ if (slash > 0) {
+ try {
+ int i = Integer.parseInt(relpath.substring(0, slash));
+ if (i <= mVolumes.length) {
+ outFile = new File(mVolumes[i].getPath(), relpath.substring(slash + 1));
+ if (DEBUG) Slog.i(TAG, " => " + outFile.getAbsolutePath());
+ } else {
+ Slog.w(TAG, "Cannot restore data for unavailable volume " + i);
+ }
+ } catch (NumberFormatException e) {
+ if (DEBUG) Slog.w(TAG, "Bad volume number token: " + relpath.substring(0, slash));
+ }
+ } else {
+ if (DEBUG) Slog.i(TAG, "Can't find volume-number token");
+ }
+ if (outFile == null) {
+ Slog.e(TAG, "Skipping data with malformed path " + relpath);
+ }
+
+ FullBackup.restoreToFile(data, size, type, mode, mtime, outFile, false);
+ }
+}
diff --git a/services/java/com/android/server/BackupManagerService.java b/services/java/com/android/server/BackupManagerService.java
index 7c6d3c1..b568af1 100644
--- a/services/java/com/android/server/BackupManagerService.java
+++ b/services/java/com/android/server/BackupManagerService.java
@@ -134,6 +134,7 @@ class BackupManagerService extends IBackupManager.Stub {
// Timeout intervals for agent backup & restore operations
static final long TIMEOUT_BACKUP_INTERVAL = 30 * 1000;
static final long TIMEOUT_FULL_BACKUP_INTERVAL = 5 * 60 * 1000;
+ static final long TIMEOUT_SHARED_BACKUP_INTERVAL = 30 * 60 * 1000;
static final long TIMEOUT_RESTORE_INTERVAL = 60 * 1000;
// User confirmation timeout for a full backup/restore operation
@@ -1691,7 +1692,7 @@ class BackupManagerService extends IBackupManager.Stub {
public void run() {
final List<PackageInfo> packagesToBackup;
- Slog.i(TAG, "--- Performing full-dataset restore ---");
+ Slog.i(TAG, "--- Performing full-dataset backup ---");
sendStartBackup();
// doAllApps supersedes the package set if any
@@ -1720,64 +1721,23 @@ class BackupManagerService extends IBackupManager.Stub {
}
}
- // Now back up the app data via the agent mechanism
PackageInfo pkg = null;
try {
+ // Now back up the app data via the agent mechanism
int N = packagesToBackup.size();
for (int i = 0; i < N; i++) {
pkg = packagesToBackup.get(i);
+ backupOnePackage(pkg);
+ }
- Slog.d(TAG, "Binding to full backup agent : " + pkg.packageName);
-
- IBackupAgent agent = bindToAgentSynchronous(pkg.applicationInfo,
- IApplicationThread.BACKUP_MODE_FULL);
- if (agent != null) {
- try {
- ApplicationInfo app = pkg.applicationInfo;
- 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());
-
- 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, "Calling doBackup()");
- final int token = generateToken();
- prepareOperationTimeout(token, TIMEOUT_FULL_BACKUP_INTERVAL);
- agent.doBackup(null, mOutputFile, null, sendApk,
- token, mBackupManagerBinder);
- boolean success = waitUntilOperationComplete(token);
- if (!success) {
- Slog.d(TAG, "Full backup failed on package " + pkg.packageName);
- } else {
- if (DEBUG) Slog.d(TAG, "Full backup success: " + pkg.packageName);
- }
- } catch (IOException e) {
- Slog.e(TAG, "Error backing up " + pkg.packageName, e);
- }
- } else {
- Slog.w(TAG, "Unable to bind to full agent for " + pkg.packageName);
- }
- tearDown(pkg);
+ // Finally, shared storage if requested
+ if (mIncludeShared) {
+ backupSharedStorage();
}
} catch (RemoteException e) {
Slog.e(TAG, "App died during full backup");
} finally {
- if (pkg != null) {
- tearDown(pkg);
- }
+ tearDown(pkg);
try {
mOutputFile.close();
} catch (IOException e) {
@@ -1796,6 +1756,79 @@ class BackupManagerService extends IBackupManager.Stub {
}
}
+ private void backupOnePackage(PackageInfo pkg) throws RemoteException {
+ Slog.d(TAG, "Binding to full backup agent : " + pkg.packageName);
+
+ IBackupAgent agent = bindToAgentSynchronous(pkg.applicationInfo,
+ IApplicationThread.BACKUP_MODE_FULL);
+ if (agent != null) {
+ try {
+ ApplicationInfo app = pkg.applicationInfo;
+ 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());
+
+ 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, "Calling doBackup()");
+ final int token = generateToken();
+ prepareOperationTimeout(token, TIMEOUT_FULL_BACKUP_INTERVAL);
+ agent.doBackup(null, mOutputFile, null, sendApk,
+ token, mBackupManagerBinder);
+ if (!waitUntilOperationComplete(token)) {
+ Slog.e(TAG, "Full backup failed on package " + pkg.packageName);
+ } else {
+ if (DEBUG) Slog.d(TAG, "Full backup success: " + pkg.packageName);
+ }
+ } catch (IOException e) {
+ Slog.e(TAG, "Error backing up " + pkg.packageName, e);
+ }
+ } else {
+ Slog.w(TAG, "Unable to bind to full agent for " + pkg.packageName);
+ }
+ tearDown(pkg);
+ }
+
+ private void backupSharedStorage() throws RemoteException {
+ PackageInfo pkg = null;
+ try {
+ pkg = mPackageManager.getPackageInfo("com.android.sharedstoragebackup", 0);
+ IBackupAgent agent = bindToAgentSynchronous(pkg.applicationInfo,
+ IApplicationThread.BACKUP_MODE_FULL);
+ if (agent != null) {
+ sendOnBackupPackage("Shared storage");
+
+ final int token = generateToken();
+ prepareOperationTimeout(token, TIMEOUT_SHARED_BACKUP_INTERVAL);
+ agent.doBackup(null, mOutputFile, null, false, token, mBackupManagerBinder);
+ if (!waitUntilOperationComplete(token)) {
+ Slog.e(TAG, "Full backup failed on shared storage");
+ } else {
+ if (DEBUG) Slog.d(TAG, "Full shared storage backup success");
+ }
+ } else {
+ Slog.e(TAG, "Could not bind to shared storage backup agent");
+ }
+ } catch (NameNotFoundException e) {
+ Slog.e(TAG, "Shared storage backup package not found");
+ } finally {
+ tearDown(pkg);
+ }
+ }
+
private void writeAppManifest(PackageInfo pkg, File manifestFile, boolean withApk)
throws IOException {
// Manifest format. All data are strings ending in LF:
@@ -1836,23 +1869,24 @@ class BackupManagerService extends IBackupManager.Stub {
}
private void tearDown(PackageInfo pkg) {
- final ApplicationInfo app = pkg.applicationInfo;
- try {
- // unbind and tidy up even on timeout or failure, just in case
- mActivityManager.unbindBackupAgent(app);
-
- // The agent was running with a stub Application object, so shut it down.
- // !!! We hardcode the confirmation UI's package name here rather than use a
- // manifest flag! TODO something less direct.
- if (app.uid != Process.SYSTEM_UID
- && !pkg.packageName.equals("com.android.backupconfirm")) {
- if (DEBUG) Slog.d(TAG, "Backup complete, killing host process");
- mActivityManager.killApplicationProcess(app.processName, app.uid);
- } else {
- if (DEBUG) Slog.d(TAG, "Not killing after restore: " + app.processName);
+ if (pkg != null) {
+ final ApplicationInfo app = pkg.applicationInfo;
+ if (app != null) {
+ try {
+ // unbind and tidy up even on timeout or failure, just in case
+ mActivityManager.unbindBackupAgent(app);
+
+ // The agent was running with a stub Application object, so shut it down.
+ if (app.uid != Process.SYSTEM_UID) {
+ if (DEBUG) Slog.d(TAG, "Backup complete, killing host process");
+ mActivityManager.killApplicationProcess(app.processName, app.uid);
+ } else {
+ if (DEBUG) Slog.d(TAG, "Not killing after restore: " + app.processName);
+ }
+ } catch (RemoteException e) {
+ Slog.d(TAG, "Lost app trying to shut down");
+ }
}
- } catch (RemoteException e) {
- Slog.d(TAG, "Lost app trying to shut down");
}
}
@@ -1949,6 +1983,7 @@ class BackupManagerService extends IBackupManager.Stub {
// with a whitelist of packages known to be unclearable.
mClearedPackages.add("android");
mClearedPackages.add("com.android.providers.settings");
+
}
class RestoreFileRunnable implements Runnable {
@@ -1988,6 +2023,11 @@ class BackupManagerService extends IBackupManager.Stub {
Slog.i(TAG, "--- Performing full-dataset restore ---");
sendStartRestore();
+ // Are we able to restore shared-storage data?
+ if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
+ mPackagePolicies.put("com.android.sharedstoragebackup", RestorePolicy.ACCEPT);
+ }
+
try {
byte[] buffer = new byte[32 * 1024];
FileInputStream instream = new FileInputStream(mInputFile.getFileDescriptor());
@@ -2707,7 +2747,9 @@ class BackupManagerService extends IBackupManager.Stub {
info.path, 0, FullBackup.SHARED_PREFIX.length())) {
// File in shared storage. !!! TODO: implement this.
info.path = info.path.substring(FullBackup.SHARED_PREFIX.length());
+ info.packageName = "com.android.sharedstoragebackup";
info.domain = FullBackup.SHARED_STORAGE_TOKEN;
+ if (DEBUG) Slog.i(TAG, "File in shared storage: " + info.path);
} else if (FullBackup.APPS_PREFIX.regionMatches(0,
info.path, 0, FullBackup.APPS_PREFIX.length())) {
// App content! Parse out the package name and domain
diff --git a/services/java/com/android/server/SystemBackupAgent.java b/services/java/com/android/server/SystemBackupAgent.java
index 99c8af6..08c6699 100644
--- a/services/java/com/android/server/SystemBackupAgent.java
+++ b/services/java/com/android/server/SystemBackupAgent.java
@@ -138,7 +138,7 @@ public class SystemBackupAgent extends BackupAgentHelper {
if (outFile == null) {
Slog.w(TAG, "Skipping unrecognized system file: [ " + domain + " : " + path + " ]");
}
- FullBackup.restoreToFile(data, size, type, mode, mtime, outFile);
+ FullBackup.restoreToFile(data, size, type, mode, mtime, outFile, true);
if (restoredWallpaper) {
WallpaperManagerService wallpaper =