gsid: suggestScratchSize() respect kMinimumFreeSpaceThreshold

gsid should take kMinimumFreeSpaceThreshold into account when
calculating the suggested scratch partition size.
Also use uint64_t to store any calculated intermediate result, so we can
stay confortable from overflowing, and downcast the result to int64_t
in the end, after we clamped the value within int64_t range.

Bug: 165925766
Bug: 179980369
Test: Install DSU and verify adb remount works
Change-Id: I919c723369d7d788c5c83a19e6b87f077fb2521b
diff --git a/gsi_service.cpp b/gsi_service.cpp
index cc6497a..66e01ee 100644
--- a/gsi_service.cpp
+++ b/gsi_service.cpp
@@ -510,20 +510,24 @@
 binder::Status GsiService::suggestScratchSize(int64_t* _aidl_return) {
     ENFORCE_SYSTEM;
 
-    static constexpr int64_t kMinScratchSize = 512_MiB;
-    static constexpr int64_t kMaxScratchSize = 2_GiB;
+    static constexpr uint64_t kMinScratchSize = 512_MiB;
+    static constexpr uint64_t kMaxScratchSize = 2_GiB;
 
-    int64_t size = 0;
+    uint64_t size = 0;
     struct statvfs info;
     if (statvfs(install_dir_.c_str(), &info)) {
         PLOG(ERROR) << "Could not statvfs(" << install_dir_ << ")";
     } else {
-        const int64_t available_space = static_cast<int64_t>(info.f_bavail) * info.f_frsize;
-        LOG(INFO) << "Available space of " << install_dir_ << ": " << available_space;
-        // Use up to half of free space. Don't exhaust the storage device with scratch partition.
-        size = available_space / 2;
+        // Keep the storage device at least 40% free, plus 1% for jitter.
+        constexpr int jitter = 1;
+        const uint64_t reserved_blocks =
+                static_cast<uint64_t>(info.f_blocks) * (kMinimumFreeSpaceThreshold + jitter) / 100;
+        if (info.f_bavail > reserved_blocks) {
+            size = (info.f_bavail - reserved_blocks) * info.f_frsize;
+        }
     }
 
+    // We can safely downcast the result here, since we clamped the result within int64_t range.
     *_aidl_return = std::clamp(size, kMinScratchSize, kMaxScratchSize);
     return binder::Status::ok();
 }