diff --git a/ccec/src/DriverImpl.cpp b/ccec/src/DriverImpl.cpp index ec6c7989..4f5f6a03 100644 --- a/ccec/src/DriverImpl.cpp +++ b/ccec/src/DriverImpl.cpp @@ -36,7 +36,6 @@ #include #include #include -#include #include #include @@ -46,6 +45,7 @@ #include "ccec/Exception.hpp" #include "DriverImpl.hpp" #include "ccec/OpCode.hpp" +#include "factoryImpl/HDMICecHalFactory.h" using CCEC_OSAL::AutoLock; @@ -71,7 +71,6 @@ void DriverImpl::DriverReceiveCallback(int handle, void *callbackData, unsigned } catch(...) { CCEC_LOG( LOG_EXP, "Exception during frame offer...discarding\r\n"); - // Copilot fix: Delete frame to prevent memory leak when offer() throws exception delete frame; } CCEC_LOG( LOG_DEBUG, "frame offered\r\n"); @@ -86,6 +85,7 @@ void DriverImpl::DriverTransmitCallback(int handle, void *callbackData, int resu DriverImpl::DriverImpl() : status(CLOSED), nativeHandle(0) { + mHal = HDMICecHalFactory::Create(); CCEC_LOG( LOG_DEBUG, "Creating DriverImpl done\r\n"); } @@ -108,6 +108,7 @@ DriverImpl::~DriverImpl() void DriverImpl::open(void) noexcept(false) { {AutoLock lock_(mutex); + CCEC_LOG( LOG_INFO, "DriverImpl::open invoked\r\n"); if (status != CLOSED) { #if 0 throw InvalidStateException(); @@ -116,14 +117,17 @@ void DriverImpl::open(void) noexcept(false) #endif } - int err = HdmiCecOpen(&nativeHandle); + int err = mHal->open(&nativeHandle); + CCEC_LOG( LOG_INFO, "DriverImpl::open mHal->open returned %d, handle=%d\r\n", err, nativeHandle); if (err != HDMI_CEC_IO_SUCCESS) { throw IOException(); } - HdmiCecSetRxCallback(nativeHandle, DriverReceiveCallback, 0); - HdmiCecSetTxCallback(nativeHandle, DriverTransmitCallback, 0); + mHal->setRxCallback(nativeHandle, DriverReceiveCallback, 0); + mHal->setTxCallback(nativeHandle, DriverTransmitCallback, 0); + status = OPENED; + CCEC_LOG( LOG_INFO, "DriverImpl::open completed successfully\r\n"); } } @@ -143,7 +147,7 @@ void DriverImpl::close(void) noexcept(false) /* Use NULL as sentinel */ rQueue.offer(0); - int err = HdmiCecClose(nativeHandle); + int err = mHal->close(nativeHandle); if (err != HDMI_CEC_IO_SUCCESS) { status = CLOSED; throw IOException(); @@ -204,12 +208,13 @@ void DriverImpl::writeAsync(const CECFrame &frame) noexcept(false) printFrameDetails(frame); {AutoLock lock_(mutex); - if (status != OPENED) { + if (status != OPENED) { throw InvalidStateException(); } + CCEC_LOG( LOG_DEBUG, "DriverImpl::write to call HdmiCecTxAsync\r\n"); - int err = HdmiCecTxAsync(nativeHandle, buf, length); + int err = mHal->txAsync(nativeHandle, buf, length); CCEC_LOG( LOG_DEBUG, ">>>>>>> >>>>> >>>> >> >> >\r\n"); @@ -222,8 +227,7 @@ void DriverImpl::writeAsync(const CECFrame &frame) noexcept(false) if (err != HDMI_CEC_IO_SUCCESS) { throw IOException(); } - - } + } CCEC_LOG( LOG_DEBUG, "Send Async Completed\r\n"); } @@ -248,7 +252,7 @@ void DriverImpl::write(const CECFrame &frame) noexcept(false) int sendResult = HDMI_CEC_IO_SUCCESS; CCEC_LOG( LOG_DEBUG, "DriverImpl::write to call HdmiCecTx\r\n"); - int err = HdmiCecTx(nativeHandle, buf, length, &sendResult); + int err = mHal->tx(nativeHandle, buf, length, &sendResult); CCEC_LOG( LOG_DEBUG, ">>>>>>> >>>>> >>>> >> >> >\r\n"); @@ -264,10 +268,10 @@ void DriverImpl::write(const CECFrame &frame) noexcept(false) if (sendResult != HDMI_CEC_IO_SUCCESS) { if ((sendResult == HDMI_CEC_IO_INVALID_HANDLE) || - (sendResult == HDMI_CEC_IO_INVALID_ARGUMENT) || - (sendResult == HDMI_CEC_IO_LOGICALADDRESS_UNAVAILABLE) || - (sendResult == HDMI_CEC_IO_SENT_FAILED) || - (sendResult == HDMI_CEC_IO_GENERAL_ERROR) ) + (sendResult == HDMI_CEC_IO_INVALID_ARGUMENT) || + (sendResult == HDMI_CEC_IO_LOGICALADDRESS_UNAVAILABLE) || + (sendResult == HDMI_CEC_IO_SENT_FAILED) || + (sendResult == HDMI_CEC_IO_GENERAL_ERROR)) { throw IOException(); } @@ -293,7 +297,7 @@ int DriverImpl::getLogicalAddress(int devType) int logicalAddress = 0; CCEC_LOG( LOG_DEBUG, "DriverImpl::getLogicalAddress called for devType : %d \r\n", devType); - HdmiCecGetLogicalAddress(nativeHandle, &logicalAddress); + mHal->getLogicalAddress(nativeHandle, devType, &logicalAddress); CCEC_LOG( LOG_DEBUG, "DriverImpl::getLogicalAddress got logical Address : %d \r\n", logicalAddress); return logicalAddress; @@ -305,7 +309,7 @@ void DriverImpl::getPhysicalAddress(unsigned int *physicalAddress) {AutoLock lock_(mutex); CCEC_LOG( LOG_DEBUG, "DriverImpl::getPhysicalAddress called \r\n"); - HdmiCecGetPhysicalAddress(nativeHandle,physicalAddress); + mHal->getPhysicalAddress(nativeHandle, physicalAddress); CCEC_LOG( LOG_DEBUG, "DriverImpl::getPhysicalAddress got physical Address : %x \r\n", *physicalAddress); return ; @@ -315,14 +319,13 @@ void DriverImpl::getPhysicalAddress(unsigned int *physicalAddress) void DriverImpl::removeLogicalAddress(const LogicalAddress &source) { -// int LA[15] = {0}; {AutoLock lock_(mutex); if (status != OPENED) { throw InvalidStateException(); } logicalAddresses.remove(source); - HdmiCecRemoveLogicalAddress(nativeHandle, source.toInt()); + mHal->removeLogicalAddress(nativeHandle, source.toInt()); } } @@ -334,7 +337,7 @@ bool DriverImpl::addLogicalAddress(const LogicalAddress &source) throw InvalidStateException(); } - int retErr = HdmiCecAddLogicalAddress(nativeHandle, source.toInt()); + int retErr = mHal->addLogicalAddress(nativeHandle, source.toInt()); if (retErr == HDMI_CEC_IO_LOGICALADDRESS_UNAVAILABLE) { throw AddressNotAvailableException(); diff --git a/ccec/src/DriverImpl.hpp b/ccec/src/DriverImpl.hpp index 59daaf57..64830de8 100644 --- a/ccec/src/DriverImpl.hpp +++ b/ccec/src/DriverImpl.hpp @@ -31,13 +31,14 @@ #define HDMI_CCEC_DRIVER_IMPL_HPP_ #include - +#include #include "osal/Mutex.hpp" #include "osal/EventQueue.hpp" #include "osal/ConditionVariable.hpp" #include "ccec/Driver.hpp" #include "ccec/Header.hpp" +#include "factoryImpl/IHDMICecHal.h" using CCEC_OSAL::EventQueue; using CCEC_OSAL::Mutex; @@ -87,6 +88,8 @@ class DriverImpl : public Driver mutable Mutex mutex; std::list logicalAddresses; + std::unique_ptr mHal; + DriverImpl(const DriverImpl &); /* Not allowed */ DriverImpl & operator = (const DriverImpl &); /* Not allowed */ diff --git a/ccec/src/Makefile b/ccec/src/Makefile index baa6637b..e5510ecb 100755 --- a/ccec/src/Makefile +++ b/ccec/src/Makefile @@ -30,11 +30,39 @@ OBJS:= CECFrame.o \ LibCCEC.o \ OpCode.o \ Util.o \ + factoryImpl/HDMICecHalFactory.o \ + factoryImpl/HDMICecRdkVHAL.o \ + factoryImpl/HDMICecAidlHAL.o \ + factoryImpl/ServiceManagerCheck.o \ + +# Calculate AIDL include path relative to workspace +AIDL_GEN_DIR := $(shell cd ../../.. && pwd)/aidl/rdk-halif-aidl/gen/hdmicec/current +AIDL_H_DIR := $(AIDL_GEN_DIR)/h +BINDER_IDL_DIR := $(shell cd ../../.. && pwd)/aidl/rdk-halif-aidl/build-tools/linux_binder_idl +BINDER_INCLUDE := $(BINDER_IDL_DIR)/android/native/libs/binder/include +BINDER_NDK_INCLUDE := $(BINDER_IDL_DIR)/android/native/libs/binder/ndk/include_cpp +BINDER_UTILS_INCLUDE := $(BINDER_IDL_DIR)/android/core/libutils/include +BINDER_CUTILS_INCLUDE := $(BINDER_IDL_DIR)/android/core/libcutils/include +BINDER_LOG_INCLUDE := $(BINDER_IDL_DIR)/android/logging/liblog/include +BINDER_BASE_INCLUDE := $(BINDER_IDL_DIR)/android/libbase/include +BINDER_BUILD_DIR := $(BINDER_IDL_DIR)/aidl-generator/out + +# Calculate include directory path explicitly +CCEC_INCLUDE_DIR := $(shell cd .. && pwd)/include INCLUDE = -I.\ - -I../include \ + -I$(CCEC_INCLUDE_DIR) \ -I../../osal/include \ -I../drivers/include \ + -IfactoryImpl \ + -I$(AIDL_H_DIR) \ + -I$(BINDER_INCLUDE) \ + -I$(BINDER_NDK_INCLUDE) \ + -I$(BINDER_UTILS_INCLUDE) \ + -I$(BINDER_CUTILS_INCLUDE) \ + -I$(BINDER_LOG_INCLUDE) \ + -I$(BINDER_BASE_INCLUDE) \ + -I$(BINDER_IDL_DIR)/android/native/include \ CFLAGS+= $(INCLUDE) @@ -42,7 +70,17 @@ CFLAGS+= $(INCLUDE) LDFLAGS+= -L$(OPENSOURCE_BASE)/lib LDFLAGS+=-L$(GLIB_LIBRARY_PATH)/ LDFLAGS+=$(GLIBS) -LDFLAGS += -L. -lpthread +LDFLAGS += -L. -lpthread -L../../osal/src/install/lib -lRCECOSHal +# Binder libraries - link if they exist +ifneq ($(wildcard $(BINDER_BUILD_DIR)/libbinder.a),) +LDFLAGS += -L$(BINDER_BUILD_DIR) -lbinder +endif +ifneq ($(wildcard $(BINDER_BUILD_DIR)/libutils.a),) +LDFLAGS += -L$(BINDER_BUILD_DIR) -lutils +endif +ifneq ($(wildcard $(BINDER_BUILD_DIR)/liblog.a),) +LDFLAGS += -L$(BINDER_BUILD_DIR) -llog +endif all: clean library @echo "Build Finished...." @@ -50,7 +88,7 @@ all: clean library library: $(OBJS) @echo "Building $(LIBNAMEFULL) ...." mkdir -p install/lib - $(CXX) $(OBJS) $(CFLAGS) -shared -o install/lib/$(LIBNAMEFULL) + $(CXX) $(OBJS) $(CFLAGS) $(LDFLAGS) -shared -o install/lib/$(LIBNAMEFULL) %.o: %.cpp @echo "Building $@ ...." diff --git a/ccec/src/Makefile.am b/ccec/src/Makefile.am index b7e49a07..6789fc1d 100644 --- a/ccec/src/Makefile.am +++ b/ccec/src/Makefile.am @@ -23,6 +23,7 @@ lib_LTLIBRARIES = libRCEC.la AM_LDFLAGS = -ltelemetry_msgsender +# Main RCEC library libRCEC_la_SOURCES = CECFrame.cpp \ Util.cpp \ DriverImpl.cpp \ @@ -31,7 +32,11 @@ libRCEC_la_SOURCES = CECFrame.cpp \ OpCode.cpp \ Connection.cpp \ Driver.cpp \ - MessageDecoder.cpp + MessageDecoder.cpp \ + factoryImpl/HDMICecHalFactory.cpp \ + factoryImpl/HDMICecRdkVHAL.cpp \ + factoryImpl/HDMICecAidlHAL.cpp \ + factoryImpl/ServiceManagerCheck.cpp libRCEC_la_LDFLAGS = -lpthread -libRCEC_la_LIBADD = -lRCECOSHal -L${top_builddir}/osal/src/.libs +libRCEC_la_LIBADD = ${top_builddir}/osal/src/libRCECOSHal.la diff --git a/ccec/src/factoryImpl/HDMICecAidlHAL.cpp b/ccec/src/factoryImpl/HDMICecAidlHAL.cpp new file mode 100644 index 00000000..ab5b0b94 --- /dev/null +++ b/ccec/src/factoryImpl/HDMICecAidlHAL.cpp @@ -0,0 +1,503 @@ +/* + * If not stated otherwise in this file or this component's LICENSE file the + * following copyright and licenses apply: + * + * Copyright 2026 RDK Management + * + * 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 "HDMICecAidlHAL.h" + +#include +#include +#include +#include +#include + +#include "ccec/Util.hpp" +#include "ccec/Exception.hpp" +#include "ccec/drivers/hdmi_cec_driver.h" + +using CCEC_OSAL::AutoLock; +using android::sp; +using android::String16; +using android::defaultServiceManager; +using android::interface_cast; +using namespace com::rdk::hal::hdmicec; + +/** + * @brief HDMI CEC AIDL Event Listener — bridges binder callbacks to the + * C-style callback function pointers stored in HDMICecAidlHAL. + */ +class HDMICecAidlHALEventListener : public BnHdmiCecEventListener { +public: + HDMICecAidlHALEventListener(HDMICecAidlHAL *AidlHal) + : mAidlHal(AidlHal) {} + + android::binder::Status onMessageReceived(const std::vector& message) override { + if (mAidlHal && !message.empty()) { + std::vector mutableMessage(message); + mAidlHal->dispatchRx(reinterpret_cast(mutableMessage.data()), + static_cast(mutableMessage.size())); + } + return android::binder::Status::ok(); + } + + android::binder::Status onStateChanged(State oldState, State newState) override { + // Handle state changes if needed + return android::binder::Status::ok(); + } + + android::binder::Status onMessageSent(const std::vector& message, SendMessageStatus status) override { + if (mAidlHal) { + int result = HDMI_CEC_IO_SENT_FAILED; + if (status == SendMessageStatus::ACK_STATE_0) { + result = HDMI_CEC_IO_SENT_AND_ACKD; + } else if (status == SendMessageStatus::ACK_STATE_1) { + result = HDMI_CEC_IO_SENT_BUT_NOT_ACKD; + } + mAidlHal->dispatchTx(result); + } + return android::binder::Status::ok(); + } + +private: + HDMICecAidlHAL *mAidlHal; +}; + + +// Return the standard logical-address candidates for a given device type. +// Used only as a fallback when AIDL reports no allocated addresses yet. +std::vector preferredLogicalAddressesForDeviceType(int devType) +{ + // Common CEC type ids used in middleware: + // 0: TV, 1: RecordingDevice, 3: Tuner, 4: PlaybackDevice, 5: AudioSystem. + switch (devType) { + case 0: return std::vector{0}; // TV + case 1: return std::vector{1, 2, 9}; // Recorder + case 3: return std::vector{3, 6, 7, 10}; // Tuner + case 5: return std::vector{5}; // AudioSystem + case 4: + default: + return std::vector{4, 8, 11}; // PlaybackDevice fallback + } +} + +HDMICecAidlHAL::HDMICecAidlHAL() + : mAidlService(nullptr), + mAidlController(nullptr), + mEventListener(nullptr), + mRxCb(nullptr), + mTxCb(nullptr), + mRxCbData(nullptr), + mTxCbData(nullptr) +{ +} + +HDMICecAidlHAL::~HDMICecAidlHAL() +{ + AutoLock lock_(mAidlMutex); + mAidlController = nullptr; + mAidlService = nullptr; + mEventListener = nullptr; +} + +android::sp HDMICecAidlHAL::getAidlService() +{ + AutoLock lock_(mAidlMutex); + if (mAidlService == nullptr) { + initAidlService(); + } + return mAidlService; +} + +void HDMICecAidlHAL::initAidlService() +{ + android::ProcessState::self()->startThreadPool(); + + sp sm = defaultServiceManager(); + if (sm != nullptr) { + mAidlService = interface_cast( + sm->getService(String16(IHdmiCec::serviceName().c_str()))); + if (mAidlService == nullptr) { + CCEC_LOG(LOG_EXP, "Failed to get AIDL HdmiCec service\r\n"); + throw IOException(); + } + CCEC_LOG(LOG_DEBUG, "Successfully obtained AIDL HdmiCec service\r\n"); + } else { + CCEC_LOG(LOG_EXP, "Failed to get service manager\n"); + throw IOException(); + } +} + +int HDMICecAidlHAL::open(int *handle) +{ + CCEC_LOG(LOG_INFO, "HDMICecAidlHAL::open invoked\n"); + + if (handle == nullptr) { + CCEC_LOG(LOG_ERROR, "HDMICecAidlHAL::open failed: invalid handle pointer\r\n"); + throw IOException(); + } + + android::sp service = getAidlService(); + if (service == nullptr) { + CCEC_LOG(LOG_ERROR, "HDMICecAidlHAL::open failed: IHdmiCec service unavailable\r\n"); + throw IOException(); + } + // Create event listener + mEventListener = new HDMICecAidlHALEventListener(this); + + // Open AIDL interface + android::sp controller; + android::binder::Status status = service->open(mEventListener, &controller); + if (!status.isOk() || controller == nullptr) { + CCEC_LOG(LOG_ERROR, "HDMICecAidlHAL::open failed: service->open status not OK or controller is null\r\n"); + throw IOException(); + } + + mAidlController = controller; + + *handle = 1; /* Dummy handle — AIDL uses controller object */ + + return 0; +} + +int HDMICecAidlHAL::close(int handle) +{ + CCEC_LOG(LOG_INFO, "HDMICecAidlHAL::close invoked\n"); + (void)handle; + + if (mAidlController != nullptr) { + android::sp service = getAidlService(); + if (service != nullptr) { + bool result = false; + android::binder::Status status = service->close(mAidlController, &result); + if (!status.isOk()) { + CCEC_LOG(LOG_EXP, "Failed to close AIDL HdmiCec interface: %s\r\n", status.toString8().c_str()); + CCEC_LOG(LOG_ERROR, "HDMICecAidlHAL::close failed: service->close status not OK\n"); + throw IOException(); + } + if (!result) { + CCEC_LOG(LOG_ERROR, "HDMICecAidlHAL::close failed: service->close returned false\n"); + throw IOException(); + } + } + mAidlController = nullptr; + } + + mEventListener = nullptr; + + CCEC_LOG(LOG_DEBUG, "Successfully closed AIDL HdmiCec interface\r\n"); + return 0; +} + +int HDMICecAidlHAL::addLogicalAddress(int handle, int logicalAddresses) +{ + (void)handle; + if (mAidlController == nullptr) { + throw IOException(); + } + std::vector addresses; + addresses.push_back(logicalAddresses); + bool result = false; + android::binder::Status status = mAidlController->addLogicalAddresses(addresses, &result); + + if (!status.isOk()) { + CCEC_LOG(LOG_EXP, "Failed to add logical address via AIDL: %s\r\n", status.toString8().c_str()); + throw IOException(); + } + + if (!result) { + throw AddressNotAvailableException(); + } + + CCEC_LOG(LOG_DEBUG, "Successfully added logical address addr=%d via AIDL\n", logicalAddresses); + return 0; +} + +int HDMICecAidlHAL::removeLogicalAddress(int handle, int logicalAddresses) +{ + (void)handle; + if (mAidlController == nullptr) { + throw IOException(); + } + + std::vector addresses; + addresses.push_back(logicalAddresses); + bool result = false; + android::binder::Status status = mAidlController->removeLogicalAddresses(addresses, &result); + if (!status.isOk() || !result) { + CCEC_LOG(LOG_EXP, "Failed to remove logical address via AIDL: %s\n", status.toString8().c_str()); + throw IOException(); + } + + CCEC_LOG(LOG_DEBUG, "Successfully removed logical address addr=%d via AIDL\n", logicalAddresses); + return 0; +} + +int HDMICecAidlHAL::getLogicalAddress(int handle, int devType, int *logicalAddress) +{ + (void)handle; + if (logicalAddress == nullptr) { + CCEC_LOG(LOG_ERROR, "HDMICecAidlHAL::getLogicalAddress invalid output pointer\r\n"); + throw IOException(); + } + + *logicalAddress = 0; + if (mAidlService == nullptr) { + android::sp service = getAidlService(); + if (service == nullptr) { + throw IOException(); + } + mAidlService = service; + } + + std::vector addresses; + android::binder::Status status = mAidlService->getLogicalAddresses(&addresses); + if (status.isOk() && addresses.size() > 0) { + *logicalAddress = addresses[0]; + }else { + CCEC_LOG(LOG_WARN, + "HDMICecAidlHAL::getLogicalAddress no allocated LA from AIDL (statusOk=%d, count=%zu devType=%d). Trying fallback allocation.\r\n", + status.isOk() ? 1 : 0, + addresses.size(), + devType); + if (mAidlController != nullptr) { + const std::vector preferred = preferredLogicalAddressesForDeviceType(devType); + for (std::vector::const_iterator it = preferred.begin(); it != preferred.end(); ++it) { + std::vector candidate; + candidate.push_back(*it); + bool addResult = false; + android::binder::Status addStatus = mAidlController->addLogicalAddresses(candidate, &addResult); + CCEC_LOG(LOG_DEBUG, + "HDMICecAidlHAL::getLogicalAddress fallback addLogicalAddresses candidate=%d addOk=%d addResult=%d\r\n", + candidate[0], + addStatus.isOk() ? 1 : 0, + addResult ? 1 : 0); + addresses.clear(); + android::binder::Status retryStatus = mAidlService->getLogicalAddresses(&addresses); + if (retryStatus.isOk() && addresses.size() > 0) { + *logicalAddress = addresses[0]; + break; + } + } + } + } + + + CCEC_LOG( LOG_DEBUG, "HDMICecAidlHAL::getLogicalAddress completed\r\n"); + + return 0; +} + +int HDMICecAidlHAL::getPhysicalAddress(int handle, unsigned int *physicalAddress) +{ + if (physicalAddress != nullptr) { + *physicalAddress = 0; + } + + CCEC_LOG( LOG_DEBUG, "HDMICecAidlHAL::getPhysicalAddress completed\r\n"); + + return 0; +} + +void HDMICecAidlHAL::dispatchRx(unsigned char *buf, int len) +{ + if (mRxCb == nullptr) { + CCEC_LOG(LOG_DEBUG, "HDMICecAidlHAL::dispatchRx callback not registered\r\n"); + return; + } + + // Track initiator LA from inbound frames so 1-byte poll can be emulated + // locally on AIDL backends that reject 1-byte sendMessage payloads. + if (buf != nullptr && len >= 1) { + const uint8_t srcLA = static_cast((buf[0] >> 4) & 0x0F); + if (srcLA <= 0x0E) { + AutoLock lock_(mAidlMutex); + mSeenLogicalAddresses.insert(srcLA); + } + } + mRxCb(0, mRxCbData, buf, len); +} + +void HDMICecAidlHAL::dispatchTx(int result) +{ + if (mTxCb == nullptr) { + CCEC_LOG(LOG_DEBUG, "HDMICecAidlHAL::dispatchTx callback not registered\r\n"); + return; + } + + mTxCb(0, mTxCbData, result); +} + +int HDMICecAidlHAL::setRxCallback(int handle, HdmiCecRxCallback_t cbfunc, void *data) +{ + (void)handle; + + mRxCb = cbfunc; + mRxCbData = data; + + CCEC_LOG(LOG_DEBUG, "HDMICecAidlHAL::setRxCallback invoked\r\n"); + return 0; +} + +int HDMICecAidlHAL::setTxCallback(int handle, HdmiCecTxCallback_t cbfunc, void *data) +{ + (void)handle; + + mTxCb = cbfunc; + mTxCbData = data; + + CCEC_LOG(LOG_DEBUG, "HDMICecAidlHAL::setTxCallback invoked\r\n"); + return 0; +} + +int HDMICecAidlHAL::tx(int handle, const unsigned char *buf, int len, int *result) +{ + (void)handle; + if (mAidlController == nullptr) { + throw IOException(); + } + + if (result == nullptr) { + CCEC_LOG(LOG_ERROR, "HDMICecAidlHAL::tx invalid result pointer\n"); + throw IOException(); + } + + if (buf == nullptr || len <= 0) { + CCEC_LOG(LOG_ERROR, "HDMICecAidlHAL::tx invalid buffer or length\n"); + throw IOException(); + } + + if(emulateAckForPollFrames(buf, len)) { + *result = HDMI_CEC_IO_SUCCESS; + return 0; + } + + std::vector message(buf, buf + len); + SendMessageStatus sendStatus; + android::binder::Status status = mAidlController->sendMessage(message, &sendStatus); + if (!status.isOk()) { + CCEC_LOG(LOG_ERROR, "AIDL sendMessage failed: %s\r\n", status.toString8().c_str()); + throw IOException(); + } + + // Map AIDL SendMessageStatus to HAL error codes + *result = HDMI_CEC_IO_SUCCESS; + if (sendStatus == SendMessageStatus::ACK_STATE_0) { + *result = HDMI_CEC_IO_SENT_AND_ACKD; + } else if (sendStatus == SendMessageStatus::ACK_STATE_1) { + *result = HDMI_CEC_IO_SENT_BUT_NOT_ACKD; + } else if (sendStatus == SendMessageStatus::BUSY){ + *result = HDMI_CEC_IO_SENT_FAILED; + throw IOException(); + } + + CCEC_LOG( LOG_DEBUG, "AIDL sendMessage DONE, result %x\r\n", *result); + + return 0; +} + +int HDMICecAidlHAL::txAsync(int handle, const unsigned char *buf, int len) +{ + (void)handle; + if (mAidlController == nullptr) { + throw IOException(); + } + if (buf == nullptr || len <= 0) { + CCEC_LOG(LOG_ERROR, "HDMICecAidlHAL::txAsync invalid buffer or length\n"); + throw IOException(); + } + + std::vector message(buf, buf + len); + SendMessageStatus sendStatus; + android::binder::Status status = mAidlController->sendMessage(message, &sendStatus); + if (!status.isOk()) { + CCEC_LOG(LOG_ERROR, "AIDL sendMessage failed: %s\r\n", status.toString8().c_str()); + throw IOException(); + } + + if (sendStatus == SendMessageStatus::BUSY) { + CCEC_LOG(LOG_ERROR, "AIDL sendMessage busy in txAsync\r\n"); + throw IOException(); + } + + CCEC_LOG( LOG_DEBUG, "AIDL txAsync completed, status: %d\r\n", static_cast(sendStatus)); + + return 0; +} + +bool HDMICecAidlHAL::emulateAckForPollFrames(const unsigned char *buf, int len) +{ + if (len <= 1) { + /* + * Poll frame (header only): emulate ACK based on seen-LA cache + * and 2-byte probe. This keeps HdmiCecSource ping-based discovery + * working on AIDL backend. + */ + const uint8_t destination = (buf != NULL) ? (buf[0] & 0x0F) : 0xFF; + + if (destination <= 0x0E) { + /* Check seen-LA cache first */ + { + AutoLock lock_(mAidlMutex); + if (mSeenLogicalAddresses.count(destination) > 0) { + CCEC_LOG(LOG_DEBUG, + "HDMICecAidlHAL::emulateAckForPollFrames destination=0x%X present in seen-LA set. Emulating ack.\r\n", + destination); + return true; + } + } + + /* Probe with a 2-byte directed frame (GiveDevicePowerStatus) */ + { + AutoLock lock_(mAidlMutex); + std::vector probe; + probe.reserve(2); + probe.push_back(buf ? buf[0] : 0); + probe.push_back(0x8F); // GiveDevicePowerStatus + + SendMessageStatus probeStatus = SendMessageStatus::BUSY; + android::binder::Status aidlStatus = mAidlController->sendMessage(probe, &probeStatus); + if (aidlStatus.isOk() && probeStatus == SendMessageStatus::ACK_STATE_0) { + mSeenLogicalAddresses.insert(destination); + CCEC_LOG(LOG_DEBUG, + "HDMICecAidlHAL::emulateAckForPollFrames destination=0x%X ACKed by 2-byte probe. Emulating ack.\r\n", + destination); + return true; + } + + CCEC_LOG(LOG_DEBUG, + "HDMICecAidlHAL::emulateAckForPollFrames destination=0x%X probe NACK/failed (aidlOk=%d status=%d).\r\n", + destination, + aidlStatus.isOk() ? 1 : 0, + static_cast(probeStatus)); + } + } + + CCEC_LOG(LOG_DEBUG, + "HDMICecAidlHAL::emulateAckForPollFrames destination=0x%X not present. Returning no-ack.\r\n", + (buf != NULL) ? (buf[0] & 0x0F) : 0xFF); + throw CECNoAckException(); + } + + if (static_cast(len) > kAidlMaxCecFrameSize) { + CCEC_LOG(LOG_EXP, + "HDMICecAidlHAL::emulateAckForPollFrames blocking unsupported CEC frame length=%zu on AIDL backend (valid range: 2..16).\r\n", + static_cast(len)); + throw IOException(); + } + + return false; +} diff --git a/ccec/src/factoryImpl/HDMICecAidlHAL.h b/ccec/src/factoryImpl/HDMICecAidlHAL.h new file mode 100644 index 00000000..2d0ea3bc --- /dev/null +++ b/ccec/src/factoryImpl/HDMICecAidlHAL.h @@ -0,0 +1,91 @@ +/* + * If not stated otherwise in this file or this component's LICENSE file the + * following copyright and licenses apply: + * + * Copyright 2026 RDK Management + * + * 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 HDMI_CEC_AIDL_HAL_H +#define HDMI_CEC_AIDL_HAL_H + +#include "IHDMICecHal.h" + + #include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "osal/Mutex.hpp" + +using CCEC_OSAL::Mutex; + +class HDMICecAidlHALEventListener; + +class HDMICecAidlHAL : public IHDMICecHal { +public: + HDMICecAidlHAL(); + ~HDMICecAidlHAL() override; + + int open(int *handle) override; + int close(int handle) override; + int addLogicalAddress(int handle, int logicalAddresses) override; + int removeLogicalAddress(int handle, int logicalAddresses) override; + int getLogicalAddress(int handle, int devType, int *logicalAddress) override; + int getPhysicalAddress(int handle, unsigned int *physicalAddress) override; + int setRxCallback(int handle, HdmiCecRxCallback_t cbfunc, void *data) override; + int setTxCallback(int handle, HdmiCecTxCallback_t cbfunc, void *data) override; + int tx(int handle, const unsigned char *buf, int len, int *result) override; + int txAsync(int handle, const unsigned char *buf, int len) override; + +private: + const size_t kAidlMinCecFrameSize = 2; + const size_t kAidlMaxCecFrameSize = 16; + android::sp getAidlService(); + void initAidlService(); + void dispatchRx(unsigned char *buf, int len); + void dispatchTx(int result); + /** + * @brief Emulate ACK for Poll messages + * This allows the driver to treat Poll frames as if they were ACKed, + * ensuring proper handling of device presence on the bus. + */ + bool emulateAckForPollFrames(const unsigned char *buf, int len); + + android::sp mAidlService; + android::sp mAidlController; + android::sp mEventListener; + HdmiCecRxCallback_t mRxCb; + HdmiCecTxCallback_t mTxCb; + void* mRxCbData; + void* mTxCbData; + mutable Mutex mAidlMutex; + // Logical addresses seen on inbound CEC frames. + // Used to emulate poll ACK/NACK locally because some AIDL backends + // reject 1-byte poll frames as invalid message size. + std::set mSeenLogicalAddresses; + + friend class HDMICecAidlHALEventListener; +}; + +#endif // HDMI_CEC_AIDL_HAL_H + diff --git a/ccec/src/factoryImpl/HDMICecHalFactory.cpp b/ccec/src/factoryImpl/HDMICecHalFactory.cpp new file mode 100644 index 00000000..6b7e62d9 --- /dev/null +++ b/ccec/src/factoryImpl/HDMICecHalFactory.cpp @@ -0,0 +1,155 @@ +/* + * If not stated otherwise in this file or this component's LICENSE file the + * following copyright and licenses apply: + * + * Copyright 2026 RDK Management + * + * 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 "HDMICecHalFactory.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ServiceManagerCheck.h" +#include "HDMICecAidlHAL.h" +#include "HDMICecRdkVHAL.h" +#include "ccec/Util.hpp" + +using namespace com::rdk::hal::hdmicec; + +static const android::String16 mServiceManagerName("manager"); + +namespace { + class HalFactoryUtility { + public: + enum class BackendType { + UNKNOWN, + LEGACY, + AIDL + }; + + static BackendType mBackendType; + + static bool isAidlServiceAvailable(const android::String16 &expectedServiceName) + { + CCEC_LOG(LOG_INFO, "isAidlServiceAvailable invoked\r\n"); + + if (mBackendType == BackendType::AIDL) { + return true; + } else if (mBackendType == BackendType::LEGACY) { + return false; + } + + if (!isServiceManagerAvailable()) { + CCEC_LOG(LOG_INFO, "Binder driver not available; falling back to legacy HAL\r\n"); + mBackendType = BackendType::LEGACY; + return false; + } + + android::sp serviceManager = android::defaultServiceManager(); + if (serviceManager == nullptr) { + CCEC_LOG(LOG_ERROR, "isAidlServiceAvailable failed: IServiceManager unavailable\r\n"); + mBackendType = BackendType::LEGACY; + return false; + } + + CCEC_LOG(LOG_INFO, "Successfully obtained IServiceManager\r\n"); + + android::Vector services = serviceManager->listServices(); + size_t discoveredServiceCount = 0; + bool matched = false; + + for (size_t index = 0; index < services.size(); ++index) { + if (services[index] != mServiceManagerName) { + ++discoveredServiceCount; + } + } + + CCEC_LOG(LOG_INFO, "isAidlServiceAvailable discovered %zu binder services\r\n", discoveredServiceCount); + if (discoveredServiceCount == 0) { + CCEC_LOG(LOG_INFO, + "isAidlServiceAvailable found no binder services beyond the ServiceManager entry while searching for '%s'\r\n", + android::String8(expectedServiceName).string()); + mBackendType = BackendType::LEGACY; + return false; + } + + CCEC_LOG(LOG_INFO, + "isAidlServiceAvailable inspecting %zu registered binder services for '%s'\r\n", + discoveredServiceCount, android::String8(expectedServiceName).string()); + + for (size_t index = 0; index < services.size(); ++index) { + if (services[index] == mServiceManagerName) { + continue; + } + + const android::String8 discoveredServiceName(services[index]); + if (services[index] == expectedServiceName) { + matched = true; + } + + CCEC_LOG(LOG_INFO, + "isAidlServiceAvailable discovered binder service[%zu]='%s'\r\n", + index, + discoveredServiceName.string()); + } + + if (matched) { + CCEC_LOG(LOG_INFO, + "isAidlServiceAvailable found AIDL service '%s'\r\n", + android::String8(expectedServiceName).string()); + mBackendType = BackendType::AIDL; + return true; + } + + CCEC_LOG(LOG_INFO, + "isAidlServiceAvailable did not find AIDL service '%s'\r\n", + android::String8(expectedServiceName).string()); + mBackendType = BackendType::LEGACY; + return false; + } + }; + HalFactoryUtility::BackendType HalFactoryUtility::mBackendType + = HalFactoryUtility::BackendType::UNKNOWN; +} + +std::unique_ptr HDMICecHalFactory::Create() +{ + CCEC_LOG(LOG_INFO, "HDMICecHalFactory::Create invoked\r\n"); + + try { + if (HalFactoryUtility::isAidlServiceAvailable(android::String16(IHdmiCec::serviceName().c_str()))) { + CCEC_LOG(LOG_INFO, "HDMICecHalFactory: Aidl Service is available — using HDMICecAidlHAL\r\n"); + return std::make_unique(); + } + } catch (...) { + CCEC_LOG(LOG_ERROR, "HDMICecHalFactory: Exception thrown while creating AIDL HAL,\r\n"); + } + + CCEC_LOG(LOG_INFO, "HDMICecHalFactory: Aidl Service is not available — using legacy HDMICecRdkVHAL\r\n"); + return std::make_unique(); +} + diff --git a/ccec/src/factoryImpl/HDMICecHalFactory.h b/ccec/src/factoryImpl/HDMICecHalFactory.h new file mode 100644 index 00000000..7e2d0479 --- /dev/null +++ b/ccec/src/factoryImpl/HDMICecHalFactory.h @@ -0,0 +1,31 @@ +/* + * If not stated otherwise in this file or this component's LICENSE file the + * following copyright and licenses apply: + * + * Copyright 2026 RDK Management + * + * 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 HDMI_CEC_HAL_FACTORY_H +#define HDMI_CEC_HAL_FACTORY_H + +#include "IHDMICecHal.h" +#include + +class HDMICecHalFactory { +public: + static std::unique_ptr Create(); +}; + +#endif // HDMI_CEC_HAL_FACTORY_H diff --git a/ccec/src/factoryImpl/HDMICecRdkVHAL.cpp b/ccec/src/factoryImpl/HDMICecRdkVHAL.cpp new file mode 100644 index 00000000..b7633391 --- /dev/null +++ b/ccec/src/factoryImpl/HDMICecRdkVHAL.cpp @@ -0,0 +1,143 @@ +/* + * If not stated otherwise in this file or this component's LICENSE file the + * following copyright and licenses apply: + * + * Copyright 2026 RDK Management + * + * 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. +*/ + +/* + * HDMICecRdkVHAL.cpp — Legacy C HAL implementation of HDMICecHal. + * + * Each function wraps the corresponding HdmiCec* C API from hdmi_cec_driver.h. + */ + +#include +#include "HDMICecRdkVHAL.h" +#include "ccec/Util.hpp" + +/* ----------------------------------------------------------------------- + * open + * Calls HdmiCecOpen() to initialise the driver and obtain a handle. + * -------------------------------------------------------------------- */ +int HDMICecRdkVHAL::open(int *handle) +{ + int ret = ::HdmiCecOpen(handle); + CCEC_LOG(LOG_DEBUG, "HDMICecRdkVHAL::open ret=%d handle=%d\r\n", ret, (handle ? *handle : -1)); + return ret; +} + +/* ----------------------------------------------------------------------- + * close + * Calls HdmiCecClose() to release driver resources. + * -------------------------------------------------------------------- */ +int HDMICecRdkVHAL::close(int handle) +{ + int ret = ::HdmiCecClose(handle); + CCEC_LOG(LOG_DEBUG, "HDMICecRdkVHAL::close handle=%d ret=%d\r\n", handle, ret); + return ret; +} + +/* ----------------------------------------------------------------------- + * setRxCallback + * Calls HdmiCecSetRxCallback() to register the incoming-message callback. + * -------------------------------------------------------------------- */ +int HDMICecRdkVHAL::setRxCallback(int handle, HdmiCecRxCallback_t cbfunc, void *data) +{ + int ret = ::HdmiCecSetRxCallback(handle, cbfunc, data); + CCEC_LOG(LOG_DEBUG, "HDMICecRdkVHAL::setRxCallback handle=%d ret=%d\r\n", handle, ret); + return ret; +} + +/* ----------------------------------------------------------------------- + * setTxCallback + * Calls HdmiCecSetTxCallback() to register the transmit-status callback. + * -------------------------------------------------------------------- */ +int HDMICecRdkVHAL::setTxCallback(int handle, HdmiCecTxCallback_t cbfunc, void *data) +{ + int ret = ::HdmiCecSetTxCallback(handle, cbfunc, data); + CCEC_LOG(LOG_DEBUG, "HDMICecRdkVHAL::setTxCallback handle=%d ret=%d\r\n", handle, ret); + return ret; +} + +/* ----------------------------------------------------------------------- + * tx + * Calls HdmiCecTx() for a synchronous transmit; blocks until ACK/NACK. + * -------------------------------------------------------------------- */ +int HDMICecRdkVHAL::tx(int handle, const unsigned char *buf, int len, int *result) +{ + int ret = ::HdmiCecTx(handle, buf, len, result); + CCEC_LOG(LOG_DEBUG, "HDMICecRdkVHAL::tx handle=%d ret=%d sendResult=%d\r\n", handle, ret, (result ? *result : -1)); + return ret; +} + +/* ----------------------------------------------------------------------- + * txAsync + * Calls HdmiCecTxAsync() for a fire-and-forget transmit. + * -------------------------------------------------------------------- */ +int HDMICecRdkVHAL::txAsync(int handle, const unsigned char *buf, int len) +{ + int ret = ::HdmiCecTxAsync(handle, buf, len); + CCEC_LOG(LOG_DEBUG, "HDMICecRdkVHAL::txAsync handle=%d ret=%d\r\n", handle, ret); + return ret; +} + +/* ----------------------------------------------------------------------- + * addLogicalAddress + * Calls HdmiCecAddLogicalAddress() to claim a logical address on the bus. + * -------------------------------------------------------------------- */ +int HDMICecRdkVHAL::addLogicalAddress(int handle, int logicalAddress) +{ + int ret = ::HdmiCecAddLogicalAddress(handle, logicalAddress); + CCEC_LOG(LOG_DEBUG, "HDMICecRdkVHAL::addLogicalAddress handle=%d addr=%d ret=%d\r\n", handle, logicalAddress, ret); + return ret; +} + +/* ----------------------------------------------------------------------- + * removeLogicalAddress + * Calls HdmiCecRemoveLogicalAddress() to release a previously claimed + * logical address. + * -------------------------------------------------------------------- */ +int HDMICecRdkVHAL::removeLogicalAddress(int handle, int logicalAddress) +{ + int ret = ::HdmiCecRemoveLogicalAddress(handle, logicalAddress); + CCEC_LOG(LOG_DEBUG, "HDMICecRdkVHAL::removeLogicalAddress handle=%d addr=%d ret=%d\r\n", handle, logicalAddress, ret); + return ret; +} + +/* ----------------------------------------------------------------------- + * getLogicalAddress + * Calls HdmiCecGetLogicalAddress() to retrieve the current logical address. + * -------------------------------------------------------------------- */ +int HDMICecRdkVHAL::getLogicalAddress(int handle, int devType, int *logicalAddress) +{ + (void)devType; + int ret = ::HdmiCecGetLogicalAddress(handle, logicalAddress); + CCEC_LOG(LOG_DEBUG, "HDMICecRdkVHAL::getLogicalAddress handle=%d ret=%d addr=%d\r\n", + handle, ret, (logicalAddress ? *logicalAddress : -1)); + return ret; +} + +/* ----------------------------------------------------------------------- + * getPhysicalAddress + * Calls HdmiCecGetPhysicalAddress() to retrieve the device physical address. + * -------------------------------------------------------------------- */ +int HDMICecRdkVHAL::getPhysicalAddress(int handle, unsigned int *physicalAddress) +{ + int ret = ::HdmiCecGetPhysicalAddress(handle, physicalAddress); + CCEC_LOG(LOG_DEBUG, "HDMICecRdkVHAL::getPhysicalAddress handle=%d ret=%d addr=0x%x\r\n", + handle, ret, (physicalAddress ? *physicalAddress : 0)); + return ret; +} + diff --git a/ccec/src/factoryImpl/HDMICecRdkVHAL.h b/ccec/src/factoryImpl/HDMICecRdkVHAL.h new file mode 100644 index 00000000..74c77753 --- /dev/null +++ b/ccec/src/factoryImpl/HDMICecRdkVHAL.h @@ -0,0 +1,96 @@ +/* + * If not stated otherwise in this file or this component's LICENSE file the + * following copyright and licenses apply: + * + * Copyright 2026 RDK Management + * + * 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 HDMI_CEC_RDK_V_HAL_H +#define HDMI_CEC_RDK_V_HAL_H + +#include "IHDMICecHal.h" + +/** + * @brief Legacy (C HAL) implementation of IHDMICecHal. + * + * Each override delegates directly to the corresponding HdmiCec* C function + * from hdmi_cec_driver.h. + */ +class HDMICecRdkVHAL : public IHDMICecHal { +public: + /** + * @brief Open the HDMI CEC HAL driver. + * Calls HdmiCecOpen(). + */ + int open(int *handle) override; + + /** + * @brief Close the HDMI CEC HAL driver. + * Calls HdmiCecClose(). + */ + int close(int handle) override; + + /** + * @brief Register the receive callback. + * Calls HdmiCecSetRxCallback(). + */ + int setRxCallback(int handle, HdmiCecRxCallback_t cbfunc, void *data) override; + + /** + * @brief Register the transmit-status callback. + * Calls HdmiCecSetTxCallback(). + */ + int setTxCallback(int handle, HdmiCecTxCallback_t cbfunc, void *data) override; + + /** + * @brief Synchronous CEC transmit. + * Calls HdmiCecTx(). The send result is written to *result. + */ + int tx(int handle, const unsigned char *buf, int len, int *result) override; + + /** + * @brief Asynchronous CEC transmit. + * Calls HdmiCecTxAsync(). Result is delivered via the TxCallback. + */ + int txAsync(int handle, const unsigned char *buf, int len) override; + + /** + * @brief Add a logical address. + * Calls HdmiCecAddLogicalAddress(). + */ + int addLogicalAddress(int handle, int logicalAddress) override; + + /** + * @brief Remove a logical address. + * Calls HdmiCecRemoveLogicalAddress(). + */ + int removeLogicalAddress(int handle, int logicalAddress) override; + + /** + * @brief Get the device logical address. + * Calls HdmiCecGetLogicalAddress(). devType is unused on legacy backend. + */ + int getLogicalAddress(int handle, int devType, int *logicalAddress) override; + + /** + * @brief Get the device physical address. + * Calls HdmiCecGetPhysicalAddress(). + */ + int getPhysicalAddress(int handle, unsigned int *physicalAddress) override; +}; + +#endif // HDMI_CEC_RDK_V_HAL_H + + diff --git a/ccec/src/factoryImpl/IHDMICecHal.h b/ccec/src/factoryImpl/IHDMICecHal.h new file mode 100644 index 00000000..fe3476eb --- /dev/null +++ b/ccec/src/factoryImpl/IHDMICecHal.h @@ -0,0 +1,170 @@ +/* + * If not stated otherwise in this file or this component's LICENSE file the + * following copyright and licenses apply: + * + * Copyright 2026 RDK Management + * + * 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 I_HDMI_CEC_HAL_H +#define I_HDMI_CEC_HAL_H + +#include +#include +#include +#include "ccec/drivers/hdmi_cec_driver.h" + +/** + * @brief Abstract base class for HDMI CEC hardware abstraction. + * + * Each virtual function maps 1:1 to a HAL operation. Subclasses provide + * either a legacy (C HAL) implementation or an AIDL (binder) implementation. + * + * - Legacy subclass: delegates directly to HdmiCec* C functions. + * - AIDL subclass: communicates with the Android HDMI CEC AIDL service. + */ +class IHDMICecHal { +public: + virtual ~IHDMICecHal() = default; + + /** + * @brief Open the HDMI CEC HAL driver. + * + * Legacy: calls HdmiCecOpen(). + * AIDL: connects to the AIDL binder service and obtains a session. + * + * @param[out] handle Receives the driver handle. + * @return HDMI_CEC_IO_SUCCESS on success, or an error code. + */ + virtual int open(int *handle) = 0; + + /** + * @brief Close the HDMI CEC HAL driver. + * + * Legacy: calls HdmiCecClose(). + * AIDL: disconnects from the binder service. + * + * @param[in] handle The driver handle returned by open(). + * @return HDMI_CEC_IO_SUCCESS on success, or an error code. + */ + virtual int close(int handle) = 0; + + /** + * @brief Set the receive callback for incoming CEC messages. + * + * Legacy: calls HdmiCecSetRxCallback(). + * AIDL: registers an AIDL callback listener that bridges to cbfunc. + * + * @param[in] handle The driver handle. + * @param[in] cbfunc Callback function invoked on message reception. + * @param[in] data Opaque user data forwarded to cbfunc. + * @return HDMI_CEC_IO_SUCCESS on success, or an error code. + */ + virtual int setRxCallback(int handle, HdmiCecRxCallback_t cbfunc, void *data) = 0; + + /** + * @brief Set the transmit callback for transmission status notification. + * + * Legacy: calls HdmiCecSetTxCallback(). + * AIDL: registers an AIDL callback listener that bridges to cbfunc. + * + * @param[in] handle The driver handle. + * @param[in] cbfunc Callback function invoked with transmit result. + * @param[in] data Opaque user data forwarded to cbfunc. + * @return HDMI_CEC_IO_SUCCESS on success, or an error code. + */ + virtual int setTxCallback(int handle, HdmiCecTxCallback_t cbfunc, void *data) = 0; + + /** + * @brief Transmit a CEC message synchronously. + * + * Legacy: calls HdmiCecTx(). + * AIDL: sends message via binder and blocks until result is available. + * + * @param[in] handle The driver handle. + * @param[in] buf Buffer containing the CEC message. + * @param[in] len Length of the message in bytes. + * @param[out] result Receives the transmission result code. + * @return HDMI_CEC_IO_SUCCESS on success, or an error code. + */ + virtual int tx(int handle, const unsigned char *buf, int len, int *result) = 0; + + /** + * @brief Transmit a CEC message asynchronously. + * + * Legacy: calls HdmiCecTxAsync(). + * AIDL: sends message via binder; result delivered through TxCallback. + * + * @param[in] handle The driver handle. + * @param[in] buf Buffer containing the CEC message. + * @param[in] len Length of the message in bytes. + * @return HDMI_CEC_IO_SUCCESS on success, or an error code. + */ + virtual int txAsync(int handle, const unsigned char *buf, int len) = 0; + + /** + * @brief Add a logical address for receiving CEC messages. + * + * Legacy: calls HdmiCecAddLogicalAddress(). + * AIDL: registers the logical address via binder. + * + * @param[in] handle The driver handle. + * @param[in] logicalAddress Logical address to add (0-15). + * @return HDMI_CEC_IO_SUCCESS on success, or an error code. + */ + virtual int addLogicalAddress(int handle, int logicalAddress) = 0; + + /** + * @brief Remove a previously added logical address. + * + * Legacy: calls HdmiCecRemoveLogicalAddress(). + * AIDL: unregisters the logical address via binder. + * + * @param[in] handle The driver handle. + * @param[in] logicalAddress Logical address to remove (0-15). + * @return HDMI_CEC_IO_SUCCESS on success, or an error code. + */ + virtual int removeLogicalAddress(int handle, int logicalAddress) = 0; + + /** + * @brief Get the logical address of the device. + * + * Legacy: calls HdmiCecGetLogicalAddress(). + * AIDL: queries the logical address via binder, and may use devType + * as a fallback hint when no logical address is currently allocated. + * + * @param[in] handle The driver handle. + * @param[in] devType Device type hint (TV/Recorder/Tuner/Playback/AudioSystem). + * @param[out] logicalAddress Pointer to store the logical address. + * @return HDMI_CEC_IO_SUCCESS on success, or an error code. + */ + virtual int getLogicalAddress(int handle, int devType, int *logicalAddress) = 0; + + /** + * @brief Get the physical address of the device. + * + * Legacy: calls HdmiCecGetPhysicalAddress(). + * AIDL: queries the physical address via binder. + * + * @param[in] handle The driver handle. + * @param[out] physicalAddress Pointer to store the physical address. + * @return HDMI_CEC_IO_SUCCESS on success, or an error code. + */ + virtual int getPhysicalAddress(int handle, unsigned int *physicalAddress) = 0; +}; + +#endif // I_HDMI_CEC_HAL_H + + + diff --git a/ccec/src/factoryImpl/ServiceManagerCheck.cpp b/ccec/src/factoryImpl/ServiceManagerCheck.cpp new file mode 100644 index 00000000..a35478d0 --- /dev/null +++ b/ccec/src/factoryImpl/ServiceManagerCheck.cpp @@ -0,0 +1,254 @@ +/* + * Copyright 2026 RDK Management + * + * 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. +*/ + +/* + * ServiceManagerCheck.cpp — Checking the availability of the Android ServiceManager via Binder IPC. + * + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ServiceManagerCheck.h" +#include "ccec/Util.hpp" + +// --- Internal implementation details --- +namespace { + +// --- Pure Legacy 32-bit Architecture Layouts --- +#pragma pack(push, 4) +struct binder_write_read_v7 { + uint32_t write_size; + uint32_t write_consumed; + uint32_t write_buffer; + uint32_t read_size; + uint32_t read_consumed; + uint32_t read_buffer; +}; + +struct binder_transaction_data_v7 { + union { + uint32_t handle; + uint32_t ptr; + } target; + uint32_t cookie; + uint32_t code; + uint32_t flags; + int32_t sender_pid; + int32_t sender_euid; + uint32_t data_size; + uint32_t offsets_size; + union { + struct { + uint32_t buffer; + uint32_t offsets; + } ptr; + uint8_t buf[8]; + } data; +}; +#pragma pack(pop) + +// --- Configuration Constants --- +constexpr uint32_t BINDER_MMAP_SIZE_V7 = (128 * 1024); +constexpr uint32_t BINDER_MMAP_SIZE_V8 = (1024 * 1024); +constexpr uint32_t BR_REPLY_V7 = 0x80247201; +constexpr uint32_t BR_REPLY_V8 = 0x80287203; +constexpr uint32_t BR_REPLY_V7_ACTUAL = 0x7206; +constexpr uint32_t BR_TRANSACTION_COMPLETE_V7 = 0x720c; +constexpr uint32_t BR_OK_V7 = 0x7205; +constexpr uint32_t PING_TRANSACTION = 0x5F504E47; // '_PNG' + +// Macro definitions for internal use +#define BINDER_VERSION _IOWR('b', 9, struct binder_version) +#define BINDER_WRITE_READ_V7 _IOWR('b', 1, struct binder_write_read_v7) +#define BC_TRANSACTION_V7 _IOW('c', 0, struct binder_transaction_data_v7) + +// --- Unified Payload Aggregator Struct --- +struct BinderTransaction { + std::vector write_payload; + std::vector read_payload; + unsigned long ioctl_command = 0; +}; + +// Helper: Generates v7 structural packets +static BinderTransaction prepare_v7_transaction() { + BinderTransaction tx; + tx.ioctl_command = BINDER_WRITE_READ_V7; + + binder_transaction_data_v7 txn{}; + txn.target.handle = 0; + txn.code = PING_TRANSACTION; + txn.flags = 0; + txn.data_size = 0; + txn.offsets_size = 0; + + const size_t tx_words = sizeof(txn) / sizeof(uint32_t); + tx.write_payload.reserve(1 + tx_words); + tx.write_payload.push_back(BC_TRANSACTION_V7); + + tx.write_payload.resize(1 + tx_words); + std::memcpy(tx.write_payload.data() + 1, &txn, sizeof(txn)); + tx.read_payload.resize(256, 0); + return tx; +} + +// Helper: Generates v8 (Current System Context) structural packets +static BinderTransaction prepare_v8_transaction() { + BinderTransaction tx; + tx.ioctl_command = BINDER_WRITE_READ; + + struct binder_transaction_data txn{}; + std::memset(&txn, 0, sizeof(txn)); + txn.target.handle = 0; + txn.code = PING_TRANSACTION; + txn.flags = TF_ACCEPT_FDS; + txn.data_size = 0; + txn.offsets_size = 0; + + const size_t tx_words = sizeof(txn) / sizeof(uint32_t); + tx.write_payload.reserve(1 + tx_words); + tx.write_payload.push_back(BC_TRANSACTION); + + tx.write_payload.resize(1 + tx_words); + std::memcpy(tx.write_payload.data() + 1, &txn, sizeof(txn)); + tx.read_payload.resize(256, 0); + return tx; +} + +// --- Common Protocol Engine Core --- +static bool execute_binder_ping(const int binder_fd, const int protocol_version) { + const BinderTransaction tx = (protocol_version == 7) ? prepare_v7_transaction() : prepare_v8_transaction(); + uint32_t bytes_consumed = 0; + + CCEC_LOG(LOG_INFO, "[*] Routing Ping via version %d layout engine...\n", protocol_version); + + if (protocol_version == 7) { + binder_write_read_v7 bwr{}; + const size_t write_size = tx.write_payload.size() * sizeof(uint32_t); + const size_t read_size = tx.read_payload.size() * sizeof(uint32_t); + bwr.write_size = write_size; + bwr.write_consumed = 0; + bwr.write_buffer = static_cast(reinterpret_cast(tx.write_payload.data())); + bwr.read_size = read_size; + bwr.read_consumed = 0; + bwr.read_buffer = static_cast(reinterpret_cast(tx.read_payload.data())); + + const unsigned long ioctl_cmd = tx.ioctl_command; + if (ioctl(binder_fd, ioctl_cmd, &bwr) < 0) { + CCEC_LOG(LOG_ERROR, "[-] ioctl execution map allocation failed\n"); + return false; + } + bytes_consumed = bwr.read_consumed; + } else { + struct binder_write_read bwr{}; + std::memset(&bwr, 0, sizeof(bwr)); + const size_t write_size = tx.write_payload.size() * sizeof(uint32_t); + const size_t read_size = tx.read_payload.size() * sizeof(uint32_t); + bwr.write_size = write_size; + bwr.write_consumed = 0; + bwr.write_buffer = reinterpret_cast(tx.write_payload.data()); + bwr.read_size = read_size; + bwr.read_consumed = 0; + bwr.read_buffer = reinterpret_cast(tx.read_payload.data()); + + const unsigned long ioctl_cmd = tx.ioctl_command; + if (ioctl(binder_fd, ioctl_cmd, &bwr) < 0) { + CCEC_LOG(LOG_ERROR, "[-] ioctl execution map allocation failed: %s\n", std::strerror(errno)); + return false; + } + bytes_consumed = bwr.read_consumed; + } + + // --- Unified Protocol Response Token Parsing Loop --- + CCEC_LOG(LOG_INFO, "[*] Driver returned %u bytes of response telemetry.\n", bytes_consumed); + + const uint32_t* const read_start = tx.read_payload.data(); + const uint32_t* const read_end = read_start + (bytes_consumed / sizeof(uint32_t)); + bool service_manager_alive = false; + + for (const uint32_t* read_ptr = read_start; read_ptr < read_end; ++read_ptr) { + const uint32_t token = *read_ptr; + CCEC_LOG(LOG_INFO, "[*] Intercepted response token: 0x%x\n", token); + + if (token == BR_REPLY || token == BR_REPLY_V7_ACTUAL || token == BR_REPLY_V7 || token == BR_REPLY_V8) { + CCEC_LOG(LOG_INFO, "[+] Explicit reply acknowledgement found!\n"); + service_manager_alive = true; + break; + } + if (token == BR_DEAD_REPLY || token == BR_FAILED_REPLY) { + CCEC_LOG(LOG_ERROR, "[-] Driver faulted payload execution target. Status: 0x%x\n", token); + break; + } + if (token == BR_TRANSACTION_COMPLETE || token == BR_TRANSACTION_COMPLETE_V7) { + CCEC_LOG(LOG_INFO, "[+] Transaction safely handed off to Binder kernel layer.\n"); + continue; + } + if (token == BR_NOOP || token == BR_OK || token == BR_OK_V7) { + continue; + } + + // Safety Fallback for unexpected or structural multi-word response components + CCEC_LOG(LOG_WARN, "[!] Structural bound reached or unhandled response code. Breaking parsing thread loop.\n"); + break; + } + + return service_manager_alive; +} + +} // namespace + +bool isServiceManagerAvailable() { + bool service_manager_alive = false; + + const int binder_fd = open("/dev/binder", O_RDWR | O_CLOEXEC); + if (binder_fd < 0) { + CCEC_LOG(LOG_ERROR, "[-] Failed to open /dev/binder\n"); + return service_manager_alive; + } + CCEC_LOG(LOG_INFO, "[+] Successfully opened /dev/binder\n"); + + binder_version version{}; + if (ioctl(binder_fd, BINDER_VERSION, &version) < 0) { + CCEC_LOG(LOG_ERROR, "[-] Failed to extract device driver protocol revision metadata\n"); + close(binder_fd); + return service_manager_alive; + } + CCEC_LOG(LOG_INFO, "[+] Binder protocol version detected: %d\n", version.protocol_version); + + const size_t binder_map_size = (version.protocol_version == 7) ? BINDER_MMAP_SIZE_V7 : BINDER_MMAP_SIZE_V8; + void* const mapped_mem = mmap(nullptr, binder_map_size, PROT_READ, MAP_PRIVATE, binder_fd, 0); + if (mapped_mem == MAP_FAILED) { + CCEC_LOG(LOG_ERROR, "[-] Shared address space context instantiation failed\n"); + close(binder_fd); + return service_manager_alive; + } + CCEC_LOG(LOG_INFO, "[+] Memory mapped successfully\n"); + + const bool ping_result = execute_binder_ping(binder_fd, version.protocol_version); + service_manager_alive = ping_result; + + munmap(mapped_mem, binder_map_size); + close(binder_fd); + return service_manager_alive; +} diff --git a/ccec/src/factoryImpl/ServiceManagerCheck.h b/ccec/src/factoryImpl/ServiceManagerCheck.h new file mode 100644 index 00000000..235ac22f --- /dev/null +++ b/ccec/src/factoryImpl/ServiceManagerCheck.h @@ -0,0 +1,25 @@ +/* + * If not stated otherwise in this file or this component's LICENSE file the + * following copyright and licenses apply: + * + * Copyright 2026 RDK Management + * + * 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 SERVICEMANAGER_CHECK_H +#define SERVICEMANAGER_CHECK_H + +bool isServiceManagerAvailable(); + +#endif // SERVICEMANAGER_CHECK_H diff --git a/stubs/binder/IServiceManager.h b/stubs/binder/IServiceManager.h new file mode 100644 index 00000000..5b2db973 --- /dev/null +++ b/stubs/binder/IServiceManager.h @@ -0,0 +1,76 @@ +#ifndef STUB_BINDER_ISERVICEMANAGER_H +#define STUB_BINDER_ISERVICEMANAGER_H + +#include +#include +#include + +#include "utils/String16.h" +#include "utils/String8.h" +#include "utils/Vector.h" + +namespace android { +template +class sp { +public: + sp() = default; + sp(std::nullptr_t) : mPtr(nullptr) {} + sp(T* ptr) : mPtr(ptr) {} + sp(const std::shared_ptr& ptr) : mPtr(ptr) {} + + T* get() const { return mPtr.get(); } + T* operator->() const { return mPtr.get(); } + operator bool() const { return static_cast(mPtr); } + bool operator==(std::nullptr_t) const { return mPtr == nullptr; } + bool operator!=(std::nullptr_t) const { return mPtr != nullptr; } + sp& operator=(T* ptr) { + mPtr.reset(ptr); + return *this; + } + +private: + std::shared_ptr mPtr; +}; + +class IBinder { +public: + virtual ~IBinder() = default; +}; + +namespace binder { +class Status { +public: + Status() : mOk(true), mMessage("OK") {} + explicit Status(bool ok, std::string message = "OK") : mOk(ok), mMessage(std::move(message)) {} + + static Status ok() { return Status(true, "OK"); } + bool isOk() const { return mOk; } + String8 toString8() const { return String8(mMessage.c_str()); } + +private: + bool mOk; + std::string mMessage; +}; +} + +class IServiceManager { +public: + virtual ~IServiceManager() = default; + virtual sp getService(const String16&) { return sp(nullptr); } + virtual Vector listServices() { return {}; } +}; + +class StubServiceManager : public IServiceManager {}; + +inline sp defaultServiceManager() { + static sp manager(new StubServiceManager()); + return manager; +} + +template +sp interface_cast(const sp&) { + return sp(new T()); +} +} + +#endif diff --git a/stubs/binder/ProcessState.h b/stubs/binder/ProcessState.h new file mode 100644 index 00000000..816837e0 --- /dev/null +++ b/stubs/binder/ProcessState.h @@ -0,0 +1,16 @@ +#ifndef STUB_BINDER_PROCESSSTATE_H +#define STUB_BINDER_PROCESSSTATE_H + +namespace android { +class ProcessState { +public: + static ProcessState* self() { + static ProcessState instance; + return &instance; + } + + void startThreadPool() {} +}; +} + +#endif diff --git a/stubs/com/rdk/hal/hdmicec/BnHdmiCecEventListener.h b/stubs/com/rdk/hal/hdmicec/BnHdmiCecEventListener.h new file mode 100644 index 00000000..9d3d5268 --- /dev/null +++ b/stubs/com/rdk/hal/hdmicec/BnHdmiCecEventListener.h @@ -0,0 +1,10 @@ +#ifndef STUB_COM_RDK_HAL_HDMICEC_BNHDMICECEVENTLISTENER_H +#define STUB_COM_RDK_HAL_HDMICEC_BNHDMICECEVENTLISTENER_H + +#include "com/rdk/hal/hdmicec/IHdmiCecEventListener.h" + +namespace com { namespace rdk { namespace hal { namespace hdmicec { +class BnHdmiCecEventListener : public IHdmiCecEventListener {}; +}}}} + +#endif diff --git a/stubs/com/rdk/hal/hdmicec/IHdmiCec.h b/stubs/com/rdk/hal/hdmicec/IHdmiCec.h new file mode 100644 index 00000000..ba8ba811 --- /dev/null +++ b/stubs/com/rdk/hal/hdmicec/IHdmiCec.h @@ -0,0 +1,41 @@ +#ifndef STUB_COM_RDK_HAL_HDMICEC_IHDMICEC_H +#define STUB_COM_RDK_HAL_HDMICEC_IHDMICEC_H + +#include +#include + +#include "binder/IServiceManager.h" +#include "com/rdk/hal/hdmicec/IHdmiCecController.h" +#include "com/rdk/hal/hdmicec/IHdmiCecEventListener.h" + +namespace com { namespace rdk { namespace hal { namespace hdmicec { +class IHdmiCec : public android::IBinder { +public: + virtual ~IHdmiCec() = default; + + static std::string serviceName() { return "com.rdk.hal.hdmicec.IHdmiCec/default"; } + + virtual android::binder::Status open(const android::sp&, android::sp* controller) { + if (controller) { + *controller = android::sp(new IHdmiCecController()); + } + return android::binder::Status::ok(); + } + + virtual android::binder::Status close(const android::sp&, bool* result) { + if (result) { + *result = true; + } + return android::binder::Status::ok(); + } + + virtual android::binder::Status getLogicalAddresses(std::vector* addresses) { + if (addresses) { + addresses->clear(); + } + return android::binder::Status::ok(); + } +}; +}}}} + +#endif diff --git a/stubs/com/rdk/hal/hdmicec/IHdmiCecController.h b/stubs/com/rdk/hal/hdmicec/IHdmiCecController.h new file mode 100644 index 00000000..d86e1559 --- /dev/null +++ b/stubs/com/rdk/hal/hdmicec/IHdmiCecController.h @@ -0,0 +1,38 @@ +#ifndef STUB_COM_RDK_HAL_HDMICEC_IHDMICECCONTROLLER_H +#define STUB_COM_RDK_HAL_HDMICEC_IHDMICECCONTROLLER_H + +#include +#include + +#include "binder/IServiceManager.h" +#include "com/rdk/hal/hdmicec/SendMessageStatus.h" + +namespace com { namespace rdk { namespace hal { namespace hdmicec { +class IHdmiCecController : public android::IBinder { +public: + virtual ~IHdmiCecController() = default; + + virtual android::binder::Status addLogicalAddresses(const std::vector&, bool* result) { + if (result) { + *result = true; + } + return android::binder::Status::ok(); + } + + virtual android::binder::Status removeLogicalAddresses(const std::vector&, bool* result) { + if (result) { + *result = true; + } + return android::binder::Status::ok(); + } + + virtual android::binder::Status sendMessage(const std::vector&, SendMessageStatus* status) { + if (status) { + *status = SendMessageStatus::ACK_STATE_0; + } + return android::binder::Status::ok(); + } +}; +}}}} + +#endif diff --git a/stubs/com/rdk/hal/hdmicec/IHdmiCecEventListener.h b/stubs/com/rdk/hal/hdmicec/IHdmiCecEventListener.h new file mode 100644 index 00000000..ef19976f --- /dev/null +++ b/stubs/com/rdk/hal/hdmicec/IHdmiCecEventListener.h @@ -0,0 +1,20 @@ +#ifndef STUB_COM_RDK_HAL_HDMICEC_IHDMICECEVENTLISTENER_H +#define STUB_COM_RDK_HAL_HDMICEC_IHDMICECEVENTLISTENER_H + +#include + +#include "binder/IServiceManager.h" +#include "com/rdk/hal/hdmicec/SendMessageStatus.h" +#include "com/rdk/hal/hdmicec/State.h" + +namespace com { namespace rdk { namespace hal { namespace hdmicec { +class IHdmiCecEventListener : public android::IBinder { +public: + virtual ~IHdmiCecEventListener() = default; + virtual android::binder::Status onMessageReceived(const std::vector&) { return android::binder::Status::ok(); } + virtual android::binder::Status onStateChanged(State, State) { return android::binder::Status::ok(); } + virtual android::binder::Status onMessageSent(const std::vector&, SendMessageStatus) { return android::binder::Status::ok(); } +}; +}}}} + +#endif diff --git a/stubs/com/rdk/hal/hdmicec/SendMessageStatus.h b/stubs/com/rdk/hal/hdmicec/SendMessageStatus.h new file mode 100644 index 00000000..d440fcb5 --- /dev/null +++ b/stubs/com/rdk/hal/hdmicec/SendMessageStatus.h @@ -0,0 +1,12 @@ +#ifndef STUB_COM_RDK_HAL_HDMICEC_SENDMESSAGESTATUS_H +#define STUB_COM_RDK_HAL_HDMICEC_SENDMESSAGESTATUS_H + +namespace com { namespace rdk { namespace hal { namespace hdmicec { +enum class SendMessageStatus { + ACK_STATE_0 = 0, + ACK_STATE_1 = 1, + BUSY = 2 +}; +}}}} + +#endif diff --git a/stubs/com/rdk/hal/hdmicec/State.h b/stubs/com/rdk/hal/hdmicec/State.h new file mode 100644 index 00000000..6e66a937 --- /dev/null +++ b/stubs/com/rdk/hal/hdmicec/State.h @@ -0,0 +1,12 @@ +#ifndef STUB_COM_RDK_HAL_HDMICEC_STATE_H +#define STUB_COM_RDK_HAL_HDMICEC_STATE_H + +namespace com { namespace rdk { namespace hal { namespace hdmicec { +enum class State { + UNKNOWN = 0, + IDLE = 1, + ACTIVE = 2 +}; +}}}} + +#endif diff --git a/stubs/linux/android/binder.h b/stubs/linux/android/binder.h new file mode 100644 index 00000000..9d72bc55 --- /dev/null +++ b/stubs/linux/android/binder.h @@ -0,0 +1,53 @@ +#ifndef STUB_LINUX_ANDROID_BINDER_H +#define STUB_LINUX_ANDROID_BINDER_H + +#include +#include + +typedef uintptr_t binder_uintptr_t; + +struct binder_version { + int32_t protocol_version; +}; + +struct binder_write_read { + uint64_t write_size; + uint64_t write_consumed; + binder_uintptr_t write_buffer; + uint64_t read_size; + uint64_t read_consumed; + binder_uintptr_t read_buffer; +}; + +struct binder_transaction_data { + union { + uint32_t handle; + binder_uintptr_t ptr; + } target; + binder_uintptr_t cookie; + uint32_t code; + uint32_t flags; + int32_t sender_pid; + int32_t sender_euid; + uint64_t data_size; + uint64_t offsets_size; + union { + struct { + binder_uintptr_t buffer; + binder_uintptr_t offsets; + } ptr; + uint8_t buf[8]; + } data; +}; + +#define BINDER_WRITE_READ _IOWR('b', 1, struct binder_write_read) +#define BC_TRANSACTION 0x0 +#define TF_ACCEPT_FDS 0x10 +#define BR_REPLY 0x1 +#define BR_DEAD_REPLY 0x2 +#define BR_FAILED_REPLY 0x3 +#define BR_TRANSACTION_COMPLETE 0x4 +#define BR_NOOP 0x5 +#define BR_OK 0x6 + +#endif diff --git a/stubs/utils/String16.h b/stubs/utils/String16.h new file mode 100644 index 00000000..2118035b --- /dev/null +++ b/stubs/utils/String16.h @@ -0,0 +1,23 @@ +#ifndef STUB_UTILS_STRING16_H +#define STUB_UTILS_STRING16_H + +#include + +namespace android { +class String16 { +public: + String16() = default; + explicit String16(const char* value) : mValue(value ? value : "") {} + explicit String16(const std::string& value) : mValue(value) {} + + const std::string& str() const { return mValue; } + + friend bool operator==(const String16& lhs, const String16& rhs) { return lhs.mValue == rhs.mValue; } + friend bool operator!=(const String16& lhs, const String16& rhs) { return !(lhs == rhs); } + +private: + std::string mValue; +}; +} + +#endif diff --git a/stubs/utils/String8.h b/stubs/utils/String8.h new file mode 100644 index 00000000..f1950e22 --- /dev/null +++ b/stubs/utils/String8.h @@ -0,0 +1,23 @@ +#ifndef STUB_UTILS_STRING8_H +#define STUB_UTILS_STRING8_H + +#include + +#include "String16.h" + +namespace android { +class String8 { +public: + String8() = default; + explicit String8(const char* value) : mValue(value ? value : "") {} + explicit String8(const String16& value) : mValue(value.str()) {} + + const char* c_str() const { return mValue.c_str(); } + const char* string() const { return mValue.c_str(); } + +private: + std::string mValue; +}; +} + +#endif diff --git a/stubs/utils/Vector.h b/stubs/utils/Vector.h new file mode 100644 index 00000000..38f6b639 --- /dev/null +++ b/stubs/utils/Vector.h @@ -0,0 +1,11 @@ +#ifndef STUB_UTILS_VECTOR_H +#define STUB_UTILS_VECTOR_H + +#include + +namespace android { +template +using Vector = std::vector; +} + +#endif