从Hal开始,具体的code不贴了,只贴下接口。
1.注册接口
hardware\libhardware\include\hardware\hdmi_cec.h
/*
* (*register_event_callback)() registers a callback that HDMI-CEC HAL
* can later use for incoming CEC messages or internal HDMI events.
* When calling from C++, use the argument arg to pass the calling object.
* It will be passed back when the callback is invoked so that the context
* can be retrieved.
*/
void (*register_event_callback)(const struct hdmi_cec_device* dev,
event_callback_t callback, void* arg);
2.IHdmiCec callback接口回调实现
Z:\p\hardware\interfaces\tv\cec\1.0\default\HdmiCec.h
如果是HDMI_EVENT_HOT_PLUG,则会带上connected boolean值和对应的portId。如果是盒子的话,portId就是1,TV的话就是从1-4.
static void eventCallback(const hdmi_event_t* event, void* /* arg */) {
if (mCallback != nullptr && event != nullptr) {
if (event->type == HDMI_EVENT_CEC_MESSAGE) {
size_t length = std::min(event->cec.length,
static_cast<size_t>(MaxLength::MESSAGE_BODY));
CecMessage cecMessage {
.initiator = static_cast<CecLogicalAddress>(event->cec.initiator),
.destination = static_cast<CecLogicalAddress>(event->cec.destination),
};
cecMessage.body.resize(length);
for (size_t i = 0; i < length; ++i) {
cecMessage.body[i] = static_cast<uint8_t>(event->cec.body[i]);
}
mCallback->onCecMessage(cecMessage);
} else if (event->type == HDMI_EVENT_HOT_PLUG) {
HotplugEvent hotplugEvent {
.connected = event->hotplug.connected > 0,
.portId = static_cast<uint32_t>(event->hotplug.port_id)
};
mCallback->onHotplugEvent(hotplugEvent);
}
}
}
3.android framework jni
会访问到java侧的HdmiCecController的handleHotplug方法。
Z:\p\frameworks\base\services\core\jni\com_android_server_hdmi_HdmiCecController.cpp
Return<void> HdmiCecController::HdmiCecCallback::onHotplugEvent(const HotplugEvent& event) {
sp<HdmiCecEventHandler> handler(new HdmiCecEventHandler(mController, event));
mController->mLooper->sendMessage(handler, HdmiCecEventHandler::EventType::HOT_PLUG);
return Void();
}
void propagateHotplugEvent(const HotplugEvent& event) {
// Note that this method should be called in service thread.
JNIEnv* env = AndroidRuntime::getJNIEnv();
jint port = static_cast<jint>(event.portId);
jboolean connected = (jboolean) event.connected;
env->CallVoidMethod(mController->getCallbacksObj(),
gHdmiCecControllerClassInfo.handleHotplug, port, connected);
checkAndClearExceptionFromCallback(env, __FUNCTION__);
}
4. HdmiCecController
Z:\p\frameworks\base\services\core\java\com\android\server\hdmi\HdmiCecController.java
在打开log.tag.HDMI=DEBUG开关以后,会有port和connected的打印。
/**
* Called by native when a hotplug event issues.
*/
@ServiceThreadOnly
private void handleHotplug(int port, boolean connected) {
assertRunOnServiceThread();
HdmiLogger.debug("Hotplug event:[port:%d, connected:%b]", port, connected);
mService.onHotplug(port, connected);
}
5.HdmiControlService
①如果不是tv,就重新分配逻辑地址。
②调用HdmiCecLocalDevice的onHotplug回调,tv会调用HotplugDetectionAction进行设备列表的处理,其他类型的设备则可能会进行唤醒的处理。
③广播HotplugEvent。
广播HotplugEvent是后续事件传输过程的关键,因为下面会交给TIF来处理,更新TvInputManagerService里面Hdmi和Hardware相关设备的更新和对应接口add、remove的回调。
/**
* Called when a new hotplug event is issued.
*
* @param portId hdmi port number where hot plug event issued.
* @param connected whether to be plugged in or not
*/
@ServiceThreadOnly
void onHotplug(int portId, boolean connected) {