1
2/*
3 * Copyright (C) 2017 The Android Open Source Project
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 *      http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17//#define LOG_NDEBUG 0
18#define LOG_TAG "CasImpl"
19
20#include <android/media/ICasListener.h>
21#include <media/cas/CasAPI.h>
22#include <media/CasImpl.h>
23#include <media/SharedLibrary.h>
24#include <utils/Log.h>
25
26namespace android {
27
28static Status getBinderStatus(status_t err) {
29    if (err == OK) {
30        return Status::ok();
31    }
32    if (err == BAD_VALUE) {
33        return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT);
34    }
35    if (err == INVALID_OPERATION) {
36        return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE);
37    }
38    return Status::fromServiceSpecificError(err);
39}
40
41static String8 sessionIdToString(const CasSessionId &sessionId) {
42    String8 result;
43    for (size_t i = 0; i < sessionId.size(); i++) {
44        result.appendFormat("%02x ", sessionId[i]);
45    }
46    if (result.isEmpty()) {
47        result.append("(null)");
48    }
49    return result;
50}
51
52struct CasImpl::PluginHolder : public RefBase {
53public:
54    explicit PluginHolder(CasPlugin *plugin) : mPlugin(plugin) {}
55    ~PluginHolder() { if (mPlugin != NULL) delete mPlugin; }
56    CasPlugin* get() { return mPlugin; }
57
58private:
59    CasPlugin *mPlugin;
60    DISALLOW_EVIL_CONSTRUCTORS(PluginHolder);
61};
62
63CasImpl::CasImpl(const sp<ICasListener> &listener)
64    : mPluginHolder(NULL), mListener(listener) {
65    ALOGV("CTOR");
66}
67
68CasImpl::~CasImpl() {
69    ALOGV("DTOR");
70    release();
71}
72
73//static
74void CasImpl::OnEvent(
75        void *appData,
76        int32_t event,
77        int32_t arg,
78        uint8_t *data,
79        size_t size) {
80    if (appData == NULL) {
81        ALOGE("Invalid appData!");
82        return;
83    }
84    CasImpl *casImpl = static_cast<CasImpl *>(appData);
85    casImpl->onEvent(event, arg, data, size);
86}
87
88void CasImpl::init(const sp<SharedLibrary>& library, CasPlugin *plugin) {
89    mLibrary = library;
90    mPluginHolder = new PluginHolder(plugin);
91}
92
93void CasImpl::onEvent(
94        int32_t event, int32_t arg, uint8_t *data, size_t size) {
95    if (mListener == NULL) {
96        return;
97    }
98
99    std::unique_ptr<CasData> eventData;
100    if (data != NULL && size > 0) {
101        eventData.reset(new CasData(data, data + size));
102    }
103
104    mListener->onEvent(event, arg, eventData);
105}
106
107Status CasImpl::setPrivateData(const CasData& pvtData) {
108    ALOGV("setPrivateData");
109    sp<PluginHolder> holder = mPluginHolder;
110    if (holder == NULL) {
111        return getBinderStatus(INVALID_OPERATION);
112    }
113    return getBinderStatus(holder->get()->setPrivateData(pvtData));
114}
115
116Status CasImpl::openSession(CasSessionId* sessionId) {
117    ALOGV("openSession");
118    sp<PluginHolder> holder = mPluginHolder;
119    if (holder == NULL) {
120        return getBinderStatus(INVALID_OPERATION);
121    }
122    status_t err = holder->get()->openSession(sessionId);
123
124    ALOGV("openSession: session opened, sessionId=%s",
125            sessionIdToString(*sessionId).string());
126
127    return getBinderStatus(err);
128}
129
130Status CasImpl::setSessionPrivateData(
131        const CasSessionId &sessionId, const CasData& pvtData) {
132    ALOGV("setSessionPrivateData: sessionId=%s",
133            sessionIdToString(sessionId).string());
134    sp<PluginHolder> holder = mPluginHolder;
135    if (holder == NULL) {
136        return getBinderStatus(INVALID_OPERATION);
137    }
138    return getBinderStatus(holder->get()->setSessionPrivateData(sessionId, pvtData));
139}
140
141Status CasImpl::closeSession(const CasSessionId &sessionId) {
142    ALOGV("closeSession: sessionId=%s",
143            sessionIdToString(sessionId).string());
144    sp<PluginHolder> holder = mPluginHolder;
145    if (holder == NULL) {
146        return getBinderStatus(INVALID_OPERATION);
147    }
148    return getBinderStatus(holder->get()->closeSession(sessionId));
149}
150
151Status CasImpl::processEcm(const CasSessionId &sessionId, const ParcelableCasData& ecm) {
152    ALOGV("processEcm: sessionId=%s",
153            sessionIdToString(sessionId).string());
154    sp<PluginHolder> holder = mPluginHolder;
155    if (holder == NULL) {
156        return getBinderStatus(INVALID_OPERATION);
157    }
158
159    return getBinderStatus(holder->get()->processEcm(sessionId, ecm));
160}
161
162Status CasImpl::processEmm(const ParcelableCasData& emm) {
163    ALOGV("processEmm");
164    sp<PluginHolder> holder = mPluginHolder;
165    if (holder == NULL) {
166        return getBinderStatus(INVALID_OPERATION);
167    }
168
169    return getBinderStatus(holder->get()->processEmm(emm));
170}
171
172Status CasImpl::sendEvent(
173        int32_t event, int32_t arg, const ::std::unique_ptr<CasData> &eventData) {
174    ALOGV("sendEvent");
175    sp<PluginHolder> holder = mPluginHolder;
176    if (holder == NULL) {
177        return getBinderStatus(INVALID_OPERATION);
178    }
179
180    status_t err;
181    if (eventData == nullptr) {
182        err = holder->get()->sendEvent(event, arg, CasData());
183    } else {
184        err = holder->get()->sendEvent(event, arg, *eventData);
185    }
186    return getBinderStatus(err);
187}
188
189Status CasImpl::provision(const String16& provisionString) {
190    ALOGV("provision: provisionString=%s", String8(provisionString).string());
191    sp<PluginHolder> holder = mPluginHolder;
192    if (holder == NULL) {
193        return getBinderStatus(INVALID_OPERATION);
194    }
195
196    return getBinderStatus(holder->get()->provision(String8(provisionString)));
197}
198
199Status CasImpl::refreshEntitlements(
200        int32_t refreshType, const ::std::unique_ptr<CasData> &refreshData) {
201    ALOGV("refreshEntitlements");
202    sp<PluginHolder> holder = mPluginHolder;
203    if (holder == NULL) {
204        return getBinderStatus(INVALID_OPERATION);
205    }
206
207    status_t err;
208    if (refreshData == nullptr) {
209        err = holder->get()->refreshEntitlements(refreshType, CasData());
210    } else {
211        err = holder->get()->refreshEntitlements(refreshType, *refreshData);
212    }
213    return getBinderStatus(err);
214}
215
216Status CasImpl::release() {
217    ALOGV("release: plugin=%p",
218            mPluginHolder == NULL ? mPluginHolder->get() : NULL);
219    mPluginHolder.clear();
220    return Status::ok();
221}
222
223} // namespace android
224
225