summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Christopher Tate <ctate@google.com> 2015-04-10 11:17:14 -0700
committer Chris Tate <ctate@android.com> 2015-04-13 22:13:23 +0000
commit9310e4285b3fc951c3524d040726d1161015562c (patch)
tree06d37db6c0192387593739c721a5c52fa2b82a0d
parent2f77da07812f01b8e1070fb71cc8ae35ca036349 (diff)
Avoid zero-payload backups in local transport
The local debugging transport now implements BackupTransport.checkFullBackupSize() to detect and reject backup attempts for which no actual file content will be committed. The documentation for checkFullBackupSize() has also been expanded to document the transport's responsibilities in this regard. The local transport now lazy-creates the destination file when data is first delivered for an approved backup operation, rather than doing it proactively in performBackup(), to ensure that changes in the datastore are only attempted after the transport has positive confirmation that data is indeed flowing. Change-Id: I6e47a7e72cd938fc0ed31da4bc490540c71f9e65
-rw-r--r--core/java/android/app/backup/BackupTransport.java7
-rw-r--r--core/java/com/android/internal/backup/LocalTransport.java53
2 files changed, 43 insertions, 17 deletions
diff --git a/core/java/android/app/backup/BackupTransport.java b/core/java/android/app/backup/BackupTransport.java
index 1131ff9faeda..9540eb136c4c 100644
--- a/core/java/android/app/backup/BackupTransport.java
+++ b/core/java/android/app/backup/BackupTransport.java
@@ -399,6 +399,13 @@ public class BackupTransport {
* operation will be skipped (and {@link #finishBackup() invoked} with no data for that
* package being passed to {@link #sendBackupData}.
*
+ * <p class="note">The platform does no size-based rejection of full backup attempts on
+ * its own: it is always the responsibility of the transport to implement its own policy.
+ * In particular, even if the preflighted payload size is zero, the platform will still call
+ * this method and will proceed to back up an archive metadata header with no file content
+ * if this method returns TRANSPORT_OK. To avoid storing such payloads the transport
+ * must recognize this case and return TRANSPORT_PACKAGE_REJECTED.
+ *
* Added in MNC (API 23).
*
* @param size The estimated size of the full-data payload for this app. This includes
diff --git a/core/java/com/android/internal/backup/LocalTransport.java b/core/java/com/android/internal/backup/LocalTransport.java
index e32a3a28bade..22d35f204de8 100644
--- a/core/java/com/android/internal/backup/LocalTransport.java
+++ b/core/java/com/android/internal/backup/LocalTransport.java
@@ -45,8 +45,7 @@ import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
-import java.util.HashSet;
-import static android.system.OsConstants.*;
+import static android.system.OsConstants.SEEK_CUR;
/**
* Backup transport for stashing stuff into a known location on disk, and
@@ -284,8 +283,10 @@ public class LocalTransport extends BackupTransport {
private int tearDownFullBackup() {
if (mSocket != null) {
try {
- mFullBackupOutputStream.flush();
- mFullBackupOutputStream.close();
+ if (mFullBackupOutputStream != null) {
+ mFullBackupOutputStream.flush();
+ mFullBackupOutputStream.close();
+ }
mSocketInputStream = null;
mFullTargetPackage = null;
mSocket.close();
@@ -296,6 +297,7 @@ public class LocalTransport extends BackupTransport {
return TRANSPORT_ERROR;
} finally {
mSocket = null;
+ mFullBackupOutputStream = null;
}
}
return TRANSPORT_OK;
@@ -311,6 +313,18 @@ public class LocalTransport extends BackupTransport {
}
@Override
+ public int checkFullBackupSize(long size) {
+ // Decline zero-size "backups"
+ final int result = (size > 0) ? TRANSPORT_OK : TRANSPORT_PACKAGE_REJECTED;
+ if (result != TRANSPORT_OK) {
+ if (DEBUG) {
+ Log.v(TAG, "Declining backup of size " + size);
+ }
+ }
+ return result;
+ }
+
+ @Override
public int performFullBackup(PackageInfo targetPackage, ParcelFileDescriptor socket) {
if (mSocket != null) {
Log.e(TAG, "Attempt to initiate full backup while one is in progress");
@@ -333,22 +347,14 @@ public class LocalTransport extends BackupTransport {
}
mFullTargetPackage = targetPackage.packageName;
- FileOutputStream tarstream;
- try {
- File tarball = tarballFile(mFullTargetPackage);
- tarstream = new FileOutputStream(tarball);
- } catch (FileNotFoundException e) {
- return TRANSPORT_ERROR;
- }
- mFullBackupOutputStream = new BufferedOutputStream(tarstream);
mFullBackupBuffer = new byte[4096];
return TRANSPORT_OK;
}
@Override
- public int sendBackupData(int numBytes) {
- if (mFullBackupBuffer == null) {
+ public int sendBackupData(final int numBytes) {
+ if (mSocket == null) {
Log.w(TAG, "Attempted sendBackupData before performFullBackup");
return TRANSPORT_ERROR;
}
@@ -356,16 +362,29 @@ public class LocalTransport extends BackupTransport {
if (numBytes > mFullBackupBuffer.length) {
mFullBackupBuffer = new byte[numBytes];
}
- while (numBytes > 0) {
+
+ if (mFullBackupOutputStream == null) {
+ FileOutputStream tarstream;
+ try {
+ File tarball = tarballFile(mFullTargetPackage);
+ tarstream = new FileOutputStream(tarball);
+ } catch (FileNotFoundException e) {
+ return TRANSPORT_ERROR;
+ }
+ mFullBackupOutputStream = new BufferedOutputStream(tarstream);
+ }
+
+ int bytesLeft = numBytes;
+ while (bytesLeft > 0) {
try {
- int nRead = mSocketInputStream.read(mFullBackupBuffer, 0, numBytes);
+ int nRead = mSocketInputStream.read(mFullBackupBuffer, 0, bytesLeft);
if (nRead < 0) {
// Something went wrong if we expect data but saw EOD
Log.w(TAG, "Unexpected EOD; failing backup");
return TRANSPORT_ERROR;
}
mFullBackupOutputStream.write(mFullBackupBuffer, 0, nRead);
- numBytes -= nRead;
+ bytesLeft -= nRead;
} catch (IOException e) {
Log.e(TAG, "Error handling backup data for " + mFullTargetPackage);
return TRANSPORT_ERROR;