Android在黄油计划中引入了三缓存+VSync的显示机制,简单概括就是屏幕每次刷新发送VSYNC信号,如果帧率为60fps,那么每隔16ms发送一个VSYNC信号,CPU加接收到VSYNC信号后放下手中的工作,立即处理显示相关的工作(layout, draw),然后将数据buffer交给GPU,GPU处理完和Display交换缓存数据buffer,Display每次都在拿到完整的一帧数据buffer后开始刷新工作,三缓存在GPU处理超时(>16ms)Jank时参与,提供一个空闲的缓存给CPU提前开始处理数据,避免下一帧因为同样的原因继续超时Jank。
其中Choreographer就是CPU用来接收VSYNC信号的对象。
一、Choreographer
Choreographer实例在ViewRootImpl构造器中被赋值给mChoreographer变量。
public ViewRootImpl(@UiContext Context context, Display display, IWindowSession session,
WindowLayout windowLayout) {
mChoreographer = Choreographer.getInstance();
}
getInstance()从线程变量Choreographer.sThreadInstance获取实例对象,可知Choreographer为线程单例对象。
private static final ThreadLocal<Choreographer> sThreadInstance =
new ThreadLocal<Choreographer>() {
@Override
protected Choreographer initialValue() {
Looper looper = Looper.myLooper();
Choreographer choreographer = new Choreographer(looper, VSYNC_SOURCE_APP);
if (looper == Looper.getMainLooper()) {
mMainInstance = choreographer;
}
return choreographer;
}
};
查看Choreographer构造方法:
private Choreographer(Looper looper, int vsyncSource) {
mLooper = looper;
// 1.创建处理 frame 事件相关的handler。
mHandler = new FrameHandler(looper);
// 2.创建mDisplayEventReceiver,VSYNC信号接收器。
mDisplayEventReceiver = USE_VSYNC
? new FrameDisplayEventReceiver(looper, vsyncSource)
: null;
// 3.记录最后绘制的时间
mLastFrameTimeNanos = Long.MIN_VALUE;
// 4.记录每帧间隔: 1s / 屏幕刷新率
mFrameIntervalNanos = (long)(1000000000 / getRefreshRate());
// 5.初始化CallbackQueue,数组大小为 5。
mCallbackQueues = new CallbackQueue[CALLBACK_LAST + 1];
for (int i = 0; i <= CALLBACK_LAST; i++) {
mCallbackQueues[i] = new CallbackQueue();
}
// b/68769804: For low FPS experiments.
setFPSDivisor(SystemProperties.getInt(ThreadedRenderer.DEBUG_FPS_DIVISOR, 1));
}
Choreographer的构造方法主要做了5件事:
- 创建处理 frame 事件相关的FrameHandler,looper是实例化ViewRootImpl的线程,一般是主线程。
- 创建mDisplayEventReceiver,VSYNC信号接收器。
- 记录最后绘制的时间mLastFrameTimeNanos。
- 设置屏幕刷新率mFrameIntervalNanos。
- 初始化CallbackQueue,数组大小为 5。CallbackQueue专门用来处理ViewRootImpl通过mChoreographer.postCallback()方法传递过来的回调事件,如ViewRootImpl在requestLayout()布局阶段:
mChoreographer.postCallback(
Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
Choreographer 定义了以下5中回调类型:- CALLBACK_INPUT:输入事件。
- CALLBACK_ANIMATION:动画事件。
- CALLBACK_INSETS_ANIMATION:insets updates,INPUT和ANIMATION都会影响INSETS_ANIMATION,所以需要在这两之后执行。insets表示app和SystemUI,IME等系统组件重叠的部分。
- CALLBACK_TRAVERSAL:layout, draw事件
- CALLBACK_COMMIT:Commit callback,处理绘制完成后的操作。
接下来看下DisplayEventReceiver创建流程:
二、DisplayEventReceiver
// Choreographer.java
private final class FrameDisplayEventReceiver extends DisplayEventReceiver
implements Runnable {
private long mTimestampNanos;
private int mFrame;
private VsyncEventData mLastVsyncEventData = new VsyncEventData();
public FrameDisplayEventReceiver(Looper looper, int vsyncSource) {
super(looper, vsyncSource, 0);
}
@Override
public void onVsync(long timestampNanos, long physicalDisplayId, int frame,
VsyncEventData vsyncEventData) {
try {
mFrame = frame;
mLastVsyncEventData = vsyncEventData;
Message msg = Message.obtain(mHandler, this);
msg.setAsynchronous(true);
mHandler.sendMessageAtTime(msg, timestampNanos / TimeUtils.NANOS_PER_MS);
} finally {
Trace.traceEnd(Trace.TRACE_TAG_VIEW);
}
}
@Override
public void run() {
mHavePendingVsync = false;
doFrame(mTimestampNanos, mFrame, mLastVsyncEventData);
}
}
FrameDisplayEventReceiver继承DisplayEventReceiver,并且实现了Runnable接口,覆盖了onVsync()方法,在接收到VSYNC信号后回调onVsync,通过mHandler发送消息回调自己的run()方法,调用doFrame(mTimestampNanos, mFrame, mLastVsyncEventData);处理业务逻辑。
查看父类DisplayEventReceiver如何实现接收VSYNC信号。
2.1 DisplayEventReceiver实例化
//DisplayEventReceiver.java
public DisplayEventReceiver(Looper looper, int vsyncSource, int eventRegistration) {
mMessageQueue = looper.getQueue();
mReceiverPtr = nativeInit(new WeakReference<DisplayEventReceiver>(this), mMessageQueue,
vsyncSource, eventRegistration);
}
调用nativeInit方法,参数vsyncSource变量值是VSYNC_SOURCE_APP,eventRegistration为0。
// android_view_DisplayEventReceiver.cpp
static jlong nativeInit(JNIEnv* env, jclass clazz, jobject receiverWeak, jobject messageQueueObj,
jint vsyncSource, jint eventRegistration) {
// 1.实例化NativeDisplayEventReceiver
sp<NativeDisplayEventReceiver> receiver =
new NativeDisplayEventReceiver(env, receiverWeak, messageQueue, vsyncSource,
eventRegistration);
// 2.initialize
status_t status = receiver->initialize();
}
class NativeDisplayEventReceiver : public DisplayEventDispatcher {
NativeDisplayEventReceiver::NativeDisplayEventReceiver(JNIEnv* env, jobject receiverWeak,
const sp<MessageQueue>& messageQueue,
jint vsyncSource, jint eventRegistration)
: DisplayEventDispatcher(messageQueue->getLooper(),
static_cast<ISurfaceComposer::VsyncSource>(vsyncSource),
static_cast<ISurfaceComposer::EventRegistration>(eventRegistration)),
mReceiverWeakGlobal(env->NewGlobalRef(receiverWeak)),
mMessageQueue(messageQueue) {}
}
nativeInit主要做了两件事:
- 实例化了NativeDisplayEventReceiver对象,NativeDisplayEventReceiver继承自父类DisplayEventDispatcher。
- 调用receiver->initialize()。
查看父类DisplayEventDispatcher。
2.1.1 DisplayEventDispatcher
// DisplayEventDispatcher.cpp
class DisplayEventDispatcher : public LooperCallback {
DisplayEventReceiver mReceiver;
DisplayEventDispatcher::DisplayEventDispatcher(
const sp<Looper>& looper, ISurfaceComposer::VsyncSource vsyncSource,
ISurfaceComposer::EventRegistrationFlags eventRegistration)
: mLooper(looper), mReceiver(vsyncSource, eventRegistration), mWaitingForVsync(false),
mLastVsyncCount(0), mLastScheduleVsyncTime(0) {}
status_t DisplayEventDispatcher::initialize() {
if (mLooper != nullptr) {
int rc = mLooper->addFd(mReceiver.getFd(), 0, Looper::EVENT_INPUT, this, NULL);
}
return OK;
}
}
DisplayEventDispatcher通过传递过来的参数实例化DisplayEventReceiver对象mReceiver,查看DisplayEventReceiver定义:
2.1.1.1 DisplayEventReceiver
// DisplayEventReceiver.cpp
DisplayEventReceiver::DisplayEventReceiver(
ISurfaceComposer::VsyncSource vsyncSource,
ISurfaceComposer::EventRegistrationFlags eventRegistration) {
// 1.获取SurfaceFlinger对象
sp<ISurfaceComposer> sf(ComposerService::getComposerService());
if (sf != nullptr) {
// 2.surfaceflinger创建新的连接
mEventConnection = sf->createDisplayEventConnection(vsyncSource, eventRegistration);
if (mEventConnection != nullptr) {
// 3.实例化BitTube对象,BitTube实例使用socket本地通信
mDataChannel = std::make_unique<gui::BitTube>();
// 4.BitTube实例关联IDisplayEventConnection
const auto status = mEventConnection->stealReceiveChannel(mDataChannel.get());
if (!status.isOk()) {
ALOGE("stealReceiveChannel failed: %s", status.toString8().c_str());
mInitError = std::make_optional<status_t>(status.transactionError());
mDataChannel.reset();
mEventConnection.clear();
}
}
}
}
DisplayEventReceiver构造方法中主要做了4件事:
- 通过ComposerService::getComposerService()获取SurfaceFlinger对象,getComposerService()方法在SurfaceComposerClient.cpp文件中实现,返回的对象是SurfaceFlinger:
// SurfaceComposerClient.cpp void ComposerService::connectLocked() { const String16 name("SurfaceFlinger"); while (getService(name, &mComposerService) != NO_ERROR) { usleep(250000); } }
- sf->createDisplayEventConnection创建新的连接,通过EventThread实例化新的EventThreadConnection对象,EventThread负责发送VSYNC信号给DisplayEventReceiver,EventThreadConnection持有变量gui::BitTube mChannel作为发送信号通道。
// EventThread.h class EventThreadConnection : public gui::BnDisplayEventConnection { private: gui::BitTube mChannel GUARDED_BY(mLock); }
- 实例化BitTube对象,BitTube类表示DisplayEventReceiver和SurfaceFlinger具体通信通道的实现,内部使用socket本地通信实现,socketpair()创建两个互相连接本地通信(AF_UNIX)的socket,分别赋值给发送端BitTube.mSendFd,接收端BitTube.mReceiveFd:
// BitTube.cpp void BitTube::init(size_t rcvbuf, size_t sndbuf) { int sockets[2]; if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, sockets) == 0) { size_t size = DEFAULT_SOCKET_BUFFER_SIZE; setsockopt(sockets[0], SOL_SOCKET, SO_RCVBUF, &rcvbuf, sizeof(rcvbuf)); setsockopt(sockets[1], SOL_SOCKET, SO_SNDBUF, &sndbuf, sizeof(sndbuf)); setsockopt(sockets[0], SOL_SOCKET, SO_SNDBUF, &size, sizeof(size)); setsockopt(sockets[1], SOL_SOCKET, SO_RCVBUF, &size, sizeof(size)); fcntl(sockets[0], F_SETFL, O_NONBLOCK); fcntl(sockets[1], F_SETFL, O_NONBLOCK); mReceiveFd.reset(sockets[0]); mSendFd.reset(sockets[1]); } }
- mEventConnection->stealReceiveChannel将刚创建好的BitTube对象传递给EventThreadConnection,至此VSYNC信号接收通道就创建好了。
// EventThread.cpp binder::Status EventThreadConnection::stealReceiveChannel(gui::BitTube* outChannel) { outChannel->setReceiveFd(mChannel.moveReceiveFd()); outChannel->setSendFd(base::unique_fd(dup(mChannel.getSendFd()))); return binder::Status::ok(); }
信号接收通道搭建好了,怎么接收处理信号呢?
2.2 receiver->initialize
回到2.1小节DisplayEventReceiver的nativeInit,在实例化NativeDisplayEventReceiver创建信号接收通道之后,调用receiver->initialize()定义信号接收处理操作。
NativeDisplayEventReceiver继承自DisplayEventDispatcher,initialize()在父类DisplayEventDispatcher中定义:
2.2.1 addFd
// DisplayEventDispatcher.cpp
status_t DisplayEventDispatcher::initialize() {
if (mLooper != nullptr) {
int rc = mLooper->addFd(mReceiver.getFd(), 0, Looper::EVENT_INPUT, this, NULL);
}
return OK;
}
通过mLooper epoll机制监听socket,也就是2.1.1.1小节中BitTube.mReceiveFd,监听事件类型为Looper::EVENT_INPUT,mLooper是从Choreographer构造方法一直传递过来的参数赋值的,也就是实例化ViewRootImpl对象的线程。
当socket存在Looper::EVENT_INPUT时唤醒looper,回调handleEvent()方法:
2.2.2 handleEvent
// DisplayEventDispatcher.cpp
int DisplayEventDispatcher::handleEvent(int, int events, void*) {
// Drain all pending events, keep the last vsync.
nsecs_t vsyncTimestamp;
PhysicalDisplayId vsyncDisplayId;
uint32_t vsyncCount;
VsyncEventData vsyncEventData;
if (processPendingEvents(&vsyncTimestamp, &vsyncDisplayId, &vsyncCount, &vsyncEventData)) {
ALOGV("dispatcher %p ~ Vsync pulse: timestamp=%" PRId64
", displayId=%s, count=%d, vsyncId=%" PRId64,
this, ns2ms(vsyncTimestamp), to_string(vsyncDisplayId).c_str(), vsyncCount,
vsyncEventData.preferredVsyncId());
mWaitingForVsync = false;
mLastVsyncCount = vsyncCount;
dispatchVsync(vsyncTimestamp, vsyncDisplayId, vsyncCount, vsyncEventData);
}
if (mWaitingForVsync) {
const nsecs_t currentTime = systemTime(SYSTEM_TIME_MONOTONIC);
const nsecs_t vsyncScheduleDelay = currentTime - mLastScheduleVsyncTime;
if (vsyncScheduleDelay > WAITING_FOR_VSYNC_TIMEOUT) {
ALOGW("Vsync time out! vsyncScheduleDelay=%" PRId64 "ms", ns2ms(vsyncScheduleDelay));
mWaitingForVsync = false;
dispatchVsync(currentTime, vsyncDisplayId /* displayId is not used */,
++mLastVsyncCount, vsyncEventData /* empty data */);
}
}
return 1; // keep the callback
}
调用processPendingEvents()封装vsyncEventData等参数,分发VSYNC事件dispatchVsync()。
2.2.3 dispatchVsync
dispatchVsync方法在子类NativeDisplayEventReceiver实现:
void NativeDisplayEventReceiver::dispatchVsync(nsecs_t timestamp, PhysicalDisplayId displayId,
uint32_t count, VsyncEventData vsyncEventData) {
JNIEnv* env = AndroidRuntime::getJNIEnv();
ScopedLocalRef<jobject> receiverObj(env, GetReferent(env, mReceiverWeakGlobal));
if (receiverObj.get()) {
jobject javaVsyncEventData = createJavaVsyncEventData(env, vsyncEventData);
env->CallVoidMethod(receiverObj.get(), gDisplayEventReceiverClassInfo.dispatchVsync,
timestamp, displayId.value, count, javaVsyncEventData);
}
mMessageQueue->raiseAndClearException(env, "dispatchVsync");
}
封装Java层的vsyncEventData对象,调用Java对象DisplayEventReceiver的dispatchVsync方法。
// DisplayEventReceiver.java
private void dispatchVsync(long timestampNanos, long physicalDisplayId, int frame) {
onVsync(timestampNanos, physicalDisplayId, frame);
}
第2小节提到过,Choreographer中FrameDisplayEventReceiver类继承自DisplayEventReceiver,自此VSYNC信号传递到了Choreographer。
Choreographer在接收到VSYNC信号后执行doFrame()方法。
2.2.4 doFrame
void doFrame(long frameTimeNanos, int frame) {
// 计算丢帧数,startNanos当前时间,frameTimeNanos信号发送时间,jitterNanos也就是信号发送到处理的时间间隔。
final long jitterNanos = startNanos - frameTimeNanos;
if (jitterNanos >= mFrameIntervalNanos) {
final long skippedFrames = jitterNanos / mFrameIntervalNanos;
}
// 更新帧信息mFrameInfo
mFrameInfo.setVsync(intendedFrameTimeNanos, frameTimeNanos);
// 处理 INPUT回调
mFrameInfo.markInputHandlingStart();
doCallbacks(Choreographer.CALLBACK_INPUT, frameTimeNanos);
// 处理 ANIMATION回调
mFrameInfo.markAnimationsStart();
doCallbacks(Choreographer.CALLBACK_ANIMATION, frameTimeNanos);
doCallbacks(Choreographer.CALLBACK_INSETS_ANIMATION, frameTimeNanos);
// 处理 TRAVERSAL回调,layout,draw
mFrameInfo.markPerformTraversalsStart();
doCallbacks(Choreographer.CALLBACK_TRAVERSAL, frameTimeNanos);
// 处理 帧被绘制完成后的操作
doCallbacks(Choreographer.CALLBACK_COMMIT, frameTimeNanos);
}
doFrame更新当前帧信息到mFrameInfo变量,轮流处理回调方法:INPUT(输入事件回调)–>ANIMATION(动画事件回调)–>TRAVERSAL(布局,绘制回调)–>COMMIT(帧被绘制完成后操作)。
一般回调事件都由ViewRootImpl发出,对于处理布局和绘制的CALLBACK_TRAVERSAL消息,为了在接收到VSYNC信号后立即处理显示数据buff,不被线程中其他事件给耽搁,在postCallback前先发送同步消息屏障postSyncBarrier到looper,优先处理异步的CALLBACK_TRAVERSAL消息,在消息被处理后移除looper中的同步消息屏障。
VSYNC信号每隔16ms发送一次,Choreographer每次都要相应VSYNC信号执行doFrame吗?答案是不会,只有在DisplayEventReceiver.scheduleVsync()后才会接收处理VSYNC,比如ViewRootImpl中调用mChoreographer.postCallback():
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);
}
}
}
dueTime判断callback是否需要立即执行,立即执行调用scheduleFrameLocked(now),通过DisplayEventReceiver.scheduleVsync()请求VSYNC信号,SurfaceFlinger在接收到请求信号后发出VSYNC信号,处理完请求后Choreographer不会接收到VSYNC,也就是说一个静止不刷新的界面是不需要接收VSYNC信号刷新的。