Android消息处理机制(Handler,Looper,MessageQueue和Message)

 原创英文链接

http://www.programering.com/a/MjM2QDMwATc.html


翻译版:

Android是一种消息驱动,消息驱动的几个要素:

    1. 消息说:消息
    2. 消息队列:MessageQueue
    3. 新闻周期,删除流通消息处理:Looper
    4. 消息处理,来自消息队列的消息循环消息应该在处理消息之后执行:Handler

  通常我们最常使用的是Message和Handler,如果你使用HandlerThread或类似的HandlerThread可能会接触到Looper,而在Looper内部使用MessageQueue,对于标准的SDK,我们无法实例化和使用(构造函数是包可见性) 。

  我们通常会接触到Looper,Message,Handler都是通过JAVA实现的,基于Linux的Android系统基于Android系统,底层存在C,C ++和NDK,消息驱动模型怎么只存在于JAVA层,实际上, Native层中对应于Java层,如Looper,MessageQueue。

初始化消息队列

  首先看一个线程是否应该实现消息循环,以HandlerThread为例:

public  void run(){
    mTid = Process.myTid();
    Looper.prepare();
    同步this ){
        mLooper = Looper.myLooper();
        notifyAll的();
    }
    Process.setThreadPriority(mPriority);
    onLooperPrepared();
    Looper.loop()
    mTid = -1 ;
} 

  是两个红色标记,第一次调用准备初始化MessageQueue和Looper,然后调用循环进入消息循环。首先看看Looper.prepare。

public  static  void prepare(){
    准备();
}

private  static  void prepare(boolean quitAllowed){
     if(sThreadLocal.get()!= null ){
         throw  new RuntimeException(“每个线程只能创建一个Looper” );
    }
    sThreadLocal.set(new Looper(quitAllowed));
}

  重载的函数,quitAllowed默认为true,从名称可以看出是否消息循环可以退出,默认是退出,主线程(UI线程)初始化消息循环称为prepareMainLooper,pass为false。使用ThreadLocal,每个线程都可以初始化一个Looper。

  在初始化中看看Looper:

私人 Looper(布尔quitAllowed){
    mQueue = new MessageQueue(quitAllowed);
    mRun = true ;
    mThread = Thread.currentThread();
}

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

  在Looper初始化中,创建一个MessageQueue对象保存在mQueue成员中。MessageQueue构造函数是包的可见性,所以我们不能直接使用,而MessageQueue初始化称为nativeInit,它是一个Native方法:

static  void android_os_MessageQueue_nativeInit(JNIEnv * env,jobject obj){
    NativeMessageQueue * nativeMessageQueue = new NativeMessageQueue();
    if(!nativeMessageQueue){
        jniThrowRuntimeException(env,无法分配本地队列);
        返回;
    }

    nativeMessageQueue - > incStrong(env);
    android_os_MessageQueue_setNativeMessageQueue(env,obj,nativeMessageQueue);
}

static  void android_os_MessageQueue_setNativeMessageQueue(JNIEnv * env,jobject messageQueueObj,
        NativeMessageQueue * nativeMessageQueue){
    env - > SetIntField(messageQueueObj,gMessageQueueClassInfo.mPtr,
             reinterpret_cast <jint> (nativeMessageQueue));
}

  在nativeInit中,Native层MessageQueue的新对象和存储在mPtr的MessageQueue成员的Java层中的地址中,有很多Android的实现,一个类已经在Java层和Native层中实现, GetFieldID和SetIntField JNI为本地层类保存了Java层的地址,以用于类mPtr成员(如Parcel)的实例。

  然后NativeMessageQueue的实现:

NativeMessageQueue :: NativeMessageQueue():mInCallback(false ),mExceptionObj(NULL){
    mLooper = Looper :: getForThread();
    if(mLooper == NULL){
        mLooper =  Looper(false );
        活套:: setForThread(mLooper);
    }
}

  获取NativeMessageQueue构造函数中的Looper对象的Native层,Native层Looper也使用线程本地存储,请注意,新Looper引入了参数false。

Looper :: Looper(bool allowNonCallbacks):
        mAllowNonCallbacks(allowNonCallbacks),mSendingMessage(false ),
        mResponseIndex(0 ),mNextMessageUptime(LLONG_MAX){
     int wakeFds [ 2 ];
    int result = pipe(wakeFds); 
    LOG_ALWAYS_FATAL_IF(result!= 0无法创建唤醒管道。errno =%d ,errno);

    mWakeReadPipeFd = wakeFds [0];
    mWakeWritePipeFd = wakeFds [1 ];

    result = fcntl(mWakeReadPipeFd,F_SETFL,O_NONBLOCK);
    LOG_ALWAYS_FATAL_IF(result!= 0无法使唤醒读取管道非阻塞。errno =%d 
            错误号);

    result = fcntl(mWakeWritePipeFd,F_SETFL,O_NONBLOCK);
    LOG_ALWAYS_FATAL_IF(result!= 0无法使唤醒写入管道非阻塞。errno =%d 
            错误号);

    // 分配epoll实例并注册唤醒管道。
   mEpollFd = epoll_create(EPOLL_SIZE_HINT); 
    LOG_ALWAYS_FATAL_IF(mEpollFd < 0无法创建epoll实例。errno =%d ,errno);

    struct epoll_event eventItem;
    memset(&eventItem,0sizeof(epoll_event)); // 将未使用的数据成员字段union 
    归零eventItem.events = EPOLLIN; 
    eventItem.data.fd = mWakeReadPipeFd;
    result = epoll_ctl(mEpollFd,EPOLL_CTL_ADD,mWakeReadPipeFd,&eventItem); 
    LOG_ALWAYS_FATAL_IF(result!= 0无法将唤醒读取管道添加到epoll实例。errno =%d 
            错误号);
}

  使用epoll的Looper中的本地图层。初始化一个管道,保留mWakeWritePipeFd和mWakeReadPipeFd以写入和读取管道末端,并监视EPOLLIN事件的读取结束。请注意初始化程序的值列表,mAllowNonCallbacks的值为false。

  什么是mAllowNonCallback?使用epoll监视mWakeReadPipeFd事件?实际上,Native Looper不仅可以监视描述符,Looper还提供addFd方法:

int addFd(int fd,int ident,int events,ALooper_callbackFunc callback,void * data);
int addFd(int fd,int ident,int events,const sp <LooperCallback>&callback,void * data);

  FD说监视描述符。Ident表示监视事件标识,Value必须>或ALOOPER_POLL_BACK; = 0(-2),Event表示监视事件,Callback是事件发生时的回调函数,这是mAllowNonCallbacks的作用,当mAllowNonCallbacks为true时,允许回调为NULL,Ident在pollOnce中作为返回结果,否则,不允许回调为空,当回调不为NULL时,ident的值将被忽略。或者只是看看易于理解的代码:

int Looper :: addFd(int fd,int ident,int events,const sp <LooperCallback>&callback,void * data){
 #if DEBUG_CALLBACKS 
    ALOGD(%p〜addFd  -  fd =%d,ident =%d,events = 0x%x,callback =%p,data =%p this ,fd,ident,
            事件,回调。get (),data);
#ENDIF 
    如果(!回调。获得()){
         如果(!mAllowNonCallbacks){
            ALOGE(无效尝试设置NULL回调但不允许此循环。);
            回报 - 1 ;
        }
        if(ident < 0 ){
            ALOGE(无效尝试设置NULL回调与身份<0。);
            回报 - 1 ;
        }
    } else {
        ident = ALOOPER_POLL_CALLBACK;
    }

    int epollEvents = 0 ;
    if(events&ALOOPER_EVENT_INPUT)epollEvents | = EPOLLIN;
    if(events&ALOOPER_EVENT_OUTPUT)epollEvents | = EPOLLOUT;

    { // 获取锁定
        AutoMutex _l(mLock);

        请求请求;
        request.fd = fd;
        request.ident = ident;
        request.callback = callback;
        request.data = data;

        struct epoll_event eventItem;
        memset(&eventItem,0sizeof(epoll_event)); // 清零未使用的数据成员字段union 
        unionItem.events = epollEvents;
        eventItem.data.fd = fd;

        ssize_t requestIndex = mRequests.indexOfKey(fd);
        if(requestIndex < 0 ){
             int epollResult = epoll_ctl(mEpollFd,EPOLL_CTL_ADD,fd,&eventItem);
            if(epollResult < 0 ){
                ALOGE(为fd%d添加epoll事件时出错,errno =%d ,fd,errno);
                回报 - 1 ;
            }
            mRequests.add(fd,request);
        } else {
             int epollResult = epoll_ctl(mEpollFd,EPOLL_CTL_MOD,fd,&eventItem);
            if(epollResult < 0 ){
                ALOGE(错误修改fd%d的epoll事件,errno =%d ,fd,errno);
                回报 - 1 ;
            }
            mRequests.replaceValueAt(requestIndex,request);
        }
    } // 释放锁定
    返回 1 ;
}

  如果回调为空,将检查是否允许mAllowNonCallbacks回调为空,如果回调为空则将确定ident> = 0。如果回调不是空的ALOOPER_POLL_CALLBACK的ident值,无论是什么值。

  然后将传入值的参数封装到一个Request结构中,并将描述符保存到一个KeyedVector的mRequests中,然后通过epoll_ctl添加或替换(如果描述符在调用addFD之前添加监听)对这个描述符的监听。

  类图:

  

发送一个消息

  通过Looper.prepare初始化后的消息队列可以在Looper.loop进入消息循环后调用,然后我们可以发送消息给消息队列,消息循环会将消息处理消除,在看到消息处理之前查看消息是如何被添加到消息队列中的。

  在Java层,Message类表示一个消息对象,发送消息时必须先获得一个消息对象,Message类的构造函数是public的,但不建议直接将new Message,Message存储在消息池的缓存中,我们可以从缓冲池得到一条消息,使用获得的消息,使用系统调用回收消息后,如果他们新增了很多消息,每次使用系统进入缓冲池后,都会占用大量的内存,如图所示下面:

    public  static Message get (){
         synchronized (sPoolSync){
             if(sPool!= null ){
                消息m = sPool;
                sPool = m.next;
                m.next = null ;
                sPoolSize - ;
                返回m;
            }
        }
        返回 新的消息();
    }

    public  void recycle(){
        clearForRecycle();

        synchronized (sPoolSync){
             if(sPoolSize < MAX_POOL_SIZE){
                next = sPool;
                sPool = this ;
                sPoolSize ++ ;
            }
        }
    }

  内部消息通过下一个成员实现列表,例如用于缓存消息列表的sPool。

  消息对象获取如何发送它,我们都知道是由Handler post,sendMessage和其他方法实现的,但这些方法最终都是通过sendMessageAtTime方法调用的:

    public  boolean sendMessageAtTime(Message msg,long uptimeMillis){
        MessageQueue队列 = mQueue;
        if(queue == null ){
            RuntimeException e = new RuntimeException(
                     this +“sendMessageAtTime()called no mQueue” );
            Log.w( “Looper” ,e.getMessage(),e);
            返回 false ;
        }
        返回enqueueMessage(队列,味精,uptimeMillis);
    } 

  SendMessageAtTime访问消息队列,然后调用enqueueMessage方法,mQueue从与Handler Looper关联的消息队列中获取。

    private  boolean enqueueMessage(MessageQueue queue,Message msg,long uptimeMillis){
        msg.target = this ;
        如果(mAsynchronous){
            msg.setAsynchronous(真);
        }
        返回queue.enqueueMessage(msg,uptimeMillis);
    }

  EnqueueMessage将消息目标设置为当前处理程序,然后调用MessageQueue enqueueMessage,在调用queue.enqueueMessage之前判断mAsynchronous,从名称是异步消息的手段,了解Asynchronous的作用,需要了解一个概念Barrier。

屏障和异步消息

  Barrier是什么意思,从名字来说是一个拦截器,后面的拦截器是暂时无法执行的消息,直到这个拦截器被删除后,MessageQueue才有一个叫enqueueSyncBarier的函数可以添加一个Barrier。

    int enqueueSyncBarrier(long when){
         // 排队一个新的同步障碍标记。
        // 我们不需要唤醒队列,因为障碍的目的是阻止它。
        synchronizedthis ){
             final  int token = mNextBarrierToken ++ ;
            最终消息msg = Message.obtain();
            msg.arg1 = 令牌;

            消息prev = null ;
            消息p = mMessages;
            if(when!= 0 ){
                 while(p!= null && p.when <= when){
                    prev = p;
                    p = p.next;
                }
            }
            if(prev!= null){ // invariant:p == prev.next 
                msg.next = p;
                prev.next = msg;
            } else {
                msg.next = p;
                mMessages = 味精;
            }
            返回令牌;
        }
    }

  在enqueueSyncBarrier中,获取一条消息,并设置msg.arg1 = token,令牌只是每次调用enqueueSyncBarrier后自增加int值以来,Objective只返回一个令牌,每次调用enqueueSyncBarrier时,该消息还需要设置执行时间,然后插入到消息队列中,特别的是该消息未设置为目标,Msg.target为空。

  输入消息循环将在实现中保留MessageQueue的消息,调用下一个函数MessageQueue,其中有:

消息msg = mMessages;
如果(msg!= null && msg.target == null ){
     // 被障碍阻挡。在队列中查找下一个异步消息。
    {
        prevMsg = msg;
        msg = msg.next;
    } while(msg!= null &&!msg.isAsynchronous());
}

  如果消息目标null的队列头部表示它是Barrier,因为只有两种方法可以添加mMessages消息,一个是enqueueMessage,另一个是enqueueBarrier,如果mst.target null是直接抛出异常,则enqueueMessage,会看到后面。

  异步消息调用实际上就是这种情况,我们可以通过enqueueBarrier向消息队列中插入一个Barrier,然后在Barrier时间执行同步消息队列,将Barrier拦截器执行到不能执行,直到我们调用removeBarrier,移除Barrier,并异步消息没有作用,默认是同步消息的消息,除非我们调用Message setAsynchronous,这个方法是隐藏的。只有在Handler初始化参数中,Handler初始化参数指定的消息所发送的消息是异步的,这样它才会在Handler的enqueueMessage中调用Message setAsynchronous,设置消息是异步的,从上面的Handler.enqueueMessage代码中可以看出。

  所谓异步消息,只有一个,就是在设置Barrier时仍然可以不受障碍的影响是正常的,如果没有设置Barrier,异步消息没有区别于同步消息,可以通过removeSyncBarrier去除障碍:

void removeSyncBarrier(int token){
     // 从队列中移除一个同步障碍标记。
    // 如果队列不再被障碍阻塞,那么将其唤醒。
    final  boolean needWake;
    同步this ){
        消息prev = null ;
        消息p = mMessages;
        while(p!= null &&(p.target!= null || p.arg1!= token)){
            prev = p;
            p = p.next;
        }
        if(p == null ){
             throw  new IllegalStateException(“指定的消息队列同步”
                    +“障碍标记尚未发布或已被删除。” );
        }
        if(prev!= null ){
            prev.next = p.next;
            needWake = false ;
        } else {
            mMessages = p.next;
            needWake = mMessages == null || mMessages.target!= null ;
        }
        p.recycle();
    }
    if (needWake){
        nativeWake(mPtr);
    }
}

  参数标记的返回值是enqueueSyncBarrier,如果不是不存在的异常将被抛出,则调用指定的标记。

enqueueMessage

  然后看看MessageQueue如何enqueueMessage。

    final  boolean enqueueMessage(Message msg,long when){
         if (msg.isInUse()){
             抛出 新的 AndroidRuntimeException(msg +“此消息已被使用。” );
        }
        if(msg.target == null){
            抛出新的AndroidRuntimeException(“Message must have a target。”);
        }

        boolean needWake;
        synchronizedthis ){
             if (mQuiting){
                RuntimeException e = new RuntimeException(
                        msg.target +“将消息发送给死线程上的处理程序” );
                Log.w( “MessageQueue” ,e.getMessage(),e);
                返回 false ;
            }

            msg.when = when;
            消息p = mMessages;
            如果(p == null || when == 0 || when < p.when){
                 // 新头,如果阻塞则唤醒事件队列。
                msg.next = p;
                mMessages = 味精;
                needWake = mBlocked;
            } else {
                 // 插入队列中间。通常我们没有醒来
                 // 了事件队列,除非是在队列的头一个障碍
                 // 和消息队列中最早的异步消息。
                needWake = mBlocked && p.target == null && msg.isAsynchronous();
                消息上一页;
                for (;;){
                    prev = p;
                    p = p.next;
                    if(p == null || when < p.when){
                         break ;
                    }
                    if(needWake && p.isAsynchronous()){
                        needWake = false ;
                    }
                }
                msg.next = p; // invariant:p == prev.next 
                prev.next = msg;
            }
        }
        if (needWake){
            nativeWake(mPtr);
        }
        返回 true ;
    }

  注意代码为红色,当msg.target为null时直接抛出异常。

  enqueueMessage中的第一个判断是,如果当前消息队列为空,执行时间或添加新消息的时间为0,或者添加的消息比消息队列头执行时间的执行时间早,则消息是添加到消息队列头(消息队列根据时间顺序),或者找到合适的位置将当前消息添加到消息队列中。

本地发送消息

  消息模型不仅可以使用Java层,Native层也可以使用,前面还看到消息队列的初始化也初始化了Looper和NativeMessageQueue Native层,所以Native层也应该可以发送消息。与Java层不同的是,Native层是Looper消息,所有的发送方法都被称为sendMessageAtTime:

void Looper :: sendMessageAtTime(nsecs_t uptime,const sp <MessageHandler>&handler,
         const Message&message){
 #if DEBUG_CALLBACKS 
    ALOGD(p〜sendMessageAtTime -  uptime =%lld,handler =%p,what =%d this,正常运行时间,处理程序。得到(),message.what);
#万一

    size_t i = 0 ;
    { // 获取锁定
        AutoMutex _l(mLock);

        size_t messageCount = mMessageEnvelopes.size();
        while(i <messageCount && uptime> = mMessageEnvelopes.itemAt(i).uptime){
            i + = 1 ;
        }

        MessageEnvelope messageEnvelope(正常运行时间,处理程序,消息);
        mMessageEnvelopes.insertAt(messageEnvelope,i,1 );

        // 优化:如果活套正在发送消息,然后我们可以跳过
         // 调用唤醒(),因为接下来的事情后处理弯针会做
         // 消息是决定下一次唤醒时间应该是。事实上,
         // 这个代码是否在Looper线程上运行都无关紧要。
        如果(mSendingMessage){
             return ;
        }
    } // 释放锁定

    // 仅当我们在头部输入新消息时才唤醒轮询循环。
    if(i == 0 ){
        唤醒();
    }
}

  Native消息只有一个int类型用于区分不同消息的字段,SendMessageAtTime消息被指定,Message消息的执行时间为,并处理消息Handler:MessageHandler,然后使用MessageEnvelope封装的MessageHandler和Message,Native消息保存到mMessageEnvelopes,MMessageEnvelopes是一个Vector <MessageEnvelope>。Native消息也根据时间顺序,并且Java层信息分别存储在两个队列中。

消息循环

  消息队列初始化不错,也知道如何发送消息,以下是如何处理消息,请参阅Handler.loop函数:

    public  static  void loop(){
         final Looper me = myLooper();
        if(me == null ){
             throw  new RuntimeException(“No Looper; Looper.prepare()not this on this thread。” );
        }
        最终的 MessageQueue队列= me.mQueue;

        // 确保该线程的身份是当地的过程中,
         // 和跟踪是什么身份令牌实际上是。
        Binder.clearCallingIdentity();
        final  long ident = Binder.clearCallingIdentity();

        for (;;){
            消息msg = queue.next(); // 可能会阻止
            if(msg == null){
                //没有消息表明消息队列正在退出。
                返回;
            }

            // 这必须在本地变量中,以防UI事件设置记录器 
            Printer logging = me.mLogging;
            if(logging!= null ){
                logging.println( “>>>>>调度到”+ msg.target +“”+ 
                        msg.callback +“:”+ msg.what);
            }

            msg.target.dispatchMessage(MSG);

            if(logging!= null ){
                logging.println( “<<<<<已完成”+ msg.target +“”+ msg.callback);
            }

            // 确保在调度过程中
             // 线程的身份没有被破坏。
            final  long newIdent = Binder.clearCallingIdentity();
            if(ident!= newIdent){
                Log.wtf(TAG, “线程身份已从0x更改”
                        + Long.toHexString(ident)+“to 0x”
                        + Long.toHexString(newIdent)+“,同时调度到”
                        + msg.target.getClass()。getName()+“”
                        + msg.callback +“what =”+ msg.what);
            }

            msg.recycle();
        }
    }

  当循环从MessageQueue接收消息时,调用msg.target.dispatchMessage(MSG),处理程序和消息关联的目标是发送消息,以便熟悉的dispatchMessage调用,消息被回收处理。当queue.next返回null时会退出消息循环,然后看MessageQueue.next是如何去除消息的,并在返回null时。

final Message next(){
         int pendingIdleHandlerCount = -1; // -1仅在第一次迭代期间
        int nextPollTimeoutMillis = 0 ;

        for (;;){
             if(nextPollTimeoutMillis!= 0 ){
                Binder.flushPendingCommands();
            }
            nativePollOnce(mPtr,nextPollTimeoutMillis);

            synchronizedthis ){
                 if(mQuiting){
                    返回null;
                }

                // 尝试检索下一条消息。如果找到则返回。
                最后 长时间 = SystemClock.uptimeMillis();
                消息prevMsg = null ;
                消息msg = mMessages;
                如果(msg!= null && msg.target == null ){
                     // 被障碍阻挡。在队列中查找下一个异步消息。
                    {
                        prevMsg = msg;
                        msg = msg.next;
                    } while(msg!= null &&!msg.isAsynchronous());
                }
                如果(msg!= null ){
                     if(now < msg.when){
                         // 下一条消息没有准备好。设置超时以在准备就绪时唤醒。
                        nextPollTimeoutMillis =(int)Math.min(msg.when  - now,Integer.MAX_VALUE);
                    } 其他{
                         // 得到一个消息。
                        mBlocked = false ;
                        if(prevMsg!= null ){
                            prevMsg.next = msg.next;
                        } else {
                            mMessages = msg.next;
                        }
                        msg.next = null ;
                        iffalse)Log.v(“MessageQueue”,“Returning message:”+ msg);
                        msg.markInUse();
                        返回味精;
                    }
                } 其他{
                     // 没有更多的消息。
                    nextPollTimeoutMillis = -1 ;
                }

                // 如果第一次闲置,然后获得闲置号码的运行。
                // 如果队列是空的,或者如果第一消息空闲仅处理运行
                 // 在队列中(可能是一个障碍)是由于在未来进行处理。
                如果(pendingIdleHandlerCount <0
                        &&(mMessages == null || now < mMessages.when)){
                    pendingIdleHandlerCount = mIdleHandlers.size();
                }
                如果(pendingIdleHandlerCount <= 0 ){
                     // 没有空闲处理程序运行。循环并等待更多。
                    mBlocked = true ;
                    继续;
                }

                if(mPendingIdleHandlers == null ){
                    mPendingIdleHandlers = new IdleHandler [Math.max(pendingIdleHandlerCount,4 )];
                }
                mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers);
            }

            // 运行闲置处理程序。
            // 在第一次迭代期间,我们只能到达这个代码块。
            forint i = 0; i <pendingIdleHandlerCount; i ++ ){
                 final IdleHandler idler = mPendingIdleHandlers [i];
                mPendingIdleHandlers [i] = null ; // 释放对处理程序的引用

                boolean keep = false ;
                尝试{
                    keep = idler.queueIdle();
                } catch (Throwable t){
                    Log.wtf( “MessageQueue”,“IdleHandler抛出异常” ,t);
                }

                如果(!keep){
                     synchronizedthis ){
                        mIdleHandlers.remove(惰轮);
                    }
                }
            }

            // 将空闲处理程序计数重置为0,以便我们不再运行它们。
            pendingIdleHandlerCount = 0 ;

            // 在调用闲置处理程序时,可能会传递一条新消息
             // 因此请返回,然后再等待一条待处理消息。
            nextPollTimeoutMillis = 0 ;
        }
    }

  MessageQueue.next将首先调用nativePollOnce,如果mQuiting true返回null,则Looper将退出消息循环。

  消息队列消息的下一个头部,如果头部消息是Barrier(target == null),则在下次遍历中查找第一个异步消息时,对消息的下一个测试访问(消息队列消息或第一个异步消息),如果NULL表示没有消息要执行,则设置nextPollTimeoutMillis = -1; 否则检测到这个消息到执行时间。如果markInUse的执行时间和消息从消息队列中删除,然后从下一个循环返回; 否则,设置nextPollTimeoutMillis =(int)Math.min(msg.when - now,Integer.MAX_VALUE),即距离最近的执行消息还需要多长时间,当前消息队列中没有消息可以执行(设置Barrier并且不设置异步消息或消息队列为空)或消息队列的头部不到执行时间,

  首先看nativePollOnce,native方法,叫做JNI,最后调用到Native Looper :: pollOnce,并从Java层传递到nextPollTimeMillis,即在消息队列中执行Java层的时间,以使近期消息的执行时间有多长。

int Looper :: pollOnce(int timeoutMillis,int * outFd,int * outEvents,void ** outData){
     int result = 0 ;
    for (;;){
         while(mResponseIndex < mResponses.size()){
             const Response&response = mResponses.itemAt(mResponseIndex ++ );
            int ident = response.request.ident;
            if(ident> = 0 ){
                 int fd = response.request.fd;
                int events =response.events;
                void * data = response.request.data;
#if DEBUG_POLL_AND_WAKE 
                ALOGD(%p〜pollOnce  - 返回信号标识符%d:
                        fd =%d,events = 0x%x,data =%p this ,ident,fd,events,data);
#endif 
                if(outFd!= NULL)* outFd = fd;
                if(outEvents!= NULL)* outEvents = events;
                如果(outData!= NULL)* outData = data;
                返回标识;
            }
        }

        如果(结果!= 0 ){
 #if DEBUG_POLL_AND_WAKE 
            ALOGD(%p〜pollOnce  - 返回结果%d this ,result);
#endif 
            if(outFd!= NULL)* outFd = 0 ;
            if(outEvents!= NULL)* outEvents = 0 ;
            如果(outData!= NULL)* outData = NULL;
            返回结果;
        }

        result = pollInner(timeoutMillis);
    }
}

  先看不到一堆代码,看看pollInner:

int Looper :: pollInner(int timeoutMillis){
 #if DEBUG_POLL_AND_WAKE 
    ALOGD(%p〜pollOnce  -  waiting:timeoutMillis =%d this ,timeoutMillis);
#万一

    // 根据下一封邮件何时到期来调整超时时间。
    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;
        }
#if DEBUG_POLL_AND_WAKE 
        ALOGD(%p〜pollOnce  - %lldns中的下一条消息,调整后的超时值:timeoutMillis =%d this,mNextMessageUptime  - now,timeoutMillis);
#万一
    }

    // 投票。
    int result = ALOOPER_POLL_WAKE;
    mResponses.clear();
    mResponseIndex = 0 ;

    struct epoll_event eventItems [EPOLL_MAX_EVENTS];
    int eventCount = epoll_wait(mEpollFd,eventItems,EPOLL_MAX_EVENTS,timeoutMillis);

    // 获取锁定。
    m锁。lock ();

    // 检查轮询错误。
    if(eventCount < 0 ){
         if(errno == EINTR){
             goto Done;
        }
        ALOGW(Poll失败,出现意外错误,errno =%d ,errno);
        结果 = ALOOPER_POLL_ERROR;
        转到完成;
    }

    // 检查轮询超时。
    if(eventCount == 0 ){
 #if DEBUG_POLL_AND_WAKE 
        ALOGD(%p〜pollOnce  -  timeout this );
#endif 
        结果 = ALOOPER_POLL_TIMEOUT;
        转到完成;
    }

    // 处理所有事件。
#if DEBUG_POLL_AND_WAKE 
    ALOGD(%p〜pollOnce  - 处理来自%d个fds的事件this ,eventCount);
#万一

    forint i = 0 ; i <eventCount; i ++ ){
         int fd = eventItems [i] .data.fd;
        uint32_t epollEvents = eventItems [i] .events;
        if(fd == mWakeReadPipeFd){
             if(epollEvents&EPOLLIN){
                苏醒();
            } else {
                ALOGW(在读取管道时忽略意外的epoll事件0x%x ,epollEvents);
            }
        } else {
            ssize_t requestIndex = mRequests.indexOfKey(fd);
            if(requestIndex> = 0 ){
                 int events = 0 ;
                if(epollEvents&EPOLLIN)events | = ALOOPER_EVENT_INPUT;
                if(epollEvents&EPOLLOUT)events | = ALOOPER_EVENT_OUTPUT;
                if(epollEvents&EPOLLERR)事件| = ALOOPER_EVENT_ERROR;
                if(epollEvents&EPOLLHUP)events | = ALOOPER_EVENT_HANGUP;
                pushResponse(events,mRequests.valueAt(requestIndex));
            } else {
                ALOGW( 忽略突发事件epoll的为0x%X上的fd%d是
                        不再注册。,epollEvents,FD);
            }
        }
    }
完成:;

    // 调用未决的消息回调。
    mNextMessageUptime = LLONG_MAX;
    while(mMessageEnvelopes.size()!= 0 ){
        nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
        const MessageEnvelope&messageEnvelope = mMessageEnvelopes.itemAt(0 );
        如果(messageEnvelope.uptime <= now){
             // 从列表中删除信封。
            // 我们保持对处理程序的强引用,直到调用handleMessage
             // 完成。然后我们放下它,以便可以在*之前删除处理程序*
             // 我们重新获取锁定。
            { // 获取处理程序 
                sp <MessageHandler> handler = messageEnvelope.handler;
                消息消息 = messageEnvelope.message;
                mMessageEnvelopes.removeAt(0 );
                mSendingMessage = true ;
                mLock.unlock();

#if DEBUG_POLL_AND_WAKE || DEBUG_CALLBACKS 
                ALOGD( %P〜pollOnce -发送消息:处理程序=%P,什么=%d 这个,处理程序获得(),message.what);
#endif 
                handler - > handleMessage(message);
            } // 发布处理程序

            mLock。lock ();
            mSendingMessage = false ;
            结果 = ALOOPER_POLL_CALLBACK;
        } else {
             // 队列头部的最后一条消息决定了下一个唤醒时间。
            mNextMessageUptime = messageEnvelope.uptime;
            休息;
        }
    }

    // 释放锁定。
    mLock.unlock();

    // 调用所有响应回调。
    for(size_t i = 0 ; i <mResponses.size(); i ++ ){
        回应与回应= mResponses.editItemAt(i);
        if(response.request.ident == ALOOPER_POLL_CALLBACK){
             int fd = response.request.fd;
            int events = response.events;
            void * data = response.request.data;
#if DEBUG_POLL_AND_WAKE || DEBUG_CALLBACKS 
            ALOGD( %P〜pollOnce -调用FD事件回调%P:FD =%d,事件=为0x%X,数据=%P ,response.request.callback 得到(),FD,事件,数据);
#endif 
            intcallbackResult = response.request.callback-> handleEvent(fd,events,data);
            if(callbackResult == 0 ){
                removeFd(FD);
            }
            //立即清除响应结构中的回调引用,因为
             // 直到下一次轮询之前
// // 不会清除响应向量本身。            response.request.callback.clear();
            结果 = ALOOPER_POLL_CALLBACK;
        }
    }
    返回结果;
}

  Java消息存储在mMessages的MessageQueue成员的Java层中,Native消息存储在Native Looper mMessageEnvelopes中,可以说有两个消息队列,并且按时间排列。TimeOutMillis表示Java层下一步执行消息执行多久,mNextMessageUpdate表示Native层下一步执行消息需要多长时间,如果timeOutMillis为0,epoll_wait不会设置TimeOut直接返回; 如果-1 Java层没有消息,直接用Native时间超时; 最小值或pollInner将两个值作为timeOut调用epoll_wait。当epoll_wait返回时可能有以下情况:

    1. 错误返回。

    2. 时间到

    3. 正常的返回,有事件产生的描述符。

如果前者直接转到了两个。 

  否则,FD发生了,如果mWakeReadPipeFd EPOLLIN事件唤醒被调用,如果没有mWakeReadPipeFd,它是通过addFD添加FD,在addFD中,将FD和events,callback,数据包放入Request对象中,以FD为key存储在KeyedVector mRequests中,所以这里FD在addFD Request中获取关联关系,并且通过添加pushResonse mResonse队列(Vector),Resonse仅用于事件和Request包。如果出现epoll_wait或超时错误,则没有事件描述符,不执行此代码,所以直接跳转到DONE。

void Looper :: pushResponse(int events,const Request&request){
    响应响应;
    response.events = events;
    response.request = 请求;
    mResponses.push(响应);
}

  接下来输入DONE,从mMessageEnvelopes中删除Native消息头,如果在执行时到达handleMessage被调用来处理它在内部存储的MessageeHandler并从Native消息队列中移除,则将结果设置为ALOOPER_POLL_CALLBACK,否则计算mNextMessageUptime表示Native消息队列消息执行时间处理时间。如果不是头部消息执行时间可能是Java层消息队列消息执行时间小于Native层消息队列消息执行时间,到达epoll_wait TimeOut Java消息的执行时间,或者通过addFd描述符添加了epoll_wait返回时发生,或epoll_wait错误返回。本机消息不是障碍和异步。

  最后,通过mResponses(只需通过pushResponse放入它),如果response.request.ident = = ALOOPER_POLL_CALLBACK,我们调用注册回调handleEvent(FD,events,data)处理,然后从mResonses队列中移除,之后遍历,MResponses保留并且ident> = 0,回调为NULL。在NativeMessageQueue初始化Looper时,将mAllowNonCallbacks设为false,因此mResponses之后的处理必须为空。

  然后返回到pollOnce。PollOnce是for循环,pollInner处理所有response.request.ident == ALOOPER_POLL_CALLBACK响应,如果mResponses不为空以查找ident> 0响应,则进入for循环的第二个响应,该函数调用pollOnce返回的值为ident自己处理,这里我们在NativeMessageQueue中调用Loope pollOnce,没有返回处理,但是mAllowNonCallbacks false不可能进入循环。pollInner的返回值可能不是0,也可能只是负值,因此循环的pollOnce将只执行两次,然后再次返回。

  Native Looper可以单独使用,也可以具有准备功能,那么mAllowNonCallbakcs值可能为true,mResponses中的pollOnce有意义。

苏醒并醒来

  在Native Looper构造函数中,管道打开了一条管道,结合使用mWakeReadPipeFd和mWakeWritePipeFd保存了管道端的读写端,然后使用epoll_ctl(mEpollFd,EPOLL_CTL_ADD,mWakeReadPipeFd,&eventItem)监视EPOLLIN事件的读取结束,在pollInner中通过epoll_wait(mEpollFd,eventItems,EPOLL_MAX_EVENTS,timeoutMillis)读取事件,写入mWakeWritePipeFd时,以及在什么时候读取mWakeReadPipeFd。

  在Looper.cpp中,我们可以在下面找到两个函数:

void Looper :: wake(){
 #if DEBUG_POLL_AND_WAKE 
    ALOGD(p〜wake this );
#万一

    ssize_t nWrite;
    {
        nWrite =写入(mWakeWritePipeFd,W 1 );
    } while(nWrite ==  - 1 && errno == EINTR);

    if(nWrite!= 1 ){
         if(errno!= EAGAIN){
            ALOGW(不能写唤醒信号,errno =%d ,errno);
        }
    }
}

void Looper :: awoken (){
 #if DEBUG_POLL_AND_WAKE 
    ALOGD(p〜awoken this );
#万一

    字符缓冲区[ 16 ];
    ssize_t nRead;
    {
        nRead = read(mWakeReadPipeFd,buffer,sizeof (buffer));
    } while((nRead ==  - 1 && errno == EINTR)|| nRead == sizeof (buffer));
}

  唤醒函数写入一个“mWakeWritePipeFd”; W“字符,从mWakeReadPipeFd中唤醒,以mWakeWritePipeFd向epoll_wait中的pollInner写入数据,您可以监听事件返回。pollInner还可以查看mWakeReadPipeFd EPOLLIN事件是否被称为唤醒消耗字符回写处理。

  当唤醒唤醒?只需找到一个呼叫线上的地方,看看Looper.cpp,在sendMessageAtTime发送Native Message时,应根据mMessageEnvelopes的执行时间插入发送消息,如果是在头插入我们调用唤醒唤醒epoll_wait,因为在pollInner中根据执行时间和Native层消息队列头消息的执行时间计算Java层消息队列头中的超时值,如果新消息插入头中,则执行至少两个消息的时间在一个之前,所以你应该唤醒epoll_wait,Epoll_wait返回,检查Native消息队列,查看头部消息是否只是插入消息到执行时间,要执行,否则你可能需要设置新的超时。

如果(p == null || when == 0 || when < p.when){
     // 新头,如果阻塞则唤醒事件队列。
    msg.next = p;
    mMessages = 味精;
    needWake = mBlocked;
} else {
     // 插入队列中间。通常我们没有醒来
     // 了事件队列,除非是在队列的头一个障碍
     // 和消息队列中最早的异步消息。
    needWake = mBlocked && p.target == null && msg.isAsynchronous(); // 如果头部是Barrier并且新消息是异步消息,则可能需要唤醒; 
    消息上一页;
    for (;;){
        prev = p;
        p = p.next;
        if(p == null || when < p.when){
             break ;
        }
        if(needWake && p.isAsynchronous()){ // 消息队列是异步消息,并且消息之前的执行时间在消息中,所以不需要唤醒。
            needWake = false ;
        }
    }
    msg.next = p; // invariant:p == prev.next 
    prev.next = msg;
}

  在头插入消息时不必调用nativeWake,因为之前可能会执行IdleHandler,如果执行IdleHandler,则在IdleHandler执行下一个PollTimeoutMillis时将其设置为0,下次启动for循环为0调用nativePollOnce,不需要唤醒,只有在没有消息可以执行的情况下(消息队列为空或不在执行时间内)并且不将IdleHandler mBlocked设置为true。

  如果消息队列的Java层是Barrier Block并且插入是异步消息,则可能需要唤醒Looper,因为异步消息可以在Barrier中执行,但异步消息必须在第一时间执行异步消息。

  退出Looper也需要唤醒,removeSyncBarrier也可能需要。 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值