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); | ||||
|     } | ||||
| } | ||||
| ``` | ||||
| 
 | ||||
|  | ||||
| 
 | ||||
| ```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