1 /*
2  * Copyright 2015 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 //#define LOG_NDEBUG 0
18 #define LOG_TAG "ResourceManagerService_test"
19 #include <utils/Log.h>
20 
21 #include <gtest/gtest.h>
22 
23 #include "ResourceManagerService.h"
24 #include <media/IResourceManagerService.h>
25 #include <media/MediaResource.h>
26 #include <media/MediaResourcePolicy.h>
27 #include <media/stagefright/foundation/ADebug.h>
28 #include <media/stagefright/ProcessInfoInterface.h>
29 
30 namespace android {
31 
getId(sp<IResourceManagerClient> client)32 static int64_t getId(sp<IResourceManagerClient> client) {
33     return (int64_t) client.get();
34 }
35 
36 struct TestProcessInfo : public ProcessInfoInterface {
TestProcessInfoandroid::TestProcessInfo37     TestProcessInfo() {}
~TestProcessInfoandroid::TestProcessInfo38     virtual ~TestProcessInfo() {}
39 
getPriorityandroid::TestProcessInfo40     virtual bool getPriority(int pid, int *priority) {
41         // For testing, use pid as priority.
42         // Lower the value higher the priority.
43         *priority = pid;
44         return true;
45     }
46 
isValidPidandroid::TestProcessInfo47     virtual bool isValidPid(int /* pid */) {
48         return true;
49     }
50 
51 private:
52     DISALLOW_EVIL_CONSTRUCTORS(TestProcessInfo);
53 };
54 
55 struct TestClient : public BnResourceManagerClient {
TestClientandroid::TestClient56     TestClient(int pid, sp<ResourceManagerService> service)
57         : mReclaimed(false), mPid(pid), mService(service) {}
58 
reclaimResourceandroid::TestClient59     virtual bool reclaimResource() {
60         sp<IResourceManagerClient> client(this);
61         mService->removeResource(mPid, (int64_t) client.get());
62         mReclaimed = true;
63         return true;
64     }
65 
getNameandroid::TestClient66     virtual String8 getName() {
67         return String8("test_client");
68     }
69 
reclaimedandroid::TestClient70     bool reclaimed() const {
71         return mReclaimed;
72     }
73 
resetandroid::TestClient74     void reset() {
75         mReclaimed = false;
76     }
77 
78 protected:
~TestClientandroid::TestClient79     virtual ~TestClient() {}
80 
81 private:
82     bool mReclaimed;
83     int mPid;
84     sp<ResourceManagerService> mService;
85     DISALLOW_EVIL_CONSTRUCTORS(TestClient);
86 };
87 
88 static const int kTestPid1 = 30;
89 static const int kTestPid2 = 20;
90 
91 static const int kLowPriorityPid = 40;
92 static const int kMidPriorityPid = 25;
93 static const int kHighPriorityPid = 10;
94 
95 class ResourceManagerServiceTest : public ::testing::Test {
96 public:
ResourceManagerServiceTest()97     ResourceManagerServiceTest()
98         : mService(new ResourceManagerService(new TestProcessInfo)),
99           mTestClient1(new TestClient(kTestPid1, mService)),
100           mTestClient2(new TestClient(kTestPid2, mService)),
101           mTestClient3(new TestClient(kTestPid2, mService)) {
102     }
103 
104 protected:
isEqualResources(const Vector<MediaResource> & resources1,const Vector<MediaResource> & resources2)105     static bool isEqualResources(const Vector<MediaResource> &resources1,
106             const Vector<MediaResource> &resources2) {
107         if (resources1.size() != resources2.size()) {
108             return false;
109         }
110         for (size_t i = 0; i < resources1.size(); ++i) {
111             if (resources1[i] != resources2[i]) {
112                 return false;
113             }
114         }
115         return true;
116     }
117 
expectEqResourceInfo(const ResourceInfo & info,sp<IResourceManagerClient> client,const Vector<MediaResource> & resources)118     static void expectEqResourceInfo(const ResourceInfo &info, sp<IResourceManagerClient> client,
119             const Vector<MediaResource> &resources) {
120         EXPECT_EQ(client, info.client);
121         EXPECT_TRUE(isEqualResources(resources, info.resources));
122     }
123 
verifyClients(bool c1,bool c2,bool c3)124     void verifyClients(bool c1, bool c2, bool c3) {
125         TestClient *client1 = static_cast<TestClient*>(mTestClient1.get());
126         TestClient *client2 = static_cast<TestClient*>(mTestClient2.get());
127         TestClient *client3 = static_cast<TestClient*>(mTestClient3.get());
128 
129         EXPECT_EQ(c1, client1->reclaimed());
130         EXPECT_EQ(c2, client2->reclaimed());
131         EXPECT_EQ(c3, client3->reclaimed());
132 
133         client1->reset();
134         client2->reset();
135         client3->reset();
136     }
137 
138     // test set up
139     // ---------------------------------------------------------------------------------
140     //   pid                priority         client           type               number
141     // ---------------------------------------------------------------------------------
142     //   kTestPid1(30)      30               mTestClient1     secure codec       1
143     //                                                        graphic memory     200
144     //                                                        graphic memory     200
145     // ---------------------------------------------------------------------------------
146     //   kTestPid2(20)      20               mTestClient2     non-secure codec   1
147     //                                                        graphic memory     300
148     //                                       -------------------------------------------
149     //                                       mTestClient3     secure codec       1
150     //                                                        graphic memory     100
151     // ---------------------------------------------------------------------------------
addResource()152     void addResource() {
153         // kTestPid1 mTestClient1
154         Vector<MediaResource> resources1;
155         resources1.push_back(MediaResource(MediaResource::kSecureCodec, 1));
156         mService->addResource(kTestPid1, getId(mTestClient1), mTestClient1, resources1);
157         resources1.push_back(MediaResource(MediaResource::kGraphicMemory, 200));
158         Vector<MediaResource> resources11;
159         resources11.push_back(MediaResource(MediaResource::kGraphicMemory, 200));
160         mService->addResource(kTestPid1, getId(mTestClient1), mTestClient1, resources11);
161 
162         // kTestPid2 mTestClient2
163         Vector<MediaResource> resources2;
164         resources2.push_back(MediaResource(MediaResource::kNonSecureCodec, 1));
165         resources2.push_back(MediaResource(MediaResource::kGraphicMemory, 300));
166         mService->addResource(kTestPid2, getId(mTestClient2), mTestClient2, resources2);
167 
168         // kTestPid2 mTestClient3
169         Vector<MediaResource> resources3;
170         mService->addResource(kTestPid2, getId(mTestClient3), mTestClient3, resources3);
171         resources3.push_back(MediaResource(MediaResource::kSecureCodec, 1));
172         resources3.push_back(MediaResource(MediaResource::kGraphicMemory, 100));
173         mService->addResource(kTestPid2, getId(mTestClient3), mTestClient3, resources3);
174 
175         const PidResourceInfosMap &map = mService->mMap;
176         EXPECT_EQ(2u, map.size());
177         ssize_t index1 = map.indexOfKey(kTestPid1);
178         ASSERT_GE(index1, 0);
179         const ResourceInfos &infos1 = map[index1];
180         EXPECT_EQ(1u, infos1.size());
181         expectEqResourceInfo(infos1[0], mTestClient1, resources1);
182 
183         ssize_t index2 = map.indexOfKey(kTestPid2);
184         ASSERT_GE(index2, 0);
185         const ResourceInfos &infos2 = map[index2];
186         EXPECT_EQ(2u, infos2.size());
187         expectEqResourceInfo(infos2[0], mTestClient2, resources2);
188         expectEqResourceInfo(infos2[1], mTestClient3, resources3);
189     }
190 
testConfig()191     void testConfig() {
192         EXPECT_TRUE(mService->mSupportsMultipleSecureCodecs);
193         EXPECT_TRUE(mService->mSupportsSecureWithNonSecureCodec);
194 
195         Vector<MediaResourcePolicy> policies1;
196         policies1.push_back(
197                 MediaResourcePolicy(
198                         String8(kPolicySupportsMultipleSecureCodecs),
199                         String8("true")));
200         policies1.push_back(
201                 MediaResourcePolicy(
202                         String8(kPolicySupportsSecureWithNonSecureCodec),
203                         String8("false")));
204         mService->config(policies1);
205         EXPECT_TRUE(mService->mSupportsMultipleSecureCodecs);
206         EXPECT_FALSE(mService->mSupportsSecureWithNonSecureCodec);
207 
208         Vector<MediaResourcePolicy> policies2;
209         policies2.push_back(
210                 MediaResourcePolicy(
211                         String8(kPolicySupportsMultipleSecureCodecs),
212                         String8("false")));
213         policies2.push_back(
214                 MediaResourcePolicy(
215                         String8(kPolicySupportsSecureWithNonSecureCodec),
216                         String8("true")));
217         mService->config(policies2);
218         EXPECT_FALSE(mService->mSupportsMultipleSecureCodecs);
219         EXPECT_TRUE(mService->mSupportsSecureWithNonSecureCodec);
220     }
221 
testRemoveResource()222     void testRemoveResource() {
223         addResource();
224 
225         mService->removeResource(kTestPid2, getId(mTestClient2));
226 
227         const PidResourceInfosMap &map = mService->mMap;
228         EXPECT_EQ(2u, map.size());
229         const ResourceInfos &infos1 = map.valueFor(kTestPid1);
230         const ResourceInfos &infos2 = map.valueFor(kTestPid2);
231         EXPECT_EQ(1u, infos1.size());
232         EXPECT_EQ(1u, infos2.size());
233         // mTestClient2 has been removed.
234         EXPECT_EQ(mTestClient3, infos2[0].client);
235     }
236 
testGetAllClients()237     void testGetAllClients() {
238         addResource();
239 
240         MediaResource::Type type = MediaResource::kSecureCodec;
241         Vector<sp<IResourceManagerClient> > clients;
242         EXPECT_FALSE(mService->getAllClients_l(kLowPriorityPid, type, &clients));
243         // some higher priority process (e.g. kTestPid2) owns the resource, so getAllClients_l
244         // will fail.
245         EXPECT_FALSE(mService->getAllClients_l(kMidPriorityPid, type, &clients));
246         EXPECT_TRUE(mService->getAllClients_l(kHighPriorityPid, type, &clients));
247 
248         EXPECT_EQ(2u, clients.size());
249         EXPECT_EQ(mTestClient3, clients[0]);
250         EXPECT_EQ(mTestClient1, clients[1]);
251     }
252 
testReclaimResourceSecure()253     void testReclaimResourceSecure() {
254         Vector<MediaResource> resources;
255         resources.push_back(MediaResource(MediaResource::kSecureCodec, 1));
256         resources.push_back(MediaResource(MediaResource::kGraphicMemory, 150));
257 
258         // ### secure codec can't coexist and secure codec can coexist with non-secure codec ###
259         {
260             addResource();
261             mService->mSupportsMultipleSecureCodecs = false;
262             mService->mSupportsSecureWithNonSecureCodec = true;
263 
264             // priority too low
265             EXPECT_FALSE(mService->reclaimResource(kLowPriorityPid, resources));
266             EXPECT_FALSE(mService->reclaimResource(kMidPriorityPid, resources));
267 
268             // reclaim all secure codecs
269             EXPECT_TRUE(mService->reclaimResource(kHighPriorityPid, resources));
270             verifyClients(true /* c1 */, false /* c2 */, true /* c3 */);
271 
272             // call again should reclaim one largest graphic memory from lowest process
273             EXPECT_TRUE(mService->reclaimResource(kHighPriorityPid, resources));
274             verifyClients(false /* c1 */, true /* c2 */, false /* c3 */);
275 
276             // nothing left
277             EXPECT_FALSE(mService->reclaimResource(kHighPriorityPid, resources));
278         }
279 
280         // ### secure codecs can't coexist and secure codec can't coexist with non-secure codec ###
281         {
282             addResource();
283             mService->mSupportsMultipleSecureCodecs = false;
284             mService->mSupportsSecureWithNonSecureCodec = false;
285 
286             // priority too low
287             EXPECT_FALSE(mService->reclaimResource(kLowPriorityPid, resources));
288             EXPECT_FALSE(mService->reclaimResource(kMidPriorityPid, resources));
289 
290             // reclaim all secure and non-secure codecs
291             EXPECT_TRUE(mService->reclaimResource(kHighPriorityPid, resources));
292             verifyClients(true /* c1 */, true /* c2 */, true /* c3 */);
293 
294             // nothing left
295             EXPECT_FALSE(mService->reclaimResource(kHighPriorityPid, resources));
296         }
297 
298 
299         // ### secure codecs can coexist but secure codec can't coexist with non-secure codec ###
300         {
301             addResource();
302             mService->mSupportsMultipleSecureCodecs = true;
303             mService->mSupportsSecureWithNonSecureCodec = false;
304 
305             // priority too low
306             EXPECT_FALSE(mService->reclaimResource(kLowPriorityPid, resources));
307             EXPECT_FALSE(mService->reclaimResource(kMidPriorityPid, resources));
308 
309             // reclaim all non-secure codecs
310             EXPECT_TRUE(mService->reclaimResource(kHighPriorityPid, resources));
311             verifyClients(false /* c1 */, true /* c2 */, false /* c3 */);
312 
313             // call again should reclaim one largest graphic memory from lowest process
314             EXPECT_TRUE(mService->reclaimResource(kHighPriorityPid, resources));
315             verifyClients(true /* c1 */, false /* c2 */, false /* c3 */);
316 
317             // call again should reclaim another largest graphic memory from lowest process
318             EXPECT_TRUE(mService->reclaimResource(kHighPriorityPid, resources));
319             verifyClients(false /* c1 */, false /* c2 */, true /* c3 */);
320 
321             // nothing left
322             EXPECT_FALSE(mService->reclaimResource(kHighPriorityPid, resources));
323         }
324 
325         // ### secure codecs can coexist and secure codec can coexist with non-secure codec ###
326         {
327             addResource();
328             mService->mSupportsMultipleSecureCodecs = true;
329             mService->mSupportsSecureWithNonSecureCodec = true;
330 
331             // priority too low
332             EXPECT_FALSE(mService->reclaimResource(kLowPriorityPid, resources));
333 
334             EXPECT_TRUE(mService->reclaimResource(kHighPriorityPid, resources));
335             // one largest graphic memory from lowest process got reclaimed
336             verifyClients(true /* c1 */, false /* c2 */, false /* c3 */);
337 
338             // call again should reclaim another graphic memory from lowest process
339             EXPECT_TRUE(mService->reclaimResource(kHighPriorityPid, resources));
340             verifyClients(false /* c1 */, true /* c2 */, false /* c3 */);
341 
342             // call again should reclaim another graphic memory from lowest process
343             EXPECT_TRUE(mService->reclaimResource(kHighPriorityPid, resources));
344             verifyClients(false /* c1 */, false /* c2 */, true /* c3 */);
345 
346             // nothing left
347             EXPECT_FALSE(mService->reclaimResource(kHighPriorityPid, resources));
348         }
349 
350         // ### secure codecs can coexist and secure codec can coexist with non-secure codec ###
351         {
352             addResource();
353             mService->mSupportsMultipleSecureCodecs = true;
354             mService->mSupportsSecureWithNonSecureCodec = true;
355 
356             Vector<MediaResource> resources;
357             resources.push_back(MediaResource(MediaResource::kSecureCodec, 1));
358 
359             EXPECT_TRUE(mService->reclaimResource(kHighPriorityPid, resources));
360             // secure codec from lowest process got reclaimed
361             verifyClients(true /* c1 */, false /* c2 */, false /* c3 */);
362 
363             // call again should reclaim another secure codec from lowest process
364             EXPECT_TRUE(mService->reclaimResource(kHighPriorityPid, resources));
365             verifyClients(false /* c1 */, false /* c2 */, true /* c3 */);
366 
367             // no more secure codec, non-secure codec will be reclaimed.
368             EXPECT_TRUE(mService->reclaimResource(kHighPriorityPid, resources));
369             verifyClients(false /* c1 */, true /* c2 */, false /* c3 */);
370         }
371     }
372 
testReclaimResourceNonSecure()373     void testReclaimResourceNonSecure() {
374         Vector<MediaResource> resources;
375         resources.push_back(MediaResource(MediaResource::kNonSecureCodec, 1));
376         resources.push_back(MediaResource(MediaResource::kGraphicMemory, 150));
377 
378         // ### secure codec can't coexist with non-secure codec ###
379         {
380             addResource();
381             mService->mSupportsSecureWithNonSecureCodec = false;
382 
383             // priority too low
384             EXPECT_FALSE(mService->reclaimResource(kLowPriorityPid, resources));
385             EXPECT_FALSE(mService->reclaimResource(kMidPriorityPid, resources));
386 
387             // reclaim all secure codecs
388             EXPECT_TRUE(mService->reclaimResource(kHighPriorityPid, resources));
389             verifyClients(true /* c1 */, false /* c2 */, true /* c3 */);
390 
391             // call again should reclaim one graphic memory from lowest process
392             EXPECT_TRUE(mService->reclaimResource(kHighPriorityPid, resources));
393             verifyClients(false /* c1 */, true /* c2 */, false /* c3 */);
394 
395             // nothing left
396             EXPECT_FALSE(mService->reclaimResource(kHighPriorityPid, resources));
397         }
398 
399 
400         // ### secure codec can coexist with non-secure codec ###
401         {
402             addResource();
403             mService->mSupportsSecureWithNonSecureCodec = true;
404 
405             // priority too low
406             EXPECT_FALSE(mService->reclaimResource(kLowPriorityPid, resources));
407 
408             EXPECT_TRUE(mService->reclaimResource(kHighPriorityPid, resources));
409             // one largest graphic memory from lowest process got reclaimed
410             verifyClients(true /* c1 */, false /* c2 */, false /* c3 */);
411 
412             // call again should reclaim another graphic memory from lowest process
413             EXPECT_TRUE(mService->reclaimResource(kHighPriorityPid, resources));
414             verifyClients(false /* c1 */, true /* c2 */, false /* c3 */);
415 
416             // call again should reclaim another graphic memory from lowest process
417             EXPECT_TRUE(mService->reclaimResource(kHighPriorityPid, resources));
418             verifyClients(false /* c1 */, false /* c2 */, true /* c3 */);
419 
420             // nothing left
421             EXPECT_FALSE(mService->reclaimResource(kHighPriorityPid, resources));
422         }
423 
424         // ### secure codec can coexist with non-secure codec ###
425         {
426             addResource();
427             mService->mSupportsSecureWithNonSecureCodec = true;
428 
429             Vector<MediaResource> resources;
430             resources.push_back(MediaResource(MediaResource::kNonSecureCodec, 1));
431 
432             EXPECT_TRUE(mService->reclaimResource(kHighPriorityPid, resources));
433             // one non secure codec from lowest process got reclaimed
434             verifyClients(false /* c1 */, true /* c2 */, false /* c3 */);
435 
436             // no more non-secure codec, secure codec from lowest priority process will be reclaimed
437             EXPECT_TRUE(mService->reclaimResource(kHighPriorityPid, resources));
438             verifyClients(true /* c1 */, false /* c2 */, false /* c3 */);
439 
440             // clean up client 3 which still left
441             mService->removeResource(kTestPid2, getId(mTestClient3));
442         }
443     }
444 
testGetLowestPriorityBiggestClient()445     void testGetLowestPriorityBiggestClient() {
446         MediaResource::Type type = MediaResource::kGraphicMemory;
447         sp<IResourceManagerClient> client;
448         EXPECT_FALSE(mService->getLowestPriorityBiggestClient_l(kHighPriorityPid, type, &client));
449 
450         addResource();
451 
452         EXPECT_FALSE(mService->getLowestPriorityBiggestClient_l(kLowPriorityPid, type, &client));
453         EXPECT_TRUE(mService->getLowestPriorityBiggestClient_l(kHighPriorityPid, type, &client));
454 
455         // kTestPid1 is the lowest priority process with MediaResource::kGraphicMemory.
456         // mTestClient1 has the largest MediaResource::kGraphicMemory within kTestPid1.
457         EXPECT_EQ(mTestClient1, client);
458     }
459 
testGetLowestPriorityPid()460     void testGetLowestPriorityPid() {
461         int pid;
462         int priority;
463         TestProcessInfo processInfo;
464 
465         MediaResource::Type type = MediaResource::kGraphicMemory;
466         EXPECT_FALSE(mService->getLowestPriorityPid_l(type, &pid, &priority));
467 
468         addResource();
469 
470         EXPECT_TRUE(mService->getLowestPriorityPid_l(type, &pid, &priority));
471         EXPECT_EQ(kTestPid1, pid);
472         int priority1;
473         processInfo.getPriority(kTestPid1, &priority1);
474         EXPECT_EQ(priority1, priority);
475 
476         type = MediaResource::kNonSecureCodec;
477         EXPECT_TRUE(mService->getLowestPriorityPid_l(type, &pid, &priority));
478         EXPECT_EQ(kTestPid2, pid);
479         int priority2;
480         processInfo.getPriority(kTestPid2, &priority2);
481         EXPECT_EQ(priority2, priority);
482     }
483 
testGetBiggestClient()484     void testGetBiggestClient() {
485         MediaResource::Type type = MediaResource::kGraphicMemory;
486         sp<IResourceManagerClient> client;
487         EXPECT_FALSE(mService->getBiggestClient_l(kTestPid2, type, &client));
488 
489         addResource();
490 
491         EXPECT_TRUE(mService->getBiggestClient_l(kTestPid2, type, &client));
492         EXPECT_EQ(mTestClient2, client);
493     }
494 
testIsCallingPriorityHigher()495     void testIsCallingPriorityHigher() {
496         EXPECT_FALSE(mService->isCallingPriorityHigher_l(101, 100));
497         EXPECT_FALSE(mService->isCallingPriorityHigher_l(100, 100));
498         EXPECT_TRUE(mService->isCallingPriorityHigher_l(99, 100));
499     }
500 
501     sp<ResourceManagerService> mService;
502     sp<IResourceManagerClient> mTestClient1;
503     sp<IResourceManagerClient> mTestClient2;
504     sp<IResourceManagerClient> mTestClient3;
505 };
506 
TEST_F(ResourceManagerServiceTest,config)507 TEST_F(ResourceManagerServiceTest, config) {
508     testConfig();
509 }
510 
TEST_F(ResourceManagerServiceTest,addResource)511 TEST_F(ResourceManagerServiceTest, addResource) {
512     addResource();
513 }
514 
TEST_F(ResourceManagerServiceTest,removeResource)515 TEST_F(ResourceManagerServiceTest, removeResource) {
516     testRemoveResource();
517 }
518 
TEST_F(ResourceManagerServiceTest,reclaimResource)519 TEST_F(ResourceManagerServiceTest, reclaimResource) {
520     testReclaimResourceSecure();
521     testReclaimResourceNonSecure();
522 }
523 
TEST_F(ResourceManagerServiceTest,getAllClients_l)524 TEST_F(ResourceManagerServiceTest, getAllClients_l) {
525     testGetAllClients();
526 }
527 
TEST_F(ResourceManagerServiceTest,getLowestPriorityBiggestClient_l)528 TEST_F(ResourceManagerServiceTest, getLowestPriorityBiggestClient_l) {
529     testGetLowestPriorityBiggestClient();
530 }
531 
TEST_F(ResourceManagerServiceTest,getLowestPriorityPid_l)532 TEST_F(ResourceManagerServiceTest, getLowestPriorityPid_l) {
533     testGetLowestPriorityPid();
534 }
535 
TEST_F(ResourceManagerServiceTest,getBiggestClient_l)536 TEST_F(ResourceManagerServiceTest, getBiggestClient_l) {
537     testGetBiggestClient();
538 }
539 
TEST_F(ResourceManagerServiceTest,isCallingPriorityHigher_l)540 TEST_F(ResourceManagerServiceTest, isCallingPriorityHigher_l) {
541     testIsCallingPriorityHigher();
542 }
543 
544 } // namespace android
545