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_util_Binder.h"
20 #include "core_jni_helpers.h"
21 
22 #include <nativehelper/JNIHelp.h>
23 
24 #include <android_runtime/AndroidRuntime.h>
25 #include <android_runtime/Log.h>
26 #include <utils/Log.h>
27 #include <utils/RefBase.h>
28 #include <binder/IServiceManager.h>
29 
30 #include <gui/IRegionSamplingListener.h>
31 #include <gui/ISurfaceComposer.h>
32 #include <gui/SurfaceComposerClient.h>
33 #include <ui/Rect.h>
34 
35 namespace android {
36 
37 namespace {
38 
39 struct {
40     jclass mClass;
41     jmethodID mDispatchOnSampleCollected;
42 } gListenerClassInfo;
43 
44 struct CompositionSamplingListener : public BnRegionSamplingListener {
CompositionSamplingListenerandroid::__anond8bf8fad0110::CompositionSamplingListener45     CompositionSamplingListener(JNIEnv* env, jobject listener)
46             : mListener(env->NewWeakGlobalRef(listener)) {}
47 
onSampleCollectedandroid::__anond8bf8fad0110::CompositionSamplingListener48     void onSampleCollected(float medianLuma) override {
49         JNIEnv* env = AndroidRuntime::getJNIEnv();
50         LOG_ALWAYS_FATAL_IF(env == nullptr, "Unable to retrieve JNIEnv in onSampleCollected.");
51 
52         jobject listener = env->NewGlobalRef(mListener);
53         if (listener == NULL) {
54             // Weak reference went out of scope
55             return;
56         }
57         env->CallStaticVoidMethod(gListenerClassInfo.mClass,
58                 gListenerClassInfo.mDispatchOnSampleCollected, listener,
59                 static_cast<jfloat>(medianLuma));
60         env->DeleteGlobalRef(listener);
61 
62         if (env->ExceptionCheck()) {
63             ALOGE("CompositionSamplingListener.onSampleCollected() failed.");
64             LOGE_EX(env);
65             env->ExceptionClear();
66         }
67     }
68 
69 protected:
~CompositionSamplingListenerandroid::__anond8bf8fad0110::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