Skip to content

android_os_MessageQueue.cpp

逐个追踪 MessageQueue JNI 方法、NativeMessageQueue 句柄、异常回抛与 FD 回调。

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

android_os_MessageQueue.cpp ​

本文承接Native层总览,只研究一个 JNI 文件:android_os_MessageQueue.cpp。问题边界很窄,但调用关系很长:Java MessageQueue 的 mPtr 如何映射到 C++ 对象,nativePollOnce() 如何把 Java 对象暂时交给 native 回调,文件描述符事件如何回到 Java,以及异常为什么要延迟到 poll 返回后再抛出。

1. 文件角色 ​

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

相关类型:NativeMessageQueue、MessageQueue、LooperCallback

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

private:
    JNIEnv* mPollEnv;
    jobject mPollObj;
    jthrowable mExceptionObj;
};

这个类同时承担两种角色:它是 Java mPtr 指向的 native 对象,也是注册到 libutils::Looper 的 LooperCallback。mPollEnv、mPollObj 和 mExceptionObj 不是长期业务状态,而是一次 native poll 期间的 JNI 桥接状态。

2. 方法注册 ​

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

相关函数:register_android_os_MessageQueue()

cpp
static const JNINativeMethod gMessageQueueMethods[] = {
        {"nativeInit", "()J", (void*)android_os_MessageQueue_nativeInit},
        {"nativeDestroy", "(J)V", (void*)android_os_MessageQueue_nativeDestroy},
        {"nativePollOnce", "(JI)V", (void*)android_os_MessageQueue_nativePollOnce},
        {"nativeWake", "(J)V", (void*)android_os_MessageQueue_nativeWake},
        {"nativeIsPolling", "(J)Z", (void*)android_os_MessageQueue_nativeIsPolling},
        {"nativeSetFileDescriptorEvents", "(JII)V",
         (void*)android_os_MessageQueue_nativeSetFileDescriptorEvents},
        {"nativeSetSkipEpollWaitForZeroTimeout", "(J)V",
         (void*)android_os_MessageQueue_nativeSetSkipEpollWaitForZeroTimeout},
};

int register_android_os_MessageQueue(JNIEnv* env) {
    int res = RegisterMethodsOrDie(env, "android/os/MessageQueue",
            gMessageQueueMethods, NELEM(gMessageQueueMethods));
    jclass clazz = FindClassOrDie(env, "android/os/MessageQueue");
    gMessageQueueClassInfo.mPtr = GetFieldIDOrDie(env, clazz, "mPtr", "J");
    gMessageQueueClassInfo.dispatchEvents = GetMethodIDOrDie(
            env, clazz, "dispatchEvents", "(II)I");
    return res;
}

注册表覆盖的不只是 poll/wake:nativeIsPolling() 给 Java 查询当前是否正在 native poll;nativeSetFileDescriptorEvents() 修改 FD 监听;nativeSetSkipEpollWaitForZeroTimeout() 修改 native Looper 的零超时策略。注册失败使用 RegisterMethodsOrDie,不会留下部分注册状态。

3. 指针句柄 ​

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

相关函数:nativeInit()、nativeDestroy()、android_os_MessageQueue_getMessageQueue()

cpp
static jlong android_os_MessageQueue_nativeInit(JNIEnv* env, jclass clazz) {
    NativeMessageQueue* nativeMessageQueue = new NativeMessageQueue();
    if (!nativeMessageQueue) {
        jniThrowRuntimeException(env, "Unable to allocate native queue");
        return 0;
    }

    nativeMessageQueue->incStrong(env);
    return reinterpret_cast<jlong>(nativeMessageQueue);
}

static void android_os_MessageQueue_nativeDestroy(JNIEnv* env, jclass clazz, jlong ptr) {
    NativeMessageQueue* nativeMessageQueue =
            reinterpret_cast<NativeMessageQueue*>(ptr);
    nativeMessageQueue->decStrong(env);
}

sp<MessageQueue> android_os_MessageQueue_getMessageQueue(
        JNIEnv* env, jobject messageQueueObj) {
    jlong ptr = env->GetLongField(messageQueueObj, gMessageQueueClassInfo.mPtr);
    return reinterpret_cast<NativeMessageQueue*>(ptr);
}

nativeInit() 返回的是 C++ 地址编码后的 jlong,不是 Java 对象 ID。强引用在初始化时增加,在销毁时减少;Java MessageQueue.dispose() 负责把 mPtr 清零,避免同一个句柄重复销毁。getMessageQueue() 还被其他 native 代码用来从 Java 对象反查桥接对象。

4. Poll上下文 ​

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

相关函数:nativePollOnce()、NativeMessageQueue::pollOnce()

cpp
static void android_os_MessageQueue_nativePollOnce(JNIEnv* env, jobject obj,
        jlong ptr, jint timeoutMillis) {
    NativeMessageQueue* nativeMessageQueue =
            reinterpret_cast<NativeMessageQueue*>(ptr);
    nativeMessageQueue->pollOnce(env, obj, timeoutMillis);
}

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 的有效范围严格包住 mLooper->pollOnce()。native Looper 只有在这段调用期间触发 handleEvent(),才能使用当前 JNI 环境和 Java MessageQueue 对象。poll 返回后两者立即清空,下一轮会重新设置。

5. 异常延迟 ​

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

相关函数:MessageQueue::raiseAndClearException()、NativeMessageQueue::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;
}

void NativeMessageQueue::raiseException(JNIEnv* env, const char* msg,
        jthrowable exceptionObj) {
    if (exceptionObj) {
        if (mPollEnv == env) {
            if (mExceptionObj) {
                env->DeleteLocalRef(mExceptionObj);
            }
            mExceptionObj = jthrowable(env->NewLocalRef(exceptionObj));
            jniLogException(env, ANDROID_LOG_ERROR, LOG_TAG, exceptionObj);
        } else {
            jniLogException(env, ANDROID_LOG_ERROR, LOG_TAG, exceptionObj);
            LOG_ALWAYS_FATAL("raiseException() was called when not in a callback, exiting.");
        }
    }
}

JNI 回调如果留下 pending exception,raiseAndClearException() 先从 JNIEnv 取出并清掉,再交给 NativeMessageQueue 暂存。这样 native Looper 可以先结束当前回调和 poll;pollOnce() 返回后再用 env->Throw() 把异常还给 Java。若异常发生在没有匹配 mPollEnv 的上下文,代码选择记录并终止进程,而不是让异常悬挂。

6. 唤醒入口 ​

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

相关函数:nativeWake()、NativeMessageQueue::wake()

cpp
static void android_os_MessageQueue_nativeWake(JNIEnv* env, jclass clazz, jlong ptr) {
    NativeMessageQueue* nativeMessageQueue =
            reinterpret_cast<NativeMessageQueue*>(ptr);
    nativeMessageQueue->wake();
}

void NativeMessageQueue::wake() {
    mLooper->wake();
}

JNI 层不保存 Java Message,也不判断队列是否需要唤醒;它只把句柄转换后转发给 native Looper。是否真的需要写 eventfd,由 Java MessageQueue.enqueueMessage() 的 mBlocked/needWake 分支决定。

7. FD掩码 ​

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

相关函数:setFileDescriptorEvents()、handleEvent()

cpp
static const int CALLBACK_EVENT_INPUT = 1 << 0;
static const int CALLBACK_EVENT_OUTPUT = 1 << 1;
static const int CALLBACK_EVENT_ERROR = 1 << 2;

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

Java 的输入/输出/错误掩码和 libutils EVENT_INPUT/OUTPUT 不是同一组常量,JNI 在这里逐位转换。错误、挂断和无效 FD 由 handleEvent() 合并为 Java 的 CALLBACK_EVENT_ERROR,而不是让 Java 直接读取 epoll 原始标志。

8. 反向回调 ​

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

相关函数:NativeMessageQueue::handleEvent()、WeakLooperCallback::handleEvent()

cpp
int NativeMessageQueue::handleEvent(int fd, int looperEvents, void* data) {
    int events = 0;
    if (looperEvents & Looper::EVENT_INPUT) events |= CALLBACK_EVENT_INPUT;
    if (looperEvents & Looper::EVENT_OUTPUT) events |= CALLBACK_EVENT_OUTPUT;
    if (looperEvents & (Looper::EVENT_ERROR | Looper::EVENT_HANGUP
            | Looper::EVENT_INVALID)) events |= CALLBACK_EVENT_ERROR;

    int oldWatchedEvents = reinterpret_cast<intptr_t>(data);
    int newWatchedEvents = mPollEnv->CallIntMethod(
            mPollObj, gMessageQueueClassInfo.dispatchEvents, fd, events);
    if (!newWatchedEvents) return 0;
    if (newWatchedEvents != oldWatchedEvents) {
        setFileDescriptorEvents(fd, newWatchedEvents);
    }
    return 1;
}

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 无条件延长 NativeMessageQueue 的回调生命周期。目标对象已经消失时返回 0,让 native Looper 注销 FD;对象仍在时才进入 Java dispatchEvents()。Java 返回的掩码变化会再次配置 native 监听。

9. Java消费者 ​

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

相关函数:dispatchEvents()

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

    int newWatchedEvents = listener.onFileDescriptorEvents(
            record.mDescriptor, events);
    if (newWatchedEvents != 0) {
        newWatchedEvents |= OnFileDescriptorEventListener.EVENT_ERROR;
    }
    return newWatchedEvents;
}

Java 先在锁内快照 listener 和序号,再锁外调用用户 listener,避免持锁执行应用代码。listener 返回 0 会让 JNI 返回 0,native Looper 注销;返回非零则自动补上 error 监听。这个返回值是 FD 监听生命周期协议,不是 MessageQueue 的消息处理返回值。

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 写入数据,断言 FD listener 被触发;重置队列后再次写入,断言旧 listener 不再收到事件。它覆盖“注册 → native epoll → Java 回调 → reset 清理”的路径,不证明所有错误/挂断事件或并发 FD 关闭竞态。

11. 生命周期 ​

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

相关函数:nativeDestroy()

cpp
static void android_os_MessageQueue_nativeDestroy(JNIEnv* env, jclass clazz, jlong ptr) {
    NativeMessageQueue* nativeMessageQueue =
            reinterpret_cast<NativeMessageQueue*>(ptr);
    nativeMessageQueue->decStrong(env);
}

销毁只减少 NativeMessageQueue 的强引用;Java dispose() 随后把 mPtr 设为 0。FD 记录通常由 Java MessageQueue 的移除或 resetForTest() 先清理;不能只依赖 native 对象析构来推断 Java listener 已经停止执行。

12. 动手验证 ​

bash
rg -n "nativeInit|nativeDestroy|nativePollOnce|nativeWake|nativeSetFileDescriptorEvents" \
  frameworks/base/core/jni/android_os_MessageQueue.cpp
rg -n "dispatchEvents|addOnFileDescriptorEventListener|removeOnFileDescriptorEventListener" \
  frameworks/base/core/java/android/os/LegacyMessageQueue/MessageQueue.java
rg -n "testResetClearsFileDescriptorEventListeners" \
  frameworks/base/core/tests/coretests/src/android/os/MessageQueueTest.java

阅读顺序建议是:先看注册表确认签名,再跟 mPtr 进入对象,接着看 pollOnce() 的上下文窗口,最后沿 FD 测试检查 listener 的返回值如何影响注销。不要把 JNI 方法名本身当作行为,行为要继续追到 Java 或 Looper 消费者。

13. 边界说明 ​

本文不展开 libutils::Looper 的完整 epoll 重建、native 消息 envelope、JNI 性能成本或所有 JNIEnv 生命周期规则。固定源码能支持的是本文件中的注册、句柄、异常、掩码和回调路径;具体 FD 是否可读仍由内核事件和 Java listener 决定。