天天看點

Android SurfaceFlinger VSync流程分析

一,VSync機制的作用及VSync在SurfaceFlinger服務中的位置:

VSync信号通常都來自硬體控制器,在Android中也可以采用軟體模拟;

VSync的作用,如下圖(以雙緩沖為例,為了提高流暢性有時也采用triple三緩沖):LCD控制器在讀取每一幀資料的開始都會産生一個VSync信号(垂直同步信号或幀同步信号);

Android SurfaceFlinger VSync流程分析

LCD的頻率是60Hz,顯示每一幀的間隔是16ms,是以每一個VSync信号的時間間隔是16ms,上圖中的A和B都是幀緩沖區framebuffer,每一個framebuffer由CPU和GPU共同完成;

在硬體晶片中,晶振産生的時鐘脈沖驅動整個硬體電路連續運作;在Surfaceflinger中,VSync信号就好像晶振電路産生的時鐘信号一樣驅動Surfaceflinger中所有子產品和諧的運作,如下圖;

Android SurfaceFlinger VSync流程分析

二,VSync流程及重要代碼:

1,整體流程概覽,如下圖:

Android SurfaceFlinger VSync流程分析

重點介紹如下過程:

2,App繪制請求發送流程(過程1(App)):

App程序調用invalidate或postinvalidate方法發送繪制請求;

Android SurfaceFlinger VSync流程分析

invalidate方法最終會調用的BpDisplayEventConnection的requestNextVsync方法,在該方法中通過Binder IPC通路服務端的requestNextSync方法;

BpDisplayEventConnection方法的執行個體化過程如下:

1>,在ViewRootImpl的構造函數中會執行個體化Choreographer對象,

public ViewRootImpl(Context context, Display display) {
                . . . . . 
        mChoreographer = Choreographer.getInstance();
 }
           

2>,在mChoreographer 的構造函數中執行個體化FrameDisplayEventReceiver對象:

private Choreographer(Looper looper) {
               . . . . . .
               mDisplayEventReceiver = USE_VSYNC ? new FrameDisplayEventReceiver(looper) : null;
 }
           

3>,在FrameDisplayEventReceiver的父類構造函數中會調用到,android_view_DisplayEventReceiver.cpp中的nativeInit方法,

4>,在nativeInit方法中有如下過程:

static jlong nativeInit(JNIEnv* env, jclass clazz, jobject receiverWeak,
        jobject messageQueueObj) {
        . . . . . .
    sp<NativeDisplayEventReceiver> receiver = new NativeDisplayEventReceiver(env,
            receiverWeak, messageQueue);
    status_t status = receiver->initialize();
    . . . . . .
           
1),建立NativeDisplayEventReceiver類類型指針,
           

在NativeDisplayEventReceiver的構造函數中會調用DisplayEventReceiver類的無參構造函數執行個體化成員mReceiver;

DisplayEventReceiver::DisplayEventReceiver() {
    sp<ISurfaceComposer> sf(ComposerService::getComposerService());
    if (sf != NULL) {
        mEventConnection = sf->createDisplayEventConnection();
        if (mEventConnection != NULL) {
            mDataChannel = mEventConnection->getDataChannel();
        }
    }
}
           

在這段代碼中擷取Surfaceflinger服務的代理對象,然後通過Binder IPC建立BpDisplayEventConnection對象,然後mEventConnection->getDataChannel()方法再次通過Binder IPC建立 BitTube對象mDataChannel ,在Binder IPC建立mDataChannel 過程中會從服務端EventThread::Connection::Connection中(在EventThread類中定義)接收一個socketpair建立的FIFO檔案描述符;

EventThread::Connection::Connection建立描述符的代碼:

Connection構造函數調用BitTube的無參構造函數,在BitTube的構造函數中調用init函數;

void BitTube::init(size_t rcvbuf, size_t sndbuf) {
    int sockets[];
    if (socketpair(AF_UNIX, SOCK_SEQPACKET, , sockets) == ) {
        size_t size = DEFAULT_SOCKET_BUFFER_SIZE;
        setsockopt(sockets[], SOL_SOCKET, SO_RCVBUF, &rcvbuf, sizeof(rcvbuf));
        setsockopt(sockets[], SOL_SOCKET, SO_SNDBUF, &sndbuf, sizeof(sndbuf));
        // sine we don't use the "return channel", we keep it small...
        setsockopt(sockets[], SOL_SOCKET, SO_SNDBUF, &size, sizeof(size));
        setsockopt(sockets[], SOL_SOCKET, SO_RCVBUF, &size, sizeof(size));
        fcntl(sockets[], F_SETFL, O_NONBLOCK);
        fcntl(sockets[], F_SETFL, O_NONBLOCK);
        mReceiveFd = sockets[];
        mSendFd = sockets[];
    } else {
        mReceiveFd = -errno;
        ALOGE("BitTube: pipe creation failed (%s)", strerror(-mReceiveFd));
    }
}
           
2)調用到NativeDisplayEventReceiver類的父類DisplayEventDispatcher中的initialize()方法,
  将BpDisplayEventConnection對象擷取到的mDataChannel (BitTube類型)中的檔案描述符添加到UI主線程Looper的epoll中,
  當檔案描述符中被寫入資料時,該epoll_wait會被喚醒;
           

3,Vsync信号驅動App程序繪制流程(過程4(App)):

4,Surfaceflinger圖冊合成請求發送流程(過程1(sf)):

5,Vsync信号驅動Surfaceflinger合成流程(過程4(sf)):