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