Skip to content

NativeMessageQueue封装

从 MessageQueue 基类到 NativeMessageQueue 回调封装,解释 native Looper 所有权、异常接口和 FD 生命周期。

基于android-17.0.0_r1
AndroidNativeMessageQueueJNILooperCallback文件描述符源码阅读

NativeMessageQueue封装 ​

本文承接 android_os_MessageQueue.cpp。上一文按 JNI 函数入口阅读;本文换一个问题:NativeMessageQueue 这个封装对象为什么同时继承 MessageQueue 和 LooperCallback,它如何被其他 native 模块持有,异常为何由基类统一转发,以及文件描述符监听怎样在 Java 锁、native 回调和弱引用之间完成一次生命周期闭环。

1. 类的两面 ​

相关源码:

  • frameworks/base/core/jni/android_os_MessageQueue.h
  • frameworks/base/core/jni/android_os_MessageQueue.cpp
  • system/core/libutils/include/utils/Looper.h
cpp
class NativeMessageQueue : public MessageQueue, public LooperCallback {
public:
    NativeMessageQueue();
    virtual ~NativeMessageQueue();
    virtual void raiseException(JNIEnv* env, const char* msg, jthrowable exceptionObj);
    void pollOnce(JNIEnv* env, jobject obj, int timeoutMillis);
    void wake();
    void setFileDescriptorEvents(int fd, int events);
    virtual int handleEvent(int fd, int events, void* data);
};

MessageQueue 基类提供 sp<Looper> mLooper 和异常接口;LooperCallback 让同一个对象能注册到 native Looper 接收 FD 事件。它不是 Java Message 的消费者,Java 链表仍由 MessageQueue 自己维护。

2. 基类所有权 ​

源码文件:frameworks/base/core/jni/android_os_MessageQueue.h

相关函数:getLooper()、android_os_MessageQueue_getMessageQueue()

cpp
class MessageQueue : public virtual RefBase {
public:
    inline sp<Looper> getLooper() const {
        return mLooper;
    }

    bool raiseAndClearException(JNIEnv* env, const char* msg);
    virtual void raiseException(JNIEnv* env, const char* msg,
            jthrowable exceptionObj) = 0;

protected:
    sp<Looper> mLooper;
};

extern sp<MessageQueue> android_os_MessageQueue_getMessageQueue(
        JNIEnv* env, jobject messageQueueObj);

mLooper 是强引用 sp<Looper>,所以拿到 sp<MessageQueue> 的 native 消费者可以继续使用对应 Looper。getMessageQueue() 从 Java mPtr 返回一个 sp<MessageQueue>,调用者必须先判断是否为空;Sensor、输入事件和 NativeActivity 等模块都通过这个接口接入同一队列。

3. 线程复用 ​

源码文件:frameworks/base/core/jni/android_os_MessageQueue.cpp

相关函数:NativeMessageQueue::NativeMessageQueue()

cpp
NativeMessageQueue::NativeMessageQueue()
        : mPollEnv(NULL), mPollObj(NULL), mExceptionObj(NULL) {
    mLooper = Looper::getForThread();
    if (mLooper == NULL) {
        mLooper = new Looper(false);
        Looper::setForThread(mLooper);
    }
}

封装对象创建时优先复用当前线程 native Looper;没有才创建并登记。多个 native 消费者可以共享这个 Looper,但共享的是等待器和 FD 注册表,不是 Java MessageQueue.mMessages 链表。

4. 异常协议 ​

源码文件:frameworks/base/core/jni/android_os_MessageQueue.h

相关函数:raiseAndClearException()、raiseException()

cpp
bool MessageQueue::raiseAndClearException(JNIEnv* env, const char* msg) {
    if (env->ExceptionCheck()) {
        jthrowable exceptionObj = env->ExceptionOccurred();
        env->ExceptionClear();
        raiseException(env, msg, exceptionObj);
        env->DeleteLocalRef(exceptionObj);
        return true;
    }
    return false;
}

基类把 JNI 的 pending exception 转成统一接口:先取出并清除,再交给具体封装保存或重新抛出。它不吞异常;返回 true 只说明发现并处理了 pending exception,真正抛回 Java 的时机由 NativeMessageQueue::pollOnce() 控制。

5. 回调窗口 ​

源码文件:frameworks/base/core/jni/android_os_MessageQueue.cpp

相关函数:pollOnce()、raiseException()

cpp
void NativeMessageQueue::pollOnce(JNIEnv* env, jobject pollObj, int timeoutMillis) {
    mPollEnv = env;
    mPollObj = pollObj;
    mLooper->pollOnce(timeoutMillis);
    mPollObj = NULL;
    mPollEnv = NULL;
    if (mExceptionObj) {
        env->Throw(mExceptionObj);
        env->DeleteLocalRef(mExceptionObj);
        mExceptionObj = NULL;
    }
}

mPollEnv/mPollObj 是一次 poll 的临时上下文。handleEvent() 在这个窗口内才能调用 Java dispatchEvents();poll 结束后清空上下文,防止后续错误回调使用失效的 JNI 对象。

6. FD注册 ​

源码文件:frameworks/base/core/jni/android_os_MessageQueue.cpp

相关函数:setFileDescriptorEvents()

cpp
void NativeMessageQueue::setFileDescriptorEvents(int fd, int events) {
    if (events) {
        int looperEvents = 0;
        if (events & CALLBACK_EVENT_INPUT) looperEvents |= Looper::EVENT_INPUT;
        if (events & CALLBACK_EVENT_OUTPUT) looperEvents |= Looper::EVENT_OUTPUT;
        mLooper->addFd(fd, Looper::POLL_CALLBACK,
                looperEvents, sp<WeakLooperCallback>::make(this),
                reinterpret_cast<void*>(events));
    } else {
        mLooper->removeFd(fd);
    }
}

events == 0 是注销,不是“监听空事件”。非零事件会附带 WeakLooperCallback,并把原始 Java 掩码放进 data,供回调判断监听集合是否发生变化。

7. 弱回调 ​

源码文件:frameworks/base/core/jni/android_os_MessageQueue.cpp

相关函数:WeakLooperCallback::handleEvent()

cpp
int NativeMessageQueue::WeakLooperCallback::handleEvent(
        int fd, int events, void* data) {
    sp<LooperCallback> callback = mCallback.promote();
    if (callback != nullptr) {
        return callback->handleEvent(fd, events, data);
    }
    return 0;
}

native Looper 持有回调对象时使用弱引用代理;目标仍存活才临时 promote() 成强引用并转发,目标已销毁则返回 0,让 Looper 注销请求。这样 FD 注册不会单独把整个 NativeMessageQueue 生命周期无限延长。

8. Java回调 ​

源码文件:frameworks/base/core/java/android/os/LegacyMessageQueue/MessageQueue.java

相关函数:dispatchEvents()

java
private int dispatchEvents(int fd, int events) {
    final FileDescriptorRecord record;
    final OnFileDescriptorEventListener listener;
    synchronized (this) {
        record = mFileDescriptorRecords.get(fd);
        if (record == null) return 0;
        events &= record.mEvents;
        if (events == 0) return record.mEvents;
        listener = record.mListener;
    }

    int newWatchedEvents = listener.onFileDescriptorEvents(
            record.mDescriptor, events);
    return newWatchedEvents;
}

Java 在锁内确认记录、过滤事件并取出 listener,锁外调用用户代码。返回 0 会沿 JNI 回到 native,最终取消 FD;返回非零表示继续监听。NativeMessageQueue 只负责桥接,不决定 listener 的业务返回值。

9. 真实消费者 ​

源码文件:frameworks/base/core/jni/android_hardware_SensorManager.cpp

相关函数:nativeInitSensorEventQueue()

cpp
sp<MessageQueue> messageQueue = android_os_MessageQueue_getMessageQueue(env, msgQ);
if (messageQueue == NULL) {
    jniThrowRuntimeException(env, "MessageQueue is not initialized.");
    return 0;
}

sp<Receiver> receiver = new Receiver(queue, messageQueue, eventQWeak);

Sensor native 队列并不重新创建 Java MessageQueue;它从 Java 对象反查 sp<MessageQueue>,把自己的接收器绑定到同一个 native Looper。若 Java 队列尚未初始化,native 入口立即失败。

其他真实消费者也使用同一接口,例如:

  • frameworks/base/core/jni/android_view_InputEventReceiver.cpp
  • frameworks/base/core/jni/android_view_DisplayEventReceiver.cpp
  • frameworks/base/core/jni/android_app_NativeActivity.cpp

这些模块在 Java 回调后调用 raiseAndClearException(),因此异常协议是跨多个 native 子系统复用的公共边界。

10. 测试路径 ​

源码文件:frameworks/base/core/tests/coretests/src/android/os/MessageQueueTest.java

相关函数:testResetClearsFileDescriptorEventListeners()

java
queue.addOnFileDescriptorEventListener(
        reader.getFD(), OnFileDescriptorEventListener.EVENT_INPUT, readerCallback);
writer.write(0);
writer.flush();
syncWait(handler);
assertEquals(1, fdEventLatch.getCount());

resetQueue();
writer.write(0);
writer.flush();
syncWait(handler);
assertEquals(1, fdEventLatch.getCount());

pipe 输入让 native Looper 产生可观察事件;重置后第二次写入不再触发旧 listener。测试覆盖注册、回调、注销消费者,不覆盖目标对象被 GC、native 异常和 FD 关闭竞态。

11. 动手验证 ​

bash
rg -n "class NativeMessageQueue|raiseAndClearException|WeakLooperCallback|setFileDescriptorEvents" \
  frameworks/base/core/jni/android_os_MessageQueue.cpp \
  frameworks/base/core/jni/android_os_MessageQueue.h
rg -n "android_os_MessageQueue_getMessageQueue|messageQueue->raiseAndClearException" \
  frameworks/base/core/jni/android_*.cpp

阅读时把一次 FD 事件分成四段:Java 注册 → native addFd → 弱代理转发 → Java listener 返回掩码。再单独追一条异常:JNI pending → raiseAndClearException → mExceptionObj → poll 返回时 env->Throw()。

12. 边界说明 ​

本文不把 MessageQueue 基类等同于 Java MessageQueue,也不展开 native Looper 的 epoll 重建和消息 envelope。sp<Looper> 的共享只说明 native 等待器的所有权关系,不意味着不同消费者共享业务状态或回调顺序。