Android P Uevent机制分析

Uevent是Android内核与用户进程进行通信的一种方式,其本质是通过netlink(通过socket)发送消息给用户进程。

本文只讲一个大概的流程,只分析通信的一个过程,不深入解析具体的数据结构和传递的参数。

关于netlink socket的通信,请参考:
https://blog.csdn.net/Sunxiaolin2016/article/details/89635302

一、Kernel发送

Uevent是在kernel中发送出来的,通过kobject_uevent_env进行发送:

kobject_uevent_env(&edev->dev.kobj, KOBJ_CHANGE, envp);

二、用户进程接收

接收过程中,使用了Linux epoll机制,对事件进行监控。

1、使用uevent_open_socket()创建netlink socket,用于监听uevent事件

//本质是打开一个netlink socket
uevent_fd = uevent_open_socket(64 * 1024, true);

2、使用epoll_create(),用于产生一个epoll的文件描述符,一个epoll文件描述符对应一个文件描述符集合

epoll_fd = epoll_create(64);

3、使用epoll_ctl(),用于控制这个集合中的成员,在内核中,epoll_ctl会将新的fd加入到一颗红黑树中加以管理

if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, uevent_fd, &ev) == -1) {
      ALOGE("epoll_ctl failed; errno=%d", errno);
      return -1;
}

4、使用epoll_wait(),用于等待集合中成员的事件发生,如果所有成员都没有I/O事件,则保持进程的睡眠状态;否则,进程会被唤醒,epoll_wait会返回所有发生的事件的信息

for ( ; ; ) {
    struct epoll_event events[64];
    //等待事件发生
    nevents = epoll_wait(epoll_fd, events, 64, -1);
    if (nevents < 0) {
        ALOGE("%s: wait the event failed", __FUNCTION__);
        continue;
    }
    for (int n = 0; n < nevents; ++n) {
    	//处理事件
        handle_events(uevent_fd);
    }
}

5、在步骤4中,事件发生后,会执行handle_events(),在handle_events()中,使用uevent_kernel_multicast_recv()去接收uevent事件

handle_events(int uevent_fd)
{
    char msg[UEVENT_MSG_LEN+2];
    int n;
    int i;
    char *cp;
    //接收uevent事件
    n = uevent_kernel_multicast_recv(uevent_fd, msg, UEVENT_MSG_LEN);
    if (n <= 0 || n >= UEVENT_MSG_LEN) return;
	
	//Do something
	//...
}
  • 1
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
Android系统中,可以使用uevent来检测U盘的挂载地址。具体步骤如下: 1. 在Android系统中,U盘的插入和拔出都会发送uevent消息,可以通过注册一个uevent监听器来接收这些消息。 2. 在uevent消息中,会包含有U盘的一些信息,比如设备名称、挂载路径等。 3. 在接收到U盘插入消息时,可以解析uevent消息中的挂载路径信息,即可获得U盘的挂载地址。 以下是一个使用uevent检测U盘挂载地址的示例代码: ``` import android.os.Handler; import android.os.Looper; import android.os.MessageQueue; import android.util.Log; import java.io.BufferedReader; import java.io.File; import java.io.FileReader; import java.io.IOException; public class UdiskMonitor { private static final String TAG = "UdiskMonitor"; private static final String UDISK_MOUNT_PATH = "/sys/class/android_usb/android0/f_mass_storage/lun/file"; private OnUdiskMountedListener mListener; public void startMonitor(final OnUdiskMountedListener listener) { mListener = listener; // 在主线程中监听uevent消息 new Handler(Looper.getMainLooper()).post(new Runnable() { @Override public void run() { Looper.myQueue().addIdleHandler(new MessageQueue.IdleHandler() { @Override public boolean queueIdle() { // 开始监听uevent消息 startUeventMonitor(); return false; } }); } }); } private void startUeventMonitor() { BufferedReader reader = null; try { // 打开uevent监听文件 reader = new BufferedReader(new FileReader(new File("/proc/net/netlink"))); String line; while ((line = reader.readLine()) != null) { // 解析uevent消息 String[] parts = line.split(" "); if (parts.length >= 6 && parts[0].equals("1")) { String action = parts[1]; String devPath = parts[4]; if (action.equals("add") && devPath.equals(UDISK_MOUNT_PATH)) { // U盘被插入,获取挂载路径并回调监听器 String mountPath = getUdiskMountPath(); if (mountPath != null) { if (mListener != null) { mListener.onUdiskMounted(mountPath); } } } } } } catch (IOException e) { Log.e(TAG, "startUeventMonitor: " + e.getMessage()); } finally { if (reader != null) { try { reader.close(); } catch (IOException e) { Log.e(TAG, "startUeventMonitor: " + e.getMessage()); } } } } private String getUdiskMountPath() { String mountPath = null; try { // 读取U盘挂载路径 BufferedReader reader = new BufferedReader(new FileReader(new File(UDISK_MOUNT_PATH))); mountPath = reader.readLine().trim(); reader.close(); } catch (IOException e) { Log.e(TAG, "getUdiskMountPath: " + e.getMessage()); } return mountPath; } public interface OnUdiskMountedListener { void onUdiskMounted(String mountPath); } } ``` 在上述代码中,我们通过监听uevent消息来检测U盘的插入和拔出事件。当接收到U盘插入事件时,我们通过读取U盘的挂载路径来获取U盘的挂载地址,并通过回调监听器来通知外部应用程序。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

sunxiaolin2016

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值