Merge "Remove AOSP-first commit hook." into main
diff --git a/Checkpoint.cpp b/Checkpoint.cpp
index 27d99e7..195a137 100644
--- a/Checkpoint.cpp
+++ b/Checkpoint.cpp
@@ -136,13 +136,16 @@
         return error(ENOTSUP, "Checkpoints not supported");
 
     if (retry < -1) return error(EINVAL, "Retry count must be more than -1");
-    std::string content = std::to_string(retry + 1);
+    std::string content;
     if (retry == -1) {
+        content = std::to_string(-1);
         auto module = BootControlClient::WaitForService();
         if (module) {
             std::string suffix = module->GetSuffix(module->GetCurrentSlot());
             if (!suffix.empty()) content += " " + suffix;
         }
+    } else {
+        content = std::to_string(retry + 1);
     }
     if (!android::base::WriteStringToFile(content, kMetadataCPFile))
         return error("Failed to write checkpoint file");
@@ -307,21 +310,21 @@
     std::string content;
     auto module = BootControlClient::WaitForService();
 
-    if (isCheckpointing) return isCheckpointing;
+    if (isCheckpointing) return true;
+
     // In case of INVALID slot or other failures, we do not perform checkpoint.
     if (module && !module->IsSlotMarkedSuccessful(module->GetCurrentSlot()).value_or(true)) {
         isCheckpointing = true;
         return true;
     }
     ret = android::base::ReadFileToString(kMetadataCPFile, &content);
-    if (ret) {
-        ret = content != "0";
-        isCheckpointing = ret;
-        if (!isCheckpointing) {
-            notifyCheckpointListeners();
-        }
-        return ret;
+    if (ret && content != "0") {
+        isCheckpointing = true;
+        return true;
     }
+
+    // Leave isCheckpointing false and notify listeners now that we know we don't need one
+    notifyCheckpointListeners();
     return false;
 }
 
diff --git a/OWNERS b/OWNERS
index 6d8d89f..81da329 100644
--- a/OWNERS
+++ b/OWNERS
@@ -1,4 +1,3 @@
-alanstokes@google.com
 drosen@google.com
 ebiggers@google.com
 jeffv@google.com
diff --git a/TEST_MAPPING b/TEST_MAPPING
index 93938b6..50bd3da 100644
--- a/TEST_MAPPING
+++ b/TEST_MAPPING
@@ -17,9 +17,6 @@
     },
     {
       "name": "CtsScopedStorageRedactUriTest"
-    },
-    {
-      "name": "AdoptableHostTest"
     }
   ],
   "hwasan-postsubmit": [
@@ -40,9 +37,6 @@
     },
     {
       "name": "CtsScopedStorageRedactUriTest"
-    },
-    {
-      "name": "AdoptableHostTest"
     }
   ]
 }
diff --git a/VolumeManager.cpp b/VolumeManager.cpp
index d932ec8..657f051 100644
--- a/VolumeManager.cpp
+++ b/VolumeManager.cpp
@@ -1247,7 +1247,8 @@
     return android::vold::OpenAppFuseFile(uid, mountId, fileId, flags);
 }
 
-static android::status_t getDeviceSize(std::string& device, int64_t* storageSize) {
+static android::status_t getDeviceSize(std::string& device, int64_t* storageSize,
+                                       bool isF2fsPrimary) {
     // Follow any symbolic links
     std::string dataDevice;
     if (!android::base::Realpath(device, &dataDevice)) {
@@ -1256,14 +1257,35 @@
 
     // Handle mapped volumes.
     auto& dm = android::dm::DeviceMapper::Instance();
-    for (;;) {
-        auto parent = dm.GetParentBlockDeviceByPath(dataDevice);
-        if (!parent.has_value()) break;
-        dataDevice = *parent;
+    std::string dmPath = dataDevice;
+    if (dm.IsDmBlockDevice(dataDevice)) {
+        for (;;) {
+            auto parent = dm.GetParentBlockDeviceByPath(dataDevice);
+            if (!parent.has_value()) break;
+            dataDevice = *parent;
+        }
+    } else if (isF2fsPrimary) {
+        if (!dm.GetDmDevicePathByName(android::base::Basename(device), &dmPath)) {
+            LOG(WARNING) << "No proper dm device for " << device;
+            isF2fsPrimary = false;
+        }
+    }
+
+    // Find a device name for F2FS primary partition
+    std::string f2fsReservedBlocksSysfs;
+    std::size_t leaf;
+    if (isF2fsPrimary) {
+        leaf = dmPath.rfind('/');
+        if (leaf == std::string::npos) {
+            LOG(WARNING) << "dm device " << dmPath << " is not a path";
+            isF2fsPrimary = false;
+        }
+        f2fsReservedBlocksSysfs =
+                std::string() + "/sys/fs/f2fs/" + dmPath.substr(leaf + 1) + "/reserved_blocks";
     }
 
     // Get the potential /sys/block entry
-    std::size_t leaf = dataDevice.rfind('/');
+    leaf = dataDevice.rfind('/');
     if (leaf == std::string::npos) {
         LOG(ERROR) << "data device " << dataDevice << " is not a path";
         return EINVAL;
@@ -1293,14 +1315,32 @@
     }
 
     // Read the size file and be done
+    int64_t sizeNum;
     std::stringstream ssSize(size);
-    ssSize >> *storageSize;
+    ssSize >> sizeNum;
     if (ssSize.fail()) {
         LOG(ERROR) << sizeFile << " cannot be read as an integer";
         return EINVAL;
     }
 
-    *storageSize *= 512;
+    sizeNum *= 512;
+    if (isF2fsPrimary) {
+        int64_t reservedBlocksNum = 0;
+        if (!android::base::ReadFileToString(f2fsReservedBlocksSysfs, &size, true)) {
+            LOG(WARNING) << "Could not find valid entry from " << f2fsReservedBlocksSysfs;
+        } else {
+            std::stringstream reservedBlocks(size);
+            reservedBlocks >> reservedBlocksNum;
+            if (reservedBlocks.fail()) {
+                LOG(WARNING) << f2fsReservedBlocksSysfs << " cannot be read as an integer";
+                reservedBlocksNum = 0;
+            }
+        }
+        int64_t blockSize = android::base::GetIntProperty("ro.boot.hardware.cpu.pagesize", 0);
+        sizeNum -= reservedBlocksNum * blockSize;
+    }
+
+    *storageSize = sizeNum;
     return OK;
 }
 
@@ -1313,14 +1353,14 @@
         return EINVAL;
     }
 
-    status = getDeviceSize(entry->blk_device, storageSize);
+    status = getDeviceSize(entry->blk_device, storageSize, entry->fs_type == "f2fs");
     if (status != OK) {
         return status;
     }
 
     for (auto device : entry->user_devices) {
         int64_t deviceStorageSize;
-        status = getDeviceSize(device, &deviceStorageSize);
+        status = getDeviceSize(device, &deviceStorageSize, false);
         if (status != OK) {
             return status;
         }
diff --git a/tests/VoldFuzzer.cpp b/tests/VoldFuzzer.cpp
index b47a783..173c765 100644
--- a/tests/VoldFuzzer.cpp
+++ b/tests/VoldFuzzer.cpp
@@ -37,6 +37,8 @@
 }
 
 extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+    // TODO(b/183141167): need to rewrite 'dump' to avoid SIGPIPE.
+    signal(SIGPIPE, SIG_IGN);
     auto voldService = sp<android::vold::VoldNativeService>::make();
     auto voldVendorService = sp<android::vold::VendorVoldNativeService>::make();
     fuzzService({voldService, voldVendorService}, FuzzedDataProvider(data, size));