1/*
2 * Copyright (C) 2010 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 "DrmPassthruPlugIn"
19#include <utils/Log.h>
20
21#include <drm/DrmRights.h>
22#include <drm/DrmConstraints.h>
23#include <drm/DrmMetadata.h>
24#include <drm/DrmInfo.h>
25#include <drm/DrmInfoEvent.h>
26#include <drm/DrmInfoStatus.h>
27#include <drm/DrmConvertedStatus.h>
28#include <drm/DrmInfoRequest.h>
29#include <drm/DrmSupportInfo.h>
30#include <DrmPassthruPlugIn.h>
31
32using namespace android;
33
34
35// This extern "C" is mandatory to be managed by TPlugInManager
36extern "C" IDrmEngine* create() {
37    return new DrmPassthruPlugIn();
38}
39
40// This extern "C" is mandatory to be managed by TPlugInManager
41extern "C" void destroy(IDrmEngine* pPlugIn) {
42    delete pPlugIn;
43    pPlugIn = NULL;
44}
45
46DrmPassthruPlugIn::DrmPassthruPlugIn()
47    : DrmEngineBase() {
48
49}
50
51DrmPassthruPlugIn::~DrmPassthruPlugIn() {
52
53}
54
55DrmMetadata* DrmPassthruPlugIn::onGetMetadata(int /*uniqueId*/, const String8* /*path*/) {
56    return NULL;
57}
58
59DrmConstraints* DrmPassthruPlugIn::onGetConstraints(
60        int uniqueId, const String8* /*path*/, int /*action*/) {
61    ALOGV("DrmPassthruPlugIn::onGetConstraints From Path: %d", uniqueId);
62    DrmConstraints* drmConstraints = new DrmConstraints();
63
64    String8 value("dummy_available_time");
65    char* charValue = NULL;
66    charValue = new char[value.length() + 1];
67    strncpy(charValue, value.string(), value.length());
68    charValue[value.length()] = '\0';
69
70    //Just add dummy available time for verification
71    drmConstraints->put(&(DrmConstraints::LICENSE_AVAILABLE_TIME), charValue);
72    delete[] charValue;
73    return drmConstraints;
74}
75
76DrmInfoStatus* DrmPassthruPlugIn::onProcessDrmInfo(int uniqueId, const DrmInfo* drmInfo) {
77    ALOGV("DrmPassthruPlugIn::onProcessDrmInfo - Enter : %d", uniqueId);
78    DrmInfoStatus* drmInfoStatus = NULL;
79    if (NULL != drmInfo) {
80        switch (drmInfo->getInfoType()) {
81        case DrmInfoRequest::TYPE_REGISTRATION_INFO: {
82            const DrmBuffer* emptyBuffer = new DrmBuffer();
83            drmInfoStatus = new DrmInfoStatus(DrmInfoStatus::STATUS_OK,
84                    DrmInfoRequest::TYPE_REGISTRATION_INFO, emptyBuffer, drmInfo->getMimeType());
85            break;
86        }
87        case DrmInfoRequest::TYPE_UNREGISTRATION_INFO: {
88            const DrmBuffer* emptyBuffer = new DrmBuffer();
89            drmInfoStatus = new DrmInfoStatus(DrmInfoStatus::STATUS_OK,
90                    DrmInfoRequest::TYPE_UNREGISTRATION_INFO, emptyBuffer, drmInfo->getMimeType());
91            break;
92        }
93        case DrmInfoRequest::TYPE_RIGHTS_ACQUISITION_INFO: {
94            String8 licenseString("dummy_license_string");
95            const int bufferSize = licenseString.size();
96            char* data = NULL;
97            data = new char[bufferSize];
98            memcpy(data, licenseString.string(), bufferSize);
99            const DrmBuffer* buffer = new DrmBuffer(data, bufferSize);
100            drmInfoStatus = new DrmInfoStatus(DrmInfoStatus::STATUS_OK,
101                    DrmInfoRequest::TYPE_RIGHTS_ACQUISITION_INFO, buffer, drmInfo->getMimeType());
102            break;
103        }
104        }
105    }
106    ALOGV("DrmPassthruPlugIn::onProcessDrmInfo - Exit");
107    return drmInfoStatus;
108}
109
110status_t DrmPassthruPlugIn::onSetOnInfoListener(
111            int uniqueId, const IDrmEngine::OnInfoListener* /*infoListener*/) {
112    ALOGV("DrmPassthruPlugIn::onSetOnInfoListener : %d", uniqueId);
113    return DRM_NO_ERROR;
114}
115
116status_t DrmPassthruPlugIn::onInitialize(int uniqueId) {
117    ALOGV("DrmPassthruPlugIn::onInitialize : %d", uniqueId);
118    return DRM_NO_ERROR;
119}
120
121status_t DrmPassthruPlugIn::onTerminate(int uniqueId) {
122    ALOGV("DrmPassthruPlugIn::onTerminate : %d", uniqueId);
123    return DRM_NO_ERROR;
124}
125
126DrmSupportInfo* DrmPassthruPlugIn::onGetSupportInfo(int uniqueId) {
127    ALOGV("DrmPassthruPlugIn::onGetSupportInfo : %d", uniqueId);
128    DrmSupportInfo* drmSupportInfo = new DrmSupportInfo();
129    // Add mimetype's
130    drmSupportInfo->addMimeType(String8("application/vnd.passthru.drm"));
131    // Add File Suffixes
132    drmSupportInfo->addFileSuffix(String8(".passthru"));
133    // Add plug-in description
134    drmSupportInfo->setDescription(String8("Passthru plug-in"));
135    return drmSupportInfo;
136}
137
138status_t DrmPassthruPlugIn::onSaveRights(int uniqueId, const DrmRights& /*drmRights*/,
139            const String8& /*rightsPath*/, const String8& /*contentPath*/) {
140    ALOGV("DrmPassthruPlugIn::onSaveRights : %d", uniqueId);
141    return DRM_NO_ERROR;
142}
143
144DrmInfo* DrmPassthruPlugIn::onAcquireDrmInfo(int uniqueId, const DrmInfoRequest* drmInfoRequest) {
145    ALOGV("DrmPassthruPlugIn::onAcquireDrmInfo : %d", uniqueId);
146    DrmInfo* drmInfo = NULL;
147
148    if (NULL != drmInfoRequest) {
149        String8 dataString("dummy_acquistion_string");
150        int length = dataString.length();
151        char* data = NULL;
152        data = new char[length];
153        memcpy(data, dataString.string(), length);
154        drmInfo = new DrmInfo(drmInfoRequest->getInfoType(),
155            DrmBuffer(data, length), drmInfoRequest->getMimeType());
156    }
157    return drmInfo;
158}
159
160bool DrmPassthruPlugIn::onCanHandle(int /*uniqueId*/, const String8& path) {
161    ALOGV("DrmPassthruPlugIn::canHandle: %s ", path.string());
162    String8 extension = path.getPathExtension();
163    extension.toLower();
164    return (String8(".passthru") == extension);
165}
166
167String8 DrmPassthruPlugIn::onGetOriginalMimeType(int uniqueId,
168            const String8& /*path*/, int /*fd*/) {
169    ALOGV("DrmPassthruPlugIn::onGetOriginalMimeType() : %d", uniqueId);
170    return String8("video/passthru");
171}
172
173int DrmPassthruPlugIn::onGetDrmObjectType(
174            int uniqueId, const String8& /*path*/, const String8& /*mimeType*/) {
175    ALOGV("DrmPassthruPlugIn::onGetDrmObjectType() : %d", uniqueId);
176    return DrmObjectType::UNKNOWN;
177}
178
179int DrmPassthruPlugIn::onCheckRightsStatus(int uniqueId, const String8& /*path*/, int /*action*/) {
180    ALOGV("DrmPassthruPlugIn::onCheckRightsStatus() : %d", uniqueId);
181    int rightsStatus = RightsStatus::RIGHTS_VALID;
182    return rightsStatus;
183}
184
185status_t DrmPassthruPlugIn::onConsumeRights(int uniqueId,
186            DecryptHandle* /*decryptHandle*/, int /*action*/, bool /*reserve*/) {
187    ALOGV("DrmPassthruPlugIn::onConsumeRights() : %d", uniqueId);
188    return DRM_NO_ERROR;
189}
190
191status_t DrmPassthruPlugIn::onSetPlaybackStatus(int uniqueId,
192            DecryptHandle* /*decryptHandle*/, int /*playbackStatus*/, int64_t /*position*/) {
193    ALOGV("DrmPassthruPlugIn::onSetPlaybackStatus() : %d", uniqueId);
194    return DRM_NO_ERROR;
195}
196
197bool DrmPassthruPlugIn::onValidateAction(int uniqueId,
198            const String8& /*path*/, int /*action*/, const ActionDescription& /*description*/) {
199    ALOGV("DrmPassthruPlugIn::onValidateAction() : %d", uniqueId);
200    return true;
201}
202
203status_t DrmPassthruPlugIn::onRemoveRights(int uniqueId, const String8& /*path*/) {
204    ALOGV("DrmPassthruPlugIn::onRemoveRights() : %d", uniqueId);
205    return DRM_NO_ERROR;
206}
207
208status_t DrmPassthruPlugIn::onRemoveAllRights(int uniqueId) {
209    ALOGV("DrmPassthruPlugIn::onRemoveAllRights() : %d", uniqueId);
210    return DRM_NO_ERROR;
211}
212
213status_t DrmPassthruPlugIn::onOpenConvertSession(int uniqueId, int /*convertId*/) {
214    ALOGV("DrmPassthruPlugIn::onOpenConvertSession() : %d", uniqueId);
215    return DRM_NO_ERROR;
216}
217
218DrmConvertedStatus* DrmPassthruPlugIn::onConvertData(
219            int uniqueId, int /*convertId*/, const DrmBuffer* inputData) {
220    ALOGV("DrmPassthruPlugIn::onConvertData() : %d", uniqueId);
221    DrmBuffer* convertedData = NULL;
222
223    if (NULL != inputData && 0 < inputData->length) {
224        int length = inputData->length;
225        char* data = NULL;
226        data = new char[length];
227        convertedData = new DrmBuffer(data, length);
228        memcpy(convertedData->data, inputData->data, length);
229    }
230    return new DrmConvertedStatus(DrmConvertedStatus::STATUS_OK, convertedData, 0 /*offset*/);
231}
232
233DrmConvertedStatus* DrmPassthruPlugIn::onCloseConvertSession(int uniqueId, int /*convertId*/) {
234    ALOGV("DrmPassthruPlugIn::onCloseConvertSession() : %d", uniqueId);
235    return new DrmConvertedStatus(DrmConvertedStatus::STATUS_OK, NULL, 0 /*offset*/);
236}
237
238status_t DrmPassthruPlugIn::onOpenDecryptSession(
239            int uniqueId, DecryptHandle* decryptHandle, int /*fd*/, off64_t /*offset*/, off64_t /*length*/) {
240    ALOGV("DrmPassthruPlugIn::onOpenDecryptSession() : %d", uniqueId);
241
242#ifdef ENABLE_PASSTHRU_DECRYPTION
243    decryptHandle->mimeType = String8("video/passthru");
244    decryptHandle->decryptApiType = DecryptApiType::ELEMENTARY_STREAM_BASED;
245    decryptHandle->status = DRM_NO_ERROR;
246    decryptHandle->decryptInfo = NULL;
247    return DRM_NO_ERROR;
248#endif
249
250    return DRM_ERROR_CANNOT_HANDLE;
251}
252
253status_t DrmPassthruPlugIn::onOpenDecryptSession(
254            int /*uniqueId*/, DecryptHandle* /*decryptHandle*/, const char* /*uri*/) {
255    return DRM_ERROR_CANNOT_HANDLE;
256}
257
258status_t DrmPassthruPlugIn::onCloseDecryptSession(int uniqueId, DecryptHandle* decryptHandle) {
259    ALOGV("DrmPassthruPlugIn::onCloseDecryptSession() : %d", uniqueId);
260    if (NULL != decryptHandle) {
261        if (NULL != decryptHandle->decryptInfo) {
262            delete decryptHandle->decryptInfo; decryptHandle->decryptInfo = NULL;
263        }
264        delete decryptHandle; decryptHandle = NULL;
265    }
266    return DRM_NO_ERROR;
267}
268
269status_t DrmPassthruPlugIn::onInitializeDecryptUnit(int uniqueId, DecryptHandle* /*decryptHandle*/,
270            int /*decryptUnitId*/, const DrmBuffer* /*headerInfo*/) {
271    ALOGV("DrmPassthruPlugIn::onInitializeDecryptUnit() : %d", uniqueId);
272    return DRM_NO_ERROR;
273}
274
275status_t DrmPassthruPlugIn::onDecrypt(int uniqueId, DecryptHandle* /*decryptHandle*/,
276            int /*decryptUnitId*/, const DrmBuffer* encBuffer, DrmBuffer** decBuffer, DrmBuffer* /*IV*/) {
277    ALOGV("DrmPassthruPlugIn::onDecrypt() : %d", uniqueId);
278    /**
279     * As a workaround implementation passthru would copy the given
280     * encrypted buffer as it is to decrypted buffer. Note, decBuffer
281     * memory has to be allocated by the caller.
282     */
283    if (NULL != (*decBuffer) && 0 < (*decBuffer)->length) {
284        if ((*decBuffer)->length >= encBuffer->length) {
285            memcpy((*decBuffer)->data, encBuffer->data, encBuffer->length);
286            (*decBuffer)->length = encBuffer->length;
287        } else {
288            ALOGE("decBuffer size (%d) too small to hold %d bytes",
289                (*decBuffer)->length, encBuffer->length);
290            return DRM_ERROR_UNKNOWN;
291        }
292    }
293    return DRM_NO_ERROR;
294}
295
296status_t DrmPassthruPlugIn::onFinalizeDecryptUnit(
297            int uniqueId, DecryptHandle* /*decryptHandle*/, int /*decryptUnitId*/) {
298    ALOGV("DrmPassthruPlugIn::onFinalizeDecryptUnit() : %d", uniqueId);
299    return DRM_NO_ERROR;
300}
301
302ssize_t DrmPassthruPlugIn::onPread(int uniqueId, DecryptHandle* /*decryptHandle*/,
303            void* /*buffer*/, ssize_t /*numBytes*/, off64_t /*offset*/) {
304    ALOGV("DrmPassthruPlugIn::onPread() : %d", uniqueId);
305    return 0;
306}
307
308