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