1 /*
2  * Copyright (C) 2012 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 "CompositionSamplingListener"
18 
19 #include <android/gui/BnRegionSamplingListener.h>
20 #include <android_runtime/AndroidRuntime.h>
21 #include <android_runtime/Log.h>
22 #include <binder/IServiceManager.h>
23 #include <gui/ISurfaceComposer.h>
24 #include <gui/SurfaceComposerClient.h>
25 #include <nativehelper/JNIHelp.h>
26 #include <ui/Rect.h>
27 #include <utils/Log.h>
28 #include <utils/RefBase.h>
29 
30 #include "android_util_Binder.h"
31 #include "core_jni_helpers.h"
32 
33 namespace android {
34 
35 namespace {
36 
37 struct {
38     jclass mClass;
39     jmethodID mDispatchOnSampleCollected;
40 } gListenerClassInfo;
41 
42 struct CompositionSamplingListener : public gui::BnRegionSamplingListener {
CompositionSamplingListenerandroid::__anon7abf192f0110::CompositionSamplingListener43     CompositionSamplingListener(JNIEnv* env, jobject listener)
44             : mListener(env->NewWeakGlobalRef(listener)) {}
45 
onSampleCollectedandroid::__anon7abf192f0110::CompositionSamplingListener46     binder::Status onSampleCollected(float medianLuma) override {
47         JNIEnv* env = AndroidRuntime::getJNIEnv();
48         LOG_ALWAYS_FATAL_IF(env == nullptr, "Unable to retrieve JNIEnv in onSampleCollected.");
49 
50         jobject listener = env->NewGlobalRef(mListener);
51         if (listener == NULL) {
52             // Weak reference went out of scope
53             return binder::Status::ok();
54         }
55         env->CallStaticVoidMethod(gListenerClassInfo.mClass,
56                 gListenerClassInfo.mDispatchOnSampleCollected, listener,
57                 static_cast<jfloat>(medianLuma));
58         env->DeleteGlobalRef(listener);
59 
60         if (env->ExceptionCheck()) {
61             ALOGE("CompositionSamplingListener.onSampleCollected() failed.");
62             LOGE_EX(env);
63             env->ExceptionClear();
64         }
65 
66         return binder::Status::ok();
67     }
68 
69 protected:
~CompositionSamplingListenerandroid::__anon7abf192f0110::CompositionSamplingListener70     virtual ~CompositionSamplingListener() {
71         JNIEnv* env = AndroidRuntime::getJNIEnv();
72         env->DeleteWeakGlobalRef(mListener);
73     }
74 
75 private:
76     jweak mListener;
77 };
78 
nativeCreate(JNIEnv * env,jclass clazz,jobject obj)79 jlong nativeCreate(JNIEnv* env, jclass clazz, jobject obj) {
80     CompositionSamplingListener* listener = new CompositionSamplingListener(env, obj);
81     listener->incStrong((void*)nativeCreate);
82     return reinterpret_cast<jlong>(listener);
83 }
84 
nativeDestroy(JNIEnv * env,jclass clazz,jlong ptr)85 void nativeDestroy(JNIEnv* env, jclass clazz, jlong ptr) {
86     CompositionSamplingListener* listener = reinterpret_cast<CompositionSamplingListener*>(ptr);
87     listener->decStrong((void*)nativeCreate);
88 }
89 
nativeRegister(JNIEnv * env,jclass clazz,jlong ptr,jlong stopLayerObj,jint left,jint top,jint right,jint bottom)90 void nativeRegister(JNIEnv* env, jclass clazz, jlong ptr, jlong stopLayerObj,
91         jint left, jint top, jint right, jint bottom) {
92     sp<CompositionSamplingListener> listener = reinterpret_cast<CompositionSamplingListener*>(ptr);
93     auto stopLayer = reinterpret_cast<SurfaceControl*>(stopLayerObj);
94     sp<IBinder> stopLayerHandle = stopLayer != nullptr ? stopLayer->getHandle() : nullptr;
95     if (SurfaceComposerClient::addRegionSamplingListener(
96             Rect(left, top, right, bottom), stopLayerHandle, listener) != OK) {
97         constexpr auto error_msg = "Couldn't addRegionSamplingListener";
98         ALOGE(error_msg);
99         jniThrowRuntimeException(env, error_msg);
100     }
101 }
102 
nativeUnregister(JNIEnv * env,jclass clazz,jlong ptr)103 void nativeUnregister(JNIEnv* env, jclass clazz, jlong ptr) {
104     sp<CompositionSamplingListener> listener = reinterpret_cast<CompositionSamplingListener*>(ptr);
105 
106     if (SurfaceComposerClient::removeRegionSamplingListener(listener) != OK) {
107         constexpr auto error_msg = "Couldn't removeRegionSamplingListener";
108         ALOGE(error_msg);
109         jniThrowRuntimeException(env, error_msg);
110     }
111 }
112 
113 const JNINativeMethod gMethods[] = {
114     /* name, signature, funcPtr */
115     { "nativeCreate", "(Landroid/view/CompositionSamplingListener;)J",
116             (void*)nativeCreate },
117     { "nativeDestroy", "(J)V",
118             (void*)nativeDestroy },
119     { "nativeRegister", "(JJIIII)V",
120             (void*)nativeRegister },
121     { "nativeUnregister", "(J)V",
122             (void*)nativeUnregister }
123 };
124 
125 } // namespace
126 
register_android_view_CompositionSamplingListener(JNIEnv * env)127 int register_android_view_CompositionSamplingListener(JNIEnv* env) {
128     int res = jniRegisterNativeMethods(env, "android/view/CompositionSamplingListener",
129             gMethods, NELEM(gMethods));
130     LOG_ALWAYS_FATAL_IF(res < 0, "Unable to register native methods.");
131 
132     jclass clazz = env->FindClass("android/view/CompositionSamplingListener");
133     gListenerClassInfo.mClass = MakeGlobalRefOrDie(env, clazz);
134     gListenerClassInfo.mDispatchOnSampleCollected = env->GetStaticMethodID(
135             clazz, "dispatchOnSampleCollected", "(Landroid/view/CompositionSamplingListener;F)V");
136     return 0;
137 }
138 
139 } // namespace android
140