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是完全不一样的。