Android :Kernel Uevent发送(热插拔)事件到用户空间

一、Uevent是一种在内核空间和用户空间之间通信的机制,主要用于热插拔事件(hotplug),比如USB和HDMI拔插事件。

二、uevent事件

         uevent事件在include/linux/kobject.h中有的定义,kobject对应的动作可分为以下几种:

三、发送事件方法

      内核中通过kobject_uevent_env函数将事件发送到用户空间

四、实例测试

      1、kernel驱动文件kobject_uevent_env.c

#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/kernel.h>
#include <linux/semaphore.h>
#include <linux/mutex.h>
#include <linux/syscalls.h>
#include <asm/unistd.h>
#include <asm/uaccess.h>
#include <linux/fs.h>
#include <linux/string.h>
#include <linux/gpio.h>
#include <linux/module.h>
#include <linux/proc_fs.h>
#include <linux/device.h>
#include <linux/kdev_t.h>
#include <linux/i2c.h>
#include <linux/input.h>
 
struct device *dev = NULL;
char * mesg[2];
static ssize_t send_message(struct device *dev,struct device_attribute *attr, const char *buf, size_t count)
{
	int ret = 0;
	char s_buf[100]={0};
	char *event_string = "HOTPLUG=1";
    mesg[0] =s_buf;
    //mesg[0]= "HOTPLUG=1";
    mesg[1] = NULL;
	
	//strcat(s_buf, "kobject_uevent_env hello");
	strcat(s_buf, buf);
	printk(KERN_WARNING "received message buf=%s s_buf=%s count=%d\n",buf,s_buf,count);
    kobject_uevent_env(&dev->kobj, KOBJ_CHANGE, mesg);
    return count;
}
static DEVICE_ATTR(m_point, S_IRUGO|S_IWUSR, NULL, send_message);

static const struct attribute *kobject_event_attr[] = {
        &dev_attr_m_point.attr,
        NULL,
};

static const struct attribute_group kobject_event_attr_group = {
        .attrs = (struct attribute **) kobject_event_attr,
};

static struct class kobject_event_class = {
        .name =         "kobject_event",
        .owner =        THIS_MODULE,
};

static int __init kobject_uevent_init(void)
{
    int ret = 0;
    ret = class_register(&kobject_event_class);
    if (ret < 0) {
      printk(KERN_ERR "song_event: class_register fail\n");
    return ret;
    }

    dev = device_create(&kobject_event_class, NULL, MKDEV(0, 0), NULL, "kobject_event");
    if (dev) {
       ret = sysfs_create_group(&dev->kobj, &kobject_event_attr_group);
       if(ret < 0) {
         printk(KERN_ERR "kobject_event:sysfs_create_group fail\r\n");
         return ret;
        }
    } else {
    printk(KERN_ERR "kobject_event:device_create fail\r\n");
    ret = -1;
    return ret;
   }
    return 0;
}
static __exit void kobject_uevent_exit(void)
{
    device_destroy(&kobject_event_class, MKDEV(0,0));
    class_destroy(&kobject_event_class);
    sysfs_remove_group(&dev->kobj, &kobject_event_attr_group);
    printk(KERN_WARNING "kobject_uevent_exit!\n");
}

module_init(kobject_uevent_init);
module_exit(kobject_uevent_exit);
 
MODULE_LICENSE("GPL");
MODULE_AUTHOR("haiyuexichen");

     2、user端c文件user_kobject_uevent_env.c

#include <sys/types.h>
#include <sys/socket.h>
#include <linux/netlink.h>

#define UEVENT_MSG_LEN 4096

int device_fd = -1;

struct listener_gliethttp {
    const char *action;
    const char *path;
    const char *subsystem;
    const char *firmware;
    int major;
    int minor;
};
static int init_socket(void)
{
    struct sockaddr_nl addr;
    int sz = 64*1024;
    int s;

    memset(&addr, 0, sizeof(addr));
    addr.nl_family = AF_NETLINK;
    addr.nl_pid = getpid();
    addr.nl_groups = 0xffffffff;

    s = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT);// uevent_fd_.Set(socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT));
    if (s < 0)
        return -1;

    setsockopt(s, SOL_SOCKET, SO_RCVBUFFORCE, &sz, sizeof(sz));

    if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
        close(s);
        return -1;
    }

    return s;
}
static void parse_event(const char *msg, struct listener_gliethttp *listener_gliethttp)
{
    listener_gliethttp->action = "";
    listener_gliethttp->path = "";
    listener_gliethttp->subsystem = "";
    listener_gliethttp->firmware = "";
    listener_gliethttp->major = -1;
    listener_gliethttp->minor = -1;
    printf("========================================================\n");
    while (*msg) {

        printf("%s\n", msg);

        if (!strncmp(msg, "ACTION=", 7)) {
            msg += 7;
            listener_gliethttp->action = msg;
        } else if (!strncmp(msg, "DEVPATH=", 8)) {
            msg += 8;
            listener_gliethttp->path = msg;
        } else if (!strncmp(msg, "SUBSYSTEM=", 10)) {
            msg += 10;
            listener_gliethttp->subsystem = msg;
        } else if (!strncmp(msg, "FIRMWARE=", 9)) {
            msg += 9;
            listener_gliethttp->firmware = msg;
        } else if (!strncmp(msg, "MAJOR=", 6)) {
         msg += 6;
            listener_gliethttp->minor = atoi(msg);
        } else if (!strncmp(msg, "PANEL_ALIVE=", 12)) {
            printf("PANEL_ALIVE==%d\n",atoi(msg));
        }

        while(*msg++)
            ;
    }
    printf("event { '%s', '%s', '%s', '%s', %d, %d }\n",
                    listener_gliethttp->action, listener_gliethttp->path, listener_gliethttp->subsystem,
                    listener_gliethttp->firmware, listener_gliethttp->major, listener_gliethttp->minor);
}
void UEventHandler() {
  char buffer[1024];
  int ret;
  while (1) {
	printf("*******************************************************************\n");
	printf("waiting data sent for kernel!\n");  
    ret = read(device_fd, &buffer, sizeof(buffer));
    if (ret == 0) {
      return;
    } else if (ret < 0) {
      printf("Got error reading uevent %d", ret);
      return;
    }
	printf("recevied message:\r\n");
    for (int i = 0; i < ret;) {
      char *event = buffer + i;
      if (strcmp(event, "DEVTYPE=drm_minor"))
      ;
      else if (strcmp(event, "HOTPLUG=1"))
      {

        printf("hwc_uevent detect hotplug");
      }
      printf("*********%s \r\n",event);
      i += strlen(event) + 1;
    }


  }
}


int main()
{
    char msg[UEVENT_MSG_LEN+2];
    int n;
    device_fd = init_socket();
	
	if(device_fd<0){
		printf("fail to init socket!\r\n");
		return 0;
	}else{
		printf("success to init socket!\r\n");
	}
		
	UEventHandler();
    while(1){
    
        while((n = recv(device_fd, msg, UEVENT_MSG_LEN, 0)) > 0){
            struct listener_gliethttp listener_gliethttp;
            
                if(n == UEVENT_MSG_LEN)
                continue;

            msg[n] = '\0';
            msg[n+1] = '\0';
            
            printf("-----------   msg=%s\n",msg);
            
            parse_event(msg, &listener_gliethttp);
            
            printf("-----------   msg=%s\n",msg);
        }
    }
}

  3、在android下真机执行效果

五、android sdk里面的就是用来实现这个Uevent事件接收 hardware\libhardware_legacy\uevent.c

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐