Merge change 26290 into eclair
* changes: Make IBackupTransport.finishBackup() also return an int code, since it too can return TRANSPORT_NOT_INITIALIZED (in fact that's typically how it comes).
This commit is contained in:
@@ -22,24 +22,6 @@ import android.os.ParcelFileDescriptor;
|
|||||||
|
|
||||||
/** {@hide} */
|
/** {@hide} */
|
||||||
interface IBackupTransport {
|
interface IBackupTransport {
|
||||||
/* STOPSHIP - don't ship with this comment in place
|
|
||||||
Things the transport interface has to do:
|
|
||||||
1. set up the connection to the destination
|
|
||||||
- set up encryption
|
|
||||||
- for Google cloud, log in using the user's gaia credential or whatever
|
|
||||||
- for adb, just set up the all-in-one destination file
|
|
||||||
2. send each app's backup transaction
|
|
||||||
- parse the data file for key/value pointers etc
|
|
||||||
- send key/blobsize set to the Google cloud, get back quota ok/rejected response
|
|
||||||
- sd/adb doesn't preflight; no per-app quota
|
|
||||||
- app's entire change is essentially atomic
|
|
||||||
- cloud transaction encrypts then sends each key/value pair separately; we already
|
|
||||||
parsed the data when preflighting so we don't have to again here
|
|
||||||
- sd target streams raw data into encryption envelope then to sd?
|
|
||||||
3. shut down connection to destination
|
|
||||||
- cloud: tear down connection etc
|
|
||||||
- adb: close the file
|
|
||||||
*/
|
|
||||||
/**
|
/**
|
||||||
* Ask the transport where, on local device storage, to keep backup state blobs.
|
* 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
|
* This is per-transport so that mock transports used for testing can coexist with
|
||||||
@@ -67,6 +49,17 @@ interface IBackupTransport {
|
|||||||
*/
|
*/
|
||||||
long requestBackupTime();
|
long requestBackupTime();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize the server side storage for this device, erasing all stored data.
|
||||||
|
* The transport may send the request immediately, or may buffer it. After
|
||||||
|
* this is called, {@link #finishBackup} must be called to ensure the request
|
||||||
|
* is sent and received successfully.
|
||||||
|
*
|
||||||
|
* @return One of {@link BackupConstants#TRANSPORT_OK} (OK so far) or
|
||||||
|
* {@link BackupConstants#TRANSPORT_ERROR} (on network error or other failure).
|
||||||
|
*/
|
||||||
|
int initializeDevice();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Send one application's data to the backup destination. The transport may send
|
* Send one application's data to the backup destination. The transport may send
|
||||||
* the data immediately, or may buffer it. After this is called, {@link #finishBackup}
|
* the data immediately, or may buffer it. After this is called, {@link #finishBackup}
|
||||||
@@ -81,15 +74,12 @@ interface IBackupTransport {
|
|||||||
* will be erased prior to the storage of the data provided here. The purpose of this
|
* will be erased prior to the storage of the data provided here. The purpose of this
|
||||||
* is to provide a guarantee that no stale data exists in the restore set when the
|
* is to provide a guarantee that no stale data exists in the restore set when the
|
||||||
* device begins providing backups.
|
* device begins providing backups.
|
||||||
* @return If everything is okay so far, returns zero (but {@link #finishBackup} must
|
* @return one of {@link BackupConstants#TRANSPORT_OK} (OK so far),
|
||||||
* still be called). If the backend dataset has unexpectedly become unavailable,
|
* {@link BackupConstants#TRANSPORT_ERROR} (on network error or other failure), or
|
||||||
* such as when it is deleted after a period of device inactivity, returns {@link
|
* {@link BackupConstants#TRANSPORT_NOT_INITIALIZED} (if the backend dataset has
|
||||||
* BackupManager#DATASET_UNAVAILABLE}; in this case, the transport should be
|
* become lost due to inactive expiry or some other reason and needs re-initializing)
|
||||||
* reinitalized and the entire backup pass restarted. Any other nonzero value is a
|
|
||||||
* fatal error requiring that this package's backup be aborted and rescheduled.
|
|
||||||
*/
|
*/
|
||||||
int performBackup(in PackageInfo packageInfo, in ParcelFileDescriptor inFd,
|
int performBackup(in PackageInfo packageInfo, in ParcelFileDescriptor inFd);
|
||||||
boolean wipeAllFirst);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Erase the give application's data from the backup destination. This clears
|
* Erase the give application's data from the backup destination. This clears
|
||||||
@@ -97,10 +87,9 @@ interface IBackupTransport {
|
|||||||
* the app had never yet been backed up. After this is called, {@link finishBackup}
|
* 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.
|
* must be called to ensure that the operation is recorded successfully.
|
||||||
*
|
*
|
||||||
* @return false if errors occurred (the backup should be aborted and rescheduled),
|
* @return the same error codes as {@link #performBackup}.
|
||||||
* true if everything is OK so far (but {@link #finishBackup} must be called).
|
|
||||||
*/
|
*/
|
||||||
boolean clearBackupData(in PackageInfo packageInfo);
|
int clearBackupData(in PackageInfo packageInfo);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Finish sending application data to the backup destination. This must be
|
* Finish sending application data to the backup destination. This must be
|
||||||
@@ -108,10 +97,9 @@ interface IBackupTransport {
|
|||||||
* all data is sent. Only when this method returns true can a backup be assumed
|
* all data is sent. Only when this method returns true can a backup be assumed
|
||||||
* to have succeeded.
|
* to have succeeded.
|
||||||
*
|
*
|
||||||
* @return false if errors occurred (the backup should be aborted and rescheduled),
|
* @return the same error codes as {@link #performBackup}.
|
||||||
* true if everything is OK.
|
|
||||||
*/
|
*/
|
||||||
boolean finishBackup();
|
int finishBackup();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the set of backups currently available over this transport.
|
* Get the set of backups currently available over this transport.
|
||||||
@@ -129,10 +117,11 @@ interface IBackupTransport {
|
|||||||
* @param token A backup token as returned by {@link #getAvailableRestoreSets}.
|
* @param token A backup token as returned by {@link #getAvailableRestoreSets}.
|
||||||
* @param packages List of applications to restore (if data is available).
|
* @param packages List of applications to restore (if data is available).
|
||||||
* Application data will be restored in the order given.
|
* Application data will be restored in the order given.
|
||||||
* @return false if errors occurred (the restore should be aborted and rescheduled),
|
* @return One of {@link BackupConstants#TRANSPORT_OK} (OK so far, call
|
||||||
* true if everything is OK so far (go ahead and call {@link #nextRestorePackage}).
|
* {@link #nextRestorePackage}) or {@link BackupConstants#TRANSPORT_ERROR}
|
||||||
|
* (an error occurred, the restore should be aborted and rescheduled).
|
||||||
*/
|
*/
|
||||||
boolean startRestore(long token, in PackageInfo[] packages);
|
int startRestore(long token, in PackageInfo[] packages);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the package name of the next application with data in the backup store.
|
* Get the package name of the next application with data in the backup store.
|
||||||
@@ -145,10 +134,9 @@ interface IBackupTransport {
|
|||||||
/**
|
/**
|
||||||
* Get the data for the application returned by {@link #nextRestorePackage}.
|
* Get the data for the application returned by {@link #nextRestorePackage}.
|
||||||
* @param data An open, writable file into which the backup data should be stored.
|
* @param data An open, writable file into which the backup data should be stored.
|
||||||
* @return false if errors occurred (the restore should be aborted and rescheduled),
|
* @return the same error codes as {@link #nextRestorePackage}.
|
||||||
* true if everything is OK so far (go ahead and call {@link #nextRestorePackage}).
|
|
||||||
*/
|
*/
|
||||||
boolean getRestoreData(in ParcelFileDescriptor outFd);
|
int getRestoreData(in ParcelFileDescriptor outFd);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* End a restore session (aborting any in-process data transfer as necessary),
|
* End a restore session (aborting any in-process data transfer as necessary),
|
||||||
|
|||||||
@@ -47,25 +47,26 @@ public class LocalTransport extends IBackupTransport.Stub {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public String transportDirName() throws RemoteException {
|
public String transportDirName() {
|
||||||
return TRANSPORT_DIR_NAME;
|
return TRANSPORT_DIR_NAME;
|
||||||
}
|
}
|
||||||
|
|
||||||
public long requestBackupTime() throws RemoteException {
|
public long requestBackupTime() {
|
||||||
// any time is a good time for local backup
|
// any time is a good time for local backup
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int performBackup(PackageInfo packageInfo, ParcelFileDescriptor data,
|
public int initializeDevice() {
|
||||||
boolean wipeAllFirst) throws RemoteException {
|
if (DEBUG) Log.v(TAG, "wiping all data");
|
||||||
|
deleteContents(mDataDir);
|
||||||
|
return BackupConstants.TRANSPORT_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int performBackup(PackageInfo packageInfo, ParcelFileDescriptor data) {
|
||||||
if (DEBUG) Log.v(TAG, "performBackup() pkg=" + packageInfo.packageName);
|
if (DEBUG) Log.v(TAG, "performBackup() pkg=" + packageInfo.packageName);
|
||||||
|
|
||||||
File packageDir = new File(mDataDir, packageInfo.packageName);
|
File packageDir = new File(mDataDir, packageInfo.packageName);
|
||||||
packageDir.mkdirs();
|
packageDir.mkdirs();
|
||||||
if (wipeAllFirst) {
|
|
||||||
if (DEBUG) Log.v(TAG, "wiping all data first");
|
|
||||||
deleteContents(mDataDir);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Each 'record' in the restore set is kept in its own file, named by
|
// Each 'record' in the restore set is kept in its own file, named by
|
||||||
// the record key. Wind through the data file, extracting individual
|
// the record key. Wind through the data file, extracting individual
|
||||||
@@ -130,7 +131,7 @@ public class LocalTransport extends IBackupTransport.Stub {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean clearBackupData(PackageInfo packageInfo) {
|
public int clearBackupData(PackageInfo packageInfo) {
|
||||||
if (DEBUG) Log.v(TAG, "clearBackupData() pkg=" + packageInfo.packageName);
|
if (DEBUG) Log.v(TAG, "clearBackupData() pkg=" + packageInfo.packageName);
|
||||||
|
|
||||||
File packageDir = new File(mDataDir, packageInfo.packageName);
|
File packageDir = new File(mDataDir, packageInfo.packageName);
|
||||||
@@ -138,12 +139,12 @@ public class LocalTransport extends IBackupTransport.Stub {
|
|||||||
f.delete();
|
f.delete();
|
||||||
}
|
}
|
||||||
packageDir.delete();
|
packageDir.delete();
|
||||||
return true;
|
return BackupConstants.TRANSPORT_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean finishBackup() throws RemoteException {
|
public int finishBackup() {
|
||||||
if (DEBUG) Log.v(TAG, "finishBackup()");
|
if (DEBUG) Log.v(TAG, "finishBackup()");
|
||||||
return true;
|
return BackupConstants.TRANSPORT_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Restore handling
|
// Restore handling
|
||||||
@@ -154,11 +155,11 @@ public class LocalTransport extends IBackupTransport.Stub {
|
|||||||
return array;
|
return array;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean startRestore(long token, PackageInfo[] packages) {
|
public int startRestore(long token, PackageInfo[] packages) {
|
||||||
if (DEBUG) Log.v(TAG, "start restore " + token);
|
if (DEBUG) Log.v(TAG, "start restore " + token);
|
||||||
mRestorePackages = packages;
|
mRestorePackages = packages;
|
||||||
mRestorePackage = -1;
|
mRestorePackage = -1;
|
||||||
return true;
|
return BackupConstants.TRANSPORT_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String nextRestorePackage() {
|
public String nextRestorePackage() {
|
||||||
@@ -175,7 +176,7 @@ public class LocalTransport extends IBackupTransport.Stub {
|
|||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean getRestoreData(ParcelFileDescriptor outFd) {
|
public int getRestoreData(ParcelFileDescriptor outFd) {
|
||||||
if (mRestorePackages == null) throw new IllegalStateException("startRestore not called");
|
if (mRestorePackages == null) throw new IllegalStateException("startRestore not called");
|
||||||
if (mRestorePackage < 0) throw new IllegalStateException("nextRestorePackage not called");
|
if (mRestorePackage < 0) throw new IllegalStateException("nextRestorePackage not called");
|
||||||
File packageDir = new File(mDataDir, mRestorePackages[mRestorePackage].packageName);
|
File packageDir = new File(mDataDir, mRestorePackages[mRestorePackage].packageName);
|
||||||
@@ -183,9 +184,9 @@ public class LocalTransport extends IBackupTransport.Stub {
|
|||||||
// The restore set is the concatenation of the individual record blobs,
|
// The restore set is the concatenation of the individual record blobs,
|
||||||
// each of which is a file in the package's directory
|
// each of which is a file in the package's directory
|
||||||
File[] blobs = packageDir.listFiles();
|
File[] blobs = packageDir.listFiles();
|
||||||
if (blobs == null) {
|
if (blobs == null) { // nextRestorePackage() ensures the dir exists, so this is an error
|
||||||
Log.e(TAG, "Error listing directory: " + packageDir);
|
Log.e(TAG, "Error listing directory: " + packageDir);
|
||||||
return false; // nextRestorePackage() ensures the dir exists, so this is an error
|
return BackupConstants.TRANSPORT_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
// We expect at least some data if the directory exists in the first place
|
// We expect at least some data if the directory exists in the first place
|
||||||
@@ -206,10 +207,10 @@ public class LocalTransport extends IBackupTransport.Stub {
|
|||||||
in.close();
|
in.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return BackupConstants.TRANSPORT_OK;
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
Log.e(TAG, "Unable to read backup records", e);
|
Log.e(TAG, "Unable to read backup records", e);
|
||||||
return false;
|
return BackupConstants.TRANSPORT_ERROR;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -920,52 +920,56 @@ class BackupManagerService extends IBackupManager.Stub {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
EventLog.writeEvent(BACKUP_START_EVENT, mTransport.transportDirName());
|
EventLog.writeEvent(BACKUP_START_EVENT, mTransport.transportDirName());
|
||||||
|
int status = BackupConstants.TRANSPORT_OK;
|
||||||
|
|
||||||
|
// If we haven't stored anything yet, we need to do an init operation.
|
||||||
|
if (status == BackupConstants.TRANSPORT_OK && mEverStoredApps.size() == 0) {
|
||||||
|
status = mTransport.initializeDevice();
|
||||||
|
}
|
||||||
|
|
||||||
// The package manager doesn't have a proper <application> etc, but since
|
// 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
|
// 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
|
// 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
|
// 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.
|
// step even if we're selecting among various transports at run time.
|
||||||
PackageManagerBackupAgent pmAgent = new PackageManagerBackupAgent(
|
if (status == BackupConstants.TRANSPORT_OK) {
|
||||||
mPackageManager, allAgentPackages());
|
PackageManagerBackupAgent pmAgent = new PackageManagerBackupAgent(
|
||||||
BackupRequest pmRequest = new BackupRequest(new ApplicationInfo(), false);
|
mPackageManager, allAgentPackages());
|
||||||
pmRequest.appInfo.packageName = PACKAGE_MANAGER_SENTINEL;
|
BackupRequest pmRequest = new BackupRequest(new ApplicationInfo(), false);
|
||||||
|
pmRequest.appInfo.packageName = PACKAGE_MANAGER_SENTINEL;
|
||||||
|
status = processOneBackup(pmRequest,
|
||||||
|
IBackupAgent.Stub.asInterface(pmAgent.onBind()), mTransport);
|
||||||
|
}
|
||||||
|
|
||||||
// If we haven't stored anything yet, we need to do an init
|
if (status == BackupConstants.TRANSPORT_OK) {
|
||||||
// operation along with recording the metadata blob.
|
// Now run all the backups in our queue
|
||||||
boolean needInit = (mEverStoredApps.size() == 0);
|
status = doQueuedBackups(mTransport);
|
||||||
int result = processOneBackup(pmRequest,
|
}
|
||||||
IBackupAgent.Stub.asInterface(pmAgent.onBind()),
|
|
||||||
mTransport, needInit);
|
if (status == BackupConstants.TRANSPORT_OK) {
|
||||||
if (result == BackupConstants.TRANSPORT_NOT_INITIALIZED) {
|
// Tell the transport to finish everything it has buffered
|
||||||
|
status = mTransport.finishBackup();
|
||||||
|
if (status == BackupConstants.TRANSPORT_OK) {
|
||||||
|
int millis = (int) (SystemClock.elapsedRealtime() - startRealtime);
|
||||||
|
EventLog.writeEvent(BACKUP_SUCCESS_EVENT, mQueue.size(), millis);
|
||||||
|
} else {
|
||||||
|
EventLog.writeEvent(BACKUP_TRANSPORT_FAILURE_EVENT, "");
|
||||||
|
Log.e(TAG, "Transport error in finishBackup()");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// When we succeed at everything, we can remove the journal
|
||||||
|
if (status == BackupConstants.TRANSPORT_OK && !mJournal.delete()) {
|
||||||
|
Log.e(TAG, "Unable to remove backup journal file " + mJournal);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (status == BackupConstants.TRANSPORT_NOT_INITIALIZED) {
|
||||||
// The backend reports that our dataset has been wiped. We need to
|
// The backend reports that our dataset has been wiped. We need to
|
||||||
// reset all of our bookkeeping and instead run a new backup pass for
|
// reset all of our bookkeeping and instead run a new backup pass for
|
||||||
// everything.
|
// everything.
|
||||||
EventLog.writeEvent(BACKUP_RESET_EVENT, mTransport.transportDirName());
|
EventLog.writeEvent(BACKUP_RESET_EVENT, mTransport.transportDirName());
|
||||||
resetBackupState(mStateDir);
|
resetBackupState(mStateDir);
|
||||||
backupNow();
|
backupNow();
|
||||||
return;
|
|
||||||
} else if (result != BackupConstants.TRANSPORT_OK) {
|
|
||||||
// Give up if we couldn't even process the metadata
|
|
||||||
Log.e(TAG, "Meta backup err " + result);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Now run all the backups in our queue
|
|
||||||
int count = mQueue.size();
|
|
||||||
doQueuedBackups(mTransport);
|
|
||||||
|
|
||||||
// Finally, tear down the transport
|
|
||||||
if (mTransport.finishBackup()) {
|
|
||||||
int millis = (int) (SystemClock.elapsedRealtime() - startRealtime);
|
|
||||||
EventLog.writeEvent(BACKUP_SUCCESS_EVENT, count, millis);
|
|
||||||
} else {
|
|
||||||
EventLog.writeEvent(BACKUP_TRANSPORT_FAILURE_EVENT, "");
|
|
||||||
Log.e(TAG, "Transport error in finishBackup()");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!mJournal.delete()) {
|
|
||||||
Log.e(TAG, "Unable to remove backup journal file " + mJournal);
|
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
Log.e(TAG, "Error in backup thread", e);
|
Log.e(TAG, "Error in backup thread", e);
|
||||||
@@ -975,7 +979,7 @@ class BackupManagerService extends IBackupManager.Stub {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void doQueuedBackups(IBackupTransport transport) {
|
private int doQueuedBackups(IBackupTransport transport) {
|
||||||
for (BackupRequest request : mQueue) {
|
for (BackupRequest request : mQueue) {
|
||||||
Log.d(TAG, "starting agent for backup of " + request);
|
Log.d(TAG, "starting agent for backup of " + request);
|
||||||
|
|
||||||
@@ -995,25 +999,26 @@ class BackupManagerService extends IBackupManager.Stub {
|
|||||||
try {
|
try {
|
||||||
agent = bindToAgentSynchronous(request.appInfo, mode);
|
agent = bindToAgentSynchronous(request.appInfo, mode);
|
||||||
if (agent != null) {
|
if (agent != null) {
|
||||||
processOneBackup(request, agent, transport, false);
|
int result = processOneBackup(request, agent, transport);
|
||||||
|
if (result != BackupConstants.TRANSPORT_OK) return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
// unbind even on timeout, just in case
|
|
||||||
mActivityManager.unbindBackupAgent(request.appInfo);
|
|
||||||
} catch (SecurityException ex) {
|
} catch (SecurityException ex) {
|
||||||
// Try for the next one.
|
// Try for the next one.
|
||||||
Log.d(TAG, "error in bind/backup", ex);
|
Log.d(TAG, "error in bind/backup", ex);
|
||||||
} catch (RemoteException e) {
|
} finally {
|
||||||
Log.v(TAG, "bind/backup threw");
|
try { // unbind even on timeout, just in case
|
||||||
e.printStackTrace();
|
mActivityManager.unbindBackupAgent(request.appInfo);
|
||||||
|
} catch (RemoteException e) {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return BackupConstants.TRANSPORT_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int processOneBackup(BackupRequest request, IBackupAgent agent,
|
private int processOneBackup(BackupRequest request, IBackupAgent agent,
|
||||||
IBackupTransport transport, boolean doInit) {
|
IBackupTransport transport) {
|
||||||
final String packageName = request.appInfo.packageName;
|
final String packageName = request.appInfo.packageName;
|
||||||
if (DEBUG) Log.d(TAG, "processOneBackup doBackup(" + doInit + ") on " + packageName);
|
if (DEBUG) Log.d(TAG, "processOneBackup doBackup() on " + packageName);
|
||||||
|
|
||||||
File savedStateName = new File(mStateDir, packageName);
|
File savedStateName = new File(mStateDir, packageName);
|
||||||
File backupDataName = new File(mDataDir, packageName + ".data");
|
File backupDataName = new File(mDataDir, packageName + ".data");
|
||||||
@@ -1073,26 +1078,23 @@ class BackupManagerService extends IBackupManager.Stub {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Now propagate the newly-backed-up data to the transport
|
// Now propagate the newly-backed-up data to the transport
|
||||||
|
int result = BackupConstants.TRANSPORT_OK;
|
||||||
try {
|
try {
|
||||||
int size = (int) backupDataName.length();
|
int size = (int) backupDataName.length();
|
||||||
if (size > 0) {
|
if (size > 0) {
|
||||||
backupData = ParcelFileDescriptor.open(backupDataName,
|
if (result == BackupConstants.TRANSPORT_OK) {
|
||||||
ParcelFileDescriptor.MODE_READ_ONLY);
|
backupData = ParcelFileDescriptor.open(backupDataName,
|
||||||
|
ParcelFileDescriptor.MODE_READ_ONLY);
|
||||||
|
result = transport.performBackup(packInfo, backupData);
|
||||||
|
}
|
||||||
|
|
||||||
// TODO - We call finishBackup() for each application backed up, because
|
// TODO - We call finishBackup() for each application backed up, because
|
||||||
// we need to know now whether it succeeded or failed. Instead, we should
|
// we need to know now whether it succeeded or failed. Instead, we should
|
||||||
// hold off on finishBackup() until the end, which implies holding off on
|
// hold off on finishBackup() until the end, which implies holding off on
|
||||||
// renaming *all* the output state files (see below) until that happens.
|
// renaming *all* the output state files (see below) until that happens.
|
||||||
|
|
||||||
int performOkay = transport.performBackup(packInfo, backupData, doInit);
|
if (result == BackupConstants.TRANSPORT_OK) {
|
||||||
if (performOkay == BackupConstants.TRANSPORT_NOT_INITIALIZED) {
|
result = transport.finishBackup();
|
||||||
Log.i(TAG, "Backend not initialized");
|
|
||||||
return performOkay;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((performOkay != 0) ||
|
|
||||||
!transport.finishBackup()) {
|
|
||||||
throw new Exception("Backup transport failed");
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (DEBUG) Log.i(TAG, "no backup data written; not calling transport");
|
if (DEBUG) Log.i(TAG, "no backup data written; not calling transport");
|
||||||
@@ -1101,18 +1103,22 @@ class BackupManagerService extends IBackupManager.Stub {
|
|||||||
// After successful transport, delete the now-stale data
|
// After successful transport, delete the now-stale data
|
||||||
// and juggle the files so that next time we supply the agent
|
// and juggle the files so that next time we supply the agent
|
||||||
// with the new state file it just created.
|
// with the new state file it just created.
|
||||||
backupDataName.delete();
|
if (result == BackupConstants.TRANSPORT_OK) {
|
||||||
newStateName.renameTo(savedStateName);
|
backupDataName.delete();
|
||||||
EventLog.writeEvent(BACKUP_PACKAGE_EVENT, packageName, size);
|
newStateName.renameTo(savedStateName);
|
||||||
|
EventLog.writeEvent(BACKUP_PACKAGE_EVENT, packageName, size);
|
||||||
|
} else {
|
||||||
|
EventLog.writeEvent(BACKUP_TRANSPORT_FAILURE_EVENT, packageName);
|
||||||
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
Log.e(TAG, "Transport error backing up " + packageName, e);
|
Log.e(TAG, "Transport error backing up " + packageName, e);
|
||||||
EventLog.writeEvent(BACKUP_TRANSPORT_FAILURE_EVENT, packageName);
|
EventLog.writeEvent(BACKUP_TRANSPORT_FAILURE_EVENT, packageName);
|
||||||
return BackupConstants.TRANSPORT_ERROR;
|
result = BackupConstants.TRANSPORT_ERROR;
|
||||||
} finally {
|
} finally {
|
||||||
try { if (backupData != null) backupData.close(); } catch (IOException e) {}
|
try { if (backupData != null) backupData.close(); } catch (IOException e) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
return BackupConstants.TRANSPORT_OK;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1237,7 +1243,8 @@ class BackupManagerService extends IBackupManager.Stub {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!mTransport.startRestore(mToken, restorePackages.toArray(new PackageInfo[0]))) {
|
if (mTransport.startRestore(mToken, restorePackages.toArray(new PackageInfo[0])) !=
|
||||||
|
BackupConstants.TRANSPORT_OK) {
|
||||||
Log.e(TAG, "Error starting restore operation");
|
Log.e(TAG, "Error starting restore operation");
|
||||||
EventLog.writeEvent(RESTORE_TRANSPORT_FAILURE_EVENT);
|
EventLog.writeEvent(RESTORE_TRANSPORT_FAILURE_EVENT);
|
||||||
return;
|
return;
|
||||||
@@ -1437,7 +1444,7 @@ class BackupManagerService extends IBackupManager.Stub {
|
|||||||
ParcelFileDescriptor.MODE_CREATE |
|
ParcelFileDescriptor.MODE_CREATE |
|
||||||
ParcelFileDescriptor.MODE_TRUNCATE);
|
ParcelFileDescriptor.MODE_TRUNCATE);
|
||||||
|
|
||||||
if (!mTransport.getRestoreData(backupData)) {
|
if (mTransport.getRestoreData(backupData) != BackupConstants.TRANSPORT_OK) {
|
||||||
Log.e(TAG, "Error getting restore data for " + packageName);
|
Log.e(TAG, "Error getting restore data for " + packageName);
|
||||||
EventLog.writeEvent(RESTORE_TRANSPORT_FAILURE_EVENT);
|
EventLog.writeEvent(RESTORE_TRANSPORT_FAILURE_EVENT);
|
||||||
return;
|
return;
|
||||||
|
|||||||
Reference in New Issue
Block a user