说明:本文基于Android2.3和Linux2.6,其余版本仅供参考。
Android2.3及Linux2.6.29内核模拟器版本编译与调试
阅读本文前请阅读:Linux总线、设备、驱动与设备节点创建、用户测试程序
一、netlink监听程序
testnet.c
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <errno.h> #include <sys/types.h> #include <asm/types.h> //该头文件需要放在netlink.h前面防止编译出现__kernel_sa_family未定义 #include <sys/socket.h> #include <linux/netlink.h> void MonitorNetlinkUevent() { int sockfd; struct sockaddr_nl sa; int len; char buf[4096]; struct iovec iov; struct msghdr msg; int i; memset(&sa,0,sizeof(sa)); sa.nl_family=AF_NETLINK; sa.nl_groups=NETLINK_KOBJECT_UEVENT; sa.nl_pid = 0;//getpid(); both is ok memset(&msg,0,sizeof(msg)); iov.iov_base=(void *)buf; iov.iov_len=sizeof(buf); msg.msg_name=(void *)&sa; msg.msg_namelen=sizeof(sa); msg.msg_iov=&iov; msg.msg_iovlen=1; sockfd=socket(AF_NETLINK,SOCK_RAW,NETLINK_KOBJECT_UEVENT); if(sockfd==-1) printf("socket creating failed:%s\n",strerror(errno)); if(bind(sockfd,(struct sockaddr *)&sa,sizeof(sa))==-1) printf("bind error:%s\n",strerror(errno)); while(1){ memset(buf,0,sizeof(buf)); len=recvmsg(sockfd,&msg,0); if(len<0){} //printf("receive error\n"); else if(len<32||len>sizeof(buf)) printf("invalid message"); for(i=0;i<len;i++) if(*(buf+i)=='\0') buf[i]='\n'; printf("received %d bytes\n%s\n",len,buf); } } int main(int argc,char **argv) { MonitorNetlinkUevent(); return 0; }Android.mk
LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) LOCAL_SRC_FILES:= \ testnet.c LOCAL_SHARED_LIBRARIES := \ libutils LOCAL_MODULE:= testnet LOCAL_MODULE_TAGS := optional include $(BUILD_EXECUTABLE)
二、如下是添加打印后的信息(Android用户空间udev为ueventd,属于init的一个软连接)
1.总线驱动
root@android:/data/tank # insmod testbus.ko
//内核模块加载成功,会上报netlink TK------->>>>>>kobject_uevent.c>>>>>kobject_uevent_env kobject: 'testbus' (bf02d1c8): kobject_uevent_env TK------->>>>>>kobject_uevent.c>>>>>kobject_uevent_env>>>>netlink_broadcast //总线注册上报netlink TK---testlddbus.c----->>>>ldd_bus_init TK--------->>>>>>bus.c>>>>>>bus_register,,,bus->name is ldd TK-------_>>>>kobject.c>>>>>>>kset_register TK-------_>>>>kobject.c>>>>>>>kset_register>>>kobject_uevent TK------->>>>>>kobject_uevent.c>>>>>kobject_uevent_env kobject: 'ldd' (cfcdb1c8): kobject_uevent_env TK------->>>>>>kobject_uevent.c>>>>>kobject_uevent_env>>>>netlink_broadcast //设备注册由于没有分配主设备号,不上报netlink TK-------_>>>>>>>>core.c>>>>>device_register TK-------_>>>>>>>>core.c>>>>>device_add TK-------_>>>>>>>>core.c>>>>>device_add>>>>>kobject_uevent TK------->>>>>>kobject_uevent.c>>>>>kobject_uevent_env TK-------_>>>>>>drivers/base/core.c>>dev_uevent_filter>>ktype is 0xc032137c,&device_ktype is 0xc032137c TK-------->>>>drivers/base/core.c>>dev_uevent_filter>>dev->uevent_suppress is 0 TK-------->>>>drivers/base/core.c>>dev_uevent_filter>>dev->bus is 0x0 TK-------->>>>drivers/base/core.c>>dev_uevent_filter>>dev->class is 0x0 kobject: 'ldd0' (bf02d074): kobject_uevent_env kobject: 'ldd0' (bf02d074): kobject_uevent_env: filter function caused the event to drop! //用户空间ueventd的处理,2个uevent事件 init: TK-------_>>>>>uevent.c>>>>>>ueventd_main>>>>ufd.fd is 4 init: TK-------_>>>>>>device.c.>>>>>>handle_device_fd init: TK------------>>>>device.c>>>>>>handle_device_event>>>>uevent->major is -1,uevent->minor is -1 init: TK------------>>>>device.c>>>>>>handle_device_event>>>>>>uevent->major and minor < 0 init: TK------------>>>>device.c>>>>>>handle_device_event>>>>uevent->major is -1,uevent->minor is -1 init: TK------------>>>>device.c>>>>>>handle_device_event>>>>>>uevent->major and minor < 0 received 83 bytes add@/module/testbus ACTION=add DEVPATH=/module/testbus SUBSYSTEM=module SEQNUM=649 received 66 bytes add@/bus/ldd ACTION=add DEVPATH=/bus/ldd SUBSYSTEM=bus SEQNUM=650说明:
drivers/base/bus.c
int bus_register(struct bus_type *bus){ retval = kset_register(&priv->subsys); /* lib/kobject.c int kset_register(struct kset *k){ kobject_uevent(&k->kobj, KOBJ_ADD); } */ retval = bus_create_file(bus, &bus_attr_uevent); priv->devices_kset = kset_create_and_add("devices", NULL, &priv->subsys.kobj); priv->drivers_kset = kset_create_and_add("drivers", NULL, &priv->subsys.kobj); }
2.插入设备
root@android:/data/tank # insmod testdev.ko
//内核模块加载会上报netlink TK------->>>>>>kobject_uevent.c>>>>>kobject_uevent_env kobject: 'testdev' (bf0334e0): kobject_uevent_env TK------->>>>>>kobject_uevent.c>>>>>kobject_uevent_env>>>>netlink_broadcast //没有主设备号,不会上报netlink TK---testdev.c----->>>>mini_init TK-------_>>>>>>>>core.c>>>>>device_register TK-------_>>>>>>>>core.c>>>>>device_add TK-------_>>>>>>>>core.c>>>>>device_add>>>>>kobject_uevent TK------->>>>>>kobject_uevent.c>>>>>kobject_uevent_env kobject: 'mini' (bf0333dc): kobject_uevent_env TK-------_>>>>>>drivers/base/core.c>>dev_uevent_filter>>ktype is 0xc032137c,&device_ktype is 0xc032137c TK-------->>>>drivers/base/core.c>>dev_uevent_filter>>dev->uevent_suppress is 0 TK-------->>>>drivers/base/core.c>>dev_uevent_filter>>dev->bus is 0xbf001130 TK---testlddbus.c----->>>>ldd_uevent TK-------_>>>>>>drivers/base/core.c>>dev_uevent>>retval is -12 kobject: 'mini' (bf0333dc): kobject_uevent_env: uevent() returned -12 //用户空间ueventd的处理,1个uevent事件 init: TK-------_>>>>>uevent.c>>>>>>ueventd_main>>>>ufd.fd is 4 init: TK-------_>>>>>>device.c.>>>>>>handle_device_fd init: TK------------>>>>device.c>>>>>>handle_device_event>>>>uevent->major is -1,uevent->minor is -1 init: TK------------>>>>device.c>>>>>>handle_device_event>>>>>>uevent->major and minor < 0 received 83 bytes add@/module/testdev ACTION=add DEVPATH=/module/testdev SUBSYSTEM=module SEQNUM=6513.设备驱动
root@android:/data/tank # insmod testdriver.ko
//内核模块成功加载,会上报netlink TK------->>>>>>kobject_uevent.c>>>>>kobject_uevent_env kobject: 'testdriver' (bf039c34): kobject_uevent_env TK------->>>>>>kobject_uevent.c>>>>>kobject_uevent_env>>>>netlink_broadcast //类注册会上报netlink(class_creat) TK---testdriver.c----->>>>driver_init Tk--------->>>>>driver.c>>>>>>driver_register TK---------_>>>>>bus.c>>>>>>>bus_add_driver TK---testbus.c----->>>>ldd_match TK---testbus.c----->>>>ldd_match TK---testlddbus.c----->>>>ldd_drv_probe TK----testdriver.c------>>>>driver_probe mini TK-------_>>>>kobject.c>>>>>>>kset_register TK-------_>>>>kobject.c>>>>>>>kset_register>>>kobject_uevent TK------->>>>>>kobject_uevent.c>>>>>kobject_uevent_env kobject: 'mymodule' (cfee5b68): kobject_uevent_env TK------->>>>>>kobject_uevent.c>>>>>kobject_uevent_env>>>>netlink_broadcast //有主设备号时设备注册上报netlink TK-------->>>>>core.c>>>>device_create TK-------_>>>>>>>>core.c>>>>>device_register TK-------_>>>>>>>>core.c>>>>>device_add TK-------_>>>>>>>>core.c>>>>>device_add>>>>>kobject_uevent TK------->>>>>>kobject_uevent.c>>>>>kobject_uevent_env kobject: 'mymod0' (caa4e724): kobject_uevent_env TK-------_>>>>>>drivers/base/core.c>>dev_uevent_filter>>ktype is 0xc032137c,&device_ktype is 0xc032137c TK-------->>>>drivers/base/core.c>>dev_uevent_filter>>dev->uevent_suppress is 0 TK-------->>>>drivers/base/core.c>>dev_uevent_filter>>dev->bus is 0x0 TK-------->>>>drivers/base/core.c>>dev_uevent_filter>>dev->class is 0xcaade760 TK-------_>>>>>>drivers/base/core.c>>dev_uevent>>retval is 0 TK------->>>>>>kobject_uevent.c>>>>>kobject_uevent_env>>>>netlink_broadcast //驱动注册都会上报netlink TK---------_>>>>>bus.c>>>>>>>bus_add_driver>>>>kobject_uevent TK------->>>>>>kobject_uevent.c>>>>>kobject_uevent_env kobject: 'mini' (c8aa48c0): kobject_uevent_env TK------->>>>>>kobject_uevent.c>>>>>kobject_uevent_env>>>>netlink_broadcast //用户空间ueventd的处理,4个uevent事件 init: TK-------_>>>>>uevent.c>>>>>>ueventd_main>>>>ufd.fd is 4 init: TK-------_>>>>>>device.c.>>>>>>handle_device_fd init: TK------------>>>>device.c>>>>>>handle_device_event>>>>uevent->major is -1,uevent->minor is -1 init: TK------------>>>>device.c>>>>>>handle_device_event>>>>>>uevent->major and minor < 0 init: TK------------>>>>device.c>>>>>>handle_device_event>>>>uevent->major is -1,uevent->minor is -1 init: TK------------>>>>device.c>>>>>>handle_device_event>>>>>>uevent->major and minor < 0 init: TK------------>>>>device.c>>>>>>handle_device_event>>>>uevent->major is 248,uevent->minor is 0 init: TK------_>>>>>>>>>make_devices init: TK------------>>>>device.c>>>>>>handle_device_event>>>>uevent->major is -1,uevent->minor is -1 init: TK------------>>>>device.c>>>>>>handle_device_event>>>>>>uevent->major and minor < 0 received 89 bytes add@/module/testdriver ACTION=add DEVPATH=/module/testdriver SUBSYSTEM=module SEQNUM=652 received 82 bytes add@/class/mymodule ACTION=add DEVPATH=/class/mymodule SUBSYSTEM=class SEQNUM=653 received 137 bytes add@/devices/virtual/mymodule/mymod0 ACTION=add DEVPATH=/devices/virtual/mymodule/mymod0 SUBSYSTEM=mymodule MAJOR=248 MINOR=0 SEQNUM=654 received 96 bytes add@/bus/ldd/drivers/mini ACTION=add DEVPATH=/bus/ldd/drivers/mini SUBSYSTEM=drivers SEQNUM=655说明:
drivers/base/driver.c
int driver_register(struct device_driver *drv){ ret = bus_add_driver(drv); /* drivers/base/bus.c int bus_add_driver(struct device_driver *drv){ kobject_uevent(&priv->kobj, KOBJ_ADD); } */ }include/linux/device.h
#define class_create(owner, name) \ ({ \ static struct lock_class_key __key; \ __class_create(owner, name, &__key); \ /* drivers/base/class.c retval = __class_register(cls, key); int __class_register(struct class *cls, struct lock_class_key *key){ error = kset_register(&cp->subsys); } lib/kobject.c int kset_register(struct kset *k){ kobject_uevent(&k->kobj, KOBJ_ADD); } */ })
drivers/base/core.c
struct device *device_create(struct class *class, struct device *parent, dev_t devt, void *drvdata, const char *fmt, ...){ dev = device_create_vargs(class, parent, devt, drvdata, fmt, vargs); /* struct device *device_create_vargs(struct class *class, struct device *parent, dev_t devt, void *drvdata, const char *fmt, va_list args){ retval = device_register(dev); } int device_register(struct device *dev){ return device_add(dev); } int device_add(struct device *dev){ error = kobject_add(&dev->kobj, dev->kobj.parent, "%s", dev_name(dev)); if (MAJOR(dev->devt)) { //有设备号才会上报uevent事件!! error = device_create_file(dev, &devt_attr); if (error) goto ueventattrError; error = device_create_sys_dev_entry(dev); if (error) goto devtattrError; } kobject_uevent(&dev->kobj, KOBJ_ADD); } */ }总结:
bus_register,driver_register,class_create,device_create以及内核模块加载有uevent通过netlink上报,
device_register的uevent会根据是否有设备号来决定是否上报事件。
三、最后分析下内核kobject_uevent函数:
对于uevent通过netlink的事件上报,其实还是kobject这个类起作用。
1.看总线注册给Linux内核总线模型的情况,即bus_register
先回忆下内核启动时总线模型初始化:
drivers/base/bus.c
int __init buses_init(void) { bus_kset = kset_create_and_add("bus", &bus_uevent_ops, NULL); } static struct kset_uevent_ops bus_uevent_ops = { .filter = bus_uevent_filter, };
具体过滤规则可以看代码;我想说的是Linux内核总线模型的过滤函数很简单、没有特别限制,这样在我们注册一个新的总线(bus_register)时、都会上报uevent事件。
2.看设备注册给Linux内核设备模型的情况,即device_register
先会议下内核启动时设备模型初始化:
drivers/base/core.c
int __init devices_init(void) { devices_kset = kset_create_and_add("devices", &device_uevent_ops, NULL); } static struct kset_uevent_ops device_uevent_ops = { .filter = dev_uevent_filter, .name = dev_uevent_name, .uevent = dev_uevent, }
具体过滤规则可以看代码;我想说的是Linux内核设备模型的过滤函数和是否uevent上报函数比较复杂,其中过滤函数功能是:如果新注册到设备模型的设备不属于总线、不会上报uevent,如果新注册设备没有主次设备号也不会上报uevent;只有上述两个同时满足时,才会上报。
lib/kobject_uevent.c
int kobject_uevent(struct kobject *kobj, enum kobject_action action){ return kobject_uevent_env(kobj, action, NULL); } EXPORT_SYMBOL_GPL(kobject_uevent); int kobject_uevent_env(struct kobject *kobj, enum kobject_action action, char *envp_ext[]){ struct kobject *top_kobj; struct kset *kset; struct kset_uevent_ops *uevent_ops; top_kobj = kobj; while (!top_kobj->kset && top_kobj->parent) top_kobj = top_kobj->parent; kset = top_kobj->kset; uevent_ops = kset->uevent_ops; if (uevent_ops && uevent_ops->filter) //kset的过滤规则,详细看drivers/base/core.c的dev_uevent_filter函数 if (!uevent_ops->filter(kset, kobj)) { /* drivers/base/core.c int __init devices_init(void){ devices_kset = kset_create_and_add("devices", &device_uevent_ops, NULL); } static struct kset_uevent_ops device_uevent_ops = { .filter = dev_uevent_filter,//上处uevent_ops->filter(kset, kobj)就是这个 .name = dev_uevent_name, .uevent = dev_uevent,//下边uevent_ops->uevent(kset, kobj, env)就是这个 }; */ pr_debug("kobject: '%s' (%p): %s: filter function " "caused the event to drop!\n", kobject_name(kobj), kobj, __func__); //change by tank from pr_debug to printk return 0; } if (uevent_ops && uevent_ops->uevent) { //无设备号的设备注册不会被上报!详细看drivers/base/core.c的dev_uevent函数 retval = uevent_ops->uevent(kset, kobj, env); if (retval) { pr_debug("kobject: '%s' (%p): %s: uevent() returned " "%d\n", kobject_name(kobj), kobj, __func__, retval); //change by tank from pr_debug to printk goto exit; } } retval = netlink_broadcast_filtered(uevent_sock, skb, 0, 1, GFP_KERNEL, kobj_bcast_filter, kobj); //netlink上报事件 }net/netlink/af_netlink.c
int netlink_broadcast_filtered(struct sock *ssk, struct sk_buff *skb, u32 pid, u32 group, gfp_t allocation, int (*filter)(struct sock *dsk, struct sk_buff *skb, void *data), void *filter_data){ }