parent
54c1571c40
commit
a2d5f7e72f
@ -0,0 +1,301 @@ |
||||
--- |
||||
说说 Android 的 UI 刷新机制 |
||||
--- |
||||
|
||||
1. 丢帧一般是什么原因引起的? |
||||
2. Android 刷新频率 60 帧/秒,每隔 16 ms 调 onDraw 绘制一次? |
||||
3. onDraw 完之后屏幕会马上刷新吗? |
||||
4. 如果界面没有重绘,还会每隔 16ms 刷新屏幕吗? |
||||
5. 如果在屏幕快要刷新的时候才去 onDraw 绘制会丢帧吗? |
||||
|
||||
```java |
||||
public void requestLayout(){ |
||||
scheduleTraversals(); |
||||
} |
||||
void scheduleTraversals(){ |
||||
mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier(); |
||||
if(!mTraversalScheduled){ |
||||
mTraversalScheduled = true; |
||||
mChoreographer.postCallback(Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null); |
||||
} |
||||
} |
||||
// mTraversalRunnable |
||||
void doTraversal(){ |
||||
if(mTraversalScheduled){ |
||||
mTraversalScheduled = false; |
||||
performTraversals(); |
||||
} |
||||
} |
||||
``` |
||||
|
||||
```java |
||||
private void postCallbackDelayedInternal(int callbackType, ){ |
||||
mCallbackQueues[callbackType].addCallbackLocked(dueTime, ...); |
||||
scheduleFrameLocked(now); |
||||
} |
||||
private void scheduleFrameLocked(long now){ |
||||
if(isRunningOnLooperThreadLocked()){ |
||||
scheduleVsyncLocked(); |
||||
}else{ |
||||
Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_VSYNC); |
||||
msg.setAsynchronous(true); |
||||
mHandler.sendMEssageAtFrontOfQueue(msg); |
||||
} |
||||
} |
||||
``` |
||||
|
||||
```java |
||||
class FrameDisplayEventReceiver extends DisplayEventReceiver{ |
||||
public void onVsync(long timestampNanos, int builtInDisplayId, int frame){ |
||||
mTimestampNanos = timestampNanos; |
||||
mFrame = frame; |
||||
Message msg = Message.obtain(mHandler, this); |
||||
msg.setAsynchronous(true); |
||||
mHandler.sendMessageAtTime(msg, timestampNanos/TimeUtils.NANOS_PER_MS); |
||||
} |
||||
public void run(){ |
||||
doFrame(mTimestampNanos, mFrame); |
||||
} |
||||
} |
||||
// Choreographer#doFrame |
||||
void doFrame(long frameTimeNanos, int frame){ |
||||
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; |
||||
frameTimeNanos = startNanos - lastFrameOffset; |
||||
} |
||||
|
||||
// 处理 Callback |
||||
doCallbacks(Choreographer.CALLBACK_INPUT, frameTimeNanos); |
||||
doCallbacks(Choreographer.CALLBACK_ANIMATION, frameTimeNanos); |
||||
doCallbacks(Choreographer.CALLBACK_INSETS_ANIMATION, frameTimeNanos); |
||||
doCallbacks(Choreographer.CALLBACK_TRAVERSAL, frameTimeNanos); |
||||
doCallbacks(Choreographer.CALLBACK_COMMIT, frameTimeNanos); |
||||
} |
||||
void doCallback(int callbackType, long frameTimeNanos){ |
||||
CallbackRecord callbacks; |
||||
callbacks = mCallbackQueues[callbackType].extractDueCallbacksLocked(...); |
||||
for (CallbackRecord c = callbacks; c != null; c = c.next) { |
||||
c.run(frameTimeNanos); |
||||
} |
||||
} |
||||
``` |
||||
|
||||
![](https://i.loli.net/2020/03/25/GfDFqBLMAvKbNdn.png) |
||||
|
||||
```java |
||||
private void scheduleVsyncLocked(){ |
||||
mDisplayEventReceiver.scheduleVsync(); |
||||
} |
||||
``` |
||||
|
||||
```c++ |
||||
status_t NativeDisplayEventReceiver::scheduleVsync(){ |
||||
status_t status = mReceiver.requestNextVsync(); |
||||
} |
||||
status_t DisplayEventReceiver::requestNextVsync(){ |
||||
mEventConnection->requestNextVsync(); |
||||
} |
||||
DisplayEventReceiver::DisplayEventReceiver(){ |
||||
sp<ISurfaceComposer> sf(ComposerService::slef()); |
||||
if(sf!=null){ |
||||
mEventConnection = sf->createDisplayEventConnection(); |
||||
mDataChannel = mEventConnection->getDataChannel(); |
||||
} |
||||
} |
||||
sp<BitTube> EventThread::Connection::getDataChannel() const{ |
||||
return mChannel; |
||||
} |
||||
``` |
||||
|
||||
创建 Connection,实现是在 SurfaceFlinger 里: |
||||
|
||||
```c++ |
||||
sp<IDisplayEventConnection> SurfaceFlinger::createDisplayEventConnection(){ |
||||
return mEventThread->createEventConnection(); |
||||
} |
||||
sp<EventThread::Connection> EventThread::createEventConnection() const { |
||||
return new Connection(const_cast<EventThread*>(this)); |
||||
} |
||||
EventThread::Connection::Connection(const sp<EventThread>&eventThread):count(-1), mEventThread(eventThread), mChannel(new BitTubr()) { |
||||
|
||||
} |
||||
void EventThread::Connection::onFirstRef(){ |
||||
mEventThread->registerDisplayEventConnection(this); |
||||
} |
||||
status_t EventThread::registerDisplayEventConnection(const sp<EventThread::Connection>&connection){ |
||||
mDisplayEventConnections.add(connection); |
||||
mCondition.broadcast(); |
||||
} |
||||
``` |
||||
|
||||
创建 EventThread: |
||||
|
||||
```c++ |
||||
void SurfaceFlinger::init(){ |
||||
sp<VSYNCSource> vsyncSrc = new DispSyncSource(&mPrimaryDispSync, ...); |
||||
mEventThread = new EventThread(vsyncSrc); |
||||
} |
||||
``` |
||||
|
||||
```c++ |
||||
bool EventThread::threadLoop(){ |
||||
DisplayEventReceiver::Event event; |
||||
Vector<sp<EventThread::Connection>> signalConnections; |
||||
signalConnections = waitForEvent(&event); |
||||
const size_t count = signalConnection,size(); |
||||
for(size_t i = 0;i<count:i++){ |
||||
const sp<Connection>&conn(signalConnections[i]); |
||||
conn->postEvent(event); |
||||
} |
||||
return true; |
||||
} |
||||
Vector<sp<EventThread::Connection>> EventThread::waitForEvent(...){ |
||||
Vector<sp<EventThread::Connectiob>> signalConnections; |
||||
do{ |
||||
// 看是否已经有 vsync 信号来了 |
||||
// 如果有的话,就准备 connection 列表返回 |
||||
// 如果没有的话,就等待 vsync 信号 |
||||
}while(signalConnections.isEmpty()); |
||||
return signalConnections; |
||||
} |
||||
``` |
||||
|
||||
```c++ |
||||
void EventThread::requestNextVsync(const sp<EventThread::Connection>&connection){ |
||||
if(connection->count<0){ |
||||
connection->count=0; |
||||
mCondition.broadcast(); |
||||
} |
||||
} |
||||
``` |
||||
|
||||
```c++ |
||||
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); |
||||
} |
||||
ssize_t size DisplayEventReceiver::sendEvents(const sp<BitTube> &dataChannel, Event const* events, size_t count) { |
||||
return BitTube:sendObjects(dataChannel, events, count); |
||||
} |
||||
ssize_t BitTube::sendObjects(const sp<BitTube> &tube, ...){ |
||||
const char* vaddr = reinterpret_cast<const char*>(events); |
||||
sszie_t size = tube->write(vaddr, count*objSize); |
||||
return size<0?size:size/static_cast<sszie_t>(objSize); |
||||
} |
||||
``` |
||||
|
||||
BitTube 是在 SurfaceFlinger 创建的,读的一端是如何传递给应用进程呢? |
||||
|
||||
```c++ |
||||
DisplayEventReceiver::DisplayEventReceiver(){ |
||||
sp<ISrufaceComposer> sf(ComposerService::getComposerService()); |
||||
mEventConnection = sf->createDisplayEventConnection(); |
||||
mDataChannel = mEventConnection->getDataChannel(); |
||||
} |
||||
virtual sp<BitTube> getDataChannel() const{ |
||||
Parcel data, reply; |
||||
data.writeInterfaceToken(IDisplayEventConnection::getInterfaceDescriptor()); |
||||
remote()->transact(GET_DATA_CHANNEL, data, &reply); |
||||
return new BitTube(reply); |
||||
} |
||||
sp<BitTube> EventThread::Connection::getDataChannel() const{ |
||||
return mChannel; |
||||
} |
||||
``` |
||||
|
||||
应用进程如何监听读的描述符呢? |
||||
|
||||
```java |
||||
private Choreographer(Looper looper){ |
||||
mDisplayEventReceiver = new FrameDisplayEventReceiver(looper); |
||||
} |
||||
public DisplayEventReceiver(Looper looper){ |
||||
mReceiverPtr = nativeInit(new WeakReference<DisplayEventReceiver>(this), ...); |
||||
} |
||||
static jlong nativeInit(JNIEnv* env, jclass clazz, jobject receiverWeak, ...){ |
||||
sp<NativeDisplayEventReceiver> receiver = new NativeDisplayEventReceiver(...); |
||||
status_t status = receiver->initialize(); |
||||
return reinterpret_cast<jlong>(receiver.get()); |
||||
} |
||||
status_t NativeDisplayEventReceiver::initialize(){ |
||||
mMessageQueue->getLooper()->addFd(mReceiver.getFd(), 0, Looper::EVENT_INPUT, this, NULL); |
||||
rwturn OK; |
||||
} |
||||
DisplayEventReceiver::DisplayEventReceiver(){ |
||||
sp<ISurfaceComposer> sf(ComposerService::getComposerService()); |
||||
mEventConnection = sf->createisplayEventConnection(); |
||||
mDataChannel = mEventConnection->getDataChannel(); |
||||
} |
||||
int DisplayEventReceiver::getFd() const{ |
||||
return mDataChannel->getFd(); |
||||
} |
||||
int BitTube::getFd() const{ |
||||
return mReceiverFd; |
||||
} |
||||
int Looper::addFd(int fd, int ident, int events, ...){ |
||||
Request request: |
||||
request.fd = fd; |
||||
struct epoll_event eventItem: |
||||
request.initEventItem(&eventItem); |
||||
int epollResult = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, fd, &eventItem); |
||||
mRequests.add(fd, request); |
||||
} |
||||
``` |
||||
|
||||
Looper 检测 fd 的读事件: |
||||
|
||||
```java |
||||
int Looper::pollInner(int timeoutMillis){ |
||||
int eventCount = epoll_wait(mEpollFd, eventItems, ...); |
||||
for(int i = 0;i<eventCount;i++){ |
||||
int fd = eventItems[i].data.fd; |
||||
uint32_t epollEvents = eventItem[i].events; |
||||
if(fd == mWakeEventFd){ |
||||
|
||||
}else{ |
||||
if(epollEvent&EPOLLIN)events|=EVENT_INPUT; |
||||
pustResponse(events, mRequest.valueAt(requestIndex)); |
||||
} |
||||
} |
||||
// 统一处理 Response |
||||
for(size_t i=0;i<mResponse.size();i++){ |
||||
Response& response = mResponse.editItemAt(i); |
||||
int fd = response.request.fd; |
||||
int events = response.events; |
||||
void* data = response.request.data; |
||||
int callbackResult = response.request.callback->handleEvent(fd, events, data); |
||||
if(callbackResult==0){ |
||||
removeFd(fd, response.request.seq); |
||||
} |
||||
response.request.callback.clear(); |
||||
result = POLL_CALLBACK; |
||||
} |
||||
return result; |
||||
} |
||||
int NativeDisplayEventReceiver::handleEvent(int receiveFd, int events, ...){ |
||||
if(processPendingEvents(&vsyncTimestamp, &vsyncDisplayId, ...)){ |
||||
mWaitingForVsync = false; |
||||
dispatchVsync(vsyncTimestamp, vsyncDisplayId, vsyncCount); |
||||
} |
||||
return 1; |
||||
} |
||||
void NativeDisplayEventReceiver::dispatchVsync(nsecs_t timestamp, ...){ |
||||
env->CallVoidMethod(receiverObj.get(), gDisplayEventReceiverClassInfo.dispatchVsync, timestamp, ...); |
||||
} |
||||
void dispatchVsync(long timestampNanos, int builtInDisplayId, int frame){ |
||||
onVsync(timestampNanos, buildInDisplayId, frame); |
||||
} |
||||
``` |
||||
|
||||
#### 总结 |
||||
|
||||
1. Vsync 的原理是怎样的? |
||||
2. Choreographer 的原理是怎样的? |
||||
3. UI 刷新的大致流程,应用和 SurfaceFlinger 的通信过程? |
After Width: | Height: | Size: 173 KiB |
Loading…
Reference in new issue