界面显示_视图Choreographer控制


为什么叫舞蹈编导,因为舞蹈是由节奏的,节奏是每个点位动作的快慢控制,跳舞时节奏很重要,编舞者控制节奏。视图刷新也是如此,不是说你想刷就能刷,一切要按照底层信号要求的节奏来。

理解屏幕刷新频率

刷新频率:每秒钟刷新屏幕的次数,从缓存中取出每一帧,显示到屏幕上的速度。
帧率:GPU/CPU生成每一帧画面图像,存入缓存中的速度。
一般情况下帧率是大于刷新频率的,每个设备的刷新频率固定,与硬件相关,若帧率是刷新率的两倍,两张图像画面,只能有一个现实到屏幕上,也就是说生产画面的速度要大于显示画面的速度。典型的生产者-消费者模式。
屏幕刷新过程:从左到右刷新一行,然后垂直刷新,再一行..,直到屏幕刷新完毕。每一次刷新,都是这一个过程,刷新一次后,中间有一个期间,刷新率太高,每秒60帧左右,人眼无法感知。
tearing:若帧率大于刷新率,会导致在刷新前一帧还未开始时,缓存已经被新一帧覆盖一部分,那么在刷新前一帧时,现显示的一部分是新一帧内容。会导致画面前后帧上下重叠。这种情况技术上称之tearing,画面撕裂的意思。
解决方案:增加缓存到两个缓存,CPU生成帧存入一个缓存A,屏幕取出帧存入另一个缓存B,解决了一个缓存导致生产者与消费者不同步的问题。增加Vsync同步信号,负责调度将A缓存拷贝到B缓存,显示取出的就是一个完整帧的画面。Vsync信号在一帧刷新完的中间期间产生,A到B的复制(交换地址即可),进入下一次刷新,并通知生产者gpu/cpu继续生产帧,只有收到Vsync信号,生产者才会生产帧。因此,可使帧率与刷新率保持同步,消耗一次才生成一次。
掉帧:若Vsync信号发出时,A缓存正在被生产者锁住生产,gpu绘制生产帧时间超过信号发出时刻一点,此时不会复制。导致B缓存仍是老帧,下一次周期与前一次刷新相同的帧。当gpu生产结束后,此时刷新老数据的刷新周期中,还没有Vsync信号,则gpu空闲
掉帧解决方案:再增加一个缓存到三个缓存。当有缓存锁住时复制他前面的上一次被锁住的另一个缓存。

Android平台提供两种信号,一种是硬件信号,另一种是软件信号,由SurfaceFlinger进程的一个线程定时发出,硬件信号由硬件发出。
App进程若要通过gpu实现图像绘制,需要在接收到Vsync信号的条件下进行,因此,App进程访问SurfaceFlinger进程获取这个信号,再进行gpu绘制。

Choreographer就是负责获取Vsync同步信号并控制App线程(主线程)完成图像绘制的类。

在Android系统中主要是主线程进行UI绘制,其他线程也可以绘制,比如SurfaceView,本文以主线程UI绘制进行介绍。

每个线程中保存一个Choreographer实例对象。

private static final ThreadLocal<Choreographer> sThreadInstance =
            new ThreadLocal<Choreographer>() {
    @Override
    protected Choreographer initialValue() {
        Looper looper = Looper.myLooper();
        if (looper == null) {
            //抛出异常。
        }
        return new Choreographer(looper);
    }
};

线程本地存储ThreadLocal变量,Choreographer类型,在主线程中初始化变量时,创建Choreographer对象,绑定主线程Looper。

同一个App的每个窗体旗下ViewRootImpl使用的同一个Choregrapher对象,他控制者整个App中大部分视图的绘制节奏。


安排一次绘制

一次绘制,就是完成一个树形视图的测量、布局、绘制的过程,遍历视图树的每一个节点,当然,可以根据条件判断,省略掉其中一个或几个环节,比如,只刷新绘制,不测量和布局。

void scheduleTraversals() {
    if (!mTraversalScheduled) {
        mTraversalScheduled = true;
        mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
        mChoreographer.postCallback(
                    Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
        ...
    }
}

ViewRootImpl对象的scheduleTraversals安排一次绘制,安排后,将设置标志位mTraversalScheduled,防止多次安排,发送同步栅栏。
当执行绘制doTraversal方法或unscheduleTraversals方法主动取消绘制时,关掉标志位,取消同步栅栏。委托Choreographer安排绘制,请求信号。
postCallbackDelayedInternal方法,调用postCallbackDelayedInternal。

private void postCallbackDelayedInternal(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);
        }
    }
}

该postCallback方法向回调请求数组CallbackQueues中存入一个对应类型的记录CallbackRecord,该纪录封装回调任务、当前时间,等待信号安排一帧绘制。数组元素是CallbackQueue,内部包含指向CallbackRecord链表的头指针。四种callbackType类型CALLBACK_INPUT、CALLBACK_ANIMATION、CALLBACK_TRAVERSAL、CALLBACK_COMMIT。每一种callbackType类型代表数组的一个索引。
CallbackQueue数组.jpg

CallbackQueue的addCallbackLocked方法,创建一个CallbackRecord,封装dueTime执行时间(当前时间+延迟),任务action和token。插入链表,按照dueTime时间排序,dueTime时间小的在链表头部。
本文只关注CALLBACK_TRAVERSAL类型和TraversalRunnable回调任务,当收到Vsync信号时,将触发任务的doTraversal方法。

没有延迟,scheduleFrameLocked方法立即安排。
有延迟,等待delayMillis时间,在特定时间dueTime,通过Choreographer内部FrameHandler发送消息。

@Override
public void handleMessage(Message msg) {
    switch (msg.what) {
        ...
        case MSG_DO_SCHEDULE_CALLBACK:
            doScheduleCallback(msg.arg1);
            break;
    }
}

FrameHandler处理延迟发送的CALLBACK,触发doScheduleCallback方法。

void doScheduleCallback(int callbackType) {
    synchronized (mLock) {
        if (!mFrameScheduled) {
            final long now = SystemClock.uptimeMillis();
            if (mCallbackQueues[callbackType].hasDueCallbacksLocked(now)) {
                scheduleFrameLocked(now);
            }
        }
    }
}

有延迟时,当到达时间dueTime,在handleMessage方法开始执行,最终实现一次绘制,和没有延迟时一样,触发scheduleFrameLocked方法。注意,经过一段时间的延迟,中间有不确定性,增加两个条件判断。
mFrameScheduled标志,表示此时已经有过一次scheduled,请求一次有回复在doFrame处重置标志。这时,不再scheduled。
当链表头结点的dueTime比当前时间now大,表示当时以(now + delayMillis)插入的CallbackRecord节点已经不在链表中了,否则在(now + delayMillis)时刻执行获取的当前时间一定会<=now,链表每个元素的dueTime都大于now,或者头节点是空,这种情况下不再scheduled。

scheduleFrameLocked方法,schedule一次具体的帧绘制。

private void scheduleFrameLocked(long now) {
    if (!mFrameScheduled) {
        mFrameScheduled = true;
        if (USE_VSYNC) {
            if (isRunningOnLooperThreadLocked()) {
                scheduleVsyncLocked();
            } else {
                Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_VSYNC);
                msg.setAsynchronous(true);
                mHandler.sendMessageAtFrontOfQueue(msg);
            }
        } else {
            final long nextFrameTime = Math.max(
                    mLastFrameTimeNanos / TimeUtils.NANOS_PER_MS + sFrameDelay, now);
            ...   
            Message msg = mHandler.obtainMessage(MSG_DO_FRAME);
            msg.setAsynchronous(true);
            mHandler.sendMessageAtTime(msg, nextFrameTime);
        }
    }
}

入参now是执行该方法前获取的当前时间,设置mFrameScheduled标志,底层回调后重置标志。
默认USE_VSYNC,当前线程和Choreographer绑定线程一致,直接调用Choreographer的scheduleVsyncLocked方法,线程不同,通过FrameHandler发送消息,在Choreographer线程处理事务消息。

@Override
public void handleMessage(Message msg) {
    switch (msg.what) {
        ...
        case MSG_DO_SCHEDULE_VSYNC:
            doScheduleVsync();
            break;
    }
}

同样,在doScheduleVsync会调用scheduleVsyncLocked方法。postCallback方法流程图。

Choreographer的postCallback方法流程.jpg

最终统一调用到scheduleVsyncLocked方法,它通过注册的接收器JNI方法访问底层,请求垂直同步信号。


显示事件接收器基础架构

scheduleVsyncLocked方法,通过DisplayEventReceiver的scheduleVsync实现请求同步信号。

private void scheduleVsyncLocked() {
    mDisplayEventReceiver.scheduleVsync();
}

它是FrameDisplayEventReceiver类型,继承DisplayEventReceiver,在编舞者的构造方法中初始化,Java层DisplayEventReceiver构造方法。

public DisplayEventReceiver(Looper looper) {
    ..//Looper是空抛异常
    mMessageQueue = looper.getQueue();
    mReceiverPtr = nativeInit(new WeakReference<DisplayEventReceiver>(this), mMessageQueue);
}

DisplayEventReceiver会绑定Choreographer线程消息队列。创建一个弱引用,和消息队列一起,JNI#nativeInit方法初始化传入底层。

static jlong nativeInit(JNIEnv* env, jclass clazz, jobject receiverWeak,
        jobject messageQueueObj) {
    sp<MessageQueue> messageQueue = android_os_MessageQueue_getMessageQueue(env, messageQueueObj);
    ...
    sp<NativeDisplayEventReceiver> receiver = new NativeDisplayEventReceiver(env,
            receiverWeak, messageQueue);
    status_t status = receiver->initialize();
    ...
    receiver->incStrong(gDisplayEventReceiverClassInfo.clazz); 
    return reinterpret_cast<jlong>(receiver.get());
}

根据Java层MQ获取底层消息队列,创建一个NativeDisplayEventReceiver,JNI层接收器,继承LooperCallback,将mReceiverPtr指针返回Java层。JNI层接收器封装Java层弱引用receiverWeak、底层消息队列,底层接收器。
JNI层接收器的initialize初始化方法。

status_t NativeDisplayEventReceiver::initialize() {
    status_t result = mReceiver.initCheck();
    ...
    int rc = mMessageQueue->getLooper()->addFd(mReceiver.getFd(), 0, Looper::EVENT_INPUT,
            this, NULL);
    return OK;
}

向Choreographer线程Looper监听底层DisplayEventReceiver对象中BitTube的mReceiverFd描述符。一旦接收到消息,将触发Looper的handleEvent回调方法。

底层DisplayEventReceive的构造方法。

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

初始化两个重要指针,IDisplayEventConnection类型(mEventConnection)和BitTube类型(mDataChannel)。
IDisplayEventConnection负责和SurfaceFlinger进程通信,真正向底层发起请求,定义了进程通信的业务接口,IDisplayEventConnection业务层接口方法。

上面代码中sf是App进程ISurfaceComposer业务代理,真实的业务对象是SurfaceFlinger对象,继承BnSurfaceComposer,在SurfaceFlinger进程。ISurfaceComposer业务进程通信。

ISurfaceComposer业务进程通信.png

在App进程,ISurfaceComposer代理的createDisplayEventConnection方法,返回IDisplayEventConnection业务代理,继承BpDisplayEventConnection,也就是mEventConnection。然后,App进程就能通过IDisplayEventConnection的三个业务方法,requestNextVsync方法,请求下一次垂直同步信号。setVsyncRate方法,设置垂直同步帧率。getDataChannel方法,获取通信管道。

在SurfaceFlinger进程,SurfaceFlinger对象的createDisplayEventConnection方法,创建IDisplayEventConnection业务真实对象Connection,继承BnDisplayEventConnection。和App进程通信时,参数是Binder类型的,Parcal的writeStrongBinder和readStrongBinder方法可以实现Binder对象的传输,内核红黑树创建服务和引用节点,App进程创建出BpDisplayEventConnection业务代理。
SurfaceFlinger进程的createDisplayEventConnection方法。

sp<IDisplayEventConnection> SurfaceFlinger::createDisplayEventConnection() {
    return mEventThread->createEventConnection();
}

sp<EventThread::Connection> EventThread::createEventConnection() const {
    //在创建前会向EventThread注册该连接,加入到mDisplayEventConnections中。
    return new Connection(const_cast<EventThread*>(this));
}

创建Connection对象,它是EventThread内部类,该类的构造方法。

EventThread::Connection::Connection(const sp<EventThread>& eventThread)
    : count(-1), mEventThread(eventThread), mChannel(new BitTube())
{
}

创建数据通道BitTube,内部一对Socket描述符,提供读写方法,用于数据通讯。
IDisplayEventConnection业务进程通信图。

IDisplayEventConnection业务进程通信.png

BitTube的构造方法和初始化方法。

BitTube::BitTube()
    : mSendFd(-1), mReceiveFd(-1){
    init(DEFAULT_SOCKET_BUFFER_SIZE, DEFAULT_SOCKET_BUFFER_SIZE);
}

void BitTube::init(size_t rcvbuf, size_t sndbuf) {
    int sockets[2];
    if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, sockets) == 0) {
        ...
        mReceiveFd = sockets[0];
        mSendFd = sockets[1];
    } else {
        mReceiveFd = -errno;
    }
}

初始化一对socket发送/接收描述符,提供读/写数据的管道功能。Tube的意思是管,BitTube即字节管道。socket缓存4M,mSendFd用于写入,mReceiveFd用于接收,写入后,接收端mReceivedFd能读取。

App进程,通过BpDisplayEventConnection的getDataChannel方法获取通信管道,SurfaceFlinger进程,通过writeDupFileDescriptor写入mReceivedFd描述符,App进程从Parcel中读取,创建新BitTube对象封装mReceivedFd描述符。

virtual sp<BitTube> getDataChannel() const {
    Parcel data, reply;
    data.writeInterfaceToken(IDisplayEventConnection::getInterfaceDescriptor());
    remote()->transact(GET_DATA_CHANNEL, data, &reply);
    return new BitTube(reply);
}

Parcel的writeDupFileDescriptor和readFileDescriptor方法负责FileDescriptor类型读写存储。BitTube的构造方法(带Parcel参数)。

BitTube::BitTube(const Parcel& data)
    : mSendFd(-1), mReceiveFd(-1) {
    mReceiveFd = dup(data.readFileDescriptor());
    if (mReceiveFd < 0) {
        mReceiveFd = -errno;
        ALOGE("BitTube(Parcel): can't dup filedescriptor (%s)",
                strerror(-mReceiveFd));
    }
}

Choreographer接收器与SurfaceFlinger通信的架构图。
Choreographer接收器与SurfaceFlinger通信的架构图.jpg

请求垂直同步信号流程

Java层DisplayEventReceiver请求一次垂直同步信号的过程。
DisplayEventReceiver请求同步信号的流程.jpg

前两个方法已经看过了,直接看一下JNI#nativeScheduleVsync方法。

static void nativeScheduleVsync(JNIEnv* env, jclass clazz, jlong receiverPtr) {
    sp<NativeDisplayEventReceiver> receiver =
            reinterpret_cast<NativeDisplayEventReceiver*>(receiverPtr);
    status_t status = receiver->scheduleVsync();
    ...
}

根据Java层receiverPtr指针,获取JNI层的NativeDisplayEventReceiver对象

status_t NativeDisplayEventReceiver::scheduleVsync() {
    if (!mWaitingForVsync) {
        ...
        processPendingEvents(&vsyncTimestamp, &vsyncDisplayId, &vsyncCount);
        status_t status = mReceiver.requestNextVsync();
        ...
        mWaitingForVsync = true;
    }
    return OK;
}

JNI层接收器封装底层DisplayEventReceiver,调用requestNextVsync方法。

status_t DisplayEventReceiver::requestNextVsync() {
    if (mEventConnection != NULL) {
        mEventConnection->requestNextVsync();
        return NO_ERROR;
    }
    return NO_INIT;
}

底层DisplayEventReceiver,内部两个重要指针已经介绍过。
IDisplayEventConnection业务#requestNextVsync方法,和SurfaceFlinger进程通信,该进程实现业务接口的是Connection对象。sf进程Connection的requestNextVsync方法。

void EventThread::Connection::requestNextVsync() {
    mEventThread->requestNextVsync(this);
}

Connection内部EventThread的requestNextVsync方法。

void EventThread::requestNextVsync(
        const sp<EventThread::Connection>& connection) {
    Mutex::Autolock _l(mLock);
    if (connection->count < 0) {
        connection->count = 0;
        mCondition.broadcast();
    }
}

通知mCondition条件,broadcast方法唤醒SurfaceFlinger进程的一个循环线程mEventThread,该线程在waitForEvent处等待,被唤醒后可利用Connection发送事件。

SurfaceFlinger循环线程EventThread的threadLoop方法

bool EventThread::threadLoop() {
    DisplayEventReceiver::Event event;
    Vector< sp<EventThread::Connection> > signalConnections;
    signalConnections = waitForEvent(&event);//等待事件,等待得到的事件保存在event指针处

    const size_t count = signalConnections.size();
    for (size_t i=0 ; i<count ; i++) {//遍历有信号的Connection,每个都发送event
        const sp<Connection>& conn(signalConnections[i]);
        status_t err = conn->postEvent(event);//写入的内容是Event类型
        if (err == -EAGAIN || err == -EWOULDBLOCK) {
            ...
        } else if (err < 0) {
            removeDisplayEventConnection(signalConnections[i]);
        }
    }
    return true;
}

该循环线程唯一的工作是在waitForEvent方法处等待VSYNC信号,当信号发生时,发送给BitTube#mSendFd句柄。
注意,SurfaceFlinger有两个EventThread线程,运行在各自的循环中。

收到信号时,遍历收到信号的Connection,调用它的postEvent方法。

status_t EventThread::Connection::postEvent(
        const DisplayEventReceiver::Event& event) {
    ssize_t size = DisplayEventReceiver::sendEvents(mChannel, &event, 1);
    return size < 0 ? status_t(size) : status_t(NO_ERROR);
 }

DisplayEventReceiver的sendEvents方法。

ssize_t DisplayEventReceiver::sendEvents(const sp<BitTube>& dataChannel,
        Event const* events, size_t count) {
    return BitTube::sendObjects(dataChannel, events, count);
}

利用Connection内部BitTube(即mChannel),BitTube的sendObjects将触发BitTube#write方法,向mSendFd写入数据,App进程mReceiveFd可收到数据,实现SurfaceFlinger进程到App进程的数据传输。

App进程Choreographer线程监听消息

在接收器架构中,JNI层的NativeDisplayEventReceiver继承LooperCallback,在初始化addFd时,将本身加入Looper回调,当App进程的mReceiveFd描述符收到消息后,Choreographer线程的底层Looper将触发LooperCallback的handleEvent方法。也就是NativeDisplayEventReceiver的handleEvent方法。
调用dispatchVsync方法。

void NativeDisplayEventReceiver::dispatchVsync(nsecs_t timestamp, int32_t 
          id, uint32_t count) {
    JNIEnv* env = AndroidRuntime::getJNIEnv();
    ScopedLocalRef<jobject> receiverObj(env, jniGetReferent(env, mReceiverWeakGlobal));
    if (receiverObj.get()) {
        env->CallVoidMethod(receiverObj.get(),
                gDisplayEventReceiverClassInfo.dispatchVsync, timestamp, id, count);
    }
    ...
}

CallVoidMethod方法将调用Java层DisplayEventReceiver对象dispatchVsync方法。

private void dispatchVsync(long timestampNanos, int builtInDisplayId, int frame) {
    onVsync(timestampNanos, builtInDisplayId, frame);
}

在Choreographer类,接收器就是FrameDisplayEventReceiver类型,它重写onVsync方法,被底层Looper监听到的,在Choreographer线程执行。onVsync方法的流程图。

FrameDisplayEventReceiver的onVsync方法执行流程图.jpg

@Override
public void onVsync(long timestampNanos, int builtInDisplayId, int frame) {
    ...
    long now = System.nanoTime();
    if (timestampNanos > now) {
        timestampNanos = now;
    }
    ...
    mTimestampNanos = timestampNanos;
    mFrame = frame;
    Message msg = Message.obtain(mHandler, this);
    msg.setAsynchronous(true);
    mHandler.sendMessageAtTime(msg, timestampNanos / TimeUtils.NANOS_PER_MS);
}

特定的时刻发送消息,Message携带任务,而FrameDisplayEventReceiver实现Runnable,因此,最后在特定的时刻运行FrameDisplayEventReceiver的run方法。

@Override
public void run() {
    mHavePendingVsync = false;
    doFrame(mTimestampNanos, mFrame);
}

触发doFrame方法。

void doFrame(long frameTimeNanos, int frame) {
    final long startNanos;
    synchronized (mLock) {
        if (!mFrameScheduled) {
            return; // no work to do
        }
        long intendedFrameTimeNanos = frameTimeNanos;
        startNanos = System.nanoTime();
        final long jitterNanos = startNanos - frameTimeNanos;
        if (jitterNanos >= mFrameIntervalNanos) {
            final long skippedFrames = jitterNanos / mFrameIntervalNanos;
            if (skippedFrames >= SKIPPED_FRAME_WARNING_LIMIT) {
                Log.i(TAG, "Skipped " + skippedFrames + " frames!  "
                        + "The application may be doing too much work on its main thread.");
            }
            final long lastFrameOffset = jitterNanos % mFrameIntervalNanos;
            if (DEBUG_JANK) {
                Log.d(TAG, "Missed vsync by " + (jitterNanos * 0.000001f) + " ms "
                        + "which is more than the frame interval of "
                        + (mFrameIntervalNanos * 0.000001f) + " ms!  "
                        + "Skipping " + skippedFrames + " frames and setting frame "
                        + "time to " + (lastFrameOffset * 0.000001f) + " ms in the past.");
            }
            frameTimeNanos = startNanos - lastFrameOffset;
        }

        if (frameTimeNanos < mLastFrameTimeNanos) {
            if (DEBUG_JANK) {
                Log.d(TAG, "Frame time appears to be going backwards.  May be due to a "
                        + "previously skipped frame.  Waiting for next vsync.");
            }
            scheduleVsyncLocked();
            return;
        }

        mFrameInfo.setVsync(intendedFrameTimeNanos, frameTimeNanos);
        mFrameScheduled = false;
        mLastFrameTimeNanos = frameTimeNanos;
    }

    try {
        mFrameInfo.markInputHandlingStart();
        doCallbacks(Choreographer.CALLBACK_INPUT, frameTimeNanos);

        mFrameInfo.markAnimationsStart();
        doCallbacks(Choreographer.CALLBACK_ANIMATION, frameTimeNanos);

        mFrameInfo.markPerformTraversalsStart();
        doCallbacks(Choreographer.CALLBACK_TRAVERSAL, frameTimeNanos);
        doCallbacks(Choreographer.CALLBACK_COMMIT, frameTimeNanos);
    } finally {
    }
}

恢复mFrameScheduled标志,入参代表上一个帧的时间,如果当前时间已经>=frameTimeNanos一个间隔,表示发生了跳帧,根据时间差值/帧间隔计算跳过帧数,重置frameTimeNanos为不发生挑帧时,最近的一个帧时间点。最后,设置mLastFrameTimeNanos值,记录上一帧的时间。
下面的事情就是回调处理每个类型的Callbacks,触发CallbackRecord的run方法,CallbackRecord封装了任务action。对于CALLBACK_TRAVERSAL类型,最终会回调到ViewRootImpl#TraversalRunnable的run方法。

final class TraversalRunnable implements Runnable {
    @Override
    public void run() {
        doTraversal();
    }
}

ViewRootImpl的doTraversal方法,实现一次遍历绘制。


总结

1,Java层DisplayEventReceiver通过JNI调用,根据底层垂直同步信号请求,实现帧画面的显示控制,在需要绘制时,发起请求,当底层发出信号时,同步回调到上层执行。底层初始化(nativeInit),发起请求(scheduleVsync),实现回调(dispatchVsync)。
2,请求信号时,利用Binder机制同surfaceflinger进程通信,在surfaceflinger进程的业务对象是Connection,代表和App的一个连接。
3,底层通知上层是通过socketpair建立一对匿名已经连接套接字mReceiveFd与mSendFd,实现SurfaceFlinger与App进程的双向通信管道。在App进程中,有mReceiveFd描述符,监听描述符来自SurfaceFlinger进程mSendFd端的消息。
4,App进程Choreographer线程Looper负责监听来自mReceiveFd描述符。


任重而道远

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 156,265评论 4 359
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 66,274评论 1 288
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 106,087评论 0 237
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,479评论 0 203
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 51,782评论 3 285
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,218评论 1 207
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,594评论 2 309
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,316评论 0 194
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 33,955评论 1 237
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,274评论 2 240
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,803评论 1 255
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,177评论 2 250
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,732评论 3 229
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 25,953评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,687评论 0 192
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,263评论 2 267
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,189评论 2 258

推荐阅读更多精彩内容