2 * Copyright (C) 2017 The Android Open Source Project
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License
17 package com.android.internal.view;
19 import android.os.Handler;
20 import android.os.Message;
21 import android.view.Choreographer;
22 import android.view.Display;
25 * Utility class to schedule things at vsync-sf instead of vsync-app
28 public class SurfaceFlingerVsyncChoreographer {
30 private static final long ONE_MS_IN_NS = 1000000;
31 private static final long ONE_S_IN_NS = ONE_MS_IN_NS * 1000;
33 private final Handler mHandler;
34 private final Choreographer mChoreographer;
37 * The offset between vsync-app and vsync-surfaceflinger. See
38 * {@link #calculateAppSurfaceFlingerVsyncOffsetMs} why this is necessary.
40 private long mSurfaceFlingerOffsetMs;
42 public SurfaceFlingerVsyncChoreographer(Handler handler, Display display,
43 Choreographer choreographer) {
45 mChoreographer = choreographer;
46 mSurfaceFlingerOffsetMs = calculateAppSurfaceFlingerVsyncOffsetMs(display);
49 public long getSurfaceFlingerOffsetMs() {
50 return mSurfaceFlingerOffsetMs;
54 * This method calculates the offset between vsync-surfaceflinger and vsync-app. If vsync-app
55 * is a couple of milliseconds before vsync-sf, a touch or animation event that causes a surface
56 * flinger transaction are sometimes processed before the vsync-sf tick, and sometimes after,
57 * which leads to jank. Figure out this difference here and then post all the touch/animation
58 * events to start being processed at vsync-sf.
60 * @return The offset between vsync-app and vsync-sf, or 0 if vsync app happens after vsync-sf.
62 private long calculateAppSurfaceFlingerVsyncOffsetMs(Display display) {
64 // Calculate vsync offset from SurfaceFlinger.
65 // See frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp:getDisplayConfigs
66 long vsyncPeriod = (long) (ONE_S_IN_NS / display.getRefreshRate());
67 long sfVsyncOffset = vsyncPeriod - (display.getPresentationDeadlineNanos() - ONE_MS_IN_NS);
68 return Math.max(0, (sfVsyncOffset - display.getAppVsyncOffsetNanos()) / ONE_MS_IN_NS);
71 public void scheduleAtSfVsync(Runnable r) {
72 final long delay = calculateDelay();
76 mHandler.postDelayed(r, delay);
80 public void scheduleAtSfVsync(Handler h, Message m) {
81 final long delay = calculateDelay();
85 m.setAsynchronous(true);
86 h.sendMessageDelayed(m, delay);
90 private long calculateDelay() {
91 final long sinceFrameStart = System.nanoTime() - mChoreographer.getLastFrameTimeNanos();
92 return mSurfaceFlingerOffsetMs - sinceFrameStart / 1000000;