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
30namespace android {
31
32static int64_t getId(sp<IResourceManagerClient> client) {
33    return (int64_t) client.get();
34}
35
36struct TestProcessInfo : public ProcessInfoInterface {
37    TestProcessInfo() {}
38    virtual ~TestProcessInfo() {}
39
40    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    virtual bool isValidPid(int /* pid */) {
48        return true;
49    }
50
51private:
52    DISALLOW_EVIL_CONSTRUCTORS(TestProcessInfo);
53};
54
55struct TestClient : public BnResourceManagerClient {
56    TestClient(int pid, sp<ResourceManagerService> service)
57        : mReclaimed(false), mPid(pid), mService(service) {}
58
59    virtual bool reclaimResource() {
60        sp<IResourceManagerClient> client(this);
61        mService->removeResource(mPid, (int64_t) client.get());
62        mReclaimed = true;
63        return true;
64    }
65
66    virtual String8 getName() {
67        return String8("test_client");
68    }
69
70    bool reclaimed() const {
71        return mReclaimed;
72    }
73
74    void reset() {
75        mReclaimed = false;
76    }
77
78protected:
79    virtual ~TestClient() {}
80
81private:
82    bool mReclaimed;
83    int mPid;
84    sp<ResourceManagerService> mService;
85    DISALLOW_EVIL_CONSTRUCTORS(TestClient);
86};
87
88static const int kTestPid1 = 30;
89static const int kTestPid2 = 20;
90
91static const int kLowPriorityPid = 40;
92static const int kMidPriorityPid = 25;
93static const int kHighPriorityPid = 10;
94
95class ResourceManagerServiceTest : public ::testing::Test {
96public:
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
104protected:
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
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
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    // ---------------------------------------------------------------------------------
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
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
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
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
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
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
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
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
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
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
507TEST_F(ResourceManagerServiceTest, config) {
508    testConfig();
509}
510
511TEST_F(ResourceManagerServiceTest, addResource) {
512    addResource();
513}
514
515TEST_F(ResourceManagerServiceTest, removeResource) {
516    testRemoveResource();
517}
518
519TEST_F(ResourceManagerServiceTest, reclaimResource) {
520    testReclaimResourceSecure();
521    testReclaimResourceNonSecure();
522}
523
524TEST_F(ResourceManagerServiceTest, getAllClients_l) {
525    testGetAllClients();
526}
527
528TEST_F(ResourceManagerServiceTest, getLowestPriorityBiggestClient_l) {
529    testGetLowestPriorityBiggestClient();
530}
531
532TEST_F(ResourceManagerServiceTest, getLowestPriorityPid_l) {
533    testGetLowestPriorityPid();
534}
535
536TEST_F(ResourceManagerServiceTest, getBiggestClient_l) {
537    testGetBiggestClient();
538}
539
540TEST_F(ResourceManagerServiceTest, isCallingPriorityHigher_l) {
541    testIsCallingPriorityHigher();
542}
543
544} // namespace android
545