Keep track of backup state independently for each transport
Backup transports now provide the Backup Manager with a suggested name with which it can disambiguate any transport-specific bookkeeping that it needs to maintain. The Manager keeps separate application backup 'state blobs' for each transport now, preventing things from getting out of step if the device is switched among multiple transports. Also, the metadata backup agent is always invoked now on each backup pass. This is cheap when there is nothing to do, but also strongly ensures that we never wind up in a situation where a given transport destination has not been given all of the metadata necessary for the backup set.
This commit is contained in:
@ -40,6 +40,20 @@ interface IBackupTransport {
|
||||
- cloud: tear down connection etc
|
||||
- adb: close the file
|
||||
*/
|
||||
/**
|
||||
* Ask the transport where, on local device storage, to keep backup state blobs.
|
||||
* This is per-transport so that mock transports used for testing can coexist with
|
||||
* "live" backup services without interfering with the live bookkeeping. The
|
||||
* returned string should be a name that is expected to be unambiguous among all
|
||||
* available backup transports; the name of the class implementing the transport
|
||||
* is a good choice.
|
||||
*
|
||||
* @return A unique name, suitable for use as a file or directory name, that the
|
||||
* Backup Manager could use to disambiguate state files associated with
|
||||
* different backup transports.
|
||||
*/
|
||||
String transportDirName();
|
||||
|
||||
/**
|
||||
* Verify that this is a suitable time for a backup pass. This should return zero
|
||||
* if a backup is reasonable right now, some positive value otherwise. This method
|
||||
|
@ -30,6 +30,9 @@ public class LocalTransport extends IBackupTransport.Stub {
|
||||
private static final String TAG = "LocalTransport";
|
||||
private static final boolean DEBUG = true;
|
||||
|
||||
private static final String TRANSPORT_DIR_NAME
|
||||
= "com.android.internal.backup.LocalTransport";
|
||||
|
||||
private Context mContext;
|
||||
private PackageManager mPackageManager;
|
||||
private File mDataDir = new File(Environment.getDownloadCacheDirectory(), "backup");
|
||||
@ -43,6 +46,11 @@ public class LocalTransport extends IBackupTransport.Stub {
|
||||
mPackageManager = context.getPackageManager();
|
||||
}
|
||||
|
||||
|
||||
public String transportDirName() throws RemoteException {
|
||||
return TRANSPORT_DIR_NAME;
|
||||
}
|
||||
|
||||
public long requestBackupTime() throws RemoteException {
|
||||
// any time is a good time for local backup
|
||||
return 0;
|
||||
|
@ -109,8 +109,8 @@ class BackupManagerService extends IBackupManager.Stub {
|
||||
// Backups that we haven't started yet.
|
||||
private HashMap<ApplicationInfo,BackupRequest> mPendingBackups
|
||||
= new HashMap<ApplicationInfo,BackupRequest>();
|
||||
// Do we need to back up the package manager metadata on the next pass?
|
||||
private boolean mDoPackageManager;
|
||||
|
||||
// Pseudoname that we use for the Package Manager metadata "package"
|
||||
private static final String PACKAGE_MANAGER_SENTINEL = "@pm@";
|
||||
|
||||
// locking around the pending-backup management
|
||||
@ -133,7 +133,8 @@ class BackupManagerService extends IBackupManager.Stub {
|
||||
private IBackupTransport mLocalTransport, mGoogleTransport;
|
||||
private RestoreSession mActiveRestoreSession;
|
||||
|
||||
private File mStateDir;
|
||||
// Where we keep our journal files and other bookkeeping
|
||||
private File mBaseStateDir;
|
||||
private File mDataDir;
|
||||
private File mJournalDir;
|
||||
private File mJournal;
|
||||
@ -145,13 +146,12 @@ class BackupManagerService extends IBackupManager.Stub {
|
||||
mActivityManager = ActivityManagerNative.getDefault();
|
||||
|
||||
// Set up our bookkeeping
|
||||
mStateDir = new File(Environment.getDataDirectory(), "backup");
|
||||
mStateDir.mkdirs();
|
||||
mBaseStateDir = new File(Environment.getDataDirectory(), "backup");
|
||||
mDataDir = Environment.getDownloadCacheDirectory();
|
||||
|
||||
// Set up the backup-request journaling
|
||||
mJournalDir = new File(mStateDir, "pending");
|
||||
mJournalDir.mkdirs();
|
||||
mJournalDir = new File(mBaseStateDir, "pending");
|
||||
mJournalDir.mkdirs(); // creates mBaseStateDir along the way
|
||||
makeJournalLocked(); // okay because no other threads are running yet
|
||||
|
||||
// Build our mapping of uid to backup client services. This implicitly
|
||||
@ -372,7 +372,6 @@ class BackupManagerService extends IBackupManager.Stub {
|
||||
mBackupParticipants.put(uid, set);
|
||||
}
|
||||
set.add(pkg.applicationInfo);
|
||||
backUpPackageManagerData();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -416,7 +415,6 @@ class BackupManagerService extends IBackupManager.Stub {
|
||||
for (ApplicationInfo entry: set) {
|
||||
if (entry.packageName.equals(pkg.packageName)) {
|
||||
set.remove(entry);
|
||||
backUpPackageManagerData();
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -459,14 +457,6 @@ class BackupManagerService extends IBackupManager.Stub {
|
||||
addPackageParticipantsLockedInner(packageName, allApps);
|
||||
}
|
||||
|
||||
private void backUpPackageManagerData() {
|
||||
// No need to schedule a backup just for the metadata; just piggyback on
|
||||
// the next actual data backup.
|
||||
synchronized(this) {
|
||||
mDoPackageManager = true;
|
||||
}
|
||||
}
|
||||
|
||||
// The queue lock should be held when scheduling a backup pass
|
||||
private void scheduleBackupPassLocked(long timeFromNowMillis) {
|
||||
mBackupHandler.removeMessages(MSG_RUN_BACKUP);
|
||||
@ -564,6 +554,7 @@ class BackupManagerService extends IBackupManager.Stub {
|
||||
private static final String TAG = "PerformBackupThread";
|
||||
IBackupTransport mTransport;
|
||||
ArrayList<BackupRequest> mQueue;
|
||||
File mStateDir;
|
||||
File mJournal;
|
||||
|
||||
public PerformBackupThread(IBackupTransport transport, ArrayList<BackupRequest> queue,
|
||||
@ -571,32 +562,31 @@ class BackupManagerService extends IBackupManager.Stub {
|
||||
mTransport = transport;
|
||||
mQueue = queue;
|
||||
mJournal = journal;
|
||||
|
||||
try {
|
||||
mStateDir = new File(mBaseStateDir, transport.transportDirName());
|
||||
} catch (RemoteException e) {
|
||||
// can't happen; the transport is local
|
||||
}
|
||||
mStateDir.mkdirs();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
if (DEBUG) Log.v(TAG, "Beginning backup of " + mQueue.size() + " targets");
|
||||
|
||||
// First, back up the package manager metadata if necessary
|
||||
boolean doPackageManager;
|
||||
synchronized (BackupManagerService.this) {
|
||||
doPackageManager = mDoPackageManager;
|
||||
mDoPackageManager = false;
|
||||
}
|
||||
if (doPackageManager) {
|
||||
// The package manager doesn't have a proper <application> etc, but since
|
||||
// it's running here in the system process we can just set up its agent
|
||||
// directly and use a synthetic BackupRequest.
|
||||
if (DEBUG) Log.i(TAG, "Running PM backup pass as well");
|
||||
|
||||
PackageManagerBackupAgent pmAgent = new PackageManagerBackupAgent(
|
||||
mPackageManager, allAgentPackages());
|
||||
BackupRequest pmRequest = new BackupRequest(new ApplicationInfo(), false);
|
||||
pmRequest.appInfo.packageName = PACKAGE_MANAGER_SENTINEL;
|
||||
processOneBackup(pmRequest,
|
||||
IBackupAgent.Stub.asInterface(pmAgent.onBind()),
|
||||
mTransport);
|
||||
}
|
||||
// The package manager doesn't have a proper <application> etc, but since
|
||||
// it's running here in the system process we can just set up its agent
|
||||
// directly and use a synthetic BackupRequest. We always run this pass
|
||||
// because it's cheap and this way we guarantee that we don't get out of
|
||||
// step even if we're selecting among various transports at run time.
|
||||
PackageManagerBackupAgent pmAgent = new PackageManagerBackupAgent(
|
||||
mPackageManager, allAgentPackages());
|
||||
BackupRequest pmRequest = new BackupRequest(new ApplicationInfo(), false);
|
||||
pmRequest.appInfo.packageName = PACKAGE_MANAGER_SENTINEL;
|
||||
processOneBackup(pmRequest,
|
||||
IBackupAgent.Stub.asInterface(pmAgent.onBind()),
|
||||
mTransport);
|
||||
|
||||
// Now run all the backups in our queue
|
||||
doQueuedBackups(mTransport);
|
||||
@ -760,6 +750,7 @@ class BackupManagerService extends IBackupManager.Stub {
|
||||
private IBackupTransport mTransport;
|
||||
private int mToken;
|
||||
private RestoreSet mImage;
|
||||
private File mStateDir;
|
||||
|
||||
class RestoreRequest {
|
||||
public PackageInfo app;
|
||||
@ -774,6 +765,13 @@ class BackupManagerService extends IBackupManager.Stub {
|
||||
PerformRestoreThread(IBackupTransport transport, int restoreSetToken) {
|
||||
mTransport = transport;
|
||||
mToken = restoreSetToken;
|
||||
|
||||
try {
|
||||
mStateDir = new File(mBaseStateDir, transport.transportDirName());
|
||||
} catch (RemoteException e) {
|
||||
// can't happen; the transport is local
|
||||
}
|
||||
mStateDir.mkdirs();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
Reference in New Issue
Block a user