Android Message机制

Android的Message机制,也叫handler机制,主要由3部分+Message组成,这三部分分别是Looper、MessageQueue和Handler。

Looper:循环体,其作用就是从MessageQueue中取出Message进行消费,一般线程的主体方法的结尾,都会调用Looper的loop方法进入循环,等待处理消息。

MessageQueue:Message的管理队列,用于保存Message。

Handler:Message处理的句柄(具体的处理操作)。

Looper

一般支持Message机制的应用进程或线程,都会调用Looper,如SystemServer和ActivityThread。

我们先看以下Looper是如何创建。

Looper的创建

// frameworks/base/core/java/android/app/ActivityThread.java
	public static void main(String[] args) {
        Looper.prepareMainLooper();

        Looper.loop();
        throw new RuntimeException("Main thread loop unexpectedly exited");
	}

以上的代码段是ActivityThread.main方法中对Looper相关代码的提取,可以看到,使用Looper只需简单的两个方法:prepareMainLooper和loop。

prepareMainLooper是Looper的静态方法,用于创建主线程的Looper对象,从名字上来看,除了主线程,子线程也是可以创建Looper对象。

public static void prepareMainLooper() {
        prepare(false);
        synchronized (Looper.class) {
            if (sMainLooper != null) {
                throw new IllegalStateException("The main Looper has already been prepared.");
            }
            sMainLooper = myLooper();
        }
    }
    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));
    }

Looper.prepareMainLooper主要是调用了prepare方法,传参false,表示创建一个不可退出的Looper,这个Looper主要是应用主线程的Looper,由于应用的主线程是不能退出的,主线程的Looper一般都会在主线程的主体结束前调用loop方法,使应用进入循环,保证主线程不会退出,而一旦主线程退出,则应用也就退出。而Looper同时为应用子线程提供了无参的prepare方法,无参的prepare方法就是调用了私有方法Boolean类型的prepare方法,传参true,表示该Looper可退出。

prepareMainLooper会将创建出来的Looper保存到sMainLooper中供应用其他的子线程快速获取。

带参prepare方法中会判断线程是否已经创建过Looper,Android只允许每个线程有一个Looper,这个是合理的设计,因为每个线程最多只能无限执行一个循环。

带参prepare方法中,使用了ThreadLocal泛型类型,以支持每个线程都能创建Looper,ThreadLocal有一个数组保存了每个线程的Looper对象,在不同的线程中调用sThreadLocal.get()获取的Looper都是不一样的。具体可参考libcore/ojluni/src/main/java/java/lang/ThreadLocal.java 。

Looper实例的构建比较简单,主要是创建了MessageQueue实例和记录当前的Thread对象,这里就不展开说明。

Looper.loop

Looper.loop是整个Looper的核心,我们在这里分析整个loop的过程,了解这当中的细节。

public static void loop() {
        final Looper me = myLooper();
        if (me == null) {
            throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
        }
        final MessageQueue queue = me.mQueue;

        // Make sure the identity of this thread is that of the local process,
        // and keep track of what that identity token actually is.
        Binder.clearCallingIdentity();
        final long ident = Binder.clearCallingIdentity();

        // Allow overriding a threshold with a system prop. e.g.
        // adb shell 'setprop log.looper.1000.main.slow 1 && stop && start'
        final int thresholdOverride =
                SystemProperties.getInt("log.looper."
                        + Process.myUid() + "."
                        + Thread.currentThread().getName()
                        + ".slow", 0);

        boolean slowDeliveryDetected = false;
        for (;;) {
            Message msg = queue.next(); // might block
            if (msg == null) {
                // No message indicates that the message queue is quitting.
                return;
            }

            // This must be in a local variable, in case a UI event sets the logger
            final Printer logging = me.mLogging;
            if (logging != null) {
                logging.println(">>>>> Dispatching to " + msg.target + " " +
                        msg.callback + ": " + msg.what);
            }
            // Make sure the observer won't change while processing a transaction.
            final Observer observer = sObserver;

            final long traceTag = me.mTraceTag;
            long slowDispatchThresholdMs = me.mSlowDispatchThresholdMs;
            long slowDeliveryThresholdMs = me.mSlowDeliveryThresholdMs;
            if (thresholdOverride > 0) {
                slowDispatchThresholdMs = thresholdOverride;
                slowDeliveryThresholdMs = thresholdOverride;
            }
            // logSlowDelivery和logSlowDispatch是处理dispatch和delivery较慢的消息。
            final boolean logSlowDelivery = (slowDeliveryThresholdMs > 0) && (msg.when > 0);
            final boolean logSlowDispatch = (slowDispatchThresholdMs > 0);

            final boolean needStartTime = logSlowDelivery || logSlowDispatch;
            final boolean needEndTime = logSlowDispatch;

            if (traceTag != 0 && Trace.isTagEnabled(traceTag)) {
                Trace.traceBegin(traceTag, msg.target.getTraceName(msg));
            }
            final long dispatchStart = needStartTime ? SystemClock.uptimeMillis() : 0;
            final long dispatchEnd;
            Object token = null;
            if (observer != null) {
                token = observer.messageDispatchStarting();
            }
            long origWorkSource = ThreadLocalWorkSource.setUid(msg.workSourceUid);
            try {
                msg.target.dispatchMessage(msg);
                if (observer != null) {
                    observer.messageDispatched(token, msg);
                }
                dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;
            } catch (Exception exception) {
                if (observer != null) {
                    observer.dispatchingThrewException(token, msg, exception);
                }
                throw exception;
            } finally {
                ThreadLocalWorkSource.restore(origWorkSource);
                if (traceTag != 0) {
                    Trace.traceEnd(traceTag);
                }
            }
            if (logSlowDelivery) {
                if (slowDeliveryDetected) {
                    if ((dispatchStart - msg.when) <= 10) {
                        Slog.w(TAG, "Drained");
                        slowDeliveryDetected = false;
                    }
                } else {
                    if (showSlowLog(slowDeliveryThresholdMs, msg.when, dispatchStart, "delivery",
                            msg)) {
                        // Once we write a slow delivery log, suppress until the queue drains.
                        slowDeliveryDetected = true;
                    }
                }
            }
            if (logSlowDispatch) {
                showSlowLog(slowDispatchThresholdMs, dispatchStart, dispatchEnd, "dispatch", msg);
            }

            if (logging != null) {
                logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
            }

            // Make sure that during the course of dispatching the
            // identity of the thread wasn't corrupted.
            final long newIdent = Binder.clearCallingIdentity();
            if (ident != newIdent) {
                Log.wtf(TAG, "Thread identity changed from 0x"
                        + Long.toHexString(ident) + " to 0x"
                        + Long.toHexString(newIdent) + " while dispatching to "
                        + msg.target.getClass().getName() + " "
                        + msg.callback + " what=" + msg.what);
            }

            msg.recycleUnchecked();
        }
    }

loop方法中代码很多,但很多都是非重点代码,都是一些调试log的代码,真正的核心代码只有以下2行:

Message msg = queue.next(); // might block
msg.target.dispatchMessage(msg);

loop就是进入一个死循环体中,不断地从MessageQueue中取出Message进行消费,消费就是调用Message中的target(Handler)的dispatchMessage方法进行处理。

Looper中的设计特点

Looper中有一些设计是非常妙的,我们来总结一下。

1.Looper的构造方法是private修饰的,意味着,外部无法实例化Looper,只能通过Looper类提供的静态方法进行创建,类似于单例模式。

2.Looper中使用的设计模式又并非单例模式,因为一个进程中,是允许有多个Looper实例对象的。

Message和Handler

MessageQueue的代码更为复杂,我们先来看看MessageQueue的数据是怎么使用的。

我们以ActivityThread内部发送Message的源码来进行抛砖引玉。

private void sendMessage(int what, Object obj, int arg1, int arg2, boolean async) {
    Message msg = Message.obtain();
    msg.what = what;
    msg.obj = obj;
    msg.arg1 = arg1;
    msg.arg2 = arg2;
    if (async) {
        msg.setAsynchronous(true);
    }
    mH.sendMessage(msg);
}

ActivityThread的sendMessage方法中,主要是通过Message.obtain()方法生成一个空的Message,然后填充what字段(必须)以及其他选填数据,最后通过Handler的sendoMessage方法发送消息。值得注意的是,Message中有setAsynchronous方法,表明Message的处理或者分发应该支持异步的操作。

Message的发送在这里我们重点关注2点:①Message的创建方式有多少种,里面有什么重要的信息。②Handler发送Message的方式有多少种,以及发送Message的过程是怎样的。

Message的创建

我们先来看看Message的类图:

android 中的 Messenger_android

Message中构造函数是public修饰的,表明其可以外部new出对象,但Message类提供了多个obtain的静态重载方法。其中主要看它们的参数,有几个重要的参数组合,无参方法表示只new出一个纯粹的Message对象,需要用户自行填充数据。带有Message对象参数的方法,将obtain一个Message,然后将参数Message中的数据copy到新的Message中。剩下的几个就是赋予不同参数的obtain方法,将这些参数赋值到Message的变量中。

其中有几个比较重要的变量:what(Message的类型,识别Message的重要变量)、arg1和arg2(Message的参数,可不设置)、obj(传递的一些数据对象)、flag(一些标志,如异步)、target(Handler,处理Message的一种方式)、callback(Runnable,处理Message的一种方式)、next和sPool(Message的缓存池,在一个进程中,Message并不是每次都会new出新的对象,以减少内存的开销)。sendToTarget方法,用于Message的发送。

Message的设计特点

Message中使用了缓存池的设计思想,是值得我们思考和参考的,我们来具体看一下。

Message的多个obtain方法,都会调用到无参的obtain方法,而无参的obtain方法就是使用缓存池的核心。

public static Message obtain() {
    synchronized (sPoolSync) {   //持锁,保证申请/创建Message对象是原子操作
        if (sPool != null) {
            Message m = sPool;
            sPool = m.next;
            m.next = null;
            m.flags = 0; // clear in-use flag
            sPoolSize--;
            return m;
        }
    }
    return new Message();
}

Message中的缓存池使用的是单链表的方式实现,sPool就是这个链表的表头,next就是指向下一个节点的指针,当调用obtain时,如果sPool非空,即缓存池中有Message实例对象时,则可直接获取该对象来使用,同时将这个实例对象的next指针赋值给sPool,此时这个实例对象就从缓存池中被取出。这个缓存池的大小是MAX_POOL_SIZE(50),那么这缓存池中的实例对象时从哪来的呢?其来源就是当Message被处理完后,调用recycleUnchecked,丢到缓存池中备用:

void recycleUnchecked() {
    // Mark the message as in use while it remains in the recycled object pool.
    // Clear out all other details.
    flags = FLAG_IN_USE;
    what = 0;
    arg1 = 0;
    arg2 = 0;
    obj = null;
    replyTo = null;
    sendingUid = UID_NONE;
    workSourceUid = UID_NONE;
    when = 0;
    target = null;
    callback = null;
    data = null;

    synchronized (sPoolSync) {
        if (sPoolSize < MAX_POOL_SIZE) {
            next = sPool;
            sPool = this;
            sPoolSize++;
        }
    }
}

recycleUnchecked的前半部分都是将Message实例的数据reset,如果目前缓存池的数量已经达到上限,则抛弃这个实例,由虚拟机的GC进行回收,否则加入到缓存池的链表头中,等待obtain方法被调用时再次使用。

Handler的消息发送

Handler的类图如下:

android 中的 Messenger_主线程_02

Handler的作用主要是分发消息和处理消息,同样,也可以通过Handler来实例化Message对象。我们主要关注Handler的一下方法:

1.post系列方法,用于发送消息,实际上底层也是调用到sendMessage。

2.sendMessage系列方法,用于发送消息。

3.dispatchMessage,分发消息。

4.handleMessage,处理消息,Handler默认空实现,用户一般会实现一个继承Handler的子类,重写handleMessage方法,进而处理消息。

5.removeMessages和removeCallbacksAndMessages,用于删除指定的一类消息。

post

我们先来看一下post系列的方法,以两个典型为例看一下;

public final boolean post(@NonNull Runnable r) {
   return  sendMessageDelayed(getPostMessage(r), 0);
}
public final boolean postAtTime(@NonNull Runnable r, long uptimeMillis) {
    return sendMessageAtTime(getPostMessage(r), uptimeMillis);
}
private static Message getPostMessage(Runnable r) {
    Message m = Message.obtain();
    m.callback = r;
    return m;
}

Handler的post方法和postAtTime方法,传参都是Runnable类型的实例,postAtTime则是添加了事件戳,两者的底层都是调用到sendMessage系列的方法。而post系统发送的消息,由getPostMessage方法来生成。从post系列的方法中可以看到,post的Message的处理都是Runnable的方式。

sendMessage

我们再来看看sendMessage方法的实现,这个是我们的重点方法,我们也还是以两个典型方法来分析:

public final boolean sendMessage(@NonNull Message msg) {
    return sendMessageDelayed(msg, 0);
}
public final boolean sendMessageDelayed(@NonNull Message msg, long delayMillis) {
    if (delayMillis < 0) {
        delayMillis = 0;
    }
    return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}
public boolean sendMessageAtTime(@NonNull 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);
}
public final boolean sendMessageAtFrontOfQueue(@NonNull Message msg) {
    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, 0);
}

不论是sendMessage、sendMessageDelay、sendMessageAtTime或者sendMessageAtFrontOfQueue,其最终都是调用enqueueMessage方法将Message压入到MessageQueue中:

private boolean enqueueMessage(@NonNull MessageQueue queue, @NonNull Message msg,
        long uptimeMillis) {
    msg.target = this;
    msg.workSourceUid = ThreadLocalWorkSource.getUid();

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

其中Message在MessageQueue中的位置是由uptimeMillis参数来决定,MessageQueue中的Message是由消息处理的时间戳来排序的,因此sendMessageAtFrontOfQueue方法中,uptimeMillis为0,表示立即处理。至于Message是如何压入到MessageQueue部分的逻辑,我们放到MessageQueue的代码中进行分析。

dispatchMessage
public void dispatchMessage(@NonNull Message msg) {
    if (msg.callback != null) {
        handleCallback(msg);
    } else {
        if (mCallback != null) {
            if (mCallback.handleMessage(msg)) {
                return;
            }
        }
        handleMessage(msg);
    }
}

dispacthMessage的逻辑十分简单,如果Message有设置自身有设置callback(Runnable实例),则执行运行callback。否则会交由Handler进行处理。Handler在构造的时候可以传入Callback实例,这样就会优先使用Callback来进行处理,如下:

// frameworks/base/core/java/android/view/LayoutInflater.java
mHandler = new Handler(new Handler.Callback() {
    @Override
    public boolean handleMessage(Message msg) {
        if (msg.what == MESSAGE_BLINK) {
            if (mBlink) {
                mBlinkState = !mBlinkState;
                makeBlink();
            }
            invalidate();
            return true;
        }
        return false;
    }
});

否则就调用handleMessage方法,一般由用户自定义实现,如下:

// frameworks/base/wifi/java/android/net/wifi/WifiManager.java
mHandler = new Handler(looper) {
    @Override
    public void handleMessage(Message msg) {
        WifiManager manager = mWifiManager.get();
        if (manager == null) {
            Log.w(TAG, "LocalOnlyHotspotCallbackProxy: handle message post GC");
            return;
        }
        switch (msg.what) {
            case HOTSPOT_STARTED:
                WifiConfiguration config = (WifiConfiguration) msg.obj;
                if (config == null) {
                    Log.e(TAG, "LocalOnlyHotspotCallbackProxy: config cannot be null.");
                    callback.onFailed(LocalOnlyHotspotCallback.ERROR_GENERIC);
                    return;
                }
                callback.onStarted(manager.new LocalOnlyHotspotReservation(config));
                break;
            case HOTSPOT_STOPPED:
                Log.w(TAG, "LocalOnlyHotspotCallbackProxy: hotspot stopped");
                callback.onStopped();
                break;
            case HOTSPOT_FAILED:
                int reasonCode = msg.arg1;
                callback.onFailed(reasonCode);
                Log.w(TAG, "done with the callback...");
                break;
            default:
                Log.e(TAG, "LocalOnlyHotspotCallbackProxy unhandled message.  type: "
                        + msg.what);
        }
    }
};

Message是怎么走到Handler的?这个可以往前参考Looper.loop和Handler.enqueueMessage,enqueueMessage将Message的target变量设置成Handler的实例,在Looper中的loop方法,从MessageQueue中取出Message后就会调用其target变量的dispatchMessage方法,这样就走到了这里来。

removeMessages方法比较简单,主要跟MessageQueue相关,我们放到MessageQueue的分析时再看。

MessageQueue

MessageQueue是Android Message机制的核心,也是最复杂的部分,我们仔细分析一下这里。下面是MessageQueue的类图:

android 中的 Messenger_android_03

MessageQueue的代码涉及了Java部分和native部分,我们还是分几条主线来进行分析:

1.MessageQueue的创建。

2.消息的来源 – enqueueMessage

3.消息的分发处理

4.消息的remove

5.设计特点

MessageQueue的创建

再Looper的创建的时候已经看到,MessageQueue的实例就是在Looper的创建时创建的:

MessageQueue(boolean quitAllowed) {
    mQuitAllowed = quitAllowed;
    mPtr = nativeInit();
}

MessageQueue跟Looper是绑定的,一个Looper有一个MessageQueue。在主Looper中,MessageQueue的mQuitAllowed为false,非主Looper则可为true。nativeInit是native的方法:

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

MessageQueue在构造时会创建一个native层对应的实例 – NativeMessageQueue,然后将这个实例的native地址返回。下面是NativeMessageQueue以及相关类的类图:

android 中的 Messenger_主线程_04

NativeMessageQueue以及其相关的类跟Java层的MessageQueue和Looper是不是十分的像。接下来的内容与就是分析native层的内容。

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

NativeMessageQueue在构造时就会获取/创建一个native层的Looper实例,而这个实例是绑定线程的,也就是说,一个线程只能有一个native层的Looper实例,这与Java层的Looper是一样的。native层的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();
}

Looper实现中有两种文件:eventfd和epoll_fd。eventfd用于唤醒Looper,epoll_fd则是用于监听消息。event_fd由eventfd方法创建,epoll_fd由rebuildEpollLocked方法创建:

void Looper::rebuildEpollLocked() {
    // Close old epoll instance if we have one.
    if (mEpollFd >= 0) {
#if DEBUG_CALLBACKS
        ALOGD("%p ~ rebuildEpollLocked - rebuilding epoll set", this);
#endif
        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));
        }
    }
}

rebuildEpollLocked将mWakeEventFd加入到mEpollFd的监听队列中。还有mRequests的文件描述符,但在常用的Message消息处理中并没有使用到,我们在本文档的最后一章使用NetworkStack的例子来进行分析。本章则先跳过。

至此,MessageQueue已经在native层构建好了一个Message驱动的框架。

消息的来源 – enqueueMessage

Message的发送在前面Message和Handler的一章中已经分析过,Message的sendToTarget方法、Handler的post和sendMessage系列方法,都可以发送Message,其最终都是调用到MessageQueue的enqueueMessage方法:

boolean enqueueMessage(Message msg, long when) {
    if (msg.target == null) {
        throw new IllegalArgumentException("Message must have a target.");
    }
    if (msg.isInUse()) {
        throw new IllegalStateException(msg + " This message is already in use.");
    }

    synchronized (this) {
        if (mQuitting) {
            IllegalStateException e = new IllegalStateException(
                    msg.target + " sending message to a Handler on a dead thread");
            Log.w(TAG, e.getMessage(), e);
            msg.recycle();
            return false;
        }

        msg.markInUse();
        msg.when = when;
        Message p = mMessages;
        boolean needWake;
        if (p == null || when == 0 || when < p.when) {
            // New head, wake up the event queue if blocked.
            msg.next = p;
            mMessages = msg;
            needWake = mBlocked;
        } else {
            // Inserted within the middle of the queue.  Usually we don't have to wake
            // up the event queue unless there is a barrier at the head of the queue
            // and the message is the earliest asynchronous message in the queue.
            needWake = mBlocked && p.target == null && msg.isAsynchronous();
            Message prev;
            for (;;) {
                prev = p;
                p = p.next;
                if (p == null || when < p.when) {
                    break;
                }
                if (needWake && p.isAsynchronous()) {
                    needWake = false;
                }
            }
            msg.next = p; // invariant: p == prev.next
            prev.next = msg;
        }

        // We can assume mPtr != 0 because mQuitting is false.
        if (needWake) {
            nativeWake(mPtr);
        }
    }
    return true;
}

MessageQueue对Message的管理使用的是单链表结构,mMessages就是这个链表结构的链表头。从上述代码上看到,enqueueMessage分了两类情况:

1.将Message压入到链表头中。

1).当前的链表已经没有数据(mMessages为null)。

2).enqueue的Message的时间戳为0,表示当前立即处理的消息。

3).enqueue的Message的时间戳比链表头的Message的时间戳更为早(链表中Message的排序是按照时间戳的顺序进行排序,链表头的Message时间戳必定是最早的)。

这种情况下needWake的值为mBlocked,表示如果当前MessageQueue正处于阻塞状态,则需要唤醒以检查是否已有需要处理的Message。

2.为Message排序,将其插入到链表中合适的位置。

这种情况下needWake的值是根据链表中表头Message和当前Message以及插入位置的前一些Message的属性来确定。

1).如果当前queue不是阻塞状态,则无需唤醒queue,needWake为false。

2).如果queue处于阻塞状态,且表头的Message没有Handler。但从Handler的enqueueMessage方法中可以看到,正常使用这是不可能发生的,除非是我们自己修改的。

3).当前的Message是异步的。满足以上3点,则neddWake为true。

4).如果前面三点都符合,needWake的值为true,但再插入Message的过程中,发现插入位置前的Message是异步的,这是由于异步的性质决定的。我们在后面分析一下这个异步会带来什么行为。

经过前面的插入到链表的操作后,如果needWake为true,则调用nativeWake方法,最后调用到native层的Looper对象的wake方法。

void Looper::wake() {
    uint64_t inc = 1;
    ssize_t nWrite = TEMP_FAILURE_RETRY(write(mWakeEventFd.get(), &inc, sizeof(uint64_t)));
}

Looper.wake会往mWakeEventFd文件节点中写入值,以唤醒Looper的epoll。

消息的分发处理

在Java层的Looper.loop分析中,得知Looper分发事件的Message来源是通过MessageQueue.next()方法来获取。

Message next() {
    final long ptr = mPtr;
    int pendingIdleHandlerCount = -1; // -1 only during first iteration
    int nextPollTimeoutMillis = 0;
    for (;;) {
        nativePollOnce(ptr, nextPollTimeoutMillis);

        synchronized (this) {
            // Try to retrieve the next message.  Return if found.
            final long now = SystemClock.uptimeMillis();
            Message prevMsg = null;
            Message msg = mMessages;
            if (msg != null && msg.target == null) {
                // Stalled by a barrier.  Find the next asynchronous message in the queue.
                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.
                    nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
                } else {
                    // Got a message.
                    mBlocked = false;
                    if (prevMsg != null) {
                        prevMsg.next = msg.next;
                    } else {
                        mMessages = msg.next;
                    }
                    msg.next = null;
                    if (DEBUG) Log.v(TAG, "Returning message: " + msg);
                    msg.markInUse();
                    return msg;
                }
            } else {
                // No more messages.
                nextPollTimeoutMillis = -1;
            }

            // 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 {
                keep = idler.queueIdle();
            } catch (Throwable t) {
                Log.wtf(TAG, "IdleHandler threw exception", t);
            }

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

从Looper.loop()方法调用MessageQueue.next()方法时的注释可得知,该方法是一个会进入阻塞状态的方法。next()方法中有两个重要的局部变量 – pendingIdleHandlerCount和nextPollTimeoutMillis。pendingIdleHandlerCount表示当前需要处理的Idlehandler的数量,当MessageQueue中没有需要立即处理分发的Messages,就会执行mIdleHandlers中注册的Idlehandler。nextPollTimeoutMillis表示下一次poll等待的时间,这个是epoll_wait的timeout参数,当值为0时,表示立即返回,不进行阻塞;当值为-1时,表示阻塞到有数据;当值大于0时,表示则是nextPollTimeoutMillis个ms时间。

当next()方法刚进入时,nextPollTimeoutMillis为0,调用nativePollOnce()本地方法(实际上是调用到(native层的Looper.pollOnce()方法)。Looper.pollInner()方法比较长,我们精简出我们要的逻辑代码。

int Looper::pollInner(int timeoutMillis) {
    // Adjust the timeout based on when the next message is due.
    if (timeoutMillis != 0 && mNextMessageUptime != LLONG_MAX) {
        nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
        int messageTimeoutMillis = toMillisecondTimeoutDelay(now, mNextMessageUptime);
        if (messageTimeoutMillis >= 0
                && (timeoutMillis < 0 || messageTimeoutMillis < timeoutMillis)) {
            timeoutMillis = messageTimeoutMillis;
        }
    }

    // Poll.
    int result = POLL_WAKE;
    // We are about to idle.
    mPolling = true;
    struct epoll_event eventItems[EPOLL_MAX_EVENTS];
    int eventCount = epoll_wait(mEpollFd.get(), eventItems, EPOLL_MAX_EVENTS, timeoutMillis);
    // No longer idling.
    mPolling = false;

    // Acquire lock.
    mLock.lock();

    // Handle all events.
    for (int i = 0; i < eventCount; i++) {
        int fd = eventItems[i].data.fd;
        uint32_t epollEvents = eventItems[i].events;
        if (fd == mWakeEventFd.get()) {
            if (epollEvents & EPOLLIN) {
                awoken();
            } else {
                ALOGW("Ignoring unexpected epoll events 0x%x on wake event fd.", epollEvents);
            }
        }
    }
Done: ;
    // Release lock.
    mLock.unlock();
    return result;
}

从Looper.pollInner()方法中提取出以上跟消息的分析有关的逻辑代码。

正常情况下,timeoutMillis为传入参数的值,这个变量的值被传入到epoll_wait中。第一次传入的值为0,表示epoll_wait不会进行阻塞等待数据,只会检查一下是否有数据,会出现两种情况:

1.此时没有数据,eventCount = 0,直接返回。

2.此时有数据,且是mWakeEventFd的数据,则调用awoken()方法。

第二种情况使用于后面阻塞的场景,因此在后面分析。按照第一种情况,nativePollOnce()方法直接返回,我们继续回到next()方法分析。

当nativePollOnce()返回后,next()方法就会去比较当前的时间与Messages链表头的Message的时间戳,如果当前时间已经到了头Message的时间戳,则表明是时候处理这个消息了,处理好链表的删除操作后,将这个Message返回,已供Looper去分发处理。当时间还没到最近一个Message的处理时间,则计算需要等待的时间(如果当前Messages链表中没有消息,则为-1)。

此时next()方法并不是直接进入nativePollOnce()方法去等待,而是去查看一下是否有pending的Idlehandlers需要去处理,Idlehandlers顾名思义,就是在MessageQueue空闲的时候进行处理的事务,当当前没有需要立即处理的消息(Messages链表为null或者当前的Message处理的时间还没到),此时才会去进行处理。而且我们可以看到pendingIdleHandlerCount这个值只有在next()方法的第一次循环时才会小于0.

假设此时MessageQueue空闲,且处理完IdleHandler的事务后,next()方法会再次进行循环,但此时nextPollTimeoutMillis的值会被重新清零,因为此时有可能最近的一次Message已经到时间去处理了。

当nextPollTimeoutMillis的值为非零值时,我们再回到native层的Looper.pollInner()方法中,此时epoll_wait则将会等待超时来处理下一个Message,或者被一个新的更优先处理的Message进来打断去处理(enqueueMessage()方法的分析种有说明)。第一种情况则直接返回,第二种情况则会调用native层的Looper.awoken()方法去清除掉mWakeEventFd的内容。

被打断的情况有可能时立即需要处理的Message,此种情况则立即将该Message返回到Java层的Looper.loop()方法。如果是并非立即处理的Message,则会重新计算nextPollTimeoutMillis的值,再次进入到阻塞状态。

经过Java层的Looper.loop()方法和MessageQueue.next()方法的配合,Message的分发处理就是这样不断地流转。

消息的remove

消息的remove只是一个概括,从前面的Handler和MessageQueue的类图中可以看到有一些对Message的处理 – 判断队列(链表)中是否有什么类型的Messages(hasMessages)和删除一个类型的Messages(removeMessages、removeCallbacksAndMessages等)。甚至包括enqueueMessage,其实都是对单链表的常用操作。我们这里就不再展开分析。

MessageQueue中的IdleHandler

我们在MessageQueue.next()方法中可以看到IdleHandler的使用,但我们还没有以具体的例子来进行分析其作用,因此在这一节中使用ActivityThread的源码来进行分析:

2040:    private class Idler implements MessageQueue.IdleHandler {
2079:    final class GcIdler implements MessageQueue.IdleHandler {
2088:    final class PurgeIdler implements MessageQueue.IdleHandler {

以AndroidQ版本的源码来看,ActivityThread中有三个实现继承了MessageQueue.IdleHandler。我们本节不展开说明这三个IdleHandler的具体作用,只看与MessageQueue相关的操作,我们找比较简单的GcIdle来进行简单分析:

final class GcIdler implements MessageQueue.IdleHandler {
    @Override
    public final boolean queueIdle() {
        doGcIfNeeded();
        purgePendingResources();
        return false;
    }
}
final GcIdler mGcIdler = new GcIdler();
void scheduleGcIdler() {
    if (!mGcIdlerScheduled) {
        mGcIdlerScheduled = true;
        Looper.myQueue().addIdleHandler(mGcIdler);
    }
    mH.removeMessages(H.GC_WHEN_IDLE);
}

void unscheduleGcIdler() {
    if (mGcIdlerScheduled) {
        mGcIdlerScheduled = false;
        Looper.myQueue().removeIdleHandler(mGcIdler);
    }
    mH.removeMessages(H.GC_WHEN_IDLE);
}

在ActivityThread的代码中与GcIdler相关的代码只有上面几行,我们可以看到使用MessageQueue.IdleHandler的步骤主要有下面3步:

1.实现MessageQueue.IdleHandler,重写queueIdle()方法,以实现自己想要的功能。queueIdle()的返回值表示这个Handler是否在被执行后继续保存在MessageQueue中,true表示可不断被执行,false表示只执行一次。

2.在适当的时机将这个IdleHandler实例注册到MessageQueue中,调用MessageQueue.addIdleHandler()方法注册。

3.在适当的时机将这个IdleHandler实例从MessageQueue中注销,调用MessageQueue,removeIdleHandler()方法注销。

设计特点

MessageQueue的核心在这里有两个核心点 : 使用单链表的数据结构管理Message以及使用native层的epoll机制(native层Looper)。这两者的相互配合,使得Message机制得以运行。

native层Looper

MessageQueue.addOnFileDescriptorEventListener

MessageQueue还提供了监听文件节点的功能,我们这一章主要分析一下这个功能的实现方式及其作用,结合NetworkStack的应用场景来看看是怎么使用这个功能的。

在NetworkStack的源码中搜索addOnFileDescriptorEventListener,可以找到只有一处在使用:

// packages/modules/NetworkStack/src/android/net/util/FdEventsReader.java
private void createAndRegisterFd() {
    if (mFd != null) return;

    try {
        mFd = createFd();
    } catch (Exception e) {
        logError("Failed to create socket: ", e);
        closeFd(mFd);
        mFd = null;
    }

    if (mFd == null) return;

    mQueue.addOnFileDescriptorEventListener(
            mFd,
            FD_EVENTS,
            (fd, events) -> {
                // Always call handleInput() so read/recvfrom are given
                // a proper chance to encounter a meaningful errno and
                // perhaps log a useful error message.
                if (!isRunning() || !handleInput()) {
                    unregisterAndDestroyFd();
                    return UNREGISTER_THIS_FD;
                }
                return FD_EVENTS;
            });
    onStart();
}

FdEventsReader是一个抽象类,createFd是一个抽象方法,在这里主要是有两个重点:①调用createFd创建一个文件节点,这个文件节点肯定是一个类似与pipe之类的多端文件通道。②调用MessageQueue.addOnFileDescriptorEventListener注册文件监听器,实现OnFileDescriptorEventListener接口类的onFileDescriptorEvents()方法,这里使用的是lamda表达式。

FdEventsReader有两个实现类,我们以其中一个来看:

// packages/modules/NetworkStack/src/android/net/ip/IpNeighborMonitor.java
@Override
protected FileDescriptor createFd() {
    FileDescriptor fd = null;
    try {
        fd = Os.socket(AF_NETLINK, SOCK_DGRAM | SOCK_NONBLOCK, NETLINK_ROUTE);
        Os.bind(fd, makeNetlinkSocketAddress(0, OsConstants.RTMGRP_NEIGH));
        NetlinkSocket.connectToKernel(fd);

        if (VDBG) {
            final SocketAddress nlAddr = Os.getsockname(fd);
            Log.d(TAG, "bound to sockaddr_nl{" + nlAddr.toString() + "}");
        }
    } catch (ErrnoException|SocketException e) {
        logError("Failed to create rtnetlink socket", e);
        NetworkStackUtils.closeSocketQuietly(fd);
        return null;
    }

    return fd;
}

createFd()方法创建了一个socket,socket大部分人都使用过,这里创建的是Netlink的socket,然后将这个socket fd返回。

我们再看会MessageQueue的addOnFileDescriptorEventListener()方法。

public void addOnFileDescriptorEventListener(@NonNull FileDescriptor fd,
        @OnFileDescriptorEventListener.Events int events,
        @NonNull OnFileDescriptorEventListener listener) {
    synchronized (this) {
        updateOnFileDescriptorEventListenerLocked(fd, events, listener);
    }
}
private void updateOnFileDescriptorEventListenerLocked(FileDescriptor fd, int events,
        OnFileDescriptorEventListener listener) {
    final int fdNum = fd.getInt$();

    int index = -1;
    FileDescriptorRecord record = null;
    if (mFileDescriptorRecords != null) {
        index = mFileDescriptorRecords.indexOfKey(fdNum);
        if (index >= 0) {
            record = mFileDescriptorRecords.valueAt(index);
            if (record != null && record.mEvents == events) {
                return;
            }
        }
    }

    if (events != 0) {
        events |= OnFileDescriptorEventListener.EVENT_ERROR;
        if (record == null) {
            if (mFileDescriptorRecords == null) {
                mFileDescriptorRecords = new SparseArray<FileDescriptorRecord>();
            }
            record = new FileDescriptorRecord(fd, events, listener);
            mFileDescriptorRecords.put(fdNum, record);
        } else {
            record.mListener = listener;
            record.mEvents = events;
            record.mSeq += 1;
        }
        nativeSetFileDescriptorEvents(mPtr, fdNum, events);
    } else if (record != null) {
        record.mEvents = 0;
        mFileDescriptorRecords.removeAt(index);
        nativeSetFileDescriptorEvents(mPtr, fdNum, 0);
    }
}

updateOnFileDescriptorEventListenerLocked()方法有三个传参:①文件描述符fd;②所要监听的事件类型;③监听回调OnFileDescriptorEventListener接口类实现。同时updateOnFileDescriptorEventListenerLocked也是removeOnFileDescriptorEventListener()所调用的方法,add和remove的区别就是监听事件类型,只要监听的事件类型不为0,则表示注册监听事件,为0表示注销监听。

事件的类型分为三类:EVENT_INPUT(输入事件,可读取状态);EVENT_OUTPUT(输出事件,写入状态);EVENT_ERROR(异常状态)。

updateOnFileDescriptorEventListenerLocked的实现比较简单,主要是根据注册/注销操作对mFileDescriptorRecords(内部实现就是两个数组保存keys和values,keys为int类型数据,然后根据keys的索引来找到value)进行管理。然后调用nativeSetFileDescriptorEvents去更新native层的数据:

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, this,
                reinterpret_cast<void*>(events));
    } else {
        mLooper->removeFd(fd);
    }
}

MessageQueue中的文件节点的监听实际上使用的是native层Looper监听文件节点的方式,这个是InputFlinger中InputDispatcher的实现类似,我们这里也步展开分析,只看一下native层Looper除了在Message机制中的作用外监听文件节点的功能。

Looper.addFd和Looper.removeFd

int Looper::addFd(int fd, int ident, int events, Looper_callbackFunc callback, void* data) {
    return addFd(fd, ident, events, callback ? new SimpleLooperCallback(callback) : nullptr, data);
}
int Looper::addFd(int fd, int ident, int events, const sp<LooperCallback>& callback, void* data) {
    if (!callback.get()) {
        if (! mAllowNonCallbacks) {
            ALOGE("Invalid attempt to set NULL callback but not allowed for this looper.");
            return -1;
        }
        if (ident < 0) {
            ALOGE("Invalid attempt to set NULL callback with ident < 0.");
            return -1;
        }
    } else {
        ident = POLL_CALLBACK;
    }

    { // acquire lock
        AutoMutex _l(mLock);
        Request request;
        request.fd = fd;
        request.ident = ident;
        request.events = events;
        request.seq = mNextRequestSeq++;
        request.callback = callback;
        request.data = data;
        if (mNextRequestSeq == -1) mNextRequestSeq = 0; // reserve sequence number -1
        struct epoll_event eventItem;
        request.initEventItem(&eventItem);

        ssize_t requestIndex = mRequests.indexOfKey(fd);
        if (requestIndex < 0) {
            int epollResult = epoll_ctl(mEpollFd.get(), EPOLL_CTL_ADD, fd, &eventItem);
            if (epollResult < 0) {
                ALOGE("Error adding epoll events for fd %d: %s", fd, strerror(errno));
                return -1;
            }
            mRequests.add(fd, request);
        } else {
            int epollResult = epoll_ctl(mEpollFd.get(), EPOLL_CTL_MOD, fd, &eventItem);
            if (epollResult < 0) {
                if (errno == ENOENT) {
                    epollResult = epoll_ctl(mEpollFd.get(), EPOLL_CTL_ADD, fd, &eventItem);
                    if (epollResult < 0) {
                        ALOGE("Error modifying or adding epoll events for fd %d: %s",
                                fd, strerror(errno));
                        return -1;
                    }
                    scheduleEpollRebuildLocked();
                } else {
                    ALOGE("Error modifying epoll events for fd %d: %s", fd, strerror(errno));
                    return -1;
                }
            }
            mRequests.replaceValueAt(requestIndex, request);
        }
    } // release lock
    return 1;
}

addFd和removeFd的代码其实很简单,addFd主要是是将文件描述符fd和NativeMessageQueue实例绑定成Request结构,加入到Looper.mRequests数组中,并将fd添加到epoll的监听队列中去。removeFd则是相反的操作。

Looper.pollInner

我们又回到Looper.pollInner()方法,在这里,epoll_wait监听这我们所注册进来的fd,以下是我们提取出跟Request相关的代码:

int Looper::pollInner(int timeoutMillis) {
    // Poll.
    int result = POLL_WAKE;
    mResponses.clear();
    mResponseIndex = 0;
    // We are about to idle.
    mPolling = true;
    struct epoll_event eventItems[EPOLL_MAX_EVENTS];
    int eventCount = epoll_wait(mEpollFd.get(), eventItems, EPOLL_MAX_EVENTS, timeoutMillis);
    // No longer idling.
    mPolling = false;
    // Acquire lock.
    mLock.lock();
    // Rebuild epoll set if needed.
    if (mEpollRebuildRequired) {
        mEpollRebuildRequired = false;
        rebuildEpollLocked();
        goto Done;
    }
    for (int i = 0; i < eventCount; i++) {
        int fd = eventItems[i].data.fd;
        uint32_t epollEvents = eventItems[i].events;
        if (fd == mWakeEventFd.get()) {
        } else {
            ssize_t requestIndex = mRequests.indexOfKey(fd);
            if (requestIndex >= 0) {
                int events = 0;
                if (epollEvents & EPOLLIN) events |= EVENT_INPUT;
                if (epollEvents & EPOLLOUT) events |= EVENT_OUTPUT;
                if (epollEvents & EPOLLERR) events |= EVENT_ERROR;
                if (epollEvents & EPOLLHUP) events |= EVENT_HANGUP;
                pushResponse(events, mRequests.valueAt(requestIndex));
            } else {
                ALOGW("Ignoring unexpected epoll events 0x%x on fd %d that is "
                        "no longer registered.", epollEvents, fd);
            }
        }
    }
Done: ;
    // Release lock.
    mLock.unlock();
    // Invoke all response callbacks.
    for (size_t i = 0; i < mResponses.size(); i++) {
        Response& response = mResponses.editItemAt(i);
        if (response.request.ident == POLL_CALLBACK) {
            int fd = response.request.fd;
            int events = response.events;
            void* data = response.request.data;
            int callbackResult = response.request.callback->handleEvent(fd, events, data);
            if (callbackResult == 0) {
                removeFd(fd, response.request.seq);
            }
            response.request.callback.clear();
            result = POLL_CALLBACK;
        }
    }
    return result;
}

当监听到注册的fd发生事件,则先将这些事件封装成Respone数据,然后在pollInner的结束时去调用callback(NativeMessageQueue)的handleEvent方法回调,如果handleEvent的返回值为0,则注销这个监听。

MessageQueue.dispatchEvents

int NativeMessageQueue::handleEvent(int fd, int looperEvents, void* data) {
    int events = 0;
    if (looperEvents & Looper::EVENT_INPUT) {
        events |= CALLBACK_EVENT_INPUT;
    }
    if (looperEvents & Looper::EVENT_OUTPUT) {
        events |= CALLBACK_EVENT_OUTPUT;
    }
    if (looperEvents & (Looper::EVENT_ERROR | Looper::EVENT_HANGUP | Looper::EVENT_INVALID)) {
        events |= CALLBACK_EVENT_ERROR;
    }
    int oldWatchedEvents = reinterpret_cast<intptr_t>(data);
    int newWatchedEvents = mPollEnv->CallIntMethod(mPollObj,
            gMessageQueueClassInfo.dispatchEvents, fd, events);
    if (!newWatchedEvents) {
        return 0; // unregister the fd
    }
    if (newWatchedEvents != oldWatchedEvents) {
        setFileDescriptorEvents(fd, newWatchedEvents);
    }
    return 1;
}

NativeMessageQueue.handleEvent()方法将Looper传过来的事件类型转换成MessageQueue这边的events,并调用Java层MessageQueue的dispatchEvents()方法来回调用户注册的回调方法,并根据其返回的继续监听的事件类型来进行判断,如果新的监听事件为0,表示不需要继续监听,则将这个监听注销,返回0。如果新的监听事件与旧的监听事件不同,则更新监听事件。

// Called from native code.
@UnsupportedAppUsage
private int dispatchEvents(int fd, int events) {
    // Get the file descriptor record and any state that might change.
    final FileDescriptorRecord record;
    final int oldWatchedEvents;
    final OnFileDescriptorEventListener listener;
    final int seq;
    synchronized (this) {
        record = mFileDescriptorRecords.get(fd);
        if (record == null) {
            return 0; // spurious, no listener registered
        }

        oldWatchedEvents = record.mEvents;
        events &= oldWatchedEvents; // filter events based on current watched set
        if (events == 0) {
            return oldWatchedEvents; // spurious, watched events changed
        }

        listener = record.mListener;
        seq = record.mSeq;
    }

    // Invoke the listener outside of the lock.
    int newWatchedEvents = listener.onFileDescriptorEvents(
            record.mDescriptor, events);
    if (newWatchedEvents != 0) {
        newWatchedEvents |= OnFileDescriptorEventListener.EVENT_ERROR;
    }

    // Update the file descriptor record if the listener changed the set of
    // events to watch and the listener itself hasn't been updated since.
    if (newWatchedEvents != oldWatchedEvents) {
        synchronized (this) {
            int index = mFileDescriptorRecords.indexOfKey(fd);
            if (index >= 0 && mFileDescriptorRecords.valueAt(index) == record
                    && record.mSeq == seq) {
                record.mEvents = newWatchedEvents;
                if (newWatchedEvents == 0) {
                    mFileDescriptorRecords.removeAt(index);
                }
            }
        }
    }

    // Return the new set of events to watch for native code to take care of.
    return newWatchedEvents;
}

MessageQueue.dispatchEvents的核心就是根据fd找到对应的listener对象,调用其onFileDescriptorEvents()方法去处理这个事件,并根据其返回的继续需要监听的事件做与NativeMessageQueue.handleEvent类似的操作。回顾NetworkStack的FdEventsReader的addOnFileDescriptorEventListener的代码,可以知道,其主要作用就是利用Android的native层的Looper来实现对Linux内核的netlink socket的监听。类似的还有InputFlinger的InputDispatcher的对应用的InputChannel的回调监听。

总结

android 中的 Messenger_ide_05

以上是Android Message机制个人理解的框图,总结如下:

1.每个线程Thread最多只有一个Looper和MessageQueue实例,一个进程可以有多个Looper和MessageQueue实例,可以参考SystemServer。

2.每个Looper和MessageQueue实例是一一对应的,Looper是线程的主体,线程的最终执行代码将是Looper的不断循环执行,MessageQueue是消息的容器,也是Looper种不断执行的指令来源。

3.MessageQueue中的重要数据元素就是Message,MessageQueue中组织Message的容器使用的是单链表。链表中Message在入链表时会进行排序,其排序时根据处理时间的顺序,也就是说链表头的Message会最先被处理。

4.Message和Handler的实例在一个线程中并不是唯一的,但两种是互相绑定的,Message中必然会有一个与其相关的Handler实例,这个Handler实例是分发Message的中介,同时也可以是Message的处理句柄,用于处理Message。但Message并不一定要交由Handler来处理,Message可以设置自己的Callback(Runnable),执行Runnable的内容。

5.Message是实现使用了缓存池的机制,主要是为了减少Java层创建对象的开销。Message是Android java层常用的类型,一个进程运行的过程可能会使用非常多的Message,如果每个Message都重新创建,会加大cpu的开销(创建需要消耗cpu,同样的,销毁执行gc也是需要消耗cpu的)。

6.MessageQueue.next()方法是一个阻塞的方法,Looper.loop()方法就是通过阻塞来进入休眠,而这个阻塞是MessageQueue的JNI层调用native层Looper实现的,native层Looper使用的是epoll机制进行监听和阻塞。

问题

1.在知乎上看到有人问,Android 中为什么需要Handler?

我认为Handler的说法并不准确,应该说的是Android为什么需要Message机制,Handler只是Message机制中的处理方式,或者说是处理消息的一种手段的具体实现,而实际上核心的东西是整套机制的协调使用。

Android中为什么需要Message机制呢?我认为主要是因为Android的设计框架很多都是基于C/S结构的,进程间、进程内线程间,很多都可以看作是C/S的架构,如SystemServer、AndroidO之后的hal层服务以及应用的UI刷新,这些都可以看作是C/S架构。那么Android中进程间的C/S架构的通信机制设计有了Binder(HwBinder等),那么线程间的通信机制呢?因为线程间是处于同一个资源集合中,无需使用Binder这种经过内核态的通信机制,而消息机制就很适合这种场景,其有控制简单,串行(消息都是通过一个线程处理)的特点,十分适合线程间通信的。

知乎上有人就Android应用的场景展开说明,谈到UI更新的使用,看似十分有理,但这仅仅只是Message机制的一个应用场景,从源码上看,一个进程并不是只能有一个Looper的存在,而是可以有多个Looper的,UI线程都是在主线程种,但是Looper并不需要一定在主线程种,而且较为新的版本种,Message机制并不仅仅可以作为消息传递,还能监听一个文件节点(socket,驱动节点等),站在系统的层面上看,Android系统是一个集中处理数据的大型软件,数据的处理离不开消息的驱动,那么必然需要一种消息机制来进行驱动,消息的机制驱动又可以分别进程间和线程间的。进程间已有binder这一高效的通信机制,那么线程间也必然需要设计一款高效的通信机制,Message机制也就应运而生(其实很多系统都会有类似的机制)。

2.MessageQueue.next()方法中,调用nativePollOnce()的作用是什么?特别是第一次循环时的作用。

nativePollOnce是进入线程阻塞的核心方法,其底层是基于epoll机制。但第一次循环时epoll的timeout为0,表示进行阻塞,只读取事件,我认为作用用二:①清除过时的wake事件;②处理监听的文件节点事件。