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

Commit 374f7654 authored by Songchun Fan's avatar Songchun Fan
Browse files

[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
parent 1581527c
Loading
Loading
Loading
Loading
+3 −2
Original line number Diff line number Diff line
@@ -90,9 +90,10 @@ interface IIncrementalService {
    int unlink(int storageId, in @utf8InCpp String path);

    /**
     * Checks if a file's certain range is loaded. File is specified by its path.
     * Returns overall loading progress of all the files on a storage, progress value between [0,1].
     * Returns a negative value on error.
     */
    boolean isFileRangeLoaded(int storageId, in @utf8InCpp String path, long start, long end);
    float getLoadingProgress(int storageId);

    /**
     * Reads the metadata of a file. File is specified by either its path or 16 byte id.
+10 −18
Original line number Diff line number Diff line
@@ -304,29 +304,21 @@ public final class IncrementalStorage {
    }

    /**
     * Checks whether a file under the current storage directory is fully loaded.
     * Returns the loading progress of a storage
     *
     * @param path The relative path of the file.
     * @return True if the file is fully loaded.
     * @return progress value between [0, 1].
     */
    public boolean isFileFullyLoaded(@NonNull String path) {
        return isFileRangeLoaded(path, 0, -1);
    }

    /**
     * Checks whether a range in a file if loaded.
     *
     * @param path The relative path of the file.
     * @param start            The starting offset of the range.
     * @param end              The ending offset of the range.
     * @return True if the file is fully loaded.
     */
    public boolean isFileRangeLoaded(@NonNull String path, long start, long end) {
    public float getLoadingProgress() throws IOException {
        try {
            return mService.isFileRangeLoaded(mId, path, start, end);
            final float res = mService.getLoadingProgress(mId);
            if (res < 0) {
                throw new IOException(
                        "getLoadingProgress() failed at querying loading progress, errno " + -res);
            }
            return res;
        } catch (RemoteException e) {
            e.rethrowFromSystemServer();
            return false;
            return 0;
        }
    }

+3 −5
Original line number Diff line number Diff line
@@ -237,11 +237,9 @@ binder::Status BinderIncrementalService::unlink(int32_t storageId, const std::st
    return ok();
}

binder::Status BinderIncrementalService::isFileRangeLoaded(int32_t storageId,
                                                           const std::string& path, int64_t start,
                                                           int64_t end, bool* _aidl_return) {
    // TODO: implement
    *_aidl_return = false;
binder::Status BinderIncrementalService::getLoadingProgress(int32_t storageId,
                                                            float* _aidl_return) {
    *_aidl_return = mImpl.getLoadingProgress(storageId);
    return ok();
}

+1 −2
Original line number Diff line number Diff line
@@ -66,8 +66,7 @@ public:
                            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 isFileRangeLoaded(int32_t storageId, const std::string& path, int64_t start,
                                     int64_t end, bool* _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;
    binder::Status getMetadataById(int32_t storageId, const std::vector<uint8_t>& id,
+47 −4
Original line number Diff line number Diff line
@@ -37,7 +37,6 @@
#include "Metadata.pb.h"

using namespace std::literals;
namespace fs = std::filesystem;

constexpr const char* kDataUsageStats = "android.permission.LOADER_USAGE_STATS";
constexpr const char* kOpUsage = "android:loader_usage_stats";
@@ -276,6 +275,7 @@ IncrementalService::IncrementalService(ServiceManagerWrapper&& sm, std::string_v
        mJni(sm.getJni()),
        mLooper(sm.getLooper()),
        mTimedQueue(sm.getTimedQueue()),
        mFs(sm.getFs()),
        mIncrementalDir(rootDir) {
    CHECK(mVold) << "Vold service is unavailable";
    CHECK(mDataLoaderManager) << "DataLoaderManagerService is unavailable";
@@ -283,6 +283,7 @@ IncrementalService::IncrementalService(ServiceManagerWrapper&& sm, std::string_v
    CHECK(mJni) << "JNI is unavailable";
    CHECK(mLooper) << "Looper is unavailable";
    CHECK(mTimedQueue) << "TimedQueue is unavailable";
    CHECK(mFs) << "Fs is unavailable";

    mJobQueue.reserve(16);
    mJobProcessor = std::thread([this]() {
@@ -344,7 +345,8 @@ void IncrementalService::onDump(int fd) {
            }
            dprintf(fd, "    storages (%d): {\n", int(mnt.storages.size()));
            for (auto&& [storageId, storage] : mnt.storages) {
                dprintf(fd, "      [%d] -> [%s]\n", storageId, storage.name.c_str());
                dprintf(fd, "      [%d] -> [%s] (%d %% loaded) \n", storageId, storage.name.c_str(),
                        (int)(getLoadingProgressFromPath(mnt, storage.name.c_str()) * 100));
            }
            dprintf(fd, "    }\n");

@@ -1671,6 +1673,45 @@ bool IncrementalService::waitForNativeBinariesExtraction(StorageId storage) {
    return mRunning;
}

float IncrementalService::getLoadingProgress(StorageId storage) const {
    std::unique_lock l(mLock);
    const auto ifs = getIfsLocked(storage);
    if (!ifs) {
        LOG(ERROR) << "getLoadingProgress failed, invalid storageId: " << storage;
        return -EINVAL;
    }
    const auto storageInfo = ifs->storages.find(storage);
    if (storageInfo == ifs->storages.end()) {
        LOG(ERROR) << "getLoadingProgress failed, no storage: " << storage;
        return -EINVAL;
    }
    l.unlock();
    return getLoadingProgressFromPath(*ifs, storageInfo->second.name);
}

float IncrementalService::getLoadingProgressFromPath(const IncFsMount& ifs,
                                                     std::string_view storagePath) const {
    size_t totalBlocks = 0, filledBlocks = 0;
    const auto filePaths = mFs->listFilesRecursive(storagePath);
    for (const auto& filePath : filePaths) {
        const auto [filledBlocksCount, totalBlocksCount] =
                mIncFs->countFilledBlocks(ifs.control, filePath);
        if (filledBlocksCount < 0) {
            LOG(ERROR) << "getLoadingProgress failed to get filled blocks count for: " << filePath
                       << " errno: " << filledBlocksCount;
            return filledBlocksCount;
        }
        totalBlocks += totalBlocksCount;
        filledBlocks += filledBlocksCount;
    }

    if (totalBlocks == 0) {
        LOG(ERROR) << "getLoadingProgress failed to get total num of blocks";
        return -EINVAL;
    }
    return (float)filledBlocks / (float)totalBlocks;
}

bool IncrementalService::perfLoggingEnabled() {
    static const bool enabled = base::GetBoolProperty("incremental.perflogging", false);
    return enabled;
@@ -2029,11 +2070,13 @@ void IncrementalService::DataLoaderStub::updateHealthStatus(bool baseline) {

        // Healthcheck depends on timestamp of the oldest pending read.
        // To get it, we need to re-open a pendingReads FD to get a full list of reads.
        // Additionally we need to re-register for epoll with fresh FDs in case there are no reads.
        // Additionally we need to re-register for epoll with fresh FDs in case there are no
        // reads.
        const auto now = Clock::now();
        const auto kernelTsUs = getOldestPendingReadTs();
        if (baseline) {
            // Updating baseline only on looper/epoll callback, i.e. on new set of pending reads.
            // Updating baseline only on looper/epoll callback, i.e. on new set of pending
            // reads.
            mHealthBase = {now, kernelTsUs};
        }

Loading