• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2012 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 "Crypto"
19 #include <utils/Log.h>
20 #include <dirent.h>
21 #include <dlfcn.h>
22 
23 #include "Crypto.h"
24 
25 #include <media/hardware/CryptoAPI.h>
26 #include <media/stagefright/foundation/ADebug.h>
27 #include <media/stagefright/foundation/AString.h>
28 #include <media/stagefright/foundation/hexdump.h>
29 #include <media/stagefright/MediaErrors.h>
30 
31 namespace android {
32 
33 KeyedVector<Vector<uint8_t>, String8> Crypto::mUUIDToLibraryPathMap;
34 KeyedVector<String8, wp<SharedLibrary> > Crypto::mLibraryPathToOpenLibraryMap;
35 Mutex Crypto::mMapLock;
36 
operator <(const Vector<uint8_t> & lhs,const Vector<uint8_t> & rhs)37 static bool operator<(const Vector<uint8_t> &lhs, const Vector<uint8_t> &rhs) {
38     if (lhs.size() < rhs.size()) {
39         return true;
40     } else if (lhs.size() > rhs.size()) {
41         return false;
42     }
43 
44     return memcmp((void *)lhs.array(), (void *)rhs.array(), rhs.size()) < 0;
45 }
46 
Crypto()47 Crypto::Crypto()
48     : mInitCheck(NO_INIT),
49       mFactory(NULL),
50       mPlugin(NULL) {
51 }
52 
~Crypto()53 Crypto::~Crypto() {
54     delete mPlugin;
55     mPlugin = NULL;
56     closeFactory();
57 }
58 
closeFactory()59 void Crypto::closeFactory() {
60     delete mFactory;
61     mFactory = NULL;
62     mLibrary.clear();
63 }
64 
initCheck() const65 status_t Crypto::initCheck() const {
66     return mInitCheck;
67 }
68 
69 /*
70  * Search the plugins directory for a plugin that supports the scheme
71  * specified by uuid
72  *
73  * If found:
74  *    mLibrary holds a strong pointer to the dlopen'd library
75  *    mFactory is set to the library's factory method
76  *    mInitCheck is set to OK
77  *
78  * If not found:
79  *    mLibrary is cleared and mFactory are set to NULL
80  *    mInitCheck is set to an error (!OK)
81  */
findFactoryForScheme(const uint8_t uuid[16])82 void Crypto::findFactoryForScheme(const uint8_t uuid[16]) {
83 
84     closeFactory();
85 
86     // lock static maps
87     Mutex::Autolock autoLock(mMapLock);
88 
89     // first check cache
90     Vector<uint8_t> uuidVector;
91     uuidVector.appendArray(uuid, sizeof(uuid));
92     ssize_t index = mUUIDToLibraryPathMap.indexOfKey(uuidVector);
93     if (index >= 0) {
94         if (loadLibraryForScheme(mUUIDToLibraryPathMap[index], uuid)) {
95             mInitCheck = OK;
96             return;
97         } else {
98             ALOGE("Failed to load from cached library path!");
99             mInitCheck = ERROR_UNSUPPORTED;
100             return;
101         }
102     }
103 
104     // no luck, have to search
105     String8 dirPath("/vendor/lib/mediadrm");
106     String8 pluginPath;
107 
108     DIR* pDir = opendir(dirPath.string());
109     if (pDir) {
110         struct dirent* pEntry;
111         while ((pEntry = readdir(pDir))) {
112 
113             pluginPath = dirPath + "/" + pEntry->d_name;
114 
115             if (pluginPath.getPathExtension() == ".so") {
116 
117                 if (loadLibraryForScheme(pluginPath, uuid)) {
118                     mUUIDToLibraryPathMap.add(uuidVector, pluginPath);
119                     mInitCheck = OK;
120                     closedir(pDir);
121                     return;
122                 }
123             }
124         }
125 
126         closedir(pDir);
127     }
128 
129     // try the legacy libdrmdecrypt.so
130     pluginPath = "libdrmdecrypt.so";
131     if (loadLibraryForScheme(pluginPath, uuid)) {
132         mUUIDToLibraryPathMap.add(uuidVector, pluginPath);
133         mInitCheck = OK;
134         return;
135     }
136 
137     ALOGE("Failed to find crypto plugin");
138     mInitCheck = ERROR_UNSUPPORTED;
139 }
140 
loadLibraryForScheme(const String8 & path,const uint8_t uuid[16])141 bool Crypto::loadLibraryForScheme(const String8 &path, const uint8_t uuid[16]) {
142 
143     // get strong pointer to open shared library
144     ssize_t index = mLibraryPathToOpenLibraryMap.indexOfKey(path);
145     if (index >= 0) {
146         mLibrary = mLibraryPathToOpenLibraryMap[index].promote();
147     } else {
148         index = mLibraryPathToOpenLibraryMap.add(path, NULL);
149     }
150 
151     if (!mLibrary.get()) {
152         mLibrary = new SharedLibrary(path);
153         if (!*mLibrary) {
154             return false;
155         }
156 
157         mLibraryPathToOpenLibraryMap.replaceValueAt(index, mLibrary);
158     }
159 
160     typedef CryptoFactory *(*CreateCryptoFactoryFunc)();
161 
162     CreateCryptoFactoryFunc createCryptoFactory =
163         (CreateCryptoFactoryFunc)mLibrary->lookup("createCryptoFactory");
164 
165     if (createCryptoFactory == NULL ||
166         (mFactory = createCryptoFactory()) == NULL ||
167         !mFactory->isCryptoSchemeSupported(uuid)) {
168         closeFactory();
169         return false;
170     }
171     return true;
172 }
173 
isCryptoSchemeSupported(const uint8_t uuid[16])174 bool Crypto::isCryptoSchemeSupported(const uint8_t uuid[16]) {
175     Mutex::Autolock autoLock(mLock);
176 
177     if (mFactory && mFactory->isCryptoSchemeSupported(uuid)) {
178         return true;
179     }
180 
181     findFactoryForScheme(uuid);
182     return (mInitCheck == OK);
183 }
184 
createPlugin(const uint8_t uuid[16],const void * data,size_t size)185 status_t Crypto::createPlugin(
186         const uint8_t uuid[16], const void *data, size_t size) {
187     Mutex::Autolock autoLock(mLock);
188 
189     if (mPlugin != NULL) {
190         return -EINVAL;
191     }
192 
193     if (!mFactory || !mFactory->isCryptoSchemeSupported(uuid)) {
194         findFactoryForScheme(uuid);
195     }
196 
197     if (mInitCheck != OK) {
198         return mInitCheck;
199     }
200 
201     return mFactory->createPlugin(uuid, data, size, &mPlugin);
202 }
203 
destroyPlugin()204 status_t Crypto::destroyPlugin() {
205     Mutex::Autolock autoLock(mLock);
206 
207     if (mInitCheck != OK) {
208         return mInitCheck;
209     }
210 
211     if (mPlugin == NULL) {
212         return -EINVAL;
213     }
214 
215     delete mPlugin;
216     mPlugin = NULL;
217 
218     return OK;
219 }
220 
requiresSecureDecoderComponent(const char * mime) const221 bool Crypto::requiresSecureDecoderComponent(const char *mime) const {
222     Mutex::Autolock autoLock(mLock);
223 
224     if (mInitCheck != OK) {
225         return mInitCheck;
226     }
227 
228     if (mPlugin == NULL) {
229         return -EINVAL;
230     }
231 
232     return mPlugin->requiresSecureDecoderComponent(mime);
233 }
234 
decrypt(bool secure,const uint8_t key[16],const uint8_t iv[16],CryptoPlugin::Mode mode,const void * srcPtr,const CryptoPlugin::SubSample * subSamples,size_t numSubSamples,void * dstPtr,AString * errorDetailMsg)235 ssize_t Crypto::decrypt(
236         bool secure,
237         const uint8_t key[16],
238         const uint8_t iv[16],
239         CryptoPlugin::Mode mode,
240         const void *srcPtr,
241         const CryptoPlugin::SubSample *subSamples, size_t numSubSamples,
242         void *dstPtr,
243         AString *errorDetailMsg) {
244     Mutex::Autolock autoLock(mLock);
245 
246     if (mInitCheck != OK) {
247         return mInitCheck;
248     }
249 
250     if (mPlugin == NULL) {
251         return -EINVAL;
252     }
253 
254     return mPlugin->decrypt(
255             secure, key, iv, mode, srcPtr, subSamples, numSubSamples, dstPtr,
256             errorDetailMsg);
257 }
258 
259 }  // namespace android
260