简述
kobject_uevent_env用于Linux下热插拔事件产生时,通知到用户空间的一种方式,uevent是sysfs向用户空间发出的消息。
基本结构
// kobject事件类型
// 源码位置/kernel/msm-3.18/include/linux/kobject.h
enum kobject_action {
KOBJ_ADD,
KOBJ_REMOVE,
KOBJ_CHANGE,
KOBJ_MOVE,
KOBJ_ONLINE,
KOBJ_OFFLINE,
KOBJ_MAX
};
// 源码位置/kernel/msm-3.18/lib/kobject_uevent.c
/**
* kobject_uevent - notify userspace by sending an uevent
*
* @action: action that is happening
* @kobj: struct kobject that the action is happening to
*
* Returns 0 if kobject_uevent() is completed with success or the
* corresponding error when it fails.
*/
int kobject_uevent(struct kobject *kobj, enum kobject_action action)
/**
* kobject_uevent_env - send an uevent with environmental data
*
* @action: action that is happening
* @kobj: struct kobject that the action is happening to
* @envp_ext: pointer to environmental data
*
* Returns 0 if kobject_uevent_env() is completed with success or the
* corresponding error when it fails.
*/
int kobject_uevent_env(struct kobject *kobj, enum kobject_action action, char *envp_ext[])
应用实例
内核空间
1.device add:
/*
* device_add函数中会调用kobject_add,通知应用层有新设备添加
* &dev->kobj:事件发生位置
* KOBJ_ADD:事件类型
*/
kobject_uevent(&dev->kobj, KOBJ_ADD);
2.也可在自己的设备驱动里主动调用uevent接口上报消息
/*
* 这里通过sysfs attribute node向应用层提供接口
* 当有用户读取该node内容时,即可触发上报动作
* 上报动作可以直接调用kobject_uevent,事件类型为KOBJ_ADD,事件位置为&dev->kobj
* 也可调用kobject_uevent_env,第三个参数envp为自定义环境变量,同样会一起上报给应用层
*/
static ssize_t kobject_test_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
unsigned int size = 0;
// char *envp[2] = {"uevents report test!", NULL};
// kobject_uevent_env(&dev->kobj, KOBJ_ADD, envp);
kobject_uevent(&dev->kobj, KOBJ_ADD);
size += sprintf(buf, "uevents report test!\n");
return size;
}
用户空间
可参考Android 8.1/system/extras/tests/uevents代码,编译后将uevents推入系统,执行后即可监听来自内核的uevent事件上报。
#include <cutils/uevent.h>
#include <stdio.h>
#define UEVENT_MSG_LEN 1024
int main(int argc, char *argv[])
{
int device_fd;
char msg[UEVENT_MSG_LEN+2];
int n;
int i;
device_fd = uevent_open_socket(64*1024, true);
if(device_fd < 0)
return -1;
while ((n = uevent_kernel_multicast_recv(device_fd, msg, UEVENT_MSG_LEN)) > 0) {
msg[n] = '\0';
msg[n+1] = '\0';
for (i = 0; i < n; i++)
if (msg[i] == '\0')
msg[i] = ' ';
printf("%s\n", msg);
}
return 0;
}
// 移除驱动后打印监听到的uevent事件
remove@/devices/soc/soc:test_dev_for_spongebob/test_class/test_node ACTION=remove DEVPATH=/devices/soc/soc:test_dev_for_spongebob/test_class/test_node SUBSYSTEM=test_class MAJOR=222 MINOR=0 DEVNAME=test_node SEQN
UM=4074
remove@/test_class ACTION=remove DEVPATH=/test_class SUBSYSTEM=class SEQNUM=4075
remove@/bus/platform/drivers/test_drv_for_spongebob ACTION=remove DEVPATH=/bus/platform/drivers/test_drv_for_spongebob SUBSYSTEM=drivers SEQNUM=4076
remove@/module/test_driver ACTION=remove DEVPATH=/module/test_driver SUBSYSTEM=module SEQNUM=4077
// 加载驱动后打印监听到的uevent事件
add@/module/test_driver ACTION=add DEVPATH=/module/test_driver SUBSYSTEM=module SEQNUM=4078
add@/class/test_class ACTION=add DEVPATH=/class/test_class SUBSYSTEM=class SEQNUM=4079
add@/devices/soc/soc:test_dev_for_spongebob/test_class/test_node ACTION=add DEVPATH=/devices/soc/soc:test_dev_for_spongebob/test_class/test_node SUBSYSTEM=test_class MAJOR=222 MINOR=0 DEVNAME=test_node SEQNUM=408
0
add@/bus/platform/drivers/test_drv_for_spongebob ACTION=add DEVPATH=/bus/platform/drivers/test_drv_for_spongebob SUBSYSTEM=drivers SEQNUM=4081
参考链接https://blog.csdn.net/spongebob1912/article/details/108626930