summaryrefslogtreecommitdiffstats
path: root/services/mediaresourcemanager
diff options
context:
space:
mode:
authorRonghua Wu <ronghuawu@google.com>2015-03-11 15:10:32 -0700
committerRonghua Wu <ronghuawu@google.com>2015-03-23 17:02:28 -0700
commit231c3d169ad029689f9d688b68179af7e96b8d78 (patch)
tree09dbf8d4dc47f5698c08190f498357b455a396c7 /services/mediaresourcemanager
parent84b784dd4f340331d36b1be3de05a6c814d9795c (diff)
downloadframeworks_av-231c3d169ad029689f9d688b68179af7e96b8d78.zip
frameworks_av-231c3d169ad029689f9d688b68179af7e96b8d78.tar.gz
frameworks_av-231c3d169ad029689f9d688b68179af7e96b8d78.tar.bz2
media: add ResourceManagerService
Bug: 19620911 Change-Id: Iea173d310d31781bc50effe3d9bd6553cb5139eb
Diffstat (limited to 'services/mediaresourcemanager')
-rw-r--r--services/mediaresourcemanager/Android.mk18
-rw-r--r--services/mediaresourcemanager/ResourceManagerService.cpp345
-rw-r--r--services/mediaresourcemanager/ResourceManagerService.h106
-rw-r--r--services/mediaresourcemanager/test/Android.mk25
-rw-r--r--services/mediaresourcemanager/test/ResourceManagerService_test.cpp464
5 files changed, 958 insertions, 0 deletions
diff --git a/services/mediaresourcemanager/Android.mk b/services/mediaresourcemanager/Android.mk
new file mode 100644
index 0000000..84218cf
--- /dev/null
+++ b/services/mediaresourcemanager/Android.mk
@@ -0,0 +1,18 @@
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := ResourceManagerService.cpp
+
+LOCAL_SHARED_LIBRARIES := libmedia libstagefright libbinder libutils liblog
+
+LOCAL_MODULE:= libresourcemanagerservice
+
+LOCAL_32_BIT_ONLY := true
+
+LOCAL_C_INCLUDES += \
+ $(TOPDIR)frameworks/av/include
+
+include $(BUILD_SHARED_LIBRARY)
+
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/services/mediaresourcemanager/ResourceManagerService.cpp b/services/mediaresourcemanager/ResourceManagerService.cpp
new file mode 100644
index 0000000..7296d47
--- /dev/null
+++ b/services/mediaresourcemanager/ResourceManagerService.cpp
@@ -0,0 +1,345 @@
+/*
+**
+** Copyright 2015, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "ResourceManagerService"
+#include <utils/Log.h>
+
+#include <binder/IServiceManager.h>
+#include <dirent.h>
+#include <media/stagefright/ProcessInfo.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <unistd.h>
+
+#include "ResourceManagerService.h"
+
+namespace android {
+
+template <typename T>
+static String8 getString(const Vector<T> &items) {
+ String8 itemsStr;
+ for (size_t i = 0; i < items.size(); ++i) {
+ itemsStr.appendFormat("%s ", items[i].toString().string());
+ }
+ return itemsStr;
+}
+
+static bool hasResourceType(String8 type, Vector<MediaResource> resources) {
+ for (size_t i = 0; i < resources.size(); ++i) {
+ if (resources[i].mType == type) {
+ return true;
+ }
+ }
+ return false;
+}
+
+static bool hasResourceType(String8 type, ResourceInfos infos) {
+ for (size_t i = 0; i < infos.size(); ++i) {
+ if (hasResourceType(type, infos[i].resources)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+static ResourceInfos& getResourceInfosForEdit(
+ int pid,
+ PidResourceInfosMap& map) {
+ ssize_t index = map.indexOfKey(pid);
+ if (index < 0) {
+ // new pid
+ ResourceInfos infosForPid;
+ map.add(pid, infosForPid);
+ }
+
+ return map.editValueFor(pid);
+}
+
+static ResourceInfo& getResourceInfoForEdit(
+ int64_t clientId,
+ const sp<IResourceManagerClient> client,
+ ResourceInfos& infos) {
+ for (size_t i = 0; i < infos.size(); ++i) {
+ if (infos[i].clientId == clientId) {
+ return infos.editItemAt(i);
+ }
+ }
+ ResourceInfo info;
+ info.clientId = clientId;
+ info.client = client;
+ infos.push_back(info);
+ return infos.editItemAt(infos.size() - 1);
+}
+
+ResourceManagerService::ResourceManagerService()
+ : mProcessInfo(new ProcessInfo()),
+ mSupportsMultipleSecureCodecs(true),
+ mSupportsSecureWithNonSecureCodec(true) {}
+
+ResourceManagerService::ResourceManagerService(sp<ProcessInfoInterface> processInfo)
+ : mProcessInfo(processInfo),
+ mSupportsMultipleSecureCodecs(true),
+ mSupportsSecureWithNonSecureCodec(true) {}
+
+ResourceManagerService::~ResourceManagerService() {}
+
+void ResourceManagerService::config(const Vector<MediaResourcePolicy> &policies) {
+ ALOGV("config(%s)", getString(policies).string());
+
+ Mutex::Autolock lock(mLock);
+ for (size_t i = 0; i < policies.size(); ++i) {
+ String8 type = policies[i].mType;
+ uint64_t value = policies[i].mValue;
+ if (type == kPolicySupportsMultipleSecureCodecs) {
+ mSupportsMultipleSecureCodecs = (value != 0);
+ } else if (type == kPolicySupportsSecureWithNonSecureCodec) {
+ mSupportsSecureWithNonSecureCodec = (value != 0);
+ }
+ }
+}
+
+void ResourceManagerService::addResource(
+ int pid,
+ int64_t clientId,
+ const sp<IResourceManagerClient> client,
+ const Vector<MediaResource> &resources) {
+ ALOGV("addResource(pid %d, clientId %lld, resources %s)",
+ pid, (long long) clientId, getString(resources).string());
+
+ Mutex::Autolock lock(mLock);
+ ResourceInfos& infos = getResourceInfosForEdit(pid, mMap);
+ ResourceInfo& info = getResourceInfoForEdit(clientId, client, infos);
+ info.resources.appendVector(resources);
+}
+
+void ResourceManagerService::removeResource(int64_t clientId) {
+ ALOGV("removeResource(%lld)", (long long) clientId);
+
+ Mutex::Autolock lock(mLock);
+ bool found = false;
+ for (size_t i = 0; i < mMap.size(); ++i) {
+ ResourceInfos &infos = mMap.editValueAt(i);
+ for (size_t j = 0; j < infos.size();) {
+ if (infos[j].clientId == clientId) {
+ j = infos.removeAt(j);
+ found = true;
+ } else {
+ ++j;
+ }
+ }
+ if (found) {
+ break;
+ }
+ }
+ if (!found) {
+ ALOGV("didn't find client");
+ }
+}
+
+bool ResourceManagerService::reclaimResource(
+ int callingPid, const Vector<MediaResource> &resources) {
+ ALOGV("reclaimResource(callingPid %d, resources %s)",
+ callingPid, getString(resources).string());
+
+ Vector<sp<IResourceManagerClient>> clients;
+ {
+ Mutex::Autolock lock(mLock);
+ // first pass to handle secure/non-secure codec conflict
+ for (size_t i = 0; i < resources.size(); ++i) {
+ String8 type = resources[i].mType;
+ if (type == kResourceSecureCodec) {
+ if (!mSupportsMultipleSecureCodecs) {
+ if (!getAllClients_l(callingPid, String8(kResourceSecureCodec), &clients)) {
+ return false;
+ }
+ }
+ if (!mSupportsSecureWithNonSecureCodec) {
+ if (!getAllClients_l(callingPid, String8(kResourceNonSecureCodec), &clients)) {
+ return false;
+ }
+ }
+ } else if (type == kResourceNonSecureCodec) {
+ if (!mSupportsSecureWithNonSecureCodec) {
+ if (!getAllClients_l(callingPid, String8(kResourceSecureCodec), &clients)) {
+ return false;
+ }
+ }
+ }
+ }
+
+ if (clients.size() == 0) {
+ // if no secure/non-secure codec conflict, run second pass to handle other resources.
+ for (size_t i = 0; i < resources.size(); ++i) {
+ String8 type = resources[i].mType;
+ if (type == kResourceGraphicMemory) {
+ sp<IResourceManagerClient> client;
+ if (!getLowestPriorityBiggestClient_l(callingPid, type, &client)) {
+ return false;
+ }
+ clients.push_back(client);
+ }
+ }
+ }
+ }
+
+ if (clients.size() == 0) {
+ return false;
+ }
+
+ for (size_t i = 0; i < clients.size(); ++i) {
+ ALOGV("reclaimResource from client %p", clients[i].get());
+ if (!clients[i]->reclaimResource()) {
+ return false;
+ }
+ }
+ return true;
+}
+
+bool ResourceManagerService::getAllClients_l(
+ int callingPid, const String8 &type, Vector<sp<IResourceManagerClient>> *clients) {
+ Vector<sp<IResourceManagerClient>> temp;
+ for (size_t i = 0; i < mMap.size(); ++i) {
+ ResourceInfos &infos = mMap.editValueAt(i);
+ for (size_t j = 0; j < infos.size(); ++j) {
+ if (hasResourceType(type, infos[j].resources)) {
+ if (!isCallingPriorityHigher_l(callingPid, mMap.keyAt(i))) {
+ // some higher/equal priority process owns the resource,
+ // this request can't be fulfilled.
+ ALOGE("getAllClients_l: can't reclaim resource %s from pid %d",
+ type.string(), mMap.keyAt(i));
+ return false;
+ }
+ temp.push_back(infos[j].client);
+ }
+ }
+ }
+ if (temp.size() == 0) {
+ ALOGV("getAllClients_l: didn't find any resource %s", type.string());
+ return true;
+ }
+ clients->appendVector(temp);
+ return true;
+}
+
+bool ResourceManagerService::getLowestPriorityBiggestClient_l(
+ int callingPid, const String8 &type, sp<IResourceManagerClient> *client) {
+ int lowestPriorityPid;
+ int lowestPriority;
+ int callingPriority;
+ if (!mProcessInfo->getPriority(callingPid, &callingPriority)) {
+ ALOGE("getLowestPriorityBiggestClient_l: can't get process priority for pid %d",
+ callingPid);
+ return false;
+ }
+ if (!getLowestPriorityPid_l(type, &lowestPriorityPid, &lowestPriority)) {
+ return false;
+ }
+ if (lowestPriority <= callingPriority) {
+ ALOGE("getLowestPriorityBiggestClient_l: lowest priority %d vs caller priority %d",
+ lowestPriority, callingPriority);
+ return false;
+ }
+
+ if (!getBiggestClient_l(lowestPriorityPid, type, client)) {
+ return false;
+ }
+ return true;
+}
+
+bool ResourceManagerService::getLowestPriorityPid_l(
+ const String8 &type, int *lowestPriorityPid, int *lowestPriority) {
+ int pid = -1;
+ int priority = -1;
+ for (size_t i = 0; i < mMap.size(); ++i) {
+ if (mMap.valueAt(i).size() == 0) {
+ // no client on this process.
+ continue;
+ }
+ if (!hasResourceType(type, mMap.valueAt(i))) {
+ // doesn't have the requested resource type
+ continue;
+ }
+ int tempPid = mMap.keyAt(i);
+ int tempPriority;
+ if (!mProcessInfo->getPriority(tempPid, &tempPriority)) {
+ ALOGV("getLowestPriorityPid_l: can't get priority of pid %d, skipped", tempPid);
+ // TODO: remove this pid from mMap?
+ continue;
+ }
+ if (pid == -1 || tempPriority > priority) {
+ // initial the value
+ pid = tempPid;
+ priority = tempPriority;
+ }
+ }
+ if (pid != -1) {
+ *lowestPriorityPid = pid;
+ *lowestPriority = priority;
+ }
+ return (pid != -1);
+}
+
+bool ResourceManagerService::isCallingPriorityHigher_l(int callingPid, int pid) {
+ int callingPidPriority;
+ if (!mProcessInfo->getPriority(callingPid, &callingPidPriority)) {
+ return false;
+ }
+
+ int priority;
+ if (!mProcessInfo->getPriority(pid, &priority)) {
+ return false;
+ }
+
+ return (callingPidPriority < priority);
+}
+
+bool ResourceManagerService::getBiggestClient_l(
+ int pid, const String8 &type, sp<IResourceManagerClient> *client) {
+ ssize_t index = mMap.indexOfKey(pid);
+ if (index < 0) {
+ ALOGE("getBiggestClient_l: can't find resource info for pid %d", pid);
+ return false;
+ }
+
+ sp<IResourceManagerClient> clientTemp;
+ uint64_t largestValue = 0;
+ const ResourceInfos &infos = mMap.valueAt(index);
+ for (size_t i = 0; i < infos.size(); ++i) {
+ Vector<MediaResource> resources = infos[i].resources;
+ for (size_t j = 0; j < resources.size(); ++j) {
+ if (resources[j].mType == type) {
+ if (resources[j].mValue > largestValue) {
+ largestValue = resources[j].mValue;
+ clientTemp = infos[i].client;
+ }
+ }
+ }
+ }
+
+ if (clientTemp == NULL) {
+ ALOGE("getBiggestClient_l: can't find resource type %s for pid %d", type.string(), pid);
+ return false;
+ }
+
+ *client = clientTemp;
+ return true;
+}
+
+} // namespace android
diff --git a/services/mediaresourcemanager/ResourceManagerService.h b/services/mediaresourcemanager/ResourceManagerService.h
new file mode 100644
index 0000000..2ed9bf8
--- /dev/null
+++ b/services/mediaresourcemanager/ResourceManagerService.h
@@ -0,0 +1,106 @@
+/*
+**
+** Copyright 2015, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#ifndef ANDROID_RESOURCEMANAGERSERVICE_H
+#define ANDROID_RESOURCEMANAGERSERVICE_H
+
+#include <arpa/inet.h>
+#include <binder/BinderService.h>
+#include <utils/Errors.h>
+#include <utils/KeyedVector.h>
+#include <utils/String8.h>
+#include <utils/threads.h>
+#include <utils/Vector.h>
+
+#include <media/IResourceManagerService.h>
+
+namespace android {
+
+struct ProcessInfoInterface;
+
+struct ResourceInfo {
+ int64_t clientId;
+ sp<IResourceManagerClient> client;
+ Vector<MediaResource> resources;
+};
+
+typedef Vector<ResourceInfo> ResourceInfos;
+typedef KeyedVector<int, ResourceInfos> PidResourceInfosMap;
+
+class ResourceManagerService
+ : public BinderService<ResourceManagerService>,
+ public BnResourceManagerService
+{
+public:
+ static char const *getServiceName() { return "media.resource_manager"; }
+
+ ResourceManagerService();
+ ResourceManagerService(sp<ProcessInfoInterface> processInfo);
+
+ // IResourceManagerService interface
+ virtual void config(const Vector<MediaResourcePolicy> &policies);
+
+ virtual void addResource(
+ int pid,
+ int64_t clientId,
+ const sp<IResourceManagerClient> client,
+ const Vector<MediaResource> &resources);
+
+ virtual void removeResource(int64_t clientId);
+
+ virtual bool reclaimResource(int callingPid, const Vector<MediaResource> &resources);
+
+protected:
+ virtual ~ResourceManagerService();
+
+private:
+ friend class ResourceManagerServiceTest;
+
+ // Gets the list of all the clients who own the specified resource type.
+ // Returns false if any client belongs to a process with higher priority than the
+ // calling process. The clients will remain unchanged if returns false.
+ bool getAllClients_l(int callingPid, const String8 &type,
+ Vector<sp<IResourceManagerClient>> *clients);
+
+ // Gets the client who owns specified resource type from lowest possible priority process.
+ // Returns false if the calling process priority is not higher than the lowest process
+ // priority. The client will remain unchanged if returns false.
+ bool getLowestPriorityBiggestClient_l(int callingPid, const String8 &type,
+ sp<IResourceManagerClient> *client);
+
+ // Gets lowest priority process that has the specified resource type.
+ // Returns false if failed. The output parameters will remain unchanged if failed.
+ bool getLowestPriorityPid_l(const String8 &type, int *pid, int *priority);
+
+ // Gets the client who owns biggest piece of specified resource type from pid.
+ // Returns false if failed. The client will remain unchanged if failed.
+ bool getBiggestClient_l(int pid, const String8 &type, sp<IResourceManagerClient> *client);
+
+ bool isCallingPriorityHigher_l(int callingPid, int pid);
+
+ mutable Mutex mLock;
+ sp<ProcessInfoInterface> mProcessInfo;
+ PidResourceInfosMap mMap;
+ bool mSupportsMultipleSecureCodecs;
+ bool mSupportsSecureWithNonSecureCodec;
+};
+
+// ----------------------------------------------------------------------------
+
+}; // namespace android
+
+#endif // ANDROID_RESOURCEMANAGERSERVICE_H
diff --git a/services/mediaresourcemanager/test/Android.mk b/services/mediaresourcemanager/test/Android.mk
new file mode 100644
index 0000000..228b62a
--- /dev/null
+++ b/services/mediaresourcemanager/test/Android.mk
@@ -0,0 +1,25 @@
+# Build the unit tests.
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := ResourceManagerService_test
+
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_SRC_FILES := \
+ ResourceManagerService_test.cpp \
+
+LOCAL_SHARED_LIBRARIES := \
+ libbinder \
+ liblog \
+ libmedia \
+ libresourcemanagerservice \
+ libutils \
+
+LOCAL_C_INCLUDES := \
+ frameworks/av/include \
+ frameworks/av/services/mediaresourcemanager \
+
+LOCAL_32_BIT_ONLY := true
+
+include $(BUILD_NATIVE_TEST)
diff --git a/services/mediaresourcemanager/test/ResourceManagerService_test.cpp b/services/mediaresourcemanager/test/ResourceManagerService_test.cpp
new file mode 100644
index 0000000..b73e1bc
--- /dev/null
+++ b/services/mediaresourcemanager/test/ResourceManagerService_test.cpp
@@ -0,0 +1,464 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "ResourceManagerService_test"
+#include <utils/Log.h>
+
+#include <gtest/gtest.h>
+
+#include "ResourceManagerService.h"
+#include <media/IResourceManagerService.h>
+#include <media/MediaResource.h>
+#include <media/MediaResourcePolicy.h>
+#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/ProcessInfoInterface.h>
+
+namespace android {
+
+struct TestProcessInfo : public ProcessInfoInterface {
+ TestProcessInfo() {}
+ virtual ~TestProcessInfo() {}
+
+ virtual bool getPriority(int pid, int *priority) {
+ // For testing, use pid as priority.
+ // Lower the value higher the priority.
+ *priority = pid;
+ return true;
+ }
+
+private:
+ DISALLOW_EVIL_CONSTRUCTORS(TestProcessInfo);
+};
+
+struct TestClient : public BnResourceManagerClient {
+ TestClient(sp<ResourceManagerService> service)
+ : mReclaimed(false), mService(service) {}
+
+ virtual bool reclaimResource() {
+ sp<IResourceManagerClient> client(this);
+ mService->removeResource((int64_t) client.get());
+ mReclaimed = true;
+ return true;
+ }
+
+ bool reclaimed() const {
+ return mReclaimed;
+ }
+
+ void reset() {
+ mReclaimed = false;
+ }
+
+protected:
+ virtual ~TestClient() {}
+
+private:
+ bool mReclaimed;
+ sp<ResourceManagerService> mService;
+ DISALLOW_EVIL_CONSTRUCTORS(TestClient);
+};
+
+static const int kTestPid1 = 30;
+static const int kTestPid2 = 20;
+
+class ResourceManagerServiceTest : public ::testing::Test {
+public:
+ ResourceManagerServiceTest()
+ : mService(new ResourceManagerService(new TestProcessInfo)),
+ mTestClient1(new TestClient(mService)),
+ mTestClient2(new TestClient(mService)),
+ mTestClient3(new TestClient(mService)) {
+ }
+
+protected:
+ static bool isEqualResources(const Vector<MediaResource> &resources1,
+ const Vector<MediaResource> &resources2) {
+ if (resources1.size() != resources2.size()) {
+ return false;
+ }
+ for (size_t i = 0; i < resources1.size(); ++i) {
+ if (resources1[i] != resources2[i]) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ static void expectEqResourceInfo(const ResourceInfo &info, sp<IResourceManagerClient> client,
+ const Vector<MediaResource> &resources) {
+ EXPECT_EQ(client, info.client);
+ EXPECT_TRUE(isEqualResources(resources, info.resources));
+ }
+
+ void verifyClients(bool c1, bool c2, bool c3) {
+ TestClient *client1 = static_cast<TestClient*>(mTestClient1.get());
+ TestClient *client2 = static_cast<TestClient*>(mTestClient2.get());
+ TestClient *client3 = static_cast<TestClient*>(mTestClient3.get());
+
+ EXPECT_EQ(c1, client1->reclaimed());
+ EXPECT_EQ(c2, client2->reclaimed());
+ EXPECT_EQ(c3, client3->reclaimed());
+
+ client1->reset();
+ client2->reset();
+ client3->reset();
+ }
+
+ void addResource() {
+ // kTestPid1 mTestClient1
+ Vector<MediaResource> resources1;
+ resources1.push_back(MediaResource(String8(kResourceSecureCodec), 1));
+ mService->addResource(kTestPid1, (int64_t) mTestClient1.get(), mTestClient1, resources1);
+ resources1.push_back(MediaResource(String8(kResourceGraphicMemory), 200));
+ Vector<MediaResource> resources11;
+ resources11.push_back(MediaResource(String8(kResourceGraphicMemory), 200));
+ mService->addResource(kTestPid1, (int64_t) mTestClient1.get(), mTestClient1, resources11);
+
+ // kTestPid2 mTestClient2
+ Vector<MediaResource> resources2;
+ resources2.push_back(MediaResource(String8(kResourceNonSecureCodec), 1));
+ resources2.push_back(MediaResource(String8(kResourceGraphicMemory), 300));
+ mService->addResource(kTestPid2, (int64_t) mTestClient2.get(), mTestClient2, resources2);
+
+ // kTestPid2 mTestClient3
+ Vector<MediaResource> resources3;
+ mService->addResource(kTestPid2, (int64_t) mTestClient3.get(), mTestClient3, resources3);
+ resources3.push_back(MediaResource(String8(kResourceSecureCodec), 1));
+ resources3.push_back(MediaResource(String8(kResourceGraphicMemory), 100));
+ mService->addResource(kTestPid2, (int64_t) mTestClient3.get(), mTestClient3, resources3);
+
+ const PidResourceInfosMap &map = mService->mMap;
+ EXPECT_EQ(2u, map.size());
+ ssize_t index1 = map.indexOfKey(kTestPid1);
+ ASSERT_GE(index1, 0);
+ const ResourceInfos &infos1 = map[index1];
+ EXPECT_EQ(1u, infos1.size());
+ expectEqResourceInfo(infos1[0], mTestClient1, resources1);
+
+ ssize_t index2 = map.indexOfKey(kTestPid2);
+ ASSERT_GE(index2, 0);
+ const ResourceInfos &infos2 = map[index2];
+ EXPECT_EQ(2u, infos2.size());
+ expectEqResourceInfo(infos2[0], mTestClient2, resources2);
+ expectEqResourceInfo(infos2[1], mTestClient3, resources3);
+ }
+
+ void testConfig() {
+ EXPECT_TRUE(mService->mSupportsMultipleSecureCodecs);
+ EXPECT_TRUE(mService->mSupportsSecureWithNonSecureCodec);
+
+ Vector<MediaResourcePolicy> policies1;
+ policies1.push_back(MediaResourcePolicy(String8(kPolicySupportsMultipleSecureCodecs), 1));
+ policies1.push_back(
+ MediaResourcePolicy(String8(kPolicySupportsSecureWithNonSecureCodec), 0));
+ mService->config(policies1);
+ EXPECT_TRUE(mService->mSupportsMultipleSecureCodecs);
+ EXPECT_FALSE(mService->mSupportsSecureWithNonSecureCodec);
+
+ Vector<MediaResourcePolicy> policies2;
+ policies2.push_back(MediaResourcePolicy(String8(kPolicySupportsMultipleSecureCodecs), 0));
+ policies2.push_back(
+ MediaResourcePolicy(String8(kPolicySupportsSecureWithNonSecureCodec), 1));
+ mService->config(policies2);
+ EXPECT_FALSE(mService->mSupportsMultipleSecureCodecs);
+ EXPECT_TRUE(mService->mSupportsSecureWithNonSecureCodec);
+ }
+
+ void testRemoveResource() {
+ addResource();
+
+ mService->removeResource((int64_t) mTestClient2.get());
+
+ const PidResourceInfosMap &map = mService->mMap;
+ EXPECT_EQ(2u, map.size());
+ const ResourceInfos &infos1 = map.valueFor(kTestPid1);
+ const ResourceInfos &infos2 = map.valueFor(kTestPid2);
+ EXPECT_EQ(1u, infos1.size());
+ EXPECT_EQ(1u, infos2.size());
+ // mTestClient2 has been removed.
+ EXPECT_EQ(mTestClient3, infos2[0].client);
+ }
+
+ void testGetAllClients() {
+ addResource();
+
+ String8 type = String8(kResourceSecureCodec);
+ String8 unknowType = String8("unknowType");
+ Vector<sp<IResourceManagerClient> > clients;
+ int lowPriorityPid = 100;
+ EXPECT_FALSE(mService->getAllClients_l(lowPriorityPid, type, &clients));
+ int midPriorityPid = 25;
+ EXPECT_FALSE(mService->getAllClients_l(lowPriorityPid, type, &clients));
+ int highPriorityPid = 10;
+ EXPECT_TRUE(mService->getAllClients_l(10, unknowType, &clients));
+ EXPECT_TRUE(mService->getAllClients_l(10, type, &clients));
+
+ EXPECT_EQ(2u, clients.size());
+ EXPECT_EQ(mTestClient3, clients[0]);
+ EXPECT_EQ(mTestClient1, clients[1]);
+ }
+
+ void testReclaimResourceSecure() {
+ Vector<MediaResource> resources;
+ resources.push_back(MediaResource(String8(kResourceSecureCodec), 1));
+ resources.push_back(MediaResource(String8(kResourceGraphicMemory), 150));
+
+ // ### secure codec can't coexist and secure codec can coexist with non-secure codec ###
+ {
+ addResource();
+ mService->mSupportsMultipleSecureCodecs = false;
+ mService->mSupportsSecureWithNonSecureCodec = true;
+
+ // priority too low
+ EXPECT_FALSE(mService->reclaimResource(40, resources));
+ EXPECT_FALSE(mService->reclaimResource(25, resources));
+
+ // reclaim all secure codecs
+ EXPECT_TRUE(mService->reclaimResource(10, resources));
+ verifyClients(true, false, true);
+
+ // call again should reclaim one largest graphic memory from lowest process
+ EXPECT_TRUE(mService->reclaimResource(10, resources));
+ verifyClients(false, true, false);
+
+ // nothing left
+ EXPECT_FALSE(mService->reclaimResource(10, resources));
+ }
+
+ // ### secure codecs can't coexist and secure codec can't coexist with non-secure codec ###
+ {
+ addResource();
+ mService->mSupportsMultipleSecureCodecs = false;
+ mService->mSupportsSecureWithNonSecureCodec = false;
+
+ // priority too low
+ EXPECT_FALSE(mService->reclaimResource(40, resources));
+ EXPECT_FALSE(mService->reclaimResource(25, resources));
+
+ // reclaim all secure and non-secure codecs
+ EXPECT_TRUE(mService->reclaimResource(10, resources));
+ verifyClients(true, true, true);
+
+ // nothing left
+ EXPECT_FALSE(mService->reclaimResource(10, resources));
+ }
+
+
+ // ### secure codecs can coexist but secure codec can't coexist with non-secure codec ###
+ {
+ addResource();
+ mService->mSupportsMultipleSecureCodecs = true;
+ mService->mSupportsSecureWithNonSecureCodec = false;
+
+ // priority too low
+ EXPECT_FALSE(mService->reclaimResource(40, resources));
+ EXPECT_FALSE(mService->reclaimResource(25, resources));
+
+ // reclaim all non-secure codecs
+ EXPECT_TRUE(mService->reclaimResource(10, resources));
+ verifyClients(false, true, false);
+
+ // call again should reclaim one largest graphic memory from lowest process
+ EXPECT_TRUE(mService->reclaimResource(10, resources));
+ verifyClients(true, false, false);
+
+ // call again should reclaim another largest graphic memory from lowest process
+ EXPECT_TRUE(mService->reclaimResource(10, resources));
+ verifyClients(false, false, true);
+
+ // nothing left
+ EXPECT_FALSE(mService->reclaimResource(10, resources));
+ }
+
+ // ### secure codecs can coexist and secure codec can coexist with non-secure codec ###
+ {
+ addResource();
+ mService->mSupportsMultipleSecureCodecs = true;
+ mService->mSupportsSecureWithNonSecureCodec = true;
+
+ // priority too low
+ EXPECT_FALSE(mService->reclaimResource(40, resources));
+
+ EXPECT_TRUE(mService->reclaimResource(10, resources));
+ // one largest graphic memory from lowest process got reclaimed
+ verifyClients(true, false, false);
+
+ // call again should reclaim another graphic memory from lowest process
+ EXPECT_TRUE(mService->reclaimResource(10, resources));
+ verifyClients(false, true, false);
+
+ // call again should reclaim another graphic memory from lowest process
+ EXPECT_TRUE(mService->reclaimResource(10, resources));
+ verifyClients(false, false, true);
+
+ // nothing left
+ EXPECT_FALSE(mService->reclaimResource(10, resources));
+ }
+ }
+
+ void testReclaimResourceNonSecure() {
+ Vector<MediaResource> resources;
+ resources.push_back(MediaResource(String8(kResourceNonSecureCodec), 1));
+ resources.push_back(MediaResource(String8(kResourceGraphicMemory), 150));
+
+ // ### secure codec can't coexist with non-secure codec ###
+ {
+ addResource();
+ mService->mSupportsSecureWithNonSecureCodec = false;
+
+ // priority too low
+ EXPECT_FALSE(mService->reclaimResource(40, resources));
+ EXPECT_FALSE(mService->reclaimResource(25, resources));
+
+ // reclaim all secure codecs
+ EXPECT_TRUE(mService->reclaimResource(10, resources));
+ verifyClients(true, false, true);
+
+ // call again should reclaim one graphic memory from lowest process
+ EXPECT_TRUE(mService->reclaimResource(10, resources));
+ verifyClients(false, true, false);
+
+ // nothing left
+ EXPECT_FALSE(mService->reclaimResource(10, resources));
+ }
+
+
+ // ### secure codec can coexist with non-secure codec ###
+ {
+ addResource();
+ mService->mSupportsSecureWithNonSecureCodec = true;
+
+ // priority too low
+ EXPECT_FALSE(mService->reclaimResource(40, resources));
+
+ EXPECT_TRUE(mService->reclaimResource(10, resources));
+ // one largest graphic memory from lowest process got reclaimed
+ verifyClients(true, false, false);
+
+ // call again should reclaim another graphic memory from lowest process
+ EXPECT_TRUE(mService->reclaimResource(10, resources));
+ verifyClients(false, true, false);
+
+ // call again should reclaim another graphic memory from lowest process
+ EXPECT_TRUE(mService->reclaimResource(10, resources));
+ verifyClients(false, false, true);
+
+ // nothing left
+ EXPECT_FALSE(mService->reclaimResource(10, resources));
+ }
+ }
+
+ void testGetLowestPriorityBiggestClient() {
+ String8 type = String8(kResourceGraphicMemory);
+ sp<IResourceManagerClient> client;
+ EXPECT_FALSE(mService->getLowestPriorityBiggestClient_l(10, type, &client));
+
+ addResource();
+
+ EXPECT_FALSE(mService->getLowestPriorityBiggestClient_l(100, type, &client));
+ EXPECT_TRUE(mService->getLowestPriorityBiggestClient_l(10, type, &client));
+
+ // kTestPid1 is the lowest priority process with kResourceGraphicMemory.
+ // mTestClient1 has the largest kResourceGraphicMemory within kTestPid1.
+ EXPECT_EQ(mTestClient1, client);
+ }
+
+ void testGetLowestPriorityPid() {
+ int pid;
+ int priority;
+ TestProcessInfo processInfo;
+
+ String8 type = String8(kResourceGraphicMemory);
+ EXPECT_FALSE(mService->getLowestPriorityPid_l(type, &pid, &priority));
+
+ addResource();
+
+ EXPECT_TRUE(mService->getLowestPriorityPid_l(type, &pid, &priority));
+ EXPECT_EQ(kTestPid1, pid);
+ int priority1;
+ processInfo.getPriority(kTestPid1, &priority1);
+ EXPECT_EQ(priority1, priority);
+
+ type = String8(kResourceNonSecureCodec);
+ EXPECT_TRUE(mService->getLowestPriorityPid_l(type, &pid, &priority));
+ EXPECT_EQ(kTestPid2, pid);
+ int priority2;
+ processInfo.getPriority(kTestPid2, &priority2);
+ EXPECT_EQ(priority2, priority);
+ }
+
+ void testGetBiggestClient() {
+ String8 type = String8(kResourceGraphicMemory);
+ sp<IResourceManagerClient> client;
+ EXPECT_FALSE(mService->getBiggestClient_l(kTestPid2, type, &client));
+
+ addResource();
+
+ EXPECT_TRUE(mService->getBiggestClient_l(kTestPid2, type, &client));
+ EXPECT_EQ(mTestClient2, client);
+ }
+
+ void testIsCallingPriorityHigher() {
+ EXPECT_FALSE(mService->isCallingPriorityHigher_l(101, 100));
+ EXPECT_FALSE(mService->isCallingPriorityHigher_l(100, 100));
+ EXPECT_TRUE(mService->isCallingPriorityHigher_l(99, 100));
+ }
+
+ sp<ResourceManagerService> mService;
+ sp<IResourceManagerClient> mTestClient1;
+ sp<IResourceManagerClient> mTestClient2;
+ sp<IResourceManagerClient> mTestClient3;
+};
+
+TEST_F(ResourceManagerServiceTest, config) {
+ testConfig();
+}
+
+TEST_F(ResourceManagerServiceTest, addResource) {
+ addResource();
+}
+
+TEST_F(ResourceManagerServiceTest, removeResource) {
+ testRemoveResource();
+}
+
+TEST_F(ResourceManagerServiceTest, reclaimResource) {
+ testReclaimResourceSecure();
+ testReclaimResourceNonSecure();
+}
+
+TEST_F(ResourceManagerServiceTest, getAllClients_l) {
+ testGetAllClients();
+}
+
+TEST_F(ResourceManagerServiceTest, getLowestPriorityBiggestClient_l) {
+ testGetLowestPriorityBiggestClient();
+}
+
+TEST_F(ResourceManagerServiceTest, getLowestPriorityPid_l) {
+ testGetLowestPriorityPid();
+}
+
+TEST_F(ResourceManagerServiceTest, getBiggestClient_l) {
+ testGetBiggestClient();
+}
+
+TEST_F(ResourceManagerServiceTest, isCallingPriorityHigher_l) {
+ testIsCallingPriorityHigher();
+}
+
+} // namespace android