1 /*
2  * Copyright 2022 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 "TaskFpsCallbackController"
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 } gCallbackClassInfo;
39 
40 struct TaskFpsCallback : public gui::BnFpsListener {
TaskFpsCallbackandroid::__anona19ea1690111::TaskFpsCallback41     TaskFpsCallback(JNIEnv* env, jobject listener) : mListener(env->NewWeakGlobalRef(listener)) {}
42 
onFpsReportedandroid::__anona19ea1690111::TaskFpsCallback43     binder::Status onFpsReported(float fps) override {
44         JNIEnv* env = AndroidRuntime::getJNIEnv();
45         LOG_ALWAYS_FATAL_IF(env == nullptr, "Unable to retrieve JNIEnv in onFpsReported.");
46 
47         jobject listener = env->NewGlobalRef(mListener);
48         if (listener == NULL) {
49             // Weak reference went out of scope
50             return binder::Status::ok();
51         }
52         env->CallStaticVoidMethod(gCallbackClassInfo.mClass,
53                                   gCallbackClassInfo.mDispatchOnFpsReported, listener,
54                                   static_cast<jfloat>(fps));
55         env->DeleteGlobalRef(listener);
56 
57         if (env->ExceptionCheck()) {
58             ALOGE("TaskFpsCallback.onFpsReported() failed.");
59             LOGE_EX(env);
60             env->ExceptionClear();
61         }
62         return binder::Status::ok();
63     }
64 
65 protected:
~TaskFpsCallbackandroid::__anona19ea1690111::TaskFpsCallback66     virtual ~TaskFpsCallback() {
67         JNIEnv* env = AndroidRuntime::getJNIEnv();
68         env->DeleteWeakGlobalRef(mListener);
69     }
70 
71 private:
72     jweak mListener;
73 };
74 
nativeRegister(JNIEnv * env,jclass clazz,jobject obj,jint taskId)75 jlong nativeRegister(JNIEnv* env, jclass clazz, jobject obj, jint taskId) {
76     TaskFpsCallback* callback = new TaskFpsCallback(env, obj);
77 
78     if (SurfaceComposerClient::addFpsListener(taskId, callback) != OK) {
79         constexpr auto error_msg = "Couldn't addFpsListener";
80         ALOGE(error_msg);
81         jniThrowRuntimeException(env, error_msg);
82     }
83     callback->incStrong((void*)nativeRegister);
84 
85     return reinterpret_cast<jlong>(callback);
86 }
87 
nativeUnregister(JNIEnv * env,jclass clazz,jlong ptr)88 void nativeUnregister(JNIEnv* env, jclass clazz, jlong ptr) {
89     sp<TaskFpsCallback> callback = reinterpret_cast<TaskFpsCallback*>(ptr);
90 
91     if (SurfaceComposerClient::removeFpsListener(callback) != OK) {
92         constexpr auto error_msg = "Couldn't removeFpsListener";
93         ALOGE(error_msg);
94         jniThrowRuntimeException(env, error_msg);
95     }
96 
97     callback->decStrong((void*)nativeRegister);
98 }
99 
100 static const JNINativeMethod gMethods[] = {
101         /* name, signature, funcPtr */
102         {"nativeRegister", "(Landroid/window/ITaskFpsCallback;I)J", (void*)nativeRegister},
103         {"nativeUnregister", "(J)V", (void*)nativeUnregister}};
104 
105 } // namespace
106 
register_com_android_server_wm_TaskFpsCallbackController(JNIEnv * env)107 int register_com_android_server_wm_TaskFpsCallbackController(JNIEnv* env) {
108     int res = jniRegisterNativeMethods(env, "com/android/server/wm/TaskFpsCallbackController",
109                                        gMethods, NELEM(gMethods));
110     LOG_ALWAYS_FATAL_IF(res < 0, "Unable to register native methods.");
111 
112     jclass clazz = env->FindClass("android/window/TaskFpsCallback");
113     gCallbackClassInfo.mClass = MakeGlobalRefOrDie(env, clazz);
114     gCallbackClassInfo.mDispatchOnFpsReported =
115             env->GetStaticMethodID(clazz, "dispatchOnFpsReported",
116                                    "(Landroid/window/ITaskFpsCallback;F)V");
117     return 0;
118 }
119 
120 } // namespace android
121