MediaCas: add MediaCasService
This CL adds API only without implementation.
bug: 22804304
Change-Id: Ibb5a29cc616ec0af81957b2bfe1419c482591753
diff --git a/services/mediadrm/Android.mk b/services/mediadrm/Android.mk
index e72236d..87fddd4 100644
--- a/services/mediadrm/Android.mk
+++ b/services/mediadrm/Android.mk
@@ -17,6 +17,7 @@
include $(CLEAR_VARS)
LOCAL_SRC_FILES:= \
+ MediaCasService.cpp \
MediaDrmService.cpp \
main_mediadrmserver.cpp
diff --git a/services/mediadrm/FactoryLoader.h b/services/mediadrm/FactoryLoader.h
new file mode 100644
index 0000000..1e03e9b
--- /dev/null
+++ b/services/mediadrm/FactoryLoader.h
@@ -0,0 +1,220 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef MEDIA_CAS_LOADER_H_
+#define MEDIA_CAS_LOADER_H_
+
+#include <dirent.h>
+#include <dlfcn.h>
+#include <media/SharedLibrary.h>
+#include <utils/KeyedVector.h>
+#include <utils/Mutex.h>
+
+namespace android {
+using namespace std;
+using namespace media;
+using namespace MediaCas;
+
+template <class T>
+class FactoryLoader {
+public:
+ FactoryLoader(const char *name) :
+ mFactory(NULL), mCreateFactoryFuncName(name) {}
+
+ virtual ~FactoryLoader() { closeFactory(); }
+
+ bool findFactoryForScheme(
+ int32_t CA_system_id,
+ sp<SharedLibrary> *library = NULL,
+ T** factory = NULL);
+
+ bool enumeratePlugins(vector<ParcelableCasPluginDescriptor>* results);
+
+private:
+ typedef T*(*CreateFactoryFunc)();
+
+ Mutex mMapLock;
+ T* mFactory;
+ const char *mCreateFactoryFuncName;
+ sp<SharedLibrary> mLibrary;
+ KeyedVector<int32_t, String8> mCASystemIdToLibraryPathMap;
+ KeyedVector<String8, wp<SharedLibrary> > mLibraryPathToOpenLibraryMap;
+
+ bool loadFactoryForSchemeFromPath(
+ const String8 &path,
+ int32_t CA_system_id,
+ sp<SharedLibrary> *library,
+ T** factory);
+
+ bool queryPluginsFromPath(
+ const String8 &path,
+ vector<ParcelableCasPluginDescriptor>* results);
+
+ bool openFactory(const String8 &path);
+ void closeFactory();
+};
+
+template <class T>
+bool FactoryLoader<T>::findFactoryForScheme(
+ int32_t CA_system_id, sp<SharedLibrary> *library, T** factory) {
+ if (library != NULL) {
+ library->clear();
+ }
+ if (factory != NULL) {
+ *factory = NULL;
+ }
+
+ Mutex::Autolock autoLock(mMapLock);
+
+ // first check cache
+ ssize_t index = mCASystemIdToLibraryPathMap.indexOfKey(CA_system_id);
+ if (index >= 0) {
+ return loadFactoryForSchemeFromPath(
+ mCASystemIdToLibraryPathMap[index],
+ CA_system_id, library, factory);
+ }
+
+ // no luck, have to search
+ String8 dirPath("/vendor/lib/mediacas");
+ DIR* pDir = opendir(dirPath.string());
+
+ if (pDir == NULL) {
+ ALOGE("Failed to open plugin directory %s", dirPath.string());
+ return false;
+ }
+
+ struct dirent* pEntry;
+ while ((pEntry = readdir(pDir))) {
+ String8 pluginPath = dirPath + "/" + pEntry->d_name;
+ if (pluginPath.getPathExtension() == ".so") {
+ if (loadFactoryForSchemeFromPath(
+ pluginPath, CA_system_id, library, factory)) {
+ mCASystemIdToLibraryPathMap.add(CA_system_id, pluginPath);
+ closedir(pDir);
+
+ return true;
+ }
+ }
+ }
+
+ closedir(pDir);
+
+ ALOGE("Failed to find plugin");
+ return false;
+}
+
+template <class T>
+bool FactoryLoader<T>::enumeratePlugins(
+ vector<ParcelableCasPluginDescriptor>* results) {
+ ALOGI("enumeratePlugins");
+
+ results->clear();
+
+ String8 dirPath("/vendor/lib/mediacas");
+ DIR* pDir = opendir(dirPath.string());
+
+ if (pDir == NULL) {
+ ALOGE("Failed to open plugin directory %s", dirPath.string());
+ return false;
+ }
+
+ Mutex::Autolock autoLock(mMapLock);
+
+ struct dirent* pEntry;
+ while ((pEntry = readdir(pDir))) {
+ String8 pluginPath = dirPath + "/" + pEntry->d_name;
+ if (pluginPath.getPathExtension() == ".so") {
+ queryPluginsFromPath(pluginPath, results);
+ }
+ }
+ return true;
+}
+
+template <class T>
+bool FactoryLoader<T>::loadFactoryForSchemeFromPath(
+ const String8 &path, int32_t CA_system_id,
+ sp<SharedLibrary> *library, T** factory) {
+ closeFactory();
+
+ if (!openFactory(path) || !mFactory->isSystemIdSupported(CA_system_id)) {
+ closeFactory();
+ return false;
+ }
+
+ if (library != NULL) {
+ *library = mLibrary;
+ }
+ if (factory != NULL) {
+ *factory = mFactory;
+ }
+ return true;
+}
+
+template <class T>
+bool FactoryLoader<T>::queryPluginsFromPath(
+ const String8 &path, vector<ParcelableCasPluginDescriptor>* results) {
+ closeFactory();
+
+ vector<CasPluginDescriptor> descriptors;
+ if (!openFactory(path) || mFactory->queryPlugins(&descriptors) != OK) {
+ closeFactory();
+ return false;
+ }
+
+ for (auto it = descriptors.begin(); it != descriptors.end(); it++) {
+ results->push_back(ParcelableCasPluginDescriptor(
+ it->CA_system_id, it->name));
+ }
+ return true;
+}
+
+template <class T>
+bool FactoryLoader<T>::openFactory(const String8 &path) {
+ // get strong pointer to open shared library
+ ssize_t index = mLibraryPathToOpenLibraryMap.indexOfKey(path);
+ if (index >= 0) {
+ mLibrary = mLibraryPathToOpenLibraryMap[index].promote();
+ } else {
+ index = mLibraryPathToOpenLibraryMap.add(path, NULL);
+ }
+
+ if (!mLibrary.get()) {
+ mLibrary = new SharedLibrary(path);
+ if (!*mLibrary) {
+ return false;
+ }
+
+ mLibraryPathToOpenLibraryMap.replaceValueAt(index, mLibrary);
+ }
+
+ CreateFactoryFunc createFactory =
+ (CreateFactoryFunc)mLibrary->lookup(mCreateFactoryFuncName);
+ if (createFactory == NULL || (mFactory = createFactory()) == NULL) {
+ return false;
+ }
+ return true;
+}
+
+template <class T>
+void FactoryLoader<T>::closeFactory() {
+ delete mFactory;
+ mFactory = NULL;
+ mLibrary.clear();
+}
+
+} // namespace android
+
+#endif // MEDIA_CAS_LOADER_H_
diff --git a/services/mediadrm/MediaCasService.cpp b/services/mediadrm/MediaCasService.cpp
new file mode 100644
index 0000000..c111283
--- /dev/null
+++ b/services/mediadrm/MediaCasService.cpp
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "MediaCasService"
+
+#include <binder/IServiceManager.h>
+#include <media/cas/CasAPI.h>
+#include <media/cas/DescramblerAPI.h>
+#include <media/CasImpl.h>
+#include <media/DescramblerImpl.h>
+#include <utils/Log.h>
+#include <utils/List.h>
+#include "MediaCasService.h"
+#include <android/media/ICasListener.h>
+
+namespace android {
+
+//static
+void MediaCasService::instantiate() {
+ defaultServiceManager()->addService(
+ String16("media.cas"), new MediaCasService());
+}
+
+MediaCasService::MediaCasService() :
+ mCasLoader(new FactoryLoader<CasFactory>("createCasFactory")),
+ mDescramblerLoader(new FactoryLoader<DescramblerFactory>(
+ "createDescramblerFactory")) {
+}
+
+MediaCasService::~MediaCasService() {
+ delete mCasLoader;
+ delete mDescramblerLoader;
+}
+
+Status MediaCasService::enumeratePlugins(
+ vector<ParcelableCasPluginDescriptor>* results) {
+ ALOGV("enumeratePlugins");
+
+ mCasLoader->enumeratePlugins(results);
+
+ return Status::ok();
+}
+
+Status MediaCasService::isSystemIdSupported(
+ int32_t CA_system_id, bool* result) {
+ ALOGV("isSystemIdSupported: CA_system_id=%d", CA_system_id);
+
+ *result = mCasLoader->findFactoryForScheme(CA_system_id);
+
+ return Status::ok();
+}
+
+Status MediaCasService::createPlugin(
+ int32_t CA_system_id,
+ const sp<ICasListener> &listener,
+ sp<ICas>* result) {
+ ALOGV("createPlugin: CA_system_id=%d", CA_system_id);
+
+ result->clear();
+
+ CasFactory *factory;
+ sp<SharedLibrary> library;
+ if (mCasLoader->findFactoryForScheme(CA_system_id, &library, &factory)) {
+ CasPlugin *plugin = NULL;
+ sp<CasImpl> casImpl = new CasImpl(listener);
+ if (factory->createPlugin(CA_system_id, (uint64_t)casImpl.get(),
+ &CasImpl::OnEvent, &plugin) == OK && plugin != NULL) {
+ casImpl->init(library, plugin);
+ *result = casImpl;
+ }
+ }
+
+ return Status::ok();
+}
+
+Status MediaCasService::isDescramblerSupported(
+ int32_t CA_system_id, bool* result) {
+ ALOGV("isDescramblerSupported: CA_system_id=%d", CA_system_id);
+
+ *result = mDescramblerLoader->findFactoryForScheme(CA_system_id);
+
+ return Status::ok();
+}
+
+Status MediaCasService::createDescrambler(
+ int32_t CA_system_id, sp<IDescrambler>* result) {
+ ALOGV("createDescrambler: CA_system_id=%d", CA_system_id);
+
+ result->clear();
+
+ DescramblerFactory *factory;
+ sp<SharedLibrary> library;
+ if (mDescramblerLoader->findFactoryForScheme(
+ CA_system_id, &library, &factory)) {
+ DescramblerPlugin *plugin = NULL;
+ if (factory->createPlugin(CA_system_id, &plugin) == OK
+ && plugin != NULL) {
+ *result = new DescramblerImpl(library, plugin);
+ }
+ }
+
+ return Status::ok();
+}
+
+} // namespace android
diff --git a/services/mediadrm/MediaCasService.h b/services/mediadrm/MediaCasService.h
new file mode 100644
index 0000000..cb828f2
--- /dev/null
+++ b/services/mediadrm/MediaCasService.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef MEDIA_CAS_SERVICE_H_
+#define MEDIA_CAS_SERVICE_H_
+
+#include <android/media/BnMediaCasService.h>
+
+#include "FactoryLoader.h"
+
+namespace android {
+using binder::Status;
+struct CasFactory;
+struct DescramblerFactory;
+
+class MediaCasService : public BnMediaCasService {
+public:
+ static void instantiate();
+
+ virtual Status enumeratePlugins(
+ vector<ParcelableCasPluginDescriptor>* results) override;
+
+ virtual Status isSystemIdSupported(
+ int32_t CA_system_id, bool* result) override;
+
+ virtual Status createPlugin(
+ int32_t CA_system_id,
+ const sp<ICasListener> &listener,
+ sp<ICas>* result) override;
+
+ virtual Status isDescramblerSupported(
+ int32_t CA_system_id, bool* result) override;
+
+ virtual Status createDescrambler(
+ int32_t CA_system_id, sp<IDescrambler>* result) override;
+
+private:
+ FactoryLoader<CasFactory> *mCasLoader;
+ FactoryLoader<DescramblerFactory> *mDescramblerLoader;
+
+ MediaCasService();
+ virtual ~MediaCasService();
+};
+
+} // namespace android
+
+#endif // MEDIA_CAS_SERVICE_H_
diff --git a/services/mediadrm/main_mediadrmserver.cpp b/services/mediadrm/main_mediadrmserver.cpp
index b767b8c..b685ae0 100644
--- a/services/mediadrm/main_mediadrmserver.cpp
+++ b/services/mediadrm/main_mediadrmserver.cpp
@@ -27,6 +27,7 @@
#include <cutils/properties.h>
#include <utils/Log.h>
#include "MediaDrmService.h"
+#include "MediaCasService.h"
using namespace android;
@@ -38,6 +39,7 @@
sp<IServiceManager> sm = defaultServiceManager();
ALOGI("ServiceManager: %p", sm.get());
MediaDrmService::instantiate();
+ MediaCasService::instantiate();
ProcessState::self()->startThreadPool();
IPCThreadState::self()->joinThreadPool();
}