1 /* 2 * Copyright (C) 2011 The Android Open Source Project 3 * 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 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 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. 15 */ 16 17 package android.view; 18 19 import android.compat.annotation.UnsupportedAppUsage; 20 import android.graphics.FrameInfo; 21 import android.os.Build; 22 import android.os.Looper; 23 import android.os.MessageQueue; 24 import android.util.Log; 25 26 import com.android.internal.annotations.VisibleForTesting; 27 28 import dalvik.annotation.optimization.FastNative; 29 30 import java.lang.ref.WeakReference; 31 32 /** 33 * Provides a low-level mechanism for an application to receive display events 34 * such as vertical sync. 35 * 36 * The display event receive is NOT thread safe. Moreover, its methods must only 37 * be called on the Looper thread to which it is attached. 38 * 39 * @hide 40 */ 41 public abstract class DisplayEventReceiver { 42 43 /** 44 * When retrieving vsync events, this specifies that the vsync event should happen at the normal 45 * vsync-app tick. 46 * <p> 47 * Needs to be kept in sync with frameworks/native/include/gui/ISurfaceComposer.h 48 */ 49 public static final int VSYNC_SOURCE_APP = 0; 50 51 /** 52 * When retrieving vsync events, this specifies that the vsync event should happen whenever 53 * Surface Flinger is processing a frame. 54 * <p> 55 * Needs to be kept in sync with frameworks/native/include/gui/ISurfaceComposer.h 56 */ 57 public static final int VSYNC_SOURCE_SURFACE_FLINGER = 1; 58 59 /** 60 * Specifies to generate mode changed events from Surface Flinger. 61 * <p> 62 * Needs to be kept in sync with frameworks/native/include/gui/ISurfaceComposer.h 63 */ 64 public static final int EVENT_REGISTRATION_MODE_CHANGED_FLAG = 0x1; 65 66 /** 67 * Specifies to generate frame rate override events from Surface Flinger. 68 * <p> 69 * Needs to be kept in sync with frameworks/native/include/gui/ISurfaceComposer.h 70 */ 71 public static final int EVENT_REGISTRATION_FRAME_RATE_OVERRIDE_FLAG = 0x2; 72 73 private static final String TAG = "DisplayEventReceiver"; 74 75 @UnsupportedAppUsage 76 private long mReceiverPtr; 77 78 // We keep a reference message queue object here so that it is not 79 // GC'd while the native peer of the receiver is using them. 80 private MessageQueue mMessageQueue; 81 nativeInit(WeakReference<DisplayEventReceiver> receiver, MessageQueue messageQueue, int vsyncSource, int eventRegistration)82 private static native long nativeInit(WeakReference<DisplayEventReceiver> receiver, 83 MessageQueue messageQueue, int vsyncSource, int eventRegistration); nativeDispose(long receiverPtr)84 private static native void nativeDispose(long receiverPtr); 85 @FastNative nativeScheduleVsync(long receiverPtr)86 private static native void nativeScheduleVsync(long receiverPtr); nativeGetLatestVsyncEventData(long receiverPtr)87 private static native VsyncEventData nativeGetLatestVsyncEventData(long receiverPtr); 88 89 /** 90 * Creates a display event receiver. 91 * 92 * @param looper The looper to use when invoking callbacks. 93 */ 94 @UnsupportedAppUsage DisplayEventReceiver(Looper looper)95 public DisplayEventReceiver(Looper looper) { 96 this(looper, VSYNC_SOURCE_APP, 0); 97 } 98 99 /** 100 * Creates a display event receiver. 101 * 102 * @param looper The looper to use when invoking callbacks. 103 * @param vsyncSource The source of the vsync tick. Must be on of the VSYNC_SOURCE_* values. 104 * @param eventRegistration Which events to dispatch. Must be a bitfield consist of the 105 * EVENT_REGISTRATION_*_FLAG values. 106 */ DisplayEventReceiver(Looper looper, int vsyncSource, int eventRegistration)107 public DisplayEventReceiver(Looper looper, int vsyncSource, int eventRegistration) { 108 if (looper == null) { 109 throw new IllegalArgumentException("looper must not be null"); 110 } 111 112 mMessageQueue = looper.getQueue(); 113 mReceiverPtr = nativeInit(new WeakReference<DisplayEventReceiver>(this), mMessageQueue, 114 vsyncSource, eventRegistration); 115 } 116 117 @Override finalize()118 protected void finalize() throws Throwable { 119 try { 120 dispose(true); 121 } finally { 122 super.finalize(); 123 } 124 } 125 126 /** 127 * Disposes the receiver. 128 */ dispose()129 public void dispose() { 130 dispose(false); 131 } 132 dispose(boolean finalized)133 private void dispose(boolean finalized) { 134 if (mReceiverPtr != 0) { 135 nativeDispose(mReceiverPtr); 136 mReceiverPtr = 0; 137 } 138 mMessageQueue = null; 139 } 140 141 static final class VsyncEventData { 142 143 static final FrameTimeline[] INVALID_FRAME_TIMELINES = 144 {new FrameTimeline(FrameInfo.INVALID_VSYNC_ID, Long.MAX_VALUE, Long.MAX_VALUE)}; 145 146 public static class FrameTimeline { FrameTimeline(long vsyncId, long expectedPresentTime, long deadline)147 FrameTimeline(long vsyncId, long expectedPresentTime, long deadline) { 148 this.vsyncId = vsyncId; 149 this.expectedPresentTime = expectedPresentTime; 150 this.deadline = deadline; 151 } 152 153 // The frame timeline vsync id, used to correlate a frame 154 // produced by HWUI with the timeline data stored in Surface Flinger. 155 public final long vsyncId; 156 157 // The frame timestamp for when the frame is expected to be presented. 158 public final long expectedPresentTime; 159 160 // The frame deadline timestamp in {@link System#nanoTime()} timebase that it is 161 // allotted for the frame to be completed. 162 public final long deadline; 163 } 164 165 /** 166 * The current interval between frames in ns. This will be used to align 167 * {@link FrameInfo#VSYNC} to the current vsync in case Choreographer callback was heavily 168 * delayed by the app. 169 */ 170 public final long frameInterval; 171 172 public final FrameTimeline[] frameTimelines; 173 174 public final int preferredFrameTimelineIndex; 175 176 // Called from native code. 177 @SuppressWarnings("unused") VsyncEventData(FrameTimeline[] frameTimelines, int preferredFrameTimelineIndex, long frameInterval)178 VsyncEventData(FrameTimeline[] frameTimelines, int preferredFrameTimelineIndex, 179 long frameInterval) { 180 this.frameTimelines = frameTimelines; 181 this.preferredFrameTimelineIndex = preferredFrameTimelineIndex; 182 this.frameInterval = frameInterval; 183 } 184 VsyncEventData()185 VsyncEventData() { 186 this.frameInterval = -1; 187 this.frameTimelines = INVALID_FRAME_TIMELINES; 188 this.preferredFrameTimelineIndex = 0; 189 } 190 preferredFrameTimeline()191 public FrameTimeline preferredFrameTimeline() { 192 return frameTimelines[preferredFrameTimelineIndex]; 193 } 194 } 195 196 /** 197 * Called when a vertical sync pulse is received. 198 * The recipient should render a frame and then call {@link #scheduleVsync} 199 * to schedule the next vertical sync pulse. 200 * 201 * @param timestampNanos The timestamp of the pulse, in the {@link System#nanoTime()} 202 * timebase. 203 * @param physicalDisplayId Stable display ID that uniquely describes a (display, port) pair. 204 * @param frame The frame number. Increases by one for each vertical sync interval. 205 * @param vsyncEventData The vsync event data. 206 */ onVsync(long timestampNanos, long physicalDisplayId, int frame, VsyncEventData vsyncEventData)207 public void onVsync(long timestampNanos, long physicalDisplayId, int frame, 208 VsyncEventData vsyncEventData) { 209 } 210 211 /** 212 * Called when a display hotplug event is received. 213 * 214 * @param timestampNanos The timestamp of the event, in the {@link System#nanoTime()} 215 * timebase. 216 * @param physicalDisplayId Stable display ID that uniquely describes a (display, port) pair. 217 * @param connected True if the display is connected, false if it disconnected. 218 */ 219 @UnsupportedAppUsage onHotplug(long timestampNanos, long physicalDisplayId, boolean connected)220 public void onHotplug(long timestampNanos, long physicalDisplayId, boolean connected) { 221 } 222 223 /** 224 * Called when a display mode changed event is received. 225 * 226 * @param timestampNanos The timestamp of the event, in the {@link System#nanoTime()} 227 * timebase. 228 * @param physicalDisplayId Stable display ID that uniquely describes a (display, port) pair. 229 * @param modeId The new mode Id 230 */ onModeChanged(long timestampNanos, long physicalDisplayId, int modeId)231 public void onModeChanged(long timestampNanos, long physicalDisplayId, int modeId) { 232 } 233 234 /** 235 * Represents a mapping between a UID and an override frame rate 236 */ 237 public static class FrameRateOverride { 238 // The application uid 239 public final int uid; 240 241 // The frame rate that this application runs at 242 public final float frameRateHz; 243 244 245 @VisibleForTesting FrameRateOverride(int uid, float frameRateHz)246 public FrameRateOverride(int uid, float frameRateHz) { 247 this.uid = uid; 248 this.frameRateHz = frameRateHz; 249 } 250 251 @Override toString()252 public String toString() { 253 return "{uid=" + uid + " frameRateHz=" + frameRateHz + "}"; 254 } 255 } 256 257 /** 258 * Called when frame rate override event is received. 259 * 260 * @param timestampNanos The timestamp of the event, in the {@link System#nanoTime()} 261 * timebase. 262 * @param physicalDisplayId Stable display ID that uniquely describes a (display, port) pair. 263 * @param overrides The mappings from uid to frame rates 264 */ onFrameRateOverridesChanged(long timestampNanos, long physicalDisplayId, FrameRateOverride[] overrides)265 public void onFrameRateOverridesChanged(long timestampNanos, long physicalDisplayId, 266 FrameRateOverride[] overrides) { 267 } 268 269 /** 270 * Schedules a single vertical sync pulse to be delivered when the next 271 * display frame begins. 272 */ 273 @UnsupportedAppUsage scheduleVsync()274 public void scheduleVsync() { 275 if (mReceiverPtr == 0) { 276 Log.w(TAG, "Attempted to schedule a vertical sync pulse but the display event " 277 + "receiver has already been disposed."); 278 } else { 279 nativeScheduleVsync(mReceiverPtr); 280 } 281 } 282 283 /** 284 * Gets the latest vsync event data from surface flinger. 285 */ getLatestVsyncEventData()286 VsyncEventData getLatestVsyncEventData() { 287 return nativeGetLatestVsyncEventData(mReceiverPtr); 288 } 289 290 // Called from native code. 291 @SuppressWarnings("unused") dispatchVsync(long timestampNanos, long physicalDisplayId, int frame, VsyncEventData vsyncEventData)292 private void dispatchVsync(long timestampNanos, long physicalDisplayId, int frame, 293 VsyncEventData vsyncEventData) { 294 onVsync(timestampNanos, physicalDisplayId, frame, vsyncEventData); 295 } 296 297 // Called from native code. 298 @SuppressWarnings("unused") 299 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) dispatchHotplug(long timestampNanos, long physicalDisplayId, boolean connected)300 private void dispatchHotplug(long timestampNanos, long physicalDisplayId, boolean connected) { 301 onHotplug(timestampNanos, physicalDisplayId, connected); 302 } 303 304 // Called from native code. 305 @SuppressWarnings("unused") dispatchModeChanged(long timestampNanos, long physicalDisplayId, int modeId)306 private void dispatchModeChanged(long timestampNanos, long physicalDisplayId, int modeId) { 307 onModeChanged(timestampNanos, physicalDisplayId, modeId); 308 } 309 310 // Called from native code. 311 @SuppressWarnings("unused") dispatchFrameRateOverrides(long timestampNanos, long physicalDisplayId, FrameRateOverride[] overrides)312 private void dispatchFrameRateOverrides(long timestampNanos, long physicalDisplayId, 313 FrameRateOverride[] overrides) { 314 onFrameRateOverridesChanged(timestampNanos, physicalDisplayId, overrides); 315 } 316 317 } 318