frameworks/base/core/java/android/os/Looper.java
final MessageQueue mQueue;
public static void prepare() {
prepare(true);
}
private static void prepare(boolean quitAllowed) {
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper(quitAllowed));
}
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
了解Android消息机制的人都知道,使用handler消息机制,必须先调用Looper.prepare(),最后调用Looper.loop()。
prepare()
会创建MessageQueue对象。loop()
会进入无限循环,不停的调用MessageQueue.next()方法尝试取得一个消息- Handler.sendMessage(msg)会调用MessageQueue.enqueueMessage()方法,把消息放入消息队列
常规的消息框架都涉及:消息、消息队列、消息中心、消息生产者和消息消费者。一般消息中心都会设计成loop,会无限循环读取消息队列中的消息。当消息队列为空时,会sleep/usleep一段时间。
frameworks/base/core/java/android/os/MessageQueue.java
MessageQueue(boolean quitAllowed) {
mQuitAllowed = quitAllowed;
mPtr = nativeInit();
}
// 把消息放入消息队列,然后调用nativeWake()唤醒消息处理Looper
boolean enqueueMessage(Message msg, long when) {
... ...
synchronized (this) {
... ...
// We can assume mPtr != 0 because mQuitting is false.
if (needWake) {
nativeWake(mPtr);
}
}
return true;
}
// 尝试从消息队列读取一个消息,如果消息队列为空,则调用nativePollOnce()等待消息的到来
Message next() {
... ...
int pendingIdleHandlerCount = -1; // -1 only during first iteration
int nextPollTimeoutMillis = 0;
for (;;) {
nativePollOnce(ptr, nextPollTimeoutMillis);
... ...
}
}
这里涉及三个native方法nativeInit/nativeWake/nativePollOnce
,下面进入JNI一探究竟。
frameworks/base/core/jni/android_os_MessageQueue.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_nativePollOnce(JNIEnv* env, jobject obj,
jlong ptr, jint timeoutMillis) {
NativeMessageQueue* nativeMessageQueue = reinterpret_cast<NativeMessageQueue*>(ptr);
nativeMessageQueue->pollOnce(env, obj, timeoutMillis);
}
static void android_os_MessageQueue_nativeWake(JNIEnv* env, jclass clazz, jlong ptr) {
NativeMessageQueue* nativeMessageQueue = reinterpret_cast<NativeMessageQueue*>(ptr);
nativeMessageQueue->wake();
}
实例化NativeMessageQueue
,然后分别调用它的pollOnce/wake
两个方法。
NativeMessageQueue::NativeMessageQueue() :
mPollEnv(NULL), mPollObj(NULL), mExceptionObj(NULL) {
mLooper = Looper::getForThread();
if (mLooper == NULL) {
mLooper = new Looper(false);
Looper::setForThread(mLooper);
}
}
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;
}
}
void NativeMessageQueue::wake() {
mLooper->wake();
}
进一步调用到Looper的pollOnce/wake
两个方法。
system/core/libutils/Looper.cpp
Looper::Looper(bool allowNonCallbacks) :
mAllowNonCallbacks(allowNonCallbacks), mSendingMessage(false),
mPolling(false), mEpollFd(-1), mEpollRebuildRequired(false),
mNextRequestSeq(0), mResponseIndex(0), mNextMessageUptime(LLONG_MAX) {
// 创建事件句柄mWakeEventFd,用于唤醒
mWakeEventFd = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC);
rebuildEpollLocked();
}
void Looper::rebuildEpollLocked() {
// 创建epoll句柄
mEpollFd = epoll_create(EPOLL_SIZE_HINT);
struct epoll_event eventItem;
memset(& eventItem, 0, sizeof(epoll_event)); // zero out unused members of data field union
eventItem.events = EPOLLIN;
eventItem.data.fd = mWakeEventFd;
// 把mWakeEventFd加入epoll监听,监听写入(EPOLLIN)事件
int result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mWakeEventFd, & eventItem);
}
int Looper::pollOnce(int timeoutMillis, int* outFd, int* outEvents, void** outData) {
int result = 0;
for (;;) {
... ...
result = pollInner(timeoutMillis);
}
}
int Looper::pollInner(int timeoutMillis) {
struct epoll_event eventItems[EPOLL_MAX_EVENTS];
// 等待监听事件
int eventCount = epoll_wait(mEpollFd, eventItems, EPOLL_MAX_EVENTS, timeoutMillis);
... ...
return result;
}
void Looper::wake() {
uint64_t inc = 1;
// 向mWakeEventFd写入数据(写入什么数据并不重要),用于唤醒消息队列
// 调用这个方法后epoll_wait函数会返回,沿着调用链一路向上pollInner->pollOnce->pollOnce->android_os_MessageQueue_nativePollOnce->nativePollOnce->next
// 这个时候Looper.loop()调用的next()会返回,循环体继续执行
ssize_t nWrite = TEMP_FAILURE_RETRY(write(mWakeEventFd, &inc, sizeof(uint64_t)));
}
这里就是Android系统的Handler消息机制的消息循环的核心实现,使用了Linux的epoll事件处理机制。当消息队列为空时,常规的循环实现是调用sleep/usleep释放cpu,当时间到了之后,会获得CPU资源进行一次消息检查;Handler的消息循环采用Linux kernel的epoll机制,当消息队列为空时,会挂起释放CPU资源,只有当消息队列有新消息到来时,才会重新获得CPU资源,进行消息处理。
相比常规实现,Android系统的Handler消息机制更加节省系统资源(CPU资源)。
相比常规实现,Android系统的Handler消息机制的生产者,把消息放入消息队列的同时,可以通知(唤醒)消息处理者。