深入学习Android framework(2)——Handler Native层

在这里插入图片描述

Handler机制切换至epoll的原因

从 Android 2.3 开始,Google 把 Handler 的阻塞/唤醒方案从 Object#wait() / notify(),改成了用 Linux epoll 来实现

Native 希望能够像 Java 一样:main 线程在没有消息时进入阻塞状态,有到期消息需要执行时,main 线程能及时醒过来处理。怎么办?有两种选择

要么,继续使用 Object#wait() / notify( ),Native 向消息队列添加新消息时,通知 Java 层自己需要什么时候被唤醒
要么,在 Native 层重新实现一套阻塞/唤醒方案,弃用 Object#wait() / notify(),Java 通过 jni 调用 Native 进入阻塞态

结局我们都知道了,Google 选择了后者

选择 epoll 的另一个原因是, Native 层支持监听 自定义 Fd (比如 Input 事件就是通过 epoll 监听 socketfd 来实现将事件转发到 APP 进程的),而一旦有监听多个流事件的需求,那就只能使用 Linux I/O 多路复用技术

理解 I/O多路复用之epoll

在 Linux 中,任何可以进行 I/O 操作的对象都可以看做是流,一个 文件, socket, pipe, 我们都可以把他们看作流
通过调用 read() ,我们可以从流中读出数据;通过 write() ,我们可以往流 写入数据

现在假定一个情形,我们需要从流中读数据,但是流中还没有数据

一个典型的例子为,客户端要从 socket 中读数据,但是服务器还没有把数据传回来,这时候该怎么办?

阻塞: 线程阻塞到 recv() 方法,直到读到数据后再继续向下执行
非阻塞: recv() 方法没读到数据立刻返回 -1 ,用户线程按照固定间隔轮询 recv() 方法,直到有数据返回

在阻塞模式下,一个线程一次只能处理一个流的 I/O 事件,想要同时处理多个流,只能使用 多线程 + 阻塞 I/O 的方案。但是,每个 socket 对应一个线程会造成很大的资源占用,尤其是对于长连接来说。

在非阻塞模式下,我们发现 单线程可以同时处理多个流了。 只要不停的把所有流从头到尾的访问一遍,就可以得知哪些流有数据(返回值大于-1,但这样的做法效率也不高, 因为如果所有的流都没有数据,那么只会白白浪费 CPU

必须让内核创建某种机制,把这些流的监听事件接管过去,这种能够让用户程序拥有 “同时监听多个流读写事件” 的机制,就被称为 I/O 多路复用!

理解 Linux eventfd

eventfd 是专门用来传递事件的 fd ,它提供的功能也非常简单:累计计数

通过 write() 函数,我们可以向 eventfd 中写入一个 int 类型的值,并且,只要没有发生 读 操作,eventfd 中保存的值将会一直累加

通过 read() 函数可以将 eventfd 保存的值读了出来,并且,在没有新的值加入之前,再次调用 read() 方法会发生阻塞,直到有人重新向 eventfd 写入值

只要 eventfd 计数不为 0 ,那么表示 fd 是可读的。再结合 epoll 的特性,我们可以非常轻松的创建出 生产者/消费者模型

epoll + eventfd 作为消费者大部分时候处于阻塞休眠状态,而一旦有请求入队(eventfd 被写入值),消费者就立刻唤醒处理,Handler 机制的底层逻辑就是利用 epoll + eventfd

Native Handler流程简述

关注 MessageQueue 类中的几个 jni 方法:nativeInit()、nativePollOnce() 和 nativeWake()
对应了 Native 消息队列中的 初始化消息队列、 消息的循环与阻塞 以及 消息的分送与唤醒 这三大环节

消息队列的初始化流程

Looper 的构造函数首先创建了 eventfd 对象 :mWakeEventFd,它的作用就是用来监听 MessageQueue 是否有新消息加入,

1.Java 层初始化消息队列时,同步调用 nativeInit() 方法,在 native 层创建了一个 NativeMessageQueue 对象
2.Native 层的消息队列被创建的同时,也会创建一个 Native Looper 对象
3.在 Native Looper 构造函数中,调用 eventfd() 生成 mWakeEventFd,它是后续用于唤醒消息队列的核心
4. 最后调用 rebuildEpollLocked() 方法,初始化了一个 epoll 实例 mEpollFd ,然后将 mWakeEventFd 注册到 epoll 池

Native 层的消息队列初始化完成,Looper 对象持有 mEpollFd 和 mWakeEventFd 两大金刚

消息的循环与阻塞

消息队列在初始化成功以后,Java 层的 Looper#loop() 会开始无限轮询,不停的获取下一条消息。如果消息队列为空,调用 epoll_wait 使线程进入到阻塞态,让出 CPU 调度

pollOnce() 会不停的轮询 pollInner() 方法,检查它的的返回值 result

这里的 result 类型是在 Looper.h 文件中声明的枚举类,一共有4种结果:

-1 表示在 “超时时间到期” 之前使用 wake() 唤醒了轮询,通常是有需要立刻执行的新消息加入了队列
-2 表示多个事件同时发生,有可能是新消息加入,也有可能是监听的 自定义 fd 发生了 I/O 事件
-3 表示设定的超时时间到期了
-4 表示错误,不知道哪里会用到

从 Java 到 Native 整个调用流程大致是这样的:

Looper#loop()
    -> MessageQueue#next()
        -> MessageQueue#nativePollOnce()
            -> NativeMessageQueue#pollOnce() //注意,进入 Native 层
                -> Looper#pollOnce()
                    -> Looper#pollInner()
                        -> epoll_wait()

消息的发送/唤醒机制流程

用户线程阻塞到了 native 层的 Looper#pollInner() 方法
Java 开发使用 Handler#sendMessage() / post(),C/C++ 开发使用 Looper#sendMessage()

使用 Handler 发送消息时,不管调用的是 sendMessage 还是 post,最后都是调用到 MessageQueue#enqueueMessage() 方法将消息入列,入列的顺序是按照执行时间先后排序

流程:

1.Java 层发送消息,调用 MessageQueue#enqueueMessage() 方法,如果消息需要马上执行,那么调用 nativeWake() 执行唤醒
2.Native 层发送消息,调用 Looper#sentMessageAtTime() 方法,处理逻辑与 Java 类似,如果需要唤醒线程,调用 Looper#wake()
3.Looper#wake() 唤醒方法很简单,向 mWakeEventFd 写入 1
4.初始化队列 时为 mWakeEventFd 注册了 epoll 监听,所以一旦有来自于 mWakeEventFd 的新内容, epoll_wait() 阻塞调用就会返回,这里就已经起到了唤醒队列的作用

唤醒后消息的分发处理

线程在没有消息需要处理时会阻塞在 Looper 中的 pollInner() 方法调用,线程唤醒以后同样也是在 pollInner() 方法中继续执行

线程醒来以后,先判断自己为什么醒过来,再根据唤醒类型执行不同的逻辑

step 1 : epoll_wait 方法返回说明有事件发生,返回值 eventCount 是发生事件的数量。如果为0,表示达到设定的超时时间,下面的判断逻辑都不会走,不为0,那么我们开始遍历内核返回的事件集合 eventItems,根据类型执行不同的逻辑

step 2 : 如果事件类型是消息队列的 eventfd ,说明有人向消息队列提交了需要马上执行的消息,我们只需把消息队列的 eventfd 数据读出来,使他重新变成可以触发 可读事件 的 fd,然后等待方法结束就行了

step 3 : 事件不是消息队列的 eventfd ,说明有其他地方注册了监听 fd,那么,我们将发生的事件保存到 mResponses 集合中,待会需要对这个事件做出响应,通知注册对象

step 4 : 遍历 Native 的消息集合 mMessageEnvelopes,检查每个消息的到期时间,如果消息到期了,交给 handler 执行分发,分发逻辑参考 Java Handler

step 5 : 遍历 mResponses 集合,把其他地方注册的 自定义 fd 消费掉,响应它们的回调方法

流程总结:

用户线程被唤醒后,优先分发 Native 层的消息,紧接着,通知 自定义 fd 发生的事件(如果有的话),最后 pollInner() 方法结束,返回到 Java 层 Looper#loop() 方法执行到 Java 层的消息分发。只有当 Java Handler 执行完消息分发,一次 loop() 循环才算是完成

再之后,因为 Looper#loop() 是死循环,所以会马上再一次进入循环,继续调用 next() 方法获取消息、阻塞到 pollInner() 、从 pollInner() 唤醒执行分发,执行结束接着进入下一次循环,无尽的轮回

main 线程的一生都将重复这一流程,直到 APP 进程结束运行…

源码分析

基于android28源码,MessageQueue类里面涉及到多个native方法,除了MessageQueue的native方法,native层本身也有一套完整的消息机制,用于处理native的消息,如下图Native层的消息机制。

在这里插入图片描述

Java层可以向MessageQueue消息队列中添加消息,Native层也可以向MessageQueue消息队列中添加消息

MessageQueue

初始化过程的调用链如下:
在这里插入图片描述

在MessageQueue中的native方法如下:

 	private native static long nativeInit();
    private native static void nativeDestroy(long ptr);
    private native void nativePollOnce(long ptr, int timeoutMillis); /*non-static for callbacks*/
    private native static void nativeWake(long ptr);
    private native static boolean nativeIsPolling(long ptr);
    private native static void nativeSetFileDescriptorEvents(long ptr, int fd, int events);

nativeInit()

【1】 new MessageQueue()

==> MessageQueue.java

  MessageQueue(boolean quitAllowed) {
        mQuitAllowed = quitAllowed;
        mPtr = nativeInit();
    }

【2】android_os_MessageQueue_nativeInit()

==> android_os_MessageQueue.cpp

static jlong android_os_MessageQueue_nativeInit(JNIEnv* env, jclass clazz) {
	//初始化native消息队列 【3】
    NativeMessageQueue* nativeMessageQueue = new NativeMessageQueue();
    if (!nativeMessageQueue) {
        jniThrowRuntimeException(env, "Unable to allocate native queue");
        return 0;
    }

    nativeMessageQueue->incStrong(env);//增加引用计数
    return reinterpret_cast<jlong>(nativeMessageQueue);
}

此处reinterpret_cast是C++里的强制类型转换符。

【3】new NativeMessageQueue()

==> android_os_MessageQueue.cpp

NativeMessageQueue::NativeMessageQueue() :
        mPollEnv(NULL), mPollObj(NULL), mExceptionObj(NULL) {
    mLooper = Looper::getForThread();//获取TLS中的Looper对象
    if (mLooper == NULL) {
        mLooper = new Looper(false);//创建native层的Looper 【4】
        Looper::setForThread(mLooper);//保存native层的Looper到TLS
    }
}

Looper::getForThread(),功能类比于Java层的Looper.myLooper();
Looper::setForThread(mLooper),功能类比于Java层的ThreadLocal.set();

此处Native层的Looper与Java层的Looper没有任何的关系,只是在Native层重实现了一套类似功能的逻辑。

【4】new Looper()

==> Looper.cpp

Looper::Looper(bool allowNonCallbacks) :
        mAllowNonCallbacks(allowNonCallbacks), mSendingMessage(false),
        mPolling(false), mEpollFd(-1), mEpollRebuildRequired(false),
        mNextRequestSeq(0), mResponseIndex(0), mNextMessageUptime(LLONG_MAX) {
    mWakeEventFd = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC);//构造唤醒事件的fd
    LOG_ALWAYS_FATAL_IF(mWakeEventFd < 0, "Could not make wake event fd: %s",
                        strerror(errno));

    AutoMutex _l(mLock);
    rebuildEpollLocked();//重建Epoll事件【5】
}

上面是C++的语法,对类成员进行初始化

调用格式为“构造函数 : A(初始值),B(初始值),C(初始值)……”

【5】epoll_create/epoll_ctl
==> Looper.cpp

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
        close(mEpollFd);//关闭旧的epoll实例
    }

    // Allocate the new epoll instance and register the wake pipe.
    mEpollFd = epoll_create(EPOLL_SIZE_HINT);//创建新的epoll实例,并注册wake管道
    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 //把未使用的数据区域进行置0操作
    eventItem.events = EPOLLIN;//可读事件
    eventItem.data.fd = mWakeEventFd;
    //将唤醒事件(mWakeEventFd)添加到epoll实例(mEpollFd)
    int result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mWakeEventFd, & eventItem);
    LOG_ALWAYS_FATAL_IF(result != 0, "Could not add wake event fd to epoll instance: %s",
                        strerror(errno));

    for (size_t i = 0; i < mRequests.size(); i++) {
        const Request& request = mRequests.valueAt(i);
        struct epoll_event eventItem;
        request.initEventItem(&eventItem);
		 //将request队列的事件,分别添加到epoll实例
        int epollResult = epoll_ctl(mEpollFd, 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));
        }
    }
}

函数说明:
1.epoll_create
创建epoll句柄epoll_create
int epfd = epoll_create(intsize);

创建一个epoll的句柄,size用来告诉内核这个监听的数目一共有多大。这个参数不同于select()中的第一个参数,给出最大监听的fd+1的值。需要注意的是,当创建好epoll句柄后,它就是会占用一个fd值,在linux下如果查看/proc/进程id/fd/,是能够看到这个fd的,所以在使用完epoll后,必须调用close()关闭,否则可能导致fd被耗尽。
函数声明:int epoll_create(int size)
该 函数生成一个epoll专用的文件描述符。它其实是在内核申请一空间,用来存放你想关注的socket fd上是否发生以及发生了什么事件。size就是你在这个epoll fd上能关注的最大socket fd数。随你定好了。只要你有空间。

Looper对象中的mWakeEventFd添加到epoll监控,以及mRequests也添加到epoll的监控范围内。

C 库函数 void *memset(void *str, int c, size_t n) 复制字符 c(一个无符号字符)到参数 str 所指向的字符串的前 n 个字符。

2.memset
声明
下面是 memset() 函数的声明。

void *memset(void *str, int c, size_t n)
参数
str – 指向要填充的内存块。
c – 要被设置的值。该值以 int 形式传递,但是函数在填充内存块时是使用该值的无符号字符形式。
n – 要被设置为该值的字节数。
返回值
该值返回一个指向存储区 str 的指针。

3.epoll_ctl
作用:将被监听的描述符添加到epoll句柄或从epool句柄中删除或者对监听事件进行修改。
函数声明:int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event)
该函数用于控制某个epoll文件描述符上的事件,可以注册事件,修改事件,删除事件。
参数:
epfd:由 epoll_create 生成的epoll专用的文件描述符;
op:要进行的操作例如注册事件,可能的取值EPOLL_CTL_ADD 注册、EPOLL_CTL_MOD 修 改、EPOLL_CTL_DEL 删除

fd:关联的文件描述符;
event:指向epoll_event的指针;
如果调用成功返回0,不成功返回-1

epoll的事件注册函数,它不同与select()是在监听事件时告诉内核要监听什么类型的事件,而是在这里先注册要监听的事件类型。

第一个参数是epoll_create()的返回值,
第二个参数表示动作,用三个宏来表示:
EPOLL_CTL_ADD: 注册新的fd到epfd中;
EPOLL_CTL_MOD: 修改已经注册的fd的监听事件;
EPOLL_CTL_DEL: 从epfd中删除一个fd;
第三个参数是需要监听的fd,
第四个参数是告诉内核需要监听什么事件,structepoll_event结构如下:

typedef union epoll_data {
void *ptr;
int fd;
__uint32_t u32;
__uint64_t u64;
} epoll_data_t;
 
struct epoll_event {
__uint32_t events; /* Epoll events */
epoll_data_t data; /* User data variable */
};

events可以是以下几个宏的集合:
EPOLLIN: 触发该事件,表示对应的文件描述符上有可读数据。(包括对端SOCKET正常关闭);
EPOLLOUT: 触发该事件,表示对应的文件描述符上可以写数据;
EPOLLPRI: 表示对应的文件描述符有紧急的数据可读(这里应该表示有带外数据到来);
EPOLLERR: 表示对应的文件描述符发生错误;
EPOLLHUP: 表示对应的文件描述符被挂断;
EPOLLET: 将EPOLL设为边缘触发(Edge Triggered)模式,这是相对于水平触发(Level Triggered)来说的。
EPOLLONESHOT: 只监听一次事件,当监听完这次事件之后,如果还需要继续监听这个socket的话,需要再次把这个socket加入到EPOLL队列里。

如:
struct epoll_event ev;
//设置与要处理的事件相关的文件描述符
ev.data.fd=listenfd;
//设置要处理的事件类型
ev.events=EPOLLIN|EPOLLET;
//注册epoll事件
epoll_ctl(epfd,EPOLL_CTL_ADD,listenfd,&ev);

Looper对象中的mWakeEventFd添加到epoll监控,以及mRequests也添加到epoll的监控范围内。

nativeDestroy()

清理回收的调用链如下:
在这里插入图片描述
下面来进一步来看看调用链的过程:

【1】MessageQueue.dispose()

==> MessageQueue.java

@Override
    protected void finalize() throws Throwable {
        try {
            dispose();
        } finally {
            super.finalize();
        }
    }

【2】android_os_MessageQueue_nativeDestroy()

==> android_os_MessageQueue.cpp

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

nativeMessageQueue继承自RefBase类,所以decStrong最终调用的是RefBase.decStrong().

【3】RefBase::decStrong()

==> RefBase.cpp

void RefBase::decStrong(const void* id) const
{
    weakref_impl* const refs = mRefs;
    refs->removeStrongRef(id);//移除强引用const int32_t c = refs->mStrong.fetch_sub(1, std::memory_order_release);
#if PRINT_REFS
    ALOGD("decStrong of %p from %p: cnt=%d\n", this, id, c);
#endif
    LOG_ALWAYS_FATAL_IF(BAD_STRONG(c), "decStrong() called on %p too many times",
            refs);
    if (c == 1) {
        std::atomic_thread_fence(std::memory_order_acquire);
        refs->mBase->onLastStrongRef(id);
        int32_t flags = refs->mFlags.load(std::memory_order_relaxed);
        if ((flags&OBJECT_LIFETIME_MASK) == OBJECT_LIFETIME_STRONG) {
            delete this;
            // The destructor does not delete refs in this case.
        }
    }
    // Note that even with only strong reference operations, the thread
    // deallocating this may not be the same as the thread deallocating refs.
    // That's OK: all accesses to this happen before its deletion here,
    // and all accesses to refs happen before its deletion in the final decWeak.
    // The destructor can safely access mRefs because either it's deleting
    // mRefs itself, or it's running entirely before the final mWeak decrement.
    //
    // Since we're doing atomic loads of `flags`, the static analyzer assumes
    // they can change between `delete this;` and `refs->decWeak(id);`. This is
    // not the case. The analyzer may become more okay with this patten when
    // https://bugs.llvm.org/show_bug.cgi?id=34365 gets resolved. NOLINTNEXTLINE
    refs->decWeak(id);// 移除弱引用
}

nativePollOnce()

nativePollOnce用于提取消息队列中的消息,提取消息的调用链,如下:
在这里插入图片描述
下面来进一步来看看调用链的过程:

【1】MessageQueue.next()

==> MessageQueue.java

Message next() {
    final long ptr = mPtr;
    if (ptr == 0) {
        return null;
    }

    for (;;) {
        ...
        nativePollOnce(ptr, nextPollTimeoutMillis); //阻塞操作 【2】
        ...
    }

【2】android_os_MessageQueue_nativePollOnce()

==> android_os_MessageQueue.cpp

static void android_os_MessageQueue_nativePollOnce(JNIEnv* env, jobject obj,
        jlong ptr, jint timeoutMillis) {
     //将Java层传递下来的mPtr转换为nativeMessageQueue
    NativeMessageQueue* nativeMessageQueue = reinterpret_cast<NativeMessageQueue*>(ptr);
    nativeMessageQueue->pollOnce(env, obj, timeoutMillis);
}

【3】NativeMessageQueue::pollOnce()

void NativeMessageQueue::pollOnce(JNIEnv* env, jobject pollObj, int timeoutMillis) {
    mPollEnv = env;
    mPollObj = pollObj;
    mLooper->pollOnce(timeoutMillis);4】
    mPollObj = NULL;
    mPollEnv = NULL;

    if (mExceptionObj) {
        env->Throw(mExceptionObj);
        env->DeleteLocalRef(mExceptionObj);
		mExceptionObj = NULL;
    }
}

【4】Looper::pollOnce()

==> Looper.h

inline int pollOnce(int timeoutMillis) {
    return pollOnce(timeoutMillis, NULL, NULL, NULL);5}

【5】 Looper::pollOnce()

==> Looper.cpp

int Looper::pollOnce(int timeoutMillis, int* outFd, int* outEvents, void** outData) {
    int result = 0;
    for (;;) {
    	// 先处理没有Callback方法的 Response事件
        while (mResponseIndex < mResponses.size()) {
            const Response& response = mResponses.itemAt(mResponseIndex++);
            int ident = response.request.ident;
            if (ident >= 0) {//ident大于0,则表示没有callback, 因为POLL_CALLBACK = -2,
                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 != NULL) *outFd = fd;
                if (outEvents != NULL) *outEvents = events;
                if (outData != NULL) *outData = data;
                return ident;
            }
        }

        if (result != 0) {
#if DEBUG_POLL_AND_WAKE
            ALOGD("%p ~ pollOnce - returning result %d", this, result);
#endif
            if (outFd != NULL) *outFd = 0;
            if (outEvents != NULL) *outEvents = 0;
            if (outData != NULL) *outData = NULL;
            return result;
        }
		// 再处理内部轮询
        result = pollInner(timeoutMillis);
    }
}

参数说明:

timeoutMillis:超时时长
outFd:发生事件的文件描述符
outEvents:当前outFd上发生的事件,包含以下4类事件
EVENT_INPUT 可读
EVENT_OUTPUT 可写
EVENT_ERROR 错误
EVENT_HANGUP 中断
outData:上下文数据

【6】Looper::pollInner()

==> Looper.cpp

int Looper::pollInner(int timeoutMillis) {
    ...
    int result = POLL_WAKE;
    mResponses.clear();
    mResponseIndex = 0;
    mPolling = true; //即将处于idle状态
    struct epoll_event eventItems[EPOLL_MAX_EVENTS]; //fd最大个数为16
    //等待事件发生或者超时,在nativeWake()方法,向管道写端写入字符,则该方法会返回;
    int eventCount = epoll_wait(mEpollFd, eventItems, EPOLL_MAX_EVENTS, timeoutMillis);

    mPolling = false; //不再处于idle状态
    mLock.lock();  //请求锁
    if (mEpollRebuildRequired) {
        mEpollRebuildRequired = false;
        rebuildEpollLocked();  // epoll重建,直接跳转Done;
        goto Done;
    }
    if (eventCount < 0) {
        if (errno == EINTR) {
            goto Done;
        }
        result = POLL_ERROR; // epoll事件个数小于0,发生错误,直接跳转Done;
        goto Done;
    }
    if (eventCount == 0) {  //epoll事件个数等于0,发生超时,直接跳转Done;
        result = POLL_TIMEOUT;
        goto Done;
    }

    //循环遍历,处理所有的事件
    for (int i = 0; i < eventCount; i++) {
        int fd = eventItems[i].data.fd;
        uint32_t epollEvents = eventItems[i].events;
        if (fd == mWakeEventFd) {
            if (epollEvents & EPOLLIN) {
                awoken(); //已经唤醒了,则读取并清空管道数据【7】
            }
        } 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;
                //处理request,生成对应的reponse对象,push到响应数组
                pushResponse(events, mRequests.valueAt(requestIndex));
            }
        }
    }
Done: ;
    //再处理Native的Message,调用相应回调方法
    mNextMessageUptime = LLONG_MAX;
    while (mMessageEnvelopes.size() != 0) {
        nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
        const MessageEnvelope& messageEnvelope = mMessageEnvelopes.itemAt(0);
        if (messageEnvelope.uptime <= now) {
            {
                sp<MessageHandler> handler = messageEnvelope.handler;
                Message message = messageEnvelope.message;
                mMessageEnvelopes.removeAt(0);
                mSendingMessage = true;
                mLock.unlock();  //释放锁
                handler->handleMessage(message);  // 处理消息事件
            }
            mLock.lock();  //请求锁
            mSendingMessage = false;
            result = POLL_CALLBACK; // 发生回调
        } else {
            mNextMessageUptime = messageEnvelope.uptime;
            break;
        }
    }
    mLock.unlock(); //释放锁

    //处理带有Callback()方法的Response事件,执行Reponse相应的回调方法
    for (size_t i = 0; i < mResponses.size(); i++) {
        Response& response = mResponses.editItemAt(i);
        if (response.request.ident == POLL_CALLBACK) {
            int fd = response.request.fd;
            int events = response.events;
            void* data = response.request.data;
            // 处理请求的回调方法
            int callbackResult = response.request.callback->handleEvent(fd, events, data);
            if (callbackResult == 0) {
                removeFd(fd, response.request.seq); //移除fd
            }
            response.request.callback.clear(); //清除reponse引用的回调方法
            result = POLL_CALLBACK;  // 发生回调
        }
    }
    return result;
}

pollOnce返回值说明:

POLL_WAKE: 表示由wake()触发,即pipe写端的write事件触发;
POLL_CALLBACK: 表示某个被监听fd被触发。
POLL_TIMEOUT: 表示等待超时;
POLL_ERROR:表示等待期间发生错误;

【7】Looper::awoken()

void Looper::awoken() {
    uint64_t counter;
    //不断读取管道数据,目的就是为了清空管道内容
    TEMP_FAILURE_RETRY(read(mWakeEventFd, &counter, sizeof(uint64_t)));
}

poll小结

pollInner()方法的处理流程:

1.先调用epoll_wait(),这是阻塞方法,用于等待事件发生或者超时;

2.对于epoll_wait()返回,当且仅当以下3种情况出现:
1)POLL_ERROR,发生错误,直接跳转到Done;
2)POLL_TIMEOUT,发生超时,直接跳转到Done;
3)检测到管道有事件发生,则再根据情况做相应处理:
如果是管道读端产生事件,则直接读取管道的数据;
如果是其他事件,则处理request,生成对应的reponse对象,push到reponse数组;

3.进入Done标记位的代码段:
先处理Native的Message,调用Native 的Handler来处理该Message;
再处理Response数组,POLL_CALLBACK类型的事件;

nativeWake()

nativeWake用于唤醒功能,在添加消息到消息队列enqueueMessage(), 或者把消息从消息队列中全部移除quit(),再有需要时都会调用 nativeWake方法。包含唤醒过程的添加消息的调用链,如下:

在这里插入图片描述
下面来进一步来看看调用链的过程:

【1】MessageQueue.enqueueMessage()

==> MessageQueue.java

boolean enqueueMessage(Message msg, long when) {
    ... //将Message按时间顺序插入MessageQueue
    if (needWake) {
            nativeWake(mPtr);2}
}

往消息队列添加Message时,需要根据mBlocked情况来决定是否需要调用nativeWake。

【2】android_os_MessageQueue_nativeWake()

==> android_os_MessageQueue.cpp

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

【3】NativeMessageQueue::wake()

==> android_os_MessageQueue.cpp

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

【4】Looper::wake()

==> Looper.cpp

void Looper::wake() {
    uint64_t inc = 1;
    // 向管道mWakeEventFd写入字符1
    ssize_t nWrite = TEMP_FAILURE_RETRY(write(mWakeEventFd, &inc, sizeof(uint64_t)));
    if (nWrite != sizeof(uint64_t)) {
        if (errno != EAGAIN) {
            ALOGW("Could not write wake signal, errno=%d", errno);
        }
    }
}

其中TEMP_FAILURE_RETRY 是一个宏定义, 当执行write失败后,会不断重复执行,直到执行成功为止。

sendMessage

讲述了Java层如何向MessageQueue类中添加消息,那么接下来讲讲Native层如何向MessageQueue发送消息。

【1】sendMessage

void Looper::sendMessage(const sp<MessageHandler>& handler, const Message& message) {
    nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
    sendMessageAtTime(now, handler, message);
}

【2】sendMessageDelayed

void Looper::sendMessageDelayed(nsecs_t uptimeDelay, const sp<MessageHandler>& handler,
        const Message& message) {
    nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
    sendMessageAtTime(now + uptimeDelay, handler, message);
}

sendMessage(),sendMessageDelayed() 都是调用sendMessageAtTime()来完成消息插入。

【3】sendMessageAtTime

void Looper::sendMessageAtTime(nsecs_t uptime, const sp<MessageHandler>& handler,
        const Message& message) {
    size_t i = 0;
    { //请求锁
        AutoMutex _l(mLock);
        size_t messageCount = mMessageEnvelopes.size();
        //找到message应该插入的位置i
        while (i < messageCount && uptime >= mMessageEnvelopes.itemAt(i).uptime) {
            i += 1;
        }
        MessageEnvelope messageEnvelope(uptime, handler, message);
        mMessageEnvelopes.insertAt(messageEnvelope, i, 1);
        //如果当前正在发送消息,那么不再调用wake(),直接返回。
        if (mSendingMessage) {
            return;
        }
    } //释放锁
    //当把消息加入到消息队列的头部时,需要唤醒poll循环。
    if (i == 0) {
        wake();
    }
}

MessageQueue的native()方法,经过层层调用:

1.nativeInit()方法:

创建了NativeMessageQueue对象,增加其引用计数,并将NativeMessageQueue指针mPtr保存在Java层的MessageQueue
创建了Native Looper对象
调用epoll的epoll_create()/epoll_ctl()来完成对mWakeEventFd和mRequests的可读事件监听

2.nativeDestroy()方法

调用RefBase::decStrong()来减少对象的引用计数
当引用计数为0时,则删除NativeMessageQueue对象

3.nativePollOnce()方法

调用Looper::pollOnce()来完成,空闲时停留在epoll_wait()方法,用于等待事件发生或者超时

4.nativeWake()方法

调用Looper::wake()来完成,向管道mWakeEventfd写入字符;

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

进击的代码家

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值