1248 lines
63 KiB
C++
1248 lines
63 KiB
C++
/*
|
|
* 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_test"
|
|
|
|
#include <utils/Log.h>
|
|
|
|
#include "ResourceManagerServiceTestUtils.h"
|
|
#include "ResourceManagerService.h"
|
|
|
|
namespace android {
|
|
|
|
class ResourceManagerServiceTest : public ResourceManagerServiceTestBase {
|
|
private:
|
|
static MediaResource createSecureVideoCodecResource(int amount = 1) {
|
|
return MediaResource(MediaResource::Type::kSecureCodec,
|
|
MediaResource::SubType::kVideoCodec, amount);
|
|
}
|
|
|
|
static MediaResource createNonSecureVideoCodecResource(int amount = 1) {
|
|
return MediaResource(MediaResource::Type::kNonSecureCodec,
|
|
MediaResource::SubType::kVideoCodec, amount);
|
|
}
|
|
|
|
static MediaResource createSecureAudioCodecResource(int amount = 1) {
|
|
return MediaResource(MediaResource::Type::kSecureCodec,
|
|
MediaResource::SubType::kAudioCodec, amount);
|
|
}
|
|
|
|
static MediaResource createNonSecureAudioCodecResource(int amount = 1) {
|
|
return MediaResource(MediaResource::Type::kNonSecureCodec,
|
|
MediaResource::SubType::kAudioCodec, amount);
|
|
}
|
|
|
|
static MediaResource createSecureImageCodecResource(int amount = 1) {
|
|
return MediaResource(MediaResource::Type::kSecureCodec,
|
|
MediaResource::SubType::kImageCodec, amount);
|
|
}
|
|
|
|
static MediaResource createNonSecureImageCodecResource(int amount = 1) {
|
|
return MediaResource(MediaResource::Type::kNonSecureCodec,
|
|
MediaResource::SubType::kImageCodec, amount);
|
|
}
|
|
|
|
static MediaResource createGraphicMemoryResource(int amount = 1) {
|
|
return MediaResource(MediaResource::Type::kGraphicMemory,
|
|
MediaResource::SubType::kUnspecifiedSubType, amount);
|
|
}
|
|
|
|
static MediaResource createDrmSessionResource(int amount = 1) {
|
|
return MediaResource(MediaResource::Type::kDrmSession,
|
|
MediaResource::SubType::kUnspecifiedSubType, amount);
|
|
}
|
|
|
|
static MediaResource createBatteryResource() {
|
|
return MediaResource(MediaResource::Type::kBattery,
|
|
MediaResource::SubType::kUnspecifiedSubType, 1);
|
|
}
|
|
|
|
static MediaResource createCpuBoostResource() {
|
|
return MediaResource(MediaResource::Type::kCpuBoost,
|
|
MediaResource::SubType::kUnspecifiedSubType, 1);
|
|
}
|
|
|
|
public:
|
|
ResourceManagerServiceTest() : ResourceManagerServiceTestBase() {}
|
|
|
|
|
|
// test set up
|
|
// ---------------------------------------------------------------------------------
|
|
// pid priority client type number
|
|
// ---------------------------------------------------------------------------------
|
|
// kTestPid1(30) 30 mTestClient1 secure codec 1
|
|
// graphic memory 200
|
|
// graphic memory 200
|
|
// ---------------------------------------------------------------------------------
|
|
// kTestPid2(20) 20 mTestClient2 non-secure codec 1
|
|
// graphic memory 300
|
|
// -------------------------------------------
|
|
// mTestClient3 secure codec 1
|
|
// graphic memory 100
|
|
// ---------------------------------------------------------------------------------
|
|
void addResource() {
|
|
// kTestPid1 mTestClient1
|
|
std::vector<MediaResourceParcel> resources1;
|
|
resources1.push_back(MediaResource(MediaResource::Type::kSecureCodec, 1));
|
|
mService->addResource(kTestPid1, kTestUid1, getId(mTestClient1), mTestClient1, resources1);
|
|
resources1.push_back(MediaResource(MediaResource::Type::kGraphicMemory, 200));
|
|
std::vector<MediaResourceParcel> resources11;
|
|
resources11.push_back(MediaResource(MediaResource::Type::kGraphicMemory, 200));
|
|
mService->addResource(kTestPid1, kTestUid1, getId(mTestClient1), mTestClient1, resources11);
|
|
|
|
// kTestPid2 mTestClient2
|
|
std::vector<MediaResourceParcel> resources2;
|
|
resources2.push_back(MediaResource(MediaResource::Type::kNonSecureCodec, 1));
|
|
resources2.push_back(MediaResource(MediaResource::Type::kGraphicMemory, 300));
|
|
mService->addResource(kTestPid2, kTestUid2, getId(mTestClient2), mTestClient2, resources2);
|
|
|
|
// kTestPid2 mTestClient3
|
|
std::vector<MediaResourceParcel> resources3;
|
|
mService->addResource(kTestPid2, kTestUid2, getId(mTestClient3), mTestClient3, resources3);
|
|
resources3.push_back(MediaResource(MediaResource::Type::kSecureCodec, 1));
|
|
resources3.push_back(MediaResource(MediaResource::Type::kGraphicMemory, 100));
|
|
mService->addResource(kTestPid2, kTestUid2, getId(mTestClient3), 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.valueFor(getId(mTestClient1)), kTestUid1, mTestClient1, resources1);
|
|
|
|
ssize_t index2 = map.indexOfKey(kTestPid2);
|
|
ASSERT_GE(index2, 0);
|
|
const ResourceInfos &infos2 = map[index2];
|
|
EXPECT_EQ(2u, infos2.size());
|
|
expectEqResourceInfo(infos2.valueFor(getId(mTestClient2)), kTestUid2, mTestClient2, resources2);
|
|
expectEqResourceInfo(infos2.valueFor(getId(mTestClient3)), kTestUid2, mTestClient3, resources3);
|
|
}
|
|
|
|
void testCombineResourceWithNegativeValues() {
|
|
// kTestPid1 mTestClient1
|
|
std::vector<MediaResourceParcel> resources1;
|
|
resources1.push_back(MediaResource(MediaResource::Type::kDrmSession, -100));
|
|
resources1.push_back(MediaResource(MediaResource::Type::kNonSecureCodec, -100));
|
|
mService->addResource(kTestPid1, kTestUid1, getId(mTestClient1), mTestClient1, resources1);
|
|
|
|
// Expected result:
|
|
// 1) the client should have been added;
|
|
// 2) both resource entries should have been rejected, resource list should be empty.
|
|
const PidResourceInfosMap &map = mService->mMap;
|
|
EXPECT_EQ(1u, map.size());
|
|
ssize_t index1 = map.indexOfKey(kTestPid1);
|
|
ASSERT_GE(index1, 0);
|
|
const ResourceInfos &infos1 = map[index1];
|
|
EXPECT_EQ(1u, infos1.size());
|
|
std::vector<MediaResourceParcel> expected;
|
|
expectEqResourceInfo(infos1.valueFor(getId(mTestClient1)), kTestUid1, mTestClient1, expected);
|
|
|
|
resources1.clear();
|
|
resources1.push_back(MediaResource(MediaResource::Type::kDrmSession, INT64_MAX));
|
|
resources1.push_back(MediaResource(MediaResource::Type::kNonSecureCodec, INT64_MAX));
|
|
mService->addResource(kTestPid1, kTestUid1, getId(mTestClient1), mTestClient1, resources1);
|
|
resources1.clear();
|
|
resources1.push_back(MediaResource(MediaResource::Type::kDrmSession, 10));
|
|
resources1.push_back(MediaResource(MediaResource::Type::kNonSecureCodec, 10));
|
|
mService->addResource(kTestPid1, kTestUid1, getId(mTestClient1), mTestClient1, resources1);
|
|
|
|
// Expected result:
|
|
// Both values should saturate to INT64_MAX
|
|
expected.push_back(MediaResource(MediaResource::Type::kDrmSession, INT64_MAX));
|
|
expected.push_back(MediaResource(MediaResource::Type::kNonSecureCodec, INT64_MAX));
|
|
expectEqResourceInfo(infos1.valueFor(getId(mTestClient1)), kTestUid1, mTestClient1, expected);
|
|
|
|
resources1.clear();
|
|
resources1.push_back(MediaResource(MediaResource::Type::kDrmSession, -10));
|
|
resources1.push_back(MediaResource(MediaResource::Type::kNonSecureCodec, -10));
|
|
mService->addResource(kTestPid1, kTestUid1, getId(mTestClient1), mTestClient1, resources1);
|
|
|
|
// Expected result:
|
|
// 1) DrmSession resource should allow negative value addition, and value should drop accordingly
|
|
// 2) Non-drm session resource should ignore negative value addition.
|
|
expected.push_back(MediaResource(MediaResource::Type::kDrmSession, INT64_MAX - 10));
|
|
expected.push_back(MediaResource(MediaResource::Type::kNonSecureCodec, INT64_MAX));
|
|
expectEqResourceInfo(infos1.valueFor(getId(mTestClient1)), kTestUid1, mTestClient1, expected);
|
|
|
|
resources1.clear();
|
|
resources1.push_back(MediaResource(MediaResource::Type::kDrmSession, INT64_MIN));
|
|
expected.push_back(MediaResource(MediaResource::Type::kNonSecureCodec, INT64_MIN));
|
|
mService->addResource(kTestPid1, kTestUid1, getId(mTestClient1), mTestClient1, resources1);
|
|
|
|
// Expected result:
|
|
// 1) DrmSession resource value should drop to 0, but the entry shouldn't be removed.
|
|
// 2) Non-drm session resource should ignore negative value addition.
|
|
expected.clear();
|
|
expected.push_back(MediaResource(MediaResource::Type::kDrmSession, 0));
|
|
expected.push_back(MediaResource(MediaResource::Type::kNonSecureCodec, INT64_MAX));
|
|
expectEqResourceInfo(infos1.valueFor(getId(mTestClient1)), kTestUid1, mTestClient1, expected);
|
|
}
|
|
|
|
void testConfig() {
|
|
EXPECT_TRUE(mService->mSupportsMultipleSecureCodecs);
|
|
EXPECT_TRUE(mService->mSupportsSecureWithNonSecureCodec);
|
|
|
|
std::vector<MediaResourcePolicyParcel> policies1;
|
|
policies1.push_back(
|
|
MediaResourcePolicy(
|
|
IResourceManagerService::kPolicySupportsMultipleSecureCodecs,
|
|
"true"));
|
|
policies1.push_back(
|
|
MediaResourcePolicy(
|
|
IResourceManagerService::kPolicySupportsSecureWithNonSecureCodec,
|
|
"false"));
|
|
mService->config(policies1);
|
|
EXPECT_TRUE(mService->mSupportsMultipleSecureCodecs);
|
|
EXPECT_FALSE(mService->mSupportsSecureWithNonSecureCodec);
|
|
|
|
std::vector<MediaResourcePolicyParcel> policies2;
|
|
policies2.push_back(
|
|
MediaResourcePolicy(
|
|
IResourceManagerService::kPolicySupportsMultipleSecureCodecs,
|
|
"false"));
|
|
policies2.push_back(
|
|
MediaResourcePolicy(
|
|
IResourceManagerService::kPolicySupportsSecureWithNonSecureCodec,
|
|
"true"));
|
|
mService->config(policies2);
|
|
EXPECT_FALSE(mService->mSupportsMultipleSecureCodecs);
|
|
EXPECT_TRUE(mService->mSupportsSecureWithNonSecureCodec);
|
|
}
|
|
|
|
void testCombineResource() {
|
|
// kTestPid1 mTestClient1
|
|
std::vector<MediaResourceParcel> resources1;
|
|
resources1.push_back(MediaResource(MediaResource::Type::kSecureCodec, 1));
|
|
mService->addResource(kTestPid1, kTestUid1, getId(mTestClient1), mTestClient1, resources1);
|
|
|
|
std::vector<MediaResourceParcel> resources11;
|
|
resources11.push_back(MediaResource(MediaResource::Type::kGraphicMemory, 200));
|
|
mService->addResource(kTestPid1, kTestUid1, getId(mTestClient1), mTestClient1, resources11);
|
|
|
|
const PidResourceInfosMap &map = mService->mMap;
|
|
EXPECT_EQ(1u, map.size());
|
|
ssize_t index1 = map.indexOfKey(kTestPid1);
|
|
ASSERT_GE(index1, 0);
|
|
const ResourceInfos &infos1 = map[index1];
|
|
EXPECT_EQ(1u, infos1.size());
|
|
|
|
// test adding existing types to combine values
|
|
resources1.push_back(MediaResource(MediaResource::Type::kGraphicMemory, 100));
|
|
mService->addResource(kTestPid1, kTestUid1, getId(mTestClient1), mTestClient1, resources1);
|
|
|
|
std::vector<MediaResourceParcel> expected;
|
|
expected.push_back(MediaResource(MediaResource::Type::kSecureCodec, 2));
|
|
expected.push_back(MediaResource(MediaResource::Type::kGraphicMemory, 300));
|
|
expectEqResourceInfo(infos1.valueFor(getId(mTestClient1)), kTestUid1, mTestClient1, expected);
|
|
|
|
// test adding new types (including types that differs only in subType)
|
|
resources11.push_back(MediaResource(MediaResource::Type::kNonSecureCodec, 1));
|
|
resources11.push_back(MediaResource(MediaResource::Type::kSecureCodec, MediaResource::SubType::kVideoCodec, 1));
|
|
mService->addResource(kTestPid1, kTestUid1, getId(mTestClient1), mTestClient1, resources11);
|
|
|
|
expected.clear();
|
|
expected.push_back(MediaResource(MediaResource::Type::kSecureCodec, 2));
|
|
expected.push_back(MediaResource(MediaResource::Type::kNonSecureCodec, 1));
|
|
expected.push_back(MediaResource(MediaResource::Type::kSecureCodec, MediaResource::SubType::kVideoCodec, 1));
|
|
expected.push_back(MediaResource(MediaResource::Type::kGraphicMemory, 500));
|
|
expectEqResourceInfo(infos1.valueFor(getId(mTestClient1)), kTestUid1, mTestClient1, expected);
|
|
}
|
|
|
|
void testRemoveResource() {
|
|
// kTestPid1 mTestClient1
|
|
std::vector<MediaResourceParcel> resources1;
|
|
resources1.push_back(MediaResource(MediaResource::Type::kSecureCodec, 1));
|
|
mService->addResource(kTestPid1, kTestUid1, getId(mTestClient1), mTestClient1, resources1);
|
|
|
|
std::vector<MediaResourceParcel> resources11;
|
|
resources11.push_back(MediaResource(MediaResource::Type::kGraphicMemory, 200));
|
|
mService->addResource(kTestPid1, kTestUid1, getId(mTestClient1), mTestClient1, resources11);
|
|
|
|
const PidResourceInfosMap &map = mService->mMap;
|
|
EXPECT_EQ(1u, map.size());
|
|
ssize_t index1 = map.indexOfKey(kTestPid1);
|
|
ASSERT_GE(index1, 0);
|
|
const ResourceInfos &infos1 = map[index1];
|
|
EXPECT_EQ(1u, infos1.size());
|
|
|
|
// test partial removal
|
|
resources11[0].value = 100;
|
|
mService->removeResource(kTestPid1, getId(mTestClient1), resources11);
|
|
|
|
std::vector<MediaResourceParcel> expected;
|
|
expected.push_back(MediaResource(MediaResource::Type::kSecureCodec, 1));
|
|
expected.push_back(MediaResource(MediaResource::Type::kGraphicMemory, 100));
|
|
expectEqResourceInfo(infos1.valueFor(getId(mTestClient1)), kTestUid1, mTestClient1, expected);
|
|
|
|
// test removal request with negative value, should be ignored
|
|
resources11[0].value = -10000;
|
|
mService->removeResource(kTestPid1, getId(mTestClient1), resources11);
|
|
|
|
expectEqResourceInfo(infos1.valueFor(getId(mTestClient1)), kTestUid1, mTestClient1, expected);
|
|
|
|
// test complete removal with overshoot value
|
|
resources11[0].value = 1000;
|
|
mService->removeResource(kTestPid1, getId(mTestClient1), resources11);
|
|
|
|
expected.clear();
|
|
expected.push_back(MediaResource(MediaResource::Type::kSecureCodec, 1));
|
|
expectEqResourceInfo(infos1.valueFor(getId(mTestClient1)), kTestUid1, mTestClient1, expected);
|
|
}
|
|
|
|
void testOverridePid() {
|
|
|
|
std::vector<MediaResourceParcel> resources;
|
|
resources.push_back(MediaResource(MediaResource::Type::kSecureCodec, 1));
|
|
resources.push_back(MediaResource(MediaResource::Type::kGraphicMemory, 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 to reclaim resource
|
|
CHECK_STATUS_FALSE(mService->reclaimResource(kLowPriorityPid, resources, &result));
|
|
|
|
// override Low Priority Pid with High Priority Pid
|
|
mService->overridePid(kLowPriorityPid, kHighPriorityPid);
|
|
CHECK_STATUS_TRUE(mService->reclaimResource(kLowPriorityPid, resources, &result));
|
|
|
|
// restore Low Priority Pid
|
|
mService->overridePid(kLowPriorityPid, -1);
|
|
CHECK_STATUS_FALSE(mService->reclaimResource(kLowPriorityPid, resources, &result));
|
|
}
|
|
}
|
|
|
|
void testMarkClientForPendingRemoval() {
|
|
{
|
|
addResource();
|
|
mService->mSupportsSecureWithNonSecureCodec = true;
|
|
|
|
std::vector<MediaResourceParcel> resources;
|
|
resources.push_back(MediaResource(MediaResource::Type::kNonSecureCodec, 1));
|
|
|
|
// Remove low priority clients
|
|
mService->removeClient(kTestPid1, getId(mTestClient1));
|
|
|
|
// no lower priority client
|
|
CHECK_STATUS_FALSE(mService->reclaimResource(kTestPid2, resources, &result));
|
|
EXPECT_EQ(false, toTestClient(mTestClient1)->checkIfReclaimedAndReset());
|
|
EXPECT_EQ(false, toTestClient(mTestClient2)->checkIfReclaimedAndReset());
|
|
EXPECT_EQ(false, toTestClient(mTestClient3)->checkIfReclaimedAndReset());
|
|
|
|
mService->markClientForPendingRemoval(kTestPid2, getId(mTestClient2));
|
|
|
|
// client marked for pending removal from the same process got reclaimed
|
|
CHECK_STATUS_TRUE(mService->reclaimResource(kTestPid2, resources, &result));
|
|
EXPECT_EQ(false, toTestClient(mTestClient1)->checkIfReclaimedAndReset());
|
|
EXPECT_EQ(true, toTestClient(mTestClient2)->checkIfReclaimedAndReset());
|
|
EXPECT_EQ(false, toTestClient(mTestClient3)->checkIfReclaimedAndReset());
|
|
|
|
// clean up client 3 which still left
|
|
mService->removeClient(kTestPid2, getId(mTestClient3));
|
|
}
|
|
|
|
{
|
|
addResource();
|
|
mService->mSupportsSecureWithNonSecureCodec = true;
|
|
|
|
std::vector<MediaResourceParcel> resources;
|
|
resources.push_back(MediaResource(MediaResource::Type::kNonSecureCodec, 1));
|
|
|
|
mService->markClientForPendingRemoval(kTestPid2, getId(mTestClient2));
|
|
|
|
// client marked for pending removal from the same process got reclaimed
|
|
// first, even though there are lower priority process
|
|
CHECK_STATUS_TRUE(mService->reclaimResource(kTestPid2, resources, &result));
|
|
EXPECT_EQ(false, toTestClient(mTestClient1)->checkIfReclaimedAndReset());
|
|
EXPECT_EQ(true, toTestClient(mTestClient2)->checkIfReclaimedAndReset());
|
|
EXPECT_EQ(false, toTestClient(mTestClient3)->checkIfReclaimedAndReset());
|
|
|
|
// lower priority client got reclaimed
|
|
CHECK_STATUS_TRUE(mService->reclaimResource(kTestPid2, resources, &result));
|
|
EXPECT_EQ(true, toTestClient(mTestClient1)->checkIfReclaimedAndReset());
|
|
EXPECT_EQ(false, toTestClient(mTestClient2)->checkIfReclaimedAndReset());
|
|
EXPECT_EQ(false, toTestClient(mTestClient3)->checkIfReclaimedAndReset());
|
|
|
|
// clean up client 3 which still left
|
|
mService->removeClient(kTestPid2, getId(mTestClient3));
|
|
}
|
|
|
|
{
|
|
addResource();
|
|
mService->mSupportsSecureWithNonSecureCodec = true;
|
|
|
|
mService->markClientForPendingRemoval(kTestPid2, getId(mTestClient2));
|
|
|
|
// client marked for pending removal got reclaimed
|
|
EXPECT_TRUE(mService->reclaimResourcesFromClientsPendingRemoval(kTestPid2).isOk());
|
|
EXPECT_EQ(false, toTestClient(mTestClient1)->checkIfReclaimedAndReset());
|
|
EXPECT_EQ(true, toTestClient(mTestClient2)->checkIfReclaimedAndReset());
|
|
EXPECT_EQ(false, toTestClient(mTestClient3)->checkIfReclaimedAndReset());
|
|
|
|
// No more clients marked for removal
|
|
EXPECT_TRUE(mService->reclaimResourcesFromClientsPendingRemoval(kTestPid2).isOk());
|
|
EXPECT_EQ(false, toTestClient(mTestClient1)->checkIfReclaimedAndReset());
|
|
EXPECT_EQ(false, toTestClient(mTestClient2)->checkIfReclaimedAndReset());
|
|
EXPECT_EQ(false, toTestClient(mTestClient3)->checkIfReclaimedAndReset());
|
|
|
|
mService->markClientForPendingRemoval(kTestPid2, getId(mTestClient3));
|
|
|
|
// client marked for pending removal got reclaimed
|
|
EXPECT_TRUE(mService->reclaimResourcesFromClientsPendingRemoval(kTestPid2).isOk());
|
|
EXPECT_EQ(false, toTestClient(mTestClient1)->checkIfReclaimedAndReset());
|
|
EXPECT_EQ(false, toTestClient(mTestClient2)->checkIfReclaimedAndReset());
|
|
EXPECT_EQ(true, toTestClient(mTestClient3)->checkIfReclaimedAndReset());
|
|
|
|
// clean up client 1 which still left
|
|
mService->removeClient(kTestPid1, getId(mTestClient1));
|
|
}
|
|
}
|
|
|
|
void testRemoveClient() {
|
|
addResource();
|
|
|
|
mService->removeClient(kTestPid2, getId(mTestClient2));
|
|
|
|
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.
|
|
// (OK to use infos2[0] as there is only 1 entry)
|
|
EXPECT_EQ(mTestClient3, infos2[0].client);
|
|
}
|
|
|
|
void testGetAllClients() {
|
|
addResource();
|
|
MediaResource::Type type = MediaResource::Type::kSecureCodec;
|
|
MediaResource::SubType subType = MediaResource::SubType::kUnspecifiedSubType;
|
|
|
|
Vector<std::shared_ptr<IResourceManagerClient> > clients;
|
|
EXPECT_FALSE(mService->getAllClients_l(kLowPriorityPid, type, subType, &clients));
|
|
// some higher priority process (e.g. kTestPid2) owns the resource, so getAllClients_l
|
|
// will fail.
|
|
EXPECT_FALSE(mService->getAllClients_l(kMidPriorityPid, type, subType, &clients));
|
|
EXPECT_TRUE(mService->getAllClients_l(kHighPriorityPid, type, subType, &clients));
|
|
|
|
EXPECT_EQ(2u, clients.size());
|
|
// (OK to require ordering in clients[], as the pid map is sorted)
|
|
EXPECT_EQ(mTestClient3, clients[0]);
|
|
EXPECT_EQ(mTestClient1, clients[1]);
|
|
}
|
|
|
|
void testReclaimResourceSecure() {
|
|
std::vector<MediaResourceParcel> resources;
|
|
resources.push_back(MediaResource(MediaResource::Type::kSecureCodec, 1));
|
|
resources.push_back(MediaResource(MediaResource::Type::kGraphicMemory, 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
|
|
CHECK_STATUS_FALSE(mService->reclaimResource(kLowPriorityPid, resources, &result));
|
|
CHECK_STATUS_FALSE(mService->reclaimResource(kMidPriorityPid, resources, &result));
|
|
|
|
// reclaim all secure codecs
|
|
CHECK_STATUS_TRUE(mService->reclaimResource(kHighPriorityPid, resources, &result));
|
|
EXPECT_TRUE(toTestClient(mTestClient1)->checkIfReclaimedAndReset());
|
|
EXPECT_FALSE(toTestClient(mTestClient2)->checkIfReclaimedAndReset());
|
|
EXPECT_TRUE(toTestClient(mTestClient3)->checkIfReclaimedAndReset());
|
|
|
|
// call again should reclaim one largest graphic memory from lowest process
|
|
CHECK_STATUS_TRUE(mService->reclaimResource(kHighPriorityPid, resources, &result));
|
|
EXPECT_FALSE(toTestClient(mTestClient1)->checkIfReclaimedAndReset());
|
|
EXPECT_TRUE(toTestClient(mTestClient2)->checkIfReclaimedAndReset());
|
|
EXPECT_FALSE(toTestClient(mTestClient3)->checkIfReclaimedAndReset());
|
|
|
|
// nothing left
|
|
CHECK_STATUS_FALSE(mService->reclaimResource(kHighPriorityPid, resources, &result));
|
|
}
|
|
|
|
// ### 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
|
|
CHECK_STATUS_FALSE(mService->reclaimResource(kLowPriorityPid, resources, &result));
|
|
CHECK_STATUS_FALSE(mService->reclaimResource(kMidPriorityPid, resources, &result));
|
|
|
|
// reclaim all secure and non-secure codecs
|
|
CHECK_STATUS_TRUE(mService->reclaimResource(kHighPriorityPid, resources, &result));
|
|
EXPECT_TRUE(toTestClient(mTestClient1)->checkIfReclaimedAndReset());
|
|
EXPECT_TRUE(toTestClient(mTestClient2)->checkIfReclaimedAndReset());
|
|
EXPECT_TRUE(toTestClient(mTestClient3)->checkIfReclaimedAndReset());
|
|
|
|
// nothing left
|
|
CHECK_STATUS_FALSE(mService->reclaimResource(kHighPriorityPid, resources, &result));
|
|
}
|
|
|
|
|
|
// ### secure codecs can coexist but secure codec can't coexist with non-secure codec ###
|
|
{
|
|
addResource();
|
|
mService->mSupportsMultipleSecureCodecs = true;
|
|
mService->mSupportsSecureWithNonSecureCodec = false;
|
|
|
|
// priority too low
|
|
CHECK_STATUS_FALSE(mService->reclaimResource(kLowPriorityPid, resources, &result));
|
|
CHECK_STATUS_FALSE(mService->reclaimResource(kMidPriorityPid, resources, &result));
|
|
|
|
// reclaim all non-secure codecs
|
|
CHECK_STATUS_TRUE(mService->reclaimResource(kHighPriorityPid, resources, &result));
|
|
EXPECT_FALSE(toTestClient(mTestClient1)->checkIfReclaimedAndReset());
|
|
EXPECT_TRUE(toTestClient(mTestClient2)->checkIfReclaimedAndReset());
|
|
EXPECT_FALSE(toTestClient(mTestClient3)->checkIfReclaimedAndReset());
|
|
|
|
// call again should reclaim one largest graphic memory from lowest process
|
|
CHECK_STATUS_TRUE(mService->reclaimResource(kHighPriorityPid, resources, &result));
|
|
EXPECT_TRUE(toTestClient(mTestClient1)->checkIfReclaimedAndReset());
|
|
EXPECT_FALSE(toTestClient(mTestClient2)->checkIfReclaimedAndReset());
|
|
EXPECT_FALSE(toTestClient(mTestClient3)->checkIfReclaimedAndReset());
|
|
|
|
// call again should reclaim another largest graphic memory from lowest process
|
|
CHECK_STATUS_TRUE(mService->reclaimResource(kHighPriorityPid, resources, &result));
|
|
EXPECT_FALSE(toTestClient(mTestClient1)->checkIfReclaimedAndReset());
|
|
EXPECT_FALSE(toTestClient(mTestClient2)->checkIfReclaimedAndReset());
|
|
EXPECT_TRUE(toTestClient(mTestClient3)->checkIfReclaimedAndReset());
|
|
|
|
// nothing left
|
|
CHECK_STATUS_FALSE(mService->reclaimResource(kHighPriorityPid, resources, &result));
|
|
}
|
|
|
|
// ### secure codecs can coexist and secure codec can coexist with non-secure codec ###
|
|
{
|
|
addResource();
|
|
mService->mSupportsMultipleSecureCodecs = true;
|
|
mService->mSupportsSecureWithNonSecureCodec = true;
|
|
|
|
// priority too low
|
|
CHECK_STATUS_FALSE(mService->reclaimResource(kLowPriorityPid, resources, &result));
|
|
|
|
CHECK_STATUS_TRUE(mService->reclaimResource(kHighPriorityPid, resources, &result));
|
|
// one largest graphic memory from lowest process got reclaimed
|
|
EXPECT_TRUE(toTestClient(mTestClient1)->checkIfReclaimedAndReset());
|
|
EXPECT_FALSE(toTestClient(mTestClient2)->checkIfReclaimedAndReset());
|
|
EXPECT_FALSE(toTestClient(mTestClient3)->checkIfReclaimedAndReset());
|
|
|
|
// call again should reclaim another graphic memory from lowest process
|
|
CHECK_STATUS_TRUE(mService->reclaimResource(kHighPriorityPid, resources, &result));
|
|
EXPECT_FALSE(toTestClient(mTestClient1)->checkIfReclaimedAndReset());
|
|
EXPECT_TRUE(toTestClient(mTestClient2)->checkIfReclaimedAndReset());
|
|
EXPECT_FALSE(toTestClient(mTestClient3)->checkIfReclaimedAndReset());
|
|
|
|
// call again should reclaim another graphic memory from lowest process
|
|
CHECK_STATUS_TRUE(mService->reclaimResource(kHighPriorityPid, resources, &result));
|
|
EXPECT_FALSE(toTestClient(mTestClient1)->checkIfReclaimedAndReset());
|
|
EXPECT_FALSE(toTestClient(mTestClient2)->checkIfReclaimedAndReset());
|
|
EXPECT_TRUE(toTestClient(mTestClient3)->checkIfReclaimedAndReset());
|
|
|
|
// nothing left
|
|
CHECK_STATUS_FALSE(mService->reclaimResource(kHighPriorityPid, resources, &result));
|
|
}
|
|
|
|
// ### secure codecs can coexist and secure codec can coexist with non-secure codec ###
|
|
{
|
|
addResource();
|
|
mService->mSupportsMultipleSecureCodecs = true;
|
|
mService->mSupportsSecureWithNonSecureCodec = true;
|
|
|
|
std::vector<MediaResourceParcel> resources;
|
|
resources.push_back(MediaResource(MediaResource::Type::kSecureCodec, 1));
|
|
|
|
CHECK_STATUS_TRUE(mService->reclaimResource(kHighPriorityPid, resources, &result));
|
|
// secure codec from lowest process got reclaimed
|
|
EXPECT_TRUE(toTestClient(mTestClient1)->checkIfReclaimedAndReset());
|
|
EXPECT_FALSE(toTestClient(mTestClient2)->checkIfReclaimedAndReset());
|
|
EXPECT_FALSE(toTestClient(mTestClient3)->checkIfReclaimedAndReset());
|
|
|
|
// call again should reclaim another secure codec from lowest process
|
|
CHECK_STATUS_TRUE(mService->reclaimResource(kHighPriorityPid, resources, &result));
|
|
EXPECT_FALSE(toTestClient(mTestClient1)->checkIfReclaimedAndReset());
|
|
EXPECT_FALSE(toTestClient(mTestClient2)->checkIfReclaimedAndReset());
|
|
EXPECT_TRUE(toTestClient(mTestClient3)->checkIfReclaimedAndReset());
|
|
|
|
// no more secure codec, non-secure codec will be reclaimed.
|
|
CHECK_STATUS_TRUE(mService->reclaimResource(kHighPriorityPid, resources, &result));
|
|
EXPECT_FALSE(toTestClient(mTestClient1)->checkIfReclaimedAndReset());
|
|
EXPECT_TRUE(toTestClient(mTestClient2)->checkIfReclaimedAndReset());
|
|
EXPECT_FALSE(toTestClient(mTestClient3)->checkIfReclaimedAndReset());
|
|
}
|
|
}
|
|
|
|
void testReclaimResourceNonSecure() {
|
|
std::vector<MediaResourceParcel> resources;
|
|
resources.push_back(MediaResource(MediaResource::Type::kNonSecureCodec, 1));
|
|
resources.push_back(MediaResource(MediaResource::Type::kGraphicMemory, 150));
|
|
|
|
// ### secure codec can't coexist with non-secure codec ###
|
|
{
|
|
addResource();
|
|
mService->mSupportsSecureWithNonSecureCodec = false;
|
|
|
|
// priority too low
|
|
CHECK_STATUS_FALSE(mService->reclaimResource(kLowPriorityPid, resources, &result));
|
|
CHECK_STATUS_FALSE(mService->reclaimResource(kMidPriorityPid, resources, &result));
|
|
|
|
// reclaim all secure codecs
|
|
CHECK_STATUS_TRUE(mService->reclaimResource(kHighPriorityPid, resources, &result));
|
|
EXPECT_TRUE(toTestClient(mTestClient1)->checkIfReclaimedAndReset());
|
|
EXPECT_FALSE(toTestClient(mTestClient2)->checkIfReclaimedAndReset());
|
|
EXPECT_TRUE(toTestClient(mTestClient3)->checkIfReclaimedAndReset());
|
|
|
|
// call again should reclaim one graphic memory from lowest process
|
|
CHECK_STATUS_TRUE(mService->reclaimResource(kHighPriorityPid, resources, &result));
|
|
EXPECT_FALSE(toTestClient(mTestClient1)->checkIfReclaimedAndReset());
|
|
EXPECT_TRUE(toTestClient(mTestClient2)->checkIfReclaimedAndReset());
|
|
EXPECT_FALSE(toTestClient(mTestClient3)->checkIfReclaimedAndReset());
|
|
|
|
// nothing left
|
|
CHECK_STATUS_FALSE(mService->reclaimResource(kHighPriorityPid, resources, &result));
|
|
}
|
|
|
|
|
|
// ### secure codec can coexist with non-secure codec ###
|
|
{
|
|
addResource();
|
|
mService->mSupportsSecureWithNonSecureCodec = true;
|
|
|
|
// priority too low
|
|
CHECK_STATUS_FALSE(mService->reclaimResource(kLowPriorityPid, resources, &result));
|
|
|
|
CHECK_STATUS_TRUE(mService->reclaimResource(kHighPriorityPid, resources, &result));
|
|
// one largest graphic memory from lowest process got reclaimed
|
|
EXPECT_TRUE(toTestClient(mTestClient1)->checkIfReclaimedAndReset());
|
|
EXPECT_FALSE(toTestClient(mTestClient2)->checkIfReclaimedAndReset());
|
|
EXPECT_FALSE(toTestClient(mTestClient3)->checkIfReclaimedAndReset());
|
|
|
|
// call again should reclaim another graphic memory from lowest process
|
|
CHECK_STATUS_TRUE(mService->reclaimResource(kHighPriorityPid, resources, &result));
|
|
EXPECT_FALSE(toTestClient(mTestClient1)->checkIfReclaimedAndReset());
|
|
EXPECT_TRUE(toTestClient(mTestClient2)->checkIfReclaimedAndReset());
|
|
EXPECT_FALSE(toTestClient(mTestClient3)->checkIfReclaimedAndReset());
|
|
|
|
// call again should reclaim another graphic memory from lowest process
|
|
CHECK_STATUS_TRUE(mService->reclaimResource(kHighPriorityPid, resources, &result));
|
|
EXPECT_FALSE(toTestClient(mTestClient1)->checkIfReclaimedAndReset());
|
|
EXPECT_FALSE(toTestClient(mTestClient2)->checkIfReclaimedAndReset());
|
|
EXPECT_TRUE(toTestClient(mTestClient3)->checkIfReclaimedAndReset());
|
|
|
|
// nothing left
|
|
CHECK_STATUS_FALSE(mService->reclaimResource(kHighPriorityPid, resources, &result));
|
|
}
|
|
|
|
// ### secure codec can coexist with non-secure codec ###
|
|
{
|
|
addResource();
|
|
mService->mSupportsSecureWithNonSecureCodec = true;
|
|
|
|
std::vector<MediaResourceParcel> resources;
|
|
resources.push_back(MediaResource(MediaResource::Type::kNonSecureCodec, 1));
|
|
|
|
CHECK_STATUS_TRUE(mService->reclaimResource(kHighPriorityPid, resources, &result));
|
|
// one non secure codec from lowest process got reclaimed
|
|
EXPECT_FALSE(toTestClient(mTestClient1)->checkIfReclaimedAndReset());
|
|
EXPECT_TRUE(toTestClient(mTestClient2)->checkIfReclaimedAndReset());
|
|
EXPECT_FALSE(toTestClient(mTestClient3)->checkIfReclaimedAndReset());
|
|
|
|
// no more non-secure codec, secure codec from lowest priority process will be reclaimed
|
|
CHECK_STATUS_TRUE(mService->reclaimResource(kHighPriorityPid, resources, &result));
|
|
EXPECT_TRUE(toTestClient(mTestClient1)->checkIfReclaimedAndReset());
|
|
EXPECT_FALSE(toTestClient(mTestClient2)->checkIfReclaimedAndReset());
|
|
EXPECT_FALSE(toTestClient(mTestClient3)->checkIfReclaimedAndReset());
|
|
|
|
// clean up client 3 which still left
|
|
mService->removeClient(kTestPid2, getId(mTestClient3));
|
|
}
|
|
}
|
|
|
|
void testGetLowestPriorityBiggestClient() {
|
|
MediaResource::Type type = MediaResource::Type::kGraphicMemory;
|
|
MediaResource::SubType subType = MediaResource::SubType::kUnspecifiedSubType;
|
|
std::shared_ptr<IResourceManagerClient> client;
|
|
EXPECT_FALSE(mService->getLowestPriorityBiggestClient_l(kHighPriorityPid, type, subType,
|
|
&client));
|
|
|
|
addResource();
|
|
|
|
EXPECT_FALSE(mService->getLowestPriorityBiggestClient_l(kLowPriorityPid, type, subType,
|
|
&client));
|
|
EXPECT_TRUE(mService->getLowestPriorityBiggestClient_l(kHighPriorityPid, type, subType,
|
|
&client));
|
|
|
|
// kTestPid1 is the lowest priority process with MediaResource::Type::kGraphicMemory.
|
|
// mTestClient1 has the largest MediaResource::Type::kGraphicMemory within kTestPid1.
|
|
EXPECT_EQ(mTestClient1, client);
|
|
}
|
|
|
|
void testGetLowestPriorityPid() {
|
|
int pid;
|
|
int priority;
|
|
TestProcessInfo processInfo;
|
|
|
|
MediaResource::Type type = MediaResource::Type::kGraphicMemory;
|
|
MediaResource::SubType subType = MediaResource::SubType::kUnspecifiedSubType;
|
|
EXPECT_FALSE(mService->getLowestPriorityPid_l(type, subType, &pid, &priority));
|
|
|
|
addResource();
|
|
|
|
EXPECT_TRUE(mService->getLowestPriorityPid_l(type, subType, &pid, &priority));
|
|
EXPECT_EQ(kTestPid1, pid);
|
|
int priority1;
|
|
processInfo.getPriority(kTestPid1, &priority1);
|
|
EXPECT_EQ(priority1, priority);
|
|
|
|
type = MediaResource::Type::kNonSecureCodec;
|
|
EXPECT_TRUE(mService->getLowestPriorityPid_l(type, subType, &pid, &priority));
|
|
EXPECT_EQ(kTestPid2, pid);
|
|
int priority2;
|
|
processInfo.getPriority(kTestPid2, &priority2);
|
|
EXPECT_EQ(priority2, priority);
|
|
}
|
|
|
|
void testIsCallingPriorityHigher() {
|
|
EXPECT_FALSE(mService->isCallingPriorityHigher_l(101, 100));
|
|
EXPECT_FALSE(mService->isCallingPriorityHigher_l(100, 100));
|
|
EXPECT_TRUE(mService->isCallingPriorityHigher_l(99, 100));
|
|
}
|
|
|
|
void testBatteryStats() {
|
|
// reset should always be called when ResourceManagerService is created (restarted)
|
|
EXPECT_EQ(1u, mSystemCB->eventCount());
|
|
EXPECT_EQ(EventType::VIDEO_RESET, mSystemCB->lastEventType());
|
|
|
|
// new client request should cause VIDEO_ON
|
|
std::vector<MediaResourceParcel> resources1;
|
|
resources1.push_back(MediaResource(MediaResource::Type::kBattery, MediaResource::SubType::kVideoCodec, 1));
|
|
mService->addResource(kTestPid1, kTestUid1, getId(mTestClient1), mTestClient1, resources1);
|
|
EXPECT_EQ(2u, mSystemCB->eventCount());
|
|
EXPECT_EQ(EventEntry({EventType::VIDEO_ON, kTestUid1}), mSystemCB->lastEvent());
|
|
|
|
// each client should only cause 1 VIDEO_ON
|
|
mService->addResource(kTestPid1, kTestUid1, getId(mTestClient1), mTestClient1, resources1);
|
|
EXPECT_EQ(2u, mSystemCB->eventCount());
|
|
|
|
// new client request should cause VIDEO_ON
|
|
std::vector<MediaResourceParcel> resources2;
|
|
resources2.push_back(MediaResource(MediaResource::Type::kBattery, MediaResource::SubType::kVideoCodec, 2));
|
|
mService->addResource(kTestPid2, kTestUid2, getId(mTestClient2), mTestClient2, resources2);
|
|
EXPECT_EQ(3u, mSystemCB->eventCount());
|
|
EXPECT_EQ(EventEntry({EventType::VIDEO_ON, kTestUid2}), mSystemCB->lastEvent());
|
|
|
|
// partially remove mTestClient1's request, shouldn't be any VIDEO_OFF
|
|
mService->removeResource(kTestPid1, getId(mTestClient1), resources1);
|
|
EXPECT_EQ(3u, mSystemCB->eventCount());
|
|
|
|
// remove mTestClient1's request, should be VIDEO_OFF for kTestUid1
|
|
// (use resource2 to test removing more instances than previously requested)
|
|
mService->removeResource(kTestPid1, getId(mTestClient1), resources2);
|
|
EXPECT_EQ(4u, mSystemCB->eventCount());
|
|
EXPECT_EQ(EventEntry({EventType::VIDEO_OFF, kTestUid1}), mSystemCB->lastEvent());
|
|
|
|
// remove mTestClient2, should be VIDEO_OFF for kTestUid2
|
|
mService->removeClient(kTestPid2, getId(mTestClient2));
|
|
EXPECT_EQ(5u, mSystemCB->eventCount());
|
|
EXPECT_EQ(EventEntry({EventType::VIDEO_OFF, kTestUid2}), mSystemCB->lastEvent());
|
|
}
|
|
|
|
void testCpusetBoost() {
|
|
// reset should always be called when ResourceManagerService is created (restarted)
|
|
EXPECT_EQ(1u, mSystemCB->eventCount());
|
|
EXPECT_EQ(EventType::VIDEO_RESET, mSystemCB->lastEventType());
|
|
|
|
// new client request should cause CPUSET_ENABLE
|
|
std::vector<MediaResourceParcel> resources1;
|
|
resources1.push_back(MediaResource(MediaResource::Type::kCpuBoost, 1));
|
|
mService->addResource(kTestPid1, kTestUid1, getId(mTestClient1), mTestClient1, resources1);
|
|
EXPECT_EQ(2u, mSystemCB->eventCount());
|
|
EXPECT_EQ(EventType::CPUSET_ENABLE, mSystemCB->lastEventType());
|
|
|
|
// each client should only cause 1 CPUSET_ENABLE
|
|
mService->addResource(kTestPid1, kTestUid1, getId(mTestClient1), mTestClient1, resources1);
|
|
EXPECT_EQ(2u, mSystemCB->eventCount());
|
|
|
|
// new client request should cause CPUSET_ENABLE
|
|
std::vector<MediaResourceParcel> resources2;
|
|
resources2.push_back(MediaResource(MediaResource::Type::kCpuBoost, 2));
|
|
mService->addResource(kTestPid2, kTestUid2, getId(mTestClient2), mTestClient2, resources2);
|
|
EXPECT_EQ(3u, mSystemCB->eventCount());
|
|
EXPECT_EQ(EventType::CPUSET_ENABLE, mSystemCB->lastEventType());
|
|
|
|
// remove mTestClient2 should not cause CPUSET_DISABLE, mTestClient1 still active
|
|
mService->removeClient(kTestPid2, getId(mTestClient2));
|
|
EXPECT_EQ(3u, mSystemCB->eventCount());
|
|
|
|
// remove 1 cpuboost from mTestClient1, should not be CPUSET_DISABLE (still 1 left)
|
|
mService->removeResource(kTestPid1, getId(mTestClient1), resources1);
|
|
EXPECT_EQ(3u, mSystemCB->eventCount());
|
|
|
|
// remove 2 cpuboost from mTestClient1, should be CPUSET_DISABLE
|
|
// (use resource2 to test removing more than previously requested)
|
|
mService->removeResource(kTestPid1, getId(mTestClient1), resources2);
|
|
EXPECT_EQ(4u, mSystemCB->eventCount());
|
|
EXPECT_EQ(EventType::CPUSET_DISABLE, mSystemCB->lastEventType());
|
|
}
|
|
|
|
void testReclaimResources_withVideoCodec_reclaimsOnlyVideoCodec() {
|
|
const std::shared_ptr<IResourceManagerClient>& audioImageTestClient = mTestClient1;
|
|
const std::shared_ptr<IResourceManagerClient>& videoTestClient = mTestClient2;
|
|
|
|
// Create an audio and image codec resource
|
|
std::vector<MediaResourceParcel> audioImageResources;
|
|
audioImageResources.push_back(createNonSecureAudioCodecResource());
|
|
audioImageResources.push_back(createNonSecureImageCodecResource());
|
|
mService->addResource(kLowPriorityPid, kTestUid1, getId(audioImageTestClient),
|
|
audioImageTestClient, audioImageResources);
|
|
|
|
// Fail to reclaim a video codec resource
|
|
std::vector<MediaResourceParcel> reclaimResources;
|
|
reclaimResources.push_back(createNonSecureVideoCodecResource());
|
|
CHECK_STATUS_FALSE(mService->reclaimResource(kHighPriorityPid, reclaimResources, &result));
|
|
|
|
// Now add a video codec resource
|
|
std::vector<MediaResourceParcel> videoResources;
|
|
videoResources.push_back(createNonSecureVideoCodecResource());
|
|
mService->addResource(kLowPriorityPid, kTestUid1, getId(videoTestClient), videoTestClient,
|
|
videoResources);
|
|
|
|
// Verify that the newly-created video codec resource can be reclaimed
|
|
CHECK_STATUS_TRUE(mService->reclaimResource(kHighPriorityPid, reclaimResources, &result));
|
|
|
|
// Verify that the audio and image resources are untouched
|
|
EXPECT_FALSE(toTestClient(audioImageTestClient)->checkIfReclaimedAndReset());
|
|
// But the video resource was reclaimed
|
|
EXPECT_TRUE(toTestClient(videoTestClient)->checkIfReclaimedAndReset());
|
|
}
|
|
|
|
void testReclaimResources_withAudioCodec_reclaimsOnlyAudioCodec() {
|
|
const auto & videoImageTestClient = mTestClient1;
|
|
const auto & audioTestClient = mTestClient2;
|
|
|
|
// Create a video and audio codec resource
|
|
std::vector<MediaResourceParcel> videoImageResources;
|
|
videoImageResources.push_back(createNonSecureVideoCodecResource());
|
|
videoImageResources.push_back(createNonSecureImageCodecResource());
|
|
mService->addResource(kLowPriorityPid, kTestUid1, getId(videoImageTestClient),
|
|
videoImageTestClient, videoImageResources);
|
|
|
|
// Fail to reclaim an audio codec resource
|
|
std::vector<MediaResourceParcel> reclaimResources;
|
|
reclaimResources.push_back(createNonSecureAudioCodecResource());
|
|
CHECK_STATUS_FALSE(mService->reclaimResource(kHighPriorityPid, reclaimResources, &result));
|
|
|
|
// Now add an audio codec resource
|
|
std::vector<MediaResourceParcel> audioResources;
|
|
audioResources.push_back(createNonSecureAudioCodecResource());
|
|
mService->addResource(kLowPriorityPid, kTestUid2, getId(audioTestClient), audioTestClient,
|
|
audioResources);
|
|
|
|
// Verify that the newly-created audio codec resource can be reclaimed
|
|
CHECK_STATUS_TRUE(mService->reclaimResource(kHighPriorityPid, reclaimResources, &result));
|
|
|
|
// Verify that the video and image resources are untouched
|
|
EXPECT_FALSE(toTestClient(videoImageTestClient)->checkIfReclaimedAndReset());
|
|
// But the audio resource was reclaimed
|
|
EXPECT_TRUE(toTestClient(audioTestClient)->checkIfReclaimedAndReset());
|
|
}
|
|
|
|
void testReclaimResources_withImageCodec_reclaimsOnlyImageCodec() {
|
|
const auto & videoAudioTestClient = mTestClient1;
|
|
const auto & imageTestClient = mTestClient2;
|
|
|
|
// Create a video and audio codec resource
|
|
std::vector<MediaResourceParcel> videoAudioResources;
|
|
videoAudioResources.push_back(createNonSecureVideoCodecResource());
|
|
videoAudioResources.push_back(createNonSecureAudioCodecResource());
|
|
mService->addResource(kLowPriorityPid, kTestUid1, getId(videoAudioTestClient),
|
|
videoAudioTestClient, videoAudioResources);
|
|
|
|
// Fail to reclaim an image codec resource
|
|
std::vector<MediaResourceParcel> reclaimResources;
|
|
reclaimResources.push_back(createNonSecureImageCodecResource());
|
|
CHECK_STATUS_FALSE(mService->reclaimResource(kHighPriorityPid, reclaimResources, &result));
|
|
|
|
// Now add an image codec resource
|
|
std::vector<MediaResourceParcel> imageResources;
|
|
imageResources.push_back(createNonSecureImageCodecResource());
|
|
mService->addResource(kLowPriorityPid, kTestUid2, getId(imageTestClient), imageTestClient,
|
|
imageResources);
|
|
|
|
// Verify that the newly-created image codec resource can be reclaimed
|
|
CHECK_STATUS_TRUE(mService->reclaimResource(kHighPriorityPid, reclaimResources, &result));
|
|
|
|
// Verify that the video and audio resources are untouched
|
|
EXPECT_FALSE(toTestClient(mTestClient1)->checkIfReclaimedAndReset());
|
|
// But the image resource was reclaimed
|
|
EXPECT_TRUE(toTestClient(mTestClient2)->checkIfReclaimedAndReset());
|
|
}
|
|
|
|
void testReclaimResources_whenPartialResourceMatch_reclaims() {
|
|
const int onlyUid = kTestUid1;
|
|
const auto onlyClient = createTestClient(kLowPriorityPid);
|
|
|
|
std::vector<MediaResourceParcel> ownedResources;
|
|
ownedResources.push_back(createNonSecureVideoCodecResource());
|
|
ownedResources.push_back(createGraphicMemoryResource(100));
|
|
mService->addResource(kLowPriorityPid, onlyUid, getId(onlyClient), onlyClient,
|
|
ownedResources);
|
|
|
|
// Reclaim an image codec instead of the video codec that is owned, but also reclaim
|
|
// graphics memory, which will trigger the reclaim.
|
|
std::vector<MediaResourceParcel> reclaimResources;
|
|
reclaimResources.push_back(createNonSecureImageCodecResource());
|
|
reclaimResources.push_back(createGraphicMemoryResource(100));
|
|
CHECK_STATUS_TRUE(mService->reclaimResource(kHighPriorityPid, reclaimResources, &result));
|
|
|
|
// Verify that the video codec resources (including the needed graphic memory) is reclaimed
|
|
EXPECT_TRUE(toTestClient(onlyClient)->checkIfReclaimedAndReset());
|
|
}
|
|
|
|
void testReclaimResourcesFromMarkedClients_removesBiggestMarkedClientForSomeResources() {
|
|
// this test only uses one pid and one uid
|
|
const int onlyPid = kTestPid1;
|
|
const int onlyUid = kTestUid1;
|
|
|
|
// secure video codec
|
|
const auto smallSecureVideoMarkedClient = createTestClient(onlyPid);
|
|
const auto largeSecureVideoMarkedClient = createTestClient(onlyPid);
|
|
const auto largestSecureVideoActiveClient = createTestClient(onlyPid);
|
|
{
|
|
std::vector<MediaResourceParcel> resources;
|
|
resources.push_back(createSecureVideoCodecResource(1));
|
|
mService->addResource(onlyPid, onlyUid, getId(smallSecureVideoMarkedClient),
|
|
smallSecureVideoMarkedClient, resources);
|
|
resources.clear();
|
|
resources.push_back(createSecureVideoCodecResource(2));
|
|
mService->addResource(onlyPid, onlyUid, getId(largeSecureVideoMarkedClient),
|
|
largeSecureVideoMarkedClient, resources);
|
|
resources.clear();
|
|
resources.push_back(createSecureVideoCodecResource(3));
|
|
mService->addResource(onlyPid, onlyUid, getId(largestSecureVideoActiveClient),
|
|
largestSecureVideoActiveClient, resources);
|
|
}
|
|
mService->markClientForPendingRemoval(onlyPid, getId(smallSecureVideoMarkedClient));
|
|
mService->markClientForPendingRemoval(onlyPid, getId(largeSecureVideoMarkedClient));
|
|
// don't mark the largest client
|
|
|
|
// non-secure video codec
|
|
const auto smallNonSecureVideoMarkedClient = createTestClient(onlyPid);
|
|
const auto largeNonSecureVideoMarkedClient = createTestClient(onlyPid);
|
|
const auto largestNonSecureVideoActiveClient = createTestClient(onlyPid);
|
|
{
|
|
std::vector<MediaResourceParcel> resources;
|
|
resources.push_back(createNonSecureVideoCodecResource(1));
|
|
mService->addResource(onlyPid, onlyUid, getId(smallNonSecureVideoMarkedClient),
|
|
smallNonSecureVideoMarkedClient, resources);
|
|
resources.clear();
|
|
resources.push_back(createNonSecureVideoCodecResource(2));
|
|
mService->addResource(onlyPid, onlyUid, getId(largeNonSecureVideoMarkedClient),
|
|
largeNonSecureVideoMarkedClient, resources);
|
|
resources.clear();
|
|
resources.push_back(createNonSecureVideoCodecResource(3));
|
|
mService->addResource(onlyPid, onlyUid, getId(largestNonSecureVideoActiveClient),
|
|
largestNonSecureVideoActiveClient, resources);
|
|
}
|
|
mService->markClientForPendingRemoval(onlyPid, getId(smallNonSecureVideoMarkedClient));
|
|
mService->markClientForPendingRemoval(onlyPid, getId(largeNonSecureVideoMarkedClient));
|
|
// don't mark the largest client
|
|
|
|
// secure audio codec
|
|
const auto smallSecureAudioMarkedClient = createTestClient(onlyPid);
|
|
const auto largeSecureAudioMarkedClient = createTestClient(onlyPid);
|
|
const auto largestSecureAudioActiveClient = createTestClient(onlyPid);
|
|
{
|
|
std::vector<MediaResourceParcel> resources;
|
|
resources.push_back(createSecureAudioCodecResource(1));
|
|
mService->addResource(onlyPid, onlyUid, getId(smallSecureAudioMarkedClient),
|
|
smallSecureAudioMarkedClient, resources);
|
|
resources.clear();
|
|
resources.push_back(createSecureAudioCodecResource(2));
|
|
mService->addResource(onlyPid, onlyUid, getId(largeSecureAudioMarkedClient),
|
|
largeSecureAudioMarkedClient, resources);
|
|
resources.clear();
|
|
resources.push_back(createSecureAudioCodecResource(3));
|
|
mService->addResource(onlyPid, onlyUid, getId(largestSecureVideoActiveClient),
|
|
largestSecureVideoActiveClient, resources);
|
|
}
|
|
mService->markClientForPendingRemoval(onlyPid, getId(smallSecureAudioMarkedClient));
|
|
mService->markClientForPendingRemoval(onlyPid, getId(largeSecureAudioMarkedClient));
|
|
// don't mark the largest client
|
|
|
|
// non-secure audio codec
|
|
const auto smallNonSecureAudioMarkedClient = createTestClient(onlyPid);
|
|
const auto largeNonSecureAudioMarkedClient = createTestClient(onlyPid);
|
|
const auto largestNonSecureAudioActiveClient = createTestClient(onlyPid);
|
|
{
|
|
std::vector<MediaResourceParcel> resources;
|
|
resources.push_back(createNonSecureAudioCodecResource(1));
|
|
mService->addResource(onlyPid, onlyUid, getId(smallNonSecureAudioMarkedClient),
|
|
smallNonSecureAudioMarkedClient, resources);
|
|
resources.clear();
|
|
resources.push_back(createNonSecureAudioCodecResource(2));
|
|
mService->addResource(onlyPid, onlyUid, getId(largeNonSecureAudioMarkedClient),
|
|
largeNonSecureAudioMarkedClient, resources);
|
|
resources.clear();
|
|
resources.push_back(createNonSecureAudioCodecResource(3));
|
|
mService->addResource(onlyPid, onlyUid, getId(largestNonSecureAudioActiveClient),
|
|
largestNonSecureAudioActiveClient, resources);
|
|
}
|
|
mService->markClientForPendingRemoval(onlyPid, getId(smallNonSecureAudioMarkedClient));
|
|
mService->markClientForPendingRemoval(onlyPid, getId(largeNonSecureAudioMarkedClient));
|
|
// don't mark the largest client
|
|
|
|
// secure image codec
|
|
const auto smallSecureImageMarkedClient = createTestClient(onlyPid);
|
|
const auto largeSecureImageMarkedClient = createTestClient(onlyPid);
|
|
const auto largestSecureImageActiveClient = createTestClient(onlyPid);
|
|
{
|
|
std::vector<MediaResourceParcel> resources;
|
|
resources.push_back(createSecureImageCodecResource(1));
|
|
mService->addResource(onlyPid, onlyUid, getId(smallSecureImageMarkedClient),
|
|
smallSecureImageMarkedClient, resources);
|
|
resources.clear();
|
|
resources.push_back(createSecureImageCodecResource(2));
|
|
mService->addResource(onlyPid, onlyUid, getId(largeSecureImageMarkedClient),
|
|
largeSecureImageMarkedClient, resources);
|
|
resources.clear();
|
|
resources.push_back(createSecureImageCodecResource(3));
|
|
mService->addResource(onlyPid, onlyUid, getId(largestSecureImageActiveClient),
|
|
largestSecureImageActiveClient, resources);
|
|
}
|
|
mService->markClientForPendingRemoval(onlyPid, getId(smallSecureImageMarkedClient));
|
|
mService->markClientForPendingRemoval(onlyPid, getId(largeSecureImageMarkedClient));
|
|
// don't mark the largest client
|
|
|
|
// non-secure image codec
|
|
const auto smallNonSecureImageMarkedClient = createTestClient(onlyPid);
|
|
const auto largeNonSecureImageMarkedClient = createTestClient(onlyPid);
|
|
const auto largestNonSecureImageActiveClient = createTestClient(onlyPid);
|
|
{
|
|
std::vector<MediaResourceParcel> resources;
|
|
resources.push_back(createNonSecureImageCodecResource(1));
|
|
mService->addResource(onlyPid, onlyUid, getId(smallNonSecureImageMarkedClient),
|
|
smallNonSecureImageMarkedClient, resources);
|
|
resources.clear();
|
|
resources.push_back(createNonSecureImageCodecResource(2));
|
|
mService->addResource(onlyPid, onlyUid, getId(largeNonSecureImageMarkedClient),
|
|
largeNonSecureImageMarkedClient, resources);
|
|
resources.clear();
|
|
resources.push_back(createNonSecureImageCodecResource(3));
|
|
mService->addResource(onlyPid, onlyUid, getId(largestNonSecureImageActiveClient),
|
|
largestNonSecureImageActiveClient, resources);
|
|
}
|
|
mService->markClientForPendingRemoval(onlyPid, getId(smallNonSecureImageMarkedClient));
|
|
mService->markClientForPendingRemoval(onlyPid, getId(largeNonSecureImageMarkedClient));
|
|
// don't mark the largest client
|
|
|
|
// graphic memory
|
|
const auto smallGraphicMemoryMarkedClient = createTestClient(onlyPid);
|
|
const auto largeGraphicMemoryMarkedClient = createTestClient(onlyPid);
|
|
const auto largestGraphicMemoryActiveClient = createTestClient(onlyPid);
|
|
{
|
|
std::vector<MediaResourceParcel> resources;
|
|
resources.push_back(createGraphicMemoryResource(100));
|
|
mService->addResource(onlyPid, onlyUid, getId(smallGraphicMemoryMarkedClient),
|
|
smallGraphicMemoryMarkedClient, resources);
|
|
resources.clear();
|
|
resources.push_back(createGraphicMemoryResource(200));
|
|
mService->addResource(onlyPid, onlyUid, getId(largeGraphicMemoryMarkedClient),
|
|
largeGraphicMemoryMarkedClient, resources);
|
|
resources.clear();
|
|
resources.push_back(createGraphicMemoryResource(300));
|
|
mService->addResource(onlyPid, onlyUid, getId(largestGraphicMemoryActiveClient),
|
|
largestGraphicMemoryActiveClient, resources);
|
|
}
|
|
mService->markClientForPendingRemoval(onlyPid, getId(smallGraphicMemoryMarkedClient));
|
|
mService->markClientForPendingRemoval(onlyPid, getId(largeGraphicMemoryMarkedClient));
|
|
// don't mark the largest client
|
|
|
|
// DRM session
|
|
const auto smallDrmSessionMarkedClient = createTestClient(onlyPid);
|
|
const auto largeDrmSessionMarkedClient = createTestClient(onlyPid);
|
|
const auto largestDrmSessionActiveClient = createTestClient(onlyPid);
|
|
{
|
|
std::vector<MediaResourceParcel> resources;
|
|
resources.push_back(createDrmSessionResource(1));
|
|
mService->addResource(onlyPid, onlyUid, getId(smallDrmSessionMarkedClient),
|
|
smallDrmSessionMarkedClient, resources);
|
|
resources.clear();
|
|
resources.push_back(createDrmSessionResource(2));
|
|
mService->addResource(onlyPid, onlyUid, getId(largeDrmSessionMarkedClient),
|
|
largeDrmSessionMarkedClient, resources);
|
|
resources.clear();
|
|
resources.push_back(createDrmSessionResource(3));
|
|
mService->addResource(onlyPid, onlyUid, getId(largestDrmSessionActiveClient),
|
|
largestDrmSessionActiveClient, resources);
|
|
}
|
|
mService->markClientForPendingRemoval(onlyPid, getId(smallDrmSessionMarkedClient));
|
|
mService->markClientForPendingRemoval(onlyPid, getId(largeDrmSessionMarkedClient));
|
|
// don't mark the largest client
|
|
|
|
// battery
|
|
const auto batteryMarkedClient = createTestClient(onlyPid);
|
|
{
|
|
std::vector<MediaResourceParcel> resources;
|
|
resources.push_back(createBatteryResource());
|
|
mService->addResource(onlyPid, onlyUid, getId(batteryMarkedClient),
|
|
batteryMarkedClient, resources);
|
|
}
|
|
mService->markClientForPendingRemoval(onlyPid, getId(batteryMarkedClient));
|
|
|
|
// CPU boost
|
|
const auto cpuBoostMarkedClient = createTestClient(onlyPid);
|
|
{
|
|
std::vector<MediaResourceParcel> resources;
|
|
resources.push_back(createCpuBoostResource());
|
|
mService->addResource(onlyPid, onlyUid, getId(cpuBoostMarkedClient),
|
|
cpuBoostMarkedClient, resources);
|
|
}
|
|
mService->markClientForPendingRemoval(onlyPid, getId(cpuBoostMarkedClient));
|
|
|
|
// now we expect that we only reclaim resources from the biggest marked client
|
|
EXPECT_TRUE(mService->reclaimResourcesFromClientsPendingRemoval(onlyPid).isOk());
|
|
// secure video codec
|
|
EXPECT_FALSE(toTestClient(smallSecureVideoMarkedClient)->checkIfReclaimedAndReset());
|
|
EXPECT_TRUE(toTestClient(largeSecureVideoMarkedClient)->checkIfReclaimedAndReset());
|
|
EXPECT_FALSE(toTestClient(largestSecureVideoActiveClient)->checkIfReclaimedAndReset());
|
|
// non-secure video codec
|
|
EXPECT_FALSE(toTestClient(smallNonSecureVideoMarkedClient)->checkIfReclaimedAndReset());
|
|
EXPECT_TRUE(toTestClient(largeNonSecureVideoMarkedClient)->checkIfReclaimedAndReset());
|
|
EXPECT_FALSE(toTestClient(largestNonSecureVideoActiveClient)->checkIfReclaimedAndReset());
|
|
// secure audio codec
|
|
EXPECT_FALSE(toTestClient(smallSecureAudioMarkedClient)->checkIfReclaimedAndReset());
|
|
EXPECT_TRUE(toTestClient(largeSecureAudioMarkedClient)->checkIfReclaimedAndReset());
|
|
EXPECT_FALSE(toTestClient(largestSecureAudioActiveClient)->checkIfReclaimedAndReset());
|
|
// non-secure audio codec
|
|
EXPECT_FALSE(toTestClient(smallNonSecureAudioMarkedClient)->checkIfReclaimedAndReset());
|
|
EXPECT_TRUE(toTestClient(largeNonSecureAudioMarkedClient)->checkIfReclaimedAndReset());
|
|
EXPECT_FALSE(toTestClient(largestNonSecureAudioActiveClient)->checkIfReclaimedAndReset());
|
|
// secure image codec
|
|
EXPECT_FALSE(toTestClient(smallSecureImageMarkedClient)->checkIfReclaimedAndReset());
|
|
EXPECT_TRUE(toTestClient(largeSecureImageMarkedClient)->checkIfReclaimedAndReset());
|
|
EXPECT_FALSE(toTestClient(largestSecureImageActiveClient)->checkIfReclaimedAndReset());
|
|
// non-secure image codec
|
|
EXPECT_FALSE(toTestClient(smallNonSecureImageMarkedClient)->checkIfReclaimedAndReset());
|
|
EXPECT_TRUE(toTestClient(largeNonSecureImageMarkedClient)->checkIfReclaimedAndReset());
|
|
EXPECT_FALSE(toTestClient(largestNonSecureImageActiveClient)->checkIfReclaimedAndReset());
|
|
// graphic memory
|
|
EXPECT_FALSE(toTestClient(smallGraphicMemoryMarkedClient)->checkIfReclaimedAndReset());
|
|
EXPECT_TRUE(toTestClient(largeGraphicMemoryMarkedClient)->checkIfReclaimedAndReset());
|
|
EXPECT_FALSE(toTestClient(largestGraphicMemoryActiveClient)->checkIfReclaimedAndReset());
|
|
// DRM session
|
|
EXPECT_FALSE(toTestClient(smallDrmSessionMarkedClient)->checkIfReclaimedAndReset());
|
|
EXPECT_TRUE(toTestClient(largeDrmSessionMarkedClient)->checkIfReclaimedAndReset());
|
|
EXPECT_FALSE(toTestClient(largestDrmSessionActiveClient)->checkIfReclaimedAndReset());
|
|
// battery is not expected to be reclaimed when marked as pending removal
|
|
EXPECT_FALSE(toTestClient(batteryMarkedClient)->checkIfReclaimedAndReset());
|
|
// CPU boost is not expected to be reclaimed when marked as pending removal
|
|
EXPECT_FALSE(toTestClient(cpuBoostMarkedClient)->checkIfReclaimedAndReset());
|
|
}
|
|
};
|
|
|
|
TEST_F(ResourceManagerServiceTest, config) {
|
|
testConfig();
|
|
}
|
|
|
|
TEST_F(ResourceManagerServiceTest, addResource) {
|
|
addResource();
|
|
}
|
|
|
|
TEST_F(ResourceManagerServiceTest, combineResource) {
|
|
testCombineResource();
|
|
}
|
|
|
|
TEST_F(ResourceManagerServiceTest, combineResourceNegative) {
|
|
testCombineResourceWithNegativeValues();
|
|
}
|
|
|
|
TEST_F(ResourceManagerServiceTest, removeResource) {
|
|
testRemoveResource();
|
|
}
|
|
|
|
TEST_F(ResourceManagerServiceTest, removeClient) {
|
|
testRemoveClient();
|
|
}
|
|
|
|
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, isCallingPriorityHigher_l) {
|
|
testIsCallingPriorityHigher();
|
|
}
|
|
|
|
TEST_F(ResourceManagerServiceTest, batteryStats) {
|
|
testBatteryStats();
|
|
}
|
|
|
|
TEST_F(ResourceManagerServiceTest, cpusetBoost) {
|
|
testCpusetBoost();
|
|
}
|
|
|
|
TEST_F(ResourceManagerServiceTest, overridePid) {
|
|
testOverridePid();
|
|
}
|
|
|
|
TEST_F(ResourceManagerServiceTest, markClientForPendingRemoval) {
|
|
testMarkClientForPendingRemoval();
|
|
}
|
|
|
|
TEST_F(ResourceManagerServiceTest, reclaimResources_withVideoCodec_reclaimsOnlyVideoCodec) {
|
|
testReclaimResources_withVideoCodec_reclaimsOnlyVideoCodec();
|
|
}
|
|
|
|
TEST_F(ResourceManagerServiceTest, reclaimResources_withAudioCodec_reclaimsOnlyAudioCodec) {
|
|
testReclaimResources_withAudioCodec_reclaimsOnlyAudioCodec();
|
|
}
|
|
|
|
TEST_F(ResourceManagerServiceTest, reclaimResources_withImageCodec_reclaimsOnlyImageCodec) {
|
|
testReclaimResources_withImageCodec_reclaimsOnlyImageCodec();
|
|
}
|
|
|
|
TEST_F(ResourceManagerServiceTest, reclaimResources_whenPartialResourceMatch_reclaims) {
|
|
testReclaimResources_whenPartialResourceMatch_reclaims();
|
|
}
|
|
|
|
TEST_F(ResourceManagerServiceTest,
|
|
reclaimResourcesFromMarkedClients_removesBiggestMarkedClientForSomeResources) {
|
|
testReclaimResourcesFromMarkedClients_removesBiggestMarkedClientForSomeResources();
|
|
}
|
|
|
|
} // namespace android
|