美文网首页
关于Choreographer

关于Choreographer

作者: Wi1ls努力努力再努力 | 来源:发表于2020-10-14 15:51 被阅读0次

    Choreographer应用最广泛的是其postCallback()方法可以提供在vsync信号来到时进行回调,本篇的就是为了说明其原理。

    • Choreographer的初始化
     private final Looper mLooper;
     private final FrameHandler mHandler;
     private final FrameDisplayEventReceiver mDisplayEventReceiver;
    
    private Choreographer(Looper looper, int vsyncSource){
      mLooper = looper;
      mHandler = new FrameHandler(looper);
      nDisplayEventReceiver = USE_VSYNC? new FrameDisplayEventReceiver(looper, vsyncSource):null;
      mLastFrameTimeNanos = Long.MIN_VALUE;
      mFrameIntervalNanos = (long)(1000000000/getRefreshRate());
      mCallbackQueues = new CallbackQueue[CALLBACK_LAST + 1];
      for(int i=0;i<=CALLBACK_LAST;i++){
        mCallbackQueuesi[i] = new CallbackQueue();
      }
      setFPSDivisor(SystemProperties.getInt(ThreadRender.DEBUG_FPS_DIVISOR,1));
    }
    

    其他的都没有什么内容,这里的关键是这个FrameDisplayEventReceiver;我们目前在这里分析的是ViewRootImpl中的Choreographer,所以认为这里的looper为MainLooper(不影响整体分析,在Choreographer中可以看到有两个ThreadLocal提供线程单例)。

    • FrameDisplayEventReceiver继承自DisplayEventReceiver,重写了onVsync与run
    //DisplayEventReceiver.java
    public DisplayEventReceiver(Looper looper, int vsyncSource){
      mMessageQueue = looper.getQueue();
      mReceiverPtr=nativeInit(new WeakReference<DisplayEventReceiver>(this), mMessageQueue, vsyncSource);
    }
    
    //messageQueue可以认为是主线程的MessageQueue,
    //该方法的native实现在../framework/base/core/jni/android_view_DisplayEventReceiver.cpp
    private static native long nativeInit(WeakReference<DisplayEventReceiver> receiver, MessageQueue messageQueue, int vsyncSource);
    
    //android_view_DisplayEventReceiver.cpp
    static jint nativeInit(JNIEnv* env, jclass clazz, jobject receiverObj, jobject messageQueueObj){
      //Java层的MessageQueue还是依托native层的MessageQueue去实现的
      sp<MessageQueue> messageQueue = android_os_MessageQueue_getMessageQueue(env, messageQueueObj);
      //创建一个NativeDisplayEventReceiver对象
      sp<NativeDisplayEventReceiver> receiver = new NativeDisplayEventReceiver(env, receiverObj, messageQueue);
      status_t status = receiver->initialize();
      receiver->incStrong(gDisplayEventReceiverClassInfo.clazz);
      return reinterpret_cast<jnit>(receiver.get());
    }
    
    
    class NativeDisplayEventReceiver : public LooperCallback{
      ...
      private:
        ...
        DisplayEventReceiver mReceiver;
    }
    
    //保存成员变量
    NativeDisplayEventReceiver::NativeDisplayEventReceiver(JNIEnv* env, jobject receiverObj, const sp<MessageQueue>& messageQueue):
      mReceiverObjGlobal(env->NewGlobalRef(receiverObj)), mMessageQueue(mMessageQueue), mWaitingForVsync(false){}
    
    
    status_t NativeDisplayEventReceiver::initialize(){
      status_t result = mReceiver.initCheck();
      int rc = mMessageQueue->getLooper()->addFd(mReceiver.getFd(), 0, ALOOPER_EVENT_INPUT, this, NULL);
    }
    

    在这里,mReceiver是DisplayEventReceiver对象

    • DisplayEventReceiver.cpp
    DisplayEventReceiver::DisplayEventReceiver(){
      sp<ISurfaceComposer> sf(ComposerService::getComposerService());
      if(sf != NULL){
        mEventConnection = sf->createDisplayEventConnection();
        if(mEventConnection != NULL){
          mDataChannel = mEventConnection->getDataChannel();
        }
      }
    }
    
    //定义在DisplayEventReciver.h
    sp<IDisplayEventConnection> mEventConnection;
    sp<BitTube> mDataChannel;
    

    从另外一篇SurfaceFlinger可以找到这里的mDataChannel为一个BitTube对象,内部为管道。并且在其创建的时候会注册在EventThread中,在接受到vsync信号后,会在EventThread中进行写入注册的BitTube的管道中。

    int DisplayEventReceiver::getFd() const {
      return mDataChannel->getFd(); 
    }
    
    • 结论

    联系Handler的阻塞分析,在底层收到vsync信号后,EventThread会往注册的BitTube中写入数据,而这里Choreographer在底层正是将这个BitTube注册到MessageQueue的Looper,于是收到一个vsync后,对应的MessageQueue就会被唤醒,从而进行下一步。


    如何利用BitTube的

    //EventThread.cpp
    void EventThread::Connection::onFirstRef(){
      mEventThread->registerDisplayConnection(this);
    }
    
    status_t EventThread::registerDisplayEventConnection(const sp<EventThread::Connection>& connection){
      mDisplayEventConnections.add(connection);
    }
    
    bool EventThread::threadLoop(){
      ...
      status_t err = conn->postEvent(event);
      ...
    }
    
    status_t EventThread::Connection::postEvent(const DisplayEventReceiver::Event& event){
      ssize_t size = DisplayEventReceiver::sendEvent(mChannel, &event, 1);
    }
    
    //DisplayEventReceiver.cpp
    ssize_t DisplayEventReceiver::sendEvents(const sp<BitTube>& dataChannel, Event const* events, size_t count){
      return BitTube::sendObject(dataChannel,events,count);
    }
    
    //BitTube.cpp
    ssize_t BitTube::sendObjects(const sp<BitTube>& tube, void const* events, size_t count, size_t objSize){
      ...
      const char* vaddr = reinterpret_cast<const char*>(events) + objSize*i;
      ssize_t size = tube->write(vaddr, objsize);
      ... 
    }
    
    ssize_t BitTube::write(void const* vaddr, size_t size){
      ...
      len = ::send(mSendFd, vaddr, size, MSG_DONTWAIT | MSG_NOSIGNAL);
      ...
    }
    

    同时在Looper中的添加的fd为mReceiveFd,与mSendFd相对应,此时Looper就会被唤醒了。


    因此每次收到vsync信号,对应的Looper中的MessageQueue都会在阻塞中被唤醒(如果被阻塞的话)。


    //Choreographer
    public void postCallback(int callbackType, Runnable action, Object token){
      postCallbackDelayed(callbackType, action, token, 0);
    }
    
    public void postCallbackDelayed(int callbackType, Runnable action, Object token, long delayMillis){
      postCallbackDelayInternal(callbackType, action, token, delayMillis);
    }
    
    private void postCallbackDelayInternal(int callbackType, Object action, Object token, long delayMillis){
      synchronized(mLock){
        final long now = SystemClock.uptimeMillis();
        final long dueTime = now + delayMillis;
         mCallbackQueues[callbackType].addCallbackLocked(dueTime,action,token);
    
      if(dueTime <= now){
        scheduleFrameLocked(now);
      }else{
        Message msg=mHandler.obtainMessage(MSG_DO_SCHEDULE_CALLBACK, action);
        msg.arg1=callbackType;
        msg.setAsynchronous(true);
        mHandler.sendMessageAtTime(msg,dueTime);
      }
      }
    }
    

    //todo

    好的学习

    相关文章

      网友评论

          本文标题:关于Choreographer

          本文链接:https://www.haomeiwen.com/subject/gwcwpktx.html