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