You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
400 lines
12 KiB
400 lines
12 KiB
/*
|
|
* Copyright (c) Hisilicon Technologies Co., Ltd. 2012-2021. All rights reserved.
|
|
* Description: hidl interface of DTV
|
|
*/
|
|
|
|
#define LOG_TAG "Hwdtv"
|
|
|
|
#include "Hwdtv.h"
|
|
#include <hardware/hardware.h>
|
|
#include <log/log_main.h>
|
|
#include <binder/Parcel.h>
|
|
#include <binder/ProcessState.h>
|
|
#include <cinttypes>
|
|
|
|
#include <dlfcn.h>
|
|
#include <android/hidl/memory/1.0/IMemory.h>
|
|
#include <securec.h>
|
|
|
|
const SVR_S32 DTV_COST_TIME = 1000;
|
|
|
|
namespace vendor {
|
|
namespace huanglong {
|
|
namespace hardware {
|
|
namespace hwdtv {
|
|
namespace V1_0 {
|
|
namespace implementation {
|
|
using ::vendor::huanglong::hardware::hwdtv::V1_0::IHwdtv;
|
|
using ::vendor::huanglong::hardware::hwdtv::V1_0::IHwdtvCallback;
|
|
using ::android::hardware::hidl_string;
|
|
using ::android::hardware::Return;
|
|
using ::android::hardware::Void;
|
|
using ::android::String8;
|
|
using ::android::hardware::hidl_memory;
|
|
using ::android::hidl::memory::V1_0::IMemory;
|
|
|
|
#define DTV_LIB_DIR "/vendor/lib/"
|
|
#define CHECK_DOFUNC(func) \
|
|
do { \
|
|
int32_t ret = 0; \
|
|
ret = func; \
|
|
if (ret != SVR_SUCCESS) { \
|
|
ALOGE("[%s] strncpy_s failed!", #func); \
|
|
}; \
|
|
} while (0)
|
|
|
|
#define CHECK_DOFUNC_SECURE_RETURN(func) \
|
|
do { \
|
|
int32_t ret = 0; \
|
|
ret = func; \
|
|
if (ret != EOK) { \
|
|
ALOGE("[%s] strncpy_s failed!", #func); \
|
|
return SVR_FAILURE; \
|
|
}; \
|
|
} while (0)
|
|
|
|
class DtvDeathRecipient : public hidl_death_recipient {
|
|
public:
|
|
explicit DtvDeathRecipient(const sp<Hwdtv> hDtv) : mHwDtv(hDtv)
|
|
{
|
|
}
|
|
~DtvDeathRecipient()
|
|
{
|
|
}
|
|
|
|
virtual void serviceDied(uint64_t cookie, const wp<::android::hidl::base::V1_0::IBase>&)
|
|
{
|
|
// handle death notify
|
|
ALOGE("serviceDied cookie = 0x%" PRIu64, cookie);
|
|
mHwDtv->onObjectDeath(cookie);
|
|
}
|
|
|
|
private:
|
|
sp<Hwdtv> mHwDtv;
|
|
};
|
|
|
|
Hwdtv::Hwdtv() : mDeathRecipient(new DtvDeathRecipient(this))
|
|
{
|
|
ALOGW("Hwdtv constructor");
|
|
setPlugins("dtv-live://plugin.libdol_dtvplg");
|
|
}
|
|
|
|
// Methods from ::vendor::huanglong::hardware::Hwdtv::V1_0::IHwdtv follow.
|
|
Return<int32_t> Hwdtv::setPlugins(const hidl_string& path)
|
|
{
|
|
ALOGE("Hwdtv setPlugins");
|
|
registerPlugin(path.c_str());
|
|
return 0;
|
|
}
|
|
|
|
Return<void> Hwdtv::getCapBuffer(uint32_t id, getCapBuffer_cb _hidl_cb)
|
|
{
|
|
ALOGE("Hwdtv getCapBuffer id = %u", id);
|
|
hidl_memory mBuffer = {};
|
|
_hidl_cb(mBuffer);
|
|
return Void();
|
|
}
|
|
|
|
Return<void> Hwdtv::hwInvoke(const hidl_string& request, hwInvoke_cb _hidl_cb)
|
|
{
|
|
const char* data = request.c_str();
|
|
int length = static_cast<int>(request.size());
|
|
|
|
android::Parcel parcelReq;
|
|
android::Parcel parcelReply;
|
|
|
|
parcelReq.write(data, length);
|
|
parcelReq.setDataPosition(0);
|
|
|
|
int32_t ret = invoke(parcelReq, &parcelReply);
|
|
hidl_string inputStr(reinterpret_cast<const char *>(parcelReply.data()), parcelReply.dataSize());
|
|
_hidl_cb(ret, inputStr);
|
|
return Void();
|
|
}
|
|
|
|
Return<void> Hwdtv::disconnect()
|
|
{
|
|
return Void();
|
|
}
|
|
|
|
Return<void> Hwdtv::onObjectDeath(uint64_t cookie)
|
|
{
|
|
Mutex::Autolock autoLock(mNotifyLock);
|
|
|
|
IHwdtvCallback* cb = reinterpret_cast<IHwdtvCallback *>((uintptr_t)cookie);
|
|
std::vector<sp<IHwdtvCallback>>::iterator itr = mCallbacks.begin();
|
|
while (itr != mCallbacks.end()) {
|
|
if (*itr == cb) {
|
|
ALOGD("delete callback");
|
|
itr = mCallbacks.erase(itr);
|
|
} else {
|
|
itr++;
|
|
}
|
|
}
|
|
|
|
ALOGD("after delete callback count = %u", mCallbacks.size());
|
|
return Void();
|
|
}
|
|
|
|
Return<int32_t> Hwdtv::setCallback(const sp<IHwdtvCallback>& callback)
|
|
{
|
|
ALOGD("Hwdtv setCallback");
|
|
|
|
if (callback == NULL) {
|
|
ALOGE("callback is NULL!\n");
|
|
return SVR_FAILURE;
|
|
}
|
|
Mutex::Autolock autoLock(mNotifyLock);
|
|
|
|
uint64_t cookie = (uint64_t)(uintptr_t)(callback.get());
|
|
if (!callback->linkToDeath(mDeathRecipient, cookie)) {
|
|
ALOGE("setCallback Failed to register death notification");
|
|
return -1;
|
|
}
|
|
|
|
mCallbacks.push_back(callback);
|
|
return 0;
|
|
}
|
|
|
|
Return<int32_t> Hwdtv::registerPlugin(const SVR_CHAR* pcUrl)
|
|
{
|
|
DOL_DTV_PLUGIN_S *pPlugin = NULL;
|
|
SVR_CHAR acRealLibPath[PATH_MAX];
|
|
|
|
if (pcUrl == NULL) {
|
|
return SVR_FAILURE;
|
|
}
|
|
|
|
Mutex::Autolock lock(mLock);
|
|
|
|
SVR_CHAR *p = NULL;
|
|
SVR_CHAR acLibName[DTV_PLUGIN_PATH_LENGTH];
|
|
SVR_CHAR acLibPath[DTV_PLUGIN_PATH_LENGTH];
|
|
SVR_CHAR acTmp[DTV_PLUGIN_PATH_LENGTH];
|
|
SVR_U32 u32Length = 0;
|
|
const SVR_U32 suffixLen = 4; // 4 is length for ".so\0"
|
|
|
|
CHECK_DOFUNC(memset_s(acTmp, sizeof(acTmp), 0, sizeof(acTmp)));
|
|
CHECK_DOFUNC_SECURE_RETURN(strncpy_s(acTmp, sizeof(acTmp), pcUrl, sizeof(acTmp) - 1));
|
|
|
|
while ((p = strrchr(acTmp, '.')) != NULL) {
|
|
CHECK_DOFUNC(memset_s(acLibName, sizeof(acLibName), 0, sizeof(acLibName)));
|
|
CHECK_DOFUNC(memset_s(acLibPath, sizeof(acLibPath), 0, sizeof(acLibPath)));
|
|
|
|
u32Length = strlen(p + 1);
|
|
if (u32Length > (DTV_PLUGIN_PATH_LENGTH - suffixLen)) {
|
|
ALOGE("%s plugin path too long", __FUNCTION__);
|
|
break;
|
|
}
|
|
|
|
CHECK_DOFUNC_SECURE_RETURN(strncpy_s(acLibName, sizeof(acLibName), p + 1, u32Length));
|
|
acLibName[DTV_PLUGIN_PATH_LENGTH - suffixLen] = '\0';
|
|
|
|
SVR_S32 len = snprintf_s(acLibPath, sizeof(acLibPath), sizeof(acLibPath) - 1, "%s%s%s",
|
|
(DTV_LIB_DIR), acLibName, ".so");
|
|
if (len < 0) {
|
|
ALOGE("[%s] strncpy_s failed!", __FUNCTION__);
|
|
return SVR_FAILURE;
|
|
}
|
|
acLibPath[DTV_PLUGIN_PATH_LENGTH - 1] = '\0';
|
|
|
|
ALOGD("enter setPlugin libName = %s", acLibPath);
|
|
*p = '\0';
|
|
}
|
|
|
|
CHECK_DOFUNC(memset_s(acRealLibPath, sizeof(acRealLibPath), 0, sizeof(acRealLibPath)));
|
|
if (strlen(acLibPath) > (DTV_PLUGIN_PATH_LENGTH - 1) || NULL == realpath(acLibPath, acRealLibPath)) {
|
|
ALOGE("url is %s error no 0x%x\n", acRealLibPath, errno);
|
|
return SVR_FAILURE;
|
|
}
|
|
|
|
SVR_U32 urlLength = strlen(acRealLibPath);
|
|
if (urlLength >= DTV_PLUGIN_PATH_LENGTH) {
|
|
ALOGE("URL length over %d error.", DTV_PLUGIN_PATH_LENGTH);
|
|
return SVR_FAILURE;
|
|
}
|
|
|
|
ALOGD("regist DTV plugin %s", acRealLibPath);
|
|
|
|
for (SVR_U32 i = 0; i < mPluginList.size(); i++) {
|
|
if (strcmp(mPluginList[i]->acLibName, acRealLibPath) == 0) {
|
|
ALOGI("plugin[%s] already opened ", acRealLibPath);
|
|
return SVR_SUCCESS;
|
|
}
|
|
}
|
|
SVR_S32 ret;
|
|
do {
|
|
pPlugin = reinterpret_cast<DOL_DTV_PLUGIN_S *>(malloc(sizeof(DOL_DTV_PLUGIN_S)));
|
|
if (pPlugin == SVR_NULL) {
|
|
ALOGE("[%s], malloc() failed\n", __FUNCTION__);
|
|
return SVR_FAILURE;
|
|
}
|
|
|
|
ret = memcpy_s(pPlugin->acLibName, sizeof(pPlugin->acLibName), acRealLibPath, urlLength + 1);
|
|
if (ret != EOK) {
|
|
ALOGE("memcpy_s failed, ret: %d\n", ret);
|
|
free(pPlugin);
|
|
pPlugin = SVR_NULL;
|
|
return SVR_FAILURE;
|
|
}
|
|
|
|
pPlugin->pHandle = dlopen(acRealLibPath, RTLD_NOW);
|
|
if (!pPlugin->pHandle) {
|
|
ALOGE("dlopen(%s) failed, err: %s\n", acRealLibPath, dlerror());
|
|
free(pPlugin);
|
|
pPlugin = SVR_NULL;
|
|
return SVR_FAILURE;
|
|
}
|
|
|
|
pPlugin->fnCreateInstance = (PFN_CREATE_PLUGIN)dlsym(pPlugin->pHandle, "createInstance");
|
|
pPlugin->fnDestroyInstance = (PFN_DESTROY_PLUGIN)dlsym(pPlugin->pHandle, "destroyInstance");
|
|
if ((pPlugin->fnCreateInstance == SVR_NULL) || (pPlugin->fnDestroyInstance == SVR_NULL)) {
|
|
ALOGE("dlsym err: %s\n", dlerror());
|
|
dlclose(pPlugin->pHandle);
|
|
free(pPlugin);
|
|
pPlugin = SVR_NULL;
|
|
return SVR_FAILURE;
|
|
}
|
|
|
|
pPlugin->pInstance = pPlugin->fnCreateInstance();
|
|
if (pPlugin->pInstance == SVR_NULL) {
|
|
ALOGD("Create %s Instance failed \n", acRealLibPath);
|
|
dlclose(pPlugin->pHandle);
|
|
free(pPlugin);
|
|
pPlugin = SVR_NULL;
|
|
return SVR_FAILURE;
|
|
}
|
|
|
|
ALOGD("Create Instance OK \n");
|
|
|
|
pPlugin->pInstance->regMsgHandler(this);
|
|
mPluginList.add(pPlugin);
|
|
} while (0);
|
|
|
|
return SVR_SUCCESS;
|
|
}
|
|
|
|
status_t Hwdtv::notify(SVR_S32 s32Msg, SVR_S32 s32Ext1, SVR_S32 s32Ext2, SVR_S32 s32Ext3,
|
|
const Parcel* pParcelObj, Parcel* pParcelReply)
|
|
{
|
|
SVR_S32 i = 0;
|
|
|
|
Mutex::Autolock autoLock(mNotifyLock);
|
|
|
|
SVR_S32 s32Len = (SVR_S32)mCallbacks.size();
|
|
ALOGD("notify: callback count = %d", s32Len);
|
|
hidl_string inputStr = nullptr;
|
|
|
|
if (pParcelObj != NULL && pParcelObj->dataSize() > 0) {
|
|
hidl_string tmpInputStr((const char *)pParcelObj->data(), pParcelObj->dataSize());
|
|
inputStr = tmpInputStr;
|
|
}
|
|
|
|
for (i = 0; i < s32Len; i++) {
|
|
if (mCallbacks[i] != nullptr) {
|
|
String8 retReply;
|
|
auto cb = [&](hidl_string strReply) {
|
|
retReply = String8(strReply.c_str(), strReply.size());
|
|
};
|
|
if (!mCallbacks[i]->ping().isOk()) {
|
|
ALOGE("NotifyCb ping failed...");
|
|
continue;
|
|
}
|
|
auto _hidl_err = mCallbacks[i]->hwNotify(s32Msg, s32Ext1, s32Ext2, s32Ext3, inputStr, cb);
|
|
if (!_hidl_err.isOk() || _hidl_err.isDeadObject()) {
|
|
ALOGE("hwNotify failed, client is nok or isDeadObject!\n");
|
|
continue;
|
|
}
|
|
|
|
if (pParcelReply != NULL) {
|
|
pParcelReply->write(retReply.c_str(), retReply.size());
|
|
pParcelReply->setDataPosition(0);
|
|
}
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
inline status_t Hwdtv::invoke(const android::Parcel& request, android::Parcel* reply)
|
|
{
|
|
SVR_BOOL invokeFlag = SVR_FALSE;
|
|
|
|
Mutex::Autolock lock(mLock);
|
|
|
|
SVR_U32 pluginCount = mPluginList.size();
|
|
if (pluginCount == 0) {
|
|
ALOGE("invoke the PluginList is TD_NULL\n");
|
|
return PLUGIN_NOT_IMPLIMENT;
|
|
}
|
|
|
|
// read DTV_INTERFACE_NAME
|
|
#if (PLATFORM_SDK_VERSION < 29) // 29 for AndroidQ
|
|
(SVR_VOID)request.readInt32();
|
|
(SVR_VOID)request.readString16();
|
|
#elif (PLATFORM_SDK_VERSION == 29)
|
|
// writeInterfaceToken is changed from P to Q
|
|
(SVR_VOID)request.readInt32();
|
|
(SVR_VOID)request.readInt32();
|
|
(SVR_VOID)request.readString16();
|
|
#elif (PLATFORM_SDK_VERSION == 31)
|
|
(SVR_VOID)request.readInt64();
|
|
(SVR_VOID)request.readInt64();
|
|
(SVR_VOID)request.readInt64();
|
|
(SVR_VOID)request.readInt64();
|
|
(SVR_VOID)request.readInt64();
|
|
(SVR_VOID)request.readInt64();
|
|
(SVR_VOID)request.readInt64();
|
|
(SVR_VOID)request.readInt64();
|
|
#endif
|
|
|
|
size_t requestPos = request.dataPosition();
|
|
SVR_U32 cmd = static_cast<SVR_U32>(request.readInt32());
|
|
|
|
for (SVR_U32 i = 0; i < pluginCount; i++) {
|
|
/* CMD must be between in [startCmd,endCmd] */
|
|
if ((cmd >= mPluginList[i]->pInstance->getStartCmd()) &&
|
|
(cmd <= mPluginList[i]->pInstance->getEndCmd())) {
|
|
struct timespec tsStart, tsEnd;
|
|
SVR_U32 timeMs = 0;
|
|
(SVR_VOID)clock_gettime(CLOCK_MONOTONIC, &tsStart);
|
|
|
|
request.setDataPosition(requestPos);
|
|
if (cmd != 0x901 && cmd != 0x903 && cmd != 0x905) { // 0x901~905 is getTime cmd
|
|
ALOGD("+++before cmd =0x%x", cmd);
|
|
}
|
|
mPluginList[i]->pInstance->invoke(request, reply);
|
|
if (cmd != 0x901 && cmd != 0x903 && cmd != 0x905) { // 0x901~905 is getTime cmd
|
|
ALOGD("---after cmd =0x%x", cmd);
|
|
}
|
|
invokeFlag = SVR_TRUE;
|
|
|
|
(SVR_VOID)clock_gettime(CLOCK_MONOTONIC, &tsEnd);
|
|
/* 1000 for s and 1000000 for ns */
|
|
timeMs = (SVR_U32)((tsEnd.tv_sec - tsStart.tv_sec) * 1000 + (tsEnd.tv_nsec - tsStart.tv_nsec) / 1000000);
|
|
if (timeMs > DTV_COST_TIME) {
|
|
ALOGE("DTV command %#x cost too much time %d ms\n", cmd, timeMs);
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (invokeFlag == SVR_FALSE && (reply != NULL)) {
|
|
reply->writeInt32(SVR_FAILURE);
|
|
}
|
|
|
|
return ((invokeFlag == SVR_TRUE) ? (status_t)SVR_SUCCESS : (status_t)PLUGIN_NOT_IMPLIMENT);
|
|
}
|
|
|
|
|
|
IHwdtv *HIDL_FETCH_IHwdtv(const char *)
|
|
{
|
|
return new Hwdtv();
|
|
}
|
|
} // namespace implementation
|
|
} // namespace V1_0
|
|
} // namespace hwdtv
|
|
} // namespace hardware
|
|
} // namespace huanglong
|
|
} // namespace vendor
|