1 /*
2  * Copyright (C) 2019 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.graphics;
18 
19 import android.annotation.NonNull;
20 import android.os.Handler;
21 
22 import com.android.internal.util.VirtualRefBasePtr;
23 
24 /**
25  * Provides streaming access to frame stats information from HardwareRenderer to apps.
26  *
27  * @hide
28  */
29 public class HardwareRendererObserver {
30     private final long[] mFrameMetrics;
31     private final Handler mHandler;
32     private final OnFrameMetricsAvailableListener mListener;
33     private VirtualRefBasePtr mNativePtr;
34 
35     /**
36      * Interface for clients that want frame timing information for each frame rendered.
37      * @hide
38      */
39     public interface OnFrameMetricsAvailableListener {
40         /**
41          * Called when information is available for the previously rendered frame.
42          *
43          * Reports can be dropped if this callback takes too long to execute, as the report producer
44          * cannot wait for the consumer to complete.
45          *
46          * It is highly recommended that clients copy the metrics array within this method
47          * and defer additional computation or storage to another thread to avoid unnecessarily
48          * dropping reports.
49          *
50          * @param dropCountSinceLastInvocation the number of reports dropped since the last time
51          * this callback was invoked.
52          */
onFrameMetricsAvailable(int dropCountSinceLastInvocation)53         void onFrameMetricsAvailable(int dropCountSinceLastInvocation);
54     }
55 
56     /**
57      * Creates a FrameMetricsObserver
58      *
59      * @param frameMetrics the available metrics. This array is reused on every call to the listener
60      * and thus <strong>this reference should only be used within the scope of the listener callback
61      * as data is not guaranteed to be valid outside the scope of that method</strong>.
62      * @param handler the Handler to use when invoking callbacks
63      */
HardwareRendererObserver(@onNull OnFrameMetricsAvailableListener listener, @NonNull long[] frameMetrics, @NonNull Handler handler, boolean waitForPresentTime)64     public HardwareRendererObserver(@NonNull OnFrameMetricsAvailableListener listener,
65             @NonNull long[] frameMetrics, @NonNull Handler handler, boolean waitForPresentTime) {
66         if (handler == null || handler.getLooper() == null) {
67             throw new NullPointerException("handler and its looper cannot be null");
68         }
69 
70         if (handler.getLooper().getQueue() == null) {
71             throw new IllegalStateException("invalid looper, null message queue\n");
72         }
73 
74         mFrameMetrics = frameMetrics;
75         mHandler = handler;
76         mListener = listener;
77         mNativePtr = new VirtualRefBasePtr(nCreateObserver(waitForPresentTime));
78     }
79 
getNativeInstance()80     /*package*/ long getNativeInstance() {
81         return mNativePtr.get();
82     }
83 
84     // Called by native on the provided Handler
85     @SuppressWarnings("unused")
notifyDataAvailable()86     private void notifyDataAvailable() {
87         mHandler.post(() -> {
88             boolean hasMoreData = true;
89             while (hasMoreData) {
90                 // a drop count of -1 is a sentinel that no more buffers are available
91                 int dropCount = nGetNextBuffer(mNativePtr.get(), mFrameMetrics);
92                 if (dropCount >= 0) {
93                     mListener.onFrameMetricsAvailable(dropCount);
94                 } else {
95                     hasMoreData = false;
96                 }
97             }
98         });
99     }
100 
nCreateObserver(boolean waitForPresentTime)101     private native long nCreateObserver(boolean waitForPresentTime);
nGetNextBuffer(long nativePtr, long[] data)102     private static native int nGetNextBuffer(long nativePtr, long[] data);
103 }
104