xref: /aosp_15_r20/frameworks/base/core/jni/android_graphics_BLASTBufferQueue.cpp (revision d57664e9bc4670b3ecf6748a746a57c557b6bc9e)
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 <android_runtime/AndroidRuntime.h>
20 #include <android_runtime/android_view_Surface.h>
21 #include <android_util_Binder.h>
22 #include <gui/BLASTBufferQueue.h>
23 #include <gui/Surface.h>
24 #include <gui/SurfaceComposerClient.h>
25 #include <nativehelper/JNIHelp.h>
26 #include <utils/Log.h>
27 #include <utils/RefBase.h>
28 
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                 ScopedLocalRef<jobject>
143                         transactionObject(env,
144                                           env->NewObject(gTransactionClassInfo.clazz,
145                                                          gTransactionClassInfo.ctor,
146                                                          reinterpret_cast<jlong>(t)));
147                 env->CallVoidMethod(globalCallbackRef->object(), gTransactionConsumer.accept,
148                                     transactionObject.get());
149             },
150             acquireSingleBuffer);
151 }
152 
nativeStopContinuousSyncTransaction(JNIEnv * env,jclass clazz,jlong ptr)153 static void nativeStopContinuousSyncTransaction(JNIEnv* env, jclass clazz, jlong ptr) {
154     sp<BLASTBufferQueue> queue = reinterpret_cast<BLASTBufferQueue*>(ptr);
155     queue->stopContinuousSyncTransaction();
156 }
157 
nativeClearSyncTransaction(JNIEnv * env,jclass clazz,jlong ptr)158 static void nativeClearSyncTransaction(JNIEnv* env, jclass clazz, jlong ptr) {
159     sp<BLASTBufferQueue> queue = reinterpret_cast<BLASTBufferQueue*>(ptr);
160     queue->clearSyncTransaction();
161 }
162 
nativeUpdate(JNIEnv * env,jclass clazz,jlong ptr,jlong surfaceControl,jlong width,jlong height,jint format)163 static void nativeUpdate(JNIEnv* env, jclass clazz, jlong ptr, jlong surfaceControl, jlong width,
164                          jlong height, jint format) {
165     sp<BLASTBufferQueue> queue = reinterpret_cast<BLASTBufferQueue*>(ptr);
166     queue->update(reinterpret_cast<SurfaceControl*>(surfaceControl), width, height, format);
167 }
168 
nativeMergeWithNextTransaction(JNIEnv *,jclass clazz,jlong ptr,jlong transactionPtr,jlong framenumber)169 static void nativeMergeWithNextTransaction(JNIEnv*, jclass clazz, jlong ptr, jlong transactionPtr,
170                                            jlong framenumber) {
171     sp<BLASTBufferQueue> queue = reinterpret_cast<BLASTBufferQueue*>(ptr);
172     auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionPtr);
173     queue->mergeWithNextTransaction(transaction, CC_UNLIKELY(framenumber < 0) ? 0 : framenumber);
174 }
175 
nativeGetLastAcquiredFrameNum(JNIEnv * env,jclass clazz,jlong ptr)176 static jlong nativeGetLastAcquiredFrameNum(JNIEnv* env, jclass clazz, jlong ptr) {
177     sp<BLASTBufferQueue> queue = reinterpret_cast<BLASTBufferQueue*>(ptr);
178     return queue->getLastAcquiredFrameNum();
179 }
180 
nativeApplyPendingTransactions(JNIEnv * env,jclass clazz,jlong ptr,jlong frameNum)181 static void nativeApplyPendingTransactions(JNIEnv* env, jclass clazz, jlong ptr, jlong frameNum) {
182     sp<BLASTBufferQueue> queue = reinterpret_cast<BLASTBufferQueue*>(ptr);
183     queue->applyPendingTransactions(frameNum);
184 }
185 
nativeIsSameSurfaceControl(JNIEnv * env,jclass clazz,jlong ptr,jlong surfaceControl)186 static bool nativeIsSameSurfaceControl(JNIEnv* env, jclass clazz, jlong ptr, jlong surfaceControl) {
187     sp<BLASTBufferQueue> queue = reinterpret_cast<BLASTBufferQueue*>(ptr);
188     return queue->isSameSurfaceControl(reinterpret_cast<SurfaceControl*>(surfaceControl));
189 }
190 
nativeSetTransactionHangCallback(JNIEnv * env,jclass clazz,jlong ptr,jobject transactionHangCallback)191 static void nativeSetTransactionHangCallback(JNIEnv* env, jclass clazz, jlong ptr,
192                                              jobject transactionHangCallback) {
193     sp<BLASTBufferQueue> queue = reinterpret_cast<BLASTBufferQueue*>(ptr);
194     if (transactionHangCallback == nullptr) {
195         queue->setTransactionHangCallback(nullptr);
196     } else {
197         sp<TransactionHangCallbackWrapper> wrapper =
198                 new TransactionHangCallbackWrapper{env, transactionHangCallback};
199         queue->setTransactionHangCallback(
200                 [wrapper](const std::string& reason) { wrapper->onTransactionHang(reason); });
201     }
202 }
203 
nativeGatherPendingTransactions(JNIEnv * env,jclass clazz,jlong ptr,jlong frameNum)204 static jobject nativeGatherPendingTransactions(JNIEnv* env, jclass clazz, jlong ptr,
205                                                jlong frameNum) {
206     sp<BLASTBufferQueue> queue = reinterpret_cast<BLASTBufferQueue*>(ptr);
207     SurfaceComposerClient::Transaction* transaction = queue->gatherPendingTransactions(frameNum);
208     return env->NewObject(gTransactionClassInfo.clazz, gTransactionClassInfo.ctor,
209                           reinterpret_cast<jlong>(transaction));
210 }
211 
nativeSetApplyToken(JNIEnv * env,jclass clazz,jlong ptr,jobject applyTokenObject)212 static void nativeSetApplyToken(JNIEnv* env, jclass clazz, jlong ptr, jobject applyTokenObject) {
213     sp<BLASTBufferQueue> queue = reinterpret_cast<BLASTBufferQueue*>(ptr);
214     sp<IBinder> token(ibinderForJavaObject(env, applyTokenObject));
215     return queue->setApplyToken(std::move(token));
216 }
217 
218 static const JNINativeMethod gMethods[] = {
219         /* name, signature, funcPtr */
220         // clang-format off
221         {"nativeCreate", "(Ljava/lang/String;Z)J", (void*)nativeCreate},
222         {"nativeGetSurface", "(JZ)Landroid/view/Surface;", (void*)nativeGetSurface},
223         {"nativeDestroy", "(J)V", (void*)nativeDestroy},
224         {"nativeSyncNextTransaction", "(JLjava/util/function/Consumer;Z)Z", (void*)nativeSyncNextTransaction},
225         {"nativeStopContinuousSyncTransaction", "(J)V", (void*)nativeStopContinuousSyncTransaction},
226         {"nativeClearSyncTransaction", "(J)V", (void*)nativeClearSyncTransaction},
227         {"nativeUpdate", "(JJJJI)V", (void*)nativeUpdate},
228         {"nativeMergeWithNextTransaction", "(JJJ)V", (void*)nativeMergeWithNextTransaction},
229         {"nativeGetLastAcquiredFrameNum", "(J)J", (void*)nativeGetLastAcquiredFrameNum},
230         {"nativeApplyPendingTransactions", "(JJ)V", (void*)nativeApplyPendingTransactions},
231         {"nativeIsSameSurfaceControl", "(JJ)Z", (void*)nativeIsSameSurfaceControl},
232         {"nativeGatherPendingTransactions", "(JJ)Landroid/view/SurfaceControl$Transaction;", (void*)nativeGatherPendingTransactions},
233         {"nativeSetTransactionHangCallback",
234          "(JLandroid/graphics/BLASTBufferQueue$TransactionHangCallback;)V",
235          (void*)nativeSetTransactionHangCallback},
236         {"nativeSetApplyToken", "(JLandroid/os/IBinder;)V", (void*)nativeSetApplyToken},
237         // clang-format on
238 };
239 
register_android_graphics_BLASTBufferQueue(JNIEnv * env)240 int register_android_graphics_BLASTBufferQueue(JNIEnv* env) {
241     int res = jniRegisterNativeMethods(env, "android/graphics/BLASTBufferQueue",
242             gMethods, NELEM(gMethods));
243     LOG_ALWAYS_FATAL_IF(res < 0, "Unable to register native methods.");
244 
245     jclass transactionClazz = FindClassOrDie(env, "android/view/SurfaceControl$Transaction");
246     gTransactionClassInfo.clazz = MakeGlobalRefOrDie(env, transactionClazz);
247     gTransactionClassInfo.ctor =
248             GetMethodIDOrDie(env, gTransactionClassInfo.clazz, "<init>", "(J)V");
249 
250     jclass consumer = FindClassOrDie(env, "java/util/function/Consumer");
251     gTransactionConsumer.accept =
252             GetMethodIDOrDie(env, consumer, "accept", "(Ljava/lang/Object;)V");
253     jclass transactionHangClass =
254             FindClassOrDie(env, "android/graphics/BLASTBufferQueue$TransactionHangCallback");
255     gTransactionHangCallback.onTransactionHang =
256             GetMethodIDOrDie(env, transactionHangClass, "onTransactionHang",
257                              "(Ljava/lang/String;)V");
258 
259     return 0;
260 }
261 
262 } // namespace android
263