AndroidQ Handler消息机制(native层)

本篇接着AndroidQ Handle消息机制(java层)分析native层的相关实现,我们一般了解handler的都知道在有消息的时候取出消息进行处理,没有消息则陷入休眠,但我们从上一篇并没有看到哪里有明显的睡眠和唤醒,其实这都是在native层实现的,可以说handler消息机制的核心就在native层,所以我们这篇文章来看看native的实现细节

MessageQueue中有许多的native方法,我们这篇文章主要分析nativeInitnativePollOncenativeWake

    private native static long nativeInit();
    private native static void nativeDestroy(long ptr);
    @UnsupportedAppUsage
    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);

在MessageQueue初始化时构造方法中调用了nativeInit,我们首先来看看这个方法:

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

通过JNI到native层

android_os_MessageQueue.cpp

static jlong android_os_MessageQueue_nativeInit(JNIEnv* env, jclass clazz) {
	//创建NativeMessageQueue
    NativeMessageQueue* nativeMessageQueue = new NativeMessageQueue();
    if (!nativeMessageQueue) {
        jniThrowRuntimeException(env, "Unable to allocate native queue");
        return 0;
    }
	//增加强引用
    nativeMessageQueue->incStrong(env);
    //将nativeMessageQueue返回到java层保存在mPtr中
    return reinterpret_cast<jlong>(nativeMessageQueue);
}

NativeMessageQueue构造函数

NativeMessageQueue::NativeMessageQueue() :
        mPollEnv(NULL), mPollObj(NULL), mExceptionObj(NULL) {
    //获取当前线程的Looper对象
    mLooper = Looper::getForThread();
    //如果没有则创建Looper
    if (mLooper == NULL) {
        mLooper = new Looper(false);
        Looper::setForThread(mLooper);
    }
}

此处的getForThread,setForThread和java ThreadLocal的set,get同样的作用,Looper属于线程私有,注意native层的Looper和java层的Looper是两个东西,并没有关系

Looper.cpp

Looper.cpp在system目录下,不在framework目录下

Looper::Looper(bool allowNonCallbacks)
      : mAllowNonCallbacks(allowNonCallbacks),
        mSendingMessage(false),
        mPolling(false),
        mEpollRebuildRequired(false),
        mNextRequestSeq(0),
        mResponseIndex(0),
        mNextMessageUptime(LLONG_MAX) {
        //创建一个唤醒事件fd
      mWakeEventFd.reset(eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC));
      LOG_ALWAYS_FATAL_IF(mWakeEventFd.get() < 0, "Could not make wake event fd: %s", strerror(errno));
  
      AutoMutex _l(mLock);
      //重建epoll
      rebuildEpollLocked();
  }

Looper构造函数中做了两件事,1.调用eventfd创建mWakeEventFd,2.调用rebuildEpollLocked重建epoll

eventfd是Linux提供的一种系统调用,可以用来实现事件通知,通过调用eventfd会返回一个文件描述符,利用IO多路复用机制epoll可以监听该描述符,实现线程间等待/通知

rebuildEpollLocked

void Looper::rebuildEpollLocked() {
      //如果有旧的epoll则先关闭掉
      if (mEpollFd >= 0) {
          mEpollFd.reset();
      }
  
      //创建epoll并注册wake管道
      mEpollFd.reset(epoll_create1(EPOLL_CLOEXEC));
		
      struct epoll_event eventItem;
      memset(& eventItem, 0, sizeof(epoll_event)); // zero out unused members of data field union
      //epoll事件为可读事件
      eventItem.events = EPOLLIN;
      //将创建的唤醒事件的fd设置到eventItem
      eventItem.data.fd = mWakeEventFd.get();
      //epoll_ctl将mWakeEventFd添加到创建的mEpollFd进行监听
      int result = epoll_ctl(mEpollFd.get(), EPOLL_CTL_ADD, mWakeEventFd.get(), &eventItem);
      
  	  //这里遍历mRequests,将其他的事件,如Input,键盘等也添加到epoll进行
  	  //监听,mRequests中的fd是通过调用Looper.addFd添加的,
  	  //这些事件和Handler消息机制没有关系
      for (size_t i = 0; i < mRequests.size(); i++) {
          const Request& request = mRequests.valueAt(i);
          struct epoll_event eventItem;
          request.initEventItem(&eventItem);
  		  //epoll_ctl方法用作添加fd到epoll进行监听
          int epollResult = epoll_ctl(mEpollFd.get(), EPOLL_CTL_ADD, request.fd, &eventItem);
          if (epollResult < 0) {
              	....//error
          }
      }
  }

在rebuildEpollLocked方法中,通过epoll机制,来实现线程间的等待与唤醒操作,Linux系统的epoll机制可以监听大批量的fd,其效率远远强于select/poll,epoll除了监听通过eventfd创建的唤醒文件描述符外,还可以监控其他的文件描述符,native层的Looper提供了addFd接口来添加文件描述符到Looper对象中,当这些被监控的文件描述符上有事情发生时,就会唤醒相应的线程来处理,比如在Input系统中UI线程和InputDispatcher线程的Looper都会调用addFd分别将InputChannel的客户端socket和服务端socket添加到各自的epoll进行监听,以便进行通信从而实现事件分发和处理

epoll机制是包含了epoll_create、epoll_create1、epoll_ctl和epoll_wait这几个方法

epoll_create1
功能:epoll_create1(EPOLL_CLOEXEC)
创建一个epoll的实例 参数接收一个flag值,如果传入0就等价于epoll_create(0)
EPOLL_CLOEXEC:如果这个参数设置为这个,那么当进程替换映像的时候会关闭这个文件描述符,这样新的映像中就无法对这个文件描述符操作,适用于多进程编程+映像替换的环境里。
返回值:
success:返回一个非0 的未使用过的最小的文件描述符
error:-1

epoll_ctl:
int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
对文件描述符进行操作
参数:
epfd:epoll_create1的返回值
op:执行的命令
EPOLL_CTL_ADD:向epoll实例中添加一个的文件描述符来监听
EPOLL_CTL_MOD:改变epoll实例中的一个文件描述符
EPOLL_CTL_DEL:移除epoll实例中的一个文件描述符的监听
fd:要操作的文件描述符
epoll_event:需要监听的事件

epoll_wait:
int epoll_wait(int epfd, struct epoll_event * events, int maxevents, int timeout);
功能:等待事件的上报
epfd:等待epfd上的io事件,最多返回maxevents个事件;
events:用来从内核得到事件的集合;
maxevents:events数量,该maxevents值不能大于创建epoll_create()时的size;
timeout:超时时间(毫秒,0会立即返回)。
该函数返回需要处理的事件数目,如返回0表示已超时

nativeInit函数已经分析完毕,主要做的事情就是创建NativeMessageQueue,在NativeMessageQueue中创建线程私有Looper,在Looper构造函数中创建唤醒事件的fd mWakeEventFd,并创建epoll,将mWakeEventFd添加到epoll进行监听,此fd用来唤醒handler机制中MessageQueue的阻塞状态

接着分析nativePollOnce方法,此方法在MessageQueue.next中调用

Message next() {
    final long ptr = mPtr;
    if (ptr == 0) {
        return null;
    }
    for (;;) {
        ...
        nativePollOnce(ptr, nextPollTimeoutMillis);
        ...
    }

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

NativeMessageQueue->pollOnce

可以看到直接调用了Looper的pollOnce方法,注意这个timeoutMillis,是java层传递下来的,代表下一个msg的执行时间

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

mLooper->pollOnce

int Looper::pollOnce(int timeoutMillis, int* outFd, int* outEvents, void** outData) {
      int result = 0;
      for (;;) {
      		// 先处理没有Callback的Response事件
          while (mResponseIndex < mResponses.size()) {
	             ....
          }
  			//待后面pollInner返回不为0的result后退出循环
          if (result != 0) {
              if (outFd != nullptr) *outFd = 0;
              if (outEvents != nullptr) *outEvents = 0;
              if (outData != nullptr) *outData = nullptr;
              return result;
          }
  		  //核心方法
          result = pollInner(timeoutMillis);
      }
  }

Looper::pollInner()

int Looper::pollInner(int timeoutMillis) {
    // 调整msg的处理时间,timeoutMillis != 0有两种情况,一是=-1,表明java层
    //此时没有msg,二是msg正常延迟执行的时间,mNextMessageUptime代表native
    //层的msg的执行时间
    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;
        }
		
    }
		......

    struct epoll_event eventItems[EPOLL_MAX_EVENTS];
    //调用epoll_wait进入等待状态,返回值是epoll上监听的事件上报的数量
    //epoll_wait返回有三种情况:1.有事件上报,2.timeoutMillis时间到了
    //3.发生错误
    int eventCount = epoll_wait(mEpollFd.get(), eventItems, EPOLL_MAX_EVENTS, timeoutMillis);
    	
    	......
    	//发生异常
    if (eventCount < 0) {
        if (errno == EINTR) {
            goto Done;
        }
        result = POLL_ERROR;
        goto Done;
    }

    // 超时唤醒
    if (eventCount == 0) {
        result = POLL_TIMEOUT;
        goto Done;
    }

    //当有事件上报则遍历处理所有事件,eventCount为上报的数量
    for (int i = 0; i < eventCount; i++) {
        int fd = eventItems[i].data.fd;
        uint32_t epollEvents = eventItems[i].events;
        //如果是唤醒事件
        if (fd == mWakeEventFd.get()) {
            if (epollEvents & EPOLLIN) {
            	//则清空管道数据,这里就是直接调用read(mWakeEventFd...)
            	//将write(mWakeEventFd...)的数据读取出来,以便下次能够再次
            	//阻塞
                awoken();
            } else {
                	...
            }
        } 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;
                //先将时间push进mResponses中,此处并未处理事件
                pushResponse(events, mRequests.valueAt(requestIndex));
            } else {
                ...
            }
        }
    }
Done: ;

    //开始处理native层的msg,mMessageEnvelopes为msg容器,MessageEnvelope中
    //包含了msg的信息
    mNextMessageUptime = LLONG_MAX;
    while (mMessageEnvelopes.size() != 0) {
        nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
        const MessageEnvelope& messageEnvelope = mMessageEnvelopes.itemAt(0);
        //messageEnvelope.uptime和java层的msg的when一样的作用,代表
        //msg处理的时间
        if (messageEnvelope.uptime <= now) {
            
            { // obtain handler
                sp<MessageHandler> handler = messageEnvelope.handler;
                Message message = messageEnvelope.message;
                mMessageEnvelopes.removeAt(0);
                mSendingMessage = true;
                mLock.unlock();

				//使用handler处理消息
                handler->handleMessage(message);
            } // release handler

            mLock.lock();
            mSendingMessage = false;
            result = POLL_CALLBACK;
        } else {
        	//此消息不是立即处理的,则将时间更新到mNextMessageUptime中
            mNextMessageUptime = messageEnvelope.uptime;
            break;
        }
    }

    mLock.unlock();

    //处理前面添加的requests
    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;
			...
			//核心代码,待用requests的callback的handleEvent函数
            int callbackResult = response.request.callback->handleEvent(fd, events, data);
            if (callbackResult == 0) {
                removeFd(fd, response.request.seq);
            }
			
            response.request.callback.clear();
            result = POLL_CALLBACK;
        }
    }
    //将处理结果返回回去
    return result;
}

pollInner返回值有四个: enum {
//通过wake()唤醒epoll_wait
POLL_WAKE = -1,
//某个fd被触发唤醒epoll_wait
POLL_CALLBACK = -2,
//超时唤醒epoll_wait
POLL_TIMEOUT = -3,
//发生错误唤醒epoll_wait
POLL_ERROR = -4,
};

pollInner函数已经分析完毕,作一个总结:

  1. 视情况对timeoutMillis进行重置,timeoutMillis这个时间代表着epoll_wait被唤醒的时间,timeoutMillis有java层和native层的mNextMessageUptime共同决定,说明epoll_wait的唤醒由java层和native层共同决定
  2. 调用epoll_wait进入等待状态,三种情况能够唤醒epoll_wait,(1)epoll监听的fd被触发,(2)超时唤醒,(3)发生错误被唤醒
  3. 在epoll_wait被fd触发唤醒之后执行相应的操作,(1)如果是mWakeEventFd则清空管道,(2)如果是其他fd,则将其request添加到Response待稍后处理
  4. 开始处理native的msg和调用request的callback

pollInner函数处理完native层的msg和request后就返回了java层,接着处理java层的msg,这就是handler消息机制msg处理的优先级

最后我们再来看看nativeWake这个函数,nativeWake作用是唤醒MessageQueue,使得Looper能够继续获取消息处理

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

mLooper->wake()

void Looper::wake() {
    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));
        }
    }
}

TEMP_FAILURE_RETRY是一个宏,作用是失败之后重复尝试,这里就是向mWakeEventFd中写入字符,起到通知的作用,前面已经分析过,在nativeInit中创建Looper对象时创建了mWakeEventFd,并在rebuildEpollLocked中将此fd添加到了epoll进行监听,所以当向mWakeEventFd写数据之后就会唤醒epoll_wait,以便能够返回到java层进行消息处理。

到这里我们已经分析完了native层的消息机制,作一个总结:

  1. java层的Looper创建时会创建MessageQueue,MessageQueue构造方法中调用nativeInit方法到native层,此方法主要作用是创建native层的MessageQueue,并创建native层的Looper,在Looper构造函数中创建了唤醒事件文件描述符mWakeEventFd,并调用rebuildEpollLocked函数创建epoll,epoll创建之后会添加mWakeEventFd以及mRequests中的所有fd进行监听
  2. java层Looper通过loop方法死循环调用MessageQueue的next方法获取msg,在next方法中会先调用nativePollOnce到native层去处理native的msg,首先会处理没有Callback方法的Response事件,接着调用pollInner函数,此函数里调用epoll_wait陷入等待,唤醒条件有三个:(1)超时唤醒,(2)发生异常唤醒,(3)收到事件上报,无论mWakeEventFd事件还是其他事件,epoll被唤醒后会根据eventCount事件数量遍历处理事件,处理顺序是,首先MessageEnvelope中的msg,其次mResponses中的request的callback,最后返回java层,处理java的msg
  3. nativeWake用作唤醒epoll,简单的向mWakeEventFd写入一个字符,起到通知的作用

我们可以看出来java层的handler机制非常依赖native层的epoll和管道机制

发布了34 篇原创文章 · 获赞 48 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/qq_34211365/article/details/104376066