Android消息机制的核心

1,253 阅读3分钟

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消息机制的生产者,把消息放入消息队列的同时,可以通知(唤醒)消息处理者。