7.2.3 创建Native层的NativeMessageQueue和Looper对象
首先分析NativeMessageQueue的创建过程,定位到其构造函数,代码如下:
NativeMessageQueue:NativeMessageQueue():mInCallback(false),mExceptionObj(NULL){
mLooper=Looper:getForThread();
if(mLooper==NULL){
mLooper=new Looper(false);//在Native层创建了Looper对象
Looper:setForThread(mLooper);
}
}
在NativeMessageQueue的构造函数中,首先调用Looper的getForThread方法,查询当前线程是否存在一个Looper对象,如果不存在,则创建一个Looper对象,并将其设置到成员变量mLooper中。NativeMessageQueue的成员变量mLooper继承自父类MessageQueue。
下面分析getForThread方法,其位于/frameworks/native/libs/utils/Looper.cpp中,代码如下:
static pthread_once_t gTLSOnce=PTHREAD_ONCE_INIT;
static pthread_key_t gTLSKey=0;
……
void Looper:initTLSKey(){
/*pthread_key_create用于创建线程局部变量gTLSKey,参数threadDestructor
用于指定该局部对象的释放处理函数/
int result=pthread_key_create(&gTLSKey, threadDestructor);
}
void Looper:threadDestructor(void*st){//释放处理函数
Looperconst self=static_cast<Looper>(st);
if(self!=NULL){
self->decStrong((void*)threadDestructor);
}
}
……
sp<Looper>Looper:getForThread(){
//本线程只执行initTLSKey一次
int result=pthread_once(&gTLSOnce, initTLSKey);
return(Looper*)pthread_getspecific(gTLSKey);
}
在getForThread方法中首先调用了pthread_once方法,传入的参数分别是gTLSOnce和initTLSKey。参数gTLSOnce是pthread_once_t类型的变量,其值为PTHREAD_ONCE_INIT;参数initTLSKey指代Looper的initTLSKey()函数。在Linux线程模型中,PTHREAD_ONCE_INIT用于指明initTLSKey函数只在本线程中运行一次。假设之前没有运行initTLSKey函数,因此进入该函数执行pthread_key_create方法创建线程局部对象,然后从initTLSKey函数中返回到getForThread函数,在该函数中通过pthread_getspecific函数返回该线程局部对象中存储的Looper对象。此时将从getForThread函数中返回到NativeMessageQueue的构造函数中,在构造函数中会判断返回的对象是否为NULL,如果为NULL,会创建一个Looper对象,并调用Looper的setForThread函数将新创建的Looper对象存入线程局部对象中。
setForThread的代码如下:
void Looper:setForThread(const sp<Looper>&looper){
sp<Looper>old=getForThread();//查询是否已经有一个Looper对象
if(looper!=NULL){//增加引用计数
looper->incStrong((void*)threadDestructor);
}
//将新的Looper对象设置到线程局部对象中
pthread_setspecific(gTLSKey, looper.get());
//将旧的Looper对象减少引用计数,以便销毁
if(old!=NULL){
old->decStrong((void*)threadDestructor);
}
}
综上所述,创建NativeMessageQueue对象的同时,还在JNI层创建了一个线程局部且线程唯一的Looper对象。因此创建NativeMessageQueue对象所实现的功能与Java层的Looper.prepare()方法实现的功能是一样的。
分析到这里,我们似乎忽略了一个问题:JNI层的Looper对象的创建过程与Java层的Looper对象创建过程是一样的吗?
接下来分析Native层Looper的创建过程,其位于frameworks/native/libs/utils/Looper.cpp中,代码如下:
Looper:Looper(bool allowNonCallbacks):
mAllowNonCallbacks(allowNonCallbacks),mSendingMessage(false),
mResponseIndex(0),mNextMessageUptime(LLONG_MAX){
int wakeFds[2];
//创建一个管道,管道的读写两端分别用wakeFds[0]和wakeFds[1]表示
int result=pipe(wakeFds);
mWakeReadPipeFd=wakeFds[0];//管道读端
mWakeWritePipeFd=wakeFds[1];//管道写端
//给读管道设置非阻塞(O_NONBLOCK)的flag,保证在无数据可读的情况下可以立即返回而不会阻塞
result=fcntl(mWakeReadPipeFd, F_SETFL, O_NONBLOCK);
//给写管道设置非阻塞(O_NONBLOCK)的flag,保证在没有缓冲区可写的情况下可以立即返回而不阻塞
result=fcntl(mWakeWritePipeFd, F_SETFL, O_NONBLOCK);
//使用epoll机制监听管道
mEpollFd=epoll_create(EPOLL_SIZE_HINT);
//定义监听的事件
struct epoll_event eventItem;
memset(&eventItem,0,sizeof(epoll_event));
//监听EPOLLIN类型的事件,该事件表示对应的文件描述符上有数据可读
eventItem.events=EPOLLIN;
eventItem.data.fd=mWakeReadPipeFd;
//注册监听事件,这里只监听mWakeReadPipeFd
result=epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mWakeReadPipeFd,&eventItem);
}
可见Native层的Looper与Java层的Looper是完全不一样的。