android & Linux uevent机制
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));
}
}
}
}
}
}
android & Linux uevent机制的更多相关文章
- Android内存管理机制之一:low memory killer
转载自http://www.miui.com/thread-29268-1-1.html 准备写这个专题之前,心里是有点忐忑的.首先Android内存管理机制相当复杂,想要讲清楚比较困难:其次对于绝大 ...
- [置顶] 深入理解android之IPC机制与Binder框架
[android之IPC机制与Binder框架] [Binder框架.Parcel.Proxy-Stub以及AIDL] Abstract [每个平台都会有自己一套跨进程的IPC机制,让不同进程里的两个 ...
- 【朝花夕拾】Android性能篇之(六)Android进程管理机制
前言 Android系统与其他操作系统有个很不一样的地方,就是其他操作系统尽可能移除不再活动的进程,从而尽可能保证多的内存空间,而Android系统却是反其道而行之,尽可能保留进程.An ...
- Android 基础 十一 Android的消息机制
Handler是Android消息机制的上层接口,这使得在开发应用过程中我们只需要和Handler交互即可.Handler的使用过程很简单,通过它可以轻松地将一个任务切换到Handler所在的线程中去 ...
- Android的消息机制简单总结
参考文章: http://gityuan.com/2015/12/26/handler-message-framework/#next 参考资料: Android Framework的源码: Mess ...
- 设备模型的uevent机制
内核模块的热插拔事件的通知基于uevent机制. 当kobject的状态发生改变(如,add, remove等)时,会通知用户空间,用户空间接收到事件通知后可以做相应的处理.uevent把事件上报给用 ...
- Linux系统——机制策略(一)
机制策略(一) 形而上谓之道:形而下谓之器: ————易经 LinuxUnix设计理念提供的一种机制不是策略:1.如果说机制是一种框架,那么,策略就是填充框架的一个个具体实施.机制提供的就是一种开放而 ...
- Android休眠唤醒机制简介(二)
本文转载自:http://blog.csdn.net/zhaoxiaoqiang10_/article/details/24408911 Android休眠唤醒机制简介(二)************* ...
- Android休眠唤醒机制简介(一)【转】
本文转载自:http://blog.csdn.net/zhaoxiaoqiang10_/article/details/24408129 Android休眠唤醒机制简介(一) ************ ...
随机推荐
- 第十二篇、高度自适应的textView
高度根据输入内容变化输入框,我们在很多的应用上都可以见到,如微信.QQ聊天,QQ空间评论等等,该输入框可以用xib,纯代码编写,但是个人觉得纯代码编写用起来更加方便一些. 1.使用自定义的UIView ...
- 轮子来袭 vJine.Core Orm 之 03_架构分析
1.vJine.Core ORM 架构: 如上图所示,vJine.Core ORM的特点如下: 所有操作均以DataManager为核心: DataManager业务部分的增删改查操作依赖于Class ...
- 新安装Eclipse后的一些配置
配置护眼的背景色 Window-> Preferences-> General-> Editors-> Text Editors: Appearance color optio ...
- Codevs 1218 疫情控制 2012年NOIP全国联赛提高组
1218 疫情控制 2012年NOIP全国联赛提高组 时间限制: 2 s 空间限制: 128000 KB 题目等级 : 钻石 Diamond 题目描述 Description H 国有 n 个城市,这 ...
- Custom Action : dynamic link library
工具:VS2010, Installshield 2008 实现功能: 创建一个C++ win32 DLL的工程,MSI 工程需要调用这个DLL,并将Basic MSI工程中的两个参数,传递给DLL, ...
- mysql密码忘记后重置密码
之前在centOS里安装了xampp,设置了mysql数据库root密码,今天需要增加个数据库,发现忘记之前设置的密码是什么了.经过一番摸爬滚打,终于搞明白了,注意以下的操作都是以linux的root ...
- Less使用——让老司机带你飞
为什么我要使用Less less的作为编写css的工具插件,省时.方便.检测,具体的安装,请参考我的一篇文章<sublime text3 个人使用心得>,里面我讲解了安装方法,使用webs ...
- WPF中实现根据拼音查找汉字
1.WPF的一个触摸屏项目,需要输入姓名,但是屏幕不支持汉字输入,使用虚拟键盘不稳定,为了解决该问题特此进行处理. 2.新建一个类转换类,里面初始化一个数组,数组包含拼音,以及拼音下的常用的汉字. 3 ...
- AngularJS(4)-服务(Service)
1.$location服务 $location 服务,它可以返回当前页面的 URL 地址 2.$http服务 $http 是 AngularJS 应用中最常用的服务. 服务向服务器发送请求,应用响应服 ...
- 网页clientWidth等相关
javascript代码: function getInfo() { var s = ""; s += & ...