[IncrementalService] getLoadingProgress (v1)

This is to unblock Launcher's work on progress ring. Currently it uses
incfs getFilledBlocks(). Will switch to the new incfs progress reporting
API once it is ready.

Test: unit test
Test: adb shell dumpsys incremental
BUG: 165799231
Change-Id: Icd68124806454f888826294da36f109bca9771ac
diff --git a/services/incremental/test/IncrementalServiceTest.cpp b/services/incremental/test/IncrementalServiceTest.cpp
index 1ae9e25..44cef49 100644
--- a/services/incremental/test/IncrementalServiceTest.cpp
+++ b/services/incremental/test/IncrementalServiceTest.cpp
@@ -54,8 +54,10 @@
     MOCK_CONST_METHOD1(unmountIncFs, binder::Status(const std::string& dir));
     MOCK_CONST_METHOD2(bindMount,
                        binder::Status(const std::string& sourceDir, const std::string& argetDir));
-    MOCK_CONST_METHOD2(setIncFsMountOptions,
-                       binder::Status(const ::android::os::incremental::IncrementalFileSystemControlParcel&, bool));
+    MOCK_CONST_METHOD2(
+            setIncFsMountOptions,
+            binder::Status(const ::android::os::incremental::IncrementalFileSystemControlParcel&,
+                           bool));
 
     void mountIncFsFails() {
         ON_CALL(*this, mountIncFs(_, _, _, _))
@@ -80,8 +82,8 @@
     }
     void setIncFsMountOptionsFails() const {
         ON_CALL(*this, setIncFsMountOptions(_, _))
-                .WillByDefault(
-                        Return(binder::Status::fromExceptionCode(1, String8("failed to set options"))));
+                .WillByDefault(Return(
+                        binder::Status::fromExceptionCode(1, String8("failed to set options"))));
     }
     void setIncFsMountOptionsSuccess() {
         ON_CALL(*this, setIncFsMountOptions(_, _)).WillByDefault(Return(binder::Status::ok()));
@@ -280,8 +282,12 @@
     MOCK_CONST_METHOD2(getMetadata, RawMetadata(const Control& control, FileId fileid));
     MOCK_CONST_METHOD2(getMetadata, RawMetadata(const Control& control, std::string_view path));
     MOCK_CONST_METHOD2(getFileId, FileId(const Control& control, std::string_view path));
+    MOCK_CONST_METHOD2(countFilledBlocks,
+                       std::pair<IncFsBlockIndex, IncFsBlockIndex>(const Control& control,
+                                                                   std::string_view path));
     MOCK_CONST_METHOD3(link,
-                       ErrorCode(const Control& control, std::string_view from, std::string_view to));
+                       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_METHOD1(writeBlocks, ErrorCode(std::span<const DataBlock> blocks));
@@ -293,6 +299,19 @@
 
     void makeFileFails() { ON_CALL(*this, makeFile(_, _, _, _, _)).WillByDefault(Return(-1)); }
     void makeFileSuccess() { ON_CALL(*this, makeFile(_, _, _, _, _)).WillByDefault(Return(0)); }
+
+    void countFilledBlocksSuccess() {
+        ON_CALL(*this, countFilledBlocks(_, _)).WillByDefault(Return(std::make_pair(1, 2)));
+    }
+
+    void countFilledBlocksFails() {
+        ON_CALL(*this, countFilledBlocks(_, _)).WillByDefault(Return(std::make_pair(-1, -1)));
+    }
+
+    void countFilledBlocksEmpty() {
+        ON_CALL(*this, countFilledBlocks(_, _)).WillByDefault(Return(std::make_pair(0, 0)));
+    }
+
     void openMountSuccess() {
         ON_CALL(*this, openMount(_)).WillByDefault(Invoke(this, &MockIncFs::openMountForHealth));
     }
@@ -447,6 +466,21 @@
     Job mWhat;
 };
 
+class MockFsWrapper : public FsWrapper {
+public:
+    MOCK_CONST_METHOD1(listFilesRecursive, std::vector<std::string>(std::string_view));
+    void hasNoFile() {
+        ON_CALL(*this, listFilesRecursive(_)).WillByDefault(Return(std::vector<std::string>()));
+    }
+    void hasFiles() {
+        ON_CALL(*this, listFilesRecursive(_))
+                .WillByDefault(Invoke(this, &MockFsWrapper::fakeFiles));
+    }
+    std::vector<std::string> fakeFiles(std::string_view directoryPath) {
+        return {"base.apk", "split.apk", "lib/a.so"};
+    }
+};
+
 class MockStorageHealthListener : public os::incremental::BnStorageHealthListener {
 public:
     MOCK_METHOD2(onHealthStatus, binder::Status(int32_t storageId, int32_t status));
@@ -474,23 +508,28 @@
                        std::unique_ptr<MockAppOpsManager> appOpsManager,
                        std::unique_ptr<MockJniWrapper> jni,
                        std::unique_ptr<MockLooperWrapper> looper,
-                       std::unique_ptr<MockTimedQueueWrapper> timedQueue)
+                       std::unique_ptr<MockTimedQueueWrapper> timedQueue,
+                       std::unique_ptr<MockFsWrapper> fs)
           : mVold(std::move(vold)),
             mDataLoaderManager(std::move(dataLoaderManager)),
             mIncFs(std::move(incfs)),
             mAppOpsManager(std::move(appOpsManager)),
             mJni(std::move(jni)),
             mLooper(std::move(looper)),
-            mTimedQueue(std::move(timedQueue)) {}
+            mTimedQueue(std::move(timedQueue)),
+            mFs(std::move(fs)) {}
     std::unique_ptr<VoldServiceWrapper> getVoldService() final { return std::move(mVold); }
     std::unique_ptr<DataLoaderManagerWrapper> getDataLoaderManager() final {
         return std::move(mDataLoaderManager);
     }
     std::unique_ptr<IncFsWrapper> getIncFs() final { return std::move(mIncFs); }
-    std::unique_ptr<AppOpsManagerWrapper> getAppOpsManager() final { return std::move(mAppOpsManager); }
+    std::unique_ptr<AppOpsManagerWrapper> getAppOpsManager() final {
+        return std::move(mAppOpsManager);
+    }
     std::unique_ptr<JniWrapper> getJni() final { return std::move(mJni); }
     std::unique_ptr<LooperWrapper> getLooper() final { return std::move(mLooper); }
     std::unique_ptr<TimedQueueWrapper> getTimedQueue() final { return std::move(mTimedQueue); }
+    std::unique_ptr<FsWrapper> getFs() final { return std::move(mFs); }
 
 private:
     std::unique_ptr<MockVoldService> mVold;
@@ -500,6 +539,7 @@
     std::unique_ptr<MockJniWrapper> mJni;
     std::unique_ptr<MockLooperWrapper> mLooper;
     std::unique_ptr<MockTimedQueueWrapper> mTimedQueue;
+    std::unique_ptr<MockFsWrapper> mFs;
 };
 
 // --- IncrementalServiceTest ---
@@ -523,6 +563,8 @@
         mLooper = looper.get();
         auto timedQueue = std::make_unique<NiceMock<MockTimedQueueWrapper>>();
         mTimedQueue = timedQueue.get();
+        auto fs = std::make_unique<NiceMock<MockFsWrapper>>();
+        mFs = fs.get();
         mIncrementalService =
                 std::make_unique<IncrementalService>(MockServiceManager(std::move(vold),
                                                                         std::move(
@@ -531,12 +573,14 @@
                                                                         std::move(appOps),
                                                                         std::move(jni),
                                                                         std::move(looper),
-                                                                        std::move(timedQueue)),
+                                                                        std::move(timedQueue),
+                                                                        std::move(fs)),
                                                      mRootDir.path);
         mDataLoaderParcel.packageName = "com.test";
         mDataLoaderParcel.arguments = "uri";
         mDataLoaderManager->unbindFromDataLoaderSuccess();
         mIncrementalService->onSystemReady();
+        setupSuccess();
     }
 
     void setUpExistingMountDir(const std::string& rootDir) {
@@ -560,6 +604,14 @@
                 .WillByDefault(Invoke(mIncFs, &MockIncFs::getStorageMetadata));
     }
 
+    void setupSuccess() {
+        mVold->mountIncFsSuccess();
+        mIncFs->makeFileSuccess();
+        mVold->bindMountSuccess();
+        mDataLoaderManager->bindToDataLoaderSuccess();
+        mDataLoaderManager->getDataLoaderSuccess();
+    }
+
 protected:
     NiceMock<MockVoldService>* mVold = nullptr;
     NiceMock<MockIncFs>* mIncFs = nullptr;
@@ -568,6 +620,7 @@
     NiceMock<MockJniWrapper>* mJni = nullptr;
     NiceMock<MockLooperWrapper>* mLooper = nullptr;
     NiceMock<MockTimedQueueWrapper>* mTimedQueue = nullptr;
+    NiceMock<MockFsWrapper>* mFs = nullptr;
     NiceMock<MockDataLoader>* mDataLoader = nullptr;
     std::unique_ptr<IncrementalService> mIncrementalService;
     TemporaryDir mRootDir;
@@ -641,11 +694,6 @@
 }
 
 TEST_F(IncrementalServiceTest, testDeleteStorageSuccess) {
-    mVold->mountIncFsSuccess();
-    mIncFs->makeFileSuccess();
-    mVold->bindMountSuccess();
-    mDataLoaderManager->bindToDataLoaderSuccess();
-    mDataLoaderManager->getDataLoaderSuccess();
     EXPECT_CALL(*mDataLoaderManager, bindToDataLoader(_, _, _, _)).Times(1);
     EXPECT_CALL(*mDataLoaderManager, unbindFromDataLoader(_)).Times(1);
     EXPECT_CALL(*mDataLoader, create(_, _, _, _)).Times(1);
@@ -661,11 +709,6 @@
 }
 
 TEST_F(IncrementalServiceTest, testDataLoaderDestroyed) {
-    mVold->mountIncFsSuccess();
-    mIncFs->makeFileSuccess();
-    mVold->bindMountSuccess();
-    mDataLoaderManager->bindToDataLoaderSuccess();
-    mDataLoaderManager->getDataLoaderSuccess();
     EXPECT_CALL(*mDataLoaderManager, bindToDataLoader(_, _, _, _)).Times(2);
     EXPECT_CALL(*mDataLoaderManager, unbindFromDataLoader(_)).Times(1);
     EXPECT_CALL(*mDataLoader, create(_, _, _, _)).Times(2);
@@ -682,12 +725,7 @@
 }
 
 TEST_F(IncrementalServiceTest, testStartDataLoaderCreate) {
-    mVold->mountIncFsSuccess();
-    mIncFs->makeFileSuccess();
-    mVold->bindMountSuccess();
     mDataLoader->initializeCreateOkNoStatus();
-    mDataLoaderManager->bindToDataLoaderSuccess();
-    mDataLoaderManager->getDataLoaderSuccess();
     EXPECT_CALL(*mDataLoaderManager, bindToDataLoader(_, _, _, _)).Times(1);
     EXPECT_CALL(*mDataLoaderManager, unbindFromDataLoader(_)).Times(1);
     EXPECT_CALL(*mDataLoader, create(_, _, _, _)).Times(1);
@@ -705,12 +743,7 @@
 }
 
 TEST_F(IncrementalServiceTest, testStartDataLoaderPendingStart) {
-    mVold->mountIncFsSuccess();
-    mIncFs->makeFileSuccess();
-    mVold->bindMountSuccess();
     mDataLoader->initializeCreateOkNoStatus();
-    mDataLoaderManager->bindToDataLoaderSuccess();
-    mDataLoaderManager->getDataLoaderSuccess();
     EXPECT_CALL(*mDataLoaderManager, bindToDataLoader(_, _, _, _)).Times(1);
     EXPECT_CALL(*mDataLoaderManager, unbindFromDataLoader(_)).Times(1);
     EXPECT_CALL(*mDataLoader, create(_, _, _, _)).Times(2);
@@ -727,12 +760,7 @@
 }
 
 TEST_F(IncrementalServiceTest, testStartDataLoaderCreateUnavailable) {
-    mVold->mountIncFsSuccess();
-    mIncFs->makeFileSuccess();
-    mVold->bindMountSuccess();
     mDataLoader->initializeCreateOkNoStatus();
-    mDataLoaderManager->bindToDataLoaderSuccess();
-    mDataLoaderManager->getDataLoaderSuccess();
     EXPECT_CALL(*mDataLoaderManager, bindToDataLoader(_, _, _, _)).Times(1);
     EXPECT_CALL(*mDataLoaderManager, unbindFromDataLoader(_)).Times(1);
     EXPECT_CALL(*mDataLoader, create(_, _, _, _)).Times(1);
@@ -748,14 +776,10 @@
 }
 
 TEST_F(IncrementalServiceTest, testStartDataLoaderRecreateOnPendingReads) {
-    mVold->mountIncFsSuccess();
-    mIncFs->makeFileSuccess();
-    mIncFs->openMountSuccess();
     mIncFs->waitForPendingReadsSuccess();
-    mVold->bindMountSuccess();
+    mIncFs->openMountSuccess();
     mDataLoader->initializeCreateOkNoStatus();
-    mDataLoaderManager->bindToDataLoaderSuccess();
-    mDataLoaderManager->getDataLoaderSuccess();
+
     EXPECT_CALL(*mDataLoaderManager, bindToDataLoader(_, _, _, _)).Times(2);
     EXPECT_CALL(*mDataLoaderManager, unbindFromDataLoader(_)).Times(2);
     EXPECT_CALL(*mDataLoader, create(_, _, _, _)).Times(2);
@@ -776,12 +800,8 @@
 }
 
 TEST_F(IncrementalServiceTest, testStartDataLoaderUnhealthyStorage) {
-    mVold->mountIncFsSuccess();
-    mIncFs->makeFileSuccess();
     mIncFs->openMountSuccess();
-    mVold->bindMountSuccess();
-    mDataLoaderManager->bindToDataLoaderSuccess();
-    mDataLoaderManager->getDataLoaderSuccess();
+
     EXPECT_CALL(*mDataLoaderManager, bindToDataLoader(_, _, _, _)).Times(1);
     EXPECT_CALL(*mDataLoaderManager, unbindFromDataLoader(_)).Times(1);
     EXPECT_CALL(*mDataLoader, create(_, _, _, _)).Times(1);
@@ -906,13 +926,9 @@
 }
 
 TEST_F(IncrementalServiceTest, testSetIncFsMountOptionsSuccess) {
-    mVold->mountIncFsSuccess();
-    mIncFs->makeFileSuccess();
-    mVold->bindMountSuccess();
     mVold->setIncFsMountOptionsSuccess();
-    mDataLoaderManager->bindToDataLoaderSuccess();
-    mDataLoaderManager->getDataLoaderSuccess();
     mAppOpsManager->checkPermissionSuccess();
+
     EXPECT_CALL(*mDataLoaderManager, unbindFromDataLoader(_));
     EXPECT_CALL(*mVold, unmountIncFs(_)).Times(2);
     // We are calling setIncFsMountOptions(true).
@@ -930,13 +946,9 @@
 }
 
 TEST_F(IncrementalServiceTest, testSetIncFsMountOptionsSuccessAndDisabled) {
-    mVold->mountIncFsSuccess();
-    mIncFs->makeFileSuccess();
-    mVold->bindMountSuccess();
     mVold->setIncFsMountOptionsSuccess();
-    mDataLoaderManager->bindToDataLoaderSuccess();
-    mDataLoaderManager->getDataLoaderSuccess();
     mAppOpsManager->checkPermissionSuccess();
+
     EXPECT_CALL(*mDataLoaderManager, unbindFromDataLoader(_));
     EXPECT_CALL(*mVold, unmountIncFs(_)).Times(2);
     // Enabling and then disabling readlogs.
@@ -958,14 +970,10 @@
 }
 
 TEST_F(IncrementalServiceTest, testSetIncFsMountOptionsSuccessAndPermissionChanged) {
-    mVold->mountIncFsSuccess();
-    mIncFs->makeFileSuccess();
-    mVold->bindMountSuccess();
     mVold->setIncFsMountOptionsSuccess();
-    mDataLoaderManager->bindToDataLoaderSuccess();
-    mDataLoaderManager->getDataLoaderSuccess();
     mAppOpsManager->checkPermissionSuccess();
     mAppOpsManager->initializeStartWatchingMode();
+
     EXPECT_CALL(*mDataLoaderManager, unbindFromDataLoader(_));
     EXPECT_CALL(*mVold, unmountIncFs(_)).Times(2);
     // We are calling setIncFsMountOptions(true).
@@ -987,12 +995,8 @@
 }
 
 TEST_F(IncrementalServiceTest, testSetIncFsMountOptionsCheckPermissionFails) {
-    mVold->mountIncFsSuccess();
-    mIncFs->makeFileSuccess();
-    mVold->bindMountSuccess();
-    mDataLoaderManager->bindToDataLoaderSuccess();
-    mDataLoaderManager->getDataLoaderSuccess();
     mAppOpsManager->checkPermissionFails();
+
     EXPECT_CALL(*mDataLoaderManager, unbindFromDataLoader(_));
     EXPECT_CALL(*mVold, unmountIncFs(_)).Times(2);
     // checkPermission fails, no calls to set opitions,  start or stop WatchingMode.
@@ -1008,13 +1012,9 @@
 }
 
 TEST_F(IncrementalServiceTest, testSetIncFsMountOptionsFails) {
-    mVold->mountIncFsSuccess();
-    mIncFs->makeFileSuccess();
-    mVold->bindMountSuccess();
     mVold->setIncFsMountOptionsFails();
-    mDataLoaderManager->bindToDataLoaderSuccess();
-    mDataLoaderManager->getDataLoaderSuccess();
     mAppOpsManager->checkPermissionSuccess();
+
     EXPECT_CALL(*mDataLoaderManager, unbindFromDataLoader(_));
     EXPECT_CALL(*mVold, unmountIncFs(_)).Times(2);
     // We are calling setIncFsMountOptions.
@@ -1031,11 +1031,6 @@
 }
 
 TEST_F(IncrementalServiceTest, testMakeDirectory) {
-    mVold->mountIncFsSuccess();
-    mIncFs->makeFileSuccess();
-    mVold->bindMountSuccess();
-    mDataLoaderManager->bindToDataLoaderSuccess();
-    mDataLoaderManager->getDataLoaderSuccess();
     TemporaryDir tempDir;
     int storageId = mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel),
                                                        IncrementalService::CreateOptions::CreateNew,
@@ -1055,11 +1050,6 @@
 }
 
 TEST_F(IncrementalServiceTest, testMakeDirectories) {
-    mVold->mountIncFsSuccess();
-    mIncFs->makeFileSuccess();
-    mVold->bindMountSuccess();
-    mDataLoaderManager->bindToDataLoaderSuccess();
-    mDataLoaderManager->getDataLoaderSuccess();
     TemporaryDir tempDir;
     int storageId = mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel),
                                                        IncrementalService::CreateOptions::CreateNew,
@@ -1078,4 +1068,51 @@
     auto res = mIncrementalService->makeDirs(storageId, dir_path, 0555);
     ASSERT_EQ(res, 0);
 }
+
+TEST_F(IncrementalServiceTest, testGetLoadingProgressFailsWithNoFile) {
+    mIncFs->countFilledBlocksSuccess();
+    mFs->hasNoFile();
+
+    TemporaryDir tempDir;
+    int storageId = mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel),
+                                                       IncrementalService::CreateOptions::CreateNew,
+                                                       {}, {}, {});
+    ASSERT_EQ(-EINVAL, mIncrementalService->getLoadingProgress(storageId));
+}
+
+TEST_F(IncrementalServiceTest, testGetLoadingProgressFailsWithFailedRanges) {
+    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->getLoadingProgress(storageId));
+}
+
+TEST_F(IncrementalServiceTest, testGetLoadingProgressFailsWithEmptyRanges) {
+    mIncFs->countFilledBlocksEmpty();
+    mFs->hasFiles();
+
+    TemporaryDir tempDir;
+    int storageId = mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel),
+                                                       IncrementalService::CreateOptions::CreateNew,
+                                                       {}, {}, {});
+    EXPECT_CALL(*mIncFs, countFilledBlocks(_, _)).Times(3);
+    ASSERT_EQ(-EINVAL, mIncrementalService->getLoadingProgress(storageId));
+}
+
+TEST_F(IncrementalServiceTest, testGetLoadingProgressSuccess) {
+    mIncFs->countFilledBlocksSuccess();
+    mFs->hasFiles();
+
+    TemporaryDir tempDir;
+    int storageId = mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel),
+                                                       IncrementalService::CreateOptions::CreateNew,
+                                                       {}, {}, {});
+    EXPECT_CALL(*mIncFs, countFilledBlocks(_, _)).Times(3);
+    ASSERT_EQ(0.5, mIncrementalService->getLoadingProgress(storageId));
+}
 } // namespace android::os::incremental