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

Commit d11a03a7 authored by Girish's avatar Girish
Browse files

resourcemanager: use std::vector for ResourceList

Encapsulate Resource List as vector of resources instead of map.
Since the number of resource is very limited, maintaining it as
std::vector helps with both performance and memory requiremnts.

Bug: 289097671
Test: atest android.media.misc.cts.ResourceManagerTest
      atest android.media.misc.cts.ResourceManagerMultiTest
      /data/nativetest64/ResourceManagerService_test/ResourceManagerService_test
      /data/nativetest64/ResourceObserverService_test/ResourceObserverService_test
Change-Id: Iec2ead5be1619c7db6d6c978f7398459ce59613b
parent 4777e5a5
Loading
Loading
Loading
Loading
+17 −40
Original line number Diff line number Diff line
@@ -74,10 +74,7 @@ void ResourceManagerService::getResourceDump(std::string& resourceLog) const {

            const ResourceList& resources = info.resources;
            resourceLog.append("        Resources:\n");
            for (auto it = resources.begin(); it != resources.end(); it++) {
                snprintf(buffer, SIZE, "          %s\n", toString(it->second).c_str());
                resourceLog.append(buffer);
            }
            resourceLog.append(resources.toString());
        }
    }

@@ -315,31 +312,21 @@ Status ResourceManagerService::addResource(const ClientInfoParcel& clientInfo,

    for (size_t i = 0; i < resources.size(); ++i) {
        const auto &res = resources[i];
        const auto resType = std::tuple(res.type, res.subType, res.id);

        if (res.value < 0 && res.type != MediaResource::Type::kDrmSession) {
            ALOGW("Ignoring request to remove negative value of non-drm resource");
            continue;
        }
        if (info.resources.find(resType) == info.resources.end()) {
            if (res.value <= 0) {
                // We can't init a new entry with negative value, although it's allowed
                // to merge in negative values after the initial add.
                ALOGW("Ignoring request to add new resource entry with value <= 0");
        bool isNewEntry = false;
        if (!info.resources.add(res, &isNewEntry)) {
            continue;
        }
        if (isNewEntry) {
            onFirstAdded(res, info.uid);
            info.resources[resType] = res;
        } else {
            mergeResources(info.resources[resType], res);
        }

        // Add it to the list of added resources for observers.
        auto it = resourceAdded.find(resType);
        if (it == resourceAdded.end()) {
            resourceAdded[resType] = res;
        } else {
            mergeResources(it->second, res);
        }
        resourceAdded.add(res);
    }
    if (info.deathNotifier == nullptr && client != nullptr) {
        info.deathNotifier = DeathNotifier::Create(
@@ -386,31 +373,22 @@ Status ResourceManagerService::removeResource(const ClientInfoParcel& clientInfo
    ResourceList resourceRemoved;
    for (size_t i = 0; i < resources.size(); ++i) {
        const auto &res = resources[i];
        const auto resType = std::tuple(res.type, res.subType, res.id);

        if (res.value < 0) {
            ALOGW("Ignoring request to remove negative value of resource");
            continue;
        }
        // ignore if we don't have it
        if (info.resources.find(resType) != info.resources.end()) {
            MediaResourceParcel &resource = info.resources[resType];

        long removedEntryValue = -1;
        if (info.resources.remove(res, &removedEntryValue)) {
            MediaResourceParcel actualRemoved = res;
            if (resource.value > res.value) {
                resource.value -= res.value;
            } else {
            if (removedEntryValue != -1) {
                onLastRemoved(res, info.uid);
                actualRemoved.value = resource.value;
                info.resources.erase(resType);
                actualRemoved.value = removedEntryValue;
            }

            // Add it to the list of removed resources for observers.
            auto it = resourceRemoved.find(resType);
            if (it == resourceRemoved.end()) {
                resourceRemoved[resType] = actualRemoved;
            } else {
                mergeResources(it->second, actualRemoved);
            }
            resourceRemoved.add(actualRemoved);
        }
    }
    if (mObserverService != nullptr && !resourceRemoved.empty()) {
@@ -453,8 +431,8 @@ Status ResourceManagerService::removeResource(const ClientInfoParcel& clientInfo
    }

    const ResourceInfo& info = foundClient->second;
    for (auto it = info.resources.begin(); it != info.resources.end(); it++) {
        onLastRemoved(it->second, info.uid);
    for (const MediaResourceParcel& res : info.resources.getResources()) {
        onLastRemoved(res, info.uid);
    }

    // Since this client has been removed, update the metrics collector.
@@ -1056,8 +1034,7 @@ bool ResourceManagerService::getBiggestClient_l(int pid, MediaResource::Type typ
        if (pendingRemovalOnly && !info.pendingRemoval) {
            continue;
        }
        for (auto it = resources.begin(); it != resources.end(); it++) {
            const MediaResourceParcel &resource = it->second;
        for (const MediaResourceParcel& resource : resources.getResources()) {
            if (hasResourceType(type, subType, resource)) {
                if (resource.value > largestValue) {
                    largestValue = resource.value;
+89 −2
Original line number Diff line number Diff line
@@ -27,6 +27,93 @@

namespace android {

bool ResourceList::add(const MediaResourceParcel& res, bool* isNewEntry) {
    // See if it's an existing entry, if so, merge it.
    for (MediaResourceParcel& item : mResourceList) {
        if (item.type == res.type && item.subType == res.subType && item.id == res.id) {
            // We already have an item. Merge them and return
            mergeResources(item, res);
            return true;
        }
    }

    // Since we have't found this resource yet, it is a new entry.
    // We can't init a new entry with negative value, although it's allowed
    // to merge in negative values after the initial add.
    if (res.value <= 0) {
        ALOGW("Ignoring request to add new resource entry with value <= 0");
        return false;
    }
    if (isNewEntry) {
        *isNewEntry = true;
    }
    mResourceList.push_back(res);
    return true;
}

void ResourceList::addOrUpdate(const MediaResourceParcel& res) {
    // See if it's an existing entry, just update the value.
    for (MediaResourceParcel& item : mResourceList) {
        if (item.type == res.type && item.subType == res.subType && item.id == res.id) {
            item.value = res.value;
            return;
        }
    }

    // Add the new entry.
    mResourceList.push_back(res);
}

bool ResourceList::remove(const MediaResourceParcel& res, long* removedEntryValue) {
    // Make sure we have an entry for this resource.
    for (std::vector<MediaResourceParcel>::iterator it = mResourceList.begin();
         it != mResourceList.end(); it++) {
        if (it->type == res.type && it->subType == res.subType && it->id == res.id) {
            if (it->value > res.value) {
                // Subtract the resource value by given value.
                it->value -= res.value;
            } else {
                // This entry will be removed.
                if (removedEntryValue) {
                    *removedEntryValue = it->value;
                }
                mResourceList.erase(it);
            }
            return true;
        }
    }

    // No such entry.
    return false;
}

std::string ResourceList::toString() const {
    std::string str;
    for (const ::aidl::android::media::MediaResourceParcel& res : mResourceList) {
        str.append(android::toString(res).c_str());
        str.append("\n");
    }

    return std::move(str);
}

bool ResourceList::operator==(const ResourceList& rhs) const {
    // Make sure the size is the same.
    if (mResourceList.size() != rhs.mResourceList.size()) {
        return false;
    }

    // Create a set from this object and check for the items from the rhs.
    std::set<::aidl::android::media::MediaResourceParcel> lhs(
            mResourceList.begin(), mResourceList.end());
    for (const ::aidl::android::media::MediaResourceParcel& res : rhs.mResourceList) {
        if (lhs.find(res) == lhs.end()) {
            return false;
        }
    }
    return true;
}

// Bunch of utility functions that looks for a specific Resource.
// Check whether a given resource (of type and subtype) is found in given resource parcel.
bool hasResourceType(MediaResource::Type type, MediaResource::SubType subType,
@@ -53,8 +140,8 @@ bool hasResourceType(MediaResource::Type type, MediaResource::SubType subType,
// Check whether a given resource (of type and subtype) is found in given resource list.
bool hasResourceType(MediaResource::Type type, MediaResource::SubType subType,
                     const ResourceList& resources) {
    for (auto it = resources.begin(); it != resources.end(); it++) {
        if (hasResourceType(type, subType, it->second)) {
    for (const MediaResourceParcel& res : resources.getResources()) {
        if (hasResourceType(type, subType, res)) {
            return true;
        }
    }
+42 −4
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@
#define ANDROID_MEDIA_RESOURCEMANAGERSERVICEUTILS_H_

#include <map>
#include <set>
#include <memory>
#include <vector>

@@ -99,10 +100,47 @@ public:
    virtual void binderDied();
};

// A map of tuple(type, sub-type, id) and the resource parcel.
typedef std::map<std::tuple<
        MediaResource::Type, MediaResource::SubType, std::vector<uint8_t>>,
        ::aidl::android::media::MediaResourceParcel> ResourceList;
// Encapsulate Resource List as vector of resources instead of map.
// Since the number of resource is very limited, maintaining it as
// std::vector helps with both performance and memory requiremnts.
struct ResourceList {
    // Add or Update an entry into ResourceList.
    // If a new entry is added, isNewEntry will be set to true upon return
    // returns true on successful update, false otherwise.
    bool add(const ::aidl::android::media::MediaResourceParcel& res, bool* isNewEntry = nullptr);

    // reduce the resource usage by subtracting the resource value.
    // If the resource value is 0 after reducing the resource usage,
    // that entry will be removed and removedEntryValue is set to the
    // value before it was removed upon return otherwise it will be set to -1.
    // returns true on successful removal of the resource, false otherwise.
    bool remove(const ::aidl::android::media::MediaResourceParcel& res,
                long* removedEntryValue = nullptr);

    // Returns true if there aren't any resource entries.
    bool empty() const {
        return mResourceList.empty();
    }

    // Returns resource list as a non-modifiable vectors
    const std::vector<::aidl::android::media::MediaResourceParcel>& getResources() const {
        return mResourceList;
    }

    // Converts resource list into string format
    std::string toString() const;

    // BEGIN: Test only function
    // Check if two resource lists are the same.
    bool operator==(const ResourceList& rhs) const;

    // Add or Update an entry into ResourceList.
    void addOrUpdate(const ::aidl::android::media::MediaResourceParcel& res);
    // END: Test only function

private:
    std::vector<::aidl::android::media::MediaResourceParcel> mResourceList;
};

// Encapsulation for Resource Info, that contains
// - pid of the app
+4 −4
Original line number Diff line number Diff line
@@ -286,9 +286,9 @@ void ResourceObserverService::notifyObservers(
    {
        std::scoped_lock lock{mObserverLock};

        for (auto &res : resources) {
        for (const MediaResourceParcel& res : resources.getResources()) {
            // Skip if this resource doesn't map to any observable type.
            MediaObservableType observableType = getObservableType(res.second);
            MediaObservableType observableType = getObservableType(res);
            if (observableType == MediaObservableType::kInvalid) {
                continue;
            }
@@ -303,9 +303,9 @@ void ResourceObserverService::notifyObservers(
                auto calleeIt = calleeList.find(subscriber.first);
                if (calleeIt == calleeList.end()) {
                    calleeList.emplace(subscriber.first, CalleeInfo{
                        subscriber.second, {{observableType, res.second.value}}});
                        subscriber.second, {{observableType, res.value}}});
                } else {
                    calleeIt->second.monitors.push_back({observableType, res.second.value});
                    calleeIt->second.monitors.push_back({observableType, res.value});
                }
            }
        }
+31 −56
Original line number Diff line number Diff line
@@ -39,12 +39,12 @@ static bool hasResourceType(MediaResource::Type type, MediaResource::SubType sub
    bool foundResource = false;
    bool matchedPrimary =
        (primarySubType == MediaResource::SubType::kUnspecifiedSubType) ?  true : false;
    for (auto it = resources.begin(); it != resources.end(); it++) {
        if (hasResourceType(type, subType, it->second)) {
    for (const MediaResourceParcel& res : resources.getResources()) {
        if (hasResourceType(type, subType, res)) {
            foundResource = true;
        } else if (it->second.subType == primarySubType) {
        } else if (res.subType == primarySubType) {
            matchedPrimary = true;
        } else if (isHwCodec(it->second.subType) == isHwCodec(primarySubType)) {
        } else if (isHwCodec(res.subType) == isHwCodec(primarySubType)) {
            matchedPrimary = true;
        }
        if (matchedPrimary && foundResource) {
@@ -111,31 +111,20 @@ bool ResourceTracker::addResource(const ClientInfoParcel& clientInfo,
    ResourceList resourceAdded;

    for (const MediaResourceParcel& res : resources) {
        const auto resType = std::tuple(res.type, res.subType, res.id);

        if (res.value < 0 && res.type != MediaResource::Type::kDrmSession) {
            ALOGV("%s: Ignoring request to remove negative value of non-drm resource", __func__);
            continue;
        }
        if (info.resources.find(resType) == info.resources.end()) {
            if (res.value <= 0) {
                // We can't init a new entry with negative value, although it's allowed
                // to merge in negative values after the initial add.
                ALOGV("%s: Ignoring request to add new resource entry with value <= 0", __func__);
        bool isNewEntry = false;
        if (!info.resources.add(res, &isNewEntry)) {
            continue;
        }
        if (isNewEntry) {
            onFirstAdded(res, info.uid);
            info.resources[resType] = res;
        } else {
            mergeResources(info.resources[resType], res);
        }

        // Add it to the list of added resources for observers.
        auto it = resourceAdded.find(resType);
        if (it == resourceAdded.end()) {
            resourceAdded[resType] = res;
        } else {
            mergeResources(it->second, res);
        }
        resourceAdded.add(res);
    }
    if (info.deathNotifier == nullptr && client != nullptr) {
        info.deathNotifier = DeathNotifier::Create(client, mService, clientInfo);
@@ -186,31 +175,21 @@ bool ResourceTracker::removeResource(const ClientInfoParcel& clientInfo,
    ResourceInfo& info = foundClient->second;
    ResourceList resourceRemoved;
    for (const MediaResourceParcel& res : resources) {
        const auto resType = std::tuple(res.type, res.subType, res.id);

        if (res.value < 0) {
            ALOGV("%s: Ignoring request to remove negative value of resource", __func__);
            continue;
        }
        // ignore if we don't have it
        if (info.resources.find(resType) != info.resources.end()) {
            MediaResourceParcel& resource = info.resources[resType];

        long removedEntryValue = -1;
        if (info.resources.remove(res, &removedEntryValue)) {
            MediaResourceParcel actualRemoved = res;
            if (resource.value > res.value) {
                resource.value -= res.value;
            } else {
            if (removedEntryValue != -1) {
                onLastRemoved(res, info.uid);
                actualRemoved.value = resource.value;
                info.resources.erase(resType);
                actualRemoved.value = removedEntryValue;
            }

            // Add it to the list of removed resources for observers.
            auto it = resourceRemoved.find(resType);
            if (it == resourceRemoved.end()) {
                resourceRemoved[resType] = actualRemoved;
            } else {
                mergeResources(it->second, actualRemoved);
            }
            resourceRemoved.add(actualRemoved);
        }
    }
    if (mObserverService != nullptr && !resourceRemoved.empty()) {
@@ -243,8 +222,8 @@ bool ResourceTracker::removeResource(const ClientInfoParcel& clientInfo, bool va
    }

    const ResourceInfo& info = foundClient->second;
    for (auto& [resType, resParcel] : info.resources) {
        onLastRemoved(resParcel, info.uid);
    for (const MediaResourceParcel& res : info.resources.getResources()) {
        onLastRemoved(res, info.uid);
    }

    if (mObserverService != nullptr && !info.resources.empty()) {
@@ -523,8 +502,7 @@ bool ResourceTracker::getBiggestClientPendingRemoval(int pid, MediaResource::Typ
        if (!info.pendingRemoval) {
            continue;
        }
        for (auto it = resources.begin(); it != resources.end(); it++) {
            const MediaResourceParcel& resource = it->second;
        for (const MediaResourceParcel& resource : resources.getResources()) {
            if (hasResourceType(type, subType, resource)) {
                if (resource.value > largestValue) {
                    largestValue = resource.value;
@@ -567,19 +545,20 @@ bool ResourceTracker::getBiggestClient(int targetPid,
        const ResourceList& resources = info->resources;
        bool matchedPrimary =
            (primarySubType == MediaResource::SubType::kUnspecifiedSubType) ?  true : false;
        for (auto it = resources.begin(); !matchedPrimary && it != resources.end(); it++) {
            if (it->second.subType == primarySubType) {
        for (const MediaResourceParcel& resource : resources.getResources()) {
            if (resource.subType == primarySubType) {
                matchedPrimary = true;
            } else if (isHwCodec(it->second.subType) == isHwCodec(primarySubType)) {
                break;
            } else if (isHwCodec(resource.subType) == isHwCodec(primarySubType)) {
                matchedPrimary = true;
                break;
            }
        }
        // Primary type doesn't match, skip the client
        if (!matchedPrimary) {
            continue;
        }
        for (auto it = resources.begin(); it != resources.end(); it++) {
            const MediaResourceParcel& resource = it->second;
        for (const MediaResourceParcel& resource : resources.getResources()) {
            if (hasResourceType(type, subType, resource)) {
                if (resource.value > largestValue) {
                    largestValue = resource.value;
@@ -629,10 +608,10 @@ bool ResourceTracker::getLeastImportantBiggestClient(int targetPid, int32_t impo
        const ResourceList& resources = info->resources;
        bool matchedPrimary =
            (primarySubType == MediaResource::SubType::kUnspecifiedSubType) ?  true : false;
        for (auto it = resources.begin(); !matchedPrimary && it != resources.end(); it++) {
            if (it->second.subType == primarySubType) {
        for (const MediaResourceParcel& resource : resources.getResources()) {
            if (resource.subType == primarySubType) {
                matchedPrimary = true;
            } else if (isHwCodec(it->second.subType) == isHwCodec(primarySubType)) {
            } else if (isHwCodec(resource.subType) == isHwCodec(primarySubType)) {
                matchedPrimary = true;
            }
        }
@@ -640,8 +619,7 @@ bool ResourceTracker::getLeastImportantBiggestClient(int targetPid, int32_t impo
        if (!matchedPrimary) {
            continue;
        }
        for (auto it = resources.begin(); it != resources.end(); it++) {
            const MediaResourceParcel& resource = it->second;
        for (const MediaResourceParcel& resource : resources.getResources()) {
            if (hasResourceType(type, subType, resource)) {
                if (resource.value > largestValue) {
                    largestValue = resource.value;
@@ -690,10 +668,7 @@ void ResourceTracker::dump(std::string& resourceLogs) {

            const ResourceList& resources = info.resources;
            resourceLogs.append("        Resources:\n");
            for (auto it = resources.begin(); it != resources.end(); it++) {
                snprintf(buffer, SIZE, "          %s\n", toString(it->second).c_str());
                resourceLogs.append(buffer);
            }
            resourceLogs.append(resources.toString());
        }
    }
    resourceLogs.append("  Process Pid override:\n");
Loading