diff options
author | Christopher Tate <ctate@google.com> | 2015-03-24 18:48:10 -0700 |
---|---|---|
committer | Christopher Tate <ctate@google.com> | 2015-03-26 18:57:36 -0700 |
commit | 11ae768cf1b8348e761ad9c09e98788da1e591b1 (patch) | |
tree | fa4a4e9fffc83e61af98476d41df4252e3cd1323 /libs/androidfw | |
parent | e7f931c4505a6bd62e01bef5193dd724571a672b (diff) | |
download | frameworks_base-11ae768cf1b8348e761ad9c09e98788da1e591b1.zip frameworks_base-11ae768cf1b8348e761ad9c09e98788da1e591b1.tar.gz frameworks_base-11ae768cf1b8348e761ad9c09e98788da1e591b1.tar.bz2 |
Add payload-size preflight stage to full transport backup
We now peform a total-size preflight pass before committing data to the
wire. This is to eliminate the large superfluous network traffic that
would otherwise happen if the transport enforces internal quotas: we
now instead ask the transport up front whether it's prepared to accept
a given payload size for the package.
From the app's perspective this preflight operation is indistinguishable
from a full-data backup pass. If the app has provided its own full-data
handling in a subclassed backup agent, their usual file-providing code
path will be executed. However, the files named for backup during this
pass are not opened and read; just measured for their total size. As
far as component lifecycles, this measurement pass is simply another
call to the agent, immediately after it is bound, with identical
timeout semantics to the existing full-data backup invocation.
Once the app's file set has been measured the preflight operation
invokes a new method on BackupTransport, called checkFullBackupSize().
This method is called after performFullBackup() (which applies any
overall whitelist/blacklist policy) but before any data is delivered
to the transport via sendBackupData(). The return code from
checkFullBackupSize() is similar to the other transport methods:
TRANSPORT_OK to permit the full backup to proceed; or
TRANSPORT_REJECT_PACKAGE to indicate that the requested payload is
unacceptable; or TRANSPORT_ERROR to report a more serious overall
transport-level problem that prevents a full-data backup operation
from occurring right now.
The estimated payload currently does not include the size of the
source-package metadata (technically, the manifest entry in its
archive payload) or the size of any widget metadata associated with
the package's install. In practice this means the preflighted size
underestimates by 3 to 5 KB. In addition, the preflight API currently
cannot distinguish between payload sizes larger than 2 gigabytes;
any payload estimate larger than that is passed as Integer.MAX_VALUE
to the checkFullBackupSize() query.
Bug 19846750
Change-Id: I44498201e2d4b07482dcb3ca8fa6935dddc467ca
Diffstat (limited to 'libs/androidfw')
-rw-r--r-- | libs/androidfw/BackupHelpers.cpp | 21 |
1 files changed, 16 insertions, 5 deletions
diff --git a/libs/androidfw/BackupHelpers.cpp b/libs/androidfw/BackupHelpers.cpp index 227de3b..9300794 100644 --- a/libs/androidfw/BackupHelpers.cpp +++ b/libs/androidfw/BackupHelpers.cpp @@ -478,7 +478,8 @@ void send_tarfile_chunk(BackupDataWriter* writer, const char* buffer, size_t siz } int write_tarfile(const String8& packageName, const String8& domain, - const String8& rootpath, const String8& filepath, BackupDataWriter* writer) + const String8& rootpath, const String8& filepath, off_t* outSize, + BackupDataWriter* writer) { // In the output stream everything is stored relative to the root const char* relstart = filepath.string() + rootpath.length(); @@ -488,6 +489,7 @@ int write_tarfile(const String8& packageName, const String8& domain, // If relpath is empty, it means this is the top of one of the standard named // domain directories, so we should just skip it if (relpath.length() == 0) { + *outSize = 0; return 0; } @@ -517,12 +519,25 @@ int write_tarfile(const String8& packageName, const String8& domain, return err; } + // very large files need a pax extended size header + if (s.st_size > 077777777777LL) { + needExtended = true; + } + String8 fullname; // for pax later on String8 prefix; const int isdir = S_ISDIR(s.st_mode); if (isdir) s.st_size = 0; // directories get no actual data in the tar stream + // Report the size, including a rough tar overhead estimation: 512 bytes for the + // overall tar file-block header, plus 2 blocks if using the pax extended format, + // plus the raw content size rounded up to a multiple of 512. + *outSize = 512 + (needExtended ? 1024 : 0) + 512*((s.st_size + 511)/512); + + // Measure case: we've returned the size; now return without moving data + if (!writer) return 0; + // !!! TODO: use mmap when possible to avoid churning the buffer cache // !!! TODO: this will break with symlinks; need to use readlink(2) int fd = open(filepath.string(), O_RDONLY); @@ -560,10 +575,6 @@ int write_tarfile(const String8& packageName, const String8& domain, snprintf(buf + 116, 8, "0%lo", (unsigned long)s.st_gid); // [ 124 : 12 ] file size in bytes - if (s.st_size > 077777777777LL) { - // very large files need a pax extended size header - needExtended = true; - } snprintf(buf + 124, 12, "%011llo", (isdir) ? 0LL : s.st_size); // [ 136 : 12 ] last mod time as a UTC time_t |