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;



int i = 0;



int retval = 0;



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



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 "



"%d\n", 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<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();

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

}

}

}

}

}

}

 

你可能感兴趣的:(android)