Android Message机制

article/2025/11/3 11:12:00

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.javapublic 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 blockif (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 loggerfinal 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的类图:

Message类图

​ 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 flagsPoolSize--;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的类图如下:

Handler类图

​ 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() {@Overridepublic 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) {@Overridepublic 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的类图:

MessageQueue类图

​ 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以及相关类的类图:

NativeMessageQueue类图

​ 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_CALLBACKSALOGD("%p ~ rebuildEpollLocked - rebuilding epoll set", this);
#endifmEpollFd.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 unioneventItem.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.nextprev.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 iterationint 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 handlerboolean 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 {@Overridepublic 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 lockAutoMutex _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 -1struct 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 lockreturn 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 setif (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的回调监听。

总结

Message机制框图

​ 以上是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事件;②处理监听的文件节点事件。


http://chatgpt.dhexx.cn/article/AD7wpbD3.shtml

相关文章

Windows 消息循环 GetMessage() PeekMessage()

GetMessage()函数的消息循环的汇编代码.while TRUEinvoke GetMessage,addr stMsg,NULL,0,0.break .if eax 0invoke TranslateMessage,addr stMsginvoke DispatchMessage,addr stMsg.endwret解读&#xff1a; 调用 GetMessage 函数,函数中都要用到一个MSG结构体&#xff0c;那是…

WindowsMessage

消息介绍 Windows是一个消息&#xff08;Message&#xff09;驱动系统&#xff0c;它不是由事件的顺序来控制&#xff0c;而是由事件的发生来控制&#xff0c;而这种事件的发生是随机的、不确定的&#xff0c;并没有预定的顺序&#xff0c;这样就允许程序的用户用各种合理的顺序…

从内核层说清GetMessage , DispatchMessage

文章目录 要点回顾&#xff1a;为什么拿到句柄非得要回零环&#xff1f;消息队列&#xff08;总共有7个小队列&#xff09;结构GetMessage的声明&#xff1a;GetMessage进入内核&#xff1a;GetMessage的功能总结&#xff1a;DispatchMessage举例验证&#xff08;有前提情况&am…

Message的消息池(sPool)

关键总结 1、消息池缓存有可重复使用的消息实例&#xff0c;避免过多的创建与回收消息实例 2、消息池是一个栈&#xff08;LIFO/FILO后进先出/先进后出&#xff09;的数据结构&#xff0c;具体的数据存放是采用了链表方式 3、消息池一开始是空的&#xff0c;需要主动添加消息进…

信息炸弹——Message Boom

前言 好的今天我们来讨论一下什么叫信息炸弹。 可能之前看过我文章的小伙伴们在想&#xff0c;这种听名字就具有攻击性的东西为什么不把它放到黑客七宗罪专栏里&#xff1f; 毕竟这只是个脚本&#xff0c;对于个人账号的攻击性确实强&#xff0c;聊天记录也会占用硬盘。但是…

handler+message【消息机制】

&#x1f356;&#x1f356; 作者 &#xff1a; 不良使 &#x1f356;&#x1f356;&#x1f356;&#x1f356; 潜力创作新星 华为云享专家 &#x1f356;&#x1f356;&#x1f356;&#x1f356;&#x1f356; PythonAndroid &#x1f356;&#x1f356;&#x1f356;&#…

c++中MessageBox弹窗的用法大全

想必大家都知道&#xff0c;MessageBox函数是c语言中很常用且好玩的函数之一&#xff0c;那你知道它怎么用吗&#xff1f; 这是MessageBox函数的标准格式之一&#xff0c;本人喜欢用这种格式&#xff0c;注意函数的大小写&#xff01; MessageBox不在 #include<bits/stdc.h&…

message broker

MB概述 MB的全称是message broker&#xff0c;即“消息代理”。“消息”一词前几年比较火&#xff0c;消息中间件也卖的很火&#xff0c;当时似乎J2EE的产品都要跟“消息”、“中间件”扯上点关系&#xff0c;以彰显潮流。我觉得初学者只需记住“消息”的异步性即可&#xff0c…

MP3音频文件格式(MPEG-1 audio layer 3)

MP3音频文件格式 【百度百科】mp3 &#xff08;一种音频编码方式&#xff09; 【维基百科】MP3&#xff08;本文重定向自 MPEG-1 Audio Layer 3&#xff09; MP3(MPEG-1 audio layer 3) MPEG-1音频分三层&#xff0c;分别为 MPEG-1 Layer1&#xff0c;MPEG-1 Layer2 以及 MPE…

怎么把wav文件改成mp3?

怎么把wav文件改成mp3&#xff1f;有过摄像摄影经历的小伙伴都应该认识wav&#xff0c;wav就是他们作品的保存格式。因为wav格式的文件体积特别大&#xff0c;在储存的时候会占用我们大量的内存&#xff0c;而且为了播放方便&#xff0c;我们通常要把wav文件改成mp3格式的&…

音频文件如何转成mp3格式

当提到音频文件格式时&#xff0c;大家往往会想到最为流行和广泛使用的mp3格式。mp3是一种广受欢迎的音频格式&#xff0c;因为各种音频格式自身特点的原因&#xff0c;所以将其他格式的音频文件转换成mp3是非常普遍的需求。就比如在我们日常生活中&#xff0c;下载到的各种格式…

如何转换音频格式为mp3?

一提到音乐&#xff0c;大家先想到的应该就是MP3了&#xff0c;既然MP3作为常用的&#xff0c;被大家所熟知的一种音频格式&#xff0c;那它必定有其他格式无可比拟的优点。其实mp3从功能上来讲它具有更强的携带性和传输性&#xff0c;利于保存和分享&#xff1b;其次MP3本身的…

电脑音频转换mp3格式怎么弄,教你音频怎么转换mp3格式

mp3格式是目前几乎全兼容的格式了&#xff0c;在我们参加一些会议或讲座时&#xff0c;需要录制一些重要的信息&#xff0c;结束后再进行复盘或分享。然而&#xff0c;不同的录制工具录制的音频格式也不同&#xff0c;这时使用软件将音频统一成mp3格式的话&#xff0c;就会方便…

免费在线MP3转换器:将音乐文件转换为MP3格式

在今天的数字时代&#xff0c;音乐成为了人们生活中不可或缺的一部分。然而&#xff0c;由于音乐文件格式的不同&#xff0c;我们有时可能无法在不同的设备上播放我们最喜爱的歌曲。MP3格式作为最常用的音乐文件格式之一&#xff0c;通常可以被几乎所有的设备支持&#xff0c;因…

mp3格式怎么弄?分享三个音频文件格式转换的方法

不知道小伙伴们有没有遇到过这样的情况&#xff0c;在网上下载一首歌下来&#xff0c;正想打开&#xff0c;结果却发现我们的播放器无法播放。你们知道这是为什么嘛&#xff0c;其实我们的音频文件是有很多不同的格式&#xff0c;其中就有些比较少见的格式&#xff0c;我们的音…

如何从MP4视频文件中抽取MP3音频?

简 介&#xff1a; 为了能够处理视频中的音频&#xff0c;测试了两种提取视频中的音频方法。一种是利用格式工程软件另外一种利用ffmpeg软件。 关键词&#xff1a; 视频文件&#xff0c;音频文件&#xff0c;mp4&#xff0c;mp3 #mermaid-svg-sPs0isryqtLTjZyg {font-family:&q…

如何将音频文件转换为MP3格式?

音频文件有很多种格式&#xff0c;如 WAV、FLAC、AAC 等&#xff0c;其中 MP3 是最为常见的一种格式&#xff0c;因为它具有压缩比高、音质损失少、兼容性强等优点&#xff0c;适合在各种设备上播放。如果你想将一个音频文件转换为 MP3 格式&#xff0c;可以采用以下几种方法&a…

Next() Nextline() hasNext()区别

next类和hasNext方法遇到缓冲区没数据时&#xff0c;会阻塞&#xff0c;等待输入后next类会读取&#xff0c;hasNext会返回true 1&#xff09;nextLine nextLine&#xff08;&#xff09;方法返回的是"\n"之前的所有字符&#xff0c;它是可以得到带空格的字符串的。 …

BNext

又搬来了大神器啊 来自德国HassoPlattner计算机系统工程研究院的NianhuiGuo和HaojinYang等研究者提出了BNext模型&#xff0c;成为第一个在ImageNet数据集上top1分类准确率突破80%的BNN。 两年前&#xff0c;依靠早期 BNN 工作 XNOR-Net 起家的 XNOR.AI 被苹果公司收购&#…

Next.js学习笔记

这是一个用于生产环境的React 框架&#xff0c;Next.js 为您提供生产环境所需的所有功能以及最佳的开发体验&#xff1a;包括静态及服务器端融合渲染、 支持 TypeScript、智能化打包、 路由预取等功能 无需任何配置。 create-next-app 使用 create-next-app创建新的 Next.js …