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); 87 88 /** 89 * Creates a display event receiver. 90 * 91 * @param looper The looper to use when invoking callbacks. 92 */ 93 @UnsupportedAppUsage DisplayEventReceiver(Looper looper)94 public DisplayEventReceiver(Looper looper) { 95 this(looper, VSYNC_SOURCE_APP, 0); 96 } 97 98 /** 99 * Creates a display event receiver. 100 * 101 * @param looper The looper to use when invoking callbacks. 102 * @param vsyncSource The source of the vsync tick. Must be on of the VSYNC_SOURCE_* values. 103 * @param eventRegistration Which events to dispatch. Must be a bitfield consist of the 104 * EVENT_REGISTRATION_*_FLAG values. 105 */ DisplayEventReceiver(Looper looper, int vsyncSource, int eventRegistration)106 public DisplayEventReceiver(Looper looper, int vsyncSource, int eventRegistration) { 107 if (looper == null) { 108 throw new IllegalArgumentException("looper must not be null"); 109 } 110 111 mMessageQueue = looper.getQueue(); 112 mReceiverPtr = nativeInit(new WeakReference<DisplayEventReceiver>(this), mMessageQueue, 113 vsyncSource, eventRegistration); 114 } 115 116 @Override finalize()117 protected void finalize() throws Throwable { 118 try { 119 dispose(true); 120 } finally { 121 super.finalize(); 122 } 123 } 124 125 /** 126 * Disposes the receiver. 127 */ dispose()128 public void dispose() { 129 dispose(false); 130 } 131 dispose(boolean finalized)132 private void dispose(boolean finalized) { 133 if (mReceiverPtr != 0) { 134 nativeDispose(mReceiverPtr); 135 mReceiverPtr = 0; 136 } 137 mMessageQueue = null; 138 } 139 140 static final class VsyncEventData { 141 // The frame timeline vsync id, used to correlate a frame 142 // produced by HWUI with the timeline data stored in Surface Flinger. 143 public final long id; 144 145 // The frame deadline timestamp in {@link System#nanoTime()} timebase that it is 146 // allotted for the frame to be completed. 147 public final long frameDeadline; 148 149 /** 150 * The current interval between frames in ns. This will be used to align 151 * {@link FrameInfo#VSYNC} to the current vsync in case Choreographer callback was heavily 152 * delayed by the app. 153 */ 154 public final long frameInterval; 155 VsyncEventData(long id, long frameDeadline, long frameInterval)156 VsyncEventData(long id, long frameDeadline, long frameInterval) { 157 this.id = id; 158 this.frameDeadline = frameDeadline; 159 this.frameInterval = frameInterval; 160 } 161 VsyncEventData()162 VsyncEventData() { 163 this.id = FrameInfo.INVALID_VSYNC_ID; 164 this.frameDeadline = Long.MAX_VALUE; 165 this.frameInterval = -1; 166 } 167 } 168 169 /** 170 * Called when a vertical sync pulse is received. 171 * The recipient should render a frame and then call {@link #scheduleVsync} 172 * to schedule the next vertical sync pulse. 173 * 174 * @param timestampNanos The timestamp of the pulse, in the {@link System#nanoTime()} 175 * timebase. 176 * @param physicalDisplayId Stable display ID that uniquely describes a (display, port) pair. 177 * @param frame The frame number. Increases by one for each vertical sync interval. 178 * @param vsyncEventData The vsync event data. 179 */ onVsync(long timestampNanos, long physicalDisplayId, int frame, VsyncEventData vsyncEventData)180 public void onVsync(long timestampNanos, long physicalDisplayId, int frame, 181 VsyncEventData vsyncEventData) { 182 } 183 184 /** 185 * Called when a display hotplug event is received. 186 * 187 * @param timestampNanos The timestamp of the event, in the {@link System#nanoTime()} 188 * timebase. 189 * @param physicalDisplayId Stable display ID that uniquely describes a (display, port) pair. 190 * @param connected True if the display is connected, false if it disconnected. 191 */ 192 @UnsupportedAppUsage onHotplug(long timestampNanos, long physicalDisplayId, boolean connected)193 public void onHotplug(long timestampNanos, long physicalDisplayId, boolean connected) { 194 } 195 196 /** 197 * Called when a display mode changed event is received. 198 * 199 * @param timestampNanos The timestamp of the event, in the {@link System#nanoTime()} 200 * timebase. 201 * @param physicalDisplayId Stable display ID that uniquely describes a (display, port) pair. 202 * @param modeId The new mode Id 203 */ onModeChanged(long timestampNanos, long physicalDisplayId, int modeId)204 public void onModeChanged(long timestampNanos, long physicalDisplayId, int modeId) { 205 } 206 207 /** 208 * Represents a mapping between a UID and an override frame rate 209 */ 210 public static class FrameRateOverride { 211 // The application uid 212 public final int uid; 213 214 // The frame rate that this application runs at 215 public final float frameRateHz; 216 217 218 @VisibleForTesting FrameRateOverride(int uid, float frameRateHz)219 public FrameRateOverride(int uid, float frameRateHz) { 220 this.uid = uid; 221 this.frameRateHz = frameRateHz; 222 } 223 224 @Override toString()225 public String toString() { 226 return "{uid=" + uid + " frameRateHz=" + frameRateHz + "}"; 227 } 228 } 229 230 /** 231 * Called when frame rate override event is received. 232 * 233 * @param timestampNanos The timestamp of the event, in the {@link System#nanoTime()} 234 * timebase. 235 * @param physicalDisplayId Stable display ID that uniquely describes a (display, port) pair. 236 * @param overrides The mappings from uid to frame rates 237 */ onFrameRateOverridesChanged(long timestampNanos, long physicalDisplayId, FrameRateOverride[] overrides)238 public void onFrameRateOverridesChanged(long timestampNanos, long physicalDisplayId, 239 FrameRateOverride[] overrides) { 240 } 241 242 /** 243 * Schedules a single vertical sync pulse to be delivered when the next 244 * display frame begins. 245 */ 246 @UnsupportedAppUsage scheduleVsync()247 public void scheduleVsync() { 248 if (mReceiverPtr == 0) { 249 Log.w(TAG, "Attempted to schedule a vertical sync pulse but the display event " 250 + "receiver has already been disposed."); 251 } else { 252 nativeScheduleVsync(mReceiverPtr); 253 } 254 } 255 256 // Called from native code. 257 @SuppressWarnings("unused") dispatchVsync(long timestampNanos, long physicalDisplayId, int frame, long frameTimelineVsyncId, long frameDeadline, long frameInterval)258 private void dispatchVsync(long timestampNanos, long physicalDisplayId, int frame, 259 long frameTimelineVsyncId, long frameDeadline, long frameInterval) { 260 onVsync(timestampNanos, physicalDisplayId, frame, 261 new VsyncEventData(frameTimelineVsyncId, frameDeadline, frameInterval)); 262 } 263 264 // Called from native code. 265 @SuppressWarnings("unused") 266 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) dispatchHotplug(long timestampNanos, long physicalDisplayId, boolean connected)267 private void dispatchHotplug(long timestampNanos, long physicalDisplayId, boolean connected) { 268 onHotplug(timestampNanos, physicalDisplayId, connected); 269 } 270 271 // Called from native code. 272 @SuppressWarnings("unused") dispatchModeChanged(long timestampNanos, long physicalDisplayId, int modeId)273 private void dispatchModeChanged(long timestampNanos, long physicalDisplayId, int modeId) { 274 onModeChanged(timestampNanos, physicalDisplayId, modeId); 275 } 276 277 // Called from native code. 278 @SuppressWarnings("unused") dispatchFrameRateOverrides(long timestampNanos, long physicalDisplayId, FrameRateOverride[] overrides)279 private void dispatchFrameRateOverrides(long timestampNanos, long physicalDisplayId, 280 FrameRateOverride[] overrides) { 281 onFrameRateOverridesChanged(timestampNanos, physicalDisplayId, overrides); 282 } 283 284 } 285