安卓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从插入到拔出经过底层一系列检测到应用层,应用层获取hdmi插入状态后又会做出一系列相应的动作,下面梳理了从应用层到底层一步步追踪到芯片的hpd-pin的检测过程。 frameworks/base/services/core/java/com/android/server/policy/PhoneWindowManager.…...
OkHttp Retrofit HttpClient之间的区别
OkHttp、Retrofit 和 HttpClient 是三个不同的 HTTP 客户端库,它们各自有不同的特点和用途。下面是它们之间的主要区别: 1. **OkHttp**: - OkHttp 是一个高性能的 HTTP 和 HTTP/2 客户端,由 Square 公司开发。 - 它…...

Paddlepaddle使用自己的VOC数据集训练目标检测(0废话简易教程)
一 安装paddlepaddle和paddledection(略) 笔者使用的是自己的数据集 二 在dataset目录下新建自己的数据集文件,如下: 其中 xml文件内容如下: 另外新建一个createList.py文件: # -- coding: UTF-8 -- imp…...
【解析】C语言两个实例
例一: 下面程序输出什么? 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是一个用于数据科学和机器学习的开源软件包管理器和环境管理器。它包含了许多流行的数据科学工具和库,如Python、Jupyter Notebook、numpy、pandas、scikit-learn等,可以帮助用户轻松地管理和安装这些工具和库。Anaco…...

Linux 驱动开发基础知识——APP 怎么读取按键值(十二)
个人名片: 🦁作者简介:学生 🐯个人主页:妄北y 🐧个人QQ:2061314755 🐻个人邮箱:2061314755qq.com 🦉个人WeChat:Vir2021GKBS 🐼本文由…...

【FastAPI】P3 请求与响应
目录 请求路径参数查询参数 响应JSON 响应文本响应返回 Pydantic 模型 在网络通讯中,请求(Request) 与 响应(Response) 扮演着至关重要的角色,它们构成了客户端与服务器间互动的根本理念。 请求࿰…...

Python学习-流程图、分支与循环(branch and loop)
十、流程图 1、流程图(Flowchart) 流程图是一种用于表示算法或代码流程的框图组合,它以不同类型的框框代表不同种类的程序步骤,每两个步骤之间以箭头连接起来。 好处: 1)代码的指导文档 2)有助…...
Python Flask Web 框架学习笔记+完整项目
Flask是一个轻量级的基于Python的web框架。 我们建议使用最新版本的 Python。Flask 支持 Python 3.8 及更高版本。 官网:欢迎使用 Flask — Flask 文档 (3.0.x) (palletsprojects.com) RESTFul API:Python Flask高级编程之REST…...

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

排序算法之——直接插入排序
直接插入排序——以升序排列为例 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基本思想 把待排序的记录按其关键码值的大小逐个插入到一个已经排好序的有序序列中,直…...

突出最强算法模型——回归算法 !!
文章目录 1、特征工程的重要性 2、缺失值和异常值的处理 (1)处理缺失值 (2)处理异常值 3、回归模型的诊断 (1)残差分析 (2)检查回归假设 (3)Cooks 距离 4、学…...

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

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

使用静态CRLSP配置MPLS TE隧道
正文共:1591 字 13 图,预估阅读时间:4 分钟 静态CRLSP(Constraint-based Routed Label Switched Paths,基于约束路由的LSP)是指在报文经过的每一跳设备上(包括Ingress、Transit和Egress…...
gentoo安装笔记
最近比较闲,所以挑战一下自己,在自己的台式电脑上安装gentoo 下面记录了我亲自安装的步骤,作为以后我再次安装时参考所用。 整体步骤 一般来将一个linux发行版的安装步骤其实大体上都差不多,基本分为一下几步: 1. …...
Git如何使用 五分钟快速入门
Git如何使用 五分钟快速入门 Git是一个分布式版本控制系统,它可以帮助开发人员跟踪和管理项目的代码变更。与传统的集中式版本控制系统(如SVN)不同,Git允许开发人员在本地存储完整的代码仓库,并且可以独立地进行代码修…...

FreeRTOS学习笔记——(FreeRTOS临界段代码保护及调度器挂起与恢复)
这里写目录标题 1,临界段代码保护简介(熟悉)2,临界段代码保护函数介绍(掌握)3,任务调度器的挂起和恢复(熟悉) 1,临界段代码保护简介(熟悉…...
应用升级/灾备测试时使用guarantee 闪回点迅速回退
1.场景 应用要升级,当升级失败时,数据库回退到升级前. 要测试系统,测试完成后,数据库要回退到测试前。 相对于RMAN恢复需要很长时间, 数据库闪回只需要几分钟。 2.技术实现 数据库设置 2个db_recovery参数 创建guarantee闪回点,不需要开启数据库闪回。…...
R语言AI模型部署方案:精准离线运行详解
R语言AI模型部署方案:精准离线运行详解 一、项目概述 本文将构建一个完整的R语言AI部署解决方案,实现鸢尾花分类模型的训练、保存、离线部署和预测功能。核心特点: 100%离线运行能力自包含环境依赖生产级错误处理跨平台兼容性模型版本管理# 文件结构说明 Iris_AI_Deployme…...

中南大学无人机智能体的全面评估!BEDI:用于评估无人机上具身智能体的综合性基准测试
作者:Mingning Guo, Mengwei Wu, Jiarun He, Shaoxian Li, Haifeng Li, Chao Tao单位:中南大学地球科学与信息物理学院论文标题:BEDI: A Comprehensive Benchmark for Evaluating Embodied Agents on UAVs论文链接:https://arxiv.…...

ESP32读取DHT11温湿度数据
芯片:ESP32 环境:Arduino 一、安装DHT11传感器库 红框的库,别安装错了 二、代码 注意,DATA口要连接在D15上 #include "DHT.h" // 包含DHT库#define DHTPIN 15 // 定义DHT11数据引脚连接到ESP32的GPIO15 #define D…...
Spring AI 入门:Java 开发者的生成式 AI 实践之路
一、Spring AI 简介 在人工智能技术快速迭代的今天,Spring AI 作为 Spring 生态系统的新生力量,正在成为 Java 开发者拥抱生成式 AI 的最佳选择。该框架通过模块化设计实现了与主流 AI 服务(如 OpenAI、Anthropic)的无缝对接&…...
AspectJ 在 Android 中的完整使用指南
一、环境配置(Gradle 7.0 适配) 1. 项目级 build.gradle // 注意:沪江插件已停更,推荐官方兼容方案 buildscript {dependencies {classpath org.aspectj:aspectjtools:1.9.9.1 // AspectJ 工具} } 2. 模块级 build.gradle plu…...

html-<abbr> 缩写或首字母缩略词
定义与作用 <abbr> 标签用于表示缩写或首字母缩略词,它可以帮助用户更好地理解缩写的含义,尤其是对于那些不熟悉该缩写的用户。 title 属性的内容提供了缩写的详细说明。当用户将鼠标悬停在缩写上时,会显示一个提示框。 示例&#x…...

零基础在实践中学习网络安全-皮卡丘靶场(第九期-Unsafe Fileupload模块)(yakit方式)
本期内容并不是很难,相信大家会学的很愉快,当然对于有后端基础的朋友来说,本期内容更加容易了解,当然没有基础的也别担心,本期内容会详细解释有关内容 本期用到的软件:yakit(因为经过之前好多期…...
怎么让Comfyui导出的图像不包含工作流信息,
为了数据安全,让Comfyui导出的图像不包含工作流信息,导出的图像就不会拖到comfyui中加载出来工作流。 ComfyUI的目录下node.py 直接移除 pnginfo(推荐) 在 save_images 方法中,删除或注释掉所有与 metadata …...
【Elasticsearch】Elasticsearch 在大数据生态圈的地位 实践经验
Elasticsearch 在大数据生态圈的地位 & 实践经验 1.Elasticsearch 的优势1.1 Elasticsearch 解决的核心问题1.1.1 传统方案的短板1.1.2 Elasticsearch 的解决方案 1.2 与大数据组件的对比优势1.3 关键优势技术支撑1.4 Elasticsearch 的竞品1.4.1 全文搜索领域1.4.2 日志分析…...