Wait for APK to be fully downloaded for full APK digests.

Bug: 160605420
Test: atest ChecksumsTest
Change-Id: Ib9fd591c67290786268b6dcdc57c7db153612e01
diff --git a/services/incremental/BinderIncrementalService.cpp b/services/incremental/BinderIncrementalService.cpp
index 41945a2..87ae4d7 100644
--- a/services/incremental/BinderIncrementalService.cpp
+++ b/services/incremental/BinderIncrementalService.cpp
@@ -237,6 +237,13 @@
     return ok();
 }
 
+binder::Status BinderIncrementalService::isFileFullyLoaded(int32_t storageId,
+                                                           const std::string& path,
+                                                           int32_t* _aidl_return) {
+    *_aidl_return = mImpl.isFileFullyLoaded(storageId, path);
+    return ok();
+}
+
 binder::Status BinderIncrementalService::getLoadingProgress(int32_t storageId,
                                                             float* _aidl_return) {
     *_aidl_return = mImpl.getLoadingProgress(storageId);
diff --git a/services/incremental/BinderIncrementalService.h b/services/incremental/BinderIncrementalService.h
index 8b40350..8478142 100644
--- a/services/incremental/BinderIncrementalService.h
+++ b/services/incremental/BinderIncrementalService.h
@@ -66,6 +66,8 @@
                             int32_t destStorageId, const std::string& destPath,
                             int32_t* _aidl_return) final;
     binder::Status unlink(int32_t storageId, const std::string& path, int32_t* _aidl_return) final;
+    binder::Status isFileFullyLoaded(int32_t storageId, const std::string& path,
+                                     int32_t* _aidl_return) final;
     binder::Status getLoadingProgress(int32_t storageId, float* _aidl_return) final;
     binder::Status getMetadataByPath(int32_t storageId, const std::string& path,
                                      std::vector<uint8_t>* _aidl_return) final;
diff --git a/services/incremental/IncrementalService.cpp b/services/incremental/IncrementalService.cpp
index 9836262e..447ee55 100644
--- a/services/incremental/IncrementalService.cpp
+++ b/services/incremental/IncrementalService.cpp
@@ -1603,7 +1603,8 @@
 
     const auto writeFd = mIncFs->openForSpecialOps(ifs->control, libFileId);
     if (!writeFd.ok()) {
-        LOG(ERROR) << "Failed to open write fd for: " << targetLibPath << " errno: " << writeFd;
+        LOG(ERROR) << "Failed to open write fd for: " << targetLibPath
+                   << " errno: " << writeFd.get();
         return;
     }
 
@@ -1673,6 +1674,37 @@
     return mRunning;
 }
 
+int IncrementalService::isFileFullyLoaded(StorageId storage, const std::string& path) const {
+    std::unique_lock l(mLock);
+    const auto ifs = getIfsLocked(storage);
+    if (!ifs) {
+        LOG(ERROR) << "isFileFullyLoaded failed, invalid storageId: " << storage;
+        return -EINVAL;
+    }
+    const auto storageInfo = ifs->storages.find(storage);
+    if (storageInfo == ifs->storages.end()) {
+        LOG(ERROR) << "isFileFullyLoaded failed, no storage: " << storage;
+        return -EINVAL;
+    }
+    l.unlock();
+    return isFileFullyLoadedFromPath(*ifs, path);
+}
+
+int IncrementalService::isFileFullyLoadedFromPath(const IncFsMount& ifs,
+                                                  std::string_view filePath) const {
+    const auto [filledBlocks, totalBlocks] = mIncFs->countFilledBlocks(ifs.control, filePath);
+    if (filledBlocks < 0) {
+        LOG(ERROR) << "isFileFullyLoadedFromPath failed to get filled blocks count for: "
+                   << filePath << " errno: " << filledBlocks;
+        return filledBlocks;
+    }
+    if (totalBlocks < filledBlocks) {
+        LOG(ERROR) << "isFileFullyLoadedFromPath failed to get total num of blocks";
+        return -EINVAL;
+    }
+    return totalBlocks - filledBlocks;
+}
+
 float IncrementalService::getLoadingProgress(StorageId storage) const {
     std::unique_lock l(mLock);
     const auto ifs = getIfsLocked(storage);
diff --git a/services/incremental/IncrementalService.h b/services/incremental/IncrementalService.h
index cd6bfed..267458d 100644
--- a/services/incremental/IncrementalService.h
+++ b/services/incremental/IncrementalService.h
@@ -132,6 +132,7 @@
              std::string_view newPath);
     int unlink(StorageId storage, std::string_view path);
 
+    int isFileFullyLoaded(StorageId storage, const std::string& path) const;
     float getLoadingProgress(StorageId storage) const;
 
     RawMetadata getMetadata(StorageId storage, std::string_view path) const;
@@ -339,6 +340,7 @@
     int makeDirs(const IncFsMount& ifs, StorageId storageId, std::string_view path, int mode);
     binder::Status applyStorageParams(IncFsMount& ifs, bool enableReadLogs);
 
+    int isFileFullyLoadedFromPath(const IncFsMount& ifs, std::string_view filePath) const;
     float getLoadingProgressFromPath(const IncFsMount& ifs, std::string_view path) const;
 
     void registerAppOpsCallback(const std::string& packageName);
diff --git a/services/incremental/ServiceWrappers.cpp b/services/incremental/ServiceWrappers.cpp
index 1ed46c4..f6d89c5 100644
--- a/services/incremental/ServiceWrappers.cpp
+++ b/services/incremental/ServiceWrappers.cpp
@@ -195,8 +195,8 @@
     ErrorCode unlink(const Control& control, std::string_view path) const final {
         return incfs::unlink(control, path);
     }
-    base::unique_fd openForSpecialOps(const Control& control, FileId id) const final {
-        return base::unique_fd{incfs::openForSpecialOps(control, id).release()};
+    incfs::UniqueFd openForSpecialOps(const Control& control, FileId id) const final {
+        return incfs::openForSpecialOps(control, id);
     }
     ErrorCode writeBlocks(std::span<const incfs::DataBlock> blocks) const final {
         return incfs::writeBlocks({blocks.data(), size_t(blocks.size())});
diff --git a/services/incremental/ServiceWrappers.h b/services/incremental/ServiceWrappers.h
index 82a1704..6376d86 100644
--- a/services/incremental/ServiceWrappers.h
+++ b/services/incremental/ServiceWrappers.h
@@ -74,6 +74,7 @@
     using Control = incfs::Control;
     using FileId = incfs::FileId;
     using ErrorCode = incfs::ErrorCode;
+    using UniqueFd = incfs::UniqueFd;
     using WaitResult = incfs::WaitResult;
 
     using ExistingMountCallback =
@@ -96,7 +97,7 @@
     virtual ErrorCode link(const Control& control, std::string_view from,
                            std::string_view to) const = 0;
     virtual ErrorCode unlink(const Control& control, std::string_view path) const = 0;
-    virtual base::unique_fd openForSpecialOps(const Control& control, FileId id) const = 0;
+    virtual UniqueFd openForSpecialOps(const Control& control, FileId id) const = 0;
     virtual ErrorCode writeBlocks(std::span<const incfs::DataBlock> blocks) const = 0;
     virtual WaitResult waitForPendingReads(
             const Control& control, std::chrono::milliseconds timeout,
diff --git a/services/incremental/test/IncrementalServiceTest.cpp b/services/incremental/test/IncrementalServiceTest.cpp
index d1000e56..a290a17 100644
--- a/services/incremental/test/IncrementalServiceTest.cpp
+++ b/services/incremental/test/IncrementalServiceTest.cpp
@@ -289,7 +289,7 @@
                        ErrorCode(const Control& control, std::string_view from,
                                  std::string_view to));
     MOCK_CONST_METHOD2(unlink, ErrorCode(const Control& control, std::string_view path));
-    MOCK_CONST_METHOD2(openForSpecialOps, base::unique_fd(const Control& control, FileId id));
+    MOCK_CONST_METHOD2(openForSpecialOps, UniqueFd(const Control& control, FileId id));
     MOCK_CONST_METHOD1(writeBlocks, ErrorCode(std::span<const DataBlock> blocks));
     MOCK_CONST_METHOD3(waitForPendingReads,
                        WaitResult(const Control& control, std::chrono::milliseconds timeout,
@@ -304,6 +304,10 @@
         ON_CALL(*this, countFilledBlocks(_, _)).WillByDefault(Return(std::make_pair(1, 2)));
     }
 
+    void countFilledBlocksFullyLoaded() {
+        ON_CALL(*this, countFilledBlocks(_, _)).WillByDefault(Return(std::make_pair(10000, 10000)));
+    }
+
     void countFilledBlocksFails() {
         ON_CALL(*this, countFilledBlocks(_, _)).WillByDefault(Return(std::make_pair(-1, -1)));
     }
@@ -1069,6 +1073,53 @@
     ASSERT_EQ(res, 0);
 }
 
+TEST_F(IncrementalServiceTest, testIsFileFullyLoadedFailsWithNoFile) {
+    mIncFs->countFilledBlocksFails();
+    mFs->hasNoFile();
+
+    TemporaryDir tempDir;
+    int storageId = mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel),
+                                                       IncrementalService::CreateOptions::CreateNew,
+                                                       {}, {}, {});
+    ASSERT_EQ(-1, mIncrementalService->isFileFullyLoaded(storageId, "base.apk"));
+}
+
+TEST_F(IncrementalServiceTest, testIsFileFullyLoadedFailsWithFailedRanges) {
+    mIncFs->countFilledBlocksFails();
+    mFs->hasFiles();
+
+    TemporaryDir tempDir;
+    int storageId = mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel),
+                                                       IncrementalService::CreateOptions::CreateNew,
+                                                       {}, {}, {});
+    EXPECT_CALL(*mIncFs, countFilledBlocks(_, _)).Times(1);
+    ASSERT_EQ(-1, mIncrementalService->isFileFullyLoaded(storageId, "base.apk"));
+}
+
+TEST_F(IncrementalServiceTest, testIsFileFullyLoadedSuccessWithEmptyRanges) {
+    mIncFs->countFilledBlocksEmpty();
+    mFs->hasFiles();
+
+    TemporaryDir tempDir;
+    int storageId = mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel),
+                                                       IncrementalService::CreateOptions::CreateNew,
+                                                       {}, {}, {});
+    EXPECT_CALL(*mIncFs, countFilledBlocks(_, _)).Times(1);
+    ASSERT_EQ(0, mIncrementalService->isFileFullyLoaded(storageId, "base.apk"));
+}
+
+TEST_F(IncrementalServiceTest, testIsFileFullyLoadedSuccess) {
+    mIncFs->countFilledBlocksFullyLoaded();
+    mFs->hasFiles();
+
+    TemporaryDir tempDir;
+    int storageId = mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel),
+                                                       IncrementalService::CreateOptions::CreateNew,
+                                                       {}, {}, {});
+    EXPECT_CALL(*mIncFs, countFilledBlocks(_, _)).Times(1);
+    ASSERT_EQ(0, mIncrementalService->isFileFullyLoaded(storageId, "base.apk"));
+}
+
 TEST_F(IncrementalServiceTest, testGetLoadingProgressSuccessWithNoFile) {
     mIncFs->countFilledBlocksSuccess();
     mFs->hasNoFile();