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
diff --git a/services/mediaresourcemanager/ResourceManagerService.cpp b/services/mediaresourcemanager/ResourceManagerService.cpp
index 2bcfe27..3a79fa0 100644
--- a/services/mediaresourcemanager/ResourceManagerService.cpp
+++ b/services/mediaresourcemanager/ResourceManagerService.cpp
@@ -74,10 +74,7 @@
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 @@
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");
- continue;
- }
+ 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 @@
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 @@
}
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 @@
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;
diff --git a/services/mediaresourcemanager/ResourceManagerServiceUtils.cpp b/services/mediaresourcemanager/ResourceManagerServiceUtils.cpp
index 4d6184d..679ab13 100644
--- a/services/mediaresourcemanager/ResourceManagerServiceUtils.cpp
+++ b/services/mediaresourcemanager/ResourceManagerServiceUtils.cpp
@@ -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 @@
// 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;
}
}
diff --git a/services/mediaresourcemanager/ResourceManagerServiceUtils.h b/services/mediaresourcemanager/ResourceManagerServiceUtils.h
index 7e336e3..32cb219 100644
--- a/services/mediaresourcemanager/ResourceManagerServiceUtils.h
+++ b/services/mediaresourcemanager/ResourceManagerServiceUtils.h
@@ -19,6 +19,7 @@
#define ANDROID_MEDIA_RESOURCEMANAGERSERVICEUTILS_H_
#include <map>
+#include <set>
#include <memory>
#include <vector>
@@ -99,10 +100,47 @@
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
diff --git a/services/mediaresourcemanager/ResourceObserverService.cpp b/services/mediaresourcemanager/ResourceObserverService.cpp
index 72e249f..21e61e9 100644
--- a/services/mediaresourcemanager/ResourceObserverService.cpp
+++ b/services/mediaresourcemanager/ResourceObserverService.cpp
@@ -286,9 +286,9 @@
{
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 @@
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});
}
}
}
diff --git a/services/mediaresourcemanager/ResourceTracker.cpp b/services/mediaresourcemanager/ResourceTracker.cpp
index 3ec3dc8..22381c3 100644
--- a/services/mediaresourcemanager/ResourceTracker.cpp
+++ b/services/mediaresourcemanager/ResourceTracker.cpp
@@ -39,12 +39,12 @@
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 @@
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__);
- continue;
- }
+ 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 @@
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 @@
}
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 @@
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 @@
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 @@
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 @@
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 @@
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");
diff --git a/services/mediaresourcemanager/test/ResourceManagerServiceTestUtils.h b/services/mediaresourcemanager/test/ResourceManagerServiceTestUtils.h
index aa3a944..7e8a4a0 100644
--- a/services/mediaresourcemanager/test/ResourceManagerServiceTestUtils.h
+++ b/services/mediaresourcemanager/test/ResourceManagerServiceTestUtils.h
@@ -245,9 +245,7 @@
// convert resource1 to ResourceList
ResourceList r1;
for (size_t i = 0; i < resources1.size(); ++i) {
- const auto &res = resources1[i];
- const auto resType = std::tuple(res.type, res.subType, res.id);
- r1[resType] = res;
+ r1.addOrUpdate(resources1[i]);
}
return r1 == resources2;
}
diff --git a/services/mediaresourcemanager/test/ResourceManagerService_test.cpp b/services/mediaresourcemanager/test/ResourceManagerService_test.cpp
index 3f11d59..b3a0932 100644
--- a/services/mediaresourcemanager/test/ResourceManagerService_test.cpp
+++ b/services/mediaresourcemanager/test/ResourceManagerService_test.cpp
@@ -209,7 +209,6 @@
resources1.clear();
resources1.push_back(MediaResource(MediaResource::Type::kDrmSession, INT64_MIN));
- expected.push_back(MediaResource(MediaResource::Type::kNonSecureCodec, INT64_MIN));
mService->addResource(client1Info, mTestClient1, resources1);
// Expected result: