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 #define LOG_TAG "BLASTBufferQueue"
18
19 #include <nativehelper/JNIHelp.h>
20
21 #include <android_runtime/AndroidRuntime.h>
22 #include <android_runtime/android_view_Surface.h>
23 #include <utils/Log.h>
24 #include <utils/RefBase.h>
25
26 #include <gui/BLASTBufferQueue.h>
27 #include <gui/Surface.h>
28 #include <gui/SurfaceComposerClient.h>
29 #include "core_jni_helpers.h"
30
31 namespace android {
32
33 static struct {
34 jclass clazz;
35 jmethodID ctor;
36 } gTransactionClassInfo;
37
38 struct {
39 jmethodID accept;
40 } gTransactionConsumer;
41
getenv(JavaVM * vm)42 static JNIEnv* getenv(JavaVM* vm) {
43 JNIEnv* env;
44 auto result = vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6);
45 if (result == JNI_EDETACHED) {
46 if (vm->AttachCurrentThreadAsDaemon(&env, nullptr) != JNI_OK) {
47 LOG_ALWAYS_FATAL("Failed to AttachCurrentThread!");
48 }
49 } else if (result != JNI_OK) {
50 LOG_ALWAYS_FATAL("Failed to get JNIEnv for JavaVM: %p", vm);
51 }
52 return env;
53 }
54
55 struct {
56 jmethodID onTransactionHang;
57 } gTransactionHangCallback;
58
59 class TransactionHangCallbackWrapper : public LightRefBase<TransactionHangCallbackWrapper> {
60 public:
TransactionHangCallbackWrapper(JNIEnv * env,jobject jobject)61 explicit TransactionHangCallbackWrapper(JNIEnv* env, jobject jobject) {
62 env->GetJavaVM(&mVm);
63 mTransactionHangObject = env->NewGlobalRef(jobject);
64 LOG_ALWAYS_FATAL_IF(!mTransactionHangObject, "Failed to make global ref");
65 }
66
~TransactionHangCallbackWrapper()67 ~TransactionHangCallbackWrapper() {
68 if (mTransactionHangObject != nullptr) {
69 getenv(mVm)->DeleteGlobalRef(mTransactionHangObject);
70 mTransactionHangObject = nullptr;
71 }
72 }
73
onTransactionHang(const std::string & reason)74 void onTransactionHang(const std::string& reason) {
75 if (!mTransactionHangObject) {
76 return;
77 }
78 JNIEnv* env = getenv(mVm);
79 ScopedLocalRef<jstring> jReason(env, env->NewStringUTF(reason.c_str()));
80 getenv(mVm)->CallVoidMethod(mTransactionHangObject,
81 gTransactionHangCallback.onTransactionHang, jReason.get());
82 DieIfException(env, "Uncaught exception in TransactionHangCallback.");
83 }
84
85 private:
86 JavaVM* mVm;
87 jobject mTransactionHangObject;
88 };
89
nativeCreate(JNIEnv * env,jclass clazz,jstring jName,jboolean updateDestinationFrame)90 static jlong nativeCreate(JNIEnv* env, jclass clazz, jstring jName,
91 jboolean updateDestinationFrame) {
92 ScopedUtfChars name(env, jName);
93 sp<BLASTBufferQueue> queue = new BLASTBufferQueue(name.c_str(), updateDestinationFrame);
94 queue->incStrong((void*)nativeCreate);
95 return reinterpret_cast<jlong>(queue.get());
96 }
97
nativeDestroy(JNIEnv * env,jclass clazz,jlong ptr)98 static void nativeDestroy(JNIEnv* env, jclass clazz, jlong ptr) {
99 sp<BLASTBufferQueue> queue = reinterpret_cast<BLASTBufferQueue*>(ptr);
100 queue->decStrong((void*)nativeCreate);
101 }
102
nativeGetSurface(JNIEnv * env,jclass clazz,jlong ptr,jboolean includeSurfaceControlHandle)103 static jobject nativeGetSurface(JNIEnv* env, jclass clazz, jlong ptr,
104 jboolean includeSurfaceControlHandle) {
105 sp<BLASTBufferQueue> queue = reinterpret_cast<BLASTBufferQueue*>(ptr);
106 return android_view_Surface_createFromSurface(env,
107 queue->getSurface(includeSurfaceControlHandle));
108 }
109
110 class JGlobalRefHolder {
111 public:
JGlobalRefHolder(JavaVM * vm,jobject object)112 JGlobalRefHolder(JavaVM* vm, jobject object) : mVm(vm), mObject(object) {}
113
~JGlobalRefHolder()114 virtual ~JGlobalRefHolder() {
115 getenv(mVm)->DeleteGlobalRef(mObject);
116 mObject = nullptr;
117 }
118
object()119 jobject object() { return mObject; }
vm()120 JavaVM* vm() { return mVm; }
121
122 private:
123 JGlobalRefHolder(const JGlobalRefHolder&) = delete;
124 void operator=(const JGlobalRefHolder&) = delete;
125
126 JavaVM* mVm;
127 jobject mObject;
128 };
129
nativeSyncNextTransaction(JNIEnv * env,jclass clazz,jlong ptr,jobject callback,jboolean acquireSingleBuffer)130 static bool nativeSyncNextTransaction(JNIEnv* env, jclass clazz, jlong ptr, jobject callback,
131 jboolean acquireSingleBuffer) {
132 LOG_ALWAYS_FATAL_IF(!callback, "callback passed in to syncNextTransaction must not be NULL");
133
134 sp<BLASTBufferQueue> queue = reinterpret_cast<BLASTBufferQueue*>(ptr);
135 JavaVM* vm = nullptr;
136 LOG_ALWAYS_FATAL_IF(env->GetJavaVM(&vm) != JNI_OK, "Unable to get Java VM");
137
138 auto globalCallbackRef = std::make_shared<JGlobalRefHolder>(vm, env->NewGlobalRef(callback));
139 return queue->syncNextTransaction(
140 [globalCallbackRef](SurfaceComposerClient::Transaction* t) {
141 JNIEnv* env = getenv(globalCallbackRef->vm());
142 env->CallVoidMethod(globalCallbackRef->object(), gTransactionConsumer.accept,
143 env->NewObject(gTransactionClassInfo.clazz,
144 gTransactionClassInfo.ctor,
145 reinterpret_cast<jlong>(t)));
146 },
147 acquireSingleBuffer);
148 }
149
nativeStopContinuousSyncTransaction(JNIEnv * env,jclass clazz,jlong ptr)150 static void nativeStopContinuousSyncTransaction(JNIEnv* env, jclass clazz, jlong ptr) {
151 sp<BLASTBufferQueue> queue = reinterpret_cast<BLASTBufferQueue*>(ptr);
152 queue->stopContinuousSyncTransaction();
153 }
154
nativeClearSyncTransaction(JNIEnv * env,jclass clazz,jlong ptr)155 static void nativeClearSyncTransaction(JNIEnv* env, jclass clazz, jlong ptr) {
156 sp<BLASTBufferQueue> queue = reinterpret_cast<BLASTBufferQueue*>(ptr);
157 queue->clearSyncTransaction();
158 }
159
nativeUpdate(JNIEnv * env,jclass clazz,jlong ptr,jlong surfaceControl,jlong width,jlong height,jint format)160 static void nativeUpdate(JNIEnv* env, jclass clazz, jlong ptr, jlong surfaceControl, jlong width,
161 jlong height, jint format) {
162 sp<BLASTBufferQueue> queue = reinterpret_cast<BLASTBufferQueue*>(ptr);
163 queue->update(reinterpret_cast<SurfaceControl*>(surfaceControl), width, height, format);
164 }
165
nativeMergeWithNextTransaction(JNIEnv *,jclass clazz,jlong ptr,jlong transactionPtr,jlong framenumber)166 static void nativeMergeWithNextTransaction(JNIEnv*, jclass clazz, jlong ptr, jlong transactionPtr,
167 jlong framenumber) {
168 sp<BLASTBufferQueue> queue = reinterpret_cast<BLASTBufferQueue*>(ptr);
169 auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionPtr);
170 queue->mergeWithNextTransaction(transaction, CC_UNLIKELY(framenumber < 0) ? 0 : framenumber);
171 }
172
nativeGetLastAcquiredFrameNum(JNIEnv * env,jclass clazz,jlong ptr)173 static jlong nativeGetLastAcquiredFrameNum(JNIEnv* env, jclass clazz, jlong ptr) {
174 sp<BLASTBufferQueue> queue = reinterpret_cast<BLASTBufferQueue*>(ptr);
175 return queue->getLastAcquiredFrameNum();
176 }
177
nativeApplyPendingTransactions(JNIEnv * env,jclass clazz,jlong ptr,jlong frameNum)178 static void nativeApplyPendingTransactions(JNIEnv* env, jclass clazz, jlong ptr, jlong frameNum) {
179 sp<BLASTBufferQueue> queue = reinterpret_cast<BLASTBufferQueue*>(ptr);
180 queue->applyPendingTransactions(frameNum);
181 }
182
nativeIsSameSurfaceControl(JNIEnv * env,jclass clazz,jlong ptr,jlong surfaceControl)183 static bool nativeIsSameSurfaceControl(JNIEnv* env, jclass clazz, jlong ptr, jlong surfaceControl) {
184 sp<BLASTBufferQueue> queue = reinterpret_cast<BLASTBufferQueue*>(ptr);
185 return queue->isSameSurfaceControl(reinterpret_cast<SurfaceControl*>(surfaceControl));
186 }
187
nativeSetTransactionHangCallback(JNIEnv * env,jclass clazz,jlong ptr,jobject transactionHangCallback)188 static void nativeSetTransactionHangCallback(JNIEnv* env, jclass clazz, jlong ptr,
189 jobject transactionHangCallback) {
190 sp<BLASTBufferQueue> queue = reinterpret_cast<BLASTBufferQueue*>(ptr);
191 if (transactionHangCallback == nullptr) {
192 queue->setTransactionHangCallback(nullptr);
193 } else {
194 sp<TransactionHangCallbackWrapper> wrapper =
195 new TransactionHangCallbackWrapper{env, transactionHangCallback};
196 queue->setTransactionHangCallback(
197 [wrapper](const std::string& reason) { wrapper->onTransactionHang(reason); });
198 }
199 }
200
nativeGatherPendingTransactions(JNIEnv * env,jclass clazz,jlong ptr,jlong frameNum)201 static jobject nativeGatherPendingTransactions(JNIEnv* env, jclass clazz, jlong ptr,
202 jlong frameNum) {
203 sp<BLASTBufferQueue> queue = reinterpret_cast<BLASTBufferQueue*>(ptr);
204 SurfaceComposerClient::Transaction* transaction = queue->gatherPendingTransactions(frameNum);
205 return env->NewObject(gTransactionClassInfo.clazz, gTransactionClassInfo.ctor,
206 reinterpret_cast<jlong>(transaction));
207 }
208
209 static const JNINativeMethod gMethods[] = {
210 /* name, signature, funcPtr */
211 // clang-format off
212 {"nativeCreate", "(Ljava/lang/String;Z)J", (void*)nativeCreate},
213 {"nativeGetSurface", "(JZ)Landroid/view/Surface;", (void*)nativeGetSurface},
214 {"nativeDestroy", "(J)V", (void*)nativeDestroy},
215 {"nativeSyncNextTransaction", "(JLjava/util/function/Consumer;Z)Z", (void*)nativeSyncNextTransaction},
216 {"nativeStopContinuousSyncTransaction", "(J)V", (void*)nativeStopContinuousSyncTransaction},
217 {"nativeClearSyncTransaction", "(J)V", (void*)nativeClearSyncTransaction},
218 {"nativeUpdate", "(JJJJI)V", (void*)nativeUpdate},
219 {"nativeMergeWithNextTransaction", "(JJJ)V", (void*)nativeMergeWithNextTransaction},
220 {"nativeGetLastAcquiredFrameNum", "(J)J", (void*)nativeGetLastAcquiredFrameNum},
221 {"nativeApplyPendingTransactions", "(JJ)V", (void*)nativeApplyPendingTransactions},
222 {"nativeIsSameSurfaceControl", "(JJ)Z", (void*)nativeIsSameSurfaceControl},
223 {"nativeGatherPendingTransactions", "(JJ)Landroid/view/SurfaceControl$Transaction;", (void*)nativeGatherPendingTransactions},
224 {"nativeSetTransactionHangCallback",
225 "(JLandroid/graphics/BLASTBufferQueue$TransactionHangCallback;)V",
226 (void*)nativeSetTransactionHangCallback},
227 // clang-format on
228 };
229
register_android_graphics_BLASTBufferQueue(JNIEnv * env)230 int register_android_graphics_BLASTBufferQueue(JNIEnv* env) {
231 int res = jniRegisterNativeMethods(env, "android/graphics/BLASTBufferQueue",
232 gMethods, NELEM(gMethods));
233 LOG_ALWAYS_FATAL_IF(res < 0, "Unable to register native methods.");
234
235 jclass transactionClazz = FindClassOrDie(env, "android/view/SurfaceControl$Transaction");
236 gTransactionClassInfo.clazz = MakeGlobalRefOrDie(env, transactionClazz);
237 gTransactionClassInfo.ctor =
238 GetMethodIDOrDie(env, gTransactionClassInfo.clazz, "<init>", "(J)V");
239
240 jclass consumer = FindClassOrDie(env, "java/util/function/Consumer");
241 gTransactionConsumer.accept =
242 GetMethodIDOrDie(env, consumer, "accept", "(Ljava/lang/Object;)V");
243 jclass transactionHangClass =
244 FindClassOrDie(env, "android/graphics/BLASTBufferQueue$TransactionHangCallback");
245 gTransactionHangCallback.onTransactionHang =
246 GetMethodIDOrDie(env, transactionHangClass, "onTransactionHang",
247 "(Ljava/lang/String;)V");
248
249 return 0;
250 }
251
252 } // namespace android
253