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
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 @@
 }
 
 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 @@
     // 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 @@
         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 @@
     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