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 "SurfaceControlHdrLayerInfoListener"
18 
19 #include <android/gui/BnHdrLayerInfoListener.h>
20 #include <android_runtime/Log.h>
21 #include <gui/ISurfaceComposer.h>
22 #include <gui/SurfaceComposerClient.h>
23 #include <log/log.h>
24 #include <nativehelper/JNIHelp.h>
25 #include <utils/RefBase.h>
26 
27 #include "android_util_Binder.h"
28 #include "core_jni_helpers.h"
29 
30 namespace android {
31 
32 namespace {
33 
34 struct {
35     jclass mClass;
36     jmethodID mOnHdrInfoChanged;
37 } gListenerClassInfo;
38 
39 struct SurfaceControlHdrLayerInfoListener : public gui::BnHdrLayerInfoListener {
SurfaceControlHdrLayerInfoListenerandroid::__anoneb3ed3f10110::SurfaceControlHdrLayerInfoListener40     SurfaceControlHdrLayerInfoListener(JNIEnv* env, jobject listener, jobject displayToken)
41           : mListener(env->NewGlobalRef(listener)), mDisplayToken(env->NewGlobalRef(displayToken)) {
42         LOG_ALWAYS_FATAL_IF(env->GetJavaVM(&mVm) != JNI_OK, "Failed to GetJavaVm");
43     }
44 
onHdrLayerInfoChangedandroid::__anoneb3ed3f10110::SurfaceControlHdrLayerInfoListener45     binder::Status onHdrLayerInfoChanged(int numberOfHdrLayers, int maxW, int maxH, int flags,
46                                          float maxDesiredHdrSdrRatio) override {
47         JNIEnv* env = requireEnv();
48 
49         env->CallVoidMethod(mListener, gListenerClassInfo.mOnHdrInfoChanged, mDisplayToken,
50                             numberOfHdrLayers, maxW, maxH, flags, maxDesiredHdrSdrRatio);
51 
52         if (env->ExceptionCheck()) {
53             ALOGE("SurfaceControlHdrLayerInfoListener.onHdrInfoChanged() failed.");
54             LOGE_EX(env);
55             env->ExceptionClear();
56         }
57         return binder::Status::ok();
58     }
59 
startListeningandroid::__anoneb3ed3f10110::SurfaceControlHdrLayerInfoListener60     status_t startListening() {
61         auto token = ibinderForJavaObject(requireEnv(), mDisplayToken);
62         return SurfaceComposerClient::addHdrLayerInfoListener(token, this);
63     }
64 
stopListeningandroid::__anoneb3ed3f10110::SurfaceControlHdrLayerInfoListener65     status_t stopListening() {
66         auto token = ibinderForJavaObject(requireEnv(), mDisplayToken);
67         return SurfaceComposerClient::removeHdrLayerInfoListener(token, this);
68     }
69 
70 protected:
~SurfaceControlHdrLayerInfoListenerandroid::__anoneb3ed3f10110::SurfaceControlHdrLayerInfoListener71     virtual ~SurfaceControlHdrLayerInfoListener() {
72         JNIEnv* env = requireEnv();
73         env->DeleteGlobalRef(mListener);
74         env->DeleteGlobalRef(mDisplayToken);
75     }
76 
requireEnvandroid::__anoneb3ed3f10110::SurfaceControlHdrLayerInfoListener77     JNIEnv* requireEnv() {
78         JNIEnv* env = nullptr;
79         if (mVm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
80             if (mVm->AttachCurrentThreadAsDaemon(&env, nullptr) != JNI_OK) {
81                 LOG_ALWAYS_FATAL("Failed to AttachCurrentThread!");
82             }
83         }
84         return env;
85     }
86 
87 private:
88     jobject mListener;
89     jobject mDisplayToken;
90     JavaVM* mVm;
91 };
92 
nRegister(JNIEnv * env,jobject jthis,jobject jbinderToken)93 jlong nRegister(JNIEnv* env, jobject jthis, jobject jbinderToken) {
94     auto callback = sp<SurfaceControlHdrLayerInfoListener>::make(env, jthis, jbinderToken);
95     status_t err = callback->startListening();
96     if (err != OK) {
97         auto errStr = statusToString(err);
98         jniThrowExceptionFmt(env, "java/lang/IllegalStateException",
99                              "Failed to register HdrLayerInfoListener, err = %d (%s)", err,
100                              errStr.c_str());
101         return 0;
102     }
103     SurfaceControlHdrLayerInfoListener* ret = callback.get();
104     ret->incStrong(0);
105     return static_cast<jlong>(reinterpret_cast<intptr_t>(ret));
106 }
107 
destroy(SurfaceControlHdrLayerInfoListener * listener)108 static void destroy(SurfaceControlHdrLayerInfoListener* listener) {
109     listener->stopListening();
110     listener->decStrong(0);
111 }
112 
nGetDestructor(JNIEnv * env,jobject clazz)113 static jlong nGetDestructor(JNIEnv* env, jobject clazz) {
114     return static_cast<jlong>(reinterpret_cast<intptr_t>(&destroy));
115 }
116 
117 const JNINativeMethod gMethods[] = {
118         /* name, signature, funcPtr */
119         {"nGetDestructor", "()J", (void*)nGetDestructor},
120         {"nRegister", "(Landroid/os/IBinder;)J", (void*)nRegister}};
121 
122 } // namespace
123 
register_android_view_SurfaceControlHdrLayerInfoListener(JNIEnv * env)124 int register_android_view_SurfaceControlHdrLayerInfoListener(JNIEnv* env) {
125     int res = jniRegisterNativeMethods(env, "android/view/SurfaceControlHdrLayerInfoListener",
126                                        gMethods, NELEM(gMethods));
127     LOG_ALWAYS_FATAL_IF(res < 0, "Unable to register native methods.");
128 
129     jclass clazz = env->FindClass("android/view/SurfaceControlHdrLayerInfoListener");
130     gListenerClassInfo.mClass = MakeGlobalRefOrDie(env, clazz);
131     gListenerClassInfo.mOnHdrInfoChanged =
132             env->GetMethodID(clazz, "onHdrInfoChanged", "(Landroid/os/IBinder;IIIIF)V");
133     return 0;
134 }
135 
136 } // namespace android
137