Merge "Use NDK version of transaction completed callback" into 24D1-dev
diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java
index d30ddca..3f795a6 100644
--- a/services/core/java/com/android/server/wm/Transition.java
+++ b/services/core/java/com/android/server/wm/Transition.java
@@ -105,6 +105,7 @@
import com.android.internal.util.function.pooled.PooledLambda;
import com.android.server.inputmethod.InputMethodManagerInternal;
import com.android.server.statusbar.StatusBarManagerInternal;
+import com.android.server.wm.utils.SurfaceControlUtils;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -1631,8 +1632,7 @@
if (mTransactionCompletedListeners != null) {
for (int i = 0; i < mTransactionCompletedListeners.size(); i++) {
final Runnable listener = mTransactionCompletedListeners.get(i);
- transaction.addTransactionCompletedListener(Runnable::run,
- (stats) -> listener.run());
+ SurfaceControlUtils.addTransactionCompletedListener(transaction, listener);
}
}
diff --git a/services/core/java/com/android/server/wm/utils/SurfaceControlUtils.java b/services/core/java/com/android/server/wm/utils/SurfaceControlUtils.java
new file mode 100644
index 0000000..e658cc9
--- /dev/null
+++ b/services/core/java/com/android/server/wm/utils/SurfaceControlUtils.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm.utils;
+
+import android.view.SurfaceControl;
+
+/**
+ * JNI wrapper for ASurfaceTransaction_setOnComplete NDK method which is not
+ * exposed as a Java API on older Android versions
+ */
+public class SurfaceControlUtils {
+
+ /**
+ * Adds a listener for transaction completion (when transaction is presented on the screen)
+ * @param transaction transaction to which add the listener
+ * @param runnable callback which will be called when transaction is presented
+ */
+ public static void addTransactionCompletedListener(SurfaceControl.Transaction transaction,
+ Runnable onComplete) {
+ nativeAddTransactionCompletedListener(transaction, onComplete);
+ }
+
+ private static native void nativeAddTransactionCompletedListener(
+ SurfaceControl.Transaction transaction, Runnable callback);
+}
diff --git a/services/core/jni/Android.bp b/services/core/jni/Android.bp
index 3607ddd..a348d58 100644
--- a/services/core/jni/Android.bp
+++ b/services/core/jni/Android.bp
@@ -76,6 +76,7 @@
"com_android_server_pm_PackageManagerShellCommandDataLoader.cpp",
"com_android_server_sensor_SensorService.cpp",
"com_android_server_wm_TaskFpsCallbackController.cpp",
+ "com_android_server_wm_utils_SurfaceControlUtils.cpp",
"onload.cpp",
":lib_cachedAppOptimizer_native",
":lib_gameManagerService_native",
diff --git a/services/core/jni/com_android_server_wm_utils_SurfaceControlUtils.cpp b/services/core/jni/com_android_server_wm_utils_SurfaceControlUtils.cpp
new file mode 100644
index 0000000..d29b396
--- /dev/null
+++ b/services/core/jni/com_android_server_wm_utils_SurfaceControlUtils.cpp
@@ -0,0 +1,105 @@
+/*
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "SurfaceControlUtils"
+
+#include <android_runtime/AndroidRuntime.h>
+#include <android_runtime/Log.h>
+#include <android/surface_control.h>
+#include <android/surface_control_jni.h>
+#include <nativehelper/JNIHelp.h>
+#include <utils/Log.h>
+#include <utils/RefBase.h>
+
+#include "core_jni_helpers.h"
+
+namespace android {
+
+namespace {
+
+static struct {
+ jclass clazz;
+ jmethodID run;
+} gRunnableClassInfo;
+
+class TransactionCompletedListenerWrapper {
+public:
+ explicit TransactionCompletedListenerWrapper(JNIEnv* env, jobject object) {
+ env->GetJavaVM(&mVm);
+ mTransactionCompletedListenerObject = env->NewGlobalRef(object);
+ LOG_ALWAYS_FATAL_IF(!mTransactionCompletedListenerObject, "Failed to make global ref");
+ }
+
+ ~TransactionCompletedListenerWrapper() {
+ getenv()->DeleteGlobalRef(mTransactionCompletedListenerObject);
+ }
+
+ void callback() {
+ JNIEnv* env = getenv();
+
+ env->CallVoidMethod(mTransactionCompletedListenerObject, gRunnableClassInfo.run);
+
+ DieIfException(env, "Uncaught exception in TransactionCompletedListener.");
+ }
+
+ static void transactionCallbackThunk(void* context, ASurfaceTransactionStats* stats) {
+ TransactionCompletedListenerWrapper* listener =
+ reinterpret_cast<TransactionCompletedListenerWrapper*>(context);
+ listener->callback();
+ delete listener;
+ }
+
+private:
+ jobject mTransactionCompletedListenerObject;
+ JavaVM* mVm;
+
+ JNIEnv* getenv() {
+ JNIEnv* env;
+ mVm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6);
+ return env;
+ }
+};
+
+static void nativeAddTransactionCompletedListener(JNIEnv* env, jclass clazz,
+ jobject transactionObj,
+ jobject transactionCompletedListener) {
+ ASurfaceTransaction* transaction = ASurfaceTransaction_fromJava(env, transactionObj);
+ auto context = new TransactionCompletedListenerWrapper(env, transactionCompletedListener);
+ ASurfaceTransaction_setOnComplete(transaction, reinterpret_cast<void*>(context),
+ TransactionCompletedListenerWrapper::
+ transactionCallbackThunk);
+}
+
+static const JNINativeMethod gMethods[] = {
+ /* name, signature, funcPtr */
+ {"nativeAddTransactionCompletedListener",
+ "(Landroid/view/SurfaceControl$Transaction;Ljava/lang/Runnable;)V",
+ (void*) nativeAddTransactionCompletedListener}};
+} // namespace
+
+int register_com_android_server_wm_utils_SurfaceControlUtils(JNIEnv* env) {
+ int res = jniRegisterNativeMethods(env, "com/android/server/wm/utils/SurfaceControlUtils",
+ gMethods, NELEM(gMethods));
+ LOG_ALWAYS_FATAL_IF(res < 0, "Unable to register native methods.");
+
+ jclass runnableClazz = FindClassOrDie(env, "java/lang/Runnable");
+ gRunnableClassInfo.clazz = MakeGlobalRefOrDie(env, runnableClazz);
+ gRunnableClassInfo.run = GetMethodIDOrDie(env, runnableClazz, "run", "()V");
+
+ return 0;
+}
+
+} // namespace android
diff --git a/services/core/jni/onload.cpp b/services/core/jni/onload.cpp
index 0936888..dbca8d1 100644
--- a/services/core/jni/onload.cpp
+++ b/services/core/jni/onload.cpp
@@ -67,6 +67,7 @@
int register_android_server_companion_virtual_InputController(JNIEnv* env);
int register_android_server_app_GameManagerService(JNIEnv* env);
int register_com_android_server_wm_TaskFpsCallbackController(JNIEnv* env);
+int register_com_android_server_wm_utils_SurfaceControlUtils(JNIEnv* env);
int register_com_android_server_display_DisplayControl(JNIEnv* env);
int register_com_android_server_SystemClockTime(JNIEnv* env);
int register_android_server_display_smallAreaDetectionController(JNIEnv* env);
@@ -130,6 +131,7 @@
register_android_server_companion_virtual_InputController(env);
register_android_server_app_GameManagerService(env);
register_com_android_server_wm_TaskFpsCallbackController(env);
+ register_com_android_server_wm_utils_SurfaceControlUtils(env);
register_com_android_server_display_DisplayControl(env);
register_com_android_server_SystemClockTime(env);
register_android_server_display_smallAreaDetectionController(env);