resourcemanager: define resource model
This change:
- defines a resource model interface
- defines a base resource model that implements the current (default) resource model
- integrates the resource model with the resource manager service
This change allows extending or replacing the resource models in the future.
Bug: 294886363
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: Ifbdd3de90bf9fc5e21f2e1eaa9993dcc0983810a
diff --git a/services/mediaresourcemanager/ResourceManagerServiceNew.cpp b/services/mediaresourcemanager/ResourceManagerServiceNew.cpp
index 045aa3d..a819237 100644
--- a/services/mediaresourcemanager/ResourceManagerServiceNew.cpp
+++ b/services/mediaresourcemanager/ResourceManagerServiceNew.cpp
@@ -18,7 +18,10 @@
//#define LOG_NDEBUG 0
#define LOG_TAG "ResourceManagerServiceNew"
#include <utils/Log.h>
+#include <binder/IPCThreadState.h>
+#include <mediautils/ProcessInfo.h>
+#include "DefaultResourceModel.h"
#include "ResourceManagerServiceNew.h"
#include "ResourceTracker.h"
#include "ServiceLog.h"
@@ -36,10 +39,29 @@
// Create the Resource Tracker
mResourceTracker = std::make_shared<ResourceTracker>(ref<ResourceManagerServiceNew>(),
mProcessInfo);
+ setUpResourceModels();
+}
+
+void ResourceManagerServiceNew::setUpResourceModels() {
+ std::scoped_lock lock{mLock};
+ // Create/Configure the default resource model.
+ if (mDefaultResourceModel == nullptr) {
+ mDefaultResourceModel = std::make_unique<DefaultResourceModel>(
+ mResourceTracker,
+ mSupportsMultipleSecureCodecs,
+ mSupportsSecureWithNonSecureCodec);
+ } else {
+ DefaultResourceModel* resourceModel =
+ static_cast<DefaultResourceModel*>(mDefaultResourceModel.get());
+ resourceModel->config(mSupportsMultipleSecureCodecs, mSupportsSecureWithNonSecureCodec);
+ }
}
Status ResourceManagerServiceNew::config(const std::vector<MediaResourcePolicyParcel>& policies) {
- return ResourceManagerService::config(policies);
+ Status status = ResourceManagerService::config(policies);
+ // Change in the config dictates update to the resource model.
+ setUpResourceModels();
+ return status;
}
void ResourceManagerServiceNew::setObserverService(
@@ -194,6 +216,120 @@
return ResourceManagerService::dump(fd, args, numArgs);
}
+bool ResourceManagerServiceNew::getTargetClients(
+ int callingPid,
+ const std::vector<MediaResourceParcel>& resources,
+ std::vector<ClientInfo>& targetClients) {
+ std::scoped_lock lock{mLock};
+ if (!mProcessInfo->isPidTrusted(callingPid)) {
+ pid_t actualCallingPid = IPCThreadState::self()->getCallingPid();
+ ALOGW("%s called with untrusted pid %d, using actual calling pid %d", __FUNCTION__,
+ callingPid, actualCallingPid);
+ callingPid = actualCallingPid;
+ }
+
+ // Use the Resource Model to get a list of all the clients that hold the
+ // needed/requested resources.
+ ReclaimRequestInfo reclaimRequestInfo{callingPid, resources};
+ std::vector<ClientInfo> clients;
+ if (!mDefaultResourceModel->getAllClients(reclaimRequestInfo, clients)) {
+ if (clients.empty()) {
+ ALOGI("%s: There aren't any clients with given resources. Nothing to reclaim",
+ __func__);
+ return false;
+ }
+ // Since there was a conflict, we need to reclaim all elements.
+ targetClients = std::move(clients);
+ } else {
+ getClientForResource_l(reclaimRequestInfo, clients, targetClients);
+ }
+ return !targetClients.empty();
+}
+
+void ResourceManagerServiceNew::getClientForResource_l(
+ const ReclaimRequestInfo& reclaimRequestInfo,
+ const std::vector<ClientInfo>& clients,
+ std::vector<ClientInfo>& targetClients) {
+ int callingPid = reclaimRequestInfo.mCallingPid;
+
+ // Before looking into other processes, check if we have clients marked for
+ // pending removal in the same process.
+ ClientInfo targetClient;
+ for (const MediaResourceParcel& resource : reclaimRequestInfo.mResources) {
+ if (mResourceTracker->getBiggestClientPendingRemoval(callingPid, resource.type,
+ resource.subType, targetClient)) {
+ targetClients.emplace_back(targetClient);
+ return;
+ }
+ }
+
+ // Now find client(s) from a lowest priority process that has needed resources.
+ ResourceRequestInfo resourceRequestInfo {callingPid, nullptr};
+ for (const MediaResourceParcel& resource : reclaimRequestInfo.mResources) {
+ resourceRequestInfo.mResource = &resource;
+ if (getLowestPriorityProcessBiggestClient_l(resourceRequestInfo, clients, targetClient)) {
+ targetClients.emplace_back(targetClient);
+ return;
+ }
+ }
+}
+
+// Process priority (oom score) based reclaim:
+// - Find a process with lowest priority (than that of calling process).
+// - Find the bigegst client (with required resources) from that process.
+bool ResourceManagerServiceNew::getLowestPriorityProcessBiggestClient_l(
+ const ResourceRequestInfo& resourceRequestInfo,
+ const std::vector<ClientInfo>& clients,
+ ClientInfo& clientInfo) {
+ int callingPid = resourceRequestInfo.mCallingPid;
+ MediaResource::Type type = resourceRequestInfo.mResource->type;
+ MediaResource::SubType subType = resourceRequestInfo.mResource->subType;
+ int lowestPriorityPid;
+ int lowestPriority;
+ int callingPriority;
+
+ if (!mResourceTracker->getPriority(callingPid, &callingPriority)) {
+ ALOGE("%s: can't get process priority for pid %d", __func__, callingPid);
+ return false;
+ }
+
+ // Find the lowest priority process among all the clients.
+ if (!mResourceTracker->getLowestPriorityPid(clients, lowestPriorityPid, lowestPriority)) {
+ ALOGE("%s: can't find a process with lower priority than that of the process[%d:%d]",
+ __func__, callingPid, callingPriority);
+ return false;
+ }
+
+ if (lowestPriority <= callingPriority) {
+ ALOGE("%s: lowest priority %d vs caller priority %d",
+ __func__, lowestPriority, callingPriority);
+ return false;
+ }
+
+ // Get the biggest client from this process.
+ if (!mResourceTracker->getBiggestClient(lowestPriorityPid, type, subType, clientInfo)) {
+ return false;
+ }
+
+ ALOGI("%s: CallingProcess(%d:%d) will reclaim from the lowestPriorityProcess(%d:%d)",
+ __func__, callingPid, callingPriority, lowestPriorityPid, lowestPriority);
+ return true;
+}
+
+bool ResourceManagerServiceNew::getLowestPriorityBiggestClient_l(
+ const ResourceRequestInfo& resourceRequestInfo,
+ ClientInfo& clientInfo) {
+ //NOTE: This function is used only by the test: ResourceManagerServiceTest
+ if (resourceRequestInfo.mResource == nullptr) {
+ return false;
+ }
+ std::vector<MediaResourceParcel> resources{*resourceRequestInfo.mResource};
+ ReclaimRequestInfo reclaimRequestInfo{resourceRequestInfo.mCallingPid, resources};
+ std::vector<ClientInfo> clients;
+ mDefaultResourceModel->getAllClients(reclaimRequestInfo, clients);
+ return getLowestPriorityProcessBiggestClient_l(resourceRequestInfo, clients, clientInfo);
+}
+
bool ResourceManagerServiceNew::getPriority_l(int pid, int* priority) const {
return mResourceTracker->getPriority(pid, priority);
}
@@ -201,22 +337,18 @@
bool ResourceManagerServiceNew::getLowestPriorityPid_l(
MediaResource::Type type, MediaResource::SubType subType,
int* lowestPriorityPid, int* lowestPriority) {
+ //NOTE: This function is used only by the test: ResourceManagerServiceTest
return mResourceTracker->getLowestPriorityPid(type, subType,
*lowestPriorityPid,
*lowestPriority);
}
-bool ResourceManagerServiceNew::getBiggestClient_l(int pid, MediaResource::Type type,
- MediaResource::SubType subType, ClientInfo& clientInfo, bool pendingRemovalOnly) {
- return mResourceTracker->getBiggestClient(pid, type, subType,
- clientInfo, pendingRemovalOnly);
-}
-
bool ResourceManagerServiceNew::getAllClients_l(
const ResourceRequestInfo& resourceRequestInfo,
std::vector<ClientInfo>& clientsInfo) {
+ //NOTE: This function is used only by the test: ResourceManagerServiceTest
MediaResource::Type type = resourceRequestInfo.mResource->type;
- // Get list of all the clients that has requested resources.
+ // Get the list of all clients that has requested resources.
std::vector<ClientInfo> clients;
mResourceTracker->getAllClients(resourceRequestInfo, clients);