1 /*
2  * Copyright 2021 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 #define LOG_TAG "SurfaceControlFpsListener"
18 
19 #include <android/gui/BnFpsListener.h>
20 #include <android_runtime/AndroidRuntime.h>
21 #include <android_runtime/Log.h>
22 #include <gui/ISurfaceComposer.h>
23 #include <gui/SurfaceComposerClient.h>
24 #include <nativehelper/JNIHelp.h>
25 #include <utils/Log.h>
26 #include <utils/RefBase.h>
27 
28 #include "android_util_Binder.h"
29 #include "core_jni_helpers.h"
30 
31 namespace android {
32 
33 namespace {
34 
35 struct {
36     jclass mClass;
37     jmethodID mDispatchOnFpsReported;
38 } gListenerClassInfo;
39 
40 struct SurfaceControlFpsListener : public gui::BnFpsListener {
SurfaceControlFpsListenerandroid::__anon51c1f4f10110::SurfaceControlFpsListener41     SurfaceControlFpsListener(JNIEnv* env, jobject listener)
42           : mListener(env->NewWeakGlobalRef(listener)) {}
43 
onFpsReportedandroid::__anon51c1f4f10110::SurfaceControlFpsListener44     binder::Status onFpsReported(float fps) override {
45         JNIEnv* env = AndroidRuntime::getJNIEnv();
46         LOG_ALWAYS_FATAL_IF(env == nullptr, "Unable to retrieve JNIEnv in onFpsReported.");
47 
48         jobject listener = env->NewGlobalRef(mListener);
49         if (listener == NULL) {
50             // Weak reference went out of scope
51             return binder::Status::ok();
52         }
53         env->CallStaticVoidMethod(gListenerClassInfo.mClass,
54                                   gListenerClassInfo.mDispatchOnFpsReported, listener,
55                                   static_cast<jfloat>(fps));
56         env->DeleteGlobalRef(listener);
57 
58         if (env->ExceptionCheck()) {
59             ALOGE("SurfaceControlFpsListener.onFpsReported() failed.");
60             LOGE_EX(env);
61             env->ExceptionClear();
62         }
63         return binder::Status::ok();
64     }
65 
66 protected:
~SurfaceControlFpsListenerandroid::__anon51c1f4f10110::SurfaceControlFpsListener67     virtual ~SurfaceControlFpsListener() {
68         JNIEnv* env = AndroidRuntime::getJNIEnv();
69         env->DeleteWeakGlobalRef(mListener);
70     }
71 
72 private:
73     jweak mListener;
74 };
75 
nativeCreate(JNIEnv * env,jclass clazz,jobject obj)76 jlong nativeCreate(JNIEnv* env, jclass clazz, jobject obj) {
77     SurfaceControlFpsListener* listener = new SurfaceControlFpsListener(env, obj);
78     listener->incStrong((void*)nativeCreate);
79     return reinterpret_cast<jlong>(listener);
80 }
81 
nativeDestroy(JNIEnv * env,jclass clazz,jlong ptr)82 void nativeDestroy(JNIEnv* env, jclass clazz, jlong ptr) {
83     SurfaceControlFpsListener* listener = reinterpret_cast<SurfaceControlFpsListener*>(ptr);
84     listener->decStrong((void*)nativeCreate);
85 }
86 
nativeRegister(JNIEnv * env,jclass clazz,jlong ptr,jint taskId)87 void nativeRegister(JNIEnv* env, jclass clazz, jlong ptr, jint taskId) {
88     sp<SurfaceControlFpsListener> listener = reinterpret_cast<SurfaceControlFpsListener*>(ptr);
89     if (SurfaceComposerClient::addFpsListener(taskId, listener) != OK) {
90         constexpr auto error_msg = "Couldn't addFpsListener";
91         ALOGE(error_msg);
92         jniThrowRuntimeException(env, error_msg);
93     }
94 }
95 
nativeUnregister(JNIEnv * env,jclass clazz,jlong ptr)96 void nativeUnregister(JNIEnv* env, jclass clazz, jlong ptr) {
97     sp<SurfaceControlFpsListener> listener = reinterpret_cast<SurfaceControlFpsListener*>(ptr);
98 
99     if (SurfaceComposerClient::removeFpsListener(listener) != OK) {
100         constexpr auto error_msg = "Couldn't removeFpsListener";
101         ALOGE(error_msg);
102         jniThrowRuntimeException(env, error_msg);
103     }
104 }
105 
106 const JNINativeMethod gMethods[] = {
107         /* name, signature, funcPtr */
108         {"nativeCreate", "(Landroid/view/SurfaceControlFpsListener;)J", (void*)nativeCreate},
109         {"nativeDestroy", "(J)V", (void*)nativeDestroy},
110         {"nativeRegister", "(JI)V", (void*)nativeRegister},
111         {"nativeUnregister", "(J)V", (void*)nativeUnregister}};
112 
113 } // namespace
114 
register_android_view_SurfaceControlFpsListener(JNIEnv * env)115 int register_android_view_SurfaceControlFpsListener(JNIEnv* env) {
116     int res = jniRegisterNativeMethods(env, "android/view/SurfaceControlFpsListener", gMethods,
117                                        NELEM(gMethods));
118     LOG_ALWAYS_FATAL_IF(res < 0, "Unable to register native methods.");
119 
120     jclass clazz = env->FindClass("android/view/SurfaceControlFpsListener");
121     gListenerClassInfo.mClass = MakeGlobalRefOrDie(env, clazz);
122     gListenerClassInfo.mDispatchOnFpsReported =
123             env->GetStaticMethodID(clazz, "dispatchOnFpsReported",
124                                    "(Landroid/view/SurfaceControlFpsListener;F)V");
125     return 0;
126 }
127 
128 } // namespace android
129