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