1/*
2 * Copyright (C) 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 "DrmSessionManager_test"
19#include <utils/Log.h>
20
21#include <gtest/gtest.h>
22
23#include "Drm.h"
24#include "DrmSessionClientInterface.h"
25#include "DrmSessionManager.h"
26#include <media/stagefright/foundation/ADebug.h>
27#include <media/stagefright/ProcessInfoInterface.h>
28
29namespace android {
30
31struct FakeProcessInfo : public ProcessInfoInterface {
32    FakeProcessInfo() {}
33    virtual ~FakeProcessInfo() {}
34
35    virtual bool getPriority(int pid, int* priority) {
36        // For testing, use pid as priority.
37        // Lower the value higher the priority.
38        *priority = pid;
39        return true;
40    }
41
42private:
43    DISALLOW_EVIL_CONSTRUCTORS(FakeProcessInfo);
44};
45
46struct FakeDrm : public DrmSessionClientInterface {
47    FakeDrm() {}
48    virtual ~FakeDrm() {}
49
50    virtual bool reclaimSession(const Vector<uint8_t>& sessionId) {
51        mReclaimedSessions.push_back(sessionId);
52        return true;
53    }
54
55    const Vector<Vector<uint8_t> >& reclaimedSessions() const {
56        return mReclaimedSessions;
57    }
58
59private:
60    Vector<Vector<uint8_t> > mReclaimedSessions;
61
62    DISALLOW_EVIL_CONSTRUCTORS(FakeDrm);
63};
64
65static const int kTestPid1 = 30;
66static const int kTestPid2 = 20;
67static const uint8_t kTestSessionId1[] = {1, 2, 3};
68static const uint8_t kTestSessionId2[] = {4, 5, 6, 7, 8};
69static const uint8_t kTestSessionId3[] = {9, 0};
70
71class DrmSessionManagerTest : public ::testing::Test {
72public:
73    DrmSessionManagerTest()
74        : mDrmSessionManager(new DrmSessionManager(new FakeProcessInfo())),
75          mTestDrm1(new FakeDrm()),
76          mTestDrm2(new FakeDrm()) {
77        GetSessionId(kTestSessionId1, ARRAY_SIZE(kTestSessionId1), &mSessionId1);
78        GetSessionId(kTestSessionId2, ARRAY_SIZE(kTestSessionId2), &mSessionId2);
79        GetSessionId(kTestSessionId3, ARRAY_SIZE(kTestSessionId3), &mSessionId3);
80    }
81
82protected:
83    static void GetSessionId(const uint8_t* ids, size_t num, Vector<uint8_t>* sessionId) {
84        for (size_t i = 0; i < num; ++i) {
85            sessionId->push_back(ids[i]);
86        }
87    }
88
89    static void ExpectEqSessionInfo(const SessionInfo& info, sp<DrmSessionClientInterface> drm,
90            const Vector<uint8_t>& sessionId, int64_t timeStamp) {
91        EXPECT_EQ(drm, info.drm);
92        EXPECT_TRUE(isEqualSessionId(sessionId, info.sessionId));
93        EXPECT_EQ(timeStamp, info.timeStamp);
94    }
95
96    void addSession() {
97        mDrmSessionManager->addSession(kTestPid1, mTestDrm1, mSessionId1);
98        mDrmSessionManager->addSession(kTestPid2, mTestDrm2, mSessionId2);
99        mDrmSessionManager->addSession(kTestPid2, mTestDrm2, mSessionId3);
100        const PidSessionInfosMap& map = sessionMap();
101        EXPECT_EQ(2u, map.size());
102        ssize_t index1 = map.indexOfKey(kTestPid1);
103        ASSERT_GE(index1, 0);
104        const SessionInfos& infos1 = map[index1];
105        EXPECT_EQ(1u, infos1.size());
106        ExpectEqSessionInfo(infos1[0], mTestDrm1, mSessionId1, 0);
107
108        ssize_t index2 = map.indexOfKey(kTestPid2);
109        ASSERT_GE(index2, 0);
110        const SessionInfos& infos2 = map[index2];
111        EXPECT_EQ(2u, infos2.size());
112        ExpectEqSessionInfo(infos2[0], mTestDrm2, mSessionId2, 1);
113        ExpectEqSessionInfo(infos2[1], mTestDrm2, mSessionId3, 2);
114    }
115
116    const PidSessionInfosMap& sessionMap() {
117        return mDrmSessionManager->mSessionMap;
118    }
119
120    void testGetLowestPriority() {
121        int pid;
122        int priority;
123        EXPECT_FALSE(mDrmSessionManager->getLowestPriority_l(&pid, &priority));
124
125        addSession();
126        EXPECT_TRUE(mDrmSessionManager->getLowestPriority_l(&pid, &priority));
127
128        EXPECT_EQ(kTestPid1, pid);
129        FakeProcessInfo processInfo;
130        int priority1;
131        processInfo.getPriority(kTestPid1, &priority1);
132        EXPECT_EQ(priority1, priority);
133    }
134
135    void testGetLeastUsedSession() {
136        sp<DrmSessionClientInterface> drm;
137        Vector<uint8_t> sessionId;
138        EXPECT_FALSE(mDrmSessionManager->getLeastUsedSession_l(kTestPid1, &drm, &sessionId));
139
140        addSession();
141
142        EXPECT_TRUE(mDrmSessionManager->getLeastUsedSession_l(kTestPid1, &drm, &sessionId));
143        EXPECT_EQ(mTestDrm1, drm);
144        EXPECT_TRUE(isEqualSessionId(mSessionId1, sessionId));
145
146        EXPECT_TRUE(mDrmSessionManager->getLeastUsedSession_l(kTestPid2, &drm, &sessionId));
147        EXPECT_EQ(mTestDrm2, drm);
148        EXPECT_TRUE(isEqualSessionId(mSessionId2, sessionId));
149
150        // mSessionId2 is no longer the least used session.
151        mDrmSessionManager->useSession(mSessionId2);
152        EXPECT_TRUE(mDrmSessionManager->getLeastUsedSession_l(kTestPid2, &drm, &sessionId));
153        EXPECT_EQ(mTestDrm2, drm);
154        EXPECT_TRUE(isEqualSessionId(mSessionId3, sessionId));
155    }
156
157    sp<DrmSessionManager> mDrmSessionManager;
158    sp<FakeDrm> mTestDrm1;
159    sp<FakeDrm> mTestDrm2;
160    Vector<uint8_t> mSessionId1;
161    Vector<uint8_t> mSessionId2;
162    Vector<uint8_t> mSessionId3;
163};
164
165TEST_F(DrmSessionManagerTest, addSession) {
166    addSession();
167}
168
169TEST_F(DrmSessionManagerTest, useSession) {
170    addSession();
171
172    mDrmSessionManager->useSession(mSessionId1);
173    mDrmSessionManager->useSession(mSessionId3);
174
175    const PidSessionInfosMap& map = sessionMap();
176    const SessionInfos& infos1 = map.valueFor(kTestPid1);
177    const SessionInfos& infos2 = map.valueFor(kTestPid2);
178    ExpectEqSessionInfo(infos1[0], mTestDrm1, mSessionId1, 3);
179    ExpectEqSessionInfo(infos2[1], mTestDrm2, mSessionId3, 4);
180}
181
182TEST_F(DrmSessionManagerTest, removeSession) {
183    addSession();
184
185    mDrmSessionManager->removeSession(mSessionId2);
186
187    const PidSessionInfosMap& map = sessionMap();
188    EXPECT_EQ(2u, map.size());
189    const SessionInfos& infos1 = map.valueFor(kTestPid1);
190    const SessionInfos& infos2 = map.valueFor(kTestPid2);
191    EXPECT_EQ(1u, infos1.size());
192    EXPECT_EQ(1u, infos2.size());
193    // mSessionId2 has been removed.
194    ExpectEqSessionInfo(infos2[0], mTestDrm2, mSessionId3, 2);
195}
196
197TEST_F(DrmSessionManagerTest, removeDrm) {
198    addSession();
199
200    sp<FakeDrm> drm = new FakeDrm;
201    const uint8_t ids[] = {123};
202    Vector<uint8_t> sessionId;
203    GetSessionId(ids, ARRAY_SIZE(ids), &sessionId);
204    mDrmSessionManager->addSession(kTestPid2, drm, sessionId);
205
206    mDrmSessionManager->removeDrm(mTestDrm2);
207
208    const PidSessionInfosMap& map = sessionMap();
209    const SessionInfos& infos2 = map.valueFor(kTestPid2);
210    EXPECT_EQ(1u, infos2.size());
211    // mTestDrm2 has been removed.
212    ExpectEqSessionInfo(infos2[0], drm, sessionId, 3);
213}
214
215TEST_F(DrmSessionManagerTest, reclaimSession) {
216    EXPECT_FALSE(mDrmSessionManager->reclaimSession(kTestPid1));
217    addSession();
218
219    // calling pid priority is too low
220    EXPECT_FALSE(mDrmSessionManager->reclaimSession(50));
221
222    EXPECT_TRUE(mDrmSessionManager->reclaimSession(10));
223    EXPECT_EQ(1u, mTestDrm1->reclaimedSessions().size());
224    EXPECT_TRUE(isEqualSessionId(mSessionId1, mTestDrm1->reclaimedSessions()[0]));
225
226    mDrmSessionManager->removeSession(mSessionId1);
227
228    // add a session from a higher priority process.
229    sp<FakeDrm> drm = new FakeDrm;
230    const uint8_t ids[] = {1, 3, 5};
231    Vector<uint8_t> sessionId;
232    GetSessionId(ids, ARRAY_SIZE(ids), &sessionId);
233    mDrmSessionManager->addSession(15, drm, sessionId);
234
235    EXPECT_TRUE(mDrmSessionManager->reclaimSession(18));
236    EXPECT_EQ(1u, mTestDrm2->reclaimedSessions().size());
237    // mSessionId2 is reclaimed.
238    EXPECT_TRUE(isEqualSessionId(mSessionId2, mTestDrm2->reclaimedSessions()[0]));
239}
240
241TEST_F(DrmSessionManagerTest, getLowestPriority) {
242    testGetLowestPriority();
243}
244
245TEST_F(DrmSessionManagerTest, getLeastUsedSession_l) {
246    testGetLeastUsedSession();
247}
248
249} // namespace android
250