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 import com.android.internal.annotations.WeaklyReferencedCallback; 28 29 import dalvik.annotation.optimization.FastNative; 30 31 import libcore.util.NativeAllocationRegistry; 32 33 import java.lang.ref.WeakReference; 34 35 /** 36 * Provides a low-level mechanism for an application to receive display events 37 * such as vertical sync. 38 * 39 * The display event receive is NOT thread safe. Moreover, its methods must only 40 * be called on the Looper thread to which it is attached. 41 * 42 * @hide 43 */ 44 @WeaklyReferencedCallback 45 public abstract class DisplayEventReceiver { 46 47 /** 48 * When retrieving vsync events, this specifies that the vsync event should happen at the normal 49 * vsync-app tick. 50 * <p> 51 * Keep in sync with frameworks/native/libs/gui/aidl/android/gui/ISurfaceComposer.aidl 52 */ 53 public static final int VSYNC_SOURCE_APP = 0; 54 55 /** 56 * When retrieving vsync events, this specifies that the vsync event should happen whenever 57 * Surface Flinger is processing a frame. 58 * <p> 59 * Keep in sync with frameworks/native/libs/gui/aidl/android/gui/ISurfaceComposer.aidl 60 */ 61 public static final int VSYNC_SOURCE_SURFACE_FLINGER = 1; 62 63 /** 64 * Specifies to generate mode changed events from Surface Flinger. 65 * <p> 66 * Keep in sync with frameworks/native/libs/gui/aidl/android/gui/ISurfaceComposer.aidl 67 */ 68 public static final int EVENT_REGISTRATION_MODE_CHANGED_FLAG = 0x1; 69 70 /** 71 * Specifies to generate frame rate override events from Surface Flinger. 72 * <p> 73 * Keep in sync with frameworks/native/libs/gui/aidl/android/gui/ISurfaceComposer.aidl 74 */ 75 public static final int EVENT_REGISTRATION_FRAME_RATE_OVERRIDE_FLAG = 0x2; 76 77 private static final String TAG = "DisplayEventReceiver"; 78 79 @UnsupportedAppUsage 80 private long mReceiverPtr; 81 82 // We keep a reference message queue object here so that it is not 83 // GC'd while the native peer of the receiver is using them. 84 private MessageQueue mMessageQueue; 85 86 private final VsyncEventData mVsyncEventData = new VsyncEventData(); 87 nativeInit(WeakReference<DisplayEventReceiver> receiver, WeakReference<VsyncEventData> vsyncEventData, MessageQueue messageQueue, int vsyncSource, int eventRegistration, long layerHandle)88 private static native long nativeInit(WeakReference<DisplayEventReceiver> receiver, 89 WeakReference<VsyncEventData> vsyncEventData, 90 MessageQueue messageQueue, int vsyncSource, int eventRegistration, long layerHandle); nativeGetDisplayEventReceiverFinalizer()91 private static native long nativeGetDisplayEventReceiverFinalizer(); 92 @FastNative nativeScheduleVsync(long receiverPtr)93 private static native void nativeScheduleVsync(long receiverPtr); nativeGetLatestVsyncEventData(long receiverPtr)94 private static native VsyncEventData nativeGetLatestVsyncEventData(long receiverPtr); 95 96 private static final NativeAllocationRegistry sNativeAllocationRegistry = 97 NativeAllocationRegistry.createMalloced( 98 DisplayEventReceiver.class.getClassLoader(), 99 nativeGetDisplayEventReceiverFinalizer()); 100 private Runnable mFreeNativeResources; 101 102 /** 103 * Creates a display event receiver. 104 * 105 * @param looper The looper to use when invoking callbacks. 106 */ 107 @UnsupportedAppUsage DisplayEventReceiver(Looper looper)108 public DisplayEventReceiver(Looper looper) { 109 this(looper, VSYNC_SOURCE_APP, /* eventRegistration */ 0, /* layerHandle */ 0L); 110 } 111 DisplayEventReceiver(Looper looper, int vsyncSource, int eventRegistration)112 public DisplayEventReceiver(Looper looper, int vsyncSource, int eventRegistration) { 113 this(looper, vsyncSource, eventRegistration, /* layerHandle */ 0L); 114 } 115 116 /** 117 * Creates a display event receiver. 118 * 119 * @param looper The looper to use when invoking callbacks. 120 * @param vsyncSource The source of the vsync tick. Must be on of the VSYNC_SOURCE_* values. 121 * @param eventRegistration Which events to dispatch. Must be a bitfield consist of the 122 * EVENT_REGISTRATION_*_FLAG values. 123 * @param layerHandle Layer to which the current instance is attached to 124 */ DisplayEventReceiver(Looper looper, int vsyncSource, int eventRegistration, long layerHandle)125 public DisplayEventReceiver(Looper looper, int vsyncSource, int eventRegistration, 126 long layerHandle) { 127 if (looper == null) { 128 throw new IllegalArgumentException("looper must not be null"); 129 } 130 131 mMessageQueue = looper.getQueue(); 132 mReceiverPtr = nativeInit(new WeakReference<DisplayEventReceiver>(this), 133 new WeakReference<VsyncEventData>(mVsyncEventData), 134 mMessageQueue, 135 vsyncSource, eventRegistration, layerHandle); 136 mFreeNativeResources = sNativeAllocationRegistry.registerNativeAllocation(this, 137 mReceiverPtr); 138 } 139 140 /** 141 * Disposes the receiver. 142 */ dispose()143 public void dispose() { 144 if (mReceiverPtr != 0) { 145 mFreeNativeResources.run(); 146 mReceiverPtr = 0; 147 } 148 mMessageQueue = null; 149 } 150 151 /** 152 * Class to capture all inputs required for syncing events data. 153 * 154 * @hide 155 */ 156 public static final class VsyncEventData { 157 // The max capacity of frame timeline choices. 158 // Must be in sync with VsyncEventData::kFrameTimelinesCapacity in 159 // frameworks/native/libs/gui/include/gui/VsyncEventData.h 160 static final int FRAME_TIMELINES_CAPACITY = 7; 161 162 public static class FrameTimeline { FrameTimeline()163 FrameTimeline() { 164 // Some reasonable values (+10 ms) for default timestamps. 165 deadline = System.nanoTime() + 10_000_000; 166 expectedPresentationTime = deadline + 10_000_000; 167 } 168 169 // Called from native code. 170 @SuppressWarnings("unused") FrameTimeline(long vsyncId, long expectedPresentationTime, long deadline)171 FrameTimeline(long vsyncId, long expectedPresentationTime, long deadline) { 172 this.vsyncId = vsyncId; 173 this.expectedPresentationTime = expectedPresentationTime; 174 this.deadline = deadline; 175 } 176 copyFrom(FrameTimeline other)177 void copyFrom(FrameTimeline other) { 178 vsyncId = other.vsyncId; 179 expectedPresentationTime = other.expectedPresentationTime; 180 deadline = other.deadline; 181 } 182 183 // The frame timeline vsync id, used to correlate a frame 184 // produced by HWUI with the timeline data stored in Surface Flinger. 185 public long vsyncId = FrameInfo.INVALID_VSYNC_ID; 186 187 // The frame timestamp for when the frame is expected to be presented. 188 public long expectedPresentationTime; 189 190 // The frame deadline timestamp in {@link System#nanoTime()} timebase that it is 191 // allotted for the frame to be completed. 192 public long deadline; 193 } 194 195 /** 196 * The current interval between frames in ns. This will be used to align 197 * {@link FrameInfo#VSYNC} to the current vsync in case Choreographer callback was heavily 198 * delayed by the app. 199 */ 200 public long frameInterval = -1; 201 202 public final FrameTimeline[] frameTimelines; 203 204 public int preferredFrameTimelineIndex = 0; 205 206 // The default FrameTimeline is a placeholder populated with invalid vsync ID and some 207 // reasonable timestamps. 208 public int frameTimelinesLength = 1; 209 210 public int numberQueuedBuffers = 0; 211 VsyncEventData()212 VsyncEventData() { 213 frameTimelines = new FrameTimeline[FRAME_TIMELINES_CAPACITY]; 214 for (int i = 0; i < frameTimelines.length; i++) { 215 frameTimelines[i] = new FrameTimeline(); 216 } 217 } 218 219 // Called from native code. 220 @SuppressWarnings("unused") VsyncEventData(FrameTimeline[] frameTimelines, int preferredFrameTimelineIndex, int frameTimelinesLength, long frameInterval, int numberQueuedBuffers)221 VsyncEventData(FrameTimeline[] frameTimelines, int preferredFrameTimelineIndex, 222 int frameTimelinesLength, long frameInterval, 223 int numberQueuedBuffers) { 224 this.frameTimelines = frameTimelines; 225 this.preferredFrameTimelineIndex = preferredFrameTimelineIndex; 226 this.frameTimelinesLength = frameTimelinesLength; 227 this.frameInterval = frameInterval; 228 this.numberQueuedBuffers = numberQueuedBuffers; 229 } 230 copyFrom(VsyncEventData other)231 void copyFrom(VsyncEventData other) { 232 preferredFrameTimelineIndex = other.preferredFrameTimelineIndex; 233 frameTimelinesLength = other.frameTimelinesLength; 234 frameInterval = other.frameInterval; 235 for (int i = 0; i < frameTimelines.length; i++) { 236 frameTimelines[i].copyFrom(other.frameTimelines[i]); 237 } 238 numberQueuedBuffers = other.numberQueuedBuffers; 239 } 240 preferredFrameTimeline()241 public FrameTimeline preferredFrameTimeline() { 242 return frameTimelines[preferredFrameTimelineIndex]; 243 } 244 } 245 246 /** 247 * Called when a vertical sync pulse is received. 248 * The recipient should render a frame and then call {@link #scheduleVsync} 249 * to schedule the next vertical sync pulse. 250 * 251 * @param timestampNanos The timestamp of the pulse, in the {@link System#nanoTime()} 252 * timebase. 253 * @param physicalDisplayId Stable display ID that uniquely describes a (display, port) pair. 254 * @param frame The frame number. Increases by one for each vertical sync interval. 255 * @param vsyncEventData The vsync event data. 256 */ onVsync(long timestampNanos, long physicalDisplayId, int frame, VsyncEventData vsyncEventData)257 public void onVsync(long timestampNanos, long physicalDisplayId, int frame, 258 VsyncEventData vsyncEventData) { 259 } 260 261 /** 262 * Called when a display hotplug event is received. 263 * 264 * @param timestampNanos The timestamp of the event, in the {@link System#nanoTime()} 265 * timebase. 266 * @param physicalDisplayId Stable display ID that uniquely describes a (display, port) pair. 267 * @param connected True if the display is connected, false if it disconnected. 268 */ 269 @UnsupportedAppUsage onHotplug(long timestampNanos, long physicalDisplayId, boolean connected)270 public void onHotplug(long timestampNanos, long physicalDisplayId, boolean connected) { 271 } 272 273 /** 274 * Called when a display hotplug event with connection error is received. 275 * 276 * @param timestampNanos The timestamp of the event, in the {@link System#nanoTime()} 277 * timebase. 278 * @param connectionError the hotplug connection error code. 279 */ onHotplugConnectionError(long timestampNanos, int connectionError)280 public void onHotplugConnectionError(long timestampNanos, int connectionError) { 281 } 282 283 /** 284 * Called when a display mode changed event is received. 285 * 286 * @param timestampNanos The timestamp of the event, in the {@link System#nanoTime()} 287 * timebase. 288 * @param physicalDisplayId Stable display ID that uniquely describes a (display, port) pair. 289 * @param modeId The new mode ID 290 * @param renderPeriod The render frame period, which is a multiple of the mode's vsync period 291 */ onModeChanged(long timestampNanos, long physicalDisplayId, int modeId, long renderPeriod)292 public void onModeChanged(long timestampNanos, long physicalDisplayId, int modeId, 293 long renderPeriod) { 294 } 295 296 /** 297 * Called when a display mode rejection event is received. 298 * 299 * @param physicalDisplayId Stable display ID that uniquely describes a (display, port) pair. 300 * @param modeId The mode ID of the mode that was rejected 301 */ onModeRejected(long physicalDisplayId, int modeId)302 public void onModeRejected(long physicalDisplayId, int modeId) { 303 } 304 305 /** 306 * Called when a display hdcp levels change event is received. 307 * 308 * @param physicalDisplayId Stable display ID that uniquely describes a (display, port) pair. 309 * @param connectedLevel the new connected HDCP level 310 * @param maxLevel the maximum HDCP level 311 */ onHdcpLevelsChanged(long physicalDisplayId, int connectedLevel, int maxLevel)312 public void onHdcpLevelsChanged(long physicalDisplayId, int connectedLevel, int maxLevel) { 313 } 314 315 /** 316 * Represents a mapping between a UID and an override frame rate 317 */ 318 public static class FrameRateOverride { 319 // The application uid 320 public final int uid; 321 322 // The frame rate that this application runs at 323 public final float frameRateHz; 324 325 326 @VisibleForTesting FrameRateOverride(int uid, float frameRateHz)327 public FrameRateOverride(int uid, float frameRateHz) { 328 this.uid = uid; 329 this.frameRateHz = frameRateHz; 330 } 331 332 @Override toString()333 public String toString() { 334 return "{uid=" + uid + " frameRateHz=" + frameRateHz + "}"; 335 } 336 } 337 338 /** 339 * Called when frame rate override event is received. 340 * 341 * @param timestampNanos The timestamp of the event, in the {@link System#nanoTime()} 342 * timebase. 343 * @param physicalDisplayId Stable display ID that uniquely describes a (display, port) pair. 344 * @param overrides The mappings from uid to frame rates 345 */ onFrameRateOverridesChanged(long timestampNanos, long physicalDisplayId, FrameRateOverride[] overrides)346 public void onFrameRateOverridesChanged(long timestampNanos, long physicalDisplayId, 347 FrameRateOverride[] overrides) { 348 } 349 350 /** 351 * Schedules a single vertical sync pulse to be delivered when the next 352 * display frame begins. 353 */ 354 @UnsupportedAppUsage scheduleVsync()355 public void scheduleVsync() { 356 if (mReceiverPtr == 0) { 357 Log.w(TAG, "Attempted to schedule a vertical sync pulse but the display event " 358 + "receiver has already been disposed."); 359 } else { 360 nativeScheduleVsync(mReceiverPtr); 361 } 362 } 363 364 /** 365 * Gets the latest vsync event data from surface flinger. 366 */ getLatestVsyncEventData()367 VsyncEventData getLatestVsyncEventData() { 368 return nativeGetLatestVsyncEventData(mReceiverPtr); 369 } 370 371 // Called from native code. 372 @SuppressWarnings("unused") dispatchVsync(long timestampNanos, long physicalDisplayId, int frame)373 private void dispatchVsync(long timestampNanos, long physicalDisplayId, int frame) { 374 onVsync(timestampNanos, physicalDisplayId, frame, mVsyncEventData); 375 } 376 377 // Called from native code. 378 @SuppressWarnings("unused") 379 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) dispatchHotplug(long timestampNanos, long physicalDisplayId, boolean connected)380 private void dispatchHotplug(long timestampNanos, long physicalDisplayId, boolean connected) { 381 onHotplug(timestampNanos, physicalDisplayId, connected); 382 } 383 384 @SuppressWarnings("unused") dispatchHotplugConnectionError(long timestampNanos, int connectionError)385 private void dispatchHotplugConnectionError(long timestampNanos, int connectionError) { 386 onHotplugConnectionError(timestampNanos, connectionError); 387 } 388 389 // Called from native code. 390 @SuppressWarnings("unused") dispatchModeChanged(long timestampNanos, long physicalDisplayId, int modeId, long renderPeriod)391 private void dispatchModeChanged(long timestampNanos, long physicalDisplayId, int modeId, 392 long renderPeriod) { 393 onModeChanged(timestampNanos, physicalDisplayId, modeId, renderPeriod); 394 } 395 396 // Called from native code. 397 @SuppressWarnings("unused") dispatchModeRejected(long physicalDisplayId, int modeId)398 private void dispatchModeRejected(long physicalDisplayId, int modeId) { 399 onModeRejected(physicalDisplayId, modeId); 400 } 401 402 // Called from native code. 403 @SuppressWarnings("unused") dispatchFrameRateOverrides(long timestampNanos, long physicalDisplayId, FrameRateOverride[] overrides)404 private void dispatchFrameRateOverrides(long timestampNanos, long physicalDisplayId, 405 FrameRateOverride[] overrides) { 406 onFrameRateOverridesChanged(timestampNanos, physicalDisplayId, overrides); 407 } 408 409 // Called from native code. 410 @SuppressWarnings("unused") dispatchHdcpLevelsChanged(long physicalDisplayId, int connectedLevel, int maxLevel)411 private void dispatchHdcpLevelsChanged(long physicalDisplayId, int connectedLevel, 412 int maxLevel) { 413 onHdcpLevelsChanged(physicalDisplayId, connectedLevel, maxLevel); 414 } 415 416 } 417