Add default implementation for CAS AIDL
Bug: 230377377, 227673974 Test: manual Change-Id: I85015dd6e1a69ff9b57f832f5b1cd01fb65dda25
This commit is contained in:
parent
fdeb39f878
commit
6545b4e343
18 changed files with 1413 additions and 0 deletions
93
cas/aidl/default/Android.bp
Executable file
93
cas/aidl/default/Android.bp
Executable file
|
@ -0,0 +1,93 @@
|
|||
package {
|
||||
// See: http://go/android-license-faq
|
||||
// A large-scale-change added 'default_applicable_licenses' to import
|
||||
// all of the 'license_kinds' from "hardware_interfaces_license"
|
||||
// to get the below license kinds:
|
||||
// SPDX-license-identifier-Apache-2.0
|
||||
default_applicable_licenses: ["hardware_interfaces_license"],
|
||||
}
|
||||
|
||||
cc_library_static {
|
||||
name: "libcasexampleimpl",
|
||||
vendor_available: true,
|
||||
|
||||
srcs: [
|
||||
"CasImpl.cpp",
|
||||
"DescramblerImpl.cpp",
|
||||
"MediaCasService.cpp",
|
||||
"SharedLibrary.cpp",
|
||||
"TypeConvert.cpp",
|
||||
],
|
||||
|
||||
shared_libs: [
|
||||
"android.hardware.cas-V1-ndk",
|
||||
"libbinder_ndk",
|
||||
"liblog",
|
||||
"libutils",
|
||||
"libcutils",
|
||||
],
|
||||
static_libs: [
|
||||
"libaidlcommonsupport",
|
||||
],
|
||||
header_libs: [
|
||||
"libstagefright_foundation_headers",
|
||||
"media_plugin_headers",
|
||||
],
|
||||
}
|
||||
|
||||
cc_defaults {
|
||||
name: "cas_service_example_defaults",
|
||||
vendor: true,
|
||||
relative_install_path: "hw",
|
||||
|
||||
srcs: ["service.cpp"],
|
||||
|
||||
static_libs: [
|
||||
"libaidlcommonsupport",
|
||||
"libcasexampleimpl",
|
||||
],
|
||||
shared_libs: [
|
||||
"android.hardware.cas-V1-ndk",
|
||||
"libbinder_ndk",
|
||||
"liblog",
|
||||
"libutils",
|
||||
"libcutils",
|
||||
],
|
||||
header_libs: ["media_plugin_headers"],
|
||||
vintf_fragments: ["android.hardware.cas-service.xml"],
|
||||
}
|
||||
|
||||
cc_binary {
|
||||
name: "android.hardware.cas-service.example",
|
||||
defaults: ["cas_service_example_defaults"],
|
||||
init_rc: ["cas-default.rc"],
|
||||
}
|
||||
|
||||
cc_binary {
|
||||
name: "android.hardware.cas-service.example-lazy",
|
||||
defaults: ["cas_service_example_defaults"],
|
||||
init_rc: ["cas-default-lazy.rc"],
|
||||
cflags: ["-DLAZY_SERVICE"],
|
||||
}
|
||||
|
||||
cc_fuzz {
|
||||
name: "android.hardware.cas-service_fuzzer",
|
||||
vendor: true,
|
||||
|
||||
defaults: ["service_fuzzer_defaults"],
|
||||
srcs: ["fuzzer.cpp"],
|
||||
|
||||
shared_libs: [
|
||||
"android.hardware.cas-V1-ndk",
|
||||
"libcutils",
|
||||
"liblog",
|
||||
],
|
||||
static_libs: [
|
||||
"libaidlcommonsupport",
|
||||
"libcasexampleimpl",
|
||||
],
|
||||
header_libs: ["media_plugin_headers"],
|
||||
fuzz_config: {
|
||||
componentid: 1344,
|
||||
},
|
||||
}
|
242
cas/aidl/default/CasImpl.cpp
Executable file
242
cas/aidl/default/CasImpl.cpp
Executable file
|
@ -0,0 +1,242 @@
|
|||
/*
|
||||
* Copyright (C) 2022 The Android Open Source Project
|
||||
*
|
||||
icensed 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_TAG "android.hardware.cas-CasImpl"
|
||||
|
||||
#include <media/cas/CasAPI.h>
|
||||
#include <utils/Log.h>
|
||||
|
||||
#include "CasImpl.h"
|
||||
#include "TypeConvert.h"
|
||||
|
||||
namespace aidl {
|
||||
namespace android {
|
||||
namespace hardware {
|
||||
namespace cas {
|
||||
|
||||
CasImpl::CasImpl(const shared_ptr<ICasListener>& 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<CasImpl*>(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<CasImpl*>(appData);
|
||||
casImpl->onEvent(sessionId, event, arg, data, size);
|
||||
}
|
||||
|
||||
// static
|
||||
void CasImpl::StatusUpdate(void* appData, int32_t event, int32_t arg) {
|
||||
if (appData == NULL) {
|
||||
ALOGE("Invalid appData!");
|
||||
return;
|
||||
}
|
||||
CasImpl* casImpl = static_cast<CasImpl*>(appData);
|
||||
casImpl->onStatusUpdate(event, arg);
|
||||
}
|
||||
|
||||
void CasImpl::init(CasPlugin* plugin) {
|
||||
shared_ptr<CasPlugin> holder(plugin);
|
||||
atomic_store(&mPluginHolder, holder);
|
||||
}
|
||||
|
||||
void CasImpl::onEvent(int32_t event, int32_t arg, uint8_t* data, size_t size) {
|
||||
if (mListener == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
vector<uint8_t> eventData;
|
||||
if (data != NULL) {
|
||||
eventData.assign(data, 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;
|
||||
}
|
||||
|
||||
vector<uint8_t> eventData;
|
||||
if (data != NULL) {
|
||||
eventData.assign(data, data + size);
|
||||
}
|
||||
|
||||
if (sessionId != NULL) {
|
||||
mListener->onSessionEvent(*sessionId, event, arg, eventData);
|
||||
} else {
|
||||
mListener->onEvent(event, arg, eventData);
|
||||
}
|
||||
}
|
||||
|
||||
void CasImpl::onStatusUpdate(int32_t event, int32_t arg) {
|
||||
if (mListener == NULL) {
|
||||
return;
|
||||
}
|
||||
mListener->onStatusUpdate(static_cast<StatusEvent>(event), arg);
|
||||
}
|
||||
|
||||
ScopedAStatus CasImpl::setPluginStatusUpdateCallback() {
|
||||
ALOGV("%s", __FUNCTION__);
|
||||
shared_ptr<CasPlugin> holder = atomic_load(&mPluginHolder);
|
||||
if (holder.get() == nullptr) {
|
||||
return toStatus(INVALID_OPERATION);
|
||||
}
|
||||
return toStatus(holder->setStatusCallback(&CasImpl::StatusUpdate));
|
||||
}
|
||||
|
||||
ScopedAStatus CasImpl::setPrivateData(const vector<uint8_t>& pvtData) {
|
||||
ALOGV("%s", __FUNCTION__);
|
||||
shared_ptr<CasPlugin> holder = atomic_load(&mPluginHolder);
|
||||
if (holder.get() == nullptr) {
|
||||
return toStatus(INVALID_OPERATION);
|
||||
}
|
||||
return toStatus(holder->setPrivateData(pvtData));
|
||||
}
|
||||
|
||||
ScopedAStatus CasImpl::openSession(SessionIntent intent, ScramblingMode mode,
|
||||
vector<uint8_t>* sessionId) {
|
||||
ALOGV("%s", __FUNCTION__);
|
||||
|
||||
shared_ptr<CasPlugin> holder = atomic_load(&mPluginHolder);
|
||||
status_t err = INVALID_OPERATION;
|
||||
if (holder.get() != nullptr) {
|
||||
err = holder->openSession(static_cast<uint32_t>(intent), static_cast<uint32_t>(mode),
|
||||
sessionId);
|
||||
holder.reset();
|
||||
}
|
||||
|
||||
return toStatus(err);
|
||||
}
|
||||
|
||||
ScopedAStatus CasImpl::setSessionPrivateData(const vector<uint8_t>& sessionId,
|
||||
const vector<uint8_t>& pvtData) {
|
||||
ALOGV("%s: sessionId=%s", __FUNCTION__, sessionIdToString(sessionId).string());
|
||||
shared_ptr<CasPlugin> holder = atomic_load(&mPluginHolder);
|
||||
if (holder.get() == nullptr) {
|
||||
return toStatus(INVALID_OPERATION);
|
||||
}
|
||||
return toStatus(holder->setSessionPrivateData(sessionId, pvtData));
|
||||
}
|
||||
|
||||
ScopedAStatus CasImpl::closeSession(const vector<uint8_t>& sessionId) {
|
||||
ALOGV("%s: sessionId=%s", __FUNCTION__, sessionIdToString(sessionId).string());
|
||||
shared_ptr<CasPlugin> holder = atomic_load(&mPluginHolder);
|
||||
if (holder.get() == nullptr) {
|
||||
return toStatus(INVALID_OPERATION);
|
||||
}
|
||||
return toStatus(holder->closeSession(sessionId));
|
||||
}
|
||||
|
||||
ScopedAStatus CasImpl::processEcm(const vector<uint8_t>& sessionId, const vector<uint8_t>& ecm) {
|
||||
ALOGV("%s: sessionId=%s", __FUNCTION__, sessionIdToString(sessionId).string());
|
||||
shared_ptr<CasPlugin> holder = atomic_load(&mPluginHolder);
|
||||
if (holder.get() == nullptr) {
|
||||
return toStatus(INVALID_OPERATION);
|
||||
}
|
||||
|
||||
return toStatus(holder->processEcm(sessionId, ecm));
|
||||
}
|
||||
|
||||
ScopedAStatus CasImpl::processEmm(const vector<uint8_t>& emm) {
|
||||
ALOGV("%s", __FUNCTION__);
|
||||
shared_ptr<CasPlugin> holder = atomic_load(&mPluginHolder);
|
||||
if (holder.get() == nullptr) {
|
||||
return toStatus(INVALID_OPERATION);
|
||||
}
|
||||
|
||||
return toStatus(holder->processEmm(emm));
|
||||
}
|
||||
|
||||
ScopedAStatus CasImpl::sendEvent(int32_t event, int32_t arg, const vector<uint8_t>& eventData) {
|
||||
ALOGV("%s", __FUNCTION__);
|
||||
shared_ptr<CasPlugin> holder = atomic_load(&mPluginHolder);
|
||||
if (holder.get() == nullptr) {
|
||||
return toStatus(INVALID_OPERATION);
|
||||
}
|
||||
|
||||
status_t err = holder->sendEvent(event, arg, eventData);
|
||||
return toStatus(err);
|
||||
}
|
||||
|
||||
ScopedAStatus CasImpl::sendSessionEvent(const vector<uint8_t>& sessionId, int32_t event,
|
||||
int32_t arg, const vector<uint8_t>& eventData) {
|
||||
ALOGV("%s", __FUNCTION__);
|
||||
shared_ptr<CasPlugin> holder = atomic_load(&mPluginHolder);
|
||||
if (holder.get() == nullptr) {
|
||||
return toStatus(INVALID_OPERATION);
|
||||
}
|
||||
|
||||
status_t err = holder->sendSessionEvent(sessionId, event, arg, eventData);
|
||||
return toStatus(err);
|
||||
}
|
||||
|
||||
ScopedAStatus CasImpl::provision(const string& provisionString) {
|
||||
ALOGV("%s: provisionString=%s", __FUNCTION__, provisionString.c_str());
|
||||
shared_ptr<CasPlugin> holder = atomic_load(&mPluginHolder);
|
||||
if (holder.get() == nullptr) {
|
||||
return toStatus(INVALID_OPERATION);
|
||||
}
|
||||
|
||||
return toStatus(holder->provision(String8(provisionString.c_str())));
|
||||
}
|
||||
|
||||
ScopedAStatus CasImpl::refreshEntitlements(int32_t refreshType,
|
||||
const vector<uint8_t>& refreshData) {
|
||||
ALOGV("%s", __FUNCTION__);
|
||||
shared_ptr<CasPlugin> holder = atomic_load(&mPluginHolder);
|
||||
if (holder.get() == nullptr) {
|
||||
return toStatus(INVALID_OPERATION);
|
||||
}
|
||||
|
||||
status_t err = holder->refreshEntitlements(refreshType, refreshData);
|
||||
return toStatus(err);
|
||||
}
|
||||
|
||||
ScopedAStatus CasImpl::release() {
|
||||
ALOGV("%s: plugin=%p", __FUNCTION__, mPluginHolder.get());
|
||||
|
||||
shared_ptr<CasPlugin> holder(nullptr);
|
||||
atomic_store(&mPluginHolder, holder);
|
||||
|
||||
return ScopedAStatus::ok();
|
||||
}
|
||||
|
||||
} // namespace cas
|
||||
} // namespace hardware
|
||||
} // namespace android
|
||||
} // namespace aidl
|
93
cas/aidl/default/CasImpl.h
Executable file
93
cas/aidl/default/CasImpl.h
Executable file
|
@ -0,0 +1,93 @@
|
|||
/*
|
||||
* Copyright (C) 2022 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.
|
||||
*/
|
||||
|
||||
#include <aidl/android/hardware/cas/BnCas.h>
|
||||
#include <aidl/android/hardware/cas/ICasListener.h>
|
||||
#include <media/stagefright/foundation/ABase.h>
|
||||
|
||||
namespace aidl {
|
||||
namespace android {
|
||||
namespace hardware {
|
||||
namespace cas {
|
||||
|
||||
using namespace ::android;
|
||||
using namespace std;
|
||||
using ndk::ScopedAStatus;
|
||||
|
||||
class CasImpl : public BnCas {
|
||||
public:
|
||||
CasImpl(const shared_ptr<ICasListener>& 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);
|
||||
|
||||
static void StatusUpdate(void* appData, int32_t event, int32_t arg);
|
||||
|
||||
void init(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);
|
||||
|
||||
void onStatusUpdate(int32_t event, int32_t arg);
|
||||
|
||||
// ICas inherits
|
||||
|
||||
ScopedAStatus setPluginStatusUpdateCallback();
|
||||
|
||||
virtual ScopedAStatus setPrivateData(const vector<uint8_t>& pvtData) override;
|
||||
|
||||
virtual ScopedAStatus openSession(SessionIntent intent, ScramblingMode mode,
|
||||
vector<uint8_t>* sessionId) override;
|
||||
|
||||
virtual ScopedAStatus closeSession(const vector<uint8_t>& sessionId) override;
|
||||
|
||||
virtual ScopedAStatus setSessionPrivateData(const vector<uint8_t>& sessionId,
|
||||
const vector<uint8_t>& pvtData) override;
|
||||
|
||||
virtual ScopedAStatus processEcm(const vector<uint8_t>& sessionId,
|
||||
const vector<uint8_t>& ecm) override;
|
||||
|
||||
virtual ScopedAStatus processEmm(const vector<uint8_t>& emm) override;
|
||||
|
||||
virtual ScopedAStatus sendEvent(int32_t event, int32_t arg,
|
||||
const vector<uint8_t>& eventData) override;
|
||||
|
||||
virtual ScopedAStatus sendSessionEvent(const vector<uint8_t>& sessionId, int32_t event,
|
||||
int32_t arg, const vector<uint8_t>& eventData) override;
|
||||
|
||||
virtual ScopedAStatus provision(const string& provisionString) override;
|
||||
|
||||
virtual ScopedAStatus refreshEntitlements(int32_t refreshType,
|
||||
const vector<uint8_t>& refreshData) override;
|
||||
|
||||
virtual ScopedAStatus release() override;
|
||||
|
||||
private:
|
||||
struct PluginHolder;
|
||||
shared_ptr<CasPlugin> mPluginHolder;
|
||||
shared_ptr<ICasListener> mListener;
|
||||
|
||||
DISALLOW_EVIL_CONSTRUCTORS(CasImpl);
|
||||
};
|
||||
|
||||
} // namespace cas
|
||||
} // namespace hardware
|
||||
} // namespace android
|
||||
} // namespace aidl
|
193
cas/aidl/default/DescramblerImpl.cpp
Executable file
193
cas/aidl/default/DescramblerImpl.cpp
Executable file
|
@ -0,0 +1,193 @@
|
|||
/*
|
||||
* Copyright (C) 2022 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_TAG "android.hardware.cas-DescramblerImpl"
|
||||
|
||||
#include <aidlcommonsupport/NativeHandle.h>
|
||||
#include <inttypes.h>
|
||||
#include <media/cas/DescramblerAPI.h>
|
||||
#include <media/hardware/CryptoAPI.h>
|
||||
#include <media/stagefright/foundation/AUtils.h>
|
||||
#include <sys/mman.h>
|
||||
#include <utils/Log.h>
|
||||
|
||||
#include "DescramblerImpl.h"
|
||||
#include "TypeConvert.h"
|
||||
|
||||
namespace aidl {
|
||||
namespace android {
|
||||
namespace hardware {
|
||||
namespace cas {
|
||||
|
||||
#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(DescramblerPlugin* plugin) : mPluginHolder(plugin) {
|
||||
ALOGV("CTOR: plugin=%p", mPluginHolder.get());
|
||||
}
|
||||
|
||||
DescramblerImpl::~DescramblerImpl() {
|
||||
ALOGV("DTOR: plugin=%p", mPluginHolder.get());
|
||||
release();
|
||||
}
|
||||
|
||||
ScopedAStatus DescramblerImpl::setMediaCasSession(const vector<uint8_t>& in_sessionId) {
|
||||
ALOGV("%s: sessionId=%s", __FUNCTION__, sessionIdToString(in_sessionId).string());
|
||||
|
||||
shared_ptr<DescramblerPlugin> holder = atomic_load(&mPluginHolder);
|
||||
if (holder.get() == nullptr) {
|
||||
return toStatus(INVALID_OPERATION);
|
||||
}
|
||||
|
||||
return toStatus(holder->setMediaCasSession(in_sessionId));
|
||||
}
|
||||
|
||||
ScopedAStatus DescramblerImpl::requiresSecureDecoderComponent(const string& in_mime,
|
||||
bool* _aidl_return) {
|
||||
shared_ptr<DescramblerPlugin> holder = atomic_load(&mPluginHolder);
|
||||
if (holder.get() == nullptr) {
|
||||
*_aidl_return = false;
|
||||
}
|
||||
|
||||
*_aidl_return = holder->requiresSecureDecoderComponent(String8(in_mime.c_str()));
|
||||
return ScopedAStatus::ok();
|
||||
}
|
||||
|
||||
static inline bool validateRangeForSize(int64_t offset, int64_t length, int64_t size) {
|
||||
return isInRange<int64_t, uint64_t>(0, (uint64_t)size, offset, (uint64_t)length);
|
||||
}
|
||||
|
||||
ScopedAStatus DescramblerImpl::descramble(ScramblingControl scramblingControl,
|
||||
const vector<SubSample>& subSamples,
|
||||
const SharedBuffer& srcBuffer, int64_t srcOffset,
|
||||
const DestinationBuffer& dstBuffer, int64_t dstOffset,
|
||||
int32_t* _aidl_return) {
|
||||
ALOGV("%s", __FUNCTION__);
|
||||
|
||||
// heapbase's size is stored in int64_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 memory size: %" PRIu64 "", srcBuffer.heapBase.size);
|
||||
android_errorWriteLog(0x534e4554, "79376389");
|
||||
return toStatus(BAD_VALUE);
|
||||
}
|
||||
|
||||
void* srcPtr = mmap(NULL, srcBuffer.heapBase.size, PROT_READ | PROT_WRITE, MAP_SHARED,
|
||||
srcBuffer.heapBase.fd.get(), 0);
|
||||
|
||||
// Validate if the offset and size in the SharedBuffer is consistent with the
|
||||
// mapped heapbase, since the offset and size is controlled by client.
|
||||
if (srcPtr == NULL) {
|
||||
ALOGE("Failed to map src buffer.");
|
||||
return toStatus(BAD_VALUE);
|
||||
}
|
||||
if (!validateRangeForSize(srcBuffer.offset, srcBuffer.size, srcBuffer.heapBase.size)) {
|
||||
ALOGE("Invalid src buffer range: offset %" PRIu64 ", size %" PRIu64
|
||||
", srcMem"
|
||||
"size %" PRIu64 "",
|
||||
srcBuffer.offset, srcBuffer.size, srcBuffer.heapBase.size);
|
||||
android_errorWriteLog(0x534e4554, "67962232");
|
||||
return toStatus(BAD_VALUE);
|
||||
}
|
||||
|
||||
// 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++) {
|
||||
uint32_t numBytesOfClearData = subSamples[i].numBytesOfClearData;
|
||||
uint32_t numBytesOfEncryptedData = subSamples[i].numBytesOfEncryptedData;
|
||||
totalBytesInSubSamples += (uint64_t)numBytesOfClearData + 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 %" PRIu64 ", totalBytesInSubSamples %" PRIu64
|
||||
", srcBuffer"
|
||||
"size %" PRIu64 "",
|
||||
srcOffset, totalBytesInSubSamples, srcBuffer.size);
|
||||
android_errorWriteLog(0x534e4554, "67962232");
|
||||
return toStatus(BAD_VALUE);
|
||||
}
|
||||
srcPtr = (uint8_t*)srcPtr + srcBuffer.offset;
|
||||
|
||||
void* dstPtr = NULL;
|
||||
if (dstBuffer.getTag() == DestinationBuffer::Tag::nonsecureMemory) {
|
||||
// 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 %" PRIu64 ", totalBytesInSubSamples %" PRIu64
|
||||
", srcBuffer"
|
||||
"size %" PRIu64 "",
|
||||
dstOffset, totalBytesInSubSamples, srcBuffer.size);
|
||||
android_errorWriteLog(0x534e4554, "67962232");
|
||||
return toStatus(BAD_VALUE);
|
||||
}
|
||||
} else {
|
||||
native_handle_t* handle = makeFromAidl(dstBuffer.get<DestinationBuffer::secureMemory>());
|
||||
dstPtr = static_cast<void*>(handle);
|
||||
}
|
||||
|
||||
// Get a local copy of the shared_ptr for the plugin. Note that before
|
||||
// calling the 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.
|
||||
shared_ptr<DescramblerPlugin> holder = atomic_load(&mPluginHolder);
|
||||
if (holder.get() == nullptr) {
|
||||
return toStatus(INVALID_OPERATION);
|
||||
}
|
||||
|
||||
// Casting SubSample to DescramblerPlugin::SubSample, but need to ensure
|
||||
// structs are actually identical
|
||||
|
||||
auto returnStatus =
|
||||
holder->descramble(dstBuffer.getTag() != DestinationBuffer::Tag::nonsecureMemory,
|
||||
(DescramblerPlugin::ScramblingControl)scramblingControl,
|
||||
subSamples.size(), (DescramblerPlugin::SubSample*)subSamples.data(),
|
||||
srcPtr, srcOffset, dstPtr, dstOffset, NULL);
|
||||
|
||||
holder.reset();
|
||||
*_aidl_return = returnStatus;
|
||||
return toStatus(returnStatus >= 0 ? OK : returnStatus);
|
||||
}
|
||||
|
||||
ScopedAStatus DescramblerImpl::release() {
|
||||
ALOGV("%s: plugin=%p", __FUNCTION__, mPluginHolder.get());
|
||||
|
||||
shared_ptr<DescramblerPlugin> holder(nullptr);
|
||||
atomic_store(&mPluginHolder, holder);
|
||||
|
||||
return ScopedAStatus::ok();
|
||||
}
|
||||
|
||||
} // namespace cas
|
||||
} // namespace hardware
|
||||
} // namespace android
|
||||
} // namespace aidl
|
56
cas/aidl/default/DescramblerImpl.h
Executable file
56
cas/aidl/default/DescramblerImpl.h
Executable file
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
* Copyright (C) 2022 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.
|
||||
*/
|
||||
|
||||
#include <aidl/android/hardware/cas/BnDescrambler.h>
|
||||
#include <media/stagefright/foundation/ABase.h>
|
||||
|
||||
namespace aidl {
|
||||
namespace android {
|
||||
namespace hardware {
|
||||
namespace cas {
|
||||
|
||||
using namespace ::android;
|
||||
using namespace std;
|
||||
using ndk::ScopedAStatus;
|
||||
|
||||
class DescramblerImpl : public BnDescrambler {
|
||||
public:
|
||||
DescramblerImpl(DescramblerPlugin* plugin);
|
||||
virtual ~DescramblerImpl();
|
||||
|
||||
virtual ScopedAStatus setMediaCasSession(const vector<uint8_t>& in_sessionId) override;
|
||||
|
||||
virtual ScopedAStatus requiresSecureDecoderComponent(const string& in_mime,
|
||||
bool* _aidl_return) override;
|
||||
|
||||
virtual ScopedAStatus descramble(ScramblingControl in_scramblingControl,
|
||||
const vector<SubSample>& in_subSamples,
|
||||
const SharedBuffer& in_srcBuffer, int64_t in_srcOffset,
|
||||
const DestinationBuffer& in_dstBuffer, int64_t in_dstOffset,
|
||||
int32_t* _aidl_return) override;
|
||||
|
||||
virtual ScopedAStatus release() override;
|
||||
|
||||
private:
|
||||
shared_ptr<DescramblerPlugin> mPluginHolder;
|
||||
|
||||
DISALLOW_EVIL_CONSTRUCTORS(DescramblerImpl);
|
||||
};
|
||||
|
||||
} // namespace cas
|
||||
} // namespace hardware
|
||||
} // namespace android
|
||||
} // namespace aidl
|
219
cas/aidl/default/FactoryLoader.h
Executable file
219
cas/aidl/default/FactoryLoader.h
Executable file
|
@ -0,0 +1,219 @@
|
|||
/*
|
||||
* Copyright (C) 2022 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.
|
||||
*/
|
||||
|
||||
#include <dirent.h>
|
||||
#include <dlfcn.h>
|
||||
#include <media/cas/CasAPI.h>
|
||||
#include <utils/KeyedVector.h>
|
||||
#include <utils/Mutex.h>
|
||||
#include "SharedLibrary.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace aidl {
|
||||
namespace android {
|
||||
namespace hardware {
|
||||
namespace cas {
|
||||
|
||||
using namespace ::android;
|
||||
|
||||
template <class T>
|
||||
class FactoryLoader {
|
||||
public:
|
||||
FactoryLoader(const char* name) : mFactory(NULL), mCreateFactoryFuncName(name) {}
|
||||
|
||||
virtual ~FactoryLoader() { closeFactory(); }
|
||||
|
||||
bool findFactoryForScheme(int32_t CA_system_id, shared_ptr<SharedLibrary>* library = NULL,
|
||||
T** factory = NULL);
|
||||
|
||||
bool enumeratePlugins(vector<AidlCasPluginDescriptor>* results);
|
||||
|
||||
private:
|
||||
typedef T* (*CreateFactoryFunc)();
|
||||
|
||||
Mutex mMapLock;
|
||||
T* mFactory;
|
||||
const char* mCreateFactoryFuncName;
|
||||
shared_ptr<SharedLibrary> mLibrary;
|
||||
KeyedVector<int32_t, String8> mCASystemIdToLibraryPathMap;
|
||||
KeyedVector<String8, shared_ptr<SharedLibrary>> mLibraryPathToOpenLibraryMap;
|
||||
|
||||
bool loadFactoryForSchemeFromPath(const String8& path, int32_t CA_system_id,
|
||||
shared_ptr<SharedLibrary>* library, T** factory);
|
||||
|
||||
bool queryPluginsFromPath(const String8& path, vector<AidlCasPluginDescriptor>* results);
|
||||
|
||||
bool openFactory(const String8& path);
|
||||
void closeFactory();
|
||||
};
|
||||
|
||||
template <class T>
|
||||
bool FactoryLoader<T>::findFactoryForScheme(int32_t CA_system_id,
|
||||
shared_ptr<SharedLibrary>* library, T** factory) {
|
||||
if (library != NULL) {
|
||||
library->reset();
|
||||
}
|
||||
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
|
||||
#ifdef __LP64__
|
||||
String8 dirPath("/vendor/lib64/mediacas");
|
||||
#else
|
||||
String8 dirPath("/vendor/lib/mediacas");
|
||||
#endif
|
||||
DIR* pDir = opendir(dirPath.string());
|
||||
|
||||
if (pDir == NULL) {
|
||||
ALOGE("Failed to open plugin directory %s", dirPath.string());
|
||||
return false;
|
||||
}
|
||||
|
||||
struct dirent* pEntry;
|
||||
while ((pEntry = readdir(pDir))) {
|
||||
String8 pluginPath = dirPath + "/" + pEntry->d_name;
|
||||
if (pluginPath.getPathExtension() == ".so") {
|
||||
if (loadFactoryForSchemeFromPath(pluginPath, CA_system_id, library, factory)) {
|
||||
mCASystemIdToLibraryPathMap.add(CA_system_id, pluginPath);
|
||||
closedir(pDir);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
closedir(pDir);
|
||||
|
||||
ALOGE("Failed to find plugin");
|
||||
return false;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
bool FactoryLoader<T>::enumeratePlugins(vector<AidlCasPluginDescriptor>* results) {
|
||||
ALOGI("enumeratePlugins");
|
||||
|
||||
results->clear();
|
||||
|
||||
#ifdef __LP64__
|
||||
String8 dirPath("/vendor/lib64/mediacas");
|
||||
#else
|
||||
String8 dirPath("/vendor/lib/mediacas");
|
||||
#endif
|
||||
DIR* pDir = opendir(dirPath.string());
|
||||
|
||||
if (pDir == NULL) {
|
||||
ALOGE("Failed to open plugin directory %s", dirPath.string());
|
||||
return false;
|
||||
}
|
||||
|
||||
Mutex::Autolock autoLock(mMapLock);
|
||||
|
||||
struct dirent* pEntry;
|
||||
while ((pEntry = readdir(pDir))) {
|
||||
String8 pluginPath = dirPath + "/" + pEntry->d_name;
|
||||
if (pluginPath.getPathExtension() == ".so") {
|
||||
queryPluginsFromPath(pluginPath, results);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
bool FactoryLoader<T>::loadFactoryForSchemeFromPath(const String8& path, int32_t CA_system_id,
|
||||
shared_ptr<SharedLibrary>* library,
|
||||
T** factory) {
|
||||
closeFactory();
|
||||
|
||||
if (!openFactory(path) || !mFactory->isSystemIdSupported(CA_system_id)) {
|
||||
closeFactory();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (library != NULL) {
|
||||
*library = mLibrary;
|
||||
}
|
||||
if (factory != NULL) {
|
||||
*factory = mFactory;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
bool FactoryLoader<T>::queryPluginsFromPath(const String8& path,
|
||||
vector<AidlCasPluginDescriptor>* results) {
|
||||
closeFactory();
|
||||
|
||||
vector<CasPluginDescriptor> descriptors;
|
||||
if (!openFactory(path) || mFactory->queryPlugins(&descriptors) != OK) {
|
||||
closeFactory();
|
||||
return false;
|
||||
}
|
||||
|
||||
for (auto it = descriptors.begin(); it != descriptors.end(); it++) {
|
||||
results->push_back(
|
||||
AidlCasPluginDescriptor{.caSystemId = it->CA_system_id, .name = it->name.c_str()});
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
bool FactoryLoader<T>::openFactory(const String8& path) {
|
||||
// get strong pointer to open shared library
|
||||
ssize_t index = mLibraryPathToOpenLibraryMap.indexOfKey(path);
|
||||
if (index >= 0) {
|
||||
mLibrary = mLibraryPathToOpenLibraryMap[index];
|
||||
} else {
|
||||
index = mLibraryPathToOpenLibraryMap.add(path, NULL);
|
||||
}
|
||||
|
||||
if (!mLibrary.get()) {
|
||||
mLibrary = ::ndk::SharedRefBase::make<SharedLibrary>(path);
|
||||
if (!*mLibrary) {
|
||||
return false;
|
||||
}
|
||||
|
||||
mLibraryPathToOpenLibraryMap.replaceValueAt(index, mLibrary);
|
||||
}
|
||||
|
||||
CreateFactoryFunc createFactory = (CreateFactoryFunc)mLibrary->lookup(mCreateFactoryFuncName);
|
||||
if (createFactory == NULL || (mFactory = createFactory()) == NULL) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void FactoryLoader<T>::closeFactory() {
|
||||
delete mFactory;
|
||||
mFactory = NULL;
|
||||
mLibrary.reset();
|
||||
}
|
||||
|
||||
} // namespace cas
|
||||
} // namespace hardware
|
||||
} // namespace android
|
||||
} // namespace aidl
|
101
cas/aidl/default/MediaCasService.cpp
Executable file
101
cas/aidl/default/MediaCasService.cpp
Executable file
|
@ -0,0 +1,101 @@
|
|||
/*
|
||||
* Copyright (C) 2022 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_TAG "android.hardware.cas-MediaCasService"
|
||||
|
||||
#include <media/cas/CasAPI.h>
|
||||
#include <media/cas/DescramblerAPI.h>
|
||||
#include <utils/Log.h>
|
||||
|
||||
#include "CasImpl.h"
|
||||
#include "DescramblerImpl.h"
|
||||
#include "MediaCasService.h"
|
||||
|
||||
namespace aidl {
|
||||
namespace android {
|
||||
namespace hardware {
|
||||
namespace cas {
|
||||
|
||||
MediaCasService::MediaCasService()
|
||||
: mCasLoader("createCasFactory"), mDescramblerLoader("createDescramblerFactory") {}
|
||||
|
||||
MediaCasService::~MediaCasService() {}
|
||||
|
||||
ScopedAStatus MediaCasService::enumeratePlugins(
|
||||
vector<AidlCasPluginDescriptor>* aidlCasPluginDescriptors) {
|
||||
ALOGV("%s", __FUNCTION__);
|
||||
|
||||
mCasLoader.enumeratePlugins(aidlCasPluginDescriptors);
|
||||
return ScopedAStatus::ok();
|
||||
}
|
||||
|
||||
ScopedAStatus MediaCasService::isSystemIdSupported(int32_t CA_system_id, bool* _aidl_return) {
|
||||
ALOGV("isSystemIdSupported: CA_system_id=%d", CA_system_id);
|
||||
|
||||
*_aidl_return = mCasLoader.findFactoryForScheme(CA_system_id);
|
||||
return ScopedAStatus::ok();
|
||||
}
|
||||
|
||||
ScopedAStatus MediaCasService::createPlugin(int32_t CA_system_id,
|
||||
const shared_ptr<ICasListener>& listener,
|
||||
shared_ptr<ICas>* _aidl_return) {
|
||||
ALOGV("%s: CA_system_id=%d", __FUNCTION__, CA_system_id);
|
||||
if (listener == NULL) ALOGV("%s: Listener is NULL", __FUNCTION__);
|
||||
|
||||
CasFactory* factory;
|
||||
shared_ptr<SharedLibrary> library;
|
||||
if (mCasLoader.findFactoryForScheme(CA_system_id, &library, &factory)) {
|
||||
CasPlugin* plugin = NULL;
|
||||
shared_ptr<CasImpl> casImpl = ::ndk::SharedRefBase::make<CasImpl>(listener);
|
||||
if (factory->createPlugin(CA_system_id, casImpl.get(), &CasImpl::CallBackExt, &plugin) ==
|
||||
OK &&
|
||||
plugin != NULL) {
|
||||
casImpl->init(plugin);
|
||||
*_aidl_return = casImpl;
|
||||
casImpl->setPluginStatusUpdateCallback();
|
||||
}
|
||||
}
|
||||
|
||||
return ScopedAStatus::ok();
|
||||
}
|
||||
|
||||
ScopedAStatus MediaCasService::isDescramblerSupported(int32_t CA_system_id, bool* _aidl_return) {
|
||||
ALOGV("%s: CA_system_id=%d", __FUNCTION__, CA_system_id);
|
||||
|
||||
*_aidl_return = mDescramblerLoader.findFactoryForScheme(CA_system_id);
|
||||
return ScopedAStatus::ok();
|
||||
}
|
||||
|
||||
ScopedAStatus MediaCasService::createDescrambler(int32_t CA_system_id,
|
||||
shared_ptr<IDescrambler>* _aidl_return) {
|
||||
ALOGV("%s: CA_system_id=%d", __FUNCTION__, CA_system_id);
|
||||
|
||||
DescramblerFactory* factory;
|
||||
shared_ptr<SharedLibrary> library;
|
||||
if (mDescramblerLoader.findFactoryForScheme(CA_system_id, &library, &factory)) {
|
||||
DescramblerPlugin* plugin = NULL;
|
||||
if (factory->createPlugin(CA_system_id, &plugin) == OK && plugin != NULL) {
|
||||
*_aidl_return = ::ndk::SharedRefBase::make<DescramblerImpl>(plugin);
|
||||
}
|
||||
}
|
||||
|
||||
return ScopedAStatus::ok();
|
||||
}
|
||||
|
||||
} // namespace cas
|
||||
} // namespace hardware
|
||||
} // namespace android
|
||||
} // namespace aidl
|
59
cas/aidl/default/MediaCasService.h
Executable file
59
cas/aidl/default/MediaCasService.h
Executable file
|
@ -0,0 +1,59 @@
|
|||
/*
|
||||
* Copyright (C) 2022 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.
|
||||
*/
|
||||
#include <aidl/android/hardware/cas/BnMediaCasService.h>
|
||||
#include <media/cas/DescramblerAPI.h>
|
||||
|
||||
#include "FactoryLoader.h"
|
||||
|
||||
namespace aidl {
|
||||
namespace android {
|
||||
namespace hardware {
|
||||
namespace cas {
|
||||
|
||||
using namespace ::android;
|
||||
using namespace std;
|
||||
using ndk::ScopedAStatus;
|
||||
|
||||
class MediaCasService : public BnMediaCasService {
|
||||
public:
|
||||
MediaCasService();
|
||||
|
||||
virtual ScopedAStatus enumeratePlugins(
|
||||
vector<AidlCasPluginDescriptor>* aidlCasPluginDescriptors) override;
|
||||
|
||||
virtual ScopedAStatus isSystemIdSupported(int32_t in_CA_system_id, bool* _aidl_return) override;
|
||||
|
||||
virtual ScopedAStatus createPlugin(int32_t in_CA_system_id,
|
||||
const shared_ptr<ICasListener>& in_listener,
|
||||
shared_ptr<ICas>* _aidl_return) override;
|
||||
|
||||
virtual ScopedAStatus isDescramblerSupported(int32_t in_CA_system_id,
|
||||
bool* _aidl_return) override;
|
||||
|
||||
virtual ScopedAStatus createDescrambler(int32_t in_CA_system_id,
|
||||
shared_ptr<IDescrambler>* _aidl_return) override;
|
||||
|
||||
private:
|
||||
FactoryLoader<CasFactory> mCasLoader;
|
||||
FactoryLoader<DescramblerFactory> mDescramblerLoader;
|
||||
|
||||
virtual ~MediaCasService();
|
||||
};
|
||||
|
||||
} // namespace cas
|
||||
} // namespace hardware
|
||||
} // namespace android
|
||||
} // namespace aidl
|
3
cas/aidl/default/OWNERS
Executable file
3
cas/aidl/default/OWNERS
Executable file
|
@ -0,0 +1,3 @@
|
|||
# Bug component: 1344
|
||||
quxiangfang@google.com
|
||||
hgchen@google.com
|
61
cas/aidl/default/SharedLibrary.cpp
Executable file
61
cas/aidl/default/SharedLibrary.cpp
Executable file
|
@ -0,0 +1,61 @@
|
|||
/*
|
||||
* Copyright (C) 2022 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_TAG "android.hardware.cas-SharedLibrary"
|
||||
|
||||
#include "SharedLibrary.h"
|
||||
#include <dlfcn.h>
|
||||
#include <utils/Log.h>
|
||||
|
||||
namespace aidl {
|
||||
namespace android {
|
||||
namespace hardware {
|
||||
namespace cas {
|
||||
|
||||
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 cas
|
||||
} // namespace hardware
|
||||
} // namespace android
|
||||
} // namespace aidl
|
45
cas/aidl/default/SharedLibrary.h
Executable file
45
cas/aidl/default/SharedLibrary.h
Executable file
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* Copyright (C) 2022 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.
|
||||
*/
|
||||
|
||||
#include <android/binder_interface_utils.h>
|
||||
#include <media/stagefright/foundation/ABase.h>
|
||||
#include <utils/String8.h>
|
||||
|
||||
namespace aidl {
|
||||
namespace android {
|
||||
namespace hardware {
|
||||
namespace cas {
|
||||
|
||||
using namespace ::android;
|
||||
|
||||
class SharedLibrary : public ndk::SharedRefBase {
|
||||
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 cas
|
||||
} // namespace hardware
|
||||
} // namespace android
|
||||
} // namespace aidl
|
110
cas/aidl/default/TypeConvert.cpp
Executable file
110
cas/aidl/default/TypeConvert.cpp
Executable file
|
@ -0,0 +1,110 @@
|
|||
/*
|
||||
* Copyright (C) 2022 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_TAG "android.hardware.cas-TypeConvert"
|
||||
|
||||
#include <aidl/android/hardware/cas/Status.h>
|
||||
#include <utils/Log.h>
|
||||
|
||||
#include "TypeConvert.h"
|
||||
|
||||
namespace aidl {
|
||||
namespace android {
|
||||
namespace hardware {
|
||||
namespace cas {
|
||||
|
||||
ScopedAStatus toStatus(status_t legacyStatus) {
|
||||
int status;
|
||||
switch (legacyStatus) {
|
||||
case OK:
|
||||
return ndk::ScopedAStatus::ok();
|
||||
case ERROR_CAS_NO_LICENSE:
|
||||
status = Status::ERROR_CAS_NO_LICENSE;
|
||||
break;
|
||||
case ERROR_CAS_LICENSE_EXPIRED:
|
||||
status = Status::ERROR_CAS_LICENSE_EXPIRED;
|
||||
break;
|
||||
case ERROR_CAS_SESSION_NOT_OPENED:
|
||||
status = Status::ERROR_CAS_SESSION_NOT_OPENED;
|
||||
break;
|
||||
case ERROR_CAS_CANNOT_HANDLE:
|
||||
status = Status::ERROR_CAS_CANNOT_HANDLE;
|
||||
break;
|
||||
case ERROR_CAS_TAMPER_DETECTED:
|
||||
status = Status::ERROR_CAS_INVALID_STATE;
|
||||
break;
|
||||
case BAD_VALUE:
|
||||
status = Status::BAD_VALUE;
|
||||
break;
|
||||
case ERROR_CAS_NOT_PROVISIONED:
|
||||
status = Status::ERROR_CAS_NOT_PROVISIONED;
|
||||
break;
|
||||
case ERROR_CAS_RESOURCE_BUSY:
|
||||
status = Status::ERROR_CAS_RESOURCE_BUSY;
|
||||
break;
|
||||
case ERROR_CAS_INSUFFICIENT_OUTPUT_PROTECTION:
|
||||
status = Status::ERROR_CAS_INSUFFICIENT_OUTPUT_PROTECTION;
|
||||
break;
|
||||
case ERROR_CAS_DEVICE_REVOKED:
|
||||
status = Status::ERROR_CAS_DEVICE_REVOKED;
|
||||
break;
|
||||
case ERROR_CAS_DECRYPT_UNIT_NOT_INITIALIZED:
|
||||
status = Status::ERROR_CAS_DECRYPT_UNIT_NOT_INITIALIZED;
|
||||
break;
|
||||
case ERROR_CAS_DECRYPT:
|
||||
status = Status::ERROR_CAS_DECRYPT;
|
||||
break;
|
||||
case ERROR_CAS_NEED_ACTIVATION:
|
||||
status = Status::ERROR_CAS_NEED_ACTIVATION;
|
||||
break;
|
||||
case ERROR_CAS_NEED_PAIRING:
|
||||
status = Status::ERROR_CAS_NEED_PAIRING;
|
||||
break;
|
||||
case ERROR_CAS_NO_CARD:
|
||||
status = Status::ERROR_CAS_NO_CARD;
|
||||
break;
|
||||
case ERROR_CAS_CARD_MUTE:
|
||||
status = Status::ERROR_CAS_CARD_MUTE;
|
||||
break;
|
||||
case ERROR_CAS_CARD_INVALID:
|
||||
status = Status::ERROR_CAS_CARD_INVALID;
|
||||
break;
|
||||
case ERROR_CAS_BLACKOUT:
|
||||
status = Status::ERROR_CAS_BLACKOUT;
|
||||
break;
|
||||
default:
|
||||
ALOGW("Unable to convert legacy status: %d, defaulting to UNKNOWN", legacyStatus);
|
||||
status = Status::ERROR_CAS_UNKNOWN;
|
||||
break;
|
||||
}
|
||||
return ScopedAStatus::fromServiceSpecificError(status);
|
||||
}
|
||||
|
||||
String8 sessionIdToString(const std::vector<uint8_t>& sessionId) {
|
||||
String8 result;
|
||||
for (auto it = sessionId.begin(); it != sessionId.end(); it++) {
|
||||
result.appendFormat("%02x ", *it);
|
||||
}
|
||||
if (result.isEmpty()) {
|
||||
result.append("(null)");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace cas
|
||||
} // namespace hardware
|
||||
} // namespace android
|
||||
} // namespace aidl
|
36
cas/aidl/default/TypeConvert.h
Executable file
36
cas/aidl/default/TypeConvert.h
Executable file
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* Copyright (C) 2022 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.
|
||||
*/
|
||||
|
||||
#include <android/binder_interface_utils.h>
|
||||
#include <media/stagefright/MediaErrors.h>
|
||||
#include <utils/String8.h>
|
||||
|
||||
namespace aidl {
|
||||
namespace android {
|
||||
namespace hardware {
|
||||
namespace cas {
|
||||
|
||||
using namespace ::android;
|
||||
using ndk::ScopedAStatus;
|
||||
|
||||
ScopedAStatus toStatus(status_t legacyStatus);
|
||||
|
||||
String8 sessionIdToString(const std::vector<uint8_t>& sessionId);
|
||||
|
||||
} // namespace cas
|
||||
} // namespace hardware
|
||||
} // namespace android
|
||||
} // namespace aidl
|
6
cas/aidl/default/android.hardware.cas-service.xml
Executable file
6
cas/aidl/default/android.hardware.cas-service.xml
Executable file
|
@ -0,0 +1,6 @@
|
|||
<manifest version="1.0" type="device">
|
||||
<hal format="aidl">
|
||||
<name>android.hardware.cas</name>
|
||||
<fqname>IMediaCasService/default</fqname>
|
||||
</hal>
|
||||
</manifest>
|
9
cas/aidl/default/cas-default-lazy.rc
Executable file
9
cas/aidl/default/cas-default-lazy.rc
Executable file
|
@ -0,0 +1,9 @@
|
|||
service vendor.cas-default-lazy /vendor/bin/hw/android.hardware.cas-service.example-lazy
|
||||
interface aidl android.hardware.cas.IMediaCasService/default
|
||||
class hal
|
||||
user media
|
||||
group mediadrm drmrpc
|
||||
ioprio rt 4
|
||||
task_profiles ProcessCapacityHigh
|
||||
oneshot
|
||||
disabled
|
7
cas/aidl/default/cas-default.rc
Executable file
7
cas/aidl/default/cas-default.rc
Executable file
|
@ -0,0 +1,7 @@
|
|||
service vendor.cas-default /vendor/bin/hw/android.hardware.cas-service.example
|
||||
interface aidl android.hardware.cas.IMediaCasService/default
|
||||
class hal
|
||||
user media
|
||||
group mediadrm drmrpc
|
||||
ioprio rt 4
|
||||
task_profiles ProcessCapacityHigh
|
30
cas/aidl/default/fuzzer.cpp
Executable file
30
cas/aidl/default/fuzzer.cpp
Executable file
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
* Copyright (C) 2022 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.
|
||||
*/
|
||||
#include <MediaCasService.h>
|
||||
#include <fuzzbinder/libbinder_ndk_driver.h>
|
||||
#include <fuzzer/FuzzedDataProvider.h>
|
||||
|
||||
using aidl::android::hardware::cas::MediaCasService;
|
||||
using android::fuzzService;
|
||||
using ndk::SharedRefBase;
|
||||
|
||||
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
|
||||
auto mediaCasServiceAidl = SharedRefBase::make<MediaCasService>();
|
||||
|
||||
fuzzService(mediaCasServiceAidl->asBinder().get(), FuzzedDataProvider(data, size));
|
||||
|
||||
return 0;
|
||||
}
|
50
cas/aidl/default/service.cpp
Executable file
50
cas/aidl/default/service.cpp
Executable file
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* Copyright 2022 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.
|
||||
*/
|
||||
|
||||
#ifdef LAZY_SERVICE
|
||||
const bool kLazyService = true;
|
||||
#define LOG_TAG "android.hardware.cas-service.example-lazy"
|
||||
#else
|
||||
const bool kLazyService = false;
|
||||
#define LOG_TAG "android.hardware.cas-service.example"
|
||||
#endif
|
||||
|
||||
#include <android/binder_manager.h>
|
||||
#include <android/binder_process.h>
|
||||
|
||||
#include "MediaCasService.h"
|
||||
|
||||
using aidl::android::hardware::cas::MediaCasService;
|
||||
|
||||
int main() {
|
||||
ABinderProcess_setThreadPoolMaxThreadCount(8);
|
||||
|
||||
// Setup hwbinder service
|
||||
std::shared_ptr<MediaCasService> service = ::ndk::SharedRefBase::make<MediaCasService>();
|
||||
|
||||
const std::string instance = std::string() + MediaCasService::descriptor + "/default";
|
||||
binder_status_t status;
|
||||
|
||||
if (kLazyService) {
|
||||
status = AServiceManager_registerLazyService(service->asBinder().get(), instance.c_str());
|
||||
} else {
|
||||
status = AServiceManager_addService(service->asBinder().get(), instance.c_str());
|
||||
}
|
||||
LOG_ALWAYS_FATAL_IF(status != STATUS_OK, "Error while registering cas service: %d", status);
|
||||
|
||||
ABinderProcess_joinThreadPool();
|
||||
return 0;
|
||||
}
|
Loading…
Reference in a new issue