Loading core/java/android/backup/IBackupManager.aidl +14 −0 Original line number Diff line number Diff line Loading @@ -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. Loading core/java/com/android/internal/backup/IBackupTransport.aidl +15 −3 Original line number Diff line number Diff line Loading @@ -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(); /** Loading core/java/com/android/internal/backup/LocalTransport.java +11 −0 Original line number Diff line number Diff line Loading @@ -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; Loading services/java/com/android/server/BackupManagerService.java +95 −0 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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; Loading Loading @@ -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; } } } } Loading Loading @@ -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 ----- Loading Loading @@ -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 { Loading Loading
core/java/android/backup/IBackupManager.aidl +14 −0 Original line number Diff line number Diff line Loading @@ -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. Loading
core/java/com/android/internal/backup/IBackupTransport.aidl +15 −3 Original line number Diff line number Diff line Loading @@ -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(); /** Loading
core/java/com/android/internal/backup/LocalTransport.java +11 −0 Original line number Diff line number Diff line Loading @@ -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; Loading
services/java/com/android/server/BackupManagerService.java +95 −0 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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; Loading Loading @@ -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; } } } } Loading Loading @@ -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 ----- Loading Loading @@ -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 { Loading