publicstaticvoidprepareMainLooper() { // 准备looper,传入false表明不允许中途退出,main线程挂了app就crash了所以永远不允许退出 prepare(false); // 由于main线程是比较特殊的线程,要供其他所有的线程使用,所以需要保存一份静态实例。 synchronized (Looper.class) { if (sMainLooper != null) { thrownewIllegalStateException("The main Looper has already been prepared."); } sMainLooper = myLooper(); } }
Handler实现原理
Looper
Looper准备
1 2 3
publicstaticvoidprepare() { prepare(true); }
在ThreadLocal中设置一个Looper实例
1 2 3 4 5 6
privatestaticvoidprepare(boolean quitAllowed) { if (sThreadLocal.get() != null) { thrownewRuntimeException("Only one Looper may be created per thread"); } sThreadLocal.set(newLooper(quitAllowed)); }
publicstaticvoidloop() { // 获取当前线程的looper对象 finalLooperme= myLooper(); if (me == null) { thrownewRuntimeException("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(); finallongident= Binder.clearCallingIdentity();
// Allow overriding a threshold with a system prop. e.g. // adb shell 'setprop log.looper.1000.main.slow 1 && stop && start' finalintthresholdOverride= SystemProperties.getInt("log.looper." + Process.myUid() + "." + Thread.currentThread().getName() + ".slow", 0);
me.mSlowDeliveryDetected = false; // 死循环loop处理消息 for (;;) { if (!loopOnce(me, ident, thresholdOverride)) { return; } } }
privatestaticvoidprepare(boolean quitAllowed) { if (sThreadLocal.get() != null) { thrownewRuntimeException("Only one Looper may be created per thread"); } sThreadLocal.set(newLooper(quitAllowed)); }
intpendingIdleHandlerCount= -1; // -1 only during first iteration intnextPollTimeoutMillis=0; for (;;) { if (nextPollTimeoutMillis != 0) { Binder.flushPendingCommands(); } // native poll nativePollOnce(ptr, nextPollTimeoutMillis);
// 第一次处于空闲状态,计算idleHandler个数 if (pendingIdleHandlerCount < 0 && (mMessages == null || now < mMessages.when)) { pendingIdleHandlerCount = mIdleHandlers.size(); } // 如果没有idleHandler,阻塞 if (pendingIdleHandlerCount <= 0) { // No idle handlers to run. Loop and wait some more. mBlocked = true; continue; } // 如果有idlehandler但是目前还没有装配, if (mPendingIdleHandlers == null) { mPendingIdleHandlers = newIdleHandler[Math.max(pendingIdleHandlerCount, 4)]; } mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers); }
// Run the idle handlers. // 运行idleHandler for (inti=0; i < pendingIdleHandlerCount; i++) { finalIdleHandleridler= mPendingIdleHandlers[i]; mPendingIdleHandlers[i] = null; // release the reference to the handler booleankeep=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; } }
// 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) { //......
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 { constauto& request_it = mRequests.find(seq); if (request_it != mRequests.end()) { constauto& 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(); 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; // 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; }
booleanenqueueMessage(Message msg, long when) { if (msg.target == null) { thrownewIllegalArgumentException("Message must have a target."); }
synchronized (this) { // 已经被使用抛异常 if (msg.isInUse()) { thrownewIllegalStateException(msg + " This message is already in use."); } // 处理退出 if (mQuitting) { IllegalStateExceptione=newIllegalStateException( msg.target + " sending message to a Handler on a dead thread"); Log.w(TAG, e.getMessage(), e); msg.recycle(); returnfalse; } // 标记为使用状态 msg.markInUse(); msg.when = when; Messagep= mMessages; boolean needWake; // 如果messageQueue中无消息 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. // 如果queue被阻塞并且队首的是同步消息屏障 // 并且msg是第一个异步消息 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; }
publicvoidaddOnFileDescriptorEventListener(@NonNull FileDescriptor fd, @OnFileDescriptorEventListener.Events int events, @NonNull OnFileDescriptorEventListener listener) { if (fd == null) { thrownewIllegalArgumentException("fd must not be null"); } if (listener == null) { thrownewIllegalArgumentException("listener must not be null"); }
intLooper::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); // There is a sequence number reserved for the WakeEventFd. if (mNextRequestSeq == WAKE_EVENT_FD_SEQ) mNextRequestSeq++; const SequenceNumber seq = mNextRequestSeq++;
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. 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 return1; }