消息處理機制之消息隊列

Android中消息處理機制主要圍繞消息隊列來實現的。一個線程擁有一個消息隊列之後,就可以進入到一個消息循環中,同時其他線程以及線程本身可以往這個消息隊列發送消息,以便在這個消息被處理時執行一個特定的操作。

Android系統主要是通過MessageQueue、Looper和Handler三個類實現消息處理機制的。其中MessageQueue來描述消息隊列;Looper類用來創建消息隊列以及消息循環;Handler用來發送消息和處理消息。

先看一個典型的Looper線程實例

class LooperThread extends Thread {
        public Handler mHandler;
         
         public void run() {
             Looper.prepare();
             mHandler = new Handler() {
                 public void handleMessage(Message msg) {
                     // process incoming messages here
                 }
             };
             Looper.loop();
         }
     }

從實例中看出我們先調用了Looper.prepare()在其中會創建消息隊列,Looper.loop()在其中會進行消息循環的過程。Handler進行消息的發送和處理

一、創建線程消息隊列

Android 中消息隊列是使用MessageQueue對象來描述的,它是在Looper的構造方法中創建的,可以通過調用looper的靜態方法prepareMainLooper和prepare方法來實例化Looper。

frameworks/base/core/java/android/os/Looper.java

public final class Looper {
     static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
    private static Looper sMainLooper;  // guarded by Looper.class
    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));
    }

    /**
     * Initialize the current thread as a looper, marking it as an
     * application's main looper. The main looper for your application
     * is created by the Android environment, so you should never need
     * to call this function yourself.  See also: {@link #prepare()}
     */
    public static void prepareMainLooper() {
        prepare(false);
        synchronized (Looper.class) {
            if (sMainLooper != null) {
                throw new IllegalStateException("The main Looper has already been prepared.");
            }
            sMainLooper = myLooper();
        }
    }

    /**
     * Returns the application's main looper, which lives in the main thread of the application.
     */
    public static Looper getMainLooper() {
        synchronized (Looper.class) {
            return sMainLooper;
        }
    }
    
}

Looper類有一個類型爲ThreadLocal的靜態成員變量sThreadLocal,用來保存線程中的Looper對象。在Looper的靜態成員函數prepare方法中,if語句會檢查當前線程是否已經存在Looper對象,如果存在就會拋出異常;否則就會創建Looper實例並將它保存在Looper的靜態成員變量sThreadLocal中。

prepareMainLooper()方法只能有系統調用,用來創建我們應用程序主線程的消息隊列。Androidxitpng 是在ActivityThread的靜態成員函數main方法中調用的。

一個looper對象在創建過程中,會在構造方法中創建一個MessageQueue對象,並且保存在成員變量mQueue中

private Looper(boolean quitAllowed) {
        mQueue = new MessageQueue(quitAllowed);
        mThread = Thread.currentThread();
    }
 MessageQueue(boolean quitAllowed) {
        mQuitAllowed = quitAllowed;
        mPtr = nativeInit();
    }

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 const JNINativeMethod gMessageQueueMethods[] = {
    /* name, signature, funcPtr */
    { "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 },
};

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

在MessagQueue對象的構造方法中調用nativeInit JIN方法在此方法中創建了NativeMessageQueue對象。在register_android_os_MessageQueue方法中mPtr指向了java中MessageQueue的成員變量mPtr

NativeMessageQueue對象在創建的過程中,又會在內部調用C++的Looper對象

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

首先調用C++層的Looper類的靜態成員函數getForThread()來獲取當前線程的Looper對象。如果沒有創建過就會創建一個C++層的Looper對象,並保存在NativeMessageQueue類的成員變量mLooper中,然後調用Looper的靜態函數setForThread將當前線程關聯起來。

C++ Looper類的創建過程中,又在內部創建一個管道

Looper::Looper(bool allowNonCallbacks)
    : mAllowNonCallbacks(allowNonCallbacks),
      mSendingMessage(false),
      mPolling(false),
      mEpollRebuildRequired(false),
      mNextRequestSeq(0),
      mResponseIndex(0),
      mNextMessageUptime(LLONG_MAX) {
    mWakeEventFd.reset(eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC));
    LOG_ALWAYS_FATAL_IF(mWakeEventFd.get() < 0, "Could not make wake event fd: %s", strerror(errno));

    AutoMutex _l(mLock);
    rebuildEpollLocked();
}

void Looper::rebuildEpollLocked() {
    // Close old epoll instance if we have one.
    if (mEpollFd >= 0) {
        mEpollFd.reset();
    }

    // Allocate the new epoll instance and register the wake pipe.
    mEpollFd.reset(epoll_create1(EPOLL_CLOEXEC));
    LOG_ALWAYS_FATAL_IF(mEpollFd < 0, "Could not create epoll instance: %s", strerror(errno));

    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.get();
    int result = epoll_ctl(mEpollFd.get(), EPOLL_CTL_ADD, mWakeEventFd.get(), &eventItem);
    LOG_ALWAYS_FATAL_IF(result != 0, "Could not add wake event fd to epoll instance: %s",
                        strerror(errno));

    for (size_t i = 0; i < mRequests.size(); i++) {
        const Request& request = mRequests.valueAt(i);
        struct epoll_event eventItem;
        request.initEventItem(&eventItem);

        int epollResult = epoll_ctl(mEpollFd.get(), EPOLL_CTL_ADD, request.fd, &eventItem);
        if (epollResult < 0) {
            ALOGE("Error adding epoll events for fd %d while rebuilding epoll set: %s",
                  request.fd, strerror(errno));
        }
    }
}

在Looper中會創建mWakeEventFd,它是unique_fd類型的,在其中會創建一個管道。這個管道在消息循環中起到的作用非常大。首先當一個線程沒有消息需要處理是,它就會睡眠在這個管道的讀端文件描述符上,直到有新的消息需要處理爲止;其次當其他線程向這個線程的消息隊列發送一個消息之後,其他線程就會通過這個寫端文件描述符往這個管道寫入一個數據,從而將這個線程喚醒,以便對剛纔發送到消息隊列中的消息進行處理。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章