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 jclass clazz;
28 jmethodID callback;
29 } gHardwareRendererObserverClassInfo;
30
getenv(JavaVM * vm)31 static JNIEnv* getenv(JavaVM* vm) {
32 JNIEnv* env;
33 if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
34 LOG_ALWAYS_FATAL("Failed to get JNIEnv for JavaVM: %p", vm);
35 }
36 return env;
37 }
38
HardwareRendererObserver(JavaVM * vm,jobject observer,bool waitForPresentTime)39 HardwareRendererObserver::HardwareRendererObserver(JavaVM* vm, jobject observer,
40 bool waitForPresentTime)
41 : uirenderer::FrameMetricsObserver(waitForPresentTime), mVm(vm) {
42 mObserver = getenv(mVm)->NewGlobalRef(observer);
43 LOG_ALWAYS_FATAL_IF(mObserver == nullptr, "unable to create frame stats observer reference");
44 }
45
~HardwareRendererObserver()46 HardwareRendererObserver::~HardwareRendererObserver() {
47 JNIEnv* env = getenv(mVm);
48 env->DeleteGlobalRef(mObserver);
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 if (!mKeepListening) return;
70
71 FrameMetricsNotification& elem = mRingBuffer[mNextFree];
72
73 if (!elem.hasData.load()) {
74 memcpy(elem.buffer, stats, kBufferSize * sizeof(stats[0]));
75
76 elem.dropCount = mDroppedReports;
77 mDroppedReports = 0;
78 mNextFree = (mNextFree + 1) % kRingSize;
79 elem.hasData = true;
80
81 JNIEnv* env = getenv(mVm);
82 mKeepListening = env->CallStaticBooleanMethod(gHardwareRendererObserverClassInfo.clazz,
83 gHardwareRendererObserverClassInfo.callback,
84 mObserver);
85 } else {
86 mDroppedReports++;
87 }
88 }
89
android_graphics_HardwareRendererObserver_createObserver(JNIEnv * env,jobject,jobject weakRefThis,jboolean waitForPresentTime)90 static jlong android_graphics_HardwareRendererObserver_createObserver(JNIEnv* env,
91 jobject /*clazz*/,
92 jobject weakRefThis,
93 jboolean waitForPresentTime) {
94 JavaVM* vm = nullptr;
95 if (env->GetJavaVM(&vm) != JNI_OK) {
96 LOG_ALWAYS_FATAL("Unable to get Java VM");
97 return 0;
98 }
99
100 HardwareRendererObserver* observer =
101 new HardwareRendererObserver(vm, weakRefThis, waitForPresentTime);
102 return reinterpret_cast<jlong>(observer);
103 }
104
android_graphics_HardwareRendererObserver_getNextBuffer(JNIEnv * env,jobject,jlong observerPtr,jlongArray metrics)105 static jint android_graphics_HardwareRendererObserver_getNextBuffer(JNIEnv* env, jobject,
106 jlong observerPtr,
107 jlongArray metrics) {
108 HardwareRendererObserver* observer = reinterpret_cast<HardwareRendererObserver*>(observerPtr);
109 int dropCount = 0;
110 if (observer->getNextBuffer(env, metrics, &dropCount)) {
111 return dropCount;
112 } else {
113 return -1;
114 }
115 }
116
117 static const std::array gMethods = {
118 MAKE_JNI_NATIVE_METHOD("nCreateObserver", "(Ljava/lang/ref/WeakReference;Z)J",
119 android_graphics_HardwareRendererObserver_createObserver),
120 MAKE_JNI_NATIVE_METHOD("nGetNextBuffer", "(J[J)I",
121 android_graphics_HardwareRendererObserver_getNextBuffer),
122 };
123
register_android_graphics_HardwareRendererObserver(JNIEnv * env)124 int register_android_graphics_HardwareRendererObserver(JNIEnv* env) {
125
126 jclass observerClass = FindClassOrDie(env, "android/graphics/HardwareRendererObserver");
127 gHardwareRendererObserverClassInfo.clazz =
128 reinterpret_cast<jclass>(env->NewGlobalRef(observerClass));
129 gHardwareRendererObserverClassInfo.callback = GetStaticMethodIDOrDie(
130 env, observerClass, "invokeDataAvailable", "(Ljava/lang/ref/WeakReference;)Z");
131
132 return RegisterMethodsOrDie(env, "android/graphics/HardwareRendererObserver",
133 gMethods.data(), gMethods.size());
134
135 }
136
137 } // namespace android