android UEvent剖析

2024-06-09 02:08
文章标签 android 剖析 uevent

本文主要是介绍android UEvent剖析,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

Uevent是内核通知android有状态变化的一种方法,比如USB线插入、拔出,电池电量变化等等。其本质是内核发送(可以通过socket)一个字符串,应用层(android)接收并解释该字符串,获取相应信息。


一、Kernel 部分:

UEVENT的发起在Kernel端,主要是通过函数

int kobject_uevent_env(struct kobject *kobj, enum kobject_action action,

                     char *envp_ext[])

该函数的主要功能是根据参数组合一个字符串并发送。


首先,准备各个字符串:

1.准备字符串

1)获取action字符串

*action_string = kobject_actions[action];

Action为KOBJ_ADD等,kobject_actions的定义如下:

static const char *kobject_actions[] = {

       [KOBJ_ADD] =            "add",

       [KOBJ_REMOVE] =           "remove",

       [KOBJ_CHANGE] =            "change",

       [KOBJ_MOVE] =         "move",

       [KOBJ_ONLINE] =             "online",

       [KOBJ_OFFLINE] =     "offline",

};


2)获取subsystem字符串

subsystem = kobject_name(&kset->kobj);

static inline const char *kobject_name(const struct kobject *kobj)

{

       return kobj->name;

}

这里主要获取kobj的名字。

以“power_supply”为例,在power_supply_core.c中注册class power_supply:

power_supply_class = class_create(THIS_MODULE, "power_supply");

将调用以下函数class_createà __class_createà __class_registerà kobject_set_name:

error = kobject_set_name(&cp->subsys.kobj, "%s", cls->name);

其中的cls->name就是“power_class”最终在kobject_set_name_vargs中赋值给kobject->name

3)devpath字符串,是改变了的uevent所在的sysfs中的位置

devpath = kobject_get_path(kobj, GFP_KERNEL);



2.填充字符串

然后分配一个env空间存储字符串,

env = kzalloc(sizeof(struct kobj_uevent_env), GFP_KERNEL);将上面这些字符串填充到其中去,

retval = add_uevent_var(env, "ACTION=%s", action_string);

retval = add_uevent_var(env, "DEVPATH=%s", devpath);

retval = add_uevent_var(env, "SUBSYSTEM=%s", subsystem);

接着加入不同class的附加的字符串

retval = add_uevent_var(env, "%s", envp_ext[i]);

retval = uevent_ops->uevent(kset, kobj, env);

然后加上该Uenvent的序号,该序号是不断递增的。

add_uevent_var(env, "SEQNUM=%llu", (unsigned long long)seq)。

3.发送

字符串准备完毕,就要准备发送了,由于Android的CONFIG_NET选项是选上的,因此可以通过socket发送:

首先分配一个skb用于存储网络发送的数据

scratch = skb_put(skb, len);

sprintf(scratch, "%s@%s", action_string, devpath);

此时scratch中就增加了change@/devices/platform/msm-battery/power_supply/usb的字符,然后将之前准备好的各个字符传加在后面

for (i = 0; i < env->envp_idx; i++) {

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

scratch = skb_put(skb, len);

       strcpy(scratch, env->envp[i]);

}

最后发送调用retval = netlink_broadcast_filtered发送就OK了。

二、Android侧:

1.启动监视

private UEventObserver mPowerSupplyObserver = new UEventObserver()

{

   @Override

public void onUEvent(UEventObserver.UEvent event) {

            update();

        }
}

申明一个observer对象,然后调用startObserving启动对该对象的监视。

mPowerSupplyObserver.startObserving("SUBSYSTEM=power_supply");

最终会调用到UEventObserver的addObserver:

private ArrayList<Object> mObservers = new ArrayList<Object>();

public void addObserver(String match, UEventObserver observer) {

   synchronized(mObservers) {

       mObservers.add(match);

      mObservers.add(observer);

   }

}

该函数最终会将”SUBSYSTEM=power_supply”增加到匹配序列中,当kernel发送具有该字符串的数据时,就返回匹配成功,然后调用mPowerSupplyObserver的onUEvent函数;

public void run() {

            ………………….

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

                            }

                        }

                    }

                }

            }

        }

next_event(buffer)从底层接收数据,然后在for循环中比较,如果符合,则调用onUevent。之所以for循环时要加2,是因为一次startObserving是调用了两次mObservers.add,其中第一次的是匹配字符串。

2.JNI函数

其中next_event是一个JNI函数(android_os_UEventObserver.c):

private static native int next_event(byte[] buffer);

static JNINativeMethod gMethods[] = {

    {"native_setup", "()V",   (void *)android_os_UEventObserver_native_setup},

    {"next_event",   "([B)I", (void *)android_os_UEventObserver_next_event},

};

android_os_UEventObserver_next_event会调用到uevent_next_event,

3.Socket接口

在hardware/libhardware_legacy/uevent/vim uevent.c中,

int uevent_next_event(char* buffer, int buffer_length)

该函数监听socket,并将socket收到的数据保存到buffer中

nr = poll(&fds, 1, -1);

   

if(nr > 0 && fds.revents == POLLIN) {

    int count = recv(fd, buffer, buffer_length, 0);

if (count > 0) {

………………………………..

}

该socket是在int uevent_init()中创建的

s = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT);

fd=s;

这篇关于android UEvent剖析的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1043952

相关文章

Android 实现一个隐私弹窗功能

《Android实现一个隐私弹窗功能》:本文主要介绍Android实现一个隐私弹窗功能,本文通过实例代码给大家介绍的非常详细,感兴趣的朋友一起看看吧... 效果图如下:1. 设置同意、退出、点击用户协议、点击隐私协议的函数参数2. 《用户协议》、《隐私政策》设置成可点击的,且颜色要区分出来res/l

Android实现一键录屏功能(附源码)

《Android实现一键录屏功能(附源码)》在Android5.0及以上版本,系统提供了MediaProjectionAPI,允许应用在用户授权下录制屏幕内容并输出到视频文件,所以本文将基于此实现一个... 目录一、项目介绍二、相关技术与原理三、系统权限与用户授权四、项目架构与流程五、环境配置与依赖六、完整

Android 12解决push framework.jar无法开机的方法小结

《Android12解决pushframework.jar无法开机的方法小结》:本文主要介绍在Android12中解决pushframework.jar无法开机的方法,包括编译指令、框架层和s... 目录1. android 编译指令1.1 framework层的编译指令1.2 替换framework.ja

Android开发环境配置避坑指南

《Android开发环境配置避坑指南》本文主要介绍了Android开发环境配置过程中遇到的问题及解决方案,包括VPN注意事项、工具版本统一、Gerrit邮箱配置、Git拉取和提交代码、MergevsR... 目录网络环境:VPN 注意事项工具版本统一:android Studio & JDKGerrit的邮

Android实现定时任务的几种方式汇总(附源码)

《Android实现定时任务的几种方式汇总(附源码)》在Android应用中,定时任务(ScheduledTask)的需求几乎无处不在:从定时刷新数据、定时备份、定时推送通知,到夜间静默下载、循环执行... 目录一、项目介绍1. 背景与意义二、相关基础知识与系统约束三、方案一:Handler.postDel

Android使用ImageView.ScaleType实现图片的缩放与裁剪功能

《Android使用ImageView.ScaleType实现图片的缩放与裁剪功能》ImageView是最常用的控件之一,它用于展示各种类型的图片,为了能够根据需求调整图片的显示效果,Android提... 目录什么是 ImageView.ScaleType?FIT_XYFIT_STARTFIT_CENTE

Android实现在线预览office文档的示例详解

《Android实现在线预览office文档的示例详解》在移动端展示在线Office文档(如Word、Excel、PPT)是一项常见需求,这篇文章为大家重点介绍了两种方案的实现方法,希望对大家有一定的... 目录一、项目概述二、相关技术知识三、实现思路3.1 方案一:WebView + Office Onl

Android实现两台手机屏幕共享和远程控制功能

《Android实现两台手机屏幕共享和远程控制功能》在远程协助、在线教学、技术支持等多种场景下,实时获得另一部移动设备的屏幕画面,并对其进行操作,具有极高的应用价值,本项目旨在实现两台Android手... 目录一、项目概述二、相关知识2.1 MediaProjection API2.2 Socket 网络

Android实现悬浮按钮功能

《Android实现悬浮按钮功能》在很多场景中,我们希望在应用或系统任意界面上都能看到一个小的“悬浮按钮”(FloatingButton),用来快速启动工具、展示未读信息或快捷操作,所以本文给大家介绍... 目录一、项目概述二、相关技术知识三、实现思路四、整合代码4.1 Java 代码(MainActivi

Android Mainline基础简介

《AndroidMainline基础简介》AndroidMainline是通过模块化更新Android核心组件的框架,可能提高安全性,本文给大家介绍AndroidMainline基础简介,感兴趣的朋... 目录关键要点什么是 android Mainline?Android Mainline 的工作原理关键