This document is based on the code of android-4.1.1_r6 (Jelly Bean).
First, the invalidate()
call will be propagated back to the root of the view hierarchy. During the propagation, the system determines the dirty area that needs to be redrawn. The propagation will eventually reach ViewRootImpl
.
frameworks/base/core/java/android/view/View.java
10219 void invalidate(boolean invalidateCache) {
... ...
10250 p.invalidateChild(this, r);
... ...
10253 }
frameworks/base/core/java/android/view/ViewGroup.java
4000 public final void invalidateChild(View child, final Rect dirty) {
... ...
4066 parent = parent.invalidateChildInParent(location, dirty);
... ...
4082 }
frameworks/base/core/java/android/view/ViewRootImpl.java
866 public ViewParent invalidateChildInParent(int[] location, Rect dirty) {
... ...
904 scheduleTraversals();
... ...
908 }
Finally, ViewRootImpl
will invoke the method scheduleTraversals()
to schedule a traversal over the view hierarchy to redraw the invalidated (dirty) area. The tricky part here is that the traversal will not be executed immediately. The system wants the traversal to be in sync with the hardware virtical synchronization events (vsync) in order to address the display tearing problem. For more details about what is vsync and why vsync is needed, please refer to this link.
frameworks/base/core/java/android/view/ViewRootImpl.java
968 void scheduleTraversals() {
969 if (!mTraversalScheduled) {
970 mTraversalScheduled = true;
971 mTraversalBarrier = mHandler.getLooper().postSyncBarrier();
972 mChoreographer.postCallback(
973 Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
974 scheduleConsumeBatchedInput();
975 }
976 }
To schedule a traversal, the system first posts barrier to the main event queue. The barrier will prevent other events from being dispatched until the actual traversal is performed. And then, it invokes mChoreographer.postCallback
to schedule a traversal with mChoreographer
, a coordinator which coordinates the timing of animations, input and drawing (link).
The Choreographer
will then schedule a DO_FRAME
callback to be invoked in sync with the underlying display vsync events.
frameworks/base/core/java/android/view/Choreographer.java
295 private void postCallbackDelayedInternal(int callbackType, ...) {
... ...
309 scheduleFrameLocked(now);
... ...
317 }
453 private void scheduleFrameLocked(long now) {
... ...
465 scheduleVsyncLocked();
... ...
482 }
588 private void scheduleVsyncLocked() {
589 mDisplayEventReceiver.scheduleVsync();
590 }
The member field mDisplayEventReceiver
is an instance of class FrameDisplayEventReceiver
extended from class DisplayEventReceiver
. The method scheduleVsync()
will eventually call a native method nativeScheduleVsync()
in class DisplayEventReceiver
.
frameworks/base/core/java/android/view/DisplayEventReceiver.java
105 public void scheduleVsync() {
... ...
110 nativeScheduleVsync(mReceiverPtr);
... ...
112 }
The native function implementation can be found in frameworks/base/core/jni/android_view_DisplayEventReceiver.cpp
. The receiver will register a file descriptor with the native event queue during initialization. Once there is a vsync event, the native event queue will invoke a callback handleEvent
which will then invoke a Java method onVsync
defined in class DisplayEventReceiver
(can be overrided) if a vsync is scheduled lately (through nativeScheduleVsync
).
frameworks/base/core/jni/android_view_DisplayEventReceiver.cpp
123 int NativeDisplayEventReceiver::handleEvent(int receiveFd, int events, void* data) {
... ...
146 mWaitingForVsync = false;
... ...
151 env->CallVoidMethod(mReceiverObjGlobal,
152 gDisplayEventReceiverClassInfo.dispatchVsync, vsyncTimestamp, vsyncCount);
... ...
157 }
frameworks/base/core/java/android/view/Choreographer.java
680 public void onVsync(long timestampNanos, int frame) {
... ...
701 mTimestampNanos = timestampNanos;
702 mFrame = frame;
703 Message msg = Message.obtain(mHandler, this);
704 msg.setAsynchronous(true);
705 mHandler.sendMessageAtTime(msg, timestampNanos / NANOS_PER_MS);
706 }
Finally, the method doFrame()
will be invoked. It will then invoke doCallbacks(Choreographer.CALLBACK_TRAVERSAL, frameTimeNanos);
which will finally invoke doTraversal()
in ViewRootImpl
.
frameworks/base/core/java/android/view/Choreographer.java
484 void doFrame(long frameTimeNanos, int frame) {
... ...
525 doCallbacks(Choreographer.CALLBACK_TRAVERSAL, frameTimeNanos);
... ...
533 }