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