summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--core/java/android/backup/IBackupManager.aidl14
-rw-r--r--core/java/com/android/internal/backup/IBackupTransport.aidl18
-rw-r--r--core/java/com/android/internal/backup/LocalTransport.java11
-rw-r--r--services/java/com/android/server/BackupManagerService.java95
4 files changed, 135 insertions, 3 deletions
diff --git a/core/java/android/backup/IBackupManager.aidl b/core/java/android/backup/IBackupManager.aidl
index 1f11762..d4933ac 100644
--- a/core/java/android/backup/IBackupManager.aidl
+++ b/core/java/android/backup/IBackupManager.aidl
@@ -32,10 +32,24 @@ interface IBackupManager {
/**
* Tell the system service that the caller has made changes to its
* data, and therefore needs to undergo an incremental backup pass.
+ *
+ * Any application can invoke this method for its own package, but
+ * only callers who hold the android.permission.BACKUP permission
+ * may invoke it for arbitrary packages.
*/
void dataChanged(String packageName);
/**
+ * Erase all backed-up data for the given package from the storage
+ * destination.
+ *
+ * Any application can invoke this method for its own package, but
+ * only callers who hold the android.permission.BACKUP permission
+ * may invoke it for arbitrary packages.
+ */
+ void clearBackupData(String packageName);
+
+ /**
* Notifies the Backup Manager Service that an agent has become available. This
* method is only invoked by the Activity Manager.
*/
diff --git a/core/java/com/android/internal/backup/IBackupTransport.aidl b/core/java/com/android/internal/backup/IBackupTransport.aidl
index 4bef265..af06965 100644
--- a/core/java/com/android/internal/backup/IBackupTransport.aidl
+++ b/core/java/com/android/internal/backup/IBackupTransport.aidl
@@ -83,13 +83,25 @@ interface IBackupTransport {
boolean performBackup(in PackageInfo packageInfo, in ParcelFileDescriptor inFd);
/**
- * Finish sending application data to the backup destination. This must be
- * called after {@link #performBackup} to ensure that all data is sent. Only
- * when this method returns true can the backup be assumed to have succeeded.
+ * Erase the give application's data from the backup destination. This clears
+ * out the given package's data from the current backup set, making it as though
+ * the app had never yet been backed up. After this is called, {@link finishBackup}
+ * must be called to ensure that the operation is recorded successfully.
*
* @return false if errors occurred (the backup should be aborted and rescheduled),
* true if everything is OK so far (but {@link #finishBackup} must be called).
*/
+ boolean clearBackupData(in PackageInfo packageInfo);
+
+ /**
+ * Finish sending application data to the backup destination. This must be
+ * called after {@link #performBackup} or {@link clearBackupData} to ensure that
+ * all data is sent. Only when this method returns true can a backup be assumed
+ * to have succeeded.
+ *
+ * @return false if errors occurred (the backup should be aborted and rescheduled),
+ * true if everything is OK.
+ */
boolean finishBackup();
/**
diff --git a/core/java/com/android/internal/backup/LocalTransport.java b/core/java/com/android/internal/backup/LocalTransport.java
index c5d9d40..2facce2 100644
--- a/core/java/com/android/internal/backup/LocalTransport.java
+++ b/core/java/com/android/internal/backup/LocalTransport.java
@@ -111,6 +111,17 @@ public class LocalTransport extends IBackupTransport.Stub {
}
}
+ public boolean clearBackupData(PackageInfo packageInfo) {
+ if (DEBUG) Log.v(TAG, "clearBackupData() pkg=" + packageInfo.packageName);
+
+ File packageDir = new File(mDataDir, packageInfo.packageName);
+ for (File f : packageDir.listFiles()) {
+ f.delete();
+ }
+ packageDir.delete();
+ return true;
+ }
+
public boolean finishBackup() throws RemoteException {
if (DEBUG) Log.v(TAG, "finishBackup()");
return true;
diff --git a/services/java/com/android/server/BackupManagerService.java b/services/java/com/android/server/BackupManagerService.java
index 953e401..8790472 100644
--- a/services/java/com/android/server/BackupManagerService.java
+++ b/services/java/com/android/server/BackupManagerService.java
@@ -81,6 +81,7 @@ class BackupManagerService extends IBackupManager.Stub {
private static final int MSG_RUN_BACKUP = 1;
private static final int MSG_RUN_FULL_BACKUP = 2;
private static final int MSG_RUN_RESTORE = 3;
+ private static final int MSG_RUN_CLEAR = 4;
// Timeout interval for deciding that a bind or clear-data has taken too long
static final long TIMEOUT_INTERVAL = 10 * 1000;
@@ -148,6 +149,16 @@ class BackupManagerService extends IBackupManager.Stub {
}
}
+ private class ClearParams {
+ public IBackupTransport transport;
+ public PackageInfo packageInfo;
+
+ ClearParams(IBackupTransport _transport, PackageInfo _info) {
+ transport = _transport;
+ packageInfo = _info;
+ }
+ }
+
// Where we keep our journal files and other bookkeeping
private File mBaseStateDir;
private File mDataDir;
@@ -386,6 +397,13 @@ class BackupManagerService extends IBackupManager.Stub {
(new PerformRestoreThread(params.transport, params.observer, params.token)).start();
break;
}
+
+ case MSG_RUN_CLEAR:
+ {
+ ClearParams params = (ClearParams)msg.obj;
+ (new PerformClearThread(params.transport, params.packageInfo)).start();
+ break;
+ }
}
}
}
@@ -1071,6 +1089,37 @@ class BackupManagerService extends IBackupManager.Stub {
}
}
+ class PerformClearThread extends Thread {
+ IBackupTransport mTransport;
+ PackageInfo mPackage;
+
+ PerformClearThread(IBackupTransport transport, PackageInfo packageInfo) {
+ mTransport = transport;
+ mPackage = packageInfo;
+ }
+
+ @Override
+ public void run() {
+ try {
+ // Clear the on-device backup state to ensure a full backup next time
+ File stateDir = new File(mBaseStateDir, mTransport.transportDirName());
+ File stateFile = new File(stateDir, mPackage.packageName);
+ stateFile.delete();
+
+ // Tell the transport to remove all the persistent storage for the app
+ mTransport.clearBackupData(mPackage);
+ } catch (RemoteException e) {
+ // can't happen; the transport is local
+ } finally {
+ try {
+ mTransport.finishBackup();
+ } catch (RemoteException e) {
+ // can't happen; the transport is local
+ }
+ }
+ }
+ }
+
// ----- IBackupManager binder interface -----
@@ -1142,6 +1191,52 @@ class BackupManagerService extends IBackupManager.Stub {
}
}
+ // Clear the given package's backup data from the current transport
+ public void clearBackupData(String packageName) {
+ if (DEBUG) Log.v(TAG, "clearBackupData() of " + packageName);
+ PackageInfo info;
+ try {
+ info = mPackageManager.getPackageInfo(packageName, PackageManager.GET_SIGNATURES);
+ } catch (NameNotFoundException e) {
+ Log.d(TAG, "No such package '" + packageName + "' - not clearing backup data");
+ return;
+ }
+
+ // If the caller does not hold the BACKUP permission, it can only request a
+ // wipe of its own backed-up data.
+ HashSet<ApplicationInfo> apps;
+ if ((mContext.checkPermission("android.permission.BACKUP", Binder.getCallingPid(),
+ Binder.getCallingUid())) == PackageManager.PERMISSION_DENIED) {
+ apps = mBackupParticipants.get(Binder.getCallingUid());
+ } else {
+ // a caller with full permission can ask to back up any participating app
+ // !!! TODO: allow data-clear of ANY app?
+ if (DEBUG) Log.v(TAG, "Privileged caller, allowing clear of other apps");
+ apps = new HashSet<ApplicationInfo>();
+ int N = mBackupParticipants.size();
+ for (int i = 0; i < N; i++) {
+ HashSet<ApplicationInfo> s = mBackupParticipants.valueAt(i);
+ if (s != null) {
+ apps.addAll(s);
+ }
+ }
+ }
+
+ // now find the given package in the set of candidate apps
+ for (ApplicationInfo app : apps) {
+ if (app.packageName.equals(packageName)) {
+ if (DEBUG) Log.v(TAG, "Found the app - running clear process");
+ // found it; fire off the clear request
+ synchronized (mQueueLock) {
+ Message msg = mBackupHandler.obtainMessage(MSG_RUN_CLEAR,
+ new ClearParams(getTransport(mCurrentTransport), info));
+ mBackupHandler.sendMessage(msg);
+ }
+ break;
+ }
+ }
+ }
+
// Run a backup pass immediately for any applications that have declared
// that they have pending updates.
public void backupNow() throws RemoteException {