android & Linux uevent机制
2024-10-02 01:21:33
Linux uevent机制 Uevent是内核通知android有状态变化的一种方法,比如USB线插入、拔出,电池电量变化等等。其本质是内核发送(可以通过socket)一个字符串,应用层(android)接收并解释该字符串,获取相应信息。 一、Kernel侧: UEVENT的发起在Kernel端,主要是通过函数 int kobject_uevent_env(struct kobject *kobj, enum kobject_action action,char *envp_ext[]) 该函数的主要功能是根据参数组合一个字符串并发送。一个典型的字符串如下:change@/devices/platform/msm-battery/power_supply/usb纮ACTION=change纮DEVPATH=/devices/platform/msm-battery/power_supply/usb纮SUBSYSTEM=power_supply纮POWER_SUPPLY_NAME=usb纮POWER_SUPPLY_ONLINE=0纮SEQNUM=1486纮 上面这块来自网上,这段内容是否有问题,待考究。 下面看这个函数: int kobject_uevent_env(struct kobject *kobj, enum kobject_action action, char *envp_ext[]) { struct kobj_uevent_env *env; const char *action_string = kobject_actions[action];//获取object的动作 //蓝色为为方便看代码加入的 static const char *kobject_actions[] = { [KOBJ_ADD] = "add", [KOBJ_REMOVE] = "remove", [KOBJ_CHANGE] = "change", [KOBJ_MOVE] = "move", [KOBJ_ONLINE] = "online", [KOBJ_OFFLINE] = "offline", }; //以上为kobject标准的动作,调用时需要传入相应的enum值 const char *devpath = NULL; const char *subsystem; struct kobject *top_kobj; struct kset *kset; const struct kset_uevent_ops *uevent_ops; u64 seq; ; ; #ifdef CONFIG_NET struct uevent_sock *ue_sk; #endif pr_debug("kobject: '%s' (%p): %s\n", kobject_name(kobj), kobj, __func__); ========================================================= 这段代码用来查找该kobject所属于的kset,得到 uevent_ops top_kobj = kobj; while (!top_kobj->kset && top_kobj->parent) top_kobj = top_kobj->parent; if (!top_kobj->kset) { pr_debug("kobject: '%s' (%p): %s: attempted to send uevent " "without kset!\n", kobject_name(kobj), kobj, __func__); return -EINVAL; } kset = top_kobj->kset; uevent_ops = kset->uevent_ops; ========================================================= if (kobj->uevent_suppress) { pr_debug("kobject: '%s' (%p): %s: uevent_suppress " "caused the event to drop!\n", kobject_name(kobj), kobj, __func__); ; } if (uevent_ops && uevent_ops->filter) if (!uevent_ops->filter(kset, kobj)) { pr_debug("kobject: '%s' (%p): %s: filter function " "caused the event to drop!\n", kobject_name(kobj), kobj, __func__); ; } ==================================================== 获取subsystem信息 if (uevent_ops && uevent_ops->name) subsystem = uevent_ops->name(kset, kobj); else subsystem = kobject_name(&kset->kobj); if (!subsystem) { pr_debug("kobject: '%s' (%p): %s: unset subsystem caused the " "event to drop!\n", kobject_name(kobj), kobj, __func__); ; } ========================================================= env = kzalloc(sizeof(struct kobj_uevent_env), GFP_KERNEL); if (!env) return -ENOMEM; devpath = kobject_get_path(kobj, GFP_KERNEL);//获取kobject的设备路径 if (!devpath) { retval = -ENOENT; goto exit; } //下面准备要传递的信息数据 retval = add_uevent_var(env, "ACTION=%s", action_string); if (retval) goto exit; retval = add_uevent_var(env, "DEVPATH=%s", devpath); if (retval) goto exit; retval = add_uevent_var(env, "SUBSYSTEM=%s", subsystem); if (retval) goto exit; //envp_ext[i]是传进来的参数,为该event时携带的一些自定义的信息 if (envp_ext) { ; envp_ext[i]; i++) { retval = add_uevent_var(env, "%s", envp_ext[i]); if (retval) goto exit; } } if (uevent_ops && uevent_ops->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); goto exit; } } if (action == KOBJ_ADD) kobj->state_add_uevent_sent = ; else if (action == KOBJ_REMOVE) kobj->state_remove_uevent_sent = ; //加入该event的序号 spin_lock(&sequence_lock); seq = ++uevent_seqnum; spin_unlock(&sequence_lock); retval = add_uevent_var(env, "SEQNUM=%llu", (unsigned long long)seq); if (retval) goto exit; #if defined(CONFIG_NET) //下面通过网络socket将数据发送出去 mutex_lock(&uevent_sock_mutex); list_for_each_entry(ue_sk, &uevent_sock_list, list) { struct sock *uevent_sock = ue_sk->sk; struct sk_buff *skb; size_t len; len = strlen(action_string) + strlen(devpath) + ; skb = alloc_skb(len + env->buflen, GFP_KERNEL);//申请网络skb数据 if (skb) { char *scratch; scratch = skb_put(skb, len); sprintf(scratch, "%s@%s", action_string, devpath); 此时scratch中就增加了change@/devices/platform/msm-battery/power_supply/usb的 //组长网络skb数据结构 ; i < env->envp_idx; i++) { len = strlen(env->envp[i]) + ; scratch = skb_put(skb, len); strcpy(scratch, env->envp[i]); } NETLINK_CB(skb).dst_group = ;//下面开始发送数据 retval = netlink_broadcast_filtered(uevent_sock, skb, , , GFP_KERNEL, kobj_bcast_filter, kobj); if (retval == -ENOBUFS || retval == -ESRCH) retval = ; } else retval = -ENOMEM; } mutex_unlock(&uevent_sock_mutex); #endif ] && !kobj_usermode_filter(kobj)) { ]; argv [] = uevent_helper; argv [] = (char *)subsystem; argv [] = NULL; retval = add_uevent_var(env, "HOME=/"); if (retval) goto exit; retval = add_uevent_var(env, "PATH=/sbin:/bin:/usr/sbin:/usr/bin"); if (retval) goto exit; retval = call_usermodehelper(argv[], argv, env->envp, UMH_WAIT_EXEC); } exit: kfree(devpath); kfree(env); return retval; } 二 android 侧 private final UEventObserver mUEventObserver = new UEventObserver() { @Override public void onUEvent(UEventObserver.UEvent event) { if (DEBUG) Slog.v(TAG, "USB UEVENT: " + event.toString()); String state = event.get("USB_STATE"); String accessory = event.get("ACCESSORY"); //Added for USB Develpment debug, more log for more debuging help if(DEBUG) Log.w(TAG, "mUEventObserver: onUEvent: state = " + state); //Added for USB Develpment debug, more log for more debuging help if (state != null) { mHandler.updateState(state); } else if ("START".equals(accessory)) { if (DEBUG) Slog.d(TAG, "got accessory start"); setCurrentFunction(UsbManager.USB_FUNCTION_ACCESSORY, false); } } }; 在类初始化时会调用下面的动作,启动监听动作。 mUEventObserver.startObserving(USB_STATE_MATCH); 最终会调用到UEventObserver的addObserver: private ArrayList<Object> mObservers = new ArrayList<Object>(); public void addObserver(String match, UEventObserver observer) { synchronized(mObservers) { mObservers.add(match); mObservers.add(observer); } } private static final String USB_STATE_MATCH = "DEVPATH=/devices/virtual/android_usb/android0"; 该函数最终会将”DEVPATH=/devices/virtual/android_usb/android0”增加到匹配序列中,当kernel发送具有该字符串的数据时,就返回匹配成功,然后调用mUEventObserver 的onUEvent函数; UeventObserver.java private static class UEventThread extends Thread { private ArrayList<Object> mObservers = new ArrayList<Object>(); UEventThread() { super("UEventObserver"); } public void run() { native_setup(); ]; int len; while (true) { len = next_event(buffer); ) { String bufferStr = , len); // easier to search a String synchronized (mObservers) { ; i < mObservers.size(); i += ) { ) { ((UEventObserver)mObservers.)) .onUEvent(new UEvent(bufferStr)); } } } } } }
最新文章
- Thinkphp的初级注意点
- 又一个半成品库 weblog rpc client
- 通过grep来进行日志分析,grep -C和配合awk实际对catalina.out使用案例
- [Java面试四]Strust2总结及在面试中的一些问题.
- ASP.NET MVC5+EF6搭建三层实例
- Spring Cache 介绍
- 在 Windows 和 Linux(Gnome) 环境下 从命令界面打开网页的方式
- [转]ubuntu环境变量配置文件
- Hibernate笔记——关联关系配置(一对多、一对一和多对多)
- Linux--------------安装tomcat8
- STL之algorithm、numeric、functional
- 全国计算机等级考试二级教程-C语言程序设计_第13章_编译预处理和动态存储分配
- 一百多道.NET面试题!
- cmd第一次推送github
- SmartCoder每日站立会议03
- linux学习(十)find命令、Linux文件后缀名、Linux和windows文件互传
- JS(API-日期和math)
- Asp.Net Core WebApi (Swagger+EF Core/Code First)
- swoole之代码热更新实现 转自https://blog.csdn.net/nep_tune/article/details/81329918
- block,inline和inline-block概念和区别(转载)