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 mode changed event is received. 268 * 269 * @param timestampNanos The timestamp of the event, in the {@link System#nanoTime()} 270 * timebase. 271 * @param physicalDisplayId Stable display ID that uniquely describes a (display, port) pair. 272 * @param modeId The new mode Id 273 * @param renderPeriod The render frame period, which is a multiple of the mode's vsync period 274 */ onModeChanged(long timestampNanos, long physicalDisplayId, int modeId, long renderPeriod)275 public void onModeChanged(long timestampNanos, long physicalDisplayId, int modeId, 276 long renderPeriod) { 277 } 278 279 /** 280 * Represents a mapping between a UID and an override frame rate 281 */ 282 public static class FrameRateOverride { 283 // The application uid 284 public final int uid; 285 286 // The frame rate that this application runs at 287 public final float frameRateHz; 288 289 290 @VisibleForTesting FrameRateOverride(int uid, float frameRateHz)291 public FrameRateOverride(int uid, float frameRateHz) { 292 this.uid = uid; 293 this.frameRateHz = frameRateHz; 294 } 295 296 @Override toString()297 public String toString() { 298 return "{uid=" + uid + " frameRateHz=" + frameRateHz + "}"; 299 } 300 } 301 302 /** 303 * Called when frame rate override event is received. 304 * 305 * @param timestampNanos The timestamp of the event, in the {@link System#nanoTime()} 306 * timebase. 307 * @param physicalDisplayId Stable display ID that uniquely describes a (display, port) pair. 308 * @param overrides The mappings from uid to frame rates 309 */ onFrameRateOverridesChanged(long timestampNanos, long physicalDisplayId, FrameRateOverride[] overrides)310 public void onFrameRateOverridesChanged(long timestampNanos, long physicalDisplayId, 311 FrameRateOverride[] overrides) { 312 } 313 314 /** 315 * Schedules a single vertical sync pulse to be delivered when the next 316 * display frame begins. 317 */ 318 @UnsupportedAppUsage scheduleVsync()319 public void scheduleVsync() { 320 if (mReceiverPtr == 0) { 321 Log.w(TAG, "Attempted to schedule a vertical sync pulse but the display event " 322 + "receiver has already been disposed."); 323 } else { 324 nativeScheduleVsync(mReceiverPtr); 325 } 326 } 327 328 /** 329 * Gets the latest vsync event data from surface flinger. 330 */ getLatestVsyncEventData()331 VsyncEventData getLatestVsyncEventData() { 332 return nativeGetLatestVsyncEventData(mReceiverPtr); 333 } 334 335 // Called from native code. 336 @SuppressWarnings("unused") dispatchVsync(long timestampNanos, long physicalDisplayId, int frame)337 private void dispatchVsync(long timestampNanos, long physicalDisplayId, int frame) { 338 onVsync(timestampNanos, physicalDisplayId, frame, mVsyncEventData); 339 } 340 341 // Called from native code. 342 @SuppressWarnings("unused") 343 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) dispatchHotplug(long timestampNanos, long physicalDisplayId, boolean connected)344 private void dispatchHotplug(long timestampNanos, long physicalDisplayId, boolean connected) { 345 onHotplug(timestampNanos, physicalDisplayId, connected); 346 } 347 348 // Called from native code. 349 @SuppressWarnings("unused") dispatchModeChanged(long timestampNanos, long physicalDisplayId, int modeId, long renderPeriod)350 private void dispatchModeChanged(long timestampNanos, long physicalDisplayId, int modeId, 351 long renderPeriod) { 352 onModeChanged(timestampNanos, physicalDisplayId, modeId, renderPeriod); 353 } 354 355 // Called from native code. 356 @SuppressWarnings("unused") dispatchFrameRateOverrides(long timestampNanos, long physicalDisplayId, FrameRateOverride[] overrides)357 private void dispatchFrameRateOverrides(long timestampNanos, long physicalDisplayId, 358 FrameRateOverride[] overrides) { 359 onFrameRateOverridesChanged(timestampNanos, physicalDisplayId, overrides); 360 } 361 362 } 363