NativeMessageQueue封装
本文承接 android_os_MessageQueue.cpp。上一文按 JNI 函数入口阅读;本文换一个问题:NativeMessageQueue 这个封装对象为什么同时继承 MessageQueue 和 LooperCallback,它如何被其他 native 模块持有,异常为何由基类统一转发,以及文件描述符监听怎样在 Java 锁、native 回调和弱引用之间完成一次生命周期闭环。
1. 类的两面
相关源码:
frameworks/base/core/jni/android_os_MessageQueue.hframeworks/base/core/jni/android_os_MessageQueue.cppsystem/core/libutils/include/utils/Looper.h
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()
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()
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()
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()
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()
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()
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()
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()
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.cppframeworks/base/core/jni/android_view_DisplayEventReceiver.cppframeworks/base/core/jni/android_app_NativeActivity.cpp
这些模块在 Java 回调后调用 raiseAndClearException(),因此异常协议是跨多个 native 子系统复用的公共边界。
10. 测试路径
源码文件:frameworks/base/core/tests/coretests/src/android/os/MessageQueueTest.java
相关函数:testResetClearsFileDescriptorEventListeners()
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. 动手验证
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 等待器的所有权关系,不意味着不同消费者共享业务状态或回调顺序。
