Handler
Handler
Java层Looper对象绑定线程方法:在Java层,线程通过Looper.Prepare()方法创建looper对象,并将该对象存到线程局部空间中,下次访问时通过Looper.myLooper()获得该线程的Looper对象,其技术细节为Looper内有一个静态ThreadLocal类型遍历sThreadLocal,该变量任何线程都能访问,但是要做到不同线程通过它获取的值不一样的方法,就是线程关联的Java Thread对象内含有ThreadLocalMap的map,则可以将Looper内的静态成员sThreadLocal作为key,创建的Looper对象作为value存到该map中,这样不同的线程就可以访问Looper的sThreadLocal就可以在自己的ThreadLocalMap中得到对应的Looper对象。
Java层Looper结构:Looper对象含有MessageQueue的mQueues成员和其绑定的Thead类型mThead成员,MessageQueue中含有Message链表,mMessages成员总是指向下一个待处理消息mQueue。同时MessageQueue也是联系java层的Looper机制与native层的Looper机制的关键。MessageQueue的成员mPtr指向的为native层的NativeMessageQueue,当java层的MessageQueue创建的时候会创建native层的NativeMessageQueue,而native层looper机制的类结构和java层不一样,native 层的NativeMessageQueue含有Looper类型成员mLooper,所有功能都是mLooper完成,NativeMessageQueue只是作为与Java层沟通的桥梁。
Native层Looper对象绑定线程方法:native层Looper与线程的绑定是调用Linux函数实现的,实现思路与java层相似,也是通过一个pthread_key_t类型公共变量 gTLSKey,gTLSKey所有线程都能访问,通过pthread_setspecific 方法,以gTLSKey为key,新创建的Looper对象为Value存在线程的局部空间中,访问的时候通过pthread_getspecific (gTLSKey)获得该Looper对象。为了向开发者屏蔽调这些linux函数,安卓 native层使用Looper::setForThread(const sp& looper) 访问gTLSKey,并将其作为key,looper对象作为value存在线程局部空间中。通过Looper::getForThread访问该looper对象。
Native层Looper结构:NativeMessageQueue含有Looper类型成员mLooper,mLooper含有处理fd事件的mRequests成员、mResponses成员和处理Handler发来的消息的mMessageEnvelopes成员。
-
mRequests是一个map,key为seq,Map为Request对象。seq为序列号,用来标识注册的fd。当在Looper中注册监听的fd时,通过向epoll_wait方法中填入待监听的fd和epoll_event。epoll_event的events成员指定了要监听fd的什么事件,这里一般是监听fd中有数据到来事件,而epoll_event的data成员是一个枚举类型,Looper中是指定其u64成员,存储Looper产生的序列号seq。当有事件到来时,该epoll_event结构体就会原封不动的返回。获得epoll_event后,通过读取data.u64字段就可以指定seq,
struct epoll_event { __uint32_t events; /* 设置时表示事件掩码,指明了需要监听的事件种类 epoll返回时,表示获取到的事件*/ epoll_data_t data; /* 使用者自定义的数据,当此事件发生时该数据将原封不动地返回给使用者 */ }; typedef union epoll_data { void*ptr; int fd; __uint32_t u32; __uint64_t u64; } epoll_data_t;
那么我们怎么知道该事件是对应哪个fd呢?Looper在注册监听fd的时候会构建Request对象,Request对象中保存了fd、events、data、callback等值,这里的data一般填入的值就是上面所说的seq,
struct Request { int fd; int ident; int events; sp<LooperCallback> callback; void* data; uint32_t getEpollEvents() const; };
callback表示fd事件到来时的处理函数式接口。其只有handleEvent一个方法。
/** * A looper callback. */ class LooperCallback : public virtual RefBase { protected: virtual ~LooperCallback(); public: /** * Handles a poll event for the given file descriptor. * It is given the file descriptor it is associated with, * a bitmask of the poll events that were triggered (typically EVENT_INPUT), * and the data pointer that was originally supplied. * * Implementations should return 1 to continue receiving callbacks, or 0 * to have this file descriptor and callback unregistered from the looper. */ virtual int handleEvent(int fd, int events, void* data) = 0; };
而ident表示signal identifier,信号标识符。在我看来是用来表示事件的处理类型。当该fd的事件到来时,如果ident为POLL_CALLBACK(-2)则表示使用callback处理,否则ident的值一定大于0,表示将到来的fd事件返回给调用者(pollOnce),这个具体处理看下面。一个Request对象就表示一个注册的监听fd,Looper使用mRequests成员来存储这些Request对象。
mResponses是一个Response对象集合。当fd事件来时,epoll_wait返回epoll_event结构,再从epoll_event结构的data.u64获得seq,通过seq便可以从mRequests获得对应的Request。然后将seq、events和Request包装成为一个Response对象。将其加入mResponses集合中。后序会遍历该集合,取出Response,通过其request成员的ident决定是调用request.callback处理,还是将还是将fd、events、seq返回给调用者(pollOnce的返回值)。
mResponses在下一次pollOnce时处理ident大于0的情况,然后在后面的pollinner中清空mResponses。
struct Response { SequenceNumber seq; int events; Request request; }; using SequenceNumber = uint64_t;
注册fd用Looper的addFd方法
-
mMessageEnvelopes是一个MessageEnvelope类型的集合,集合中元素按照到来时间从小到大排列。MessageEnvelope中含有handler和message,native的handler是MessageHandler类型,不像在java层是Handler类型。在pollInner中当epoll_wait返回构建好了Response后第一个处理的就是mMessageEnvelopes,然后再是mResponses。遍历mMessageEnvelopes,取出MessageEnvelop然后获得
struct MessageEnvelope { MessageEnvelope() : uptime(0) { } MessageEnvelope(nsecs_t u, sp<MessageHandler> h, const Message& m) : uptime(u), handler(std::move(h)), message(m) {} nsecs_t uptime; //发送时间,uptime clock sp<MessageHandler> handler; Message message; };
法消息为sendMessage
循环过程:Java层Looper创建后调用它的loop()方法开启消息循环,looper()方法
looper(){
....
final Looper me = myLooper();
me.mInLoop = true;
final long ident = Binder.clearCallingIdentity();
for (;;) {
//死循环,除非调用了quit方法
if (!loopOnce(me, ident, thresholdOverride)) {
return;
}
}
}
loopOnce返回true表示还想要循环,否则退出循环,当调用Looper的quit方法时,就会导致loopOnce返回True并退出循环。
* Poll and deliver single message, return true if the outer loop should continue.
*/
@SuppressWarnings("AndroidFrameworkBinderIdentity")
private static boolean loopOnce(final Looper me,
final long ident, final int thresholdOverride) {
Message msg = me.mQueue.next(); // might block
……
try {
msg.target.dispatchMessage(msg);
} finally {
……
}
……
msg.recycleUnchecked();
}
loopOnce处理三斧头:取消息、分发消息、回收消息。同时Looper会监测消息执行时间,过长会打印日志,这个暂且不表。
-
取消息
MessageQueue的next方法首先调用nativePollOnce;处理native层的消息。nativePollOnce就是调用NativeMessageQueue的pollOnce方法,其调用mLooper->pollOnce(timeoutMillis);。最终实现都是Looper的pollOnce方法,pollOnce会调用epoll_wait等待消息,填入的timeoutMillis表示等待时间,为0表示不等待,为负表示一直等待直到有事件到来。当Java层的Handler的sendMessage时,会使得native层epoll_wait返回,从而nativePollOnce返回,从而让现场回到java层,从MessageQueue中取的消息,然后调用handler的
-
分发消息
handler的dispatchMessage方法
/** * Handle system messages here. */ public void dispatchMessage(@NonNull Message msg) { if (msg.callback != null) { handleCallback(msg); } else { if (mCallback != null) { if (mCallback.handleMessage(msg)) { return; } } handleMessage(msg); } }
先处理Message中自带的callback
-
回收消息
msg.recycleUnchecked();
线程绑定该Looper对象,并不意味着其它线程不能访问,其它线程也是可以访问的,只不过将线程绑定Looper,访问起来要方便一点而已。
上面其实说的是Java层的Looper,因为java层Looper必然会创建关联的native层Looper。或者java层的Looper离不开native层的Looper,本质上是离不开epoll_wait实现的休眠和唤醒机制。
而Native层的Looper却可以离开java层的Looper。可以完成创建Native层的Looper,不需要创建java层Looper已经Native层的NativeMessageQueue(其只是与Java层沟通的桥梁,既然不需要创建Java层Looper,那么也不需要它)。Native层的Looper也可以不用将其保存在线程的局部空间,只要一个线程在循环中不断调用它的pollOnce方法则就会休眠在它上面,当其它线程调用该looper对象的wake方法,wake方法就会想mWakeFd发送数据,则监听的epoll_wait就会返回,休眠在它上面的线程就会醒来。
—具体分析—————
先看官方介绍:
A Handler allows you to send and process Messageand Runnable objects associated with a thread's
MessageQueue`
There are two main uses for a Handler: (1) to schedule messages and runnables to be executed at some point in the future; and (2) to enqueue an action to be performed on a different thread than your own.
Scheduling messages is accomplished with the post(Runnable), postAtTime(java.lang.Runnable, long), [postDelayed(Runnable, Object, long)] (https://developer.android.google.cn/reference/android/os/Handler#postDelayed(java.lang.Runnable,%20java.lang.Object,%20long)), sendEmptyMessage(int),
sendMessage(Message),
sendMessageAtTime(Message, long), and
sendMessageDelayed(Message, long). methods. The post versions allow you to enqueue Runnable objects to be called by the message queue when they are received; the sendMessage versions allow you to enqueue a Messageobject containing a bundle of data that will be processed by the Handler's
handleMessage(Message)` method (requiring that you implement a subclass of Handler)
再上一张框架图。
java层一个线程只能绑定一个looper,而native层如果是监听文件,不用发消息的话好像不用绑定,直接new 一个looper 然后,在looper的pollOnce中调用epoll_wai
最后开始Looper之旅:创建—注册—取消息—处理消息—回收消息。
1 looper创建
1.1 java层looper创建
Looper.prepare()
/** Initialize the current thread as a looper.
* This gives you a chance to create handlers that then reference
* this looper, before actually starting the loop. Be sure to call
* {@link #loop()} after calling this method, and end it by calling
* {@link #quit()}.
*/
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));
}
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
sThreadLocal是Looper类的ThreadLocal类型静态变量
ThreadLocal
ThreadLocal并不是真的将变量隐藏在线程内部,而是通过一个公有变量,这个变量任何线程都能访问,但是不同线程访问出来的值不一样,这个变量就是ThreadLocal。
ThreadLocal<Integer> local=new TheadLocal<Integer>(); //Interger代表value类型,这是泛型
当A线程执行下面的代码
local.set(100);
当B线程执行下面的代码
local.set(200)
则当A和B分别执行下面的代码的时候值不一样
local.get() //A线程执行得100,B线程执行得200
那么这种是怎么实现的呢,
当A线程调用local.set(100)时,ThreadLocal将自己作为key,传进来的100作为value存到线程关联的Java类Thread的ThreadLocalMap类成员threadLocals中,如果不存在ThreadLocal会创建该成员(通过createMap)方法。可参照上图深入理解。
/**
* Sets the current thread's copy of this thread-local variable
* to the specified value. Most subclasses will have no need to
* override this method, relying solely on the {@link #initialValue}
* method to set the values of thread-locals.
*
* @param value the value to be stored in the current thread's copy of
* this thread-local.
*/
public void set(T value) {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
}
/**
* Create the map associated with a ThreadLocal. Overridden in
* InheritableThreadLocal.
*
* @param t the current thread
* @param firstValue value for the initial entry of the map
*/
void createMap(Thread t, T firstValue) {
t.threadLocals = new ThreadLocalMap(this, firstValue);
}
回到Looper。sThreadLocal 是Looper类的静态成员变量,其关联的值类型为Looper
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
调用sThreadLocal 的set(new Looper(quitAllowed))方法将该sThreadLocal为key,新创建的looper对象为value存到线程的Thread的ThreadLocalMap中。下次要访问该Looper对象,只要通过Looper类就行,因为通过Looper类就访问到了静态成员sThreadLocal,通过该ThreadLocal对象就访问到了线程中该key对应value,即looper对象(调用ThreadLocal.get())方法。
通过Looper类访问Looper对象的方式:
final Looper me = myLooper();
看一下Looper对象的构造函数,其创建了MessageQueue和保存了线程的java Thread对象。
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
MessageQueue的创建,就会创建native层的MessageQueue
MessageQueue(boolean quitAllowed) {
mQuitAllowed = quitAllowed;
mPtr = nativeInit(); //mptr执行native层的MessageQueue
}
1.2 native层的MessageQueue创建
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);
}
NativeMessageQueue::NativeMessageQueue() :
mPollEnv(NULL), mPollObj(NULL), mExceptionObj(NULL) {
mLooper = Looper::getForThread();
if (mLooper == NULL) {
mLooper = new Looper(false);
Looper::setForThread(mLooper);
}
}
native层的Looper和java层Looper一点关系也没有,这里刚刚创建NativeMessageQueue时,显然还不存在looper,因此走下面的new looper流程,这里说一下native层“threadLocal”,线程独立的实现方法。
native “ThreadLocal”
native层实现方法与java层的ThreadLocal类似,或者说java层的ThreadLocal是参照了native层,因此这个是linux的函数。
int pthread_key_create (pthread_key_t *key, void (*destructor)(void *));
// Returns 0 on success, or a positive error number on error
int pthread_key_delete (pthread_key_t key);
// Returns 0 on success, or a positive error number on error
int pthread_setspecific (pthread_key_t key, const void *value);
// Returns pointer, or NULL if no thread-specific data is associated with key
void *pthread_getspecific (pthread_key_t key);
pthread_key_create为线程创建一个key,该key其它线程也可以使用,因此常设为全局变量。
pthread_key_delete 则在线程中删除该key,而pthread_setspecific 和pthread_getspecific 分别用于设置或者获取key对应的value。
回到Native层的Looper,其调用pthread_setspecific设置gTLSKey对应的value,这里的value指定为刚刚创建的looper,
static pthread_key_t gTLSKey = 0;
void Looper::setForThread(const sp<Looper>& looper) {
sp<Looper> old = getForThread(); // also has side-effect of initializing TLS
if (looper != nullptr) {
looper->incStrong((void*)threadDestructor);
}
pthread_setspecific(gTLSKey, looper.get());
if (old != nullptr) {
old->decStrong((void*)threadDestructor);
}
}
sp<Looper> Looper::getForThread() {
int result = pthread_once(& gTLSOnce, initTLSKey);
LOG_ALWAYS_FATAL_IF(result != 0, "pthread_once failed");
//这里-------
return (Looper*)pthread_getspecific(gTLSKey);
}
因此native层的“ThreadLocal”就是pthread_key_t 。
因此通过Looper类就可获取线程对应的Looper对象,因为通过Looper类能够访问pthread_key_t ,通过该key便可以从线程中读取对应的value,即Looper对象。这样就将线程和Looper对象绑定起来。
通过Looper类访问looper对象的方式:
Looper::getForThread()
native looper
mLooper = new Looper(false);
Looper::Looper(bool allowNonCallbacks)
: mAllowNonCallbacks(allowNonCallbacks),
mSendingMessage(false),
mPolling(false),
mEpollRebuildRequired(false),
mNextRequestSeq(WAKE_EVENT_FD_SEQ + 1),
mResponseIndex(0),
mNextMessageUptime(LLONG_MAX) {
mWakeEventFd.reset(eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC)); //构造唤醒事件的fd
LOG_ALWAYS_FATAL_IF(mWakeEventFd.get() < 0, "Could not make wake event fd: %s", strerror(errno));
AutoMutex _l(mLock);
rebuildEpollLocked();重建Epoll事件
}
Epoll创建以及监听
创建Looper时,会做以下事情:
- 通过eventfd创建mWakeEventFd用于线程间通信去唤醒Looper的,当需要唤醒Looper时,就往里面写1
- 创建用于监听epoll_event的mEpollFd,并初始化mEpollFd要监听的epoll_event类型
- 通过epoll_ctl将mWakeEventFd注册到mEpollFd中,当mWakeEventFd有事件可读则唤醒Looper
- 如果mRequests不为空的话,说明前面注册了有要监听的fd,则遍历mRequests中的Request,将它初始化为epoll_event并通过epoll_ctl注册到mEpollFd中,当有可读事件同样唤醒Looper
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 WakeEventFd.
mEpollFd.reset(epoll_create1(EPOLL_CLOEXEC));
LOG_ALWAYS_FATAL_IF(mEpollFd < 0, "Could not create epoll instance: %s", strerror(errno));
epoll_event wakeEvent = createEpollEvent(EPOLLIN, WAKE_EVENT_FD_SEQ);
//加入epoll 监听
int result = epoll_ctl(mEpollFd.get(), EPOLL_CTL_ADD, mWakeEventFd.get(), &wakeEvent);
LOG_ALWAYS_FATAL_IF(result != 0, "Could not add wake event fd to epoll instance: %s",
strerror(errno));
for (const auto& [seq, request] : mRequests) {
epoll_event eventItem = createEpollEvent(request.getEpollEvents(), seq);
//加入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));
}
}
}
2 Looper启动启动
Looper.loop()
/**
* Run the message queue in this thread. Be sure to call
* {@link #quit()} to end the loop.
*/
@SuppressWarnings("AndroidFrameworkBinderIdentity")
public static void loop() {
final Looper me = myLooper();
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
if (me.mInLoop) {
Slog.w(TAG, "Loop again would have the queued messages be executed"
+ " before this one completed.");
}
me.mInLoop = true;
// 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);
me.mSlowDeliveryDetected = false;
for (;;) {
//死循环,除非调用了quit方法
if (!loopOnce(me, ident, thresholdOverride)) {
return;
}
}
}
/**
* Poll and deliver single message, return true if the outer loop should continue.
*/
@SuppressWarnings("AndroidFrameworkBinderIdentity")
private static boolean loopOnce(final Looper me,
final long ident, final int thresholdOverride) {
Message msg = me.mQueue.next(); // might block
if (msg == null) {
// No message indicates that the message queue is quitting.
return false;
}
// 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;
}
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 (me.mSlowDeliveryDetected) {
if ((dispatchStart - msg.when) <= 10) {
Slog.w(TAG, "Drained");
me.mSlowDeliveryDetected = false;
}
} else {
if (showSlowLog(slowDeliveryThresholdMs, msg.when, dispatchStart, "delivery",
msg)) {
// Once we write a slow delivery log, suppress until the queue drains.
me.mSlowDeliveryDetected = 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();
return true;
}
总结一下就是下面的结构,取出消息,分发消息,回收消息。
public static void loop() {
……
for (;;) {
Message msg = queue.next(); // might block
……
try {
msg.target.dispatchMessage(msg);
} finally {
……
}
……
msg.recycleUnchecked();
}
}
3. 注册(发消息)
3.1 native层注册
- 文件注册
looper对象的addFd方法
events指定了要监听上面事件,是fd中有数据时的事件还是其它,events与epoll_event的events一一对应。构建epoll_event,其中epool_event的events为该events转化过的events,epoll_event的data为联合类型,这里指定了其中的u64字段存储seq,Looper为每一个fd创建一个唯一seq。当事件到来时,从返回的epoll_event中的data.u64就可以获取seq值,再从looper的mSequenceNumberByFd成员就可指定对应的fd。
同时,为每一个注册的fd构建一个Request对象,存储在mRequests中。其ident也标识了该fd,当fd指定了callback时,ident为负数POLL_CALLBACK(-2),ident 表示singal indentifier,信号标识符。用于标识到来的事件
当事件来的时候,从seq获得Request对象,然后通过Request对象、seq、events构造Response对象,并将其放入mResponses队列中。只有文件fd才构造Request对象并加入mRequests列表,同时当epoll_wait返回的时候才构造Response对象并加入到mResponses列表中。
文件fd都会指定一个callback,因此到epoll监听到事件的时候,当looper进入到epoll_wait时就会知道,然后就执行callback而不会构造消息。
int Looper::addFd(int fd, int ident, int events, const sp<LooperCallback>& callback, void* data) {
#if DEBUG_CALLBACKS
ALOGD("%p ~ addFd - fd=%d, ident=%d, events=0x%x, callback=%p, data=%p", this, fd, ident,
events, callback.get(), data);
#endif
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);
// There is a sequence number reserved for the WakeEventFd.
if (mNextRequestSeq == WAKE_EVENT_FD_SEQ) mNextRequestSeq++;
const SequenceNumber seq = mNextRequestSeq++;
Request request;
request.fd = fd;
request.ident = ident;
request.events = events;
request.callback = callback;
request.data = data;
epoll_event eventItem = createEpollEvent(request.getEpollEvents(), seq);
auto seq_it = mSequenceNumberByFd.find(fd);
if (seq_it == mSequenceNumberByFd.end()) {
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.emplace(seq, request);
mSequenceNumberByFd.emplace(fd, seq);
} else {
int epollResult = epoll_ctl(mEpollFd.get(), EPOLL_CTL_MOD, fd, &eventItem);
if (epollResult < 0) {
if (errno == ENOENT) {
// Tolerate ENOENT because it means that an older file descriptor was
// closed before its callback was unregistered and meanwhile a new
// file descriptor with the same number has been created and is now
// being registered for the first time. This error may occur naturally
// when a callback has the side-effect of closing the file descriptor
// before returning and unregistering itself. Callback sequence number
// checks further ensure that the race is benign.
//
// Unfortunately due to kernel limitations we need to rebuild the epoll
// set from scratch because it may contain an old file handle that we are
// now unable to remove since its file descriptor is no longer valid.
// No such problem would have occurred if we were using the poll system
// call instead, but that approach carries other disadvantages.
#if DEBUG_CALLBACKS
ALOGD("%p ~ addFd - EPOLL_CTL_MOD failed due to file descriptor "
"being recycled, falling back on EPOLL_CTL_ADD: %s",
this, strerror(errno));
#endif
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;
}
}
const SequenceNumber oldSeq = seq_it->second;
mRequests.erase(oldSeq);
mRequests.emplace(seq, request);
seq_it->second = seq;
}
} // release lock
return 1;
}
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);
}
}
- 添加Handler和消息:Looper:sendMessage
一个是sendMessage,消息及时分发。还有一个sendMessageDelayed,延时分发消息
看一下Message结构,只有一个what字段,指明这是上面消息
struct Message {
Message() : what(0) { }
Message(int w) : what(w) { }
/* The message type. (interpretation is left up to the handler) */
int what;
};
/**
* Enqueues a message to be processed by the specified handler.
*
* The handler must not be null.
* This method can be called on any thread.
*/
void Looper::sendMessage(const sp<MessageHandler>& handler, const Message& message)
/**
* Enqueues a message to be processed by the specified handler after all pending messages
* after the specified delay.
*
* The time delay is specified in uptime nanoseconds.
* The handler must not be null.
* This method can be called on any thread.
*/
void Looper::sendMessageDelayed(nsecs_t uptimeDelay, const sp<MessageHandler>& handler,
const Message& message)
sendMessage
void Looper::sendMessage(const sp<MessageHandler>& handler, const Message& message) {
nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
sendMessageAtTime(now, handler, message);
}
void Looper::sendMessageAtTime(nsecs_t uptime, const sp<MessageHandler>& handler,
const Message& message) {
#if DEBUG_CALLBACKS
ALOGD("%p ~ sendMessageAtTime - uptime=%" PRId64 ", handler=%p, what=%d",
this, uptime, handler.get(), message.what);
#endif
size_t i = 0;
{ // acquire lock
AutoMutex _l(mLock);
size_t messageCount = mMessageEnvelopes.size();
while (i < messageCount && uptime >= mMessageEnvelopes.itemAt(i).uptime) {
i += 1;
}
MessageEnvelope messageEnvelope(uptime, handler, message);
mMessageEnvelopes.insertAt(messageEnvelope, i, 1);
// Optimization: If the Looper is currently sending a message, then we can skip
// the call to wake() because the next thing the Looper will do after processing
// messages is to decide when the next wakeup time should be. In fact, it does
// not even matter whether this code is running on the Looper thread.
if (mSendingMessage) {
return;
}
} // release lock
// Wake the poll loop only when we enqueue a new message at the head.
if (i == 0) {
wake();
}
}
Looper中含有MessageEnvelope列表mMessageEnvelope成员,列表中的元素按照时间顺序从小到大排列,代表了Looper待处理的消息,当Looper的sendMessage被调用的时候,参数Message就被包装为MessageEnvelope放入该队列中。这里也用到了等待服务模型(我自己命名的),即众多消息来的时候,先将第一个消息入队列并处理,后面的消息进入队列排队,等第一个消息处理完后,再处理队列中的消息
// Wake the poll loop only when we enqueue a new message at the head.
if (i == 0) { //表示是第一个入队的消息
wake();
}
Looper的mMessageEnvelopes针对的只是Handler。
3.2 Java层发送消息
Message,不想Native层的Message只有一个what成员,Java层Message含有what表示消息类型,arg1、arg2、obj、data用来传递数据。Target表示目标handler,即该消息要发送给该Handler处理。如果Target为null,表示这是barrier消息。when表示这个消息应该什么时候处理,如果没有设置when,则在调用handler的sendxxx或者postxxx时设置为当前时间,表示立即处理。设置该when表示用户希望该消息应该在什么时候处理。flag存储消息的标识,如果设置了FLAG_ASYNCHRONOUS标志,标识这是一个异步消息。callback标识Message中的回调,handler的dispatchMessage中会检查是否设置了该成员,设置了就调用该callback,然后返回,否则就调用Handler的mCallback成员,没有设置才最后调用Handler的handleMessage。同时Message实现了消息池,需要message的时候可以去池子里拿(通过obtain方法),用了之后会被回收(被Looper).
/**
*
* Defines a message containing a description and arbitrary data object that can be
* sent to a {@link Handler}. This object contains two extra int fields and an
* extra object field that allow you to not do allocations in many cases.
*
* <p class="note">While the constructor of Message is public, the best way to get
* one of these is to call {@link #obtain Message.obtain()} or one of the
* {@link Handler#obtainMessage Handler.obtainMessage()} methods, which will pull
* them from a pool of recycled objects.</p>
*/
public final class Message implements Parcelable {
/**
* User-defined message code so that the recipient can identify
* what this message is about. Each {@link Handler} has its own name-space
* for message codes, so you do not need to worry about yours conflicting
* with other handlers.
*/
public int what;
/**
* arg1 and arg2 are lower-cost alternatives to using
* {@link #setData(Bundle) setData()} if you only need to store a
* few integer values.
*/
public int arg1;
/**
* arg1 and arg2 are lower-cost alternatives to using
* {@link #setData(Bundle) setData()} if you only need to store a
* few integer values.
*/
public int arg2;
/**
* An arbitrary object to send to the recipient. When using
* {@link Messenger} to send the message across processes this can only
* be non-null if it contains a Parcelable of a framework class (not one
* implemented by the application). For other data transfer use
* {@link #setData}.
*
* <p>Note that Parcelable objects here are not supported prior to
* the {@link android.os.Build.VERSION_CODES#FROYO} release.
*/
public Object obj;
/**
* Optional Messenger where replies to this message can be sent. The
* semantics of exactly how this is used are up to the sender and
* receiver.
*/
public Messenger replyTo;
/**
* Indicates that the uid is not set;
*
* @hide Only for use within the system server.
*/
public static final int UID_NONE = -1;
/**
* Optional field indicating the uid that sent the message. This is
* only valid for messages posted by a {@link Messenger}; otherwise,
* it will be -1.
*/
public int sendingUid = UID_NONE;
/**
* Optional field indicating the uid that caused this message to be enqueued.
*
* @hide Only for use within the system server.
*/
public int workSourceUid = UID_NONE;
/** If set message is in use.
* This flag is set when the message is enqueued and remains set while it
* is delivered and afterwards when it is recycled. The flag is only cleared
* when a new message is created or obtained since that is the only time that
* applications are allowed to modify the contents of the message.
*
* It is an error to attempt to enqueue or recycle a message that is already in use.
*/
/*package*/ static final int FLAG_IN_USE = 1 << 0;
/** If set message is asynchronous */
/*package*/ static final int FLAG_ASYNCHRONOUS = 1 << 1;
/** Flags to clear in the copyFrom method */
/*package*/ static final int FLAGS_TO_CLEAR_ON_COPY_FROM = FLAG_IN_USE;
@UnsupportedAppUsage
/*package*/ int flags;
/**
* The targeted delivery time of this message. The time-base is
* {@link SystemClock#uptimeMillis}.
* @hide Only for use within the tests.
*/
@UnsupportedAppUsage
@VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
public long when;
/*package*/ Bundle data;
@UnsupportedAppUsage
/*package*/ Handler target;
@UnsupportedAppUsage
/*package*/ Runnable callback;
// sometimes we store linked lists of these things
@UnsupportedAppUsage
/*package*/ Message next;
/** @hide */
public static final Object sPoolSync = new Object();
private static Message sPool;
private static int sPoolSize = 0;
private static final int MAX_POOL_SIZE = 50;
private static boolean gCheckRecycle = true;
/**
* Return a new Message instance from the global pool. Allows us to
* avoid allocating new objects in many cases.
*/
public static Message obtain() {
synchronized (sPoolSync) {
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();
}
/**
* Same as {@link #obtain()}, but copies the values of an existing
* message (including its target) into the new one.
* @param orig Original message to copy.
* @return A Message object from the global pool.
*/
public static Message obtain(Message orig) {
Message m = obtain();
m.what = orig.what;
m.arg1 = orig.arg1;
m.arg2 = orig.arg2;
m.obj = orig.obj;
m.replyTo = orig.replyTo;
m.sendingUid = orig.sendingUid;
m.workSourceUid = orig.workSourceUid;
if (orig.data != null) {
m.data = new Bundle(orig.data);
}
m.target = orig.target;
m.callback = orig.callback;
return m;
}
java层发送消息都是通过Handler的方法(native层是通过Looper的sendMessage)和MessageQueue,Handler发送的有Post消息、Send消息、Barrier消息。而MessageQueue发送的只有Barrier消息。Post版本发送callback消息(有callback成员的message),而send版本则是一般消息(没有设置callback成员。
Handler方法
new Handler(@Nullable Callback callback, boolean async)
post(Runnable),
postAtTime(java.lang.Runnable, long),
postDelayed(Runnable, Object, long),
sendEmptyMessage(int),
sendMessage(Message),
sendMessageAtTime(Message, long),
sendMessageDelayed(Message, long)
MessageQueue方法:
postSyncBarrier()
postSyncBarrier(long when)
removeSyncBarrier(token)
3.2.1 barrier消息
MessageQueue
int postSyncBarrier() {
return postSyncBarrier(SystemClock.uptimeMillis());
}
private int postSyncBarrier(long when) {
// Enqueue a new sync barrier token.
// We don't need to wake the queue because the purpose of a barrier is to stall it.
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;
}
}
可见barrier消息就是Handler为null的消息,MessageQueue开发分发消息的时会根据handler是否为null识别出是否为barrier消息。返回的token用来标识该Barrier消息,后面调用removeSyncBarrier方法可以移除该消息。
常用的方法:
token= mHandler.getLooper().getQueue().postSyncBarrier();
mHandler.getLooper().getQueue().removeSyncBarrier(token)
3.2.2 普通消息
这个没有啥子好说的
3.2.3 Callback消息
CalBack有两种,一种是对Message的callback赋值,使用PostXXX方法发送Callback消息,先构造message,然后对message的callback进行赋值。 最后再调用sendxxx的方法进入messageQueue。
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(@NonNull Message msg, long delayMillis) {
if (delayMillis < 0) {
delayMillis = 0;
}
return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}
另外一种是设置Handler的mCallback成员,当有MessageQueue调用Handler分发消息的时候,如果消息没有callback成员,则会调用Handler的mCallback成员,没有的话才最后调用Handler的handleMessage方法。App端是不能设置mCallbackd,因为有@UnsupportedAppUsage注释,App访问不了。设置mCallBack的方法就是Handler的构造函数调用的时候设置。
* @hide
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
public Handler(@Nullable Callback callback, boolean async) {
if (FIND_POTENTIAL_LEAKS) {
final Class<? extends Handler> 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;
}
3.2.4 Handler的产生
Handler的构函数如下,总结就是指定如下几项成员:
- mLooper对:指定Handler关联的Looper对象,不指定looper对象,使用此时线程的looper对象
- mCallback:指定了mCallback,当MessageQueue分发消息的时候,如果消息没有指定callback,就调用handler的mCallback,如果没有最后才调用handleMessage
- mAsynchronous:是否为异步Handler,通过异步Handler发送的消息全是异步消息,其Message的flag会被设置FLAG_ASYNCHRONOUS标志。
public Handler() {
this(null, false);
}
@Deprecated
public Handler(@Nullable Callback callback) {
this(callback, false);
}
public Handler(@NonNull Looper looper) {
this(looper, null, false);
}
public Handler(@NonNull Looper looper, @Nullable Callback callback) {
this(looper, callback, false);
}
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
public Handler(boolean async) {
this(null, async);
}
public Handler(@Nullable Callback callback, boolean async)
@UnsupportedAppUsage
public Handler(@NonNull Looper looper, @Nullable Callback callback, boolean async)
最好是创建一个继承Handler的静态内部类来使用Handler,应为要重写handleMessage,因此就必定继承Handler,而继承Handler有有三种方式,一种是非静态内部类,一种是匿名内部类,一种是静态内部类。前两种都会持有外部对象,一般这里的外部对象就是MainActivity,而通过handler发送消息时,message是持有该handler对象的(这样MessageQueue才知道消息应该发给谁处理),message没有被回收之前,Handler是不会被回收的,而Handler有持有外部类也就是MainActivity,导致Handler没有被回收之前,MainActivity是不会被回收的,当Message一直没有被回收,那么MainActivyt也就不会被回收,这就会导致内存泄漏问题,一般会提示:
This Handler class should be static or leaks might occur。
4. 取消息与处理消息
4.1 获取native层消息并处理
MessageQueue的next方法,先处理native层的MessageQueue
@UnsupportedAppUsage
Message next() {
// Return here if the message loop has already quit and been disposed.
// This can happen if the application tries to restart a looper after quit
// which is not supported.
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();
}
//获取native层消息并处理
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;
}
// Process the quit message now that all pending messages have been handled.
if (mQuitting) {
dispose();
return null;
}
// 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;
}
}
nativePollOnce
static void android_os_MessageQueue_nativePollOnce(JNIEnv* env, jobject obj,
jlong ptr, jint timeoutMillis) {
NativeMessageQueue* nativeMessageQueue = reinterpret_cast<NativeMessageQueue*>(ptr);
nativeMessageQueue->pollOnce(env, obj, timeoutMillis);
}
void NativeMessageQueue::pollOnce(JNIEnv* env, jobject pollObj, int timeoutMillis) {
mPollEnv = env;
mPollObj = pollObj;
mLooper->pollOnce(timeoutMillis);
mPollObj = NULL;
mPollEnv = NULL;
if (mExceptionObj) {
env->Throw(mExceptionObj);
env->DeleteLocalRef(mExceptionObj);
mExceptionObj = NULL;
}
}
pollOnce为轮询一次,如果没有事件,则在指定时间醒来,如果事件为0,则不休眠立即起来,为负数,则一直等待知道有事件到来才醒来。这里的指定事件为0.
/**
* Waits for events to be available, with optional timeout in milliseconds.
* Invokes callbacks for all file descriptors on which an event occurred.
*
* If the timeout is zero, returns immediately without blocking.
* If the timeout is negative, waits indefinitely until an event appears.
*
* Returns POLL_WAKE if the poll was awoken using wake() before
* the timeout expired and no callbacks were invoked and no other file
* descriptors were ready.
*
* Returns POLL_CALLBACK if one or more callbacks were invoked.
*
* Returns POLL_TIMEOUT if there was no data before the given
* timeout expired.
*
* Returns POLL_ERROR if an error occurred.
*
* Returns a value >= 0 containing an identifier if its file descriptor has data
* and it has no callback function (requiring the caller here to handle it).
* In this (and only this) case outFd, outEvents and outData will contain the poll
* events and data associated with the fd, otherwise they will be set to NULL.
*
* This method does not return until it has finished invoking the appropriate callbacks
* for all file descriptors that were signalled.
*/
int pollOnce(int timeoutMillis, int* outFd, int* outEvents, void** outData);
inline int pollOnce(int timeoutMillis) {
return pollOnce(timeoutMillis, nullptr, nullptr, nullptr);
}
- 优先处理mResponses里的Response,即来自fd的事件
- 如果没有需处理的Response,再调用pollInner
int Looper::pollOnce(int timeoutMillis, int* outFd, int* outEvents, void** outData) {
int result = 0;
for (;;) {
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 DEBUG_POLL_AND_WAKE
ALOGD("%p ~ pollOnce - returning signalled identifier %d: "
"fd=%d, events=0x%x, data=%p",
this, ident, fd, events, data);
#endif
if (outFd != nullptr) *outFd = fd;
if (outEvents != nullptr) *outEvents = events;
if (outData != nullptr) *outData = data;
return ident;
}
}
if (result != 0) {
#if DEBUG_POLL_AND_WAKE
ALOGD("%p ~ pollOnce - returning result %d", this, result);
#endif
if (outFd != nullptr) *outFd = 0;
if (outEvents != nullptr) *outEvents = 0;
if (outData != nullptr) *outData = nullptr;
return result;
}
/这里=====
result = pollInner(timeoutMillis);
}
}
std::unordered_map<int /*fd*/, SequenceNumber> mSequenceNumberByFd; // guarded by mLock
using SequenceNumber = uint64_t;
int Looper::pollInner(int timeoutMillis) {
#if DEBUG_POLL_AND_WAKE
ALOGD("%p ~ pollOnce - waiting: timeoutMillis=%d", this, timeoutMillis);
#endif
// 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;
}
#if DEBUG_POLL_AND_WAKE
ALOGD("%p ~ pollOnce - next message in %" PRId64 "ns, adjusted timeout: timeoutMillis=%d",
this, mNextMessageUptime - now, timeoutMillis);
#endif
}
// Poll.
//清除mResponses----------------------
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;
}
// Check for poll error.
if (eventCount < 0) {
if (errno == EINTR) {
goto Done;
}
ALOGW("Poll failed with an unexpected error: %s", strerror(errno));
result = POLL_ERROR;
goto Done;
}
// Check for poll timeout.
if (eventCount == 0) {
#if DEBUG_POLL_AND_WAKE
ALOGD("%p ~ pollOnce - timeout", this);
#endif
result = POLL_TIMEOUT;
goto Done;
}
// Handle all events.
#if DEBUG_POLL_AND_WAKE
ALOGD("%p ~ pollOnce - handling events from %d fds", this, eventCount);
#endif
for (int i = 0; i < eventCount; i++) {
const SequenceNumber seq = eventItems[i].data.u64;
uint32_t epollEvents = eventItems[i].events;
if (seq == WAKE_EVENT_FD_SEQ) {
if (epollEvents & EPOLLIN) {
awoken();
} else {
ALOGW("Ignoring unexpected epoll events 0x%x on wake event fd.", epollEvents);
}
} else {
const auto& request_it = mRequests.find(seq);
if (request_it != mRequests.end()) {
const auto& request = request_it->second;
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;
mResponses.push({.seq = seq, .events = events, .request = request});
} else {
ALOGW("Ignoring unexpected epoll events 0x%x for sequence number %" PRIu64
" that is no longer registered.",
epollEvents, seq);
}
}
}
Done: ;
// Invoke pending message callbacks.
mNextMessageUptime = LLONG_MAX;
while (mMessageEnvelopes.size() != 0) {
nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
const MessageEnvelope& messageEnvelope = mMessageEnvelopes.itemAt(0);
if (messageEnvelope.uptime <= now) {
// Remove the envelope from the list.
// We keep a strong reference to the handler until the call to handleMessage
// finishes. Then we drop it so that the handler can be deleted *before*
// we reacquire our lock.
{ // obtain handler
sp<MessageHandler> handler = messageEnvelope.handler;
Message message = messageEnvelope.message;
mMessageEnvelopes.removeAt(0);
mSendingMessage = true;
mLock.unlock();
#if DEBUG_POLL_AND_WAKE || DEBUG_CALLBACKS
ALOGD("%p ~ pollOnce - sending message: handler=%p, what=%d",
this, handler.get(), message.what);
#endif
handler->handleMessage(message);
} // release handler
mLock.lock();
mSendingMessage = false;
result = POLL_CALLBACK;
} else {
// The last message left at the head of the queue determines the next wakeup time.
mNextMessageUptime = messageEnvelope.uptime;
break;
}
}
// 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;
#if DEBUG_POLL_AND_WAKE || DEBUG_CALLBACKS
ALOGD("%p ~ pollOnce - invoking fd event callback %p: fd=%d, events=0x%x, data=%p",
this, response.request.callback.get(), fd, events, data);
#endif
// Invoke the callback. Note that the file descriptor may be closed by
// the callback (and potentially even reused) before the function returns so
// we need to be a little careful when removing the file descriptor afterwards.
int callbackResult = response.request.callback->handleEvent(fd, events, data);
if (callbackResult == 0) {
AutoMutex _l(mLock);
removeSequenceNumberLocked(response.seq);
}
// Clear the callback reference in the response structure promptly because we
// will not clear the response vector itself until the next poll.
response.request.callback.clear();
result = POLL_CALLBACK;
}
}
return result;
}
这里有两种处理,先调用epoll_wait等待fd事件,fd事件到来后,如果是wake事件,则调用 awoken();函数,否则将这些事件包装为Response对象加入到mResponses列表中,然后进入done部分。进入done部分后依次进行两种处理
处理1:Handler消息处理,遍历mMessageEnvelops列表,取出列表的元素MessageEnvelop中的message(拆封)和对应的Handler,然后调用Handler的handleMessage(message)。MessageEnvelope被取出后就会从mMessageEnvelops中移除。
处理2:处理完Handler的消息后,开始处理fd消息,遍历mResponses列表,取出Response对象,取出其中Request类成员request的callback、fd、data和Response的events(监听的事件),对于request的ident等于POLL_CALLBACK的Resonse就会调用callback的handleEvent(fd, events, data),这里的data其实是seq(注册的时候传入的)。fd事件被处理后不一定会消息对fd的监听,还要看**handleEvent的返回值,如果为0,则取消监听,为1则不取消监听。**而ident若不为POLL_CALLBACK(-2)则就是一个正值,表示应该不这个事件传出去,而不是自己处理。该处理不在pollinner中,而在pollOnce中。
为什么不处理完后不清除mResponses中的元素呢,因为此时只处理了ident为POLL_CALLBACK的Response元素,还有ident大于0的Resonse元素没有处理,因此此时还不能清空,这些ident大于0的response元素在下一轮的pollonce开头处理,而清空则在接下来的pollinner开头处理。
处理ident大于0的元素,在进入pollonce中一开头,便遍历mResponses中的ident大于0的Response对象,用mResponseIndex 记录其位置,然后返回pollonce函数,将fd、events、data传出去,在下次looper进入pollonce的时候又开始这个流程(从mResponseIndex 所指位置开始),直到将所有ident大于0的fd事件处理完后才进入pollinner函数,该函数一开头便情况mResponses和重置mmResponseIndex 。但在有java层Looper存在的情况下,mAllowNonCallbacks为false,也就意味着fd注册的时候必须有callback,没有callback即ident大于0的情况是不被允许注册的。
4.2 java层获取消息与处理
在java层MessageQueue的next方法中,先处理native层消息,处理完之后再从消息链表中取出一个消息,不管是什么消息都会调用msg.target.dispatchMessage(msg)进行分发处理。
@UnsupportedAppUsage
Message next() {
// Return here if the message loop has already quit and been disposed.
// This can happen if the application tries to restart a looper after quit
// which is not supported.
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();
}
//获取native层消息并处理
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;
}
// Process the quit message now that all pending messages have been handled.
if (mQuitting) {
dispose();
return null;
}
// 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;
}
}
获取消息后,调用msg.target.dispatchMessage(msg)进行分发处理进行处理
/**
* Handle system messages here.
*/
public void dispatchMessage(@NonNull Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
5. 停止
Looper.quit()