1 /*
2  * Copyright (C) 2019 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 #include "android_graphics_HardwareRendererObserver.h"
18 
19 #include "graphics_jni_helpers.h"
20 #include "nativehelper/jni_macros.h"
21 
22 #include <array>
23 
24 namespace android {
25 
26 struct {
27     jmethodID callback;
28 } gHardwareRendererObserverClassInfo;
29 
getenv(JavaVM * vm)30 static JNIEnv* getenv(JavaVM* vm) {
31     JNIEnv* env;
32     if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
33         LOG_ALWAYS_FATAL("Failed to get JNIEnv for JavaVM: %p", vm);
34     }
35     return env;
36 }
37 
HardwareRendererObserver(JavaVM * vm,jobject observer,bool waitForPresentTime)38 HardwareRendererObserver::HardwareRendererObserver(JavaVM* vm, jobject observer,
39                                                    bool waitForPresentTime)
40         : uirenderer::FrameMetricsObserver(waitForPresentTime), mVm(vm) {
41     mObserverWeak = getenv(mVm)->NewWeakGlobalRef(observer);
42     LOG_ALWAYS_FATAL_IF(mObserverWeak == nullptr,
43             "unable to create frame stats observer reference");
44 }
45 
~HardwareRendererObserver()46 HardwareRendererObserver::~HardwareRendererObserver() {
47     JNIEnv* env = getenv(mVm);
48     env->DeleteWeakGlobalRef(mObserverWeak);
49 }
50 
getNextBuffer(JNIEnv * env,jlongArray metrics,int * dropCount)51 bool HardwareRendererObserver::getNextBuffer(JNIEnv* env, jlongArray metrics, int* dropCount) {
52     jsize bufferSize = env->GetArrayLength(reinterpret_cast<jarray>(metrics));
53     LOG_ALWAYS_FATAL_IF(bufferSize != HardwareRendererObserver::kBufferSize,
54                         "Mismatched Java/Native FrameMetrics data format.");
55 
56     FrameMetricsNotification& elem = mRingBuffer[mNextInQueue];
57     if (elem.hasData.load()) {
58         env->SetLongArrayRegion(metrics, 0, kBufferSize, elem.buffer);
59         *dropCount = elem.dropCount;
60         mNextInQueue = (mNextInQueue + 1) % kRingSize;
61         elem.hasData = false;
62         return true;
63     }
64 
65     return false;
66 }
67 
notify(const int64_t * stats)68 void HardwareRendererObserver::notify(const int64_t* stats) {
69     FrameMetricsNotification& elem = mRingBuffer[mNextFree];
70 
71     if (!elem.hasData.load()) {
72         memcpy(elem.buffer, stats, kBufferSize * sizeof(stats[0]));
73 
74         elem.dropCount = mDroppedReports;
75         mDroppedReports = 0;
76         mNextFree = (mNextFree + 1) % kRingSize;
77         elem.hasData = true;
78 
79         JNIEnv* env = getenv(mVm);
80         jobject target = env->NewLocalRef(mObserverWeak);
81         if (target != nullptr) {
82             env->CallVoidMethod(target, gHardwareRendererObserverClassInfo.callback);
83             env->DeleteLocalRef(target);
84         }
85     } else {
86         mDroppedReports++;
87     }
88 }
89 
android_graphics_HardwareRendererObserver_createObserver(JNIEnv * env,jobject observerObj,jboolean waitForPresentTime)90 static jlong android_graphics_HardwareRendererObserver_createObserver(JNIEnv* env,
91                                                                       jobject observerObj,
92                                                                       jboolean waitForPresentTime) {
93     JavaVM* vm = nullptr;
94     if (env->GetJavaVM(&vm) != JNI_OK) {
95         LOG_ALWAYS_FATAL("Unable to get Java VM");
96         return 0;
97     }
98 
99     HardwareRendererObserver* observer =
100             new HardwareRendererObserver(vm, observerObj, waitForPresentTime);
101     return reinterpret_cast<jlong>(observer);
102 }
103 
android_graphics_HardwareRendererObserver_getNextBuffer(JNIEnv * env,jobject,jlong observerPtr,jlongArray metrics)104 static jint android_graphics_HardwareRendererObserver_getNextBuffer(JNIEnv* env, jobject,
105                                                                     jlong observerPtr,
106                                                                     jlongArray metrics) {
107     HardwareRendererObserver* observer = reinterpret_cast<HardwareRendererObserver*>(observerPtr);
108     int dropCount = 0;
109     if (observer->getNextBuffer(env, metrics, &dropCount)) {
110         return dropCount;
111     } else {
112         return -1;
113     }
114 }
115 
116 static const std::array gMethods = {
117         MAKE_JNI_NATIVE_METHOD("nCreateObserver", "(Z)J",
118                                android_graphics_HardwareRendererObserver_createObserver),
119         MAKE_JNI_NATIVE_METHOD("nGetNextBuffer", "(J[J)I",
120                                android_graphics_HardwareRendererObserver_getNextBuffer),
121 };
122 
register_android_graphics_HardwareRendererObserver(JNIEnv * env)123 int register_android_graphics_HardwareRendererObserver(JNIEnv* env) {
124 
125     jclass observerClass = FindClassOrDie(env, "android/graphics/HardwareRendererObserver");
126     gHardwareRendererObserverClassInfo.callback = GetMethodIDOrDie(env, observerClass,
127                                                                    "notifyDataAvailable", "()V");
128 
129     return RegisterMethodsOrDie(env, "android/graphics/HardwareRendererObserver",
130                                 gMethods.data(), gMethods.size());
131 
132 }
133 
134 } // namespace android