背景
技术需求,在插入hdmi接口的时候打开扩展屏应用程序,在拔出的时候关闭应用程序
udev
使用udev查询触发哪个事件
运行udev实时监视命令,然后拔插设备,观察输出信息
udevadm monitor
插入hdmi:
拔出hdmi:
观察输出可以发现,插入和拔出内核都是发送的change事件,而不是add/remove事件,容易踩坑。同时可以从后面看出系统显示设备的路径,这里截取后面的路径即/drm/card1
,因此可以得到该显示驱动路径:/sys/class/drm/card1
。
一般显示设备都会在/sys/class/drm
路径下:
不确定的话可以去某个文件下用cat读取status文件可以获取其状态,在插拔一下确认状态是否正确改变:
通过udev查询详细信息
使用上面确认后的设备路径,执行下面命令:
udevadm info --attribute-walk --path=$(udevadm info --query=path --path=/sys/class/drm/card1-HDMI-A-1)
通过命令的输出可以确认KERNELS和SUBSYSTEMS的值,于是编写udev的规则文件99-custom-hdmi.rules
sudo vim /etc/udev/rules.d/99-custom-hdmi.rules
加入如下内容:
ACTION=="change", KERNEL=="card1", SUBSYSTEMS=="drm", RUN+="/path/to/your/script.sh"
其中,捕获事件设置为change,KERNEL值设置为card1-HDMI-A-1,但实测这个值不起作用,于是设置为其父设备的值,SUBSYSTEMS的值设为drm,RUN中为事件响应时执行的脚本。
然后使配置文件生效:
udevadm trigger
这里我也设置不起作用,于是还是重启试试。
事件响应脚本
在响应脚本中执行你要处理的事情,我的脚本是启动扩展屏程序。
由于设备的插入或者拔出都是触发的change事件,所以需要在响应脚本中手动判断是插入或拔出。我的判断逻辑是读取设备文件的状态文件/sys/class/drm/card1/card1-HDMI-A-1/status
,插入时该状态是connected
,拔出时为disconnected
,代码:
#!/bin/bash
# 读取HDMI连接状态
status=$(cat /sys/class/drm/card1-HDMI-A-1/status)
tty=/dev/pts/0
# 拔出事件
if [ "$status" = "disconnected" ]; then
echo "HDMI disconnected..." > $tty
# 插入事件
else
echo "HDMI connected..." > $tty
fi
由于脚本不在tty中执行,因为需要指定tty才能接收到输出信息,可以在终端中使用tty
命令查看当前终端位置:
ok,这下插拔时就会有相应的响应了,上面脚本只是示例脚本,实际我在插入事件中启动我的应用,在拔出事件中杀掉应用。
注意:*.rules规则文件修改后必须重启生效,而响应脚本修改后不需要重启即生效。
problem:在脚本中执行我的程序,事件响应后会直接杀掉该程序
无论我的启动方式是后台还是挂起,脚本执行完毕后都会杀掉程序
我们打印执行前后的进程树:pstree -up
执行事件处理时:
执行事件处理后:
也是通过这一步才发现原来脚本执行后就会杀掉程序,不知道什么原因,但是这种处理方式肯定不行。
后面想到了把应用程序注册为服务,在响应脚本中启动服务,这样应用程序的进程与响应脚本的进程独立,不受影响。
第一次写,记录一下工作中遇到的问题,文笔不好切莫责怪,感谢支持~~~