UEventObserver 源码分析

什么是

UEventObserver 是 Android 框架中一个隐藏的抽象类(@hide),位于 frameworks/base/core/java/android/os/UEventObserver.java,主要用于监听内核(Kernel)发送的 UEvent(用户事件)。这些事件通常来自内核的 netlink 套接字,涉及硬件变化如 USB 连接、电池状态、GPIO 变化等。UEventObserver 允许应用程序或系统服务(如 BatteryService、UsbService)订阅特定匹配字符串的事件,并在事件发生时回调 onUEvent 方法。

该类不是标准 SDK 的一部分(android.jar 中不可见),因此在应用开发中无法直接导入和使用,通常需要在 AOSP(Android Open Source Project)环境中编译或通过反射访问。它依赖于 JNI(Java Native Interface)与底层 C/C++ 代码交互,使用 hardware_legacy/uevent.h 库处理内核事件。

源码概述(UEventObserver.java)

  • 关键类结构

  • UEventObserver:抽象基类。

  • 抽象方法:onUEvent(UEvent event) – 子类需实现此方法处理事件。
    UEvent:内部静态类,表示单个事件,封装了键值对(如 "USB_STATE=1")。

  • 方法:get(String key) 获取值;toString() 输出事件字符串。

  • UEventThread:内部静态类,继承 Thread,负责事件轮询和分发。

  • 单例:通过 getThread() 获取,确保进程只有一个实例。
    成员:

  • ArrayList<Object> mKeysAndObservers:存储匹配字符串和观察者(偶数索引为 match,奇数为 Observer)。使用 ArrayList 模拟 Multimap,因为 Android 早期无内置 Multimap。

  • ArrayList<UEventObserver> mTempObserversToSignal:临时列表,用于分发事件。

  • 运行逻辑:在 run() 中循环调用 native 方法等待事件,解析后分发给匹配的观察者。

startObserving(String match):

  • 参数:match 为非空字符串,如 "USB_STATE" 或 "SWITCH_STATE"。
  • 逻辑:获取 UEventThread 实例,调用 addObserver(match, this) 添加订阅。如果线程未启动,则启动它。
  • 异常:match 为空抛 IllegalArgumentException。
  • 源码片段:
public final void startObserving(String match) {
    if (match == null || match.isEmpty()) {
        throw new IllegalArgumentException("match substring must be non-empty");
    }
    final UEventThread t = getThread();
    t.addObserver(match, this);
}

stopObserving(String match):

  • 移除指定 match 的订阅。
  • 逻辑:从 mKeysAndObservers 中移除对应条目。

UEventThread 的 run():

  • 调用 nativeSetup() 初始化 native 层。

  • 循环:nativeWaitForNextEvent() 获取事件字符串。
    如果事件非空,调用 sendEvent(message) 分发:

  • 遍历 mKeysAndObservers,检查 message 是否包含 match。

  • 匹配则解析为 UEvent,添加到临时列表。

  • 遍历临时列表,调用 onUEvent 回调。

  • 源码片段

@Override
public void run() {
    nativeSetup();
    while (true) {
        String message = nativeWaitForNextEvent();
        if (message != null) {
            if (DEBUG) Log.d(TAG, message);
            sendEvent(message);
        }
    }
}

private void sendEvent(String message) {
    // 解析 message 为键值对
    HashMap<String, String> map = new HashMap<String, String>();
    // ... 解析逻辑 ...
    UEvent event = new UEvent(map);

    // 查找匹配观察者
    for (int i = 0; i < mKeysAndObservers.size(); i += 2) {
        String match = (String) mKeysAndObservers.get(i);
        if (message.contains(match)) {
            mTempObserversToSignal.add((UEventObserver) mKeysAndObservers.get(i + 1));
        }
    }

    // 回调
    for (UEventObserver observer : mTempObserversToSignal) {
        observer.onUEvent(event);
    }
    mTempObserversToSignal.clear();
}
  1. JNI 实现(android_os_UEventObserver.cpp)
    Java 层通过 native 方法与内核交互,JNI 代码位于 frameworks/base/core/jni/android_os_UEventObserver.cpp。它使用 uevent.h(来自 system/core/libcutils 或 hardware_legacy)库,该库封装了 netlink 套接字(AF_NETLINK,NETLINK_KOBJECT_UEVENT)。

关键 native 方法
nativeSetup():
调用 uevent_init() 初始化 netlink 套接字。
如果失败,抛 RuntimeException:"Unable to open socket for UEventObserver"。
源码片段:

static void android_os_UEventObserver_native_setup(JNIEnv *env, jclass clazz) {
    if (!uevent_init()) {
        jniThrowException(env, "java/lang/RuntimeException", "Unable to open socket for UEventObserver");
    }
}
  • nativeWaitForNextEvent()(Java 中为 String 返回):

实际对应 next_event JNI 方法,使用字节数组 buffer 接收事件。
调用 uevent_next_event(buffer, buf_sz - 1) 阻塞等待内核事件。
返回事件长度,Java 层转换为 String。
源码片段:

  static int android_os_UEventObserver_next_event(JNIEnv *env, jclass clazz, jbyteArray jbuffer) {
    int buf_sz = env->GetArrayLength(jbuffer);
    char *buffer = (char*)env->GetByteArrayElements(jbuffer, NULL);
    int length = uevent_next_event(buffer, buf_sz - 1);
    env->ReleaseByteArrayElements(jbuffer, (jbyte*)buffer, 0);
    return length;
}
  • nativeAddMatch(String match) 和 nativeRemoveMatch(String match):

调用 uevent_add_filter() 和 uevent_remove_filter() 添加/移除内核过滤器,提高效率(避免接收无关事件)。
源码类似,未在早期版本中完全实现,但 AOSP 中有。

3. 整体架构与工作流程

初始化:

系统进程(如 SystemServer)启动时,创建 UEventObserver 子类实例。
调用 startObserving(match),启动 UEventThread(如果未启动)。

事件监听:

UEventThread 在后台线程运行,nativeSetup() 打开 netlink 套接字。
内核通过 netlink 广播 UEvent(如 add@/devices/... USB_STATE=1)。
uevent_next_event() 阻塞读取,获取原始字符串。

事件分发:

Java 层解析字符串为键值对(e.g., HashMap<"KEY", "VALUE">)。
检查所有订阅的 match,匹配则创建 UEvent 对象。
回调 onUEvent(UEvent event) – 线程安全(synchronized)。

停止监听:

stopObserving(match) 移除订阅,但线程继续运行(进程只有一个线程)。

资源管理:

线程永不停止,除非进程结束。
常见问题:uevent_init() 失败(权限或套接字冲突),导致 RuntimeException 和 bootloop(系统进程崩溃)。

©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容