diff options
| author | Ronghua Wu <ronghuawu@google.com> | 2015-03-11 15:10:32 -0700 | 
|---|---|---|
| committer | Ronghua Wu <ronghuawu@google.com> | 2015-03-23 17:02:28 -0700 | 
| commit | 231c3d169ad029689f9d688b68179af7e96b8d78 (patch) | |
| tree | 09dbf8d4dc47f5698c08190f498357b455a396c7 /services/mediaresourcemanager | |
| parent | 84b784dd4f340331d36b1be3de05a6c814d9795c (diff) | |
| download | frameworks_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.mk | 18 | ||||
| -rw-r--r-- | services/mediaresourcemanager/ResourceManagerService.cpp | 345 | ||||
| -rw-r--r-- | services/mediaresourcemanager/ResourceManagerService.h | 106 | ||||
| -rw-r--r-- | services/mediaresourcemanager/test/Android.mk | 25 | ||||
| -rw-r--r-- | services/mediaresourcemanager/test/ResourceManagerService_test.cpp | 464 | 
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  | 
