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
|
* Tell the system service that the caller has made changes to its
|
||||||
* data, and therefore needs to undergo an incremental backup pass.
|
* 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);
|
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
|
* Notifies the Backup Manager Service that an agent has become available. This
|
||||||
* method is only invoked by the Activity Manager.
|
* method is only invoked by the Activity Manager.
|
||||||
|
|||||||
@@ -83,13 +83,25 @@ interface IBackupTransport {
|
|||||||
boolean performBackup(in PackageInfo packageInfo, in ParcelFileDescriptor inFd);
|
boolean performBackup(in PackageInfo packageInfo, in ParcelFileDescriptor inFd);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Finish sending application data to the backup destination. This must be
|
* Erase the give application's data from the backup destination. This clears
|
||||||
* called after {@link #performBackup} to ensure that all data is sent. Only
|
* out the given package's data from the current backup set, making it as though
|
||||||
* when this method returns true can the backup be assumed to have succeeded.
|
* 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),
|
* @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).
|
* 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();
|
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 {
|
public boolean finishBackup() throws RemoteException {
|
||||||
if (DEBUG) Log.v(TAG, "finishBackup()");
|
if (DEBUG) Log.v(TAG, "finishBackup()");
|
||||||
return true;
|
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_BACKUP = 1;
|
||||||
private static final int MSG_RUN_FULL_BACKUP = 2;
|
private static final int MSG_RUN_FULL_BACKUP = 2;
|
||||||
private static final int MSG_RUN_RESTORE = 3;
|
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
|
// Timeout interval for deciding that a bind or clear-data has taken too long
|
||||||
static final long TIMEOUT_INTERVAL = 10 * 1000;
|
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
|
// Where we keep our journal files and other bookkeeping
|
||||||
private File mBaseStateDir;
|
private File mBaseStateDir;
|
||||||
private File mDataDir;
|
private File mDataDir;
|
||||||
@@ -386,6 +397,13 @@ class BackupManagerService extends IBackupManager.Stub {
|
|||||||
(new PerformRestoreThread(params.transport, params.observer, params.token)).start();
|
(new PerformRestoreThread(params.transport, params.observer, params.token)).start();
|
||||||
break;
|
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 -----
|
// ----- 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
|
// Run a backup pass immediately for any applications that have declared
|
||||||
// that they have pending updates.
|
// that they have pending updates.
|
||||||
public void backupNow() throws RemoteException {
|
public void backupNow() throws RemoteException {
|
||||||
|
|||||||
Reference in New Issue
Block a user