Merge change 6104 into donut
* changes: Add a "clear backed-up data" method to the backup mechanism
This commit is contained in:
@@ -32,9 +32,23 @@ 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.
|
||||
|
||||
@@ -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();
|
||||
|
||||
/**
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user