From: Chong Zhang Date: Tue, 25 Apr 2017 00:18:25 +0000 (-0700) Subject: cas: add CAS hal X-Git-Url: http://git.osdn.net/view?a=commitdiff_plain;h=a4f6751e49cca8cd1b673a3917c38ae0620754fc;p=android-x86%2Fhardware-interfaces.git cas: add CAS hal Add CAS hal definitions and default service implementation. bug: 22804304 Change-Id: I0a89608fe75c5f3c5e6888f9b771305742760707 --- diff --git a/cas/1.0/Android.bp b/cas/1.0/Android.bp new file mode 100644 index 00000000..2251f119 --- /dev/null +++ b/cas/1.0/Android.bp @@ -0,0 +1,84 @@ +// This file is autogenerated by hidl-gen. Do not edit manually. + +filegroup { + name: "android.hardware.cas@1.0_hal", + srcs: [ + "types.hal", + "ICas.hal", + "ICasListener.hal", + "IDescramblerBase.hal", + "IMediaCasService.hal", + ], +} + +genrule { + name: "android.hardware.cas@1.0_genc++", + tools: ["hidl-gen"], + cmd: "$(location hidl-gen) -o $(genDir) -Lc++-sources -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.cas@1.0", + srcs: [ + ":android.hardware.cas@1.0_hal", + ], + out: [ + "android/hardware/cas/1.0/types.cpp", + "android/hardware/cas/1.0/CasAll.cpp", + "android/hardware/cas/1.0/CasListenerAll.cpp", + "android/hardware/cas/1.0/DescramblerBaseAll.cpp", + "android/hardware/cas/1.0/MediaCasServiceAll.cpp", + ], +} + +genrule { + name: "android.hardware.cas@1.0_genc++_headers", + tools: ["hidl-gen"], + cmd: "$(location hidl-gen) -o $(genDir) -Lc++-headers -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.cas@1.0", + srcs: [ + ":android.hardware.cas@1.0_hal", + ], + out: [ + "android/hardware/cas/1.0/types.h", + "android/hardware/cas/1.0/hwtypes.h", + "android/hardware/cas/1.0/ICas.h", + "android/hardware/cas/1.0/IHwCas.h", + "android/hardware/cas/1.0/BnHwCas.h", + "android/hardware/cas/1.0/BpHwCas.h", + "android/hardware/cas/1.0/BsCas.h", + "android/hardware/cas/1.0/ICasListener.h", + "android/hardware/cas/1.0/IHwCasListener.h", + "android/hardware/cas/1.0/BnHwCasListener.h", + "android/hardware/cas/1.0/BpHwCasListener.h", + "android/hardware/cas/1.0/BsCasListener.h", + "android/hardware/cas/1.0/IDescramblerBase.h", + "android/hardware/cas/1.0/IHwDescramblerBase.h", + "android/hardware/cas/1.0/BnHwDescramblerBase.h", + "android/hardware/cas/1.0/BpHwDescramblerBase.h", + "android/hardware/cas/1.0/BsDescramblerBase.h", + "android/hardware/cas/1.0/IMediaCasService.h", + "android/hardware/cas/1.0/IHwMediaCasService.h", + "android/hardware/cas/1.0/BnHwMediaCasService.h", + "android/hardware/cas/1.0/BpHwMediaCasService.h", + "android/hardware/cas/1.0/BsMediaCasService.h", + ], +} + +cc_library_shared { + name: "android.hardware.cas@1.0", + defaults: ["hidl-module-defaults"], + generated_sources: ["android.hardware.cas@1.0_genc++"], + generated_headers: ["android.hardware.cas@1.0_genc++_headers"], + export_generated_headers: ["android.hardware.cas@1.0_genc++_headers"], + vendor_available: true, + shared_libs: [ + "libhidlbase", + "libhidltransport", + "libhwbinder", + "liblog", + "libutils", + "libcutils", + ], + export_shared_lib_headers: [ + "libhidlbase", + "libhidltransport", + "libhwbinder", + "libutils", + ], +} diff --git a/cas/1.0/CasHal.mk b/cas/1.0/CasHal.mk new file mode 100644 index 00000000..3cae6bf4 --- /dev/null +++ b/cas/1.0/CasHal.mk @@ -0,0 +1,192 @@ +# +# 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. + + +######################################################################## +# Included by frameworks/base for MediaCas. Hidl HAL can't be linked as +# Java lib from frameworks because it has dependency on frameworks itself. +# + +intermediates := $(TARGET_OUT_COMMON_GEN)/JAVA_LIBRARIES/android.hardware.cas-V1.0-java_intermediates + +HIDL := $(HOST_OUT_EXECUTABLES)/hidl-gen$(HOST_EXECUTABLE_SUFFIX) +HIDL_PATH := system/libhidl/transport/base/1.0 + +# +# Build types.hal (DebugInfo) +# +GEN := $(intermediates)/android/hidl/base/V1_0/DebugInfo.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(HIDL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hidl:system/libhidl/transport \ + android.hidl.base@1.0::types.DebugInfo + +$(GEN): $(HIDL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build IBase.hal +# +GEN := $(intermediates)/android/hidl/base/V1_0/IBase.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(HIDL_PATH)/IBase.hal +$(GEN): PRIVATE_DEPS += $(HIDL_PATH)/types.hal +$(GEN): $(HIDL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hidl:system/libhidl/transport \ + android.hidl.base@1.0::IBase + +$(GEN): $(HIDL_PATH)/IBase.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +HIDL_PATH := hardware/interfaces/cas/1.0 + +# +# Build types.hal (HidlCasPluginDescriptor) +# +GEN := $(intermediates)/android/hardware/cas/V1_0/HidlCasPluginDescriptor.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(HIDL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.cas@1.0::types.HidlCasPluginDescriptor + +$(GEN): $(HIDL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (Status) +# +GEN := $(intermediates)/android/hardware/cas/V1_0/Status.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(HIDL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.cas@1.0::types.Status + +$(GEN): $(HIDL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build ICas.hal +# +GEN := $(intermediates)/android/hardware/cas/V1_0/ICas.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(HIDL_PATH)/ICas.hal +$(GEN): PRIVATE_DEPS += $(HIDL_PATH)/types.hal +$(GEN): $(HIDL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.cas@1.0::ICas + +$(GEN): $(HIDL_PATH)/ICas.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build ICasListener.hal +# +GEN := $(intermediates)/android/hardware/cas/V1_0/ICasListener.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(HIDL_PATH)/ICasListener.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.cas@1.0::ICasListener + +$(GEN): $(HIDL_PATH)/ICasListener.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build IDescramblerBase.hal +# +GEN := $(intermediates)/android/hardware/cas/V1_0/IDescramblerBase.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(HIDL_PATH)/IDescramblerBase.hal +$(GEN): PRIVATE_DEPS += $(HIDL_PATH)/types.hal +$(GEN): $(HIDL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.cas@1.0::IDescramblerBase + +$(GEN): $(HIDL_PATH)/IDescramblerBase.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build IMediaCasService.hal +# +GEN := $(intermediates)/android/hardware/cas/V1_0/IMediaCasService.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(HIDL_PATH)/IMediaCasService.hal +$(GEN): PRIVATE_DEPS += $(HIDL_PATH)/ICas.hal +$(GEN): $(HIDL_PATH)/ICas.hal +$(GEN): PRIVATE_DEPS += $(HIDL_PATH)/ICasListener.hal +$(GEN): $(HIDL_PATH)/ICasListener.hal +$(GEN): PRIVATE_DEPS += $(HIDL_PATH)/IDescramblerBase.hal +$(GEN): $(HIDL_PATH)/IDescramblerBase.hal +$(GEN): PRIVATE_DEPS += $(HIDL_PATH)/types.hal +$(GEN): $(HIDL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.cas@1.0::IMediaCasService + +$(GEN): $(HIDL_PATH)/IMediaCasService.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + diff --git a/cas/1.0/ICas.hal b/cas/1.0/ICas.hal new file mode 100644 index 00000000..08a92da1 --- /dev/null +++ b/cas/1.0/ICas.hal @@ -0,0 +1,122 @@ +/* + * 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. + */ +package android.hardware.cas@1.0; + +import android.hardware.cas@1.0::types; + +/** + * 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 { + /** + * Provide the CA private data from a CA_descriptor in the conditional + * access table to a CasPlugin. + * + * @param pvtData a byte array containing the private data, the format of + * which is scheme-specific and opaque to the framework. + * @return status the status of the call. + */ + setPrivateData(vec pvtData) generates (Status status); + + /** + * Open a session to descramble one or more streams scrambled by the + * conditional access system. + * + * @return status the status of the call. + * @return sessionId the id of the newly opened session. + */ + openSession() generates(Status status, HidlCasSessionId sessionId); + + /** + * Close a session. + * + * @param sessionId the id of the session to be closed. + * @return status the status of the call. + */ + closeSession(HidlCasSessionId sessionId) generates (Status status); + + /** + * Provide the CA private data from a CA_descriptor in the program map + * table to a session. + * + * @param sessionId the id of the session which the private data applies to. + * @param pvtData a byte array containing the private data, the format of + * which is scheme-specific and opaque to the framework. + * @return status the status of the call. + */ + setSessionPrivateData(HidlCasSessionId sessionId, vec pvtData) + generates (Status status); + + /** + * Process an ECM from the ECM stream for this session’s elementary stream. + * + * @param sessionId the id of the session which the ecm data applies to. + * @param ecm a byte array containing the ecm data. + * @return status the status of the call. + */ + processEcm(HidlCasSessionId sessionId, vec ecm) + generates (Status status); + + /** + * Process an in-band EMM from the EMM stream. + * + * @param emm a byte array containing the emm data. + * @return status the status of the call. + */ + processEmm(vec emm) generates (Status status); + + /** + * Send an scheme-specific event to the CasPlugin. + * + * @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. + */ + sendEvent(int32_t event, int32_t arg, vec eventData) + generates (Status status); + + /** + * Initiate a provisioning operation for a CA system. + * + * @param provisionString string containing information needed for the + * provisioning operation, the format of which is scheme and implementation + * specific. + * @return status the status of the call. + */ + provision(string provisionString) generates (Status status); + + /** + * Notify the CA system to refresh entitlement keys. + * + * @param refreshType the type of the refreshment. + * @param refreshData private data associated with the refreshment. + * @return status the status of the call. + */ + refreshEntitlements(int32_t refreshType, vec refreshData) + generates (Status status); + + /** + * Release the descrambler instance. + * + * @return status the status of the call. + */ + release() generates (Status status); +}; diff --git a/cas/1.0/ICasListener.hal b/cas/1.0/ICasListener.hal new file mode 100644 index 00000000..8ae6014d --- /dev/null +++ b/cas/1.0/ICasListener.hal @@ -0,0 +1,28 @@ +/* + * 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. + */ +package android.hardware.cas@1.0; + +interface ICasListener { + /** + * Notify the listener of a scheme-specific event from the CA system. + * + * @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. + */ + onEvent(int32_t event, int32_t arg, vec data); +}; diff --git a/cas/1.0/IDescramblerBase.hal b/cas/1.0/IDescramblerBase.hal new file mode 100644 index 00000000..a126084b --- /dev/null +++ b/cas/1.0/IDescramblerBase.hal @@ -0,0 +1,49 @@ +/* + * 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. + */ +package android.hardware.cas@1.0; + +import android.hardware.cas@1.0::types; + +/** + * IDescramblerBase is the API to control the descrambler and is accessible + * from both Java and native level. + */ + +interface IDescramblerBase { + /** + * Associate a MediaCas session with this MediaDescrambler instance. + * + * @param sessionId the id of the session to associate with this descrambler instance. + * @return status the status of the call. + */ + setMediaCasSession(HidlCasSessionId sessionId) generates (Status status); + + /** + * Query if the scrambling scheme requires the use of a secure decoder + * to decode data of the given mime type. + * + * @param mime the mime type of the media data. + * @return result whether the descrambler requires a secure decoder. + */ + requiresSecureDecoderComponent(string mime) generates (bool result); + + /** + * Release the descrambler instance. + * + * @return status the status of the call. + */ + release() generates (Status status); +}; diff --git a/cas/1.0/IMediaCasService.hal b/cas/1.0/IMediaCasService.hal new file mode 100644 index 00000000..cfeafad2 --- /dev/null +++ b/cas/1.0/IMediaCasService.hal @@ -0,0 +1,68 @@ +/* + * 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. + */ +package android.hardware.cas@1.0; + +import android.hardware.cas@1.0::ICas; +import android.hardware.cas@1.0::ICasListener; +import android.hardware.cas@1.0::IDescramblerBase; + +/** + * 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 { + /** + * List all available CA systems on the device. + * + * @return descriptors an array of descriptors for the available CA systems. + */ + enumeratePlugins() generates (vec descriptors); + + /** + * Query if a certain CA system is supported on this device. + * + * @param CA_system_id the id of the CA system. + * @return result whether the specified CA system is supported on this device. + */ + isSystemIdSupported(int32_t CA_system_id) generates (bool result); + + /** + * Construct a new instance of a CasPlugin given a CA_system_id. + * + * @param CA_system_id 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. + */ + createPlugin(int32_t CA_system_id, ICasListener listener) generates (ICas cas); + + /** + * Query if the descrambling scheme for a CA system is supported on this device. + * + * @param CA_system_id the id of the CA system. + * @return result whether the specified descrambling scheme is supported on this device. + */ + isDescramblerSupported(int32_t CA_system_id) generates (bool result); + + /** + * Construct a new instance of a DescramblerPlugin given a CA_system_id. + * + * @param CA_system_id the id of the CA system. + * @return descrambler the newly created plugin interface. + */ + createDescrambler(int32_t CA_system_id) generates (IDescramblerBase descrambler); +}; diff --git a/cas/1.0/default/Android.bp b/cas/1.0/default/Android.bp new file mode 100644 index 00000000..953aa372 --- /dev/null +++ b/cas/1.0/default/Android.bp @@ -0,0 +1,35 @@ +cc_binary { + name: "android.hardware.cas@1.0-service", + defaults: ["hidl_defaults"], + vendor: true, + relative_install_path: "hw", + srcs: [ + "CasImpl.cpp", + "DescramblerImpl.cpp", + "MediaCasService.cpp", + "service.cpp", + "SharedLibrary.cpp", + "TypeConvert.cpp", + ], + + product_variables: { + treble: { + cflags: ["-DUSE_VNDBINDER"], + }, + }, + + compile_multilib: "32", + init_rc: ["android.hardware.cas@1.0-service.rc"], + + shared_libs: [ + "android.hardware.cas@1.0", + "android.hardware.cas.native@1.0", + "android.hidl.memory@1.0", + "libbinder", + "libhidlbase", + "libhidlmemory", + "libhidltransport", + "liblog", + "libutils", + ], +} diff --git a/cas/1.0/default/CasImpl.cpp b/cas/1.0/default/CasImpl.cpp new file mode 100644 index 00000000..9d1f4a32 --- /dev/null +++ b/cas/1.0/default/CasImpl.cpp @@ -0,0 +1,205 @@ +/* + * 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 "android.hardware.cas@1.0-CasImpl" + +#include +#include +#include + +#include "CasImpl.h" +#include "SharedLibrary.h" +#include "TypeConvert.h" + +namespace android { +namespace hardware { +namespace cas { +namespace V1_0 { +namespace implementation { + +struct CasImpl::PluginHolder : public RefBase { +public: + explicit PluginHolder(CasPlugin *plugin) : mPlugin(plugin) {} + ~PluginHolder() { if (mPlugin != NULL) delete mPlugin; } + CasPlugin* get() { return mPlugin; } + +private: + CasPlugin *mPlugin; + DISALLOW_EVIL_CONSTRUCTORS(PluginHolder); +}; + +CasImpl::CasImpl(const sp &listener) + : mPluginHolder(NULL), 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); +} + +void CasImpl::init(const sp& library, CasPlugin *plugin) { + mLibrary = library; + mPluginHolder = new PluginHolder(plugin); +} + +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); +} + +Return CasImpl::setPrivateData(const HidlCasData& pvtData) { + ALOGV("%s", __FUNCTION__); + sp holder = mPluginHolder; + if (holder == NULL) { + return toStatus(INVALID_OPERATION); + } + return toStatus(holder->get()->setPrivateData(pvtData)); +} + +Return CasImpl::openSession(openSession_cb _hidl_cb) { + ALOGV("%s", __FUNCTION__); + CasSessionId sessionId; + + sp holder = mPluginHolder; + status_t err = INVALID_OPERATION; + if (holder != NULL) { + err = holder->get()->openSession(&sessionId); + } + + _hidl_cb(toStatus(err), sessionId); + + return Void(); +} + +Return CasImpl::setSessionPrivateData( + const HidlCasSessionId &sessionId, const HidlCasData& pvtData) { + ALOGV("%s: sessionId=%s", __FUNCTION__, + sessionIdToString(sessionId).string()); + sp holder = mPluginHolder; + if (holder == NULL) { + return toStatus(INVALID_OPERATION); + } + return toStatus( + holder->get()->setSessionPrivateData( + sessionId, pvtData)); +} + +Return CasImpl::closeSession(const HidlCasSessionId &sessionId) { + ALOGV("%s: sessionId=%s", __FUNCTION__, + sessionIdToString(sessionId).string()); + sp holder = mPluginHolder; + if (holder == NULL) { + return toStatus(INVALID_OPERATION); + } + return toStatus(holder->get()->closeSession(sessionId)); +} + +Return CasImpl::processEcm( + const HidlCasSessionId &sessionId, const HidlCasData& ecm) { + ALOGV("%s: sessionId=%s", __FUNCTION__, + sessionIdToString(sessionId).string()); + sp holder = mPluginHolder; + if (holder == NULL) { + return toStatus(INVALID_OPERATION); + } + + return toStatus(holder->get()->processEcm(sessionId, ecm)); +} + +Return CasImpl::processEmm(const HidlCasData& emm) { + ALOGV("%s", __FUNCTION__); + sp holder = mPluginHolder; + if (holder == NULL) { + return toStatus(INVALID_OPERATION); + } + + return toStatus(holder->get()->processEmm(emm)); +} + +Return CasImpl::sendEvent( + int32_t event, int32_t arg, + const HidlCasData& eventData) { + ALOGV("%s", __FUNCTION__); + sp holder = mPluginHolder; + if (holder == NULL) { + return toStatus(INVALID_OPERATION); + } + + status_t err = holder->get()->sendEvent(event, arg, eventData); + return toStatus(err); +} + +Return CasImpl::provision(const hidl_string& provisionString) { + ALOGV("%s: provisionString=%s", __FUNCTION__, provisionString.c_str()); + sp holder = mPluginHolder; + if (holder == NULL) { + return toStatus(INVALID_OPERATION); + } + + return toStatus(holder->get()->provision(String8(provisionString.c_str()))); +} + +Return CasImpl::refreshEntitlements( + int32_t refreshType, + const HidlCasData& refreshData) { + ALOGV("%s", __FUNCTION__); + sp holder = mPluginHolder; + if (holder == NULL) { + return toStatus(INVALID_OPERATION); + } + + status_t err = holder->get()->refreshEntitlements(refreshType, refreshData); + return toStatus(err); +} + +Return CasImpl::release() { + ALOGV("%s: plugin=%p", __FUNCTION__, + mPluginHolder != NULL ? mPluginHolder->get() : NULL); + mPluginHolder.clear(); + return Status::OK; +} + +} // namespace implementation +} // namespace V1_0 +} // namespace cas +} // namespace hardware +} // namespace android diff --git a/cas/1.0/default/CasImpl.h b/cas/1.0/default/CasImpl.h new file mode 100644 index 00000000..841d64e0 --- /dev/null +++ b/cas/1.0/default/CasImpl.h @@ -0,0 +1,103 @@ +/* + * 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 ANDROID_HARDWARE_CAS_V1_0_CAS_IMPL_H_ +#define ANDROID_HARDWARE_CAS_V1_0_CAS_IMPL_H_ + +#include +#include + +namespace android { +struct CasPlugin; + +namespace hardware { +namespace cas { +namespace V1_0 { +struct ICasListener; +namespace implementation { + +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); + + void init(const sp& library, CasPlugin *plugin); + void onEvent( + 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 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; + sp mPluginHolder; + sp mListener; + + DISALLOW_EVIL_CONSTRUCTORS(CasImpl); +}; + +} // namespace implementation +} // namespace V1_0 +} // namespace cas +} // namespace hardware +} // namespace android + +#endif // ANDROID_HARDWARE_CAS_V1_0_CAS_IMPL_H_ diff --git a/cas/1.0/default/DescramblerImpl.cpp b/cas/1.0/default/DescramblerImpl.cpp new file mode 100644 index 00000000..3d90809c --- /dev/null +++ b/cas/1.0/default/DescramblerImpl.cpp @@ -0,0 +1,127 @@ +/* + * 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 "android.hardware.cas@1.0-DescramblerImpl" + +#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_0 { +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), mPlugin(plugin) { + ALOGV("CTOR: mPlugin=%p", mPlugin); +} + +DescramblerImpl::~DescramblerImpl() { + ALOGV("DTOR: mPlugin=%p", mPlugin); + release(); +} + +Return DescramblerImpl::setMediaCasSession(const HidlCasSessionId& sessionId) { + ALOGV("%s: sessionId=%s", __FUNCTION__, + sessionIdToString(sessionId).string()); + + return toStatus(mPlugin->setMediaCasSession(sessionId)); +} + +Return DescramblerImpl::requiresSecureDecoderComponent( + const hidl_string& mime) { + return mPlugin->requiresSecureDecoderComponent(String8(mime.c_str())); +} + +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__); + + sp srcMem = mapMemory(srcBuffer.heapBase); + 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; + } else { + native_handle_t *handle = const_cast( + dstBuffer.secureMemory.getNativeHandle()); + dstPtr = static_cast(handle); + } + // Casting hidl SubSample to DescramblerPlugin::SubSample, but need + // to ensure structs are actually idential + + int32_t result = mPlugin->descramble( + dstBuffer.type != BufferType::SHARED_MEMORY, + (DescramblerPlugin::ScramblingControl)scramblingControl, + subSamples.size(), + (DescramblerPlugin::SubSample*)subSamples.data(), + srcPtr, + srcOffset, + dstPtr, + dstOffset, + NULL); + + _hidl_cb(toStatus(result >= 0 ? OK : result), result, NULL); + return Void(); +} + +Return DescramblerImpl::release() { + ALOGV("%s: mPlugin=%p", __FUNCTION__, mPlugin); + + if (mPlugin != NULL) { + delete mPlugin; + mPlugin = NULL; + } + return Status::OK; +} + +} // namespace implementation +} // namespace V1_0 +} // namespace cas +} // namespace hardware +} // namespace android diff --git a/cas/1.0/default/DescramblerImpl.h b/cas/1.0/default/DescramblerImpl.h new file mode 100644 index 00000000..d3b146ec --- /dev/null +++ b/cas/1.0/default/DescramblerImpl.h @@ -0,0 +1,69 @@ +/* + * 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 ANDROID_HARDWARE_CAS_V1_0_DESCRAMBLER_IMPL_H_ +#define ANDROID_HARDWARE_CAS_V1_0_DESCRAMBLER_IMPL_H_ + +#include +#include + +namespace android { +struct DescramblerPlugin; +using namespace hardware::cas::native::V1_0; + +namespace hardware { +namespace cas { +namespace V1_0 { +namespace implementation { + +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; + DescramblerPlugin *mPlugin; + + DISALLOW_EVIL_CONSTRUCTORS(DescramblerImpl); +}; + +} // namespace implementation +} // namespace V1_0 +} // namespace cas +} // namespace hardware +} // namespace android + +#endif // ANDROID_HARDWARE_CAS_V1_0_DESCRAMBLER_IMPL_H_ diff --git a/cas/1.0/default/FactoryLoader.h b/cas/1.0/default/FactoryLoader.h new file mode 100644 index 00000000..18c2186d --- /dev/null +++ b/cas/1.0/default/FactoryLoader.h @@ -0,0 +1,229 @@ +/* + * 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 ANDROID_HARDWARE_CAS_V1_0_FACTORY_LOADER_H_ +#define ANDROID_HARDWARE_CAS_V1_0_FACTORY_LOADER_H_ + +#include +#include +#include "SharedLibrary.h" +#include +#include +#include + +using namespace std; + +namespace android { +namespace hardware { +namespace cas { +namespace V1_0 { +namespace implementation { + +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_0 +} // namespace cas +} // namespace hardware +} // namespace android + +#endif // ANDROID_HARDWARE_CAS_V1_0_FACTORY_LOADER_H_ diff --git a/cas/1.0/default/MediaCasService.cpp b/cas/1.0/default/MediaCasService.cpp new file mode 100644 index 00000000..ca432246 --- /dev/null +++ b/cas/1.0/default/MediaCasService.cpp @@ -0,0 +1,112 @@ +/* + * 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 "android.hardware.cas@1.0-MediaCasService" + +#include +#include +#include +#include + +#include "CasImpl.h" +#include "DescramblerImpl.h" +#include "MediaCasService.h" + +namespace android { +namespace hardware { +namespace cas { +namespace V1_0 { +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) { + + 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, (uint64_t)casImpl.get(), + &CasImpl::OnEvent, &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_0 +} // namespace cas +} // namespace hardware +} // namespace android diff --git a/cas/1.0/default/MediaCasService.h b/cas/1.0/default/MediaCasService.h new file mode 100644 index 00000000..77ddac60 --- /dev/null +++ b/cas/1.0/default/MediaCasService.h @@ -0,0 +1,64 @@ +/* + * 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 ANDROID_HARDWARE_CAS_V1_0_MEDIA_CAS_SERVICE_H_ +#define ANDROID_HARDWARE_CAS_V1_0_MEDIA_CAS_SERVICE_H_ + +#include + +#include "FactoryLoader.h" + +namespace android { +struct CasFactory; +struct DescramblerFactory; +namespace hardware { +namespace cas { +namespace V1_0 { +namespace implementation { + +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 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_0 +} // namespace cas +} // namespace hardware +} // namespace android + +#endif // ANDROID_HARDWARE_CAS_V1_0_MEDIA_CAS_SERVICE_H_ diff --git a/cas/1.0/default/SharedLibrary.cpp b/cas/1.0/default/SharedLibrary.cpp new file mode 100644 index 00000000..9c7f3855 --- /dev/null +++ b/cas/1.0/default/SharedLibrary.cpp @@ -0,0 +1,65 @@ +/* + * 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 "android.hardware.cas@1.0-SharedLibrary" + +#include +#include +#include "SharedLibrary.h" +#include + +namespace android { +namespace hardware { +namespace cas { +namespace V1_0 { +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_0 +} // namespace cas +} // namespace hardware +} // namespace android diff --git a/cas/1.0/default/SharedLibrary.h b/cas/1.0/default/SharedLibrary.h new file mode 100644 index 00000000..18130a54 --- /dev/null +++ b/cas/1.0/default/SharedLibrary.h @@ -0,0 +1,50 @@ +/* + * 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 ANDROID_HARDWARE_CAS_V1_0_SHARED_LIBRARY_H_ +#define ANDROID_HARDWARE_CAS_V1_0_SHARED_LIBRARY_H_ + +#include +#include +#include + +namespace android { +namespace hardware { +namespace cas { +namespace V1_0 { +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_0 +} // namespace cas +} // namespace hardware +} // namespace android + +#endif // ANDROID_HARDWARE_CAS_V1_0_SHARED_LIBRARY_H_ diff --git a/cas/1.0/default/TypeConvert.cpp b/cas/1.0/default/TypeConvert.cpp new file mode 100644 index 00000000..de1f92bc --- /dev/null +++ b/cas/1.0/default/TypeConvert.cpp @@ -0,0 +1,92 @@ +/* + * 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 "android.hardware.cas@1.0-TypeConvert" + +#include +#include "TypeConvert.h" + +namespace android { +namespace hardware { +namespace cas { +namespace V1_0 { +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: + 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_0 +} // namespace cas +} // namespace hardware +} // namespace android diff --git a/cas/1.0/default/TypeConvert.h b/cas/1.0/default/TypeConvert.h new file mode 100644 index 00000000..7c3ddedd --- /dev/null +++ b/cas/1.0/default/TypeConvert.h @@ -0,0 +1,41 @@ +/* + * 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 ANDROID_HARDWARE_CAS_V1_0_TYPE_CONVERT_H +#define ANDROID_HARDWARE_CAS_V1_0_TYPE_CONVERT_H + +#include +#include +#include +#include + +namespace android { +namespace hardware { +namespace cas { +namespace V1_0 { +namespace implementation { + +Status toStatus(status_t legacyStatus); + +String8 sessionIdToString(const CasSessionId &sessionId); + +} // namespace implementation +} // namespace V1_0 +} // namespace cas +} // namespace hardware +} // namespace android + +#endif // ANDROID_HARDWARE_CAS_V1_0_TYPE_CONVERT_H diff --git a/cas/1.0/default/android.hardware.cas@1.0-service.rc b/cas/1.0/default/android.hardware.cas@1.0-service.rc new file mode 100644 index 00000000..93de7944 --- /dev/null +++ b/cas/1.0/default/android.hardware.cas@1.0-service.rc @@ -0,0 +1,6 @@ +service cas-hal-1-0 /vendor/bin/hw/android.hardware.cas@1.0-service + class hal + user media + group mediadrm drmrpc + ioprio rt 4 + writepid /dev/cpuset/foreground/tasks diff --git a/cas/1.0/default/service.cpp b/cas/1.0/default/service.cpp new file mode 100644 index 00000000..3f1df5a5 --- /dev/null +++ b/cas/1.0/default/service.cpp @@ -0,0 +1,50 @@ +/* + * 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 +#define LOG_TAG "android.hardware.cas@1.0-service" + +#include +#include +#include + +#include "MediaCasService.h" + +using android::hardware::configureRpcThreadpool; +using android::hardware::joinRpcThreadpool; +using android::hardware::cas::V1_0::implementation::MediaCasService; +using android::hardware::cas::V1_0::IMediaCasService; + +int main() { + ALOGD("android.hardware.cas@1.0-service starting..."); + +#ifdef USE_VNDBINDER + // The CAS HAL may communicate to other vendor components via + // /dev/vndbinder + android::ProcessState::initWithDriver("/dev/vndbinder"); +#endif // USE_VNDBINDER + + configureRpcThreadpool(8, true /* callerWillJoin */); + + // Setup hwbinder service + android::sp service = new MediaCasService(); + android::status_t status = service->registerAsService(); + LOG_ALWAYS_FATAL_IF( + status != android::OK, + "Error while registering cas service: %d", status); + joinRpcThreadpool(); + return 0; +} diff --git a/cas/1.0/types.hal b/cas/1.0/types.hal new file mode 100644 index 00000000..7337f001 --- /dev/null +++ b/cas/1.0/types.hal @@ -0,0 +1,124 @@ +/** + * 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. + */ + +package android.hardware.cas@1.0; + +enum Status : uint32_t { + /** + * The CAS plugin must return OK when an operation completes without any + * errors. + */ + OK, + + /** + * The CAS plugin must return ERROR_CAS_NO_LICENSE, when descrambling is + * attempted and no license keys have been provided. + */ + ERROR_CAS_NO_LICENSE, + + /** + * ERROR_CAS_LICENSE_EXPIRED must be returned when an attempt is made + * to use a license and the keys in that license have expired. + */ + ERROR_CAS_LICENSE_EXPIRED, + + /** + * The CAS plugin must return ERROR_CAS_SESSION_NOT_OPENED when an + * attempt is made to use a session that has not been opened. + */ + ERROR_CAS_SESSION_NOT_OPENED, + + /** + * The CAS plugin must return ERROR_CAS_CANNOT_HANDLE when an unsupported + * data format or operation is attempted. + */ + ERROR_CAS_CANNOT_HANDLE, + + /** + * ERROR_CAS_INVALID_STATE must be returned when the device is in a state + * where it is not able to perform descrambling. + */ + ERROR_CAS_INVALID_STATE, + + /** + * The CAS plugin must return BAD_VALUE whenever an illegal parameter is + * passed to one of the interface functions. + */ + BAD_VALUE, + + /** + * The CAS plugin must return ERROR_CAS_NOT_PROVISIONED when the device + * has not yet been provisioned. + */ + ERROR_CAS_NOT_PROVISIONED, + + /** + * ERROR_CAS_RESOURCE_BUSY must be returned when resources, such as CAS + * sessions or secure buffers are not available to perform a requested + * operation because they are already in use. + */ + ERROR_CAS_RESOURCE_BUSY, + + /** + * The CAS Plugin must return ERROR_CAS_INSUFFICIENT_OUTPUT_PROTECTION + * when the output protection level enabled on the device is not + * sufficient to meet the requirements in the license policy. HDCP is an + * example of a form of output protection. + */ + ERROR_CAS_INSUFFICIENT_OUTPUT_PROTECTION, + + /** + * The CAS Plugin must return ERROR_CAS_TAMPER_DETECTED if an attempt to + * tamper with the CAS system is detected. + */ + ERROR_CAS_TAMPER_DETECTED, + + /** + * The CAS Plugin must return ERROR_CAS_DEVICE_REVOKED if the response + * indicates that the device has been revoked. Device revocation means + * that the device is no longer permitted to play content. + */ + ERROR_CAS_DEVICE_REVOKED, + + /** + * The CAS plugin must return ERROR_CAS_DECRYPT_UNIT_NOT_INITIALIZED when + * descrambling is failing because the session is not initialized properly. + */ + ERROR_CAS_DECRYPT_UNIT_NOT_INITIALIZED, + + /** + * The CAS Plugin must return ERROR_CAS_DECRYPT if the DescramblerPlugin's + * descramble operation fails. + */ + ERROR_CAS_DECRYPT, + + /** + * ERROR_CAS_UNKNOWN must be returned when a fatal failure occurs and no + * other defined error is appropriate. + */ + ERROR_CAS_UNKNOWN, +}; + +typedef vec HidlCasSessionId; +typedef vec HidlCasData; + +/** + * Describes a CAS plugin with its system id and name. + */ +struct HidlCasPluginDescriptor { + int32_t caSystemId; + string name; +}; diff --git a/cas/Android.bp b/cas/Android.bp new file mode 100644 index 00000000..57532a08 --- /dev/null +++ b/cas/Android.bp @@ -0,0 +1,6 @@ +// This is an autogenerated file, do not edit. +subdirs = [ + "1.0", + "1.0/default", + "native/1.0", +] diff --git a/cas/native/1.0/Android.bp b/cas/native/1.0/Android.bp new file mode 100644 index 00000000..414fca7b --- /dev/null +++ b/cas/native/1.0/Android.bp @@ -0,0 +1,65 @@ +// This file is autogenerated by hidl-gen. Do not edit manually. + +filegroup { + name: "android.hardware.cas.native@1.0_hal", + srcs: [ + "types.hal", + "IDescrambler.hal", + ], +} + +genrule { + name: "android.hardware.cas.native@1.0_genc++", + tools: ["hidl-gen"], + cmd: "$(location hidl-gen) -o $(genDir) -Lc++-sources -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.cas.native@1.0", + srcs: [ + ":android.hardware.cas.native@1.0_hal", + ], + out: [ + "android/hardware/cas/native/1.0/types.cpp", + "android/hardware/cas/native/1.0/DescramblerAll.cpp", + ], +} + +genrule { + name: "android.hardware.cas.native@1.0_genc++_headers", + tools: ["hidl-gen"], + cmd: "$(location hidl-gen) -o $(genDir) -Lc++-headers -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.cas.native@1.0", + srcs: [ + ":android.hardware.cas.native@1.0_hal", + ], + out: [ + "android/hardware/cas/native/1.0/types.h", + "android/hardware/cas/native/1.0/hwtypes.h", + "android/hardware/cas/native/1.0/IDescrambler.h", + "android/hardware/cas/native/1.0/IHwDescrambler.h", + "android/hardware/cas/native/1.0/BnHwDescrambler.h", + "android/hardware/cas/native/1.0/BpHwDescrambler.h", + "android/hardware/cas/native/1.0/BsDescrambler.h", + ], +} + +cc_library_shared { + name: "android.hardware.cas.native@1.0", + defaults: ["hidl-module-defaults"], + generated_sources: ["android.hardware.cas.native@1.0_genc++"], + generated_headers: ["android.hardware.cas.native@1.0_genc++_headers"], + export_generated_headers: ["android.hardware.cas.native@1.0_genc++_headers"], + vendor_available: true, + shared_libs: [ + "libhidlbase", + "libhidltransport", + "libhwbinder", + "liblog", + "libutils", + "libcutils", + "android.hardware.cas@1.0", + ], + export_shared_lib_headers: [ + "libhidlbase", + "libhidltransport", + "libhwbinder", + "libutils", + "android.hardware.cas@1.0", + ], +} diff --git a/cas/native/1.0/IDescrambler.hal b/cas/native/1.0/IDescrambler.hal new file mode 100644 index 00000000..459e5e30 --- /dev/null +++ b/cas/native/1.0/IDescrambler.hal @@ -0,0 +1,45 @@ +/* + * 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. + */ +package android.hardware.cas.native@1.0; + +import android.hardware.cas@1.0::IDescramblerBase; + +/** + * IDescrambler is the native plugin API for descrambling operations. + */ + +interface IDescrambler extends IDescramblerBase { + /** + * Descramble the data in a source SharedBuffer, described by an array of + * SubSample structures. + * + * @param scramblingControl an enumeration indicating the key that the subsamples + * were scrambled with. + * @param subSamples an array of SubSample structures describing the number of + * clear and scrambled bytes within each subsample. + * @param srcBuffer the SharedBuffer containing the source scrambled data. + * @param srcOffset the position where the source scrambled data starts at. + * @param dstBuffer the DestinationBuffer to hold the descrambled data. + * @param dstOffset the position where the descrambled data should start at. + * + * @return status the status of the call. + * @return bytesWritten number of bytes that have been successfully descrambled. + * @return detailedError a detailed message describing the error (if any). + */ + descramble(ScramblingControl scramblingControl, vec subSamples, + SharedBuffer srcBuffer, uint64_t srcOffset, DestinationBuffer dstBuffer, uint64_t dstOffset) + generates(Status status, uint32_t bytesWritten, string detailedError); +}; diff --git a/cas/native/1.0/types.hal b/cas/native/1.0/types.hal new file mode 100644 index 00000000..a576d039 --- /dev/null +++ b/cas/native/1.0/types.hal @@ -0,0 +1,90 @@ +/** + * 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. + */ + +package android.hardware.cas.native@1.0; + +import android.hardware.cas@1.0::types; + +/** + * Enumerates the keys used to scramble the content. + */ +enum ScramblingControl : uint32_t { + UNSCRAMBLED = 0, + RESERVED = 1, + EVENKEY = 2, + ODDKEY = 3, +}; + +/** + * A subsample consists of some number of bytes of clear (unscrambled) + * data followed by a number of bytes of scrambled data. + */ +struct SubSample { + uint32_t numBytesOfClearData; + uint32_t numBytesOfEncryptedData; +}; + +/** + * SharedBuffer describes a shared buffer which is defined by a heapBase, an + * offset and a size. The offset is relative to the shared memory base for the + * memory region identified by heapBase. + */ +struct SharedBuffer { + /** + * The shared memory base handle + */ + memory heapBase; + + /** + * The offset from the shared memory base + */ + uint64_t offset; + + /** + * The size of the shared buffer in bytes + */ + uint64_t size; +}; + +/** + * A descrambling destination buffer can be either normal user-space shared + * memory for the non-secure descrambling case, or it can be a secure buffer + * which is referenced by a native-handle. The native handle is allocated + * by the vendor's buffer allocator. + */ +enum BufferType : uint32_t { + SHARED_MEMORY = 0, + NATIVE_HANDLE = 1, +}; + +struct DestinationBuffer { + /** + * The type of the buffer + */ + BufferType type; + + /** + * If type == SHARED_MEMORY, the descrambled data must be written + * to user-space non-secure shared memory. + */ + SharedBuffer nonsecureMemory; + + /** + * If type == NATIVE_HANDLE, the descrambled data must be written + * to secure memory referenced by the vendor's buffer allocator. + */ + handle secureMemory; +};