diff options
| author | 2021-02-24 22:41:10 +0000 | |
|---|---|---|
| committer | 2021-02-24 22:41:10 +0000 | |
| commit | 1a621e8efffa2b3cc1edae6340cab4c5b0f80b13 (patch) | |
| tree | 718a27c0a1f217657371fbf0b1170b6e1e857718 | |
| parent | 491cbd85c83b53f2aaf72df49401d62dcbce8392 (diff) | |
| parent | 644553d06fbbaa802e89d39e5546e0241f82870a (diff) | |
Merge "JNI wrapper for FpsListener." into sc-dev
| -rw-r--r-- | core/java/android/view/SurfaceControlFpsListener.java | 93 | ||||
| -rw-r--r-- | core/jni/Android.bp | 1 | ||||
| -rw-r--r-- | core/jni/AndroidRuntime.cpp | 2 | ||||
| -rw-r--r-- | core/jni/android_view_SurfaceControlFpsListener.cpp | 130 | ||||
| -rw-r--r-- | core/tests/coretests/src/android/view/SurfaceControlFpsListenerTest.java | 46 |
5 files changed, 272 insertions, 0 deletions
diff --git a/core/java/android/view/SurfaceControlFpsListener.java b/core/java/android/view/SurfaceControlFpsListener.java new file mode 100644 index 000000000000..517b0fb8ccd3 --- /dev/null +++ b/core/java/android/view/SurfaceControlFpsListener.java @@ -0,0 +1,93 @@ +/* + * Copyright 2021 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 android.view; + +import android.annotation.NonNull; + +/** + * Listener for sampling the frames per second for a SurfaceControl and its children. + * This should only be used by a system component that needs to listen to a SurfaceControl's + * tree's FPS when it is not actively submitting transactions for that SurfaceControl. + * Otherwise, ASurfaceTransaction_OnComplete callbacks should be used. + * + * @hide + */ +public abstract class SurfaceControlFpsListener { + private long mNativeListener; + + public SurfaceControlFpsListener() { + mNativeListener = nativeCreate(this); + } + + protected void destroy() { + if (mNativeListener == 0) { + return; + } + unregister(); + nativeDestroy(mNativeListener); + mNativeListener = 0; + } + + @Override + protected void finalize() throws Throwable { + try { + destroy(); + } finally { + super.finalize(); + } + } + + /** + * Reports the fps from the registered SurfaceControl + */ + public abstract void onFpsReported(float fps); + + /** + * Registers the sampling listener. + */ + public void register(@NonNull SurfaceControl layer) { + if (mNativeListener == 0) { + return; + } + + nativeRegister(mNativeListener, layer.mNativeObject); + } + + /** + * Unregisters the sampling listener. + */ + public void unregister() { + if (mNativeListener == 0) { + return; + } + nativeUnregister(mNativeListener); + } + + /** + * Dispatch the collected sample. + * + * Called from native code on a binder thread. + */ + private static void dispatchOnFpsReported(SurfaceControlFpsListener listener, float fps) { + listener.onFpsReported(fps); + } + + private static native long nativeCreate(SurfaceControlFpsListener thiz); + private static native void nativeDestroy(long ptr); + private static native void nativeRegister(long ptr, long layerObject); + private static native void nativeUnregister(long ptr); +} diff --git a/core/jni/Android.bp b/core/jni/Android.bp index dd1a5941eed8..b485f0f4fb62 100644 --- a/core/jni/Android.bp +++ b/core/jni/Android.bp @@ -121,6 +121,7 @@ cc_library_shared { "android_view_PointerIcon.cpp", "android_view_Surface.cpp", "android_view_SurfaceControl.cpp", + "android_view_SurfaceControlFpsListener.cpp", "android_graphics_BLASTBufferQueue.cpp", "android_view_SurfaceSession.cpp", "android_view_TextureView.cpp", diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp index 1751be0af2cc..dc77bba44607 100644 --- a/core/jni/AndroidRuntime.cpp +++ b/core/jni/AndroidRuntime.cpp @@ -120,6 +120,7 @@ extern int register_android_view_InputApplicationHandle(JNIEnv* env); extern int register_android_view_InputWindowHandle(JNIEnv* env); extern int register_android_view_Surface(JNIEnv* env); extern int register_android_view_SurfaceControl(JNIEnv* env); +extern int register_android_view_SurfaceControlFpsListener(JNIEnv* env); extern int register_android_view_SurfaceSession(JNIEnv* env); extern int register_android_view_CompositionSamplingListener(JNIEnv* env); extern int register_android_view_TextureView(JNIEnv* env); @@ -1488,6 +1489,7 @@ static const RegJNIRec gRegJNI[] = { REG_JNI(register_android_view_InputWindowHandle), REG_JNI(register_android_view_Surface), REG_JNI(register_android_view_SurfaceControl), + REG_JNI(register_android_view_SurfaceControlFpsListener), REG_JNI(register_android_view_SurfaceSession), REG_JNI(register_android_view_CompositionSamplingListener), REG_JNI(register_android_view_TextureView), diff --git a/core/jni/android_view_SurfaceControlFpsListener.cpp b/core/jni/android_view_SurfaceControlFpsListener.cpp new file mode 100644 index 000000000000..6fa12e510459 --- /dev/null +++ b/core/jni/android_view_SurfaceControlFpsListener.cpp @@ -0,0 +1,130 @@ +/* + * Copyright 2021 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 "SurfaceControlFpsListener" + +#include <android/gui/BnFpsListener.h> +#include <android_runtime/AndroidRuntime.h> +#include <android_runtime/Log.h> +#include <gui/ISurfaceComposer.h> +#include <gui/SurfaceComposerClient.h> +#include <nativehelper/JNIHelp.h> +#include <utils/Log.h> +#include <utils/RefBase.h> + +#include "android_util_Binder.h" +#include "core_jni_helpers.h" + +namespace android { + +namespace { + +struct { + jclass mClass; + jmethodID mDispatchOnFpsReported; +} gListenerClassInfo; + +struct SurfaceControlFpsListener : public gui::BnFpsListener { + SurfaceControlFpsListener(JNIEnv* env, jobject listener) + : mListener(env->NewWeakGlobalRef(listener)) {} + + binder::Status onFpsReported(float fps) override { + JNIEnv* env = AndroidRuntime::getJNIEnv(); + LOG_ALWAYS_FATAL_IF(env == nullptr, "Unable to retrieve JNIEnv in onFpsReported."); + + jobject listener = env->NewGlobalRef(mListener); + if (listener == NULL) { + // Weak reference went out of scope + return binder::Status::ok(); + } + env->CallStaticVoidMethod(gListenerClassInfo.mClass, + gListenerClassInfo.mDispatchOnFpsReported, listener, + static_cast<jfloat>(fps)); + env->DeleteGlobalRef(listener); + + if (env->ExceptionCheck()) { + ALOGE("SurfaceControlFpsListener.onFpsReported() failed."); + LOGE_EX(env); + env->ExceptionClear(); + } + return binder::Status::ok(); + } + +protected: + virtual ~SurfaceControlFpsListener() { + JNIEnv* env = AndroidRuntime::getJNIEnv(); + env->DeleteWeakGlobalRef(mListener); + } + +private: + jweak mListener; +}; + +jlong nativeCreate(JNIEnv* env, jclass clazz, jobject obj) { + SurfaceControlFpsListener* listener = new SurfaceControlFpsListener(env, obj); + listener->incStrong((void*)nativeCreate); + return reinterpret_cast<jlong>(listener); +} + +void nativeDestroy(JNIEnv* env, jclass clazz, jlong ptr) { + SurfaceControlFpsListener* listener = reinterpret_cast<SurfaceControlFpsListener*>(ptr); + listener->decStrong((void*)nativeCreate); +} + +void nativeRegister(JNIEnv* env, jclass clazz, jlong ptr, jlong layerObj) { + sp<SurfaceControlFpsListener> listener = reinterpret_cast<SurfaceControlFpsListener*>(ptr); + auto layer = reinterpret_cast<SurfaceControl*>(layerObj); + sp<IBinder> layerHandle = layer != nullptr ? layer->getHandle() : nullptr; + if (SurfaceComposerClient::addFpsListener(layerHandle, listener) != OK) { + constexpr auto error_msg = "Couldn't addFpsListener"; + ALOGE(error_msg); + jniThrowRuntimeException(env, error_msg); + } +} + +void nativeUnregister(JNIEnv* env, jclass clazz, jlong ptr) { + sp<SurfaceControlFpsListener> listener = reinterpret_cast<SurfaceControlFpsListener*>(ptr); + + if (SurfaceComposerClient::removeFpsListener(listener) != OK) { + constexpr auto error_msg = "Couldn't removeFpsListener"; + ALOGE(error_msg); + jniThrowRuntimeException(env, error_msg); + } +} + +const JNINativeMethod gMethods[] = { + /* name, signature, funcPtr */ + {"nativeCreate", "(Landroid/view/SurfaceControlFpsListener;)J", (void*)nativeCreate}, + {"nativeDestroy", "(J)V", (void*)nativeDestroy}, + {"nativeRegister", "(JJ)V", (void*)nativeRegister}, + {"nativeUnregister", "(J)V", (void*)nativeUnregister}}; + +} // namespace + +int register_android_view_SurfaceControlFpsListener(JNIEnv* env) { + int res = jniRegisterNativeMethods(env, "android/view/SurfaceControlFpsListener", gMethods, + NELEM(gMethods)); + LOG_ALWAYS_FATAL_IF(res < 0, "Unable to register native methods."); + + jclass clazz = env->FindClass("android/view/SurfaceControlFpsListener"); + gListenerClassInfo.mClass = MakeGlobalRefOrDie(env, clazz); + gListenerClassInfo.mDispatchOnFpsReported = + env->GetStaticMethodID(clazz, "dispatchOnFpsReported", + "(Landroid/view/SurfaceControlFpsListener;F)V"); + return 0; +} + +} // namespace android diff --git a/core/tests/coretests/src/android/view/SurfaceControlFpsListenerTest.java b/core/tests/coretests/src/android/view/SurfaceControlFpsListenerTest.java new file mode 100644 index 000000000000..36104cf0f71d --- /dev/null +++ b/core/tests/coretests/src/android/view/SurfaceControlFpsListenerTest.java @@ -0,0 +1,46 @@ +/* + * Copyright 2021 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 android.view; + +import android.platform.test.annotations.Presubmit; + +import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; + +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(AndroidJUnit4.class) +@SmallTest +@Presubmit +public class SurfaceControlFpsListenerTest { + + @Test + public void registersAndUnregisters() { + + SurfaceControlFpsListener listener = new SurfaceControlFpsListener() { + @Override + public void onFpsReported(float fps) { + // Ignore + } + }; + + listener.register(new SurfaceControl()); + + listener.unregister(); + } +} |