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机制的更多相关文章

  1. Android内存管理机制之一:low memory killer

    转载自http://www.miui.com/thread-29268-1-1.html 准备写这个专题之前,心里是有点忐忑的.首先Android内存管理机制相当复杂,想要讲清楚比较困难:其次对于绝大 ...

  2. [置顶] 深入理解android之IPC机制与Binder框架

    [android之IPC机制与Binder框架] [Binder框架.Parcel.Proxy-Stub以及AIDL] Abstract [每个平台都会有自己一套跨进程的IPC机制,让不同进程里的两个 ...

  3. 【朝花夕拾】Android性能篇之(六)Android进程管理机制

    前言        Android系统与其他操作系统有个很不一样的地方,就是其他操作系统尽可能移除不再活动的进程,从而尽可能保证多的内存空间,而Android系统却是反其道而行之,尽可能保留进程.An ...

  4. Android 基础 十一 Android的消息机制

    Handler是Android消息机制的上层接口,这使得在开发应用过程中我们只需要和Handler交互即可.Handler的使用过程很简单,通过它可以轻松地将一个任务切换到Handler所在的线程中去 ...

  5. Android的消息机制简单总结

    参考文章: http://gityuan.com/2015/12/26/handler-message-framework/#next 参考资料: Android Framework的源码: Mess ...

  6. 设备模型的uevent机制

    内核模块的热插拔事件的通知基于uevent机制. 当kobject的状态发生改变(如,add, remove等)时,会通知用户空间,用户空间接收到事件通知后可以做相应的处理.uevent把事件上报给用 ...

  7. Linux系统——机制策略(一)

    机制策略(一) 形而上谓之道:形而下谓之器: ————易经 LinuxUnix设计理念提供的一种机制不是策略:1.如果说机制是一种框架,那么,策略就是填充框架的一个个具体实施.机制提供的就是一种开放而 ...

  8. Android休眠唤醒机制简介(二)

    本文转载自:http://blog.csdn.net/zhaoxiaoqiang10_/article/details/24408911 Android休眠唤醒机制简介(二)************* ...

  9. Android休眠唤醒机制简介(一)【转】

    本文转载自:http://blog.csdn.net/zhaoxiaoqiang10_/article/details/24408129 Android休眠唤醒机制简介(一) ************ ...

随机推荐

  1. IOS-UI-UIDynamic(二)

    UIPushBehavior :推动效果 UIAttachmentBehavior:附着效果 UISnapBehavior:迅速移动效果 一.重要的属性 UIPushBehavior :推动效果 ty ...

  2. Go与GUI——GO语言的图形界面Walk

    GO没有原生的界面库,所以不能直接用来写GUI界面.但最近互联网上已经涌现出不少成熟.好用的第三方界面库.使用它们,就同样可以写出同C#.C++的界面.而且效率还更胜一筹. 关于Walk界面库(官方介 ...

  3. redis 实践—— sorted set, hash set

    在这里就不谈redis的安装与启动啦,网上太多人写这个了. 从最近的一个项目[钻石夺宝]说起,如果大家有玩过一元夺宝或者全名夺宝的话,大概会知道如果参与人数多的话,每隔几秒.快的话每隔一秒都会新生成一 ...

  4. css3 animation实现逐帧动画

    css3里面的animation属性非常强大,但是自己用的比较少,最近有次面试就刚好被问到了,趁现在有时间就对animation做一个小总结.同时实现一个逐帧动画的demo作为练习 animation ...

  5. 线程间通信--生产者消费者 升级版JDK5

    import java.util.concurrent.locks.*; /*1.新的解锁,上锁操作,据说是jdk5.0升级版,以前的枷锁,解锁都是隐藏的,默认的,现在变成显式 2.新的异常处理方式  ...

  6. bash 脚本

    一.英文版 1.Advanced Bash-Scripting Guide 二.中文 1.BashGuide for Beginners 中文版

  7. OpenJudge/Poj 1083 Moving Tables

    1.链接地址: http://poj.org/problem?id=1083 http://bailian.openjudge.cn/practice/1083/ 2.题目: 总时间限制: 1000m ...

  8. N个数随机相加得出固定值的排列组合

    static double[] iArr = new double[10] { 1,2,3,4,5,6,7,8,9,10 }; static Stack<double> stack = n ...

  9. MySQL生产库主从重新同步操作注意事项

    因为一些原因,我们会遇到生产主从库重新同步的时候.重新同步MYSQL主从的时候有有一些注意的地方. 从库还原前一定要记得reset,因为重启mysql并不影响复制进程,如果忘记reset,会导致你一边 ...

  10. sae-服务器php运行环境配置

    config.yaml 语法- OPTION: ARG1 ARG2 ... - OPTION: if (CONDICTIONs) ACTION CONDITION可以是以下任意一种: 使用 == 和 ...