diff options
author | 2015-04-10 11:17:14 -0700 | |
---|---|---|
committer | 2015-04-13 22:13:23 +0000 | |
commit | 9310e4285b3fc951c3524d040726d1161015562c (patch) | |
tree | 06d37db6c0192387593739c721a5c52fa2b82a0d | |
parent | 2f77da07812f01b8e1070fb71cc8ae35ca036349 (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.java | 7 | ||||
-rw-r--r-- | core/java/com/android/internal/backup/LocalTransport.java | 53 |
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; |