From f9f0a25b26d93cf86ccb44c046f83b86ce962c3d Mon Sep 17 00:00:00 2001 From: Henry Fang Date: Thu, 17 Jan 2019 17:25:05 -0800 Subject: [PATCH] Update cas@1.0 hal to cas@1.1 Add sendSessionEvent to notify hal what happened on a session. Add onSessionEvent to listen notification from hal for a session Test: manual Bug: 122472761 Change-Id: I98434325915e7bee57e63bdeeedba9ed5578e493 --- cas/1.1/Android.bp | 20 ++ cas/1.1/ICas.hal | 42 ++++ cas/1.1/ICasListener.hal | 33 +++ cas/1.1/IMediaCasService.hal | 38 +++ cas/1.1/default/Android.bp | 49 ++++ cas/1.1/default/CasImpl.cpp | 222 ++++++++++++++++++ cas/1.1/default/CasImpl.h | 98 ++++++++ cas/1.1/default/DescramblerImpl.cpp | 195 +++++++++++++++ cas/1.1/default/DescramblerImpl.h | 67 ++++++ cas/1.1/default/FactoryLoader.h | 217 +++++++++++++++++ cas/1.1/default/MediaCasService.cpp | 126 ++++++++++ cas/1.1/default/MediaCasService.h | 66 ++++++ cas/1.1/default/SharedLibrary.cpp | 65 +++++ cas/1.1/default/SharedLibrary.h | 50 ++++ cas/1.1/default/TypeConvert.cpp | 94 ++++++++ cas/1.1/default/TypeConvert.h | 43 ++++ .../android.hardware.cas@1.1-service-lazy.rc | 9 + .../android.hardware.cas@1.1-service-lazy.xml | 11 + .../android.hardware.cas@1.1-service.rc | 6 + .../android.hardware.cas@1.1-service.xml | 11 + cas/1.1/default/service.cpp | 58 +++++ .../compatibility_matrix.current.xml | 2 +- 22 files changed, 1521 insertions(+), 1 deletion(-) create mode 100644 cas/1.1/Android.bp create mode 100644 cas/1.1/ICas.hal create mode 100644 cas/1.1/ICasListener.hal create mode 100644 cas/1.1/IMediaCasService.hal create mode 100644 cas/1.1/default/Android.bp create mode 100644 cas/1.1/default/CasImpl.cpp create mode 100644 cas/1.1/default/CasImpl.h create mode 100644 cas/1.1/default/DescramblerImpl.cpp create mode 100644 cas/1.1/default/DescramblerImpl.h create mode 100644 cas/1.1/default/FactoryLoader.h create mode 100644 cas/1.1/default/MediaCasService.cpp create mode 100644 cas/1.1/default/MediaCasService.h create mode 100644 cas/1.1/default/SharedLibrary.cpp create mode 100644 cas/1.1/default/SharedLibrary.h create mode 100644 cas/1.1/default/TypeConvert.cpp create mode 100644 cas/1.1/default/TypeConvert.h create mode 100644 cas/1.1/default/android.hardware.cas@1.1-service-lazy.rc create mode 100644 cas/1.1/default/android.hardware.cas@1.1-service-lazy.xml create mode 100644 cas/1.1/default/android.hardware.cas@1.1-service.rc create mode 100644 cas/1.1/default/android.hardware.cas@1.1-service.xml create mode 100644 cas/1.1/default/service.cpp diff --git a/cas/1.1/Android.bp b/cas/1.1/Android.bp new file mode 100644 index 0000000000..bb0edb970c --- /dev/null +++ b/cas/1.1/Android.bp @@ -0,0 +1,20 @@ +// This file is autogenerated by hidl-gen -Landroidbp. + +hidl_interface { + name: "android.hardware.cas@1.1", + root: "android.hardware", + vndk: { + enabled: true, + }, + srcs: [ + "ICas.hal", + "ICasListener.hal", + "IMediaCasService.hal", + ], + interfaces: [ + "android.hardware.cas@1.0", + "android.hidl.base@1.0", + ], + gen_java: true, +} + diff --git a/cas/1.1/ICas.hal b/cas/1.1/ICas.hal new file mode 100644 index 0000000000..027968e565 --- /dev/null +++ b/cas/1.1/ICas.hal @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2019 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. + */ +package android.hardware.cas@1.1; + +import @1.0::HidlCasSessionId; +import @1.0::ICas; +import @1.0::Status; + +/** + * ICas is the API to control the cas system and is accessible from both + * Java and native level. It is used to manage sessions, provision/refresh + * the cas system, and process the EMM/ECM messages. It also allows bi-directional, + * scheme-specific communications between the client and the cas system. + */ + +interface ICas extends @1.0::ICas { + /** + * Send an scheme-specific session event to the CasPlugin. + * + * @param sessionId the id of an opened session. + * @param event an integer denoting a scheme-specific event to be sent. + * @param arg a scheme-specific integer argument for the event. + * @param data a byte array containing scheme-specific data for the event. + * @return status the status of the call. + */ + sendSessionEvent(HidlCasSessionId sessionId, int32_t event, int32_t arg, + vec eventData) + generates (Status status); +}; diff --git a/cas/1.1/ICasListener.hal b/cas/1.1/ICasListener.hal new file mode 100644 index 0000000000..5ec1154a3f --- /dev/null +++ b/cas/1.1/ICasListener.hal @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2019 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. + */ +package android.hardware.cas@1.1; + +import @1.0::ICasListener; +import @1.0::HidlCasSessionId; + +interface ICasListener extends @1.0::ICasListener{ + /** + * Notify the listener of a scheme-specific session event from CA system. + * + * @param sessionId the id of an opened session. + * @param event an integer whose meaning is scheme-specific. + * @param arg an integer whose meaning is scheme-specific. + * @param data a byte array of data whose format and meaning are + * scheme-specific. + */ + onSessionEvent(HidlCasSessionId sessionId, int32_t event, int32_t arg, + vec data); +}; diff --git a/cas/1.1/IMediaCasService.hal b/cas/1.1/IMediaCasService.hal new file mode 100644 index 0000000000..e82b54c9db --- /dev/null +++ b/cas/1.1/IMediaCasService.hal @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2019 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. + */ +package android.hardware.cas@1.1; + +import @1.1::ICas; +import @1.1::ICasListener; +import @1.0::IMediaCasService; + +/** + * IMediaCasService is the main entry point for interacting with a vendor's + * cas HAL to create cas and descrambler plugin instances. A cas plugin instance + * opens cas sessions which are used to obtain keys for a descrambler session, + * which can in turn be used to descramble protected video content. + */ + +interface IMediaCasService extends @1.0::IMediaCasService { + /** + * Construct a new instance of a @1.1 ICAS CasPlugin given a CA_system_id. + * + * @param caSystemId the id of the CA system. + * @param listener the event listener to receive events coming from the CasPlugin. + * @return cas the newly created CasPlugin interface. + */ + createPluginExt(int32_t caSystemId, ICasListener listener) generates (ICas cas); +}; diff --git a/cas/1.1/default/Android.bp b/cas/1.1/default/Android.bp new file mode 100644 index 0000000000..68a49cf5b1 --- /dev/null +++ b/cas/1.1/default/Android.bp @@ -0,0 +1,49 @@ +cc_defaults { + name: "cas_service_defaults@1.1", + defaults: ["hidl_defaults"], + vendor: true, + relative_install_path: "hw", + srcs: [ + "CasImpl.cpp", + "DescramblerImpl.cpp", + "MediaCasService.cpp", + "service.cpp", + "SharedLibrary.cpp", + "TypeConvert.cpp", + ], + + compile_multilib: "32", + + shared_libs: [ + "android.hardware.cas@1.0", + "android.hardware.cas@1.1", + "android.hardware.cas.native@1.0", + "android.hidl.memory@1.0", + "libbinder", + "libhidlbase", + "libhidlmemory", + "libhidltransport", + "liblog", + "libutils", + ], + header_libs: [ + "libstagefright_foundation_headers", + "media_plugin_headers", + ], +} + +cc_binary { + name: "android.hardware.cas@1.1-service", + vintf_fragments: ["android.hardware.cas@1.1-service.xml"], + defaults: ["cas_service_defaults@1.1"], + init_rc: ["android.hardware.cas@1.1-service.rc"], +} + +cc_binary { + name: "android.hardware.cas@1.1-service-lazy", + vintf_fragments: ["android.hardware.cas@1.1-service-lazy.xml"], + overrides: ["android.hardware.cas@1.1-service"], + defaults: ["cas_service_defaults@1.1"], + init_rc: ["android.hardware.cas@1.1-service-lazy.rc"], + cflags: ["-DLAZY_SERVICE"], +} diff --git a/cas/1.1/default/CasImpl.cpp b/cas/1.1/default/CasImpl.cpp new file mode 100644 index 0000000000..4cc6017028 --- /dev/null +++ b/cas/1.1/default/CasImpl.cpp @@ -0,0 +1,222 @@ +/* + * Copyright (C) 2019 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 "android.hardware.cas@1.1-CasImpl" + +#include +#include +#include + +#include "CasImpl.h" +#include "SharedLibrary.h" +#include "TypeConvert.h" + +namespace android { +namespace hardware { +namespace cas { +namespace V1_1 { +namespace implementation { + +CasImpl::CasImpl(const sp& listener) : mListener(listener) { + ALOGV("CTOR"); +} + +CasImpl::~CasImpl() { + ALOGV("DTOR"); + 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(appData); + casImpl->onEvent(event, arg, data, size); +} + +// static +void CasImpl::CallBackExt(void* appData, int32_t event, int32_t arg, uint8_t* data, size_t size, + const CasSessionId* sessionId) { + if (appData == NULL) { + ALOGE("Invalid appData!"); + return; + } + CasImpl* casImpl = static_cast(appData); + casImpl->onEvent(sessionId, event, arg, data, size); +} + +void CasImpl::init(const sp& library, CasPlugin* plugin) { + mLibrary = library; + std::shared_ptr holder(plugin); + std::atomic_store(&mPluginHolder, holder); +} + +void CasImpl::onEvent(int32_t event, int32_t arg, uint8_t* data, size_t size) { + if (mListener == NULL) { + return; + } + + HidlCasData eventData; + if (data != NULL) { + eventData.setToExternal(data, size); + } + + mListener->onEvent(event, arg, eventData); +} + +void CasImpl::onEvent(const CasSessionId* sessionId, int32_t event, int32_t arg, uint8_t* data, + size_t size) { + if (mListener == NULL) { + return; + } + + HidlCasData eventData; + if (data != NULL) { + eventData.setToExternal(data, size); + } + + if (sessionId != NULL) { + mListener->onSessionEvent(*sessionId, event, arg, eventData); + } else { + mListener->onEvent(event, arg, eventData); + } +} + +Return CasImpl::setPrivateData(const HidlCasData& pvtData) { + ALOGV("%s", __FUNCTION__); + std::shared_ptr holder = std::atomic_load(&mPluginHolder); + if (holder.get() == nullptr) { + return toStatus(INVALID_OPERATION); + } + return toStatus(holder->setPrivateData(pvtData)); +} + +Return CasImpl::openSession(openSession_cb _hidl_cb) { + ALOGV("%s", __FUNCTION__); + CasSessionId sessionId; + + std::shared_ptr holder = std::atomic_load(&mPluginHolder); + status_t err = INVALID_OPERATION; + if (holder.get() != nullptr) { + err = holder->openSession(&sessionId); + holder.reset(); + } + + _hidl_cb(toStatus(err), sessionId); + + return Void(); +} + +Return CasImpl::setSessionPrivateData(const HidlCasSessionId& sessionId, + const HidlCasData& pvtData) { + ALOGV("%s: sessionId=%s", __FUNCTION__, sessionIdToString(sessionId).string()); + std::shared_ptr holder = std::atomic_load(&mPluginHolder); + if (holder.get() == nullptr) { + return toStatus(INVALID_OPERATION); + } + return toStatus(holder->setSessionPrivateData(sessionId, pvtData)); +} + +Return CasImpl::closeSession(const HidlCasSessionId& sessionId) { + ALOGV("%s: sessionId=%s", __FUNCTION__, sessionIdToString(sessionId).string()); + std::shared_ptr holder = std::atomic_load(&mPluginHolder); + if (holder.get() == nullptr) { + return toStatus(INVALID_OPERATION); + } + return toStatus(holder->closeSession(sessionId)); +} + +Return CasImpl::processEcm(const HidlCasSessionId& sessionId, const HidlCasData& ecm) { + ALOGV("%s: sessionId=%s", __FUNCTION__, sessionIdToString(sessionId).string()); + std::shared_ptr holder = std::atomic_load(&mPluginHolder); + if (holder.get() == nullptr) { + return toStatus(INVALID_OPERATION); + } + + return toStatus(holder->processEcm(sessionId, ecm)); +} + +Return CasImpl::processEmm(const HidlCasData& emm) { + ALOGV("%s", __FUNCTION__); + std::shared_ptr holder = std::atomic_load(&mPluginHolder); + if (holder.get() == nullptr) { + return toStatus(INVALID_OPERATION); + } + + return toStatus(holder->processEmm(emm)); +} + +Return CasImpl::sendEvent(int32_t event, int32_t arg, const HidlCasData& eventData) { + ALOGV("%s", __FUNCTION__); + std::shared_ptr holder = std::atomic_load(&mPluginHolder); + if (holder.get() == nullptr) { + return toStatus(INVALID_OPERATION); + } + + status_t err = holder->sendEvent(event, arg, eventData); + return toStatus(err); +} + +Return CasImpl::sendSessionEvent(const HidlCasSessionId& sessionId, int32_t event, + int32_t arg, const HidlCasData& eventData) { + ALOGV("%s", __FUNCTION__); + std::shared_ptr holder = std::atomic_load(&mPluginHolder); + if (holder.get() == nullptr) { + return toStatus(INVALID_OPERATION); + } + + status_t err = holder->sendSessionEvent(sessionId, event, arg, eventData); + return toStatus(err); +} + +Return CasImpl::provision(const hidl_string& provisionString) { + ALOGV("%s: provisionString=%s", __FUNCTION__, provisionString.c_str()); + std::shared_ptr holder = std::atomic_load(&mPluginHolder); + if (holder.get() == nullptr) { + return toStatus(INVALID_OPERATION); + } + + return toStatus(holder->provision(String8(provisionString.c_str()))); +} + +Return CasImpl::refreshEntitlements(int32_t refreshType, const HidlCasData& refreshData) { + ALOGV("%s", __FUNCTION__); + std::shared_ptr holder = std::atomic_load(&mPluginHolder); + if (holder.get() == nullptr) { + return toStatus(INVALID_OPERATION); + } + + status_t err = holder->refreshEntitlements(refreshType, refreshData); + return toStatus(err); +} + +Return CasImpl::release() { + ALOGV("%s: plugin=%p", __FUNCTION__, mPluginHolder.get()); + + std::shared_ptr holder(nullptr); + std::atomic_store(&mPluginHolder, holder); + + return Status::OK; +} + +} // namespace implementation +} // namespace V1_1 +} // namespace cas +} // namespace hardware +} // namespace android diff --git a/cas/1.1/default/CasImpl.h b/cas/1.1/default/CasImpl.h new file mode 100644 index 0000000000..18aee9e457 --- /dev/null +++ b/cas/1.1/default/CasImpl.h @@ -0,0 +1,98 @@ +/* + * Copyright (C) 2019 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 ANDROID_HARDWARE_CAS_V1_1_CAS_IMPL_H_ +#define ANDROID_HARDWARE_CAS_V1_1_CAS_IMPL_H_ + +#include +#include + +namespace android { +struct CasPlugin; + +namespace hardware { +namespace cas { +namespace V1_1 { +struct ICasListener; +namespace implementation { + +using ::android::hardware::cas::V1_0::HidlCasData; +using ::android::hardware::cas::V1_0::HidlCasSessionId; +using ::android::hardware::cas::V1_0::Status; + +class SharedLibrary; + +class CasImpl : public ICas { + public: + CasImpl(const sp& listener); + virtual ~CasImpl(); + + static void OnEvent(void* appData, int32_t event, int32_t arg, uint8_t* data, size_t size); + + static void CallBackExt(void* appData, int32_t event, int32_t arg, uint8_t* data, size_t size, + const CasSessionId* sessionId); + + void init(const sp& library, CasPlugin* plugin); + void onEvent(int32_t event, int32_t arg, uint8_t* data, size_t size); + + void onEvent(const CasSessionId* sessionId, int32_t event, int32_t arg, uint8_t* data, + size_t size); + + // ICas inherits + + virtual Return setPrivateData(const HidlCasData& pvtData) override; + + virtual Return openSession(openSession_cb _hidl_cb) override; + + virtual Return closeSession(const HidlCasSessionId& sessionId) override; + + virtual Return setSessionPrivateData(const HidlCasSessionId& sessionId, + const HidlCasData& pvtData) override; + + virtual Return processEcm(const HidlCasSessionId& sessionId, + const HidlCasData& ecm) override; + + virtual Return processEmm(const HidlCasData& emm) override; + + virtual Return sendEvent(int32_t event, int32_t arg, + const HidlCasData& eventData) override; + + virtual Return sendSessionEvent(const HidlCasSessionId& sessionId, int32_t event, + int32_t arg, const HidlCasData& eventData) override; + + virtual Return provision(const hidl_string& provisionString) override; + + virtual Return refreshEntitlements(int32_t refreshType, + const HidlCasData& refreshData) override; + + virtual Return release() override; + + private: + struct PluginHolder; + sp mLibrary; + std::shared_ptr mPluginHolder; + sp mListener; + + DISALLOW_EVIL_CONSTRUCTORS(CasImpl); +}; + +} // namespace implementation +} // namespace V1_1 +} // namespace cas +} // namespace hardware +} // namespace android + +#endif // ANDROID_HARDWARE_CAS_V1_1_CAS_IMPL_H_ diff --git a/cas/1.1/default/DescramblerImpl.cpp b/cas/1.1/default/DescramblerImpl.cpp new file mode 100644 index 0000000000..36dc1a51d0 --- /dev/null +++ b/cas/1.1/default/DescramblerImpl.cpp @@ -0,0 +1,195 @@ +/* + * Copyright (C) 2019 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 "android.hardware.cas@1.1-DescramblerImpl" + +#include +#include +#include +#include +#include + +#include "DescramblerImpl.h" +#include "SharedLibrary.h" +#include "TypeConvert.h" + +namespace android { +using hidl::memory::V1_0::IMemory; + +namespace hardware { +namespace cas { +namespace V1_1 { +namespace implementation { + +#define CHECK_SUBSAMPLE_DEF(type) \ + static_assert(sizeof(SubSample) == sizeof(type::SubSample), "SubSample: size doesn't match"); \ + static_assert(offsetof(SubSample, numBytesOfClearData) == \ + offsetof(type::SubSample, mNumBytesOfClearData), \ + "SubSample: numBytesOfClearData offset doesn't match"); \ + static_assert(offsetof(SubSample, numBytesOfEncryptedData) == \ + offsetof(type::SubSample, mNumBytesOfEncryptedData), \ + "SubSample: numBytesOfEncryptedData offset doesn't match") + +CHECK_SUBSAMPLE_DEF(DescramblerPlugin); +CHECK_SUBSAMPLE_DEF(CryptoPlugin); + +DescramblerImpl::DescramblerImpl(const sp& library, DescramblerPlugin* plugin) + : mLibrary(library), mPluginHolder(plugin) { + ALOGV("CTOR: plugin=%p", mPluginHolder.get()); +} + +DescramblerImpl::~DescramblerImpl() { + ALOGV("DTOR: plugin=%p", mPluginHolder.get()); + release(); +} + +Return DescramblerImpl::setMediaCasSession(const HidlCasSessionId& sessionId) { + ALOGV("%s: sessionId=%s", __FUNCTION__, sessionIdToString(sessionId).string()); + + std::shared_ptr holder = std::atomic_load(&mPluginHolder); + if (holder.get() == nullptr) { + return toStatus(INVALID_OPERATION); + } + + return toStatus(holder->setMediaCasSession(sessionId)); +} + +Return DescramblerImpl::requiresSecureDecoderComponent(const hidl_string& mime) { + std::shared_ptr holder = std::atomic_load(&mPluginHolder); + if (holder.get() == nullptr) { + return false; + } + + return holder->requiresSecureDecoderComponent(String8(mime.c_str())); +} + +static inline bool validateRangeForSize(uint64_t offset, uint64_t length, uint64_t size) { + return isInRange(0, size, offset, length); +} + +Return DescramblerImpl::descramble(ScramblingControl scramblingControl, + const hidl_vec& subSamples, + const SharedBuffer& srcBuffer, uint64_t srcOffset, + const DestinationBuffer& dstBuffer, uint64_t dstOffset, + descramble_cb _hidl_cb) { + ALOGV("%s", __FUNCTION__); + + // hidl_memory's size is stored in uint64_t, but mapMemory's mmap will map + // size in size_t. If size is over SIZE_MAX, mapMemory mapMemory could succeed + // but the mapped memory's actual size will be smaller than the reported size. + if (srcBuffer.heapBase.size() > SIZE_MAX) { + ALOGE("Invalid hidl_memory size: %llu", srcBuffer.heapBase.size()); + android_errorWriteLog(0x534e4554, "79376389"); + _hidl_cb(toStatus(BAD_VALUE), 0, NULL); + return Void(); + } + + sp srcMem = mapMemory(srcBuffer.heapBase); + + // Validate if the offset and size in the SharedBuffer is consistent with the + // mapped ashmem, since the offset and size is controlled by client. + if (srcMem == NULL) { + ALOGE("Failed to map src buffer."); + _hidl_cb(toStatus(BAD_VALUE), 0, NULL); + return Void(); + } + if (!validateRangeForSize(srcBuffer.offset, srcBuffer.size, (uint64_t)srcMem->getSize())) { + ALOGE("Invalid src buffer range: offset %llu, size %llu, srcMem size %llu", + srcBuffer.offset, srcBuffer.size, (uint64_t)srcMem->getSize()); + android_errorWriteLog(0x534e4554, "67962232"); + _hidl_cb(toStatus(BAD_VALUE), 0, NULL); + return Void(); + } + + // use 64-bit here to catch bad subsample size that might be overflowing. + uint64_t totalBytesInSubSamples = 0; + for (size_t i = 0; i < subSamples.size(); i++) { + totalBytesInSubSamples += + (uint64_t)subSamples[i].numBytesOfClearData + subSamples[i].numBytesOfEncryptedData; + } + // Further validate if the specified srcOffset and requested total subsample size + // is consistent with the source shared buffer size. + if (!validateRangeForSize(srcOffset, totalBytesInSubSamples, srcBuffer.size)) { + ALOGE("Invalid srcOffset and subsample size: " + "srcOffset %llu, totalBytesInSubSamples %llu, srcBuffer size %llu", + srcOffset, totalBytesInSubSamples, srcBuffer.size); + android_errorWriteLog(0x534e4554, "67962232"); + _hidl_cb(toStatus(BAD_VALUE), 0, NULL); + return Void(); + } + + void* srcPtr = (uint8_t*)(void*)srcMem->getPointer() + srcBuffer.offset; + void* dstPtr = NULL; + if (dstBuffer.type == BufferType::SHARED_MEMORY) { + // When using shared memory, src buffer is also used as dst, + // we don't map it again here. + dstPtr = srcPtr; + + // In this case the dst and src would be the same buffer, need to validate + // dstOffset against the buffer size too. + if (!validateRangeForSize(dstOffset, totalBytesInSubSamples, srcBuffer.size)) { + ALOGE("Invalid dstOffset and subsample size: " + "dstOffset %llu, totalBytesInSubSamples %llu, srcBuffer size %llu", + dstOffset, totalBytesInSubSamples, srcBuffer.size); + android_errorWriteLog(0x534e4554, "67962232"); + _hidl_cb(toStatus(BAD_VALUE), 0, NULL); + return Void(); + } + } else { + native_handle_t* handle = + const_cast(dstBuffer.secureMemory.getNativeHandle()); + dstPtr = static_cast(handle); + } + + // Get a local copy of the shared_ptr for the plugin. Note that before + // calling the HIDL callback, this shared_ptr must be manually reset, + // since the client side could proceed as soon as the callback is called + // without waiting for this method to go out of scope. + std::shared_ptr holder = std::atomic_load(&mPluginHolder); + if (holder.get() == nullptr) { + _hidl_cb(toStatus(INVALID_OPERATION), 0, NULL); + return Void(); + } + + // Casting hidl SubSample to DescramblerPlugin::SubSample, but need + // to ensure structs are actually idential + + int32_t result = + holder->descramble(dstBuffer.type != BufferType::SHARED_MEMORY, + (DescramblerPlugin::ScramblingControl)scramblingControl, + subSamples.size(), (DescramblerPlugin::SubSample*)subSamples.data(), + srcPtr, srcOffset, dstPtr, dstOffset, NULL); + + holder.reset(); + _hidl_cb(toStatus(result >= 0 ? OK : result), result, NULL); + return Void(); +} + +Return DescramblerImpl::release() { + ALOGV("%s: plugin=%p", __FUNCTION__, mPluginHolder.get()); + + std::shared_ptr holder(nullptr); + std::atomic_store(&mPluginHolder, holder); + + return Status::OK; +} + +} // namespace implementation +} // namespace V1_1 +} // namespace cas +} // namespace hardware +} // namespace android diff --git a/cas/1.1/default/DescramblerImpl.h b/cas/1.1/default/DescramblerImpl.h new file mode 100644 index 0000000000..a1f66ae464 --- /dev/null +++ b/cas/1.1/default/DescramblerImpl.h @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2019 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 ANDROID_HARDWARE_CAS_V1_1_DESCRAMBLER_IMPL_H_ +#define ANDROID_HARDWARE_CAS_V1_1_DESCRAMBLER_IMPL_H_ + +#include +#include + +namespace android { +struct DescramblerPlugin; +using namespace hardware::cas::native::V1_0; + +namespace hardware { +namespace cas { +namespace V1_1 { +namespace implementation { + +using ::android::hardware::cas::V1_0::HidlCasSessionId; +using ::android::hardware::cas::V1_0::Status; + +class SharedLibrary; + +class DescramblerImpl : public IDescrambler { + public: + DescramblerImpl(const sp& library, DescramblerPlugin* plugin); + virtual ~DescramblerImpl(); + + virtual Return setMediaCasSession(const HidlCasSessionId& sessionId) override; + + virtual Return requiresSecureDecoderComponent(const hidl_string& mime) override; + + virtual Return descramble(ScramblingControl scramblingControl, + const hidl_vec& subSamples, + const SharedBuffer& srcBuffer, uint64_t srcOffset, + const DestinationBuffer& dstBuffer, uint64_t dstOffset, + descramble_cb _hidl_cb) override; + + virtual Return release() override; + + private: + sp mLibrary; + std::shared_ptr mPluginHolder; + + DISALLOW_EVIL_CONSTRUCTORS(DescramblerImpl); +}; + +} // namespace implementation +} // namespace V1_1 +} // namespace cas +} // namespace hardware +} // namespace android + +#endif // ANDROID_HARDWARE_CAS_V1_1_DESCRAMBLER_IMPL_H_ diff --git a/cas/1.1/default/FactoryLoader.h b/cas/1.1/default/FactoryLoader.h new file mode 100644 index 0000000000..c4a48e2852 --- /dev/null +++ b/cas/1.1/default/FactoryLoader.h @@ -0,0 +1,217 @@ +/* + * Copyright (C) 2019 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 ANDROID_HARDWARE_CAS_V1_1_FACTORY_LOADER_H_ +#define ANDROID_HARDWARE_CAS_V1_1_FACTORY_LOADER_H_ + +#include +#include +#include +#include +#include +#include "SharedLibrary.h" + +using namespace std; + +namespace android { +namespace hardware { +namespace cas { +namespace V1_1 { +namespace implementation { + +using ::android::hardware::cas::V1_0::HidlCasPluginDescriptor; + +template +class FactoryLoader { + public: + FactoryLoader(const char* name) : mFactory(NULL), mCreateFactoryFuncName(name) {} + + virtual ~FactoryLoader() { closeFactory(); } + + bool findFactoryForScheme(int32_t CA_system_id, sp* library = NULL, + T** factory = NULL); + + bool enumeratePlugins(vector* results); + + private: + typedef T* (*CreateFactoryFunc)(); + + Mutex mMapLock; + T* mFactory; + const char* mCreateFactoryFuncName; + sp mLibrary; + KeyedVector mCASystemIdToLibraryPathMap; + KeyedVector > mLibraryPathToOpenLibraryMap; + + bool loadFactoryForSchemeFromPath(const String8& path, int32_t CA_system_id, + sp* library, T** factory); + + bool queryPluginsFromPath(const String8& path, vector* results); + + bool openFactory(const String8& path); + void closeFactory(); +}; + +template +bool FactoryLoader::findFactoryForScheme(int32_t CA_system_id, sp* 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 +bool FactoryLoader::enumeratePlugins(vector* 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 +bool FactoryLoader::loadFactoryForSchemeFromPath(const String8& path, int32_t CA_system_id, + sp* 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 +bool FactoryLoader::queryPluginsFromPath(const String8& path, + vector* results) { + closeFactory(); + + vector descriptors; + if (!openFactory(path) || mFactory->queryPlugins(&descriptors) != OK) { + closeFactory(); + return false; + } + + for (auto it = descriptors.begin(); it != descriptors.end(); it++) { + results->push_back( + HidlCasPluginDescriptor{.caSystemId = it->CA_system_id, .name = it->name.c_str()}); + } + return true; +} + +template +bool FactoryLoader::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 +void FactoryLoader::closeFactory() { + delete mFactory; + mFactory = NULL; + mLibrary.clear(); +} + +} // namespace implementation +} // namespace V1_1 +} // namespace cas +} // namespace hardware +} // namespace android + +#endif // ANDROID_HARDWARE_CAS_V1_1_FACTORY_LOADER_H_ diff --git a/cas/1.1/default/MediaCasService.cpp b/cas/1.1/default/MediaCasService.cpp new file mode 100644 index 0000000000..e2d3357023 --- /dev/null +++ b/cas/1.1/default/MediaCasService.cpp @@ -0,0 +1,126 @@ +/* + * Copyright (C) 2019 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 "android.hardware.cas@1.1-MediaCasService" + +#include +#include +#include +#include + +#include "CasImpl.h" +#include "DescramblerImpl.h" +#include "MediaCasService.h" + +namespace android { +namespace hardware { +namespace cas { +namespace V1_1 { +namespace implementation { + +MediaCasService::MediaCasService() + : mCasLoader("createCasFactory"), mDescramblerLoader("createDescramblerFactory") {} + +MediaCasService::~MediaCasService() {} + +Return MediaCasService::enumeratePlugins(enumeratePlugins_cb _hidl_cb) { + ALOGV("%s", __FUNCTION__); + + vector results; + mCasLoader.enumeratePlugins(&results); + + _hidl_cb(results); + return Void(); +} + +Return MediaCasService::isSystemIdSupported(int32_t CA_system_id) { + ALOGV("isSystemIdSupported: CA_system_id=%d", CA_system_id); + + return mCasLoader.findFactoryForScheme(CA_system_id); +} + +Return> MediaCasService::createPlugin(int32_t /* CA_system_id */, + const sp& /* listener */) { + ALOGE("%s:Use createPluginExt to create plugin with cas@1.1", __FUNCTION__); + + sp result; + /* + CasFactory *factory; + sp library; + if (mCasLoader.findFactoryForScheme(CA_system_id, &library, &factory)) { + CasPlugin *plugin = NULL; + sp casImpl = new CasImpl(listener); + if (factory->createPlugin(CA_system_id, casImpl.get(), + CasImpl::OnEvent, &plugin) == OK && plugin != NULL) { + casImpl->init(library, plugin); + result = casImpl; + } + } + */ + return result; +} + +Return> MediaCasService::createPluginExt(int32_t CA_system_id, + const sp& listener) { + ALOGV("%s: CA_system_id=%d", __FUNCTION__, CA_system_id); + + sp result; + + CasFactory* factory; + sp library; + if (mCasLoader.findFactoryForScheme(CA_system_id, &library, &factory)) { + CasPlugin* plugin = NULL; + sp casImpl = new CasImpl(listener); + if (factory->createPlugin(CA_system_id, casImpl.get(), &CasImpl::CallBackExt, &plugin) == + OK && + plugin != NULL) { + casImpl->init(library, plugin); + result = casImpl; + } + } + + return result; +} + +Return MediaCasService::isDescramblerSupported(int32_t CA_system_id) { + ALOGV("%s: CA_system_id=%d", __FUNCTION__, CA_system_id); + + return mDescramblerLoader.findFactoryForScheme(CA_system_id); +} + +Return> MediaCasService::createDescrambler(int32_t CA_system_id) { + ALOGV("%s: CA_system_id=%d", __FUNCTION__, CA_system_id); + + sp result; + + DescramblerFactory* factory; + sp 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 result; +} + +} // namespace implementation +} // namespace V1_1 +} // namespace cas +} // namespace hardware +} // namespace android diff --git a/cas/1.1/default/MediaCasService.h b/cas/1.1/default/MediaCasService.h new file mode 100644 index 0000000000..ec5a86d9b3 --- /dev/null +++ b/cas/1.1/default/MediaCasService.h @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2019 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 ANDROID_HARDWARE_CAS_V1_1_MEDIA_CAS_SERVICE_H_ +#define ANDROID_HARDWARE_CAS_V1_1_MEDIA_CAS_SERVICE_H_ + +#include + +#include "FactoryLoader.h" + +namespace android { +struct CasFactory; +struct DescramblerFactory; +namespace hardware { +namespace cas { +namespace V1_1 { +namespace implementation { + +using ::android::hardware::cas::V1_0::HidlCasPluginDescriptor; +using ::android::hardware::cas::V1_0::IDescramblerBase; + +class MediaCasService : public IMediaCasService { + public: + MediaCasService(); + + virtual Return enumeratePlugins(enumeratePlugins_cb _hidl_cb) override; + + virtual Return isSystemIdSupported(int32_t CA_system_id) override; + + virtual Return> createPlugin(int32_t CA_system_id, + const sp& listener) override; + + virtual Return> createPluginExt(int32_t CA_system_id, + const sp& listener) override; + + virtual Return isDescramblerSupported(int32_t CA_system_id) override; + + virtual Return> createDescrambler(int32_t CA_system_id) override; + + private: + FactoryLoader mCasLoader; + FactoryLoader mDescramblerLoader; + + virtual ~MediaCasService(); +}; + +} // namespace implementation +} // namespace V1_1 +} // namespace cas +} // namespace hardware +} // namespace android + +#endif // ANDROID_HARDWARE_CAS_V1_1_MEDIA_CAS_SERVICE_H_ diff --git a/cas/1.1/default/SharedLibrary.cpp b/cas/1.1/default/SharedLibrary.cpp new file mode 100644 index 0000000000..ffe4bb977a --- /dev/null +++ b/cas/1.1/default/SharedLibrary.cpp @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2019 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 "android.hardware.cas@1.1-SharedLibrary" + +#include "SharedLibrary.h" +#include +#include +#include + +namespace android { +namespace hardware { +namespace cas { +namespace V1_1 { +namespace implementation { + +SharedLibrary::SharedLibrary(const String8& path) { + mLibHandle = dlopen(path.string(), RTLD_NOW); +} + +SharedLibrary::~SharedLibrary() { + if (mLibHandle != NULL) { + dlclose(mLibHandle); + mLibHandle = NULL; + } +} + +bool SharedLibrary::operator!() const { + return mLibHandle == NULL; +} + +void* SharedLibrary::lookup(const char* symbol) const { + 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); +} + +const char* SharedLibrary::lastError() const { + const char* error = dlerror(); + return error ? error : "No errors or unknown error"; +} + +} // namespace implementation +} // namespace V1_1 +} // namespace cas +} // namespace hardware +} // namespace android diff --git a/cas/1.1/default/SharedLibrary.h b/cas/1.1/default/SharedLibrary.h new file mode 100644 index 0000000000..f4d2ff6b9d --- /dev/null +++ b/cas/1.1/default/SharedLibrary.h @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2019 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 ANDROID_HARDWARE_CAS_V1_1_SHARED_LIBRARY_H_ +#define ANDROID_HARDWARE_CAS_V1_1_SHARED_LIBRARY_H_ + +#include +#include +#include + +namespace android { +namespace hardware { +namespace cas { +namespace V1_1 { +namespace implementation { + +class SharedLibrary : public RefBase { + public: + explicit SharedLibrary(const String8& path); + ~SharedLibrary(); + + bool operator!() const; + void* lookup(const char* symbol) const; + const char* lastError() const; + + private: + void* mLibHandle; + DISALLOW_EVIL_CONSTRUCTORS(SharedLibrary); +}; + +} // namespace implementation +} // namespace V1_1 +} // namespace cas +} // namespace hardware +} // namespace android + +#endif // ANDROID_HARDWARE_CAS_V1_1_SHARED_LIBRARY_H_ diff --git a/cas/1.1/default/TypeConvert.cpp b/cas/1.1/default/TypeConvert.cpp new file mode 100644 index 0000000000..09ef41ae8f --- /dev/null +++ b/cas/1.1/default/TypeConvert.cpp @@ -0,0 +1,94 @@ +/* + * Copyright (C) 2019 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 "android.hardware.cas@1.1-TypeConvert" + +#include "TypeConvert.h" +#include + +namespace android { +namespace hardware { +namespace cas { +namespace V1_1 { +namespace implementation { + +Status toStatus(status_t legacyStatus) { + Status status; + switch (legacyStatus) { + case android::OK: + status = Status::OK; + break; + case android::ERROR_CAS_NO_LICENSE: + status = Status::ERROR_CAS_NO_LICENSE; + break; + case android::ERROR_CAS_LICENSE_EXPIRED: + status = Status::ERROR_CAS_LICENSE_EXPIRED; + break; + case android::ERROR_CAS_SESSION_NOT_OPENED: + status = Status::ERROR_CAS_SESSION_NOT_OPENED; + break; + case android::ERROR_CAS_CANNOT_HANDLE: + status = Status::ERROR_CAS_CANNOT_HANDLE; + break; + case android::ERROR_CAS_TAMPER_DETECTED: + status = Status::ERROR_CAS_INVALID_STATE; + break; + case android::BAD_VALUE: + status = Status::BAD_VALUE; + break; + case android::ERROR_CAS_NOT_PROVISIONED: + status = Status::ERROR_CAS_NOT_PROVISIONED; + break; + case android::ERROR_CAS_RESOURCE_BUSY: + status = Status::ERROR_CAS_RESOURCE_BUSY; + break; + case android::ERROR_CAS_INSUFFICIENT_OUTPUT_PROTECTION: + status = Status::ERROR_CAS_INSUFFICIENT_OUTPUT_PROTECTION; + break; + case android::ERROR_CAS_DEVICE_REVOKED: + status = Status::ERROR_CAS_DEVICE_REVOKED; + break; + case android::ERROR_CAS_DECRYPT_UNIT_NOT_INITIALIZED: + status = Status::ERROR_CAS_DECRYPT_UNIT_NOT_INITIALIZED; + break; + case android::ERROR_CAS_DECRYPT: + status = Status::ERROR_CAS_DECRYPT; + break; + default: + ALOGW("Unable to convert legacy status: %d, defaulting to UNKNOWN", legacyStatus); + status = Status::ERROR_CAS_UNKNOWN; + break; + } + return status; +} + +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; +} + +} // namespace implementation +} // namespace V1_1 +} // namespace cas +} // namespace hardware +} // namespace android diff --git a/cas/1.1/default/TypeConvert.h b/cas/1.1/default/TypeConvert.h new file mode 100644 index 0000000000..c4a0119926 --- /dev/null +++ b/cas/1.1/default/TypeConvert.h @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2019 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 ANDROID_HARDWARE_CAS_V1_1_TYPE_CONVERT_H +#define ANDROID_HARDWARE_CAS_V1_1_TYPE_CONVERT_H + +#include +#include +#include +#include + +namespace android { +namespace hardware { +namespace cas { +namespace V1_1 { +namespace implementation { + +using ::android::hardware::cas::V1_0::Status; + +Status toStatus(status_t legacyStatus); + +String8 sessionIdToString(const CasSessionId& sessionId); + +} // namespace implementation +} // namespace V1_1 +} // namespace cas +} // namespace hardware +} // namespace android + +#endif // ANDROID_HARDWARE_CAS_V1_1_TYPE_CONVERT_H diff --git a/cas/1.1/default/android.hardware.cas@1.1-service-lazy.rc b/cas/1.1/default/android.hardware.cas@1.1-service-lazy.rc new file mode 100644 index 0000000000..9227b6f7e4 --- /dev/null +++ b/cas/1.1/default/android.hardware.cas@1.1-service-lazy.rc @@ -0,0 +1,9 @@ +service vendor.cas-hal-1-1 /vendor/bin/hw/android.hardware.cas@1.1-service-lazy + interface android.hardware.cas@1.1::IMediaCasService default + oneshot + disabled + class hal + user media + group mediadrm drmrpc + ioprio rt 4 + writepid /dev/cpuset/foreground/tasks diff --git a/cas/1.1/default/android.hardware.cas@1.1-service-lazy.xml b/cas/1.1/default/android.hardware.cas@1.1-service-lazy.xml new file mode 100644 index 0000000000..c9f13ba34a --- /dev/null +++ b/cas/1.1/default/android.hardware.cas@1.1-service-lazy.xml @@ -0,0 +1,11 @@ + + + android.hardware.cas + hwbinder + 1.1 + + IMediaCasService + default + + + diff --git a/cas/1.1/default/android.hardware.cas@1.1-service.rc b/cas/1.1/default/android.hardware.cas@1.1-service.rc new file mode 100644 index 0000000000..4081fe1e64 --- /dev/null +++ b/cas/1.1/default/android.hardware.cas@1.1-service.rc @@ -0,0 +1,6 @@ +service vendor.cas-hal-1-1 /vendor/bin/hw/android.hardware.cas@1.1-service + class hal + user media + group mediadrm drmrpc + ioprio rt 4 + writepid /dev/cpuset/foreground/tasks diff --git a/cas/1.1/default/android.hardware.cas@1.1-service.xml b/cas/1.1/default/android.hardware.cas@1.1-service.xml new file mode 100644 index 0000000000..c9f13ba34a --- /dev/null +++ b/cas/1.1/default/android.hardware.cas@1.1-service.xml @@ -0,0 +1,11 @@ + + + android.hardware.cas + hwbinder + 1.1 + + IMediaCasService + default + + + diff --git a/cas/1.1/default/service.cpp b/cas/1.1/default/service.cpp new file mode 100644 index 0000000000..962530370c --- /dev/null +++ b/cas/1.1/default/service.cpp @@ -0,0 +1,58 @@ +/* + * Copyright 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 +#ifdef LAZY_SERVICE +#define LOG_TAG "android.hardware.cas@1.1-service-lazy" +#else +#define LOG_TAG "android.hardware.cas@1.1-service" +#endif + +#include +#include +#include + +#include "MediaCasService.h" + +using android::hardware::configureRpcThreadpool; +using android::hardware::joinRpcThreadpool; +using android::hardware::LazyServiceRegistrar; +using android::hardware::cas::V1_1::IMediaCasService; +using android::hardware::cas::V1_1::implementation::MediaCasService; + +#ifdef LAZY_SERVICE +const bool kLazyService = true; +#else +const bool kLazyService = false; +#endif + +int main() { + configureRpcThreadpool(8, true /* callerWillJoin */); + + // Setup hwbinder service + android::sp service = new MediaCasService(); + android::status_t status; + if (kLazyService) { + auto serviceRegistrar = std::make_shared(); + status = serviceRegistrar->registerService(service); + } else { + status = service->registerAsService(); + } + LOG_ALWAYS_FATAL_IF(status != android::OK, "Error while registering cas service: %d", status); + + joinRpcThreadpool(); + return 0; +} diff --git a/compatibility_matrices/compatibility_matrix.current.xml b/compatibility_matrices/compatibility_matrix.current.xml index 94ffe80aab..89855a0e65 100644 --- a/compatibility_matrices/compatibility_matrix.current.xml +++ b/compatibility_matrices/compatibility_matrix.current.xml @@ -121,7 +121,7 @@ android.hardware.cas - 1.0 + 1.0-1 IMediaCasService default