Choreographer
Choreographer的中文翻譯是編舞者、舞蹈編導的意思,爲什麼起這個名字呢?因爲view的刷新和舞蹈一樣是需要按着節拍來的,Choreographer就是根據VSync信號這個節拍來安排view的刷新動作。
它使用ThreadLocal單例模式,每個線程都有自己的Choreographer,靠Looper去同步:
public final class Choreographer {
...
private static final ThreadLocal<Choreographer> sThreadInstance = new ThreadLocal<Choreographer>() {
@Override
protected Choreographer initialValue() {
Looper looper = Looper.myLooper();
if (looper == null) {
throw new IllegalStateException("The current thread must have a looper!");
}
return new Choreographer(looper, VSYNC_SOURCE_APP);
}
};
..
public static Choreographer getInstance() {
return sThreadInstance.get();
}
}
而且Choreographer實際上不僅僅是控制view刷新,作爲一個舞蹈編導需要編排多個人的動作,它也需要控制多種類型的事件的處理。
它內部有4條CallbackQueue,分別控制input、animation、traversal和commit:
public static final int CALLBACK_INPUT = 0;
public static final int CALLBACK_ANIMATION = 1;
public static final int CALLBACK_TRAVERSAL = 2;
public static final int CALLBACK_COMMIT = 3;
private static final int CALLBACK_LAST = CALLBACK_COMMIT;
private Choreographer(Looper looper, int vsyncSource) {
...
mCallbackQueues = new CallbackQueue[CALLBACK_LAST + 1];
for (int i = 0; i <= CALLBACK_LAST; i++) {
mCallbackQueues[i] = new CallbackQueue();
}
}
ViewRootImpl在requestLayout的時候就是丟到了CALLBACK_TRAVERSAL類型的CallbackQueue裏面:
@Override
public void requestLayout() {
...
scheduleTraversals();
..
}
void scheduleTraversals() {
if (!mTraversalScheduled) {
mTraversalScheduled = true;
mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
mChoreographer.postCallback(
Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
...
}
}
Choreographer會找到對應的CallbackQueue然後使用addCallbackLocked將他們按時間順序插入:
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) {
...
postCallbackDelayedInternal(callbackType, action, token, delayMillis);
}
private void postCallbackDelayedInternal(int callbackType,
Object action, Object token, long delayMillis) {
...
final long now = SystemClock.uptimeMillis();
final long dueTime = now + delayMillis;
mCallbackQueues[callbackType].addCallbackLocked(dueTime, action, token);
...
}
private final class CallbackQueue {
...
public void addCallbackLocked(long dueTime, Object action, Object token) {
CallbackRecord callback = obtainCallbackLocked(dueTime, action, token);
CallbackRecord entry = mHead;
if (entry == null) {
mHead = callback;
return;
}
if (dueTime < entry.dueTime) {
callback.next = entry;
mHead = callback;
return;
}
while (entry.next != null) {
if (dueTime < entry.next.dueTime) {
callback.next = entry.next;
break;
}
entry = entry.next;
}
entry.next = callback;
}
...
}
從上面代碼我們可以看出來CallbackQueue是個單鏈表,而Choreographer裏維護了四條CallbackQueue用於不同類的回調:
插入CallbackQueue之後Choreographer就會向DisplayEventReceiver請求一個Vsync信號的監聽:
private void postCallbackDelayedInternal(int callbackType,
Object action, Object token, long delayMillis) {
...
scheduleFrameLocked(now);
...
}
private void scheduleFrameLocked(long now) {
...
scheduleVsyncLocked();
...
}
private void scheduleVsyncLocked() {
mDisplayEventReceiver.scheduleVsync();
}
DisplayEventReceiver的監聽原理我們等下再看,總之調用scheduleVsync之後DisplayEventReceiver會監聽一次Vsync信號,然後在接收到信號的時候回調onVsync,而Choreographer有個FrameDisplayEventReceiver內部類繼承了DisplayEventReceiver並且實現了Runnable接口,它在onVsync裏面就會通過Handler機制將自己同步到Looper線程去執行run方法,去調用Choreographer.doFrame:
private final class FrameDisplayEventReceiver extends DisplayEventReceiver
implements Runnable {
...
@Override
public void onVsync(long timestampNanos, int builtInDisplayId, int frame) {
...
mFrame = frame;
Message msg = Message.obtain(mHandler, this);
msg.setAsynchronous(true);
mHandler.sendMessageAtTime(msg, timestampNanos / TimeUtils.NANOS_PER_MS);
}
@Override
public void run() {
mHavePendingVsync = false;
doFrame(mTimestampNanos, mFrame);
}
}
而Choreographer.doFrame裏面就會去回調之前post的callback了:
void doFrame(long frameTimeNanos, int frame) {
...
try {
Trace.traceBegin(Trace.TRACE_TAG_VIEW, "Choreographer#doFrame");
AnimationUtils.lockAnimationClock(frameTimeNanos / TimeUtils.NANOS_PER_MS);
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 {
AnimationUtils.unlockAnimationClock();
Trace.traceEnd(Trace.TRACE_TAG_VIEW);
}
...
}
DisplayEventReceiver
java層的DisplayEventReceiver基本就是個殼,都是通過jni調到native層,由native層c++的NativeDisplayEventReceiver去幹活:
public DisplayEventReceiver(Looper looper, int vsyncSource) {
...
mReceiverPtr = nativeInit(new WeakReference<DisplayEventReceiver>(this), mMessageQueue,
vsyncSource);
...
}
private void dispose(boolean finalized) {
...
nativeDispose(mReceiverPtr);
mReceiverPtr = 0;
...
}
public void scheduleVsync() {
...
nativeScheduleVsync(mReceiverPtr);
...
}
jni層是這樣的,溝通了java層的DisplayEventReceiver和native層的NativeDisplayEventReceiver:
// 動態註冊JNI回調
static const JNINativeMethod gMethods[] = {
{ "nativeInit",
"(Ljava/lang/ref/WeakReference;Landroid/os/MessageQueue;I)J",
(void*)nativeInit },
{ "nativeDispose",
"(J)V",
(void*)nativeDispose },
{ "nativeScheduleVsync", "(J)V",
(void*)nativeScheduleVsync }
};
static jlong nativeInit(JNIEnv* env, jclass clazz, jobject receiverWeak,
jobject messageQueueObj, jint vsyncSource) {
...
sp<NativeDisplayEventReceiver> receiver = new NativeDisplayEventReceiver(env,
receiverWeak, messageQueue, vsyncSource);
...
return reinterpret_cast<jlong>(receiver.get());
}
static void nativeDispose(JNIEnv* env, jclass clazz, jlong receiverPtr) {
NativeDisplayEventReceiver* receiver =
reinterpret_cast<NativeDisplayEventReceiver*>(receiverPtr);
receiver->dispose();
..
}
static void nativeScheduleVsync(JNIEnv* env, jclass clazz, jlong receiverPtr) {
sp<NativeDisplayEventReceiver> receiver =
reinterpret_cast<NativeDisplayEventReceiver*>(receiverPtr);
status_t status = receiver->scheduleVsync();
...
}
我們現在開始看看scheduleVsync裏面具體幹了些啥,由於NativeDisplayEventReceiver是繼承了DisplayEventDispatcher,而且沒有重寫該方法,所以我們要實際應該去看DisplayEventDispatcher::scheduleVsync。
class NativeDisplayEventReceiver : public DisplayEventDispatcher {
public:
NativeDisplayEventReceiver(JNIEnv* env,
jobject receiverWeak, const sp<MessageQueue>& messageQueue, jint vsyncSource);
void dispose();
protected:
virtual ~NativeDisplayEventReceiver();
private:
jobject mReceiverWeakGlobal;
sp<MessageQueue> mMessageQueue;
DisplayEventReceiver mReceiver;
virtual void dispatchVsync(nsecs_t timestamp, int32_t id, uint32_t count);
virtual void dispatchHotplug(nsecs_t timestamp, int32_t id, bool connected);
};
status_t DisplayEventDispatcher::scheduleVsync() {
if (!mWaitingForVsync) {
...
status_t status = mReceiver.requestNextVsync();
...
mWaitingForVsync = true;
}
return OK;
}
可以看到DisplayEventDispatcher::scheduleVsync又是調用mReceiver.requestNextVsync請求下一個VSync信號,這個mReceiver是DisplayEventReceiver:
DisplayEventReceiver mReceiver;
所以我們就繼續追蹤:
status_t DisplayEventReceiver::requestNextVsync() {
if (mEventConnection != NULL) {
mEventConnection->requestNextVsync();
return NO_ERROR;
}
return NO_INIT;
}
DisplayEventReceiver::DisplayEventReceiver(ISurfaceComposer::VsyncSource vsyncSource) {
sp<ISurfaceComposer> sf(ComposerService::getComposerService());
if (sf != NULL) {
mEventConnection = sf->createDisplayEventConnection(vsyncSource);
if (mEventConnection != NULL) {
mDataChannel = std::make_unique<gui::BitTube>();
mEventConnection->stealReceiveChannel(mDataChannel.get());
}
}
}
這裏打開了一個ComposerService連接,然後實際是向這個服務請求VSync信號。Composer是作曲家的意思,實際上和之前java層的編舞者是對應的。作曲家作曲,譜寫節奏,編舞者根據節奏指揮舞蹈。
上面講的DisplayEventReceiver感覺就是個套娃架構,一層套一層。而且類的名字又很接近,所以直接追蹤代碼的確比較暈,看下面的時序圖的話會好一些:
VSync信號的讀取
ComposerService實際上是指的SurfaceFlinger服務的client端包裝類:
/*static*/ sp<ISurfaceComposer> ComposerService::getComposerService() {
ComposerService& instance = ComposerService::getInstance();
...
if (instance.mComposerService == NULL) {
ComposerService::getInstance().connectLocked();
...
}
return instance.mComposerService;
}
void ComposerService::connectLocked() {
const String16 name("SurfaceFlinger");
while (getService(name, &mComposerService) != NO_ERROR) {
usleep(250000);
}
...
}
所以createDisplayEventConnection最終調用到SurfaceFlinger::createDisplayEventConnection,在這個方法用mEventThread去createEventConnection,最終創建一個Connection:
sp<IDisplayEventConnection> SurfaceFlinger::createDisplayEventConnection(
ISurfaceComposer::VsyncSource vsyncSource) {
...
return mEventThread->createEventConnection();
...
}
sp<EventThread::Connection> EventThread::createEventConnection() const {
return new Connection(const_cast<EventThread*>(this));
}
然後Connection是個安卓裏面的只能指針類型(RefBase)它在第一次引用計數的時候會調用onFirstRef,在這裏Connection會將自己註冊到EventThread的mDisplayEventConnections列表裏:
void EventThread::Connection::onFirstRef() {
// NOTE: mEventThread doesn't hold a strong reference on us
mEventThread->registerDisplayEventConnection(this);
}
status_t EventThread::registerDisplayEventConnection(
const sp<EventThread::Connection>& connection) {
...
mDisplayEventConnections.add(connection);
...
return NO_ERROR;
}
requestNextVsync最終是會調用到Connection::requestNextVsync,而這裏除了會調用到SurfaceFlinger::resyncWithRateLimit去請求VSync信號之外還會將設置Connection的count:
void EventThread::Connection::requestNextVsync() {
mEventThread->requestNextVsync(this);
}
void EventThread::requestNextVsync(
const sp<EventThread::Connection>& connection) {
Mutex::Autolock _l(mLock);
mFlinger.resyncWithRateLimit();
if (connection->count < 0) {
connection->count = 0;
mCondition.broadcast();
}
}
從註釋可以看出來這個count是用來標誌這次應用進程VSync信號的請求是一次性的,還是多次的:
// count >= 1 : continuous event. count is the vsync rate
// count == 0 : one-shot event that has not fired
// count ==-1 : one-shot event that fired this round / disabled
int32_t count;
然後mCondition.broadcast()就會喚醒EventThread的waitForEvent流程,這個流程相對比較複雜,我先將刪除註釋之後的完整代碼貼出來,然後再詳細解釋:
001 Vector< sp<EventThread::Connection> > EventThread::waitForEvent(
002 DisplayEventReceiver::Event* event)
003 {
004 Mutex::Autolock _l(mLock);
005 Vector< sp<EventThread::Connection> > signalConnections;
006
007 do {
008 bool eventPending = false;
009 bool waitForVSync = false;
010
011 size_t vsyncCount = 0;
012 nsecs_t timestamp = 0;
013 for (int32_t i=0 ; i<DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES ; i++) {
014 timestamp = mVSyncEvent[i].header.timestamp;
015 if (timestamp) {
016 if (mInterceptVSyncs) {
017 mFlinger.mInterceptor.saveVSyncEvent(timestamp);
018 }
019 *event = mVSyncEvent[i];
020 mVSyncEvent[i].header.timestamp = 0;
021 vsyncCount = mVSyncEvent[i].vsync.count;
022 break;
023 }
024 }
025
026 if (!timestamp) {
027 eventPending = !mPendingEvents.isEmpty();
028 if (eventPending) {
029 *event = mPendingEvents[0];
030 mPendingEvents.removeAt(0);
031 }
032 }
033
034 size_t count = mDisplayEventConnections.size();
035 for (size_t i=0 ; i<count ; i++) {
036 sp<Connection> connection(mDisplayEventConnections[i].promote());
037 if (connection != NULL) {
038 bool added = false;
039 if (connection->count >= 0) {
040 waitForVSync = true;
041 if (timestamp) {
042 if (connection->count == 0) {
043 connection->count = -1;
044 signalConnections.add(connection);
045 added = true;
046 } else if (connection->count == 1 ||
047 (vsyncCount % connection->count) == 0) {
048 signalConnections.add(connection);
049 added = true;
050 }
051 }
052 }
053
054 if (eventPending && !timestamp && !added) {
055 signalConnections.add(connection);
056 }
057 } else {
058 mDisplayEventConnections.removeAt(i);
059 --i; --count;
060 }
061 }
062
063 if (timestamp && !waitForVSync) {
064 disableVSyncLocked();
065 } else if (!timestamp && waitForVSync) {
066 enableVSyncLocked();
067 }
068
069 if (!timestamp && !eventPending) {
070 if (waitForVSync) {
071 bool softwareSync = mUseSoftwareVSync;
072 nsecs_t timeout = softwareSync ? ms2ns(16) : ms2ns(1000);
073 if (mCondition.waitRelative(mLock, timeout) == TIMED_OUT) {
074 if (!softwareSync) {
075 ALOGW("Timed out waiting for hw vsync; faking it");
076 }
077 mVSyncEvent[0].header.type = DisplayEventReceiver::DISPLAY_EVENT_VSYNC;
078 mVSyncEvent[0].header.id = DisplayDevice::DISPLAY_PRIMARY;
079 mVSyncEvent[0].header.timestamp = systemTime(SYSTEM_TIME_MONOTONIC);
080 mVSyncEvent[0].vsync.count++;
081 }
082 } else {
083 mCondition.wait(mLock);
084 }
085 }
086 } while (signalConnections.isEmpty());
087
088 return signalConnections;
089 }
首先一開始waitForEvent是阻塞在083行的mCondition.wait(mLock)這裏等待,EventThread::requestNextVsync會將它喚醒,然後在013~024檢查喚醒之前是否已經有VSync信號,我們先假設沒有,那麼timestamp就一直是0。
然後繼續跑到039行,這個的count在EventThread::requestNextVsync已經被設置>=0了,所以會進去將waitForVSync設置成true。而041行由於timestamp是0所以不會進去。
我們假設mPendingEvents也是空的,於是eventPending也是false, 接着就繼續跑到073等待VSync信號了。
這裏用mCondition.waitRelative等待一段時間,其實是在等待之前調用SurfaceFlinger::resyncWithRateLimit請求的屏幕硬件VSync信號,如果信號到來的話EventThread::onVSyncEvent會被調用,然後喚醒線程:
void EventThread::onVSyncEvent(nsecs_t timestamp) {
Mutex::Autolock _l(mLock);
mVSyncEvent[0].header.type = DisplayEventReceiver::DISPLAY_EVENT_VSYNC;
mVSyncEvent[0].header.id = 0;
mVSyncEvent[0].header.timestamp = timestamp;
mVSyncEvent[0].vsync.count++;
mCondition.broadcast();
}
如果一直沒有到來的話,等待時間結束,返回TIMED_OUT的話也會用軟件模擬一個VSync信號。
然後就會繼續do-while循環跑到013~024將timestamp和參數出參event的內容給設置了,接着在041行的timestamp判斷不爲0,於是就會將Connection放到signalConnections,最後在while裏面判斷到signalConnections不爲空退出循環。
VSync信號的發送
於是乎threadLoop就能拿到event和Connection列表,將事件分發出去:
bool EventThread::threadLoop() {
DisplayEventReceiver::Event event;
Vector< sp<EventThread::Connection> > signalConnections;
signalConnections = waitForEvent(&event);
// dispatch events to listeners...
const size_t count = signalConnections.size();
for (size_t i=0 ; i<count ; i++) {
const sp<Connection>& conn(signalConnections[i]);
// now see if we still need to report this event
status_t err = conn->postEvent(event);
...
}
return true;
}
Connection::postEvent實際是調用DisplayEventReceiver::sendEvents往Channel裏面發送消息:
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);
}
還記得在app端createDisplayEventConnection的代碼嗎?我們得到Connection之後調用了stealReceiveChannel方法,它就將c/s兩端的通信鏈路打通了:
DisplayEventReceiver::DisplayEventReceiver(ISurfaceComposer::VsyncSource vsyncSource) {
sp<ISurfaceComposer> sf(ComposerService::getComposerService());
if (sf != NULL) {
mEventConnection = sf->createDisplayEventConnection(vsyncSource);
if (mEventConnection != NULL) {
mDataChannel = std::make_unique<gui::BitTube>();
mEventConnection->stealReceiveChannel(mDataChannel.get());
}
}
}
status_t EventThread::Connection::stealReceiveChannel(gui::BitTube* outChannel) {
outChannel->setReceiveFd(mChannel.moveReceiveFd());
return NO_ERROR;
}
所以s端寫入event之後c端就能讀取到。這個fd的監聽是在DisplayEventDispatcher::initialize裏面寫入的,它往mLooper裏面add了DataChannel的Fd:
status_t DisplayEventDispatcher::initialize() {
...
int rc = mLooper->addFd(mReceiver.getFd(), 0, Looper::EVENT_INPUT,
this, NULL);
...
}
int DisplayEventReceiver::getFd() const {
if (mDataChannel == NULL)
return NO_INIT;
return mDataChannel->getFd();
}
所以當消息到來之後DisplayEventDispatcher::handleEvent就會被調用然後再使用dispatchVsync去發送VSync事件
int DisplayEventDispatcher::handleEvent(int, int events, void*) {
...
nsecs_t vsyncTimestamp;
int32_t vsyncDisplayId;
uint32_t vsyncCount;
if (processPendingEvents(&vsyncTimestamp, &vsyncDisplayId, &vsyncCount)) {
...
dispatchVsync(vsyncTimestamp, vsyncDisplayId, vsyncCount);
}
return 1; // keep the callback
}
這個在dispatchVsync子類NativeDisplayEventReceiver中實現,它會使用jni回調java層的DisplayEventReceiver.dispatchVsync:
gDisplayEventReceiverClassInfo.dispatchVsync = GetMethodIDOrDie(env,
gDisplayEventReceiverClassInfo.clazz, "dispatchVsync", "(JII)V");
void NativeDisplayEventReceiver::dispatchVsync(nsecs_t timestamp, int32_t id, uint32_t count) {
JNIEnv* env = AndroidRuntime::getJNIEnv();
...
env->CallVoidMethod(receiverObj.get(),
gDisplayEventReceiverClassInfo.dispatchVsync, timestamp, id, count);
...
}
而java層的dispatchVsync再調onVsync方法
@SuppressWarnings("unused")
private void dispatchVsync(long timestampNanos, int builtInDisplayId, int frame) {
onVsync(timestampNanos, builtInDisplayId, frame);
}
而這個onVsync在我們在第一節Choreographer流程裏面有講到,它會調到Choreographer.doFrame去回調註冊的Callback:
private final class FrameDisplayEventReceiver extends DisplayEventReceiver
implements Runnable {
...
@Override
public void onVsync(long timestampNanos, int builtInDisplayId, int frame) {
...
mFrame = frame;
Message msg = Message.obtain(mHandler, this);
msg.setAsynchronous(true);
mHandler.sendMessageAtTime(msg, timestampNanos / TimeUtils.NANOS_PER_MS);
}
@Override
public void run() {
mHavePendingVsync = false;
doFrame(mTimestampNanos, mFrame);
}
}
總結
所以整個調用關係如下圖:
ViewRootImpl將Callback丟到Choreographer之後,通過FrameDisplayEventReceiver調到Native層的NativeDisplayEventReceiver。
然後通過Connect調用到SurfaceFlinger進程的EventThread,在這裏向SurfaceFlinger請求一次VSync信號並且等待信號到來之後通過DataChannel回調到應用進程的NativeDisplayEventReceiver。
之後再通過jni調回java層FrameDisplayEventReceiver和Choreographer去執行post的Callback去執行view的佈局繪製。