MediaCas: add MediaCasService
This CL adds API only without implementation.
bug: 22804304
Change-Id: Ibb5a29cc616ec0af81957b2bfe1419c482591753
diff --git a/drm/libmediadrm/Android.mk b/drm/libmediadrm/Android.mk
index 8e3cc40..7176582 100644
--- a/drm/libmediadrm/Android.mk
+++ b/drm/libmediadrm/Android.mk
@@ -6,12 +6,24 @@
include $(CLEAR_VARS)
-LOCAL_SRC_FILES:= \
+LOCAL_AIDL_INCLUDES := \
+ frameworks/base/media/java
+
+LOCAL_SRC_FILES := \
+ ../../../base/media/java/android/media/ICas.aidl \
+ ../../../base/media/java/android/media/ICasListener.aidl \
+ ../../../base/media/java/android/media/IDescrambler.aidl \
+ ../../../base/media/java/android/media/IMediaCasService.aidl \
+
+LOCAL_SRC_FILES += \
+ CasImpl.cpp \
+ DescramblerImpl.cpp \
DrmSessionManager.cpp \
ICrypto.cpp \
IDrm.cpp \
IDrmClient.cpp \
IMediaDrmService.cpp \
+ MediaCasDefs.cpp \
SharedLibrary.cpp
ifneq ($(DISABLE_TREBLE_DRM), true)
LOCAL_SRC_FILES += \
diff --git a/drm/libmediadrm/CasImpl.cpp b/drm/libmediadrm/CasImpl.cpp
new file mode 100644
index 0000000..de15244
--- /dev/null
+++ b/drm/libmediadrm/CasImpl.cpp
@@ -0,0 +1,201 @@
+
+/*
+ * 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 "CasImpl"
+
+#include <android/media/ICasListener.h>
+#include <media/cas/CasAPI.h>
+#include <media/CasImpl.h>
+#include <media/SharedLibrary.h>
+#include <utils/Log.h>
+
+namespace android {
+
+static Status getBinderStatus(status_t err) {
+ if (err == OK) {
+ return Status::ok();
+ }
+ if (err == BAD_VALUE) {
+ return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT);
+ }
+ if (err == INVALID_OPERATION) {
+ return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE);
+ }
+ return Status::fromServiceSpecificError(err);
+}
+
+static String8 sessionIdToString(const CasSessionId &sessionId) {
+ String8 result;
+ for (size_t i = 0; i < sessionId.size(); i++) {
+ result.appendFormat("%02x ", sessionId[i]);
+ }
+ if (result.isEmpty()) {
+ result.append("(null)");
+ }
+ return result;
+}
+
+CasImpl::CasImpl(const sp<ICasListener> &listener)
+ : mPlugin(NULL), mListener(listener) {
+ ALOGV("CTOR: mPlugin=%p", mPlugin);
+}
+
+CasImpl::~CasImpl() {
+ ALOGV("DTOR: mPlugin=%p", mPlugin);
+ release();
+}
+
+//static
+void CasImpl::OnEvent(
+ void *appData,
+ int32_t event,
+ int32_t arg,
+ uint8_t *data,
+ size_t size) {
+ if (appData == NULL) {
+ ALOGE("Invalid appData!");
+ return;
+ }
+ CasImpl *casImpl = static_cast<CasImpl *>(appData);
+ casImpl->onEvent(event, arg, data, size);
+}
+
+void CasImpl::init(const sp<SharedLibrary>& library, CasPlugin *plugin) {
+ mLibrary = library;
+ mPlugin = plugin;
+}
+
+void CasImpl::onEvent(
+ int32_t event, int32_t arg, uint8_t *data, size_t size) {
+ if (mListener == NULL) {
+ return;
+ }
+
+ std::unique_ptr<CasData> eventData;
+ if (data != NULL && size > 0) {
+ eventData.reset(new CasData(data, data + size));
+ }
+
+ mListener->onEvent(event, arg, eventData);
+}
+
+Status CasImpl::setPrivateData(const CasData& pvtData) {
+ ALOGV("setPrivateData");
+ return getBinderStatus(mPlugin->setPrivateData(pvtData));
+}
+
+Status CasImpl::openSession(int32_t program_number, CasSessionId* sessionId) {
+ ALOGV("openSession: program_number=%d", program_number);
+
+ status_t err = mPlugin->openSession(program_number, sessionId);
+
+ ALOGV("openSession: session opened for program_number=%d, sessionId=%s",
+ program_number, sessionIdToString(*sessionId).string());
+
+ return getBinderStatus(err);
+}
+
+Status CasImpl::openSessionForStream(
+ int32_t program_number,
+ int32_t elementary_PID,
+ CasSessionId* sessionId) {
+ ALOGV("openSession: program_number=%d, elementary_PID=%d",
+ program_number, elementary_PID);
+
+ status_t err = mPlugin->openSession(
+ program_number, elementary_PID, sessionId);
+
+ ALOGV("openSession: session opened for "
+ "program_number=%d, elementary_PID=%d, sessionId=%s",
+ program_number, elementary_PID,
+ sessionIdToString(*sessionId).string());
+
+ return getBinderStatus(err);
+}
+
+Status CasImpl::setSessionPrivateData(
+ const CasSessionId &sessionId, const CasData& pvtData) {
+ ALOGV("setSessionPrivateData: sessionId=%s",
+ sessionIdToString(sessionId).string());
+
+ return getBinderStatus(mPlugin->setSessionPrivateData(sessionId, pvtData));
+}
+
+Status CasImpl::closeSession(const CasSessionId &sessionId) {
+ ALOGV("closeSession: sessionId=%s",
+ sessionIdToString(sessionId).string());
+
+ return getBinderStatus(mPlugin->closeSession(sessionId));
+}
+
+Status CasImpl::processEcm(const CasSessionId &sessionId, const ParcelableCasData& ecm) {
+ ALOGV("processEcm: sessionId=%s",
+ sessionIdToString(sessionId).string());
+
+ return getBinderStatus(mPlugin->processEcm(sessionId, ecm));
+}
+
+Status CasImpl::processEmm(const ParcelableCasData& emm) {
+ ALOGV("processEmm");
+
+ return getBinderStatus(mPlugin->processEmm(emm));
+}
+
+Status CasImpl::sendEvent(
+ int32_t event, int32_t arg, const ::std::unique_ptr<CasData> &eventData) {
+ ALOGV("sendEvent");
+
+ status_t err;
+ if (eventData == nullptr) {
+ err = mPlugin->sendEvent(event, arg, CasData());
+ } else {
+ err = mPlugin->sendEvent(event, arg, *eventData);
+ }
+ return getBinderStatus(err);
+}
+
+Status CasImpl::provision(const String16& provisionString) {
+ ALOGV("provision: provisionString=%s", String8(provisionString).string());
+
+ return getBinderStatus(mPlugin->provision(String8(provisionString)));
+}
+
+Status CasImpl::refreshEntitlements(
+ int32_t refreshType, const ::std::unique_ptr<CasData> &refreshData) {
+ ALOGV("refreshEntitlements");
+
+ status_t err;
+ if (refreshData == nullptr) {
+ err = mPlugin->refreshEntitlements(refreshType, CasData());
+ } else {
+ err = mPlugin->refreshEntitlements(refreshType, *refreshData);
+ }
+ return getBinderStatus(err);
+}
+
+Status CasImpl::release() {
+ ALOGV("release: mPlugin=%p", mPlugin);
+
+ if (mPlugin != NULL) {
+ delete mPlugin;
+ mPlugin = NULL;
+ }
+ return Status::ok();
+}
+
+} // namespace android
+
diff --git a/drm/libmediadrm/DescramblerImpl.cpp b/drm/libmediadrm/DescramblerImpl.cpp
new file mode 100644
index 0000000..94e09e2
--- /dev/null
+++ b/drm/libmediadrm/DescramblerImpl.cpp
@@ -0,0 +1,107 @@
+
+/*
+ * 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 "DescramblerImpl"
+
+#include <media/cas/DescramblerAPI.h>
+#include <media/DescramblerImpl.h>
+#include <media/SharedLibrary.h>
+#include <utils/Log.h>
+#include <binder/IMemory.h>
+
+namespace android {
+
+static Status getBinderStatus(status_t err) {
+ if (err == OK) {
+ return Status::ok();
+ }
+ if (err == BAD_VALUE) {
+ return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT);
+ }
+ if (err == INVALID_OPERATION) {
+ return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE);
+ }
+ return Status::fromServiceSpecificError(err);
+}
+
+static String8 sessionIdToString(const CasSessionId &sessionId) {
+ String8 result;
+ for (size_t i = 0; i < sessionId.size(); i++) {
+ result.appendFormat("%02x ", sessionId[i]);
+ }
+ if (result.isEmpty()) {
+ result.append("(null)");
+ }
+ return result;
+}
+
+DescramblerImpl::DescramblerImpl(
+ const sp<SharedLibrary>& library, DescramblerPlugin *plugin) :
+ mLibrary(library), mPlugin(plugin) {
+ ALOGV("CTOR: mPlugin=%p", mPlugin);
+}
+
+DescramblerImpl::~DescramblerImpl() {
+ ALOGV("DTOR: mPlugin=%p", mPlugin);
+ release();
+}
+
+Status DescramblerImpl::setMediaCasSession(const CasSessionId& sessionId) {
+ ALOGV("setMediaCasSession: sessionId=%s",
+ sessionIdToString(sessionId).string());
+
+ return getBinderStatus(mPlugin->setMediaCasSession(sessionId));
+}
+
+Status DescramblerImpl::requiresSecureDecoderComponent(
+ const String16& mime, bool *result) {
+ *result = mPlugin->requiresSecureDecoderComponent(String8(mime));
+
+ return getBinderStatus(OK);
+}
+
+Status DescramblerImpl::descramble(
+ const DescrambleInfo& info, int32_t *result) {
+ ALOGV("descramble");
+
+ *result = mPlugin->descramble(
+ info.dstType != DescrambleInfo::kDestinationTypeVmPointer,
+ info.scramblingControl,
+ info.numSubSamples,
+ info.subSamples,
+ info.srcMem->pointer(),
+ info.srcOffset,
+ info.dstType == DescrambleInfo::kDestinationTypeVmPointer ?
+ info.srcMem->pointer() : info.dstPtr,
+ info.dstOffset,
+ NULL);
+
+ return getBinderStatus(*result >= 0 ? OK : *result);
+}
+
+Status DescramblerImpl::release() {
+ ALOGV("release: mPlugin=%p", mPlugin);
+
+ if (mPlugin != NULL) {
+ delete mPlugin;
+ mPlugin = NULL;
+ }
+ return Status::ok();
+}
+
+} // namespace android
+
diff --git a/drm/libmediadrm/MediaCasDefs.cpp b/drm/libmediadrm/MediaCasDefs.cpp
new file mode 100644
index 0000000..9c2ba38
--- /dev/null
+++ b/drm/libmediadrm/MediaCasDefs.cpp
@@ -0,0 +1,184 @@
+/*
+ * 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 "MediaCas"
+
+#include <media/MediaCasDefs.h>
+#include <utils/Log.h>
+#include <binder/IMemory.h>
+
+namespace android {
+namespace media {
+
+///////////////////////////////////////////////////////////////////////////////
+namespace MediaCas {
+
+status_t ParcelableCasData::readFromParcel(const Parcel* parcel) {
+ return parcel->readByteVector(this);
+}
+
+status_t ParcelableCasData::writeToParcel(Parcel* parcel) const {
+ return parcel->writeByteVector(*this);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+status_t ParcelableCasPluginDescriptor::readFromParcel(const Parcel* /*parcel*/) {
+ ALOGE("CAPluginDescriptor::readFromParcel() shouldn't be called");
+ return INVALID_OPERATION;
+}
+
+status_t ParcelableCasPluginDescriptor::writeToParcel(Parcel* parcel) const {
+ status_t err = parcel->writeInt32(mCASystemId);
+ if (err != NO_ERROR) {
+ return err;
+ }
+ return parcel->writeString16(mName);
+}
+
+} // namespace MediaCas
+///////////////////////////////////////////////////////////////////////////////
+
+namespace MediaDescrambler {
+
+DescrambleInfo::DescrambleInfo() {}
+
+DescrambleInfo::~DescrambleInfo() {}
+
+status_t DescrambleInfo::readFromParcel(const Parcel* parcel) {
+ status_t err = parcel->readInt32((int32_t*)&dstType);
+ if (err != OK) {
+ return err;
+ }
+ if (dstType != kDestinationTypeNativeHandle
+ && dstType != kDestinationTypeVmPointer) {
+ return BAD_VALUE;
+ }
+
+ err = parcel->readInt32((int32_t*)&scramblingControl);
+ if (err != OK) {
+ return err;
+ }
+
+ err = parcel->readUint32((uint32_t*)&numSubSamples);
+ if (err != OK) {
+ return err;
+ }
+ if (numSubSamples > 0xffff) {
+ return BAD_VALUE;
+ }
+
+ subSamples = new DescramblerPlugin::SubSample[numSubSamples];
+ if (subSamples == NULL) {
+ return NO_MEMORY;
+ }
+
+ for (size_t i = 0; i < numSubSamples; i++) {
+ err = parcel->readUint32(&subSamples[i].mNumBytesOfClearData);
+ if (err != OK) {
+ return err;
+ }
+ err = parcel->readUint32(&subSamples[i].mNumBytesOfEncryptedData);
+ if (err != OK) {
+ return err;
+ }
+ }
+
+ srcMem = interface_cast<IMemory>(parcel->readStrongBinder());
+ if (srcMem == NULL) {
+ return BAD_VALUE;
+ }
+
+ err = parcel->readInt32(&srcOffset);
+ if (err != OK) {
+ return err;
+ }
+
+ native_handle_t *nativeHandle = NULL;
+ if (dstType == kDestinationTypeNativeHandle) {
+ nativeHandle = parcel->readNativeHandle();
+ dstPtr = static_cast<void *>(nativeHandle);
+ } else {
+ dstPtr = NULL;
+ }
+
+ err = parcel->readInt32(&dstOffset);
+ if (err != OK) {
+ return err;
+ }
+
+ return OK;
+}
+
+status_t DescrambleInfo::writeToParcel(Parcel* parcel) const {
+ if (dstType != kDestinationTypeNativeHandle
+ && dstType != kDestinationTypeVmPointer) {
+ return BAD_VALUE;
+ }
+
+ status_t err = parcel->writeInt32((int32_t)dstType);
+ if (err != OK) {
+ return err;
+ }
+
+ err = parcel->writeInt32(scramblingControl);
+ if (err != OK) {
+ return err;
+ }
+
+ err = parcel->writeUint32(numSubSamples);
+ if (err != OK) {
+ return err;
+ }
+
+ for (size_t i = 0; i < numSubSamples; i++) {
+ err = parcel->writeUint32(subSamples[i].mNumBytesOfClearData);
+ if (err != OK) {
+ return err;
+ }
+ err = parcel->writeUint32(subSamples[i].mNumBytesOfEncryptedData);
+ if (err != OK) {
+ return err;
+ }
+ }
+
+ err = parcel->writeStrongBinder(IInterface::asBinder(srcMem));
+ if (err != OK) {
+ return err;
+ }
+
+ err = parcel->writeInt32(srcOffset);
+ if (err != OK) {
+ return err;
+ }
+
+ if (dstType == kDestinationTypeNativeHandle) {
+ parcel->writeNativeHandle(static_cast<native_handle_t *>(dstPtr));
+ }
+
+ err = parcel->writeInt32(dstOffset);
+ if (err != OK) {
+ return err;
+ }
+
+ return OK;
+}
+
+} // namespace MediaDescrambler
+
+} // namespace media
+} // namespace android
+
diff --git a/drm/libmediadrm/SharedLibrary.cpp b/drm/libmediadrm/SharedLibrary.cpp
index 74b3a71..bebafa8 100644
--- a/drm/libmediadrm/SharedLibrary.cpp
+++ b/drm/libmediadrm/SharedLibrary.cpp
@@ -43,6 +43,9 @@
if (!mLibHandle) {
return NULL;
}
+ // Clear last error before we load the symbol again,
+ // in case the caller didn't retrieve it.
+ (void)dlerror();
return dlsym(mLibHandle, symbol);
}
diff --git a/include/media/CasImpl.h b/include/media/CasImpl.h
new file mode 100644
index 0000000..80c901e
--- /dev/null
+++ b/include/media/CasImpl.h
@@ -0,0 +1,96 @@
+/*
+ * 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 CAS_IMPL_H_
+#define CAS_IMPL_H_
+
+#include <media/stagefright/foundation/ABase.h>
+#include <android/media/BnCas.h>
+
+namespace android {
+namespace media {
+class ICasListener;
+}
+using namespace media;
+using namespace MediaCas;
+using binder::Status;
+class CasPlugin;
+class SharedLibrary;
+
+class CasImpl : public BnCas {
+public:
+ CasImpl(const sp<ICasListener> &listener);
+ virtual ~CasImpl();
+
+ static void OnEvent(
+ void *appData,
+ int32_t event,
+ int32_t arg,
+ uint8_t *data,
+ size_t size);
+
+ void init(const sp<SharedLibrary>& library, CasPlugin *plugin);
+ void onEvent(
+ int32_t event,
+ int32_t arg,
+ uint8_t *data,
+ size_t size);
+
+ // ICas inherits
+
+ virtual Status setPrivateData(
+ const CasData& pvtData) override;
+
+ virtual Status openSession(
+ int32_t program_number, CasSessionId* _aidl_return) override;
+
+ virtual Status openSessionForStream(
+ int32_t program_number,
+ int32_t elementary_PID,
+ CasSessionId* _aidl_return) override;
+
+ virtual Status closeSession(const CasSessionId& sessionId) override;
+
+ virtual Status setSessionPrivateData(
+ const CasSessionId& sessionId,
+ const CasData& pvtData) override;
+
+ virtual Status processEcm(
+ const CasSessionId& sessionId, const ParcelableCasData& ecm) override;
+
+ virtual Status processEmm(const ParcelableCasData& emm) override;
+
+ virtual Status sendEvent(
+ int32_t event, int32_t arg, const ::std::unique_ptr<CasData> &eventData) override;
+
+ virtual Status provision(const String16& provisionString) override;
+
+ virtual Status refreshEntitlements(
+ int32_t refreshType, const ::std::unique_ptr<CasData> &refreshData) override;
+
+ virtual Status release() override;
+
+private:
+ sp<SharedLibrary> mLibrary;
+ CasPlugin *mPlugin;
+ sp<ICasListener> mListener;
+
+ DISALLOW_EVIL_CONSTRUCTORS(CasImpl);
+};
+
+} // namespace android
+
+#endif // CAS_IMPL_H_
diff --git a/include/media/DescramblerImpl.h b/include/media/DescramblerImpl.h
new file mode 100644
index 0000000..c1c79b3
--- /dev/null
+++ b/include/media/DescramblerImpl.h
@@ -0,0 +1,55 @@
+/*
+ * 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 DESCRAMBLER_IMPL_H_
+#define DESCRAMBLER_IMPL_H_
+
+#include <media/stagefright/foundation/ABase.h>
+#include <android/media/BnDescrambler.h>
+
+namespace android {
+using namespace media;
+using namespace MediaDescrambler;
+using binder::Status;
+class DescramblerPlugin;
+class SharedLibrary;
+
+class DescramblerImpl : public BnDescrambler {
+public:
+ DescramblerImpl(const sp<SharedLibrary>& library, DescramblerPlugin *plugin);
+ virtual ~DescramblerImpl();
+
+ virtual Status setMediaCasSession(
+ const CasSessionId& sessionId) override;
+
+ virtual Status requiresSecureDecoderComponent(
+ const String16& mime, bool *result) override;
+
+ virtual Status descramble(
+ const DescrambleInfo& descrambleInfo, int32_t *result) override;
+
+ virtual Status release() override;
+
+private:
+ sp<SharedLibrary> mLibrary;
+ DescramblerPlugin *mPlugin;
+
+ DISALLOW_EVIL_CONSTRUCTORS(DescramblerImpl);
+};
+
+} // namespace android
+
+#endif // DESCRAMBLER_IMPL_H_
diff --git a/include/media/IMediaExtractor.h b/include/media/IMediaExtractor.h
index 06db359..cf1b9fb 100644
--- a/include/media/IMediaExtractor.h
+++ b/include/media/IMediaExtractor.h
@@ -24,6 +24,10 @@
namespace android {
class MetaData;
+namespace media {
+class ICas;
+};
+using namespace media;
class IMediaExtractor : public IInterface {
public:
@@ -57,6 +61,9 @@
// for DRM
virtual char* getDrmTrackInfo(size_t trackID, int *len) = 0;
+
+ virtual status_t setMediaCas(const sp<ICas> &cas) = 0;
+
virtual void setUID(uid_t uid) = 0;
virtual const char * name() = 0;
diff --git a/include/media/MediaCasDefs.h b/include/media/MediaCasDefs.h
new file mode 100644
index 0000000..8c5a967
--- /dev/null
+++ b/include/media/MediaCasDefs.h
@@ -0,0 +1,97 @@
+/*
+ * 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_DEFS_H_
+#define MEDIA_CAS_DEFS_H_
+
+#include <binder/Parcel.h>
+#include <media/cas/CasAPI.h>
+#include <media/cas/DescramblerAPI.h>
+#include <media/stagefright/foundation/ABase.h>
+
+namespace android {
+class IMemory;
+namespace media {
+
+namespace MediaCas {
+class ParcelableCasData : public CasData,
+ public Parcelable {
+public:
+ ParcelableCasData() {}
+ ParcelableCasData(const uint8_t *data, size_t size) :
+ CasData(data, data + size) {}
+ virtual ~ParcelableCasData() {}
+ status_t readFromParcel(const Parcel* parcel) override;
+ status_t writeToParcel(Parcel* parcel) const override;
+
+private:
+ DISALLOW_EVIL_CONSTRUCTORS(ParcelableCasData);
+};
+
+class ParcelableCasPluginDescriptor : public Parcelable {
+public:
+ ParcelableCasPluginDescriptor(int32_t CA_system_id, const char *name)
+ : mCASystemId(CA_system_id), mName(name) {}
+
+ ParcelableCasPluginDescriptor() : mCASystemId(0) {}
+
+ ParcelableCasPluginDescriptor(ParcelableCasPluginDescriptor&& desc) = default;
+
+ virtual ~ParcelableCasPluginDescriptor() {}
+
+ status_t readFromParcel(const Parcel* parcel) override;
+ status_t writeToParcel(Parcel* parcel) const override;
+
+private:
+ int32_t mCASystemId;
+ String16 mName;
+ DISALLOW_EVIL_CONSTRUCTORS(ParcelableCasPluginDescriptor);
+};
+}
+
+namespace MediaDescrambler {
+class DescrambleInfo : public Parcelable {
+public:
+ enum DestinationType {
+ kDestinationTypeVmPointer, // non-secure
+ kDestinationTypeNativeHandle // secure
+ };
+
+ DestinationType dstType;
+ DescramblerPlugin::ScramblingControl scramblingControl;
+ size_t numSubSamples;
+ DescramblerPlugin::SubSample *subSamples;
+ sp<IMemory> srcMem;
+ int32_t srcOffset;
+ void *dstPtr;
+ int32_t dstOffset;
+
+ DescrambleInfo();
+ virtual ~DescrambleInfo();
+ status_t readFromParcel(const Parcel* parcel) override;
+ status_t writeToParcel(Parcel* parcel) const override;
+
+private:
+
+ DISALLOW_EVIL_CONSTRUCTORS(DescrambleInfo);
+};
+}
+
+} // namespace media
+} // namespace android
+
+
+#endif // MEDIA_CAS_DEFS_H_
diff --git a/include/media/MediaDefs.h b/include/media/MediaDefs.h
index 0682413..7f17013 100644
--- a/include/media/MediaDefs.h
+++ b/include/media/MediaDefs.h
@@ -31,6 +31,7 @@
extern const char *MEDIA_MIMETYPE_VIDEO_MPEG2;
extern const char *MEDIA_MIMETYPE_VIDEO_RAW;
extern const char *MEDIA_MIMETYPE_VIDEO_DOLBY_VISION;
+extern const char *MEDIA_MIMETYPE_VIDEO_SCRAMBLED;
extern const char *MEDIA_MIMETYPE_AUDIO_AMR_NB;
extern const char *MEDIA_MIMETYPE_AUDIO_AMR_WB;
@@ -50,6 +51,7 @@
extern const char *MEDIA_MIMETYPE_AUDIO_MSGSM;
extern const char *MEDIA_MIMETYPE_AUDIO_AC3;
extern const char *MEDIA_MIMETYPE_AUDIO_EAC3;
+extern const char *MEDIA_MIMETYPE_AUDIO_SCRAMBLED;
extern const char *MEDIA_MIMETYPE_CONTAINER_MPEG4;
extern const char *MEDIA_MIMETYPE_CONTAINER_WAV;
diff --git a/include/media/stagefright/MediaCodec.h b/include/media/stagefright/MediaCodec.h
index 20b26e2..fd3ff26 100644
--- a/include/media/stagefright/MediaCodec.h
+++ b/include/media/stagefright/MediaCodec.h
@@ -47,6 +47,10 @@
struct PersistentSurface;
class SoftwareRenderer;
class Surface;
+namespace media {
+class IDescrambler;
+};
+using namespace media;
struct MediaCodec : public AHandler {
enum ConfigureFlags {
@@ -91,6 +95,13 @@
const sp<ICrypto> &crypto,
uint32_t flags);
+ status_t configure(
+ const sp<AMessage> &format,
+ const sp<Surface> &nativeWindow,
+ const sp<ICrypto> &crypto,
+ const sp<IDescrambler> &descrambler,
+ uint32_t flags);
+
status_t releaseCrypto();
status_t setCallback(const sp<AMessage> &callback);
@@ -345,6 +356,8 @@
sp<ICrypto> mCrypto;
+ sp<IDescrambler> mDescrambler;
+
List<sp<ABuffer> > mCSD;
sp<AMessage> mActivityNotify;
diff --git a/include/media/stagefright/MediaExtractor.h b/include/media/stagefright/MediaExtractor.h
index 9ce6cc5..073391f 100644
--- a/include/media/stagefright/MediaExtractor.h
+++ b/include/media/stagefright/MediaExtractor.h
@@ -23,7 +23,10 @@
#include <media/MediaAnalyticsItem.h>
namespace android {
-
+namespace media {
+class ICas;
+};
+using namespace media;
class DataSource;
struct MediaSource;
class MetaData;
@@ -67,6 +70,9 @@
}
virtual void setUID(uid_t /*uid*/) {
}
+ virtual status_t setMediaCas(const sp<ICas> &cas) override {
+ return INVALID_OPERATION;
+ }
virtual const char * name() { return "<unspecified>"; }
diff --git a/include/media/stagefright/NuMediaExtractor.h b/include/media/stagefright/NuMediaExtractor.h
index ad0d37b..3e3cc17 100644
--- a/include/media/stagefright/NuMediaExtractor.h
+++ b/include/media/stagefright/NuMediaExtractor.h
@@ -28,6 +28,10 @@
#include <utils/Vector.h>
namespace android {
+namespace media {
+class ICas;
+}
+using namespace media;
struct ABuffer;
struct AMessage;
@@ -60,6 +64,8 @@
status_t setDataSource(const sp<DataSource> &datasource);
+ status_t setMediaCas(const sp<ICas> &cas);
+
size_t countTracks() const;
status_t getTrackFormat(size_t index, sp<AMessage> *format, uint32_t flags = 0) const;
@@ -109,6 +115,7 @@
sp<DataSource> mDataSource;
sp<IMediaExtractor> mImpl;
+ sp<ICas> mCas;
Vector<TrackInfo> mSelectedTracks;
int64_t mTotalBitrate; // in bits/sec
diff --git a/media/libmedia/Android.mk b/media/libmedia/Android.mk
index 6c6c369..eac532b 100644
--- a/media/libmedia/Android.mk
+++ b/media/libmedia/Android.mk
@@ -60,10 +60,10 @@
libui liblog libcutils libutils libbinder libsonivox libicuuc libicui18n libexpat \
libcamera_client libstagefright_foundation \
libgui libdl libaudioutils libaudioclient \
- libmedia_helper \
+ libmedia_helper libmediadrm \
libhidlbase \
-LOCAL_EXPORT_SHARED_LIBRARY_HEADERS := libbinder libsonivox
+LOCAL_EXPORT_SHARED_LIBRARY_HEADERS := libbinder libsonivox libmediadrm
# for memory heap analysis
LOCAL_STATIC_LIBRARIES := libc_malloc_debug_backtrace libc_logging
diff --git a/media/libmedia/IMediaExtractor.cpp b/media/libmedia/IMediaExtractor.cpp
index bfc43a6..f08fabb 100644
--- a/media/libmedia/IMediaExtractor.cpp
+++ b/media/libmedia/IMediaExtractor.cpp
@@ -21,6 +21,7 @@
#include <stdint.h>
#include <sys/types.h>
+#include <android/media/ICas.h>
#include <binder/IPCThreadState.h>
#include <binder/Parcel.h>
#include <media/IMediaExtractor.h>
@@ -35,6 +36,7 @@
GETMETADATA,
FLAGS,
GETDRMTRACKINFO,
+ SETMEDIACAS,
SETUID,
NAME,
GETMETRICS
@@ -114,6 +116,21 @@
ALOGV("getDrmTrackInfo NOT IMPLEMENTED");
return NULL;
}
+
+ virtual status_t setMediaCas(const sp<ICas> & cas) {
+ ALOGV("setMediaCas");
+
+ Parcel data, reply;
+ data.writeInterfaceToken(BpMediaExtractor::getInterfaceDescriptor());
+ data.writeStrongBinder(IInterface::asBinder(cas));
+
+ status_t err = remote()->transact(SETMEDIACAS, data, &reply);
+ if (err != NO_ERROR) {
+ return err;
+ }
+ return reply.readInt32();
+ }
+
virtual void setUID(uid_t uid __unused) {
ALOGV("setUID NOT IMPLEMENTED");
}
@@ -185,6 +202,21 @@
status_t ret = getMetrics(reply);
return ret;
}
+ case SETMEDIACAS: {
+ ALOGV("setMediaCas");
+ CHECK_INTERFACE(IMediaExtractor, data, reply);
+
+ sp<IBinder> casBinder;
+ status_t err = data.readNullableStrongBinder(&casBinder);
+ if (err != NO_ERROR) {
+ ALOGE("Error reading cas from parcel");
+ return err;
+ }
+ sp<ICas> cas = interface_cast<ICas>(casBinder);
+
+ reply->writeInt32(setMediaCas(cas));
+ return OK;
+ }
default:
return BBinder::onTransact(code, data, reply, flags);
}
diff --git a/media/libmedia/MediaDefs.cpp b/media/libmedia/MediaDefs.cpp
index 2ae71f7..544a6ae 100644
--- a/media/libmedia/MediaDefs.cpp
+++ b/media/libmedia/MediaDefs.cpp
@@ -29,6 +29,7 @@
const char *MEDIA_MIMETYPE_VIDEO_MPEG2 = "video/mpeg2";
const char *MEDIA_MIMETYPE_VIDEO_RAW = "video/raw";
const char *MEDIA_MIMETYPE_VIDEO_DOLBY_VISION = "video/dolby-vision";
+const char *MEDIA_MIMETYPE_VIDEO_SCRAMBLED = "video/scrambled";
const char *MEDIA_MIMETYPE_AUDIO_AMR_NB = "audio/3gpp";
const char *MEDIA_MIMETYPE_AUDIO_AMR_WB = "audio/amr-wb";
@@ -48,6 +49,7 @@
const char *MEDIA_MIMETYPE_AUDIO_MSGSM = "audio/gsm";
const char *MEDIA_MIMETYPE_AUDIO_AC3 = "audio/ac3";
const char *MEDIA_MIMETYPE_AUDIO_EAC3 = "audio/eac3";
+const char *MEDIA_MIMETYPE_AUDIO_SCRAMBLED = "audio/scrambled";
const char *MEDIA_MIMETYPE_CONTAINER_MPEG4 = "video/mp4";
const char *MEDIA_MIMETYPE_CONTAINER_WAV = "audio/x-wav";
diff --git a/media/libstagefright/Android.mk b/media/libstagefright/Android.mk
index d044754..4300140 100644
--- a/media/libstagefright/Android.mk
+++ b/media/libstagefright/Android.mk
@@ -93,6 +93,7 @@
libui \
libutils \
libvorbisidec \
+ libmediadrm \
LOCAL_STATIC_LIBRARIES := \
libstagefright_color_conversion \
diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp
index 03010ab..6674e2c 100644
--- a/media/libstagefright/MediaCodec.cpp
+++ b/media/libstagefright/MediaCodec.cpp
@@ -23,6 +23,7 @@
#include "include/SharedMemoryBuffer.h"
#include "include/SoftwareRenderer.h"
+#include <android/media/IDescrambler.h>
#include <binder/IMemory.h>
#include <binder/IPCThreadState.h>
#include <binder/IServiceManager.h>
@@ -680,8 +681,17 @@
status_t MediaCodec::configure(
const sp<AMessage> &format,
+ const sp<Surface> &nativeWindow,
+ const sp<ICrypto> &crypto,
+ uint32_t flags) {
+ return configure(format, nativeWindow, crypto, NULL, flags);
+}
+
+status_t MediaCodec::configure(
+ const sp<AMessage> &format,
const sp<Surface> &surface,
const sp<ICrypto> &crypto,
+ const sp<IDescrambler> &descrambler,
uint32_t flags) {
sp<AMessage> msg = new AMessage(kWhatConfigure, this);
@@ -710,8 +720,12 @@
msg->setInt32("flags", flags);
msg->setObject("surface", surface);
- if (crypto != NULL) {
- msg->setPointer("crypto", crypto.get());
+ if (crypto != NULL || descrambler != NULL) {
+ if (crypto != NULL) {
+ msg->setPointer("crypto", crypto.get());
+ } else {
+ msg->setPointer("descrambler", descrambler.get());
+ }
if (mAnalyticsItem != NULL) {
// XXX: save indication that it's crypto in some way...
mAnalyticsItem->setInt32("crypto", 1);
@@ -1992,6 +2006,13 @@
ALOGV("kWhatConfigure: New mCrypto: %p (%d)",
mCrypto.get(), (mCrypto != NULL ? mCrypto->getStrongCount() : 0));
+ void *descrambler;
+ if (!msg->findPointer("descrambler", &descrambler)) {
+ descrambler = NULL;
+ }
+
+ mDescrambler = static_cast<IDescrambler *>(descrambler);
+
uint32_t flags;
CHECK(msg->findInt32("flags", (int32_t *)&flags));
@@ -2592,6 +2613,7 @@
mCrypto.get(), (mCrypto != NULL ? mCrypto->getStrongCount() : 0));
}
mCrypto.clear();
+ mDescrambler.clear();
handleSetSurface(NULL);
mInputFormat.clear();
diff --git a/media/libstagefright/NuMediaExtractor.cpp b/media/libstagefright/NuMediaExtractor.cpp
index 1c1acb0..ea3ed28 100644
--- a/media/libstagefright/NuMediaExtractor.cpp
+++ b/media/libstagefright/NuMediaExtractor.cpp
@@ -35,6 +35,7 @@
#include <media/stagefright/MediaSource.h>
#include <media/stagefright/MetaData.h>
#include <media/stagefright/Utils.h>
+#include <android/media/ICas.h>
namespace android {
@@ -82,6 +83,10 @@
return ERROR_UNSUPPORTED;
}
+ if (mCas != NULL) {
+ mImpl->setMediaCas(mCas);
+ }
+
status_t err = updateDurationAndBitrate();
if (err == OK) {
mDataSource = dataSource;
@@ -114,6 +119,10 @@
return ERROR_UNSUPPORTED;
}
+ if (mCas != NULL) {
+ mImpl->setMediaCas(mCas);
+ }
+
err = updateDurationAndBitrate();
if (err == OK) {
mDataSource = fileSource;
@@ -140,6 +149,10 @@
return ERROR_UNSUPPORTED;
}
+ if (mCas != NULL) {
+ mImpl->setMediaCas(mCas);
+ }
+
err = updateDurationAndBitrate();
if (err == OK) {
mDataSource = source;
@@ -148,6 +161,27 @@
return err;
}
+status_t NuMediaExtractor::setMediaCas(const sp<ICas> &cas) {
+ ALOGV("setMediaCas: cas=%p", cas.get());
+
+ Mutex::Autolock autoLock(mLock);
+
+ if (cas == NULL) {
+ return BAD_VALUE;
+ }
+
+ if (mImpl != NULL) {
+ mImpl->setMediaCas(cas);
+ status_t err = updateDurationAndBitrate();
+ if (err != OK) {
+ return err;
+ }
+ }
+
+ mCas = cas;
+ return OK;
+}
+
status_t NuMediaExtractor::updateDurationAndBitrate() {
if (mImpl->countTracks() > kMaxTrackCount) {
return ERROR_UNSUPPORTED;
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();
}