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;

int i = 0;

int retval = 0;

#ifdef CONFIG_NET

struct uevent_sock

*ue_sk;

#endif

pr_debug("kobject: '%s' (%p):

%sn",

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__);

return 0;

}

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__);

return 0;

}

====================================================

获取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__);

return 0;

}

=========================================================

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) {

for (i = 0; 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 "

"%dn", kobject_name(kobj),

kobj,

__func__, retval);

goto exit;

}

}

if (action ==

KOBJ_ADD)

kobj->state_add_uevent_sent

= 1;

else if (action ==

KOBJ_REMOVE)

kobj->state_remove_uevent_sent

= 1;

//加入该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) + 2;

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数据结构

for (i = 0; i

< env->envp_idx; i++) {

len =

strlen(env->envp[i]) + 1;

scratch = skb_put(skb,

len);

strcpy(scratch,

env->envp[i]);

}

NETLINK_CB(skb).dst_group =

1;//下面开始发送数据

retval =

netlink_broadcast_filtered(uevent_sock, skb,

0, 1, GFP_KERNEL,

kobj_bcast_filter,

kobj);

if (retval == -ENOBUFS ||

retval == -ESRCH)

retval = 0;

} else

retval = -ENOMEM;

}

mutex_unlock(&uevent_sock_mutex);

#endif

if (uevent_helper[0]

&& !kobj_usermode_filter(kobj))

{

char *argv [3];

argv [0] =

uevent_helper;

argv [1] = (char

*)subsystem;

argv [2] = 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[0], 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 mObservers = new

ArrayList();

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 mObservers = new

ArrayList();

UEventThread() {

super("UEventObserver");

}

public void run() {

native_setup();

byte[] buffer = new byte[1024];

int len;

while (true) {

len = next_event(buffer);

if

(len > 0) {

String bufferStr = new String(buffer, 0,

len); // easier to search a String

synchronized (mObservers) {

for (int i = 0; i <

mObservers.size(); i += 2) {

if

(bufferStr.indexOf((String)mObservers.get(i)) != -1) {

((UEventObserver)mObservers.get(i+1))

.onUEvent(new

UEvent(bufferStr));

}

}

}

}

}

}

Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐