Android消息机制

前菜

介绍

Handler机制为Android提供给予开发者用于线程间切换,处理Java层消息与Native层消息的一种机制。

相关类

Java层

  • Thread
  • ThreadLocal
  • ThreadLocalMap
  • Looper
  • Message
  • MessageQueue
  • Handler

Native层

  • Looper
  • ALooper
  • NativeMessageQueue
  • Message
  • MessageHandler
  • WeakMessageHandler

基础知识介绍

1. ThreadLocal

源码链接

https://cs.android.com/android/platform/superproject/+/master:libcore/ojluni/src/main/java/java/lang/ThreadLocal.java

https://cs.android.com/android/platform/superproject/+/master:libcore/ojluni/src/main/java/java/lang/Thread.java

类关系

public class ThreadLocal {
    
     static class ThreadLocalMap {
       
         private static final int INITIAL_CAPACITY = 16;
         private Entry[] table  = new Entry[INITIAL_CAPACITY];
             
         static class Entry extends WeakReference> {
            Object value;
            Entry(ThreadLocal k, Object v) {
                super(k);
                value = v;
            }
         }
     }
}

一般使用ThreadLocal例子,以Looper为例。

static final ThreadLocal sThreadLocal = new ThreadLocal();
...
sThreadLocal.set(new Looper(quitAllowed));

储存数据

public class ThreadLocal {
    ...
    public void set(T value) {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null)
            map.set(this, value);
        else
            createMap(t, value);//第一次存储,该map一定为空
    }
    
    //从当前线程的 threadLocals 变量获取ThreadLocalMap对象
    ThreadLocalMap getMap(Thread t) {
        return t.threadLocals;
    }
    
     //创建ThreadLocalMap对象,并保存到当前线程的threadLocals变量中。
    void createMap(Thread t, T firstValue) {
        t.threadLocals = new ThreadLocalMap(this, firstValue);
    }
    
}
public class Thread implements Runnable{
    ...
    ThreadLocal.ThreadLocalMap threadLocals = null;
    ...
}

ThreadLocalMap结构

static class ThreadLocalMap{
    ...
    ThreadLocalMap(ThreadLocal firstKey, Object firstValue) {
        table = new Entry[INITIAL_CAPACITY];
        int i = firstKey.threadLocalHashCode & (INITIAL_CAPACITY - 1);
        table[i] = new Entry(firstKey, firstValue);
        size = 1;
        setThreshold(INITIAL_CAPACITY);
    }  
    
    
    
    private void set(ThreadLocal key, Object value) {

            Entry[] tab = table;
            int len = tab.length;
            int i = key.threadLocalHashCode & (len-1);

            for (Entry e = tab[i];
                 e != null;
                 e = tab[i = nextIndex(i, len)]) {
                ThreadLocal k = e.get();

                if (k == key) {
                    e.value = value;
                    return;
                }

                //如果ThreadLocal被回收了,则也进行Entry数组的回收工作
                if (k == null) {
                    replaceStaleEntry(key, value, i);
                    return;
                }
            }

            tab[i] = new Entry(key, value);
            int sz = ++size;
            if (!cleanSomeSlots(i, sz) && sz >= threshold)
                rehash();
        }
}

读取数据

public class ThreadLocal {
    
    public T get() {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null) {
            ThreadLocalMap.Entry e = map.getEntry(this);
            if (e != null) {
                @SuppressWarnings("unchecked")
                T result = (T)e.value;
                return result;
            }
        }
        //第一次获取,map为空,直接走初始化方法
        return setInitialValue();
    }
    
    private T setInitialValue() {
        T value = initialValue();
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null)
            map.set(this, value);
        else
            createMap(t, value);
        return value;
    }
    
    //如果之前没有保存过该ThreadLocal,则先存入一个null进入。
    protected T initialValue() {
        return null;
    }
    
}

image

结论

  1. ThreadLocal 里面有一个静态内部类 ThreadLocalMap,ThreadLocalMap 有个静态类 Entry,Entry继承 WeakReference。
  2. ThreadLocal 是一个工具类,主要负责从当前 Thread 中操作 ThreadLocalMap。
  3. ThreadLocalMap 里面维护着一个 Entry 数组,每一个 Entry 对象都保存着一个以ThreadLocal 为key,Object 为value的结构。
  4. Entry 里面的key被封装为弱引用,便于释放回收处理。
  5. 在同一个线程中,ThreadLocal对象与Object进行组合,同一个ThreadLocal对象,在Entry中只能保存一个值。

2. epoll 机制

epoll 是 Linux 提供的高效访问 I/O 的机制。

1.使用epoll前,需要先通过 epoll_create 函数创建一个epoll句柄。

// 创建能容纳10个fd相关信息的缓存。

int epollHandle = epoll_create( 10 );

2.得到epoll句柄后,通过epoll_ctl 把需要监听的文件句柄加入 epoll 句柄中。

// 先定义一个event

struct epoll_event listenEvent;

// 指定该句柄的可读事件

// EPOLLIN(句柄可读)

// EPOLLOUT(句柄可写)

// EPOLLERR(句柄错误)

// EPOLLUP(句柄断)

listenEvent.events = EPOLLIN;

// epoll_event 中有个联合体叫data,用来存储上下文数据。

data.fd = listenEvent;

3.EPOLL_CTL_ADD将监听fd和监听事件加入epoll句柄的等待队列中。

// EPOLL_CTL_DEL 将监听fd从epoll句柄中移除。

// EPOLL_CTL_MOD修改fd的监听事件。

epoll_ctl(epollHandle, Epoll_CTL_ADD ,listener, &listenEvent)

4调用epoll_wait用于等待事件。

struct epoll_event resultEvents[10];
......
int timeout = -1;
while(1){
    int nfds == epoll_wait(epollHandle,resultEvents,10,timeout);
    // nfds 大于0表示所监听的句柄上有事件发生。
    // nfds 等于0表示等待超时。
    // nfds 小于0表示等待过程中发生了错误。
    //
    if(nfds == -1){
        //错误
    }else if(nfds == 0){
        //超时
    }else{
        //resultEvents 用于返回哪些发生了事件的信息。
        struct epoll_event &event = resultEvents[i];
        if(event & EPOLLIN){
         //收到可读事件
          ......
        }
        ......//其他处理
    }
}
//添加监听
int Looper::addFd(int fd, int ident, int events, Looper_callbackFunc callback, void* data) ;

//处理监控请求
void Looper::pushResponse(int events, const Request& request) ;

正餐

Looper、MessageQueue、NativeMessageQueue创建过程

相关源码链接:

https://cs.android.com/android/platform/superproject/+/master:libcore/ojluni/src/main/java/java/lang/ThreadLocal.java

https://cs.android.com/android/platform/superproject/+/master:frameworks/base/core/java/android/os/Looper.java

https://cs.android.com/android/platform/superproject/+/master:frameworks/base/core/java/android/os/MessageQueue.java

https://cs.android.com/android/platform/superproject/+/master:frameworks/base/core/java/android/os/Message.java

https://cs.android.com/android/platform/superproject/+/master:frameworks/base/core/jni/android_os_MessageQueue.cpp

一般使用Looper,以ActivityThread为例。

public final class ActivityThread{
    public static void main(String[] args) {
        Looper.prepareMainLooper();
        ...
        Looper.loop();
    }
}

构建Looper对象

使用ThreadLocal工具保存到ThreadLocalMap中。

public final class Looper {
    //ThreadLocal声明为静态对象,确保在同一个线程下,只有一个Looper对象存在。
    static final ThreadLocal sThreadLocal = new ThreadLocal();
    
    public static void prepareMainLooper() {
        prepare(false);
        synchronized (Looper.class) {
            if (sMainLooper != null) {
                throw new IllegalStateException("The main Looper has already been prepared.");
            }
            sMainLooper = myLooper();
        }
    }
    
    //创建Looper对象,并将Looper对象保存到ThreadLocalMap中。
    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));
    }    
 
    //从ThreadLocalMap中获取Looper对象。
    public static Looper myLooper() {
        return sThreadLocal.get();
    } 
}

构建MessageQueue队列

public final class Looper {
    
    final MessageQueue mQueue;
    final Thread mThread;   
    
    ...
        
    private Looper(boolean quitAllowed) {
        mQueue = new MessageQueue(quitAllowed);
        mThread = Thread.currentThread();
    }
 
}
public final class MessageQueue {
    private final boolean mQuitAllowed;
    private long mPtr;
    
    MessageQueue(boolean quitAllowed) {
        mQuitAllowed = quitAllowed;
        //构造函数调用naitveInit,该函数由Native层实现。
        //Native层的 NativeMessageQueue 对象引用指针。
        mPtr = nativeInit();
    }    
}

构建Native层 NativeMessageQueue 对象

nativeInit 方法在 frameworks/base/core/jni/android_os_MessageQueue.cpp 定义实现。

class NativeMessageQueue : public MessageQueue, public LooperCallback {
    
    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(nativeMessageQueue);
    }

    
    NativeMessageQueue::NativeMessageQueue() :
            mPollEnv(NULL), mPollObj(NULL), mExceptionObj(NULL) {
        //一个线程会有一个Looper循环来处理消息队列中的消息。
        //获取保存在本地线程的存储空间的Looper对象
        mLooper = Looper::getForThread();
        if (mLooper == NULL) {
            //如果第一次进来,则该线程没有设置本地存储,所以需要先创建一个Looper,然后后再将其保存到TLS中,
            //这是很常见的一种以线程为单位的单利模式。
            mLooper = new Looper(false);
            Looper::setForThread(mLooper);
        }
    }    
}

注册epoll机制

Looper::Looper(bool allowNonCallbacks)
    : mAllowNonCallbacks(allowNonCallbacks),
      mSendingMessage(false),
      mPolling(false),
      mEpollRebuildRequired(false),
      mNextRequestSeq(0),
      mResponseIndex(0),
      mNextMessageUptime(LLONG_MAX) {
    // Android 6.0 之前为 pipe, 6.0 之后为 eventfd
    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() {
    // 如果有新的epoll事件,则把原来的epoll事件关闭
    if (mEpollFd >= 0) {
        mEpollFd.reset();
    }

    // Allocate the new epoll instance and register the wake pipe.
    // 创建一个epoll实例,并注册wake管道
    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;
    // 监控的fd为唤醒事件fd
    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));
    // 如果请求队列中有数据,则还需要将请求中的事件注册到epoll实例中
    for (size_t i = 0; i < mRequests.size(); i++) {
        const Request& request = mRequests.valueAt(i);
        struct epoll_event eventItem;
        request.initEventItem(&eventItem);
        // 注册请求中的事件到epoll实例中
        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));
        }
    }
}

image

Handler

相关源码链接:

https://cs.android.com/android/platform/superproject/+/master:frameworks/base/core/java/android/os/Handler.java

构建Handler

public class Handler {
    
    final Looper mLooper;
    final MessageQueue mQueue;
    
    public Handler() {
        this(null, false);
    }
    
    public Handler(Callback callback) {
        this(callback, false);
    }
    
    public Handler(Looper looper) {
        this(looper, null, false);
    }
   
    ...
    
    public Handler(Looper looper,Callback callback) {
        this(looper, callback, false);
    }
  
    public Handler(@Nullable Callback callback, boolean async) {
        if (FIND_POTENTIAL_LEAKS) {
            final Class klass = getClass();
            if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
                    (klass.getModifiers() & Modifier.STATIC) == 0) {
                Log.w(TAG, "The following Handler class should be static or leaks might occur: " +
                    klass.getCanonicalName());
            }
        }

        mLooper = Looper.myLooper();
        if (mLooper == null) {
            throw new RuntimeException(
                "Can't create handler inside thread " + Thread.currentThread()
                        + " that has not called Looper.prepare()");
        }
        mQueue = mLooper.mQueue;
        mCallback = callback;
        mAsynchronous = async;
    }

   public Handler(@NonNull Looper looper, @Nullable Callback callback, boolean async) {
        mLooper = looper;
        mQueue = looper.mQueue;
        mCallback = callback;
        mAsynchronous = async;
    }
}

通过Handler发送Message

举个栗子

Handler mHandler = new Handler();

#1.1 发送空消息
mHandler.sendEmptyMessage(what);
#1.3 发送延时消息
mHandler.sendEmptyMessageDelayed(what, 0);

#2.1 发送Message对象
Message msg = Message.obtail();
msg.what = ...;
msg.obj = ...;
mHandler.sendMessage(msg);

#2.2 发送延时消息
mHandler.sendMessageDelayed(msg,1000);

#2.3 在指定时间发送消息
mHandler.sendMessageAtTime(msg,uptimeMillis);

#4. 发送Runnable消息
mHandler.post(Runnable r);

...
public class Handler {
    
    //方式一
    public final boolean sendEmptyMessage(int what) {
        return sendEmptyMessageDelayed(what, 0);
    }
  
    public final boolean sendEmptyMessageDelayed(int what, long delayMillis) {
        Message msg = Message.obtain();
        msg.what = what;
        return sendMessageDelayed(msg, delayMillis);
    }
    
    //方式二
    public final boolean sendMessage(Message msg) {
        return sendMessageDelayed(msg, 0);
    }
    
    //方式三
    public final boolean post(@NonNull Runnable r) {
       return  sendMessageDelayed(getPostMessage(r), 0);
    }
 
    private static Message getPostMessage(Runnable r) {
        Message m = Message.obtain();
        m.callback = r;
        return m;
    }    
    

    public final boolean sendMessageDelayed(Message msg, long delayMillis) {
        if (delayMillis < 0) {
            delayMillis = 0;
        }
        return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
    }


    public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
        MessageQueue queue = mQueue;
        if (queue == null) {
            RuntimeException e = new RuntimeException(
                    this + " sendMessageAtTime() called with no mQueue");
            Log.w("Looper", e.getMessage(), e);
            return false;
        }
        return enqueueMessage(queue, msg, uptimeMillis);
    }
    
    private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
        //这里将当前Handler进行保存,主要为了后续分发到对应 Handler 的对象的 handleMessage 方法。
        msg.target = this;
        msg.workSourceUid = ThreadLocalWorkSource.getUid();

        if (mAsynchronous) {
            msg.setAsynchronous(true);
        }
        return queue.enqueueMessage(msg, uptimeMillis);
    }
}

MessageQueue处理逻辑

Message结构

public final class Message implements Parcelable {
    public int what;    
    public int arg1;
    public int arg2;
    public Object obj;
    Handler target;//发送该Message的对象,用于回调
    Runnable callback;
    Message next;
    public long when;//执行时间
    ...
}

MessageQueue 与 Message 关系图

MessageQueue里面维护的是Message链表。

image

在Java层投递Message

public final class MessageQueue {
 
    boolean enqueueMessage(Message msg, long when) {
        ......
        boolean needWake;
        synchronized (this) {
            if (mQuitting) {
                msg.recycle();
                return false;
            }
            ......
            msg.when = when;
            Message p = mMessages;

            if (p == null || when == 0 || when < p.when) {
                // 如果p为空,表明消息队列中没有消息,那么msg将是第一个消息,needwake需要根据mBlocked的
                //情况考虑是否触发。
                msg.next = p;
                mMessages = msg;
                needWake = mBlocked;
            } else {
                //如果p不为空,表明消息队列中还有剩余的消息,需要将新的msg添加到对应的位置。
                needWake = mBlocked && p.target == null && msg.isAsynchronous();
                Message prev;
                for (;;) {
                    prev = p;
                    p = p.next;
                    //从消息队列中取出消息,判断该消息的触发时间,与要新添加的Message的时间对比。
                    //如果新添加的Message时间小于 当前消息队列中获取的Message的时间,则直接break。
                    if (p == null || when < p.when) {
                        break;
                    }
                    if (needWake && p.isAsynchronous()) {
                        needWake = false;
                    }
                }
                //将新添加的Message添加到该队列的指定位置。如下图所示
                msg.next = p; // invariant: p == prev.next
                prev.next = msg;
            }

            // We can assume mPtr != 0 because mQuitting is false.
            //最后根据情况判断是否需要唤醒
            if (needWake) {
                // 调用nativeWake,以触发nativePollOnce函数结束等待。
                nativeWake(mPtr);
            }
        }
        return true;
    }
  
}
image

在Java层提取Message

public final class MessageQueue {
    Message next() {
        ......
        final long ptr = mPtr;
        if (ptr == 0) {
            return null;
        }

        int pendingIdleHandlerCount = -1; // -1 only during first iteration
        int nextPollTimeoutMillis = 0;
        for (;;) {
            if (nextPollTimeoutMillis != 0) {
                Binder.flushPendingCommands();
            }
            
            // ptr 保存了 NativeMessageQueue的指针,调用nativePollOnce进行等待
            nativePollOnce(ptr, nextPollTimeoutMillis);

            synchronized (this) {
                final long now = SystemClock.uptimeMillis();
                Message prevMsg = null;
                Message msg = mMessages;
                if (msg != null && msg.target == null) {
                    // 尝试先从消息队列中寻找异步消息
                    do {
                        prevMsg = msg;
                        msg = msg.next;
                    } while (msg != null && !msg.isAsynchronous());
                }
                if (msg != null) {
                    if (now < msg.when) {
                        // Next message is not ready.  Set a timeout to wake up when it is ready.
                        // 从消息队列中拿到的Message的执行时间,比当前时间还后面,则计算其差值,用于后面休眠。
                        nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
                    } else {
                        //如果从消息队列中获取的Message小于当前时间,则返回给Looper进行派发和处理。
                        mBlocked = false;
                        if (prevMsg != null) {
                            prevMsg.next = msg.next;
                        } else {
                            mMessages = msg.next;
                        }
                        msg.next = null;//断开引用链,便于GC回收
                        msg.markInUse();
                        return msg;
                    }
                } else {
                    // No more messages.
                    // 消息队列中没有更多的消息了。则进行长时间休眠。
                    // -1代表长时间等待。
                    nextPollTimeoutMillis = -1;
                }

                ......
                // 下面主要IdleHandler的相关逻辑
                    
                // If first time idle, then get the number of idlers to run.
                // Idle handles only run if the queue is empty or if the first message
                // in the queue (possibly a barrier) is due to be handled in the future.
                if (pendingIdleHandlerCount < 0
                        && (mMessages == null || now < mMessages.when)) {
                    pendingIdleHandlerCount = mIdleHandlers.size();
                }
                if (pendingIdleHandlerCount <= 0) {
                    // No idle handlers to run.  Loop and wait some more.
                    mBlocked = true;
                    continue;
                }

                if (mPendingIdleHandlers == null) {
                    mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)];
                }
                mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers);
            }

            // Run the idle handlers.
            // We only ever reach this code block during the first iteration.
            for (int i = 0; i < pendingIdleHandlerCount; i++) {
                final IdleHandler idler = mPendingIdleHandlers[i];
                mPendingIdleHandlers[i] = null; // release the reference to the handler

                boolean keep = false;
                try {
                    //这里函数的返回值,觉得后续是否还会调用该IdleHandler的方法。
                    keep = idler.queueIdle();
                } catch (Throwable t) {
                    Log.wtf(TAG, "IdleHandler threw exception", t);
                }

                // queueIdle 返回false的时候,就会将其从ArrayList队列中移除掉,下次就不会再接收到函数调用。
                if (!keep) {
                    synchronized (this) {
                        mIdleHandlers.remove(idler);
                    }
                }
            }

            // Reset the idle handler count to 0 so we do not run them again.
            pendingIdleHandlerCount = 0;

            // While calling an idle handler, a new message could have been delivered
            // so go back and look again for a pending message without waiting.
            nextPollTimeoutMillis = 0;
        }
    }
    
}

nativeWake函数分析

nativeWake函数分析

frameworks/base/core/jni/android_os_MessageQueue.cpp
class NativeMessageQueue : public MessageQueue, public LooperCallback {
    
    static void android_os_MessageQueue_nativeWake(JNIEnv* env, jclass clazz, jlong ptr) {
        NativeMessageQueue* nativeMessageQueue = reinterpret_cast(ptr);
        nativeMessageQueue->wake();
    }
    
    void NativeMessageQueue::wake() {
        mLooper->wake();
    }
}
system/core/libutils/Looper.cpp
void Looper::wake() {
    ......
    uint64_t inc = 1;
    //向管道的写端写入一个字符(旧版本是写入一个"W"字符)。
    ssize_t nWrite = TEMP_FAILURE_RETRY(write(mWakeEventFd.get(), &inc, sizeof(uint64_t)));
    if (nWrite != sizeof(uint64_t)) {
        ......
    }
}


//旧版
//父进程、子进程
void Looper::wake() {
#if DEBUG_POLL_AND_WAKE
    ALOGD("%p ~ wake", this);
#endif

    ssize_t nWrite;
    do {
        nWrite = write(mWakeWritePipeFd, "W", 1);
    } while (nWrite == -1 && errno == EINTR);

    if (nWrite != 1) {
        if (errno != EAGAIN) {
            ALOGW("Could not write wake signal, errno=%d", errno);
        }
    }
}

nativePollOnce函数分析

frameworks/base/core/jni/android_os_MessageQueue.cpp
class NativeMessageQueue : public MessageQueue, public LooperCallback {
    
    static void android_os_MessageQueue_nativePollOnce(JNIEnv* env, jobject obj,
            jlong ptr, jint timeoutMillis) {
        NativeMessageQueue* nativeMessageQueue = reinterpret_cast(ptr);
        nativeMessageQueue->pollOnce(env, obj, timeoutMillis);
    }
    
    void NativeMessageQueue::pollOnce(JNIEnv* env, jobject pollObj, int timeoutMillis) {
        ......
        mLooper->pollOnce(timeoutMillis);
        ......
    }    
}
system/core/libutils/Looper.cpp
inline int pollOnce(int timeoutMillis) {
   return pollOnce(timeoutMillis, nullptr, nullptr, nullptr);
}
int Looper::pollOnce(int timeoutMillis, int* outFd, int* outEvents, void** outData);

timeoutMillis:超时等待时间。
            如果为-1,则表示无限等待,直到有事件发生为止。
            如果值为0,则无需等待立即返回。
outFd:用来存储发生事件的那个文件描述符。
outEvents:用来存储在该文件描述符上发生了哪些事件,目前支持可读、可写、错误和中断4个事件。(从epoll事件对应而来)
outData:用来存储上下文数据,这个上下文数据是由用户在添加监听句柄时传递的,它的作用和 pthread_create 函数的最后
            一个参数 parame 一样,用来传递用户数据。
int Looper::pollOnce(int timeoutMillis, int* outFd, int* outEvents, void** outData) {
    int result = 0;
    for (;;) {  //无限循环
        // mResponses 为 Vector数据结构。
        while (mResponseIndex < mResponses.size()) {
            const Response& response = mResponses.itemAt(mResponseIndex++);
            int ident = response.request.ident;
            if (ident >= 0) {
                int fd = response.request.fd;
                int events = response.events;
                void* data = response.request.data;
                if (outFd != nullptr) *outFd = fd;
                if (outEvents != nullptr) *outEvents = events;
                if (outData != nullptr) *outData = data;
                return ident;
            }
        }

        if (result != 0) {
            if (outFd != nullptr) *outFd = 0;
            if (outEvents != nullptr) *outEvents = 0;
            if (outData != nullptr) *outData = nullptr;
            return result;
        }

        result = pollInner(timeoutMillis);
    }
}
int Looper::pollInner(int timeoutMillis) {
    ......
    调用epoll函数等待,查看epoll函数返回结果;
    超时、错误、有事件发生;
    如果是管道读端有事件,则认为是控制命令,可以直接读取管道中的数据;(eventfd)
    如果是其他fd发生事件,则根据Request构造Response,并push到Response数组中。
    真正处理事件,首先处理Native的Message。调用Native Handler 的 handleMessage处理该Message。
    处理Response数组中带有callback的事件。
    
}

Handler、Looper、MessageQueue、Thread关系

image.png
  • 一个线程里面有一个Looper。
  • 一个Looper对应一个MessageQueue。
  • 一个Looper可能对应多个Handler。
  • 相同的Looper的Handler发消息,都发送到同一个MessageQueue。
  • MessageQueue处理完成后,分发消息会根据target字段,找到Handler的引用,并完成分发工作。

甜点

1. IdelHandler

    public static interface IdleHandler {
        boolean queueIdle();
    }

当一个线程准备等待更多消息时,即其将消息分发完之后就会回调这个接口。

queueIdle返回false代表一次性,返回true可能有多次回调。

添加IdleHandler

public final class MessageQueue { 
    public void addIdleHandler(@NonNull IdleHandler handler) {
        if (handler == null) {
            throw new NullPointerException("Can't add a null IdleHandler");
        }
        synchronized (this) {
            mIdleHandlers.add(handler);
        }
    }
}

2. 消息屏障

image

Message类型分为3种类型:

  • normal 普通消息
  • barrier 消息屏障
  • async 异步消息

插入消息屏障

public final class MessageQueue {
    public int postSyncBarrier() {
        return postSyncBarrier(SystemClock.uptimeMillis());
    }
    
    private int postSyncBarrier(long when) {
        // 按照时间排序,将这个msg插入到消息队列中
        synchronized (this) {
            final int token = mNextBarrierToken++;
            final Message msg = Message.obtain();
            msg.markInUse();
            msg.when = when;
            msg.arg1 = token;

            Message prev = null;
            Message p = mMessages;
            if (when != 0) {
                while (p != null && p.when <= when) {
                    prev = p;
                    p = p.next;
                }
            }
            if (prev != null) { // invariant: p == prev.next
                msg.next = p;
                prev.next = msg;
            } else {
                msg.next = p;
                mMessages = msg;
            }
            return token;
        }
    }
}

消息屏障有6点注意事项!

  1. 没有设置target。
  2. 消息屏障也是带着时间戳的,也是按时间来进行排序,只影响后面他后面的消息。
  3. 消息队列是可以插入多个消息屏障的。
  4. 插入到消息队列的时候,是没有唤醒线程的。
  5. 插入消息屏障的时候会返回一个token,后续撤除这个消息屏障,需要使用token去消息队列中查找。
  6. 消息屏障没有对外开放,要使用需要利用反射机制。

移除消息屏障

public final class MessageQueue {
    //根据token移除消息屏障。
    public void removeSyncBarrier(int token) {
        // Remove a sync barrier token from the queue.
        // If the queue is no longer stalled by a barrier then wake it.
        synchronized (this) {
            Message prev = null;
            Message p = mMessages;
            while (p != null && (p.target != null || p.arg1 != token)) {
                prev = p;
                p = p.next;
            }
            if (p == null) {
                throw new IllegalStateException("The specified message queue synchronization "
                        + " barrier token has not been posted or has already been removed.");
            }
            final boolean needWake;
            if (prev != null) {
                prev.next = p.next;
                needWake = false;
            } else {
                mMessages = p.next;
                needWake = mMessages == null || mMessages.target != null;
            }
            p.recycleUnchecked();

            // If the loop is quitting then it is already awake.
            // We can assume mPtr != 0 when mQuitting is false.
            if (needWake && !mQuitting) {
                nativeWake(mPtr);
            }
        }
    }
}

处理屏障

next方法里面处理,具体逻辑为:

public final class MessageQueue {
    Message next() {
        for (;;) {
            nativePollOnce(ptr, nextPollTimeoutMillis);
            ......
            如果第一条消息是就是屏障,就往后面遍历查看是否有异步消息。
            如果没有,就无限休眠,等待被别人唤醒。
            如果有,就看这个消息触发时间还有多长,设置一个超时,继续休眠。
        }
        
    }
}
  • 如果将消息插入到队列头部,不受消息屏障的影响,唤醒线程,去处理消息。
  • 如果没有插入到队列头部,并且头部是消息屏障,此时插入普通消息不唤醒消息队列。
  • 如果此时插入的是异步消息,并且插入的位置前面没有其他异步消息,则进行队列的唤醒。

Android中内存屏障使用例子

https://cs.android.com/android/platform/superproject/+/master:frameworks/base/core/java/android/view/ViewRootImpl.java;l=1919?q=scheduleTrav&sq=

总结

image
  • Java层提供了Looper类和MessageQueue类,其中Looper类提供循环处理消息的机制,以及插入、删除和提取消息的函数接口。
  • Handler常用于用户与MessageQueue处理相关。
  • MessageQueue内部通过mPtr变量保存了一个Native层的NativeMessageQueue对象。
  • NativeMessageQueue保存了一个Native层的Looper对象,该Looper从ALooper派生,提供pollOnce 和addFd等函数。
  • Java层有Message类和Handler类,而Native层也有对应的Message类和MessageHandler抽象类。

你可能感兴趣的:(Android消息机制)