diff --git a/tv/cec/1.0/default/Android.bp b/tv/cec/1.0/default/Android.bp index 069f327389..5fe731b771 100644 --- a/tv/cec/1.0/default/Android.bp +++ b/tv/cec/1.0/default/Android.bp @@ -39,3 +39,26 @@ cc_binary { ], } + +cc_binary { + name: "android.hardware.tv.cec@1.0-service.mock", + vintf_fragments: ["android.hardware.tv.cec@1.0-service.mock.xml"], + relative_install_path: "hw", + vendor: true, + init_rc: ["android.hardware.tv.cec@1.0-service.mock.rc"], + srcs: [ + "serviceMock.cpp", + "HdmiCecMock.cpp", + ], + + shared_libs: [ + "liblog", + "libcutils", + "libbase", + "libutils", + "libhardware", + "libhidlbase", + "libhidltransport", + "android.hardware.tv.cec@1.0", + ], +} diff --git a/tv/cec/1.0/default/HdmiCecMock.cpp b/tv/cec/1.0/default/HdmiCecMock.cpp new file mode 100644 index 0000000000..eba8f95f57 --- /dev/null +++ b/tv/cec/1.0/default/HdmiCecMock.cpp @@ -0,0 +1,157 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "android.hardware.tv.cec@1.0-mock" +#include +#include + +#include +#include +#include "HdmiCecMock.h" + +namespace android { +namespace hardware { +namespace tv { +namespace cec { +namespace V1_0 { +namespace implementation { + +/* + * (*set_option)() passes flags controlling the way HDMI-CEC service works down + * to HAL implementation. Those flags will be used in case the feature needs + * update in HAL itself, firmware or microcontroller. + */ +void HdmiCecMock::cec_set_option(int flag, int value) { + // maintain options and set them accordingly + switch (flag) { + case HDMI_OPTION_WAKEUP: + mOptionWakeUp = value; + break; + case HDMI_OPTION_ENABLE_CEC: + mOptionEnableCec = value; + break; + case HDMI_OPTION_SYSTEM_CEC_CONTROL: + mOptionSystemCecControl = value; + break; + case HDMI_OPTION_SET_LANG: + mOptionLanguage = value; + } +} + +// Methods from ::android::hardware::tv::cec::V1_0::IHdmiCec follow. +Return HdmiCecMock::addLogicalAddress(CecLogicalAddress addr) { + // have a list to maintain logical addresses + int size = mLogicalAddresses.size(); + mLogicalAddresses.resize(size + 1); + mLogicalAddresses[size + 1] = addr; + return Result::SUCCESS; +} + +Return HdmiCecMock::clearLogicalAddress() { + // remove logical address from the list + mLogicalAddresses = {}; + return Void(); +} + +Return HdmiCecMock::getPhysicalAddress(getPhysicalAddress_cb _hidl_cb) { + // maintain a physical address and return it + // default 0xFFFF, update on hotplug event + _hidl_cb(Result::SUCCESS, mPhysicalAddress); + return Void(); +} + +Return HdmiCecMock::sendMessage(const CecMessage& message) { + if (message.body.size() == 0) { + return SendMessageResult::NACK; + } + return SendMessageResult::SUCCESS; +} + +Return HdmiCecMock::setCallback(const sp& callback) { + if (mCallback != nullptr) { + mCallback = nullptr; + } + + if (callback != nullptr) { + mCallback = callback; + mCallback->linkToDeath(this, 0 /*cookie*/); + } + return Void(); +} + +Return HdmiCecMock::getCecVersion() { + // maintain a cec version and return it + return mCecVersion; +} + +Return HdmiCecMock::getVendorId() { + return mCecVendorId; +} + +Return HdmiCecMock::getPortInfo(getPortInfo_cb _hidl_cb) { + vector portInfos; + // TODO ready port info from device specific config + portInfos.resize(mTotalPorts); + for (int i = 0; i < mTotalPorts; ++i) { + portInfos[i] = {.type = HdmiPortType::INPUT, + .portId = static_cast(i), + .cecSupported = true, + .arcSupported = (i == 0), + .physicalAddress = static_cast(i << 12)}; + } + _hidl_cb(portInfos); + return Void(); +} + +Return HdmiCecMock::setOption(OptionKey key, bool value) { + cec_set_option(static_cast(key), value ? 1 : 0); + return Void(); +} + +Return HdmiCecMock::setLanguage(const hidl_string& language) { + if (language.size() != 3) { + LOG(ERROR) << "Wrong language code: expected 3 letters, but it was " << language.size() + << "."; + return Void(); + } + // TODO validate if language is a valid language code + const char* languageStr = language.c_str(); + int convertedLanguage = ((languageStr[0] & 0xFF) << 16) | ((languageStr[1] & 0xFF) << 8) | + (languageStr[2] & 0xFF); + cec_set_option(HDMI_OPTION_SET_LANG, convertedLanguage); + return Void(); +} + +Return HdmiCecMock::enableAudioReturnChannel(int32_t portId __unused, bool enable __unused) { + // Maintain ARC status + return Void(); +} + +Return HdmiCecMock::isConnected(int32_t portId __unused) { + // maintain port connection status and update on hotplug event + return false; +} + +HdmiCecMock::HdmiCecMock() { + ALOGE("Opening a virtual HAL for testing and virtual machine."); +} + +} // namespace implementation +} // namespace V1_0 +} // namespace cec +} // namespace tv +} // namespace hardware +} // namespace android diff --git a/tv/cec/1.0/default/HdmiCecMock.h b/tv/cec/1.0/default/HdmiCecMock.h new file mode 100644 index 0000000000..b2f1113e8a --- /dev/null +++ b/tv/cec/1.0/default/HdmiCecMock.h @@ -0,0 +1,97 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_HARDWARE_TV_CEC_V1_0_HDMICEC_H +#define ANDROID_HARDWARE_TV_CEC_V1_0_HDMICEC_H + +#include +#include +#include +#include +#include +#include +#include + +using namespace std; + +namespace android { +namespace hardware { +namespace tv { +namespace cec { +namespace V1_0 { +namespace implementation { + +using ::android::sp; +using ::android::hardware::hidl_string; +using ::android::hardware::hidl_vec; +using ::android::hardware::Return; +using ::android::hardware::Void; +using ::android::hardware::tv::cec::V1_0::CecLogicalAddress; +using ::android::hardware::tv::cec::V1_0::CecMessage; +using ::android::hardware::tv::cec::V1_0::HdmiPortInfo; +using ::android::hardware::tv::cec::V1_0::IHdmiCec; +using ::android::hardware::tv::cec::V1_0::IHdmiCecCallback; +using ::android::hardware::tv::cec::V1_0::MaxLength; +using ::android::hardware::tv::cec::V1_0::OptionKey; +using ::android::hardware::tv::cec::V1_0::Result; +using ::android::hardware::tv::cec::V1_0::SendMessageResult; + +struct HdmiCecMock : public IHdmiCec, public hidl_death_recipient { + HdmiCecMock(); + // Methods from ::android::hardware::tv::cec::V1_0::IHdmiCec follow. + Return addLogicalAddress(CecLogicalAddress addr) override; + Return clearLogicalAddress() override; + Return getPhysicalAddress(getPhysicalAddress_cb _hidl_cb) override; + Return sendMessage(const CecMessage& message) override; + Return setCallback(const sp& callback) override; + Return getCecVersion() override; + Return getVendorId() override; + Return getPortInfo(getPortInfo_cb _hidl_cb) override; + Return setOption(OptionKey key, bool value) override; + Return setLanguage(const hidl_string& language) override; + Return enableAudioReturnChannel(int32_t portId, bool enable) override; + Return isConnected(int32_t portId) override; + + virtual void serviceDied(uint64_t /*cookie*/, + const wp<::android::hidl::base::V1_0::IBase>& /*who*/) { + setCallback(nullptr); + } + + void cec_set_option(int flag, int value); + + private: + sp mCallback; + // Variables for the virtual cec hal impl + uint16_t mPhysicalAddress = 0xFFFF; + vector mLogicalAddresses; + int32_t mCecVersion = 0; + uint32_t mCecVendorId = 0; + // Port configuration + int mTotalPorts = 4; + // CEC Option value + int mOptionWakeUp = 0; + int mOptionEnableCec = 0; + int mOptionSystemCecControl = 0; + int mOptionLanguage = 0; +}; +} // namespace implementation +} // namespace V1_0 +} // namespace cec +} // namespace tv +} // namespace hardware +} // namespace android + +#endif // ANDROID_HARDWARE_TV_CEC_V1_0_HDMICEC_H diff --git a/tv/cec/1.0/default/android.hardware.tv.cec@1.0-service.mock.rc b/tv/cec/1.0/default/android.hardware.tv.cec@1.0-service.mock.rc new file mode 100644 index 0000000000..170b485af8 --- /dev/null +++ b/tv/cec/1.0/default/android.hardware.tv.cec@1.0-service.mock.rc @@ -0,0 +1,5 @@ +service vendor.cec-hal-1-0-mock /vendor/bin/hw/android.hardware.tv.cec@1.0-service.mock + interface android.hardware.tv.cec@1.0::IHdmiCec default + class hal + user system + group system diff --git a/tv/cec/1.0/default/android.hardware.tv.cec@1.0-service.mock.xml b/tv/cec/1.0/default/android.hardware.tv.cec@1.0-service.mock.xml new file mode 100644 index 0000000000..5afa59d7db --- /dev/null +++ b/tv/cec/1.0/default/android.hardware.tv.cec@1.0-service.mock.xml @@ -0,0 +1,11 @@ + + + android.hardware.tv.cec + hwbinder + 1.0 + + IHdmiCec + default + + + diff --git a/tv/cec/1.0/default/serviceMock.cpp b/tv/cec/1.0/default/serviceMock.cpp new file mode 100644 index 0000000000..c0af22f099 --- /dev/null +++ b/tv/cec/1.0/default/serviceMock.cpp @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "android.hardware.tv.cec@1.0-service-shim" + +#include +#include +#include "HdmiCecMock.h" + +using android::hardware::configureRpcThreadpool; +using android::hardware::joinRpcThreadpool; +using android::hardware::tv::cec::V1_0::IHdmiCec; +using android::hardware::tv::cec::V1_0::implementation::HdmiCecMock; + +int main() { + configureRpcThreadpool(8, true /* callerWillJoin */); + + // Setup hwbinder service + android::sp service = new HdmiCecMock(); + android::status_t status; + status = service->registerAsService(); + LOG_ALWAYS_FATAL_IF(status != android::OK, "Error while registering mock cec service: %d", + status); + + joinRpcThreadpool(); + return 0; +}