• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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