Loading [MathJax]/jax/input/TeX/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >Android Looper,Handler,Message,MessageQueue介绍

Android Looper,Handler,Message,MessageQueue介绍

作者头像
一只小虾米
发布于 2022-10-25 08:20:04
发布于 2022-10-25 08:20:04
89300
代码可运行
举报
文章被收录于专栏:Android点滴分享Android点滴分享
运行总次数:0
代码可运行

摘要

最近在看WMS代码,里面好多都涉及到Handler, Looper通信,相比Binder通信,Handler适用于线程间通信,并且没有Binder那么复杂,也容易理解,对于更新UI操作更是需要Handler,本篇就专门介绍下Handler相关内容,包括App层的使用,FWK和Native的具体实现,通过这块内容介绍, 可以对这块有一个清晰的认识。

Handler 使用举例

我们都知道对于App,只有UI线程才可以更新UI,其他线程更新UI会直接导致应用crash,对于非UI线程需要更新UI的,可以通过handler将数据发送过去, UI线程会读取数据并执行更新UI操作。下面是一个例子,每次点击按钮都会随机生成一个字符串,并且将该字符串放入一个BlockingQueue,内部一个非UI线程循环读取该BlockingQueue,并将内容通过Handler显示到UI上。代码如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class MainActivity extends AppCompatActivity {
    private static final String TAG = "MyTest";
    private static final BlockingQueue<String> blockingQueue = new LinkedBlockingDeque<>(10);
    private static Thread thread = null;
    private static final Lock lock = new ReentrantLock();
    private static Handler handler = null;
    private static TextView textView = null;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        init();

        Log.d(TAG, "hello");
        Button button = findViewById(R.id.button1);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                StringBuilder sb = new StringBuilder();
                for (int i = 0; i < 10; i++) {
                    sb.append((char)('a' + (int) (Math.random() * ('z' - 'a'))));
                }
                Log.i(TAG, "content " + sb.toString());
                blockingQueue.offer(sb.toString()); 
            }
        });
    }

    private void init() {
        lock.lock();
        textView = (TextView)findViewById(R.id.textView);
        handler = new MyHandler(Looper.myLooper());
        if (thread == null) {
            thread = new Thread(new Runnable() {
                @Override
                public void run() {
                    while (true) {
                        try {
                            String content = blockingQueue.take();
                            Message message = handler.obtainMessage(1);
                            message.obj = content;
                            handler.sendMessage(message);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
            });
            thread.start();
        }
        lock.unlock();
    }

    static class MyHandler extends Handler {
        @Override
        public void handleMessage(Message msg) {
            Log.i(TAG, "receive " + msg.what);
            switch (msg.what) {
                case 1:
                    textView.setText((String)msg.obj);
                    break;
                default:
                    Log.e(TAG, "unknown what");
            }
        }

        public MyHandler(Looper looper) {
            super(looper);
        }
    }
}

关键点就在于自己需要继承Handler类并实现handleMessage方法,并提供一个构造函数,可以使用指定的Looper来初始化该Handler。每个应用在启动的时候会自动创建一个Looper,每个线程只能有一个Looper,因为这个是一个线程私有变量。下面是Looper成员的关系图。

类图

可以发现Fwk和Native都有一套Looper,而包含关系正好相反,Fwk层是Looper包含MessageQueue,而Native是MessageQueue包含Looper,Fwk的具体实现是完全由Native提供的。

Looper代码解读

我们知道android应用,包括system_server都会运行ActivityThread的main函数,并且将之作为主线程,我们就从这块开始介绍

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
 public static void main(String[] args) {
        Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ActivityThreadMain");
        // Install selective syscall interception
        AndroidOs.install();
        // CloseGuard defaults to true and can be quite spammy.  We
        // disable it here, but selectively enable it later (via
        // StrictMode) on debug builds, but using DropBox, not logs.
        CloseGuard.setEnabled(false);
        Environment.initForCurrentUser();
        // Make sure TrustedCertificateStore looks in the right place for CA certificates
        final File configDir = Environment.getUserConfigDirectory(UserHandle.myUserId());
        TrustedCertificateStore.setDefaultUserDirectory(configDir);
        // Call per-process mainline module initialization.
        initializeMainlineModules();
        Process.setArgV0("<pre-initialized>");
        Looper.prepareMainLooper();
        if (sMainThreadHandler == null) {
        sMainThreadHandler = thread.getHandler();
        }

        if (false) {
              Looper.myLooper().setMessageLogging(new LogPrinter(Log.DEBUG, "ActivityThread"));
        }

        // End of event ActivityThreadMain.
        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
        Looper.loop();
        ...

这儿调用了Looper.prepareMainLooper(),这个就是为主线程生成默认的Looper,如果普通线程需要使用Handler就需要自己手动创建Looper了。看下具体实现

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    public static void prepareMainLooper() {
        prepare(false);
        synchronized (Looper.class) {
            if (sMainLooper != null) {
                throw new IllegalStateException("The main Looper has already been prepared.");
            }
            sMainLooper = myLooper();
        }
    }

 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,在初始化的时候会会主线程生成一个不允许退出的Looper并且设置到主线程变量中。对于普通线程,Looper就可以是允许退出的了,这块可以通过prepare的参数来控制。那如何拿到主线程Looper呢?看下下面这个函数

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    public static Looper getMainLooper() {
        synchronized (Looper.class) {
            return sMainLooper;
        }
    }

通过调用getMainLooper就可以拿到主线程Looper。 接下来看下loop实现

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    public static void loop() {
        final Looper me = myLooper(); //拿到当前线程Looper
        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;
        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(); // 清理Binder pid,uid,使得通过IPC接口拿到的uid和pid都是本进程的uid,pid
        final long ident = Binder.clearCallingIdentity();
        // Allow overriding a threshold with a system prop. e.g.
        // adb shell 'setprop log.looper.1000.main.slow 1 && stop && start'
        final int thresholdOverride =
                SystemProperties.getInt("log.looper."
                        + Process.myUid() + "."
                        + Thread.currentThread().getName()
                        + ".slow", 0);
        boolean slowDeliveryDetected = false;
        for (;;) {
            Message msg = queue.next(); // might block // 阻塞式等待,最终是会阻塞到epoll_wait上等待消息,这块是通过读写eventfd实现的,相比pipe优势很大,后面具体介绍
            if (msg == null) {
                // No message indicates that the message queue is quitting.
                return;
            }
           ...
            long origWorkSource = ThreadLocalWorkSource.setUid(msg.workSourceUid);
            try {
                msg.target.dispatchMessage(msg); // 调用handler的处理函数
                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);
                }
            }
           ...
            msg.recycleUnchecked();
        }
    }

这个函数比较长,很多都是各种维测打印,我这边把维测相关的信息去掉了,这样只关心流程主线即可。从上述代码可以看到,loop的流程如下:

  • 循环从MessageQueue中拿到待处理的Message
  • 调用Message中target的dispatchMessage方法, Message的target就是一个Handler。
  • 回收Message,Message做了一个对象池,创建Message先从对象池中获取,如果获取失败再从堆上申请,释放也是先放到对象池中,可以提升对象获取速度,对性能和内存都有好处。

看下MessageQueue的next实现:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    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();
            }
            nativePollOnce(ptr, nextPollTimeoutMillis); //按照最近Message的截止时间作为超时时间阻塞到epoll_wait上,返回后,说明等待了足够的时间,应该有Message到时间了。后面会详细介绍具体实现
            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); // 计算下一次最接近Message的等待时间
                    } 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;
                }
          ...
    }

Handler代码解读

使用Handler的地方,一个是复写它的handleMessage方法,一个是获取Message对象,一个是发送Message对象,下面分别介绍下。

handleMessage

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    /**
     * Subclasses must implement this to receive messages.
     */
    public void handleMessage(@NonNull Message msg) {
    }

可以看到是空实现,所有需要自定义Message处理函数的场景均需要继承Handler类并重写下这个方法,当然也可以直接在msg中提供一个callback,这样不重写不继承也没问题,使用上更加简单。

获取Message对象

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    public final Message obtainMessage()
    {
        return Message.obtain(this);
    }

    public final Message obtainMessage(int what)
    {
        return Message.obtain(this, what);
    }

    public final Message obtainMessage(int what, @Nullable Object obj) {
        return Message.obtain(this, what, obj);
    }

    public final Message obtainMessage(int what, int arg1, int arg2)
    {
        return Message.obtain(this, what, arg1, arg2);
    }

     public final Message obtainMessage(int what, int arg1, int arg2, @Nullable Object obj) {
        return Message.obtain(this, what, arg1, arg2, obj);
    }

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

可以看到实现方法都是从对象池里面获取一个Message,然后按照参数对应赋值即可。

发送Message对象

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    public final boolean sendMessage(@NonNull Message msg) {
        return sendMessageDelayed(msg, 0);
    }
     public final boolean sendEmptyMessage(int what)
    {
        return sendEmptyMessageDelayed(what, 0);
    }
   
    public final boolean post(@NonNull Runnable r) {
       return  sendMessageDelayed(getPostMessage(r), 0);
    }

      private boolean enqueueMessage(@NonNull MessageQueue queue, @NonNull Message msg,
            long uptimeMillis) {
        msg.target = this; // 关键操作:将target指定为当前Handler
        msg.workSourceUid = ThreadLocalWorkSource.getUid();
        if (mAsynchronous) {
            msg.setAsynchronous(true);
        }
        return queue.enqueueMessage(msg, uptimeMillis);
    }
 ...

这儿发送Message的方法也很多,都是针对创建Message的各种封装简化,最终都是调用的enqueueMessage, 这个函数里面有个关键操作就是将Message的target指定为当前Handler,然后调用MessageQueue的enqueueMessage方法。 看下该方法的实现:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    boolean enqueueMessage(Message msg, long when) {
        if (msg.target == null) {
            throw new IllegalArgumentException("Message must have a target.");
        }
        synchronized (this) {
            if (msg.isInUse()) {
                throw new IllegalStateException(msg + " This message is already in use.");
            }
            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 (;;) { // 每个Message有个触发时间,这儿是按照触发时间顺序插入Message,越在前面的触发时间越早
                    prev = p;
                    p = p.next;
                    if (p == null || when < p.when) {
                        break;
                    }
                    if (needWake && p.isAsynchronous()) {
                        needWake = false;
                    }
                }
                msg.next = p; // invariant: p == prev.next  
                prev.next = msg;
            }
            // We can assume mPtr != 0 because mQuitting is false.
            if (needWake) {
                nativeWake(mPtr); //唤醒操作,后面具体介绍
            }
        }
        return true;
    }

这块就是将Message按照时间顺序插入到Message队列中,然后执行下唤醒操作,那这儿的唤醒是如何唤醒next中的阻塞呢?这块就需要了解native的实现了,下面开始看下吧。

NativeMessageQueue实现

MessageQueue是这样构造的

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    MessageQueue(boolean quitAllowed) {
        mQuitAllowed = quitAllowed;
        mPtr = nativeInit();
    }

这儿的mPtr就是NativeMessageQueue对象的指针,通过在Java中保存Native对象的指针来操作Native对象。看下具体实现

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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); //将native对象指针传递给java
}


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

这儿就实现了Fwk使用Native的Looper。接下来看下两个关键调用的具体实现,一个是nativePollOnce, 一个是nativeWake。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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;
    }
}

static void android_os_MessageQueue_nativeWake(JNIEnv* env, jclass clazz, jlong ptr) {
    NativeMessageQueue* nativeMessageQueue = reinterpret_cast<NativeMessageQueue*>(ptr);
    nativeMessageQueue->wake();
}

void NativeMessageQueue::wake() {
    mLooper->wake();
}

可以看到上面两个函数最终都是调用的Native Looper的对应调用,接下来就看下Native的Looper是如何实现的。

Native Looper介绍

先看下下面这两个函数,通过这两个函数可以看出Native的Looper也是线程级的变量。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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);
}

看下Looper的初始化:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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)); //创建eventfd
    LOG_ALWAYS_FATAL_IF(mWakeEventFd.get() < 0, "Could not make wake event fd: %s", strerror(errno));

    AutoMutex _l(mLock);
    rebuildEpollLocked();
}

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

    // Allocate the new epoll instance and register the wake pipe.
    mEpollFd.reset(epoll_create1(EPOLL_CLOEXEC));
    LOG_ALWAYS_FATAL_IF(mEpollFd < 0, "Could not create epoll instance: %s", strerror(errno));

    struct epoll_event eventItem;
    memset(& eventItem, 0, sizeof(epoll_event)); // zero out unused members of data field union
    eventItem.events = EPOLLIN;
    eventItem.data.fd = mWakeEventFd.get();
    int result = epoll_ctl(mEpollFd.get(), EPOLL_CTL_ADD, mWakeEventFd.get(), &eventItem); //注册eventfd 输入事件
    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));
        }
    }
}

这块最主要的就是eventfd的使用,之前android使用的是pipe,后来换成了eventfd,这儿使用eventfd相对于pipe有以下几个好处:

  • 对于进程间通信,如果使用pipe,就需要每个进程创建2个fd,如果是n个进程,那么就需要2n个fd,并且每个京城都需要维护这么多个fd,而fd对于进程是很宝贵的资源,一共也才1024个。而使用eventfd就只需要一个fd就可以了
  • 使用pipe效率没有eventfd高,eventfd就是一个计数器,内容就是一个32字节的整数,传输开销可以忽略不计,而pipe则需要内存至少分配一个4k内存。

接下来看下pollOnce的实现:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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);
    }
}

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.
    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++) { //对于Fwk的Looper,其实一般只有一个fd,就是eventfd,除非也通过addFd设置了某些fd的事件回调
        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);
            }
        } 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: ;

    // Invoke pending message callbacks.
    mNextMessageUptime = LLONG_MAX;
    while (mMessageEnvelopes.size() != 0) {  // native Message消息处理,类似于Fwk的,MessageEnvelope中保存有hander。
        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) {
                removeFd(fd, response.request.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;
}

可以看出pollOnce主要就是在epoll_wait上阻塞等待,要不有fd事件唤醒,要不就是超时返回,这块也有native massage的处理,类似于Fwk的,调用Message相关的Handler中的handleMessage。 接下来看下wake的实现:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
void Looper::wake() {
#if DEBUG_POLL_AND_WAKE
    ALOGD("%p ~ wake", this);
#endif

    uint64_t inc = 1;
    ssize_t nWrite = TEMP_FAILURE_RETRY(write(mWakeEventFd.get(), &inc, sizeof(uint64_t)));
    if (nWrite != sizeof(uint64_t)) {
        if (errno != EAGAIN) {
            LOG_ALWAYS_FATAL("Could not write wake signal to fd %d (returned %zd): %s",
                             mWakeEventFd.get(), nWrite, strerror(errno));
        }
    }
}

看到这里应该就有豁然开朗的感觉了,这儿就向eventfd中写入一个数字,这样就可以把阻塞到epoll_wait上的线程唤醒了。

总结

本篇通过例子,源码介绍了下Android中的Handler机制,本质上就是一个支持跨进程的基于IO多路复用的生产消费者框架,能理解到这里,Handler应该算是彻底明白了。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2020-12-21,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
how to understand Looper Handler and MessageQueue
https://developer.android.com/reference/android/os/Looper.html
平凡的学生族
2019/05/25
3440
Android Handler机制10之Native的实现
在Android Handler机制6之MessageQueue简介中的五、native层代码的初始化中 说了MessaegQueue构造函数调用了nativeInit(),为了更好的理解,我们便从MessageQueue构造函数开始说起
隔壁老李头
2018/08/30
2.2K1
Android Handler机制10之Native的实现
Android Handler与Looper原理浅析
本文分析下Android的消息处理机制,主要是针对Handler、Looper、MessageQueue组成的异步消息处理模型,先主观想一下这个模型需要的材料:
看书的小蜗牛
2018/06/29
1.2K0
Android Handler与Looper原理浅析
Android Framework学习(八)之Handler消息机制(Native层)解析
在深入解析Android中Handler消息机制一文中,我们学习了Handler消息机制的java层代码,这次我们来学习Handler消息机制的native层代码。
老马的编程之旅
2022/06/22
1.2K0
Android Framework学习(八)之Handler消息机制(Native层)解析
深入理解 Android 消息机制原理
导语: 本文讲述的是Android的消息机制原理,从Java到Native代码进行了梳理,并结合其中使用到的Epoll模型予以介绍。 Android的消息传递,是系统的核心功能,对于如何使用相信大家都
汪毅雄
2017/11/08
2K0
深入理解 Android 消息机制原理
Android framework学习(2)——Handler Native层
基于android28源码,MessageQueue类里面涉及到多个native方法,除了MessageQueue的native方法,native层本身也有一套完整的消息机制,用于处理native的消息,如下图Native层的消息机制。
老马的编程之旅
2022/06/23
7310
Android framework学习(2)——Handler Native层
Android进阶技术之——一文吃透Android的消息机制
作为Android中 至关重要 的机制之一,十多年来,分析它的文章不断,大量的内容已经被挖掘过了。所以:
BlueSocks
2022/04/11
1.6K0
Android进阶技术之——一文吃透Android的消息机制
View的postDelayed方法深度思考
突然某天好友老瑞问我 “View的postdelay方法,延迟时间如果设置10分钟或者更长的时间有什么问题吗?“ 。当时听到这个问题时候我只能联想到 Handle.postDelay ,与此同时让我回想起了之前的一些疑问?
静默加载
2020/05/29
2.3K0
「细品源码」 Android 系统的血液:Handler
作为 Android 开发者,相信对于 Handler 的使用早已烂熟于心。Handler 对于 Android 非常重要,可以说,没有它,Android App 就是一堆“破铜烂铁”,它就像 Android 的血液,穿梭在 App 的各个角落,输送养分。
开发的猫
2020/06/19
1K0
「细品源码」 Android 系统的血液:Handler
【Android 异步操作】Handler 机制 ( MessageQueue 消息队列的阻塞机制 | Java 层机制 | native 层阻塞机制 | native 层解除阻塞机制 )
之前在 【Android 异步操作】手写 Handler ( 消息队列 MessageQueue | 消息保存到链表 | 从链表中获取消息 ) 中 , 模仿 Android 的 MessageQueue 手写的 MessageQueue , 使用了如下同步机制 ,
韩曙亮
2023/03/28
1.4K0
深入理解Android消息机制
戳上面的蓝字关注我们哦! 作者:烧麦 链接:https://www.jianshu.com/p/1abba4e4cb93 著作权归作者所有,转载请联系作者获得授权。 在日常的开发中,Android 的消息机制作为系统运行的根本机制之一,显得十分的重要。 从 Handler 发送消息开始 查看源码,Handler的post、send方法最终都会走到 public final boolean sendMessageDelayed(Message msg, long delayMillis) { if
用户1269200
2018/06/22
5540
面试官带你学Android——面试中Handler 这些必备知识点你都知道吗?
在Android面试中,关于 Handler 的问题是必备的,但是这些关于 Handler 的知识点你都知道吗?
Android技术干货分享
2020/10/12
7280
面试官带你学Android——面试中Handler 这些必备知识点你都知道吗?
Android Handler,Looper 与 MessageQueue 使用与分析
一个Handler允许发送和处理Message,通过关联线程的 MessageQueue 执行 Runnable 对象。 每个Handler实例都和一个单独的线程及其消息队列绑定。 可以将一个任务切换到Handler所在的线程中去执行。一个用法就是子线程通过Handler更新UI。
AnRFDev
2021/02/01
7990
深入Handler、Looper、MessageQueue
Handler、Looper、MessageQueue基本了解可以看下这篇文章 Android源码解读-Handler、Loop、MessageQueue
笔头
2022/01/24
3890
Android Handler机制6之MessageQueue简介
我们知道MessageQueue就一个构造函数 代码在MessageQueue.java 68行
隔壁老李头
2018/08/30
1.1K0
Android Handler机制6之MessageQueue简介
Handler,Message, MessageQueue 和 Looper
在开发过程中非主线程更新UI,第一个想到的就是通过Handler来刷新UI,那Handler是如何工作的呢? Handler Handler是消息处理器,负责Message消息的发送和处理。 mHa
艳龙
2021/12/16
2720
[039]Looper的wake机制升级
我做了两期有关Looper的视频,目前来看播放量还不错,有兴趣的可以去B站观看,视频中我提到Looper采用pipe机制wake,纠正一下自己的错误,新版本的Looper已经采用eventfd代替pipe。
王小二
2020/06/08
1.3K0
[039]Looper的wake机制升级
Android Handler机制:Looper、Handler、MessageQueue、Message的关系
Handler是Android中处理异步消息的机制。Looper、Handler、MessageQueue、Message概括来说就是:Looper负责的就是创建一个MessageQueue,然后进入一个无限循环体不断从该MessageQueue中读取消息Message,然后回调相应的消息处理函数,而消息的创建者就是一个或多个Handler,执行完成一个消息后则继续循环。
没关系再继续努力
2021/11/18
1.4K0
【Android】Handler 机制 ( Handler | Message | Looper | MessageQueue )
① 子线程更新 UI : 在子线程中更新 UI , 就是在子线程中将刷新 UI 的任务分配给了主线程 ; ( 子线程刷新 UI 会崩溃 )
韩曙亮
2023/03/27
1.5K0
从Looper源码看美团监控系统:MessageQueue延迟回收如何引发万亿级日志丢失
大家好,我是稳稳,一个曾经励志用技术改变世界,现在为随时失业做准备的中年奶爸程序员,与你分享生活和学习的点滴。
AntDream
2025/03/27
1160
从Looper源码看美团监控系统:MessageQueue延迟回收如何引发万亿级日志丢失
推荐阅读
相关推荐
how to understand Looper Handler and MessageQueue
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档