fastboot: Handle libsparse failures better.

sparse_file_len is not actually infallible; on Windows it's pretty easy
to make it fail by embedding large files in the stream. fastboot didn't
handle this anywhere, leading to bad sparse images when libsparse
runs out of address space.

Bug: 273933042
Bug: 268872725
Test: fastboot flashall on Windows
Change-Id: Ie68aed2f1970e820350d9f97aa89a6c0242229b8
diff --git a/fastboot/task.cpp b/fastboot/task.cpp
index c70139b..b21558c 100644
--- a/fastboot/task.cpp
+++ b/fastboot/task.cpp
@@ -19,6 +19,8 @@
 #include "filesystem.h"
 #include "super_flash_helper.h"
 
+#include <android-base/parseint.h>
+
 using namespace std::string_literals;
 
 FlashTask::FlashTask(const std::string& slot, const std::string& pname)
@@ -70,14 +72,18 @@
 
 FlashSuperLayoutTask::FlashSuperLayoutTask(const std::string& super_name,
                                            std::unique_ptr<SuperFlashHelper> helper,
-                                           SparsePtr sparse_layout)
+                                           SparsePtr sparse_layout, uint64_t super_size)
     : super_name_(super_name),
       helper_(std::move(helper)),
-      sparse_layout_(std::move(sparse_layout)) {}
+      sparse_layout_(std::move(sparse_layout)),
+      super_size_(super_size) {}
 
 void FlashSuperLayoutTask::Run() {
+    // Use the reported super partition size as the upper limit, rather than
+    // sparse_file_len, which (1) can fail and (2) is kind of expensive, since
+    // it will map in all of the embedded fds.
     std::vector<SparsePtr> files;
-    if (int limit = get_sparse_limit(sparse_file_len(sparse_layout_.get(), false, false))) {
+    if (int limit = get_sparse_limit(super_size_)) {
         files = resparse_file(sparse_layout_.get(), limit);
     } else {
         files.emplace_back(std::move(sparse_layout_));
@@ -111,12 +117,19 @@
     if (fp->fb->GetVar("super-partition-name", &super_name) != fastboot::SUCCESS) {
         super_name = "super";
     }
-    std::string partition_size_str;
 
+    uint64_t partition_size;
+    std::string partition_size_str;
     if (fp->fb->GetVar("partition-size:" + super_name, &partition_size_str) != fastboot::SUCCESS) {
         LOG(VERBOSE) << "Cannot optimize super flashing: could not determine super partition";
         return nullptr;
     }
+    partition_size_str = fb_fix_numeric_var(partition_size_str);
+    if (!android::base::ParseUint(partition_size_str, &partition_size)) {
+        LOG(VERBOSE) << "Could not parse " << super_name << " size: " << partition_size_str;
+        return nullptr;
+    }
+
     std::unique_ptr<SuperFlashHelper> helper = std::make_unique<SuperFlashHelper>(*fp->source);
     if (!helper->Open(fd)) {
         return nullptr;
@@ -140,7 +153,8 @@
     };
     os_images.erase(std::remove_if(os_images.begin(), os_images.end(), remove_if_callback),
                     os_images.end());
-    return std::make_unique<FlashSuperLayoutTask>(super_name, std::move(helper), std::move(s));
+    return std::make_unique<FlashSuperLayoutTask>(super_name, std::move(helper), std::move(s),
+                                                  partition_size);
 }
 
 UpdateSuperTask::UpdateSuperTask(FlashingPlan* fp) : fp_(fp) {}