• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2013 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 "Drm"
19 #include <utils/Log.h>
20 
21 #include <dirent.h>
22 #include <dlfcn.h>
23 
24 #include "Drm.h"
25 
26 #include <media/drm/DrmAPI.h>
27 #include <media/stagefright/foundation/ADebug.h>
28 #include <media/stagefright/foundation/AString.h>
29 #include <media/stagefright/foundation/hexdump.h>
30 #include <media/stagefright/MediaErrors.h>
31 
32 namespace android {
33 
34 KeyedVector<Vector<uint8_t>, String8> Drm::mUUIDToLibraryPathMap;
35 KeyedVector<String8, wp<SharedLibrary> > Drm::mLibraryPathToOpenLibraryMap;
36 Mutex Drm::mMapLock;
37 
operator <(const Vector<uint8_t> & lhs,const Vector<uint8_t> & rhs)38 static bool operator<(const Vector<uint8_t> &lhs, const Vector<uint8_t> &rhs) {
39     if (lhs.size() < rhs.size()) {
40         return true;
41     } else if (lhs.size() > rhs.size()) {
42         return false;
43     }
44 
45     return memcmp((void *)lhs.array(), (void *)rhs.array(), rhs.size()) < 0;
46 }
47 
Drm()48 Drm::Drm()
49     : mInitCheck(NO_INIT),
50       mListener(NULL),
51       mFactory(NULL),
52       mPlugin(NULL) {
53 }
54 
~Drm()55 Drm::~Drm() {
56     delete mPlugin;
57     mPlugin = NULL;
58     closeFactory();
59 }
60 
closeFactory()61 void Drm::closeFactory() {
62     delete mFactory;
63     mFactory = NULL;
64     mLibrary.clear();
65 }
66 
initCheck() const67 status_t Drm::initCheck() const {
68     return mInitCheck;
69 }
70 
setListener(const sp<IDrmClient> & listener)71 status_t Drm::setListener(const sp<IDrmClient>& listener)
72 {
73     Mutex::Autolock lock(mEventLock);
74     if (mListener != NULL){
75         mListener->asBinder()->unlinkToDeath(this);
76     }
77     if (listener != NULL) {
78         listener->asBinder()->linkToDeath(this);
79     }
80     mListener = listener;
81     return NO_ERROR;
82 }
83 
sendEvent(DrmPlugin::EventType eventType,int extra,Vector<uint8_t> const * sessionId,Vector<uint8_t> const * data)84 void Drm::sendEvent(DrmPlugin::EventType eventType, int extra,
85                     Vector<uint8_t> const *sessionId,
86                     Vector<uint8_t> const *data)
87 {
88     mEventLock.lock();
89     sp<IDrmClient> listener = mListener;
90     mEventLock.unlock();
91 
92     if (listener != NULL) {
93         Parcel obj;
94         if (sessionId && sessionId->size()) {
95             obj.writeInt32(sessionId->size());
96             obj.write(sessionId->array(), sessionId->size());
97         } else {
98             obj.writeInt32(0);
99         }
100 
101         if (data && data->size()) {
102             obj.writeInt32(data->size());
103             obj.write(data->array(), data->size());
104         } else {
105             obj.writeInt32(0);
106         }
107 
108         Mutex::Autolock lock(mNotifyLock);
109         listener->notify(eventType, extra, &obj);
110     }
111 }
112 
113 /*
114  * Search the plugins directory for a plugin that supports the scheme
115  * specified by uuid
116  *
117  * If found:
118  *    mLibrary holds a strong pointer to the dlopen'd library
119  *    mFactory is set to the library's factory method
120  *    mInitCheck is set to OK
121  *
122  * If not found:
123  *    mLibrary is cleared and mFactory are set to NULL
124  *    mInitCheck is set to an error (!OK)
125  */
findFactoryForScheme(const uint8_t uuid[16])126 void Drm::findFactoryForScheme(const uint8_t uuid[16]) {
127 
128     closeFactory();
129 
130     // lock static maps
131     Mutex::Autolock autoLock(mMapLock);
132 
133     // first check cache
134     Vector<uint8_t> uuidVector;
135     uuidVector.appendArray(uuid, sizeof(uuid));
136     ssize_t index = mUUIDToLibraryPathMap.indexOfKey(uuidVector);
137     if (index >= 0) {
138         if (loadLibraryForScheme(mUUIDToLibraryPathMap[index], uuid)) {
139             mInitCheck = OK;
140             return;
141         } else {
142             ALOGE("Failed to load from cached library path!");
143             mInitCheck = ERROR_UNSUPPORTED;
144             return;
145         }
146     }
147 
148     // no luck, have to search
149     String8 dirPath("/vendor/lib/mediadrm");
150     DIR* pDir = opendir(dirPath.string());
151 
152     if (pDir == NULL) {
153         mInitCheck = ERROR_UNSUPPORTED;
154         ALOGE("Failed to open plugin directory %s", dirPath.string());
155         return;
156     }
157 
158 
159     struct dirent* pEntry;
160     while ((pEntry = readdir(pDir))) {
161 
162         String8 pluginPath = dirPath + "/" + pEntry->d_name;
163 
164         if (pluginPath.getPathExtension() == ".so") {
165 
166             if (loadLibraryForScheme(pluginPath, uuid)) {
167                 mUUIDToLibraryPathMap.add(uuidVector, pluginPath);
168                 mInitCheck = OK;
169                 closedir(pDir);
170                 return;
171             }
172         }
173     }
174 
175     closedir(pDir);
176 
177     ALOGE("Failed to find drm plugin");
178     mInitCheck = ERROR_UNSUPPORTED;
179 }
180 
loadLibraryForScheme(const String8 & path,const uint8_t uuid[16])181 bool Drm::loadLibraryForScheme(const String8 &path, const uint8_t uuid[16]) {
182 
183     // get strong pointer to open shared library
184     ssize_t index = mLibraryPathToOpenLibraryMap.indexOfKey(path);
185     if (index >= 0) {
186         mLibrary = mLibraryPathToOpenLibraryMap[index].promote();
187     } else {
188         index = mLibraryPathToOpenLibraryMap.add(path, NULL);
189     }
190 
191     if (!mLibrary.get()) {
192         mLibrary = new SharedLibrary(path);
193         if (!*mLibrary) {
194             return false;
195         }
196 
197         mLibraryPathToOpenLibraryMap.replaceValueAt(index, mLibrary);
198     }
199 
200     typedef DrmFactory *(*CreateDrmFactoryFunc)();
201 
202     CreateDrmFactoryFunc createDrmFactory =
203         (CreateDrmFactoryFunc)mLibrary->lookup("createDrmFactory");
204 
205     if (createDrmFactory == NULL ||
206         (mFactory = createDrmFactory()) == NULL ||
207         !mFactory->isCryptoSchemeSupported(uuid)) {
208         closeFactory();
209         return false;
210     }
211     return true;
212 }
213 
isCryptoSchemeSupported(const uint8_t uuid[16],const String8 & mimeType)214 bool Drm::isCryptoSchemeSupported(const uint8_t uuid[16], const String8 &mimeType) {
215 
216     Mutex::Autolock autoLock(mLock);
217 
218     if (!mFactory || !mFactory->isCryptoSchemeSupported(uuid)) {
219         findFactoryForScheme(uuid);
220         if (mInitCheck != OK) {
221             return false;
222         }
223     }
224 
225     if (mimeType != "") {
226         return mFactory->isContentTypeSupported(mimeType);
227     }
228 
229     return true;
230 }
231 
createPlugin(const uint8_t uuid[16])232 status_t Drm::createPlugin(const uint8_t uuid[16]) {
233     Mutex::Autolock autoLock(mLock);
234 
235     if (mPlugin != NULL) {
236         return -EINVAL;
237     }
238 
239     if (!mFactory || !mFactory->isCryptoSchemeSupported(uuid)) {
240         findFactoryForScheme(uuid);
241     }
242 
243     if (mInitCheck != OK) {
244         return mInitCheck;
245     }
246 
247     status_t result = mFactory->createDrmPlugin(uuid, &mPlugin);
248     mPlugin->setListener(this);
249     return result;
250 }
251 
destroyPlugin()252 status_t Drm::destroyPlugin() {
253     Mutex::Autolock autoLock(mLock);
254 
255     if (mInitCheck != OK) {
256         return mInitCheck;
257     }
258 
259     if (mPlugin == NULL) {
260         return -EINVAL;
261     }
262 
263     delete mPlugin;
264     mPlugin = NULL;
265 
266     return OK;
267 }
268 
openSession(Vector<uint8_t> & sessionId)269 status_t Drm::openSession(Vector<uint8_t> &sessionId) {
270     Mutex::Autolock autoLock(mLock);
271 
272     if (mInitCheck != OK) {
273         return mInitCheck;
274     }
275 
276     if (mPlugin == NULL) {
277         return -EINVAL;
278     }
279 
280     return mPlugin->openSession(sessionId);
281 }
282 
closeSession(Vector<uint8_t> const & sessionId)283 status_t Drm::closeSession(Vector<uint8_t> const &sessionId) {
284     Mutex::Autolock autoLock(mLock);
285 
286     if (mInitCheck != OK) {
287         return mInitCheck;
288     }
289 
290     if (mPlugin == NULL) {
291         return -EINVAL;
292     }
293 
294     return mPlugin->closeSession(sessionId);
295 }
296 
getKeyRequest(Vector<uint8_t> const & sessionId,Vector<uint8_t> const & initData,String8 const & mimeType,DrmPlugin::KeyType keyType,KeyedVector<String8,String8> const & optionalParameters,Vector<uint8_t> & request,String8 & defaultUrl)297 status_t Drm::getKeyRequest(Vector<uint8_t> const &sessionId,
298                             Vector<uint8_t> const &initData,
299                             String8 const &mimeType, DrmPlugin::KeyType keyType,
300                             KeyedVector<String8, String8> const &optionalParameters,
301                             Vector<uint8_t> &request, String8 &defaultUrl) {
302     Mutex::Autolock autoLock(mLock);
303 
304     if (mInitCheck != OK) {
305         return mInitCheck;
306     }
307 
308     if (mPlugin == NULL) {
309         return -EINVAL;
310     }
311 
312     return mPlugin->getKeyRequest(sessionId, initData, mimeType, keyType,
313                                   optionalParameters, request, defaultUrl);
314 }
315 
provideKeyResponse(Vector<uint8_t> const & sessionId,Vector<uint8_t> const & response,Vector<uint8_t> & keySetId)316 status_t Drm::provideKeyResponse(Vector<uint8_t> const &sessionId,
317                                  Vector<uint8_t> const &response,
318                                  Vector<uint8_t> &keySetId) {
319     Mutex::Autolock autoLock(mLock);
320 
321     if (mInitCheck != OK) {
322         return mInitCheck;
323     }
324 
325     if (mPlugin == NULL) {
326         return -EINVAL;
327     }
328 
329     return mPlugin->provideKeyResponse(sessionId, response, keySetId);
330 }
331 
removeKeys(Vector<uint8_t> const & keySetId)332 status_t Drm::removeKeys(Vector<uint8_t> const &keySetId) {
333     Mutex::Autolock autoLock(mLock);
334 
335     if (mInitCheck != OK) {
336         return mInitCheck;
337     }
338 
339     if (mPlugin == NULL) {
340         return -EINVAL;
341     }
342 
343     return mPlugin->removeKeys(keySetId);
344 }
345 
restoreKeys(Vector<uint8_t> const & sessionId,Vector<uint8_t> const & keySetId)346 status_t Drm::restoreKeys(Vector<uint8_t> const &sessionId,
347                           Vector<uint8_t> const &keySetId) {
348     Mutex::Autolock autoLock(mLock);
349 
350     if (mInitCheck != OK) {
351         return mInitCheck;
352     }
353 
354     if (mPlugin == NULL) {
355         return -EINVAL;
356     }
357 
358     return mPlugin->restoreKeys(sessionId, keySetId);
359 }
360 
queryKeyStatus(Vector<uint8_t> const & sessionId,KeyedVector<String8,String8> & infoMap) const361 status_t Drm::queryKeyStatus(Vector<uint8_t> const &sessionId,
362                              KeyedVector<String8, String8> &infoMap) const {
363     Mutex::Autolock autoLock(mLock);
364 
365     if (mInitCheck != OK) {
366         return mInitCheck;
367     }
368 
369     if (mPlugin == NULL) {
370         return -EINVAL;
371     }
372 
373     return mPlugin->queryKeyStatus(sessionId, infoMap);
374 }
375 
getProvisionRequest(Vector<uint8_t> & request,String8 & defaultUrl)376 status_t Drm::getProvisionRequest(Vector<uint8_t> &request, String8 &defaultUrl) {
377     Mutex::Autolock autoLock(mLock);
378 
379     if (mInitCheck != OK) {
380         return mInitCheck;
381     }
382 
383     if (mPlugin == NULL) {
384         return -EINVAL;
385     }
386 
387     return mPlugin->getProvisionRequest(request, defaultUrl);
388 }
389 
provideProvisionResponse(Vector<uint8_t> const & response)390 status_t Drm::provideProvisionResponse(Vector<uint8_t> const &response) {
391     Mutex::Autolock autoLock(mLock);
392 
393     if (mInitCheck != OK) {
394         return mInitCheck;
395     }
396 
397     if (mPlugin == NULL) {
398         return -EINVAL;
399     }
400 
401     return mPlugin->provideProvisionResponse(response);
402 }
403 
404 
getSecureStops(List<Vector<uint8_t>> & secureStops)405 status_t Drm::getSecureStops(List<Vector<uint8_t> > &secureStops) {
406     Mutex::Autolock autoLock(mLock);
407 
408     if (mInitCheck != OK) {
409         return mInitCheck;
410     }
411 
412     if (mPlugin == NULL) {
413         return -EINVAL;
414     }
415 
416     return mPlugin->getSecureStops(secureStops);
417 }
418 
releaseSecureStops(Vector<uint8_t> const & ssRelease)419 status_t Drm::releaseSecureStops(Vector<uint8_t> const &ssRelease) {
420     Mutex::Autolock autoLock(mLock);
421 
422     if (mInitCheck != OK) {
423         return mInitCheck;
424     }
425 
426     if (mPlugin == NULL) {
427         return -EINVAL;
428     }
429 
430     return mPlugin->releaseSecureStops(ssRelease);
431 }
432 
getPropertyString(String8 const & name,String8 & value) const433 status_t Drm::getPropertyString(String8 const &name, String8 &value ) const {
434     Mutex::Autolock autoLock(mLock);
435 
436     if (mInitCheck != OK) {
437         return mInitCheck;
438     }
439 
440     if (mPlugin == NULL) {
441         return -EINVAL;
442     }
443 
444     return mPlugin->getPropertyString(name, value);
445 }
446 
getPropertyByteArray(String8 const & name,Vector<uint8_t> & value) const447 status_t Drm::getPropertyByteArray(String8 const &name, Vector<uint8_t> &value ) const {
448     Mutex::Autolock autoLock(mLock);
449 
450     if (mInitCheck != OK) {
451         return mInitCheck;
452     }
453 
454     if (mPlugin == NULL) {
455         return -EINVAL;
456     }
457 
458     return mPlugin->getPropertyByteArray(name, value);
459 }
460 
setPropertyString(String8 const & name,String8 const & value) const461 status_t Drm::setPropertyString(String8 const &name, String8 const &value ) const {
462     Mutex::Autolock autoLock(mLock);
463 
464     if (mInitCheck != OK) {
465         return mInitCheck;
466     }
467 
468     if (mPlugin == NULL) {
469         return -EINVAL;
470     }
471 
472     return mPlugin->setPropertyString(name, value);
473 }
474 
setPropertyByteArray(String8 const & name,Vector<uint8_t> const & value) const475 status_t Drm::setPropertyByteArray(String8 const &name,
476                                    Vector<uint8_t> const &value ) const {
477     Mutex::Autolock autoLock(mLock);
478 
479     if (mInitCheck != OK) {
480         return mInitCheck;
481     }
482 
483     if (mPlugin == NULL) {
484         return -EINVAL;
485     }
486 
487     return mPlugin->setPropertyByteArray(name, value);
488 }
489 
490 
setCipherAlgorithm(Vector<uint8_t> const & sessionId,String8 const & algorithm)491 status_t Drm::setCipherAlgorithm(Vector<uint8_t> const &sessionId,
492                                  String8 const &algorithm) {
493     Mutex::Autolock autoLock(mLock);
494 
495     if (mInitCheck != OK) {
496         return mInitCheck;
497     }
498 
499     if (mPlugin == NULL) {
500         return -EINVAL;
501     }
502 
503     return mPlugin->setCipherAlgorithm(sessionId, algorithm);
504 }
505 
setMacAlgorithm(Vector<uint8_t> const & sessionId,String8 const & algorithm)506 status_t Drm::setMacAlgorithm(Vector<uint8_t> const &sessionId,
507                               String8 const &algorithm) {
508     Mutex::Autolock autoLock(mLock);
509 
510     if (mInitCheck != OK) {
511         return mInitCheck;
512     }
513 
514     if (mPlugin == NULL) {
515         return -EINVAL;
516     }
517 
518     return mPlugin->setMacAlgorithm(sessionId, algorithm);
519 }
520 
encrypt(Vector<uint8_t> const & sessionId,Vector<uint8_t> const & keyId,Vector<uint8_t> const & input,Vector<uint8_t> const & iv,Vector<uint8_t> & output)521 status_t Drm::encrypt(Vector<uint8_t> const &sessionId,
522                       Vector<uint8_t> const &keyId,
523                       Vector<uint8_t> const &input,
524                       Vector<uint8_t> const &iv,
525                       Vector<uint8_t> &output) {
526     Mutex::Autolock autoLock(mLock);
527 
528     if (mInitCheck != OK) {
529         return mInitCheck;
530     }
531 
532     if (mPlugin == NULL) {
533         return -EINVAL;
534     }
535 
536     return mPlugin->encrypt(sessionId, keyId, input, iv, output);
537 }
538 
decrypt(Vector<uint8_t> const & sessionId,Vector<uint8_t> const & keyId,Vector<uint8_t> const & input,Vector<uint8_t> const & iv,Vector<uint8_t> & output)539 status_t Drm::decrypt(Vector<uint8_t> const &sessionId,
540                       Vector<uint8_t> const &keyId,
541                       Vector<uint8_t> const &input,
542                       Vector<uint8_t> const &iv,
543                       Vector<uint8_t> &output) {
544     Mutex::Autolock autoLock(mLock);
545 
546     if (mInitCheck != OK) {
547         return mInitCheck;
548     }
549 
550     if (mPlugin == NULL) {
551         return -EINVAL;
552     }
553 
554     return mPlugin->decrypt(sessionId, keyId, input, iv, output);
555 }
556 
sign(Vector<uint8_t> const & sessionId,Vector<uint8_t> const & keyId,Vector<uint8_t> const & message,Vector<uint8_t> & signature)557 status_t Drm::sign(Vector<uint8_t> const &sessionId,
558                    Vector<uint8_t> const &keyId,
559                    Vector<uint8_t> const &message,
560                    Vector<uint8_t> &signature) {
561     Mutex::Autolock autoLock(mLock);
562 
563     if (mInitCheck != OK) {
564         return mInitCheck;
565     }
566 
567     if (mPlugin == NULL) {
568         return -EINVAL;
569     }
570 
571     return mPlugin->sign(sessionId, keyId, message, signature);
572 }
573 
verify(Vector<uint8_t> const & sessionId,Vector<uint8_t> const & keyId,Vector<uint8_t> const & message,Vector<uint8_t> const & signature,bool & match)574 status_t Drm::verify(Vector<uint8_t> const &sessionId,
575                      Vector<uint8_t> const &keyId,
576                      Vector<uint8_t> const &message,
577                      Vector<uint8_t> const &signature,
578                      bool &match) {
579     Mutex::Autolock autoLock(mLock);
580 
581     if (mInitCheck != OK) {
582         return mInitCheck;
583     }
584 
585     if (mPlugin == NULL) {
586         return -EINVAL;
587     }
588 
589     return mPlugin->verify(sessionId, keyId, message, signature, match);
590 }
591 
binderDied(const wp<IBinder> & the_late_who)592 void Drm::binderDied(const wp<IBinder> &the_late_who)
593 {
594     delete mPlugin;
595     mPlugin = NULL;
596     closeFactory();
597     mListener.clear();
598 }
599 
600 }  // namespace android
601