当前位置: 首页 > news >正文

安卓11-HDMI插拔检测流程

hdmi从插入到拔出经过底层一系列检测到应用层,应用层获取hdmi插入状态后又会做出一系列相应的动作,下面梳理了从应用层到底层一步步追踪到芯片的hpd-pin的检测过程。


frameworks/base/services/core/java/com/android/server/policy/PhoneWindowManager.java +775private class HdmiVideoExtconUEventObserver extends ExtconStateObserver<Boolean> {private static final String HDMI_EXIST = "HDMI=1";private static final String NAME = "hdmi";private final ExtconInfo mHdmi = new ExtconInfo(NAME);private boolean init() {boolean plugged = false;try {plugged = parseStateFromFile(mHdmi);} catch (FileNotFoundException e) {Slog.w(TAG, mHdmi.getStatePath()+ " not found while attempting to determine initial state", e);} catch (IOException e) {Slog.e(TAG,"Error reading " + mHdmi.getStatePath()+ " while attempting to determine initial state",e);}startObserving(mHdmi);return plugged;}@Overridepublic void updateState(ExtconInfo extconInfo, String eventName, Boolean state) {//通过这里更新hdmi plug状态,这个转态来自hal层//这里的变化来自hdmicec_event.cpp mDefaultDisplayPolicy.setHdmiPlugged(state);}@Overridepublic Boolean parseState(ExtconInfo extconIfno, String state) {// extcon event state changes from kernel4.9// new state will be like STATE=HDMI=1return state.contains(HDMI_EXIST);}}void initializeHdmiStateInternal() {boolean plugged = false;// watch for HDMI plug messages if the hdmi switch existsif (new File("/sys/devices/virtual/switch/hdmi/state").exists()) {mHDMIObserver.startObserving("DEVPATH=/devices/virtual/switch/hdmi");final String filename = "/sys/class/switch/hdmi/state";FileReader reader = null;try {reader = new FileReader(filename);char[] buf = new char[15];int n = reader.read(buf);if (n > 1) {plugged = 0 != Integer.parseInt(new String(buf, 0, n - 1));}} catch (IOException ex) {Slog.w(TAG, "Couldn't read hdmi state from " + filename + ": " + ex);} catch (NumberFormatException ex) {Slog.w(TAG, "Couldn't read hdmi state from " + filename + ": " + ex);} finally {if (reader != null) {try {reader.close();} catch (IOException ex) {}}}} else if (ExtconUEventObserver.extconExists()   //走这里  判断sys/class/extcon是否存在&& ExtconUEventObserver.namedExtconDirExists(HdmiVideoExtconUEventObserver.NAME)) {Log.i("fan","xtconUEventObserver.extconExists");HdmiVideoExtconUEventObserver observer = new HdmiVideoExtconUEventObserver();//新建一个hdmi观察者,检测hdmi hpd引脚的变化plugged = observer.init();mHDMIObserver = observer;} else if (localLOGV) {Slog.v(TAG, "Not observing HDMI plug state because HDMI was not found.");}// This dance forces the code in setHdmiPlugged to run.// Always do this so the sticky intent is stuck (to false) if there is no hdmi.mDefaultDisplayPolicy.setHdmiPlugged(plugged, true /* force */);}
frameworks/base/core/java/android/view/WindowManagerPolicyConstants.java:78    String ACTION_HDMI_PLUGGED = "android.intent.action.HDMI_PLUGGED";public void setHdmiPlugged(boolean plugged) {setHdmiPlugged(plugged, false /* force */);}public void setHdmiPlugged(boolean plugged, boolean force) {if (force || mHdmiPlugged != plugged) {mHdmiPlugged = plugged;mService.updateRotation(true /* alwaysSendConfiguration */, true /* forceRelayout */);final Intent intent = new Intent(ACTION_HDMI_PLUGGED);intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);intent.putExtra(EXTRA_HDMI_PLUGGED_STATE, plugged);mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);//通知系统hdmi插入状态}}boolean isHdmiPlugged() {return mHdmiPlugged;}    
frameworks/base/services/core/java/com/android/server/ExtconUEventObserver.java    public static boolean extconExists() {File extconDir = new File("/sys/class/extcon"); //检查这个文件是否存在,对应上面的else if (ExtconUEventObserver.extconExists() return extconDir.exists() && extconDir.isDirectory();}\hardware\rockchip\hdmicec\hdmicec_event.cpp
static void *uevent_loop(void *param)
{hdmi_cec_context_t * ctx = reinterpret_cast<hdmi_cec_context_t *>(param);char thread_name[64] = HDMI_CEC_UEVENT_THREAD_NAME;hdmi_event_t cec_event;struct pollfd pfd[2];int fd[2];int ret, i;prctl(PR_SET_NAME, (unsigned long) &thread_name, 0, 0, 0);setpriority(PRIO_PROCESS, 0, HAL_PRIORITY_URGENT_DISPLAY);fd[0] = ctx->fd;if (fd[0] < 0) {ALOGE ("%s:not able to open cec state node", __func__);return NULL;}pfd[0].fd = fd[0];if (pfd[0].fd >= 0)pfd[0].events = POLLIN | POLLRDNORM | POLLPRI;while (true) {usleep(1000);int err = poll(&pfd[0], 1, 20);if (!err) {continue;} else if(err > 0) {if (!ctx->enable || !ctx->system_control)continue;ALOGD("poll revent:%02x\n", pfd[0].revents);memset(&cec_event, 0, sizeof(hdmi_event_t));if (pfd[0].revents & (POLLIN)) {struct cec_msg cecframe;ALOGD("poll receive msg\n");ret = ioctl(pfd[0].fd, CEC_RECEIVE, &cecframe);if (!ret) {cec_event.type = HDMI_EVENT_CEC_MESSAGE;cec_event.dev = &ctx->device;cec_event.cec.initiator = (cec_logical_address_t)(cecframe.msg[0] >> 4);cec_event.cec.destination = (cec_logical_address_t)(cecframe.msg[0] & 0x0f);cec_event.cec.length = cecframe.len - 1;cec_event.cec.body[0] = cecframe.msg[1];if (!validcecmessage(cec_event)) {for (ret = 0; ret < cec_event.cec.length; ret++)cec_event.cec.body [ret + 1] = cecframe.msg[ret + 2];for (i = 0; i < cecframe.len; i++)ALOGD("poll receive msg[%d]:%02x\n", i, cecframe.msg[i]);if (ctx->event_callback)ctx->event_callback(&cec_event, ctx->cec_arg);} else {ALOGE("%s cec_event length > 15 ", __func__);}} else {ALOGE("%s hdmi cec read error", __FUNCTION__);}}if (pfd[0].revents & (POLLPRI)) {int state = -1;struct cec_event event;ALOGI("poll receive event\n");ret = ioctl(pfd[0].fd, CEC_DQEVENT, &event);//取得一个cec事件,然后判断事件的状态,此部分内容在内核层if (!ret) {ALOGD("event:%d\n", event.event);if (event.event == CEC_EVENT_PIN_HPD_LOW) {//获取底层hpdin管教状态ALOGI("CEC_EVENT_PIN_HPD_LOW\n");ctx->hotplug = false;cec_event.type = HDMI_EVENT_HOT_PLUG;cec_event.dev = &ctx->device;cec_event.hotplug.connected = HDMI_NOT_CONNECTED;cec_event.hotplug.port_id = HDMI_CEC_PORT_ID;if (ctx->event_callback)ctx->event_callback(&cec_event, ctx->cec_arg);} else if (event.event == CEC_EVENT_PIN_HPD_HIGH) {//高为连接ALOGI("CEC_EVENT_PIN_HPD_HIGH\n");ctx->hotplug = true;cec_event.type = HDMI_EVENT_HOT_PLUG;cec_event.dev = &ctx->device;cec_event.hotplug.connected = HDMI_CONNECTED;cec_event.hotplug.port_id = HDMI_CEC_PORT_ID;if (ctx->event_callback)ctx->event_callback(&cec_event, ctx->cec_arg);} else if (event.event == CEC_EVENT_STATE_CHANGE) {ALOGD("adapt state change,phy_addr:%x,flags:%x\n", event.state_change.phys_addr, event.flags);/** Before cec HAL is initialized, hdmi hpd state may be* changed. So we should confirm the hpd status* after cec is initialized(Kernel will report* CEC_EVENT_FL_INITIAL_STATE to notify HAL that* initialization is done).*/if (event.flags & CEC_EVENT_FL_INITIAL_STATE) {ALOGD("cec adapter init complete, get connect state\n");ctx->hotplug = get_hpd_state_from_node(ctx);ctx->cec_init = true;/** Framework will start la polling when box turn on,* In addition, as soon as framewrok receives hdmi* plug in, it will start la polling immediately.* There is not need to report plug in event if hdmi* is connecting when box turn on. So we should report* hdmi plug out only.*/if (!ctx->hotplug)report_hdp_event(ctx, ctx->hotplug);}ctx->phy_addr = event.state_change.phys_addr;}} else {ALOGE("%s cec event get err, ret:%d\n", __func__, ret);}}} else {ALOGE("%s: cec poll failed errno: %s", __FUNCTION__,strerror(errno));continue;}}return NULL;
}Kernel/drivers/media/cec/cec-api.c 
static long cec_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)case CEC_DQEVENT:return cec_dqevent(adap, fh, block, parg);  //hal层调用这里获取一个cec事件,既然有获取事件就有把时间放入事件队列的地方drivers/media/cec/cec-adap.cvoid cec_queue_pin_hpd_event(struct cec_adapter *adap, bool is_high, ktime_t ts)
{struct cec_event ev = {.event = is_high ? CEC_EVENT_PIN_HPD_HIGH :CEC_EVENT_PIN_HPD_LOW,};struct cec_fh *fh;if (!adap)return;/* hdmi HPD may occur before devnode is registered */if (!adap->devnode.registered)return;mutex_lock(&adap->devnode.lock);list_for_each_entry(fh, &adap->devnode.fhs, list)cec_queue_event_fh(fh, &ev, ktime_to_ns(ts)); //插入一个cec事件,把这个事件放入到ece事件队列,供hal层获取,hal层获取后传到framework层mutex_unlock(&adap->devnode.lock);
}

相关文章:

安卓11-HDMI插拔检测流程

hdmi从插入到拔出经过底层一系列检测到应用层&#xff0c;应用层获取hdmi插入状态后又会做出一系列相应的动作&#xff0c;下面梳理了从应用层到底层一步步追踪到芯片的hpd-pin的检测过程。 frameworks/base/services/core/java/com/android/server/policy/PhoneWindowManager.…...

OkHttp Retrofit HttpClient之间的区别

OkHttp、Retrofit 和 HttpClient 是三个不同的 HTTP 客户端库&#xff0c;它们各自有不同的特点和用途。下面是它们之间的主要区别&#xff1a; 1. **OkHttp**&#xff1a; - OkHttp 是一个高性能的 HTTP 和 HTTP/2 客户端&#xff0c;由 Square 公司开发。 - 它…...

Paddlepaddle使用自己的VOC数据集训练目标检测(0废话简易教程)

一 安装paddlepaddle和paddledection&#xff08;略&#xff09; 笔者使用的是自己的数据集 二 在dataset目录下新建自己的数据集文件&#xff0c;如下&#xff1a; 其中 xml文件内容如下&#xff1a; 另外新建一个createList.py文件&#xff1a; # -- coding: UTF-8 -- imp…...

【解析】C语言两个实例

例一&#xff1a; 下面程序输出什么&#xff1f; int main() { int i 43; int n printf("%d\n",i); printf("%d\n",n); return 0; } 大家深入考虑一下为什么返回是3这背后有什么鲜为人知的秘密到底是C语言离奇的规定还是深思熟…...

阅读笔记(Multimedia Systems2020)Review on image-stitching techniques

Wang Z, Yang Z. Review on image-stitching techniques[J]. Multimedia Systems, 2020, 26: 413-430. DOI https://doi.org/10.1007/s00530-020-00651-y...

【Java程序员面试专栏 数据结构】三 高频面试算法题:栈和队列

一轮的算法训练完成后,对相关的题目有了一个初步理解了,接下来进行专题训练,以下这些题目就是汇总的高频题目,因为栈和队列这两哥们结构特性比较向对应,所以放到一篇Blog中集中练习 题目题干直接给出对应博客链接,这里只给出简单思路、代码实现、复杂度分析 题目关键字…...

Python | Conda常用命令

一、介绍 1、Anaconda工具 Anaconda是一个用于数据科学和机器学习的开源软件包管理器和环境管理器。它包含了许多流行的数据科学工具和库&#xff0c;如Python、Jupyter Notebook、numpy、pandas、scikit-learn等&#xff0c;可以帮助用户轻松地管理和安装这些工具和库。Anaco…...

Linux 驱动开发基础知识——APP 怎么读取按键值(十二)

个人名片&#xff1a; &#x1f981;作者简介&#xff1a;学生 &#x1f42f;个人主页&#xff1a;妄北y &#x1f427;个人QQ&#xff1a;2061314755 &#x1f43b;个人邮箱&#xff1a;2061314755qq.com &#x1f989;个人WeChat&#xff1a;Vir2021GKBS &#x1f43c;本文由…...

【FastAPI】P3 请求与响应

目录 请求路径参数查询参数 响应JSON 响应文本响应返回 Pydantic 模型 在网络通讯中&#xff0c;请求&#xff08;Request&#xff09; 与 响应&#xff08;Response&#xff09; 扮演着至关重要的角色&#xff0c;它们构成了客户端与服务器间互动的根本理念。 请求&#xff0…...

Python学习-流程图、分支与循环(branch and loop)

十、流程图 1、流程图&#xff08;Flowchart&#xff09; 流程图是一种用于表示算法或代码流程的框图组合&#xff0c;它以不同类型的框框代表不同种类的程序步骤&#xff0c;每两个步骤之间以箭头连接起来。 好处&#xff1a; 1&#xff09;代码的指导文档 2&#xff09;有助…...

Python Flask Web 框架学习笔记+完整项目

Flask是一个轻量级的基于Python的web框架。 我们建议使用最新版本的 Python。Flask 支持 Python 3.8 及更高版本。 官网&#xff1a;欢迎使用 Flask — Flask 文档 &#xff08;3.0.x&#xff09; (palletsprojects.com) RESTFul API&#xff1a;Python Flask高级编程之REST…...

XML Map 端口进阶篇——常用关键字和格式化器详解

XML Map 端口是用于在不同XML之间建立关系映射的工具&#xff0c;允许通过拖拽操作实现源XML和目标 XML之间的数据字段映射&#xff0c;除此之外&#xff0c;XML Map 端口还提供了其它丰富多彩的功能&#xff0c;使用户能够更加灵活和高效的处理XML 数据映射任务&#xff0c;让…...

排序算法之——直接插入排序

直接插入排序——以升序排列为例 1.1基本思想1.2动态图示感知1.3静态图示详解1.4代码实现1.5时间复杂度1.5.1最好情况1.5.2最差情况 1.6空间复杂度1.7稳定性1.7.1一个小问题 1.1基本思想 把待排序的记录按其关键码值的大小逐个插入到一个已经排好序的有序序列中&#xff0c;直…...

突出最强算法模型——回归算法 !!

文章目录 1、特征工程的重要性 2、缺失值和异常值的处理 &#xff08;1&#xff09;处理缺失值 &#xff08;2&#xff09;处理异常值 3、回归模型的诊断 &#xff08;1&#xff09;残差分析 &#xff08;2&#xff09;检查回归假设 &#xff08;3&#xff09;Cooks 距离 4、学…...

云数据库 Redis 性能深度评测(阿里云、华为云、腾讯云、百度智能云)

在当今的云服务市场中&#xff0c;阿里云、腾讯云、华为云和百度智能云都是领先的云服务提供商&#xff0c;他们都提供了全套的云数据库服务&#xff0c;其中 Redis属于RDS 之后第二被广泛应用的服务&#xff0c;本次测试旨在深入比较这四家云服务巨头在Redis云数据库性能方面的…...

Android---Retrofit实现网络请求:Java 版

简介 在 Android 开发中&#xff0c;网络请求是一个极为关键的部分。Retrofit 作为一个强大的网络请求库&#xff0c;能够简化开发流程&#xff0c;提供高效的网络请求能力。 Retrofit 是一个建立在 OkHttp 基础之上的网络请求库&#xff0c;能够将我们定义的 Java 接口转化为…...

使用静态CRLSP配置MPLS TE隧道

正文共&#xff1a;1591 字 13 图&#xff0c;预估阅读时间&#xff1a;4 分钟 静态CRLSP&#xff08;Constraint-based Routed Label Switched Paths&#xff0c;基于约束路由的LSP&#xff09;是指在报文经过的每一跳设备上&#xff08;包括Ingress、Transit和Egress&#xf…...

gentoo安装笔记

最近比较闲&#xff0c;所以挑战一下自己&#xff0c;在自己的台式电脑上安装gentoo 下面记录了我亲自安装的步骤&#xff0c;作为以后我再次安装时参考所用。 整体步骤 一般来将一个linux发行版的安装步骤其实大体上都差不多&#xff0c;基本分为一下几步&#xff1a; 1. …...

Git如何使用 五分钟快速入门

Git如何使用 五分钟快速入门 Git是一个分布式版本控制系统&#xff0c;它可以帮助开发人员跟踪和管理项目的代码变更。与传统的集中式版本控制系统&#xff08;如SVN&#xff09;不同&#xff0c;Git允许开发人员在本地存储完整的代码仓库&#xff0c;并且可以独立地进行代码修…...

FreeRTOS学习笔记——(FreeRTOS临界段代码保护及调度器挂起与恢复)

这里写目录标题 1&#xff0c;临界段代码保护简介&#xff08;熟悉&#xff09;2&#xff0c;临界段代码保护函数介绍&#xff08;掌握&#xff09;3&#xff0c;任务调度器的挂起和恢复&#xff08;熟悉&#xff09; 1&#xff0c;临界段代码保护简介&#xff08;熟悉&#xf…...

多模态2025:技术路线“神仙打架”,视频生成冲上云霄

文&#xff5c;魏琳华 编&#xff5c;王一粟 一场大会&#xff0c;聚集了中国多模态大模型的“半壁江山”。 智源大会2025为期两天的论坛中&#xff0c;汇集了学界、创业公司和大厂等三方的热门选手&#xff0c;关于多模态的集中讨论达到了前所未有的热度。其中&#xff0c;…...

DeepSeek 赋能智慧能源:微电网优化调度的智能革新路径

目录 一、智慧能源微电网优化调度概述1.1 智慧能源微电网概念1.2 优化调度的重要性1.3 目前面临的挑战 二、DeepSeek 技术探秘2.1 DeepSeek 技术原理2.2 DeepSeek 独特优势2.3 DeepSeek 在 AI 领域地位 三、DeepSeek 在微电网优化调度中的应用剖析3.1 数据处理与分析3.2 预测与…...

Mybatis逆向工程,动态创建实体类、条件扩展类、Mapper接口、Mapper.xml映射文件

今天呢&#xff0c;博主的学习进度也是步入了Java Mybatis 框架&#xff0c;目前正在逐步杨帆旗航。 那么接下来就给大家出一期有关 Mybatis 逆向工程的教学&#xff0c;希望能对大家有所帮助&#xff0c;也特别欢迎大家指点不足之处&#xff0c;小生很乐意接受正确的建议&…...

Java 二维码

Java 二维码 **技术&#xff1a;**谷歌 ZXing 实现 首先添加依赖 <!-- 二维码依赖 --><dependency><groupId>com.google.zxing</groupId><artifactId>core</artifactId><version>3.5.1</version></dependency><de…...

Reasoning over Uncertain Text by Generative Large Language Models

https://ojs.aaai.org/index.php/AAAI/article/view/34674/36829https://ojs.aaai.org/index.php/AAAI/article/view/34674/36829 1. 概述 文本中的不确定性在许多语境中传达,从日常对话到特定领域的文档(例如医学文档)(Heritage 2013;Landmark、Gulbrandsen 和 Svenevei…...

C++ 设计模式 《小明的奶茶加料风波》

&#x1f468;‍&#x1f393; 模式名称&#xff1a;装饰器模式&#xff08;Decorator Pattern&#xff09; &#x1f466; 小明最近上线了校园奶茶配送功能&#xff0c;业务火爆&#xff0c;大家都在加料&#xff1a; 有的同学要加波霸 &#x1f7e4;&#xff0c;有的要加椰果…...

群晖NAS如何在虚拟机创建飞牛NAS

套件中心下载安装Virtual Machine Manager 创建虚拟机 配置虚拟机 飞牛官网下载 https://iso.liveupdate.fnnas.com/x86_64/trim/fnos-0.9.2-863.iso 群晖NAS如何在虚拟机创建飞牛NAS - 个人信息分享...

PostgreSQL——环境搭建

一、Linux # 安装 PostgreSQL 15 仓库 sudo dnf install -y https://download.postgresql.org/pub/repos/yum/reporpms/EL-$(rpm -E %{rhel})-x86_64/pgdg-redhat-repo-latest.noarch.rpm# 安装之前先确认是否已经存在PostgreSQL rpm -qa | grep postgres# 如果存在&#xff0…...

sshd代码修改banner

sshd服务连接之后会收到字符串&#xff1a; SSH-2.0-OpenSSH_9.5 容易被hacker识别此服务为sshd服务。 是否可以通过修改此banner达到让人无法识别此服务的目的呢&#xff1f; 不能。因为这是写的SSH的协议中的。 也就是协议规定了banner必须这么写。 SSH- 开头&#xff0c…...

【把数组变成一棵树】有序数组秒变平衡BST,原来可以这么优雅!

【把数组变成一棵树】有序数组秒变平衡BST,原来可以这么优雅! 🌱 前言:一棵树的浪漫,从数组开始说起 程序员的世界里,数组是最常见的基本结构之一,几乎每种语言、每种算法都少不了它。可你有没有想过,一组看似“线性排列”的有序数组,竟然可以**“长”成一棵平衡的二…...