Handler源码解读(二)

上文介绍了 Handler 的创建,今天看下消息的传递机制

首先发送一个消息,Handler 的 sendMessage 和 post

    public final boolean post(Runnable r)
    {
       return  sendMessageDelayed(getPostMessage(r), 0);
    }

    public final boolean sendMessage(Message msg)
    {
        return sendMessageDelayed(msg, 0);
    }

    private static Message getPostMessage(Runnable r) {
        Message m = Message.obtain();
        m.callback = r;
        return m;
    }

这两函数同样会走到 enqueueMessage 方法中,注意这里的 getPostMessage 方法将 Runnable 设置为 Message 的 callback 。

    private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
        msg.target = this;
        if (mAsynchronous) {
            msg.setAsynchronous(true);
        }
        return queue.enqueueMessage(msg, uptimeMillis);
    }

注意这里将 Message 的 target 属性设置为当前 Handler 了。看下 MessageQueue 的 enqueueMessage 方法

    Message mMessages;
    boolean enqueueMessage(Message msg, long when) {
        //
        synchronized (this) {
            //
            //将消息置为使用中
            msg.markInUse();
            msg.when = when;
            Message p = mMessages;
            //等待判断
            boolean needWake;
            //

            if (needWake) {
                nativeWake(mPtr);
            }
        }
        return true;
    }

判断消息的参数是否符合,判断消息插入的位置(后文讲解),之后调用 nativeWake 将消息插入到 MessageQueue 中。nativeWake 是 native 方法,在 native 的 MessageQueue,上文给到地址了。

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

nativeMessageQueue 有调用 native 的 looper 的 wake()

void Looper::wake() {

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

上文已说明,在创建的 mWakeEventFd 中写数据。

Android 线程间消息的发送已经明白,接下来看下怎么取出数据并分发。

    public static void loop() {
        final Looper me = myLooper();
        final MessageQueue queue = me.mQueue;
       
        for (;;) {
            Message msg = queue.next(); // might block
            if (msg == null) {
                // No message indicates that the message queue is quitting.
                return;
            }

            try {
                msg.target.dispatchMessage(msg);
                end = (slowDispatchThresholdMs == 0) ? 0 : SystemClock.uptimeMillis();
            } finally {
                if (traceTag != 0) {
                    Trace.traceEnd(traceTag);
                }
            }
            
            msg.recycleUnchecked();
        }
    }

获取 Looper 对象,由 Looper 获取 MessageQueue 对象,在 MessageQueue 中调用 next() 取出 message,之后分发 message。

msg.target 就是当前的 Handler,所以 msg.target.dispatchMessage(msg); 实则调用了发送 Handler 的 dispatchMessage。

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

先判断 callback 是否为 null,也就是是否是 post 方式发送的消息。如果不为 null 的话,直接运行 Runnable。

    private static void handleCallback(Message message) {
        message.callback.run();
    }

在判断 mCallback 是否为 null,不为 null,则会执行 mCallback的handleMessage 方法。比如插件化技术中,去 Hook 类 H,重写 handlerMessage 方法,当收到的消息类型为 LAUNCH_ACTIVITY 时,处理相关逻辑。

之后处理自身的 handleMessage

    public void handleMessage(Message msg) {
    }

接下来重点了解下 next()

    Message next() {
        //
        int nextPollTimeoutMillis = 0;
        for (;;) {
            if (nextPollTimeoutMillis != 0) {
                Binder.flushPendingCommands();
            }

            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) {
                    if (now < msg.when) {
                      //时间未到
                    } else {
                        
                        mBlocked = false;
                        if (prevMsg != null) {
                            prevMsg.next = msg.next;
                        } else {
                            mMessages = msg.next;
                        }
                        msg.next = null;
                        //
                        msg.markInUse();
                        return msg;
                    }
                } else {
                    // No more messages.
                    nextPollTimeoutMillis = -1;
                }
                //其他处理
            }

        }
    }

nativePollOnce 一直阻塞,当有消息或超时时,就会返回。判断消息类型、消息触发时间,之后返回此消息。

nativePollOnce() 函数时 native 层,

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

转发给 nativeMessageQueue 的 pollOnce,之后有转发给 mLooper 的 pollOnce。我们上节提到了 pollOnce,它会转发给 pollInner,这里代码就不全贴了,重点看下 epoll_wait 函数。

    int eventCount = epoll_wait(mEpollFd, eventItems, EPOLL_MAX_EVENTS, timeoutMillis);

epoll_wait 这个系统调用是用来等待 mEpollFd 中的事件。eventItems 指向调用者可以使用的事件的内存区域。EPOLL_MAX_EVENTS 告知内核有多少个 events,必须要大于 0。timeoutMillis 这个参数是用来制定 epoll_wait 会阻塞多少毫秒。这个函数会阻塞调用线程,当一个文件描述符触发了事件,或者 timeout 超时了就会返回。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值