Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 249a37c5 authored by Yurii Zubrytskyi's avatar Yurii Zubrytskyi Committed by Android (Google) Code Review
Browse files

Merge "[incfs] Space trimming for IncFS v1" into sc-dev

parents cb6fedf4 4cd24925
Loading
Loading
Loading
Loading
+33 −11
Original line number Diff line number Diff line
@@ -1086,9 +1086,7 @@ int IncrementalService::makeFile(StorageId storage, std::string_view path, int m
        return err;
    }
    if (params.size > 0) {
        // Only v2+ incfs supports automatically trimming file over-reserved sizes
        if (mIncFs->features() & incfs::Features::v2) {
            if (auto err = mIncFs->reserveSpace(ifs->control, normPath, params.size)) {
        if (auto err = mIncFs->reserveSpace(ifs->control, id, params.size)) {
            if (err != -EOPNOTSUPP) {
                LOG(ERROR) << "Failed to reserve space for a new file: " << err;
                (void)mIncFs->unlink(ifs->control, normPath);
@@ -1098,7 +1096,6 @@ int IncrementalService::makeFile(StorageId storage, std::string_view path, int m
                                "may run out of disk later";
            }
        }
        }
        if (!data.empty()) {
            if (auto err = setFileContent(ifs, id, path, data); err) {
                (void)mIncFs->unlink(ifs->control, normPath);
@@ -1680,6 +1677,15 @@ void IncrementalService::runCmdLooper() {
    }
}

void IncrementalService::trimReservedSpaceV1(const IncFsMount& ifs) {
    mIncFs->forEachFile(ifs.control, [this](auto&& control, auto&& fileId) {
        if (mIncFs->isFileFullyLoaded(control, fileId) == incfs::LoadingState::Full) {
            mIncFs->reserveSpace(control, fileId, -1);
        }
        return true;
    });
}

void IncrementalService::prepareDataLoaderLocked(IncFsMount& ifs, DataLoaderParamsParcel&& params,
                                                 DataLoaderStatusListener&& statusListener,
                                                 const StorageHealthCheckParams& healthCheckParams,
@@ -1699,6 +1705,22 @@ void IncrementalService::prepareDataLoaderLocked(IncFsMount& ifs, DataLoaderPara
                               std::move(statusListener), healthCheckParams,
                               std::move(healthListener), path::join(ifs.root, constants().mount));

    // pre-v2 IncFS doesn't do automatic reserved space trimming - need to run it manually
    if (!(mIncFs->features() & incfs::Features::v2)) {
        addIfsStateCallback(ifs.mountId, [this](StorageId storageId, IfsState state) -> bool {
            if (!state.fullyLoaded) {
                return true;
            }

            const auto ifs = getIfs(storageId);
            if (!ifs) {
                return false;
            }
            trimReservedSpaceV1(*ifs);
            return false;
        });
    }

    addIfsStateCallback(ifs.mountId, [this](StorageId storageId, IfsState state) -> bool {
        if (!state.fullyLoaded || state.readLogsEnabled) {
            return true;
+2 −0
Original line number Diff line number Diff line
@@ -452,6 +452,8 @@ private:
                               StorageLoadingProgressListener&& progressListener);
    long getMillsSinceOldestPendingRead(StorageId storage);

    void trimReservedSpaceV1(const IncFsMount& ifs);

private:
    const std::unique_ptr<VoldServiceWrapper> mVold;
    const std::unique_ptr<DataLoaderManagerWrapper> mDataLoaderManager;
+16 −7
Original line number Diff line number Diff line
@@ -212,6 +212,9 @@ public:
                                          std::string_view path) const final {
        return incfs::isFullyLoaded(control, path);
    }
    incfs::LoadingState isFileFullyLoaded(const Control& control, FileId id) const final {
        return incfs::isFullyLoaded(control, id);
    }
    incfs::LoadingState isEverythingFullyLoaded(const Control& control) const final {
        return incfs::isEverythingFullyLoaded(control);
    }
@@ -227,9 +230,8 @@ public:
    ErrorCode writeBlocks(std::span<const incfs::DataBlock> blocks) const final {
        return incfs::writeBlocks({blocks.data(), size_t(blocks.size())});
    }
    ErrorCode reserveSpace(const Control& control, std::string_view path,
                           IncFsSize size) const final {
        return incfs::reserveSpace(control, path, size);
    ErrorCode reserveSpace(const Control& control, FileId id, IncFsSize size) const final {
        return incfs::reserveSpace(control, id, size);
    }
    WaitResult waitForPendingReads(const Control& control, std::chrono::milliseconds timeout,
                                   std::vector<incfs::ReadInfo>* pendingReadsBuffer) const final {
@@ -238,19 +240,26 @@ public:
    ErrorCode setUidReadTimeouts(const Control& control,
                                 const std::vector<android::os::incremental::PerUidReadTimeouts>&
                                         perUidReadTimeouts) const final {
        std::vector<incfs::UidReadTimeouts> timeouts;
        timeouts.resize(perUidReadTimeouts.size());
        std::vector<incfs::UidReadTimeouts> timeouts(perUidReadTimeouts.size());
        for (int i = 0, size = perUidReadTimeouts.size(); i < size; ++i) {
            auto&& timeout = timeouts[i];
            auto& timeout = timeouts[i];
            const auto& perUidTimeout = perUidReadTimeouts[i];
            timeout.uid = perUidTimeout.uid;
            timeout.minTimeUs = perUidTimeout.minTimeUs;
            timeout.minPendingTimeUs = perUidTimeout.minPendingTimeUs;
            timeout.maxPendingTimeUs = perUidTimeout.maxPendingTimeUs;
        }

        return incfs::setUidReadTimeouts(control, timeouts);
    }
    ErrorCode forEachFile(const Control& control, FileCallback cb) const final {
        return incfs::forEachFile(control,
                                  [&](auto& control, FileId id) { return cb(control, id); });
    }
    ErrorCode forEachIncompleteFile(const Control& control, FileCallback cb) const final {
        return incfs::forEachIncompleteFile(control, [&](auto& control, FileId id) {
            return cb(control, id);
        });
    }
};

static JNIEnv* getOrAttachJniEnv(JavaVM* jvm);
+6 −2
Original line number Diff line number Diff line
@@ -84,6 +84,8 @@ public:
            void(std::string_view root, std::string_view backingDir,
                 std::span<std::pair<std::string_view, std::string_view>> binds)>;

    using FileCallback = android::base::function_ref<bool(const Control& control, FileId fileId)>;

    static std::string toString(FileId fileId);

    virtual ~IncFsWrapper() = default;
@@ -105,14 +107,14 @@ public:
            const Control& control, std::string_view path) const = 0;
    virtual incfs::LoadingState isFileFullyLoaded(const Control& control,
                                                  std::string_view path) const = 0;
    virtual incfs::LoadingState isFileFullyLoaded(const Control& control, FileId id) const = 0;
    virtual incfs::LoadingState isEverythingFullyLoaded(const Control& control) const = 0;
    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 UniqueFd openForSpecialOps(const Control& control, FileId id) const = 0;
    virtual ErrorCode writeBlocks(std::span<const incfs::DataBlock> blocks) const = 0;
    virtual ErrorCode reserveSpace(const Control& control, std::string_view path,
                                   IncFsSize size) const = 0;
    virtual ErrorCode reserveSpace(const Control& control, FileId id, IncFsSize size) const = 0;
    virtual WaitResult waitForPendingReads(
            const Control& control, std::chrono::milliseconds timeout,
            std::vector<incfs::ReadInfo>* pendingReadsBuffer) const = 0;
@@ -120,6 +122,8 @@ public:
            const Control& control,
            const std::vector<::android::os::incremental::PerUidReadTimeouts>& perUidReadTimeouts)
            const = 0;
    virtual ErrorCode forEachFile(const Control& control, FileCallback cb) const = 0;
    virtual ErrorCode forEachIncompleteFile(const Control& control, FileCallback cb) const = 0;
};

class AppOpsManagerWrapper {
+7 −5
Original line number Diff line number Diff line
@@ -379,6 +379,7 @@ public:
                                                                   std::string_view path));
    MOCK_CONST_METHOD2(isFileFullyLoaded,
                       incfs::LoadingState(const Control& control, std::string_view path));
    MOCK_CONST_METHOD2(isFileFullyLoaded, incfs::LoadingState(const Control& control, FileId id));
    MOCK_CONST_METHOD1(isEverythingFullyLoaded, incfs::LoadingState(const Control& control));
    MOCK_CONST_METHOD3(link,
                       ErrorCode(const Control& control, std::string_view from,
@@ -386,14 +387,15 @@ public:
    MOCK_CONST_METHOD2(unlink, ErrorCode(const Control& control, std::string_view path));
    MOCK_CONST_METHOD2(openForSpecialOps, UniqueFd(const Control& control, FileId id));
    MOCK_CONST_METHOD1(writeBlocks, ErrorCode(std::span<const DataBlock> blocks));
    MOCK_CONST_METHOD3(reserveSpace,
                       ErrorCode(const Control& control, std::string_view path, IncFsSize size));
    MOCK_CONST_METHOD3(reserveSpace, ErrorCode(const Control& control, FileId id, IncFsSize size));
    MOCK_CONST_METHOD3(waitForPendingReads,
                       WaitResult(const Control& control, std::chrono::milliseconds timeout,
                                  std::vector<incfs::ReadInfo>* pendingReadsBuffer));
    MOCK_CONST_METHOD2(setUidReadTimeouts,
                       ErrorCode(const Control& control,
                                 const std::vector<PerUidReadTimeouts>& perUidReadTimeouts));
    MOCK_CONST_METHOD2(forEachFile, ErrorCode(const Control& control, FileCallback cb));
    MOCK_CONST_METHOD2(forEachIncompleteFile, ErrorCode(const Control& control, FileCallback cb));

    MockIncFs() {
        ON_CALL(*this, listExistingMounts(_)).WillByDefault(Return());
@@ -1594,7 +1596,7 @@ TEST_F(IncrementalServiceTest, testIsFileFullyLoadedNoData) {
    int storageId =
            mIncrementalService->createStorage(tempDir.path, mDataLoaderParcel,
                                               IncrementalService::CreateOptions::CreateNew);
    EXPECT_CALL(*mIncFs, isFileFullyLoaded(_, _))
    EXPECT_CALL(*mIncFs, isFileFullyLoaded(_, An<std::string_view>()))
            .Times(1)
            .WillOnce(Return(incfs::LoadingState::MissingBlocks));
    ASSERT_GT((int)mIncrementalService->isFileFullyLoaded(storageId, "base.apk"), 0);
@@ -1605,7 +1607,7 @@ TEST_F(IncrementalServiceTest, testIsFileFullyLoadedError) {
    int storageId =
            mIncrementalService->createStorage(tempDir.path, mDataLoaderParcel,
                                               IncrementalService::CreateOptions::CreateNew);
    EXPECT_CALL(*mIncFs, isFileFullyLoaded(_, _))
    EXPECT_CALL(*mIncFs, isFileFullyLoaded(_, An<std::string_view>()))
            .Times(1)
            .WillOnce(Return(incfs::LoadingState(-1)));
    ASSERT_LT((int)mIncrementalService->isFileFullyLoaded(storageId, "base.apk"), 0);
@@ -1616,7 +1618,7 @@ TEST_F(IncrementalServiceTest, testIsFileFullyLoadedSuccess) {
    int storageId =
            mIncrementalService->createStorage(tempDir.path, mDataLoaderParcel,
                                               IncrementalService::CreateOptions::CreateNew);
    EXPECT_CALL(*mIncFs, isFileFullyLoaded(_, _))
    EXPECT_CALL(*mIncFs, isFileFullyLoaded(_, An<std::string_view>()))
            .Times(1)
            .WillOnce(Return(incfs::LoadingState::Full));
    ASSERT_EQ(0, (int)mIncrementalService->isFileFullyLoaded(storageId, "base.apk"));