Loading core/jni/Android.bp +1 −0 Original line number Diff line number Diff line Loading @@ -153,6 +153,7 @@ cc_library_shared { "android_view_InputEventReceiver.cpp", "android_view_InputEventSender.cpp", "android_view_InputQueue.cpp", "android_view_FrameMetricsObserver.cpp", "android_view_KeyCharacterMap.cpp", "android_view_KeyEvent.cpp", "android_view_MotionEvent.cpp", Loading core/jni/AndroidRuntime.cpp +2 −0 Original line number Diff line number Diff line Loading @@ -158,6 +158,7 @@ extern int register_android_graphics_text_MeasuredText(JNIEnv* env); extern int register_android_graphics_text_LineBreaker(JNIEnv *env); extern int register_android_view_DisplayEventReceiver(JNIEnv* env); extern int register_android_view_DisplayListCanvas(JNIEnv* env); extern int register_android_view_FrameMetricsObserver(JNIEnv* env); extern int register_android_view_InputApplicationHandle(JNIEnv* env); extern int register_android_view_InputWindowHandle(JNIEnv* env); extern int register_android_view_TextureLayer(JNIEnv* env); Loading Loading @@ -1464,6 +1465,7 @@ static const RegJNIRec gRegJNI[] = { REG_JNI(register_android_view_RenderNode), REG_JNI(register_android_view_RenderNodeAnimator), REG_JNI(register_android_view_DisplayListCanvas), REG_JNI(register_android_view_FrameMetricsObserver), REG_JNI(register_android_view_InputApplicationHandle), REG_JNI(register_android_view_InputWindowHandle), REG_JNI(register_android_view_TextureLayer), Loading core/jni/android_view_FrameMetricsObserver.cpp 0 → 100644 +149 −0 Original line number Diff line number Diff line /* * Copyright (C) 2019 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. */ #include "android_view_FrameMetricsObserver.h" namespace android { struct { jfieldID frameMetrics; jfieldID timingDataBuffer; jfieldID messageQueue; jmethodID callback; } gFrameMetricsObserverClassInfo; static JNIEnv* getenv(JavaVM* vm) { JNIEnv* env; if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) { LOG_ALWAYS_FATAL("Failed to get JNIEnv for JavaVM: %p", vm); } return env; } static jlongArray get_metrics_buffer(JNIEnv* env, jobject observer) { jobject frameMetrics = env->GetObjectField( observer, gFrameMetricsObserverClassInfo.frameMetrics); LOG_ALWAYS_FATAL_IF(frameMetrics == nullptr, "unable to retrieve data sink object"); jobject buffer = env->GetObjectField( frameMetrics, gFrameMetricsObserverClassInfo.timingDataBuffer); LOG_ALWAYS_FATAL_IF(buffer == nullptr, "unable to retrieve data sink buffer"); return reinterpret_cast<jlongArray>(buffer); } class NotifyHandler : public MessageHandler { public: NotifyHandler(JavaVM* vm, FrameMetricsObserverProxy* observer) : mVm(vm), mObserver(observer) {} virtual void handleMessage(const Message& message); private: JavaVM* const mVm; FrameMetricsObserverProxy* const mObserver; }; void NotifyHandler::handleMessage(const Message& message) { JNIEnv* env = getenv(mVm); jobject target = env->NewLocalRef(mObserver->getObserverReference()); if (target != nullptr) { jlongArray javaBuffer = get_metrics_buffer(env, target); int dropCount = 0; while (mObserver->getNextBuffer(env, javaBuffer, &dropCount)) { env->CallVoidMethod(target, gFrameMetricsObserverClassInfo.callback, dropCount); } env->DeleteLocalRef(target); } mObserver->decStrong(nullptr); } FrameMetricsObserverProxy::FrameMetricsObserverProxy(JavaVM *vm, jobject observer) : mVm(vm) { JNIEnv* env = getenv(mVm); mObserverWeak = env->NewWeakGlobalRef(observer); LOG_ALWAYS_FATAL_IF(mObserverWeak == nullptr, "unable to create frame stats observer reference"); jlongArray buffer = get_metrics_buffer(env, observer); jsize bufferSize = env->GetArrayLength(reinterpret_cast<jarray>(buffer)); LOG_ALWAYS_FATAL_IF(bufferSize != kBufferSize, "Mismatched Java/Native FrameMetrics data format."); jobject messageQueueLocal = env->GetObjectField( observer, gFrameMetricsObserverClassInfo.messageQueue); mMessageQueue = android_os_MessageQueue_getMessageQueue(env, messageQueueLocal); LOG_ALWAYS_FATAL_IF(mMessageQueue == nullptr, "message queue not available"); mMessageHandler = new NotifyHandler(mVm, this); LOG_ALWAYS_FATAL_IF(mMessageHandler == nullptr, "OOM: unable to allocate NotifyHandler"); } FrameMetricsObserverProxy::~FrameMetricsObserverProxy() { JNIEnv* env = getenv(mVm); env->DeleteWeakGlobalRef(mObserverWeak); } bool FrameMetricsObserverProxy::getNextBuffer(JNIEnv* env, jlongArray sink, int* dropCount) { FrameMetricsNotification& elem = mRingBuffer[mNextInQueue]; if (elem.hasData.load()) { env->SetLongArrayRegion(sink, 0, kBufferSize, elem.buffer); *dropCount = elem.dropCount; mNextInQueue = (mNextInQueue + 1) % kRingSize; elem.hasData = false; return true; } return false; } void FrameMetricsObserverProxy::notify(const int64_t* stats) { FrameMetricsNotification& elem = mRingBuffer[mNextFree]; if (!elem.hasData.load()) { memcpy(elem.buffer, stats, kBufferSize * sizeof(stats[0])); elem.dropCount = mDroppedReports; mDroppedReports = 0; incStrong(nullptr); mNextFree = (mNextFree + 1) % kRingSize; elem.hasData = true; mMessageQueue->getLooper()->sendMessage(mMessageHandler, mMessage); } else { mDroppedReports++; } } int register_android_view_FrameMetricsObserver(JNIEnv* env) { jclass observerClass = FindClassOrDie(env, "android/view/FrameMetricsObserver"); gFrameMetricsObserverClassInfo.frameMetrics = GetFieldIDOrDie( env, observerClass, "mFrameMetrics", "Landroid/view/FrameMetrics;"); gFrameMetricsObserverClassInfo.messageQueue = GetFieldIDOrDie( env, observerClass, "mMessageQueue", "Landroid/os/MessageQueue;"); gFrameMetricsObserverClassInfo.callback = GetMethodIDOrDie( env, observerClass, "notifyDataAvailable", "(I)V"); jclass metricsClass = FindClassOrDie(env, "android/view/FrameMetrics"); gFrameMetricsObserverClassInfo.timingDataBuffer = GetFieldIDOrDie( env, metricsClass, "mTimingData", "[J"); return JNI_OK; } } // namespace android No newline at end of file core/jni/android_view_FrameMetricsObserver.h 0 → 100644 +71 −0 Original line number Diff line number Diff line /* * Copyright (C) 2019 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. */ #include "jni.h" #include "core_jni_helpers.h" #include "android_os_MessageQueue.h" #include <FrameInfo.h> #include <FrameMetricsObserver.h> namespace android { /* * Implements JNI layer for hwui frame metrics reporting. */ class FrameMetricsObserverProxy : public uirenderer::FrameMetricsObserver { public: FrameMetricsObserverProxy(JavaVM *vm, jobject observer); ~FrameMetricsObserverProxy(); jweak getObserverReference() { return mObserverWeak; } bool getNextBuffer(JNIEnv* env, jlongArray sink, int* dropCount); virtual void notify(const int64_t* stats); private: static const int kBufferSize = static_cast<int>(uirenderer::FrameInfoIndex::NumIndexes); static constexpr int kRingSize = 3; class FrameMetricsNotification { public: FrameMetricsNotification() : hasData(false) {} std::atomic_bool hasData; int64_t buffer[kBufferSize]; int dropCount = 0; }; JavaVM* const mVm; jweak mObserverWeak; sp<MessageQueue> mMessageQueue; sp<MessageHandler> mMessageHandler; Message mMessage; int mNextFree = 0; int mNextInQueue = 0; FrameMetricsNotification mRingBuffer[kRingSize]; int mDroppedReports = 0; }; } // namespace android core/jni/android_view_ThreadedRenderer.cpp +3 −158 Original line number Diff line number Diff line Loading @@ -30,6 +30,8 @@ #include <gui/BufferQueue.h> #include <gui/Surface.h> #include "android_view_FrameMetricsObserver.h" #include <private/EGL/cache.h> #include <utils/RefBase.h> Loading @@ -39,10 +41,7 @@ #include <android_runtime/android_view_Surface.h> #include <system/window.h> #include "android_os_MessageQueue.h" #include <FrameInfo.h> #include <FrameMetricsObserver.h> #include <IContextFactory.h> #include <Picture.h> #include <Properties.h> Loading @@ -59,13 +58,6 @@ namespace android { using namespace android::uirenderer; using namespace android::uirenderer::renderthread; struct { jfieldID frameMetrics; jfieldID timingDataBuffer; jfieldID messageQueue; jmethodID callback; } gFrameMetricsObserverClassInfo; struct { jclass clazz; jmethodID invokePictureCapturedCallback; Loading Loading @@ -133,142 +125,6 @@ private: } }; class ObserverProxy; class NotifyHandler : public MessageHandler { public: NotifyHandler(JavaVM* vm, ObserverProxy* observer) : mVm(vm), mObserver(observer) {} virtual void handleMessage(const Message& message); private: JavaVM* const mVm; ObserverProxy* const mObserver; }; static jlongArray get_metrics_buffer(JNIEnv* env, jobject observer) { jobject frameMetrics = env->GetObjectField( observer, gFrameMetricsObserverClassInfo.frameMetrics); LOG_ALWAYS_FATAL_IF(frameMetrics == nullptr, "unable to retrieve data sink object"); jobject buffer = env->GetObjectField( frameMetrics, gFrameMetricsObserverClassInfo.timingDataBuffer); LOG_ALWAYS_FATAL_IF(buffer == nullptr, "unable to retrieve data sink buffer"); return reinterpret_cast<jlongArray>(buffer); } /* * Implements JNI layer for hwui frame metrics reporting. */ class ObserverProxy : public FrameMetricsObserver { public: ObserverProxy(JavaVM *vm, jobject observer) : mVm(vm) { JNIEnv* env = getenv(mVm); mObserverWeak = env->NewWeakGlobalRef(observer); LOG_ALWAYS_FATAL_IF(mObserverWeak == nullptr, "unable to create frame stats observer reference"); jlongArray buffer = get_metrics_buffer(env, observer); jsize bufferSize = env->GetArrayLength(reinterpret_cast<jarray>(buffer)); LOG_ALWAYS_FATAL_IF(bufferSize != kBufferSize, "Mismatched Java/Native FrameMetrics data format."); jobject messageQueueLocal = env->GetObjectField( observer, gFrameMetricsObserverClassInfo.messageQueue); mMessageQueue = android_os_MessageQueue_getMessageQueue(env, messageQueueLocal); LOG_ALWAYS_FATAL_IF(mMessageQueue == nullptr, "message queue not available"); mMessageHandler = new NotifyHandler(mVm, this); LOG_ALWAYS_FATAL_IF(mMessageHandler == nullptr, "OOM: unable to allocate NotifyHandler"); } ~ObserverProxy() { JNIEnv* env = getenv(mVm); env->DeleteWeakGlobalRef(mObserverWeak); } jweak getObserverReference() { return mObserverWeak; } bool getNextBuffer(JNIEnv* env, jlongArray sink, int* dropCount) { FrameMetricsNotification& elem = mRingBuffer[mNextInQueue]; if (elem.hasData.load()) { env->SetLongArrayRegion(sink, 0, kBufferSize, elem.buffer); *dropCount = elem.dropCount; mNextInQueue = (mNextInQueue + 1) % kRingSize; elem.hasData = false; return true; } return false; } virtual void notify(const int64_t* stats) { FrameMetricsNotification& elem = mRingBuffer[mNextFree]; if (!elem.hasData.load()) { memcpy(elem.buffer, stats, kBufferSize * sizeof(stats[0])); elem.dropCount = mDroppedReports; mDroppedReports = 0; incStrong(nullptr); mNextFree = (mNextFree + 1) % kRingSize; elem.hasData = true; mMessageQueue->getLooper()->sendMessage(mMessageHandler, mMessage); } else { mDroppedReports++; } } private: static const int kBufferSize = static_cast<int>(FrameInfoIndex::NumIndexes); static constexpr int kRingSize = 3; class FrameMetricsNotification { public: FrameMetricsNotification() : hasData(false) {} std::atomic_bool hasData; int64_t buffer[kBufferSize]; int dropCount = 0; }; JavaVM* const mVm; jweak mObserverWeak; sp<MessageQueue> mMessageQueue; sp<NotifyHandler> mMessageHandler; Message mMessage; int mNextFree = 0; int mNextInQueue = 0; FrameMetricsNotification mRingBuffer[kRingSize]; int mDroppedReports = 0; }; void NotifyHandler::handleMessage(const Message& message) { JNIEnv* env = getenv(mVm); jobject target = env->NewLocalRef(mObserver->getObserverReference()); if (target != nullptr) { jlongArray javaBuffer = get_metrics_buffer(env, target); int dropCount = 0; while (mObserver->getNextBuffer(env, javaBuffer, &dropCount)) { env->CallVoidMethod(target, gFrameMetricsObserverClassInfo.callback, dropCount); } env->DeleteLocalRef(target); } mObserver->decStrong(nullptr); } static void android_view_ThreadedRenderer_rotateProcessStatsBuffer(JNIEnv* env, jobject clazz) { RenderProxy::rotateProcessStatsBuffer(); } Loading Loading @@ -734,7 +590,7 @@ static jlong android_view_ThreadedRenderer_addFrameMetricsObserver(JNIEnv* env, renderthread::RenderProxy* renderProxy = reinterpret_cast<renderthread::RenderProxy*>(proxyPtr); FrameMetricsObserver* observer = new ObserverProxy(vm, fso); FrameMetricsObserver* observer = new FrameMetricsObserverProxy(vm, fso); renderProxy->addFrameMetricsObserver(observer); return reinterpret_cast<jlong>(observer); } Loading Loading @@ -853,17 +709,6 @@ static void attachRenderThreadToJvm(const char* name) { int register_android_view_ThreadedRenderer(JNIEnv* env) { env->GetJavaVM(&mJvm); RenderThread::setOnStartHook(&attachRenderThreadToJvm); jclass observerClass = FindClassOrDie(env, "android/view/FrameMetricsObserver"); gFrameMetricsObserverClassInfo.frameMetrics = GetFieldIDOrDie( env, observerClass, "mFrameMetrics", "Landroid/view/FrameMetrics;"); gFrameMetricsObserverClassInfo.messageQueue = GetFieldIDOrDie( env, observerClass, "mMessageQueue", "Landroid/os/MessageQueue;"); gFrameMetricsObserverClassInfo.callback = GetMethodIDOrDie( env, observerClass, "notifyDataAvailable", "(I)V"); jclass metricsClass = FindClassOrDie(env, "android/view/FrameMetrics"); gFrameMetricsObserverClassInfo.timingDataBuffer = GetFieldIDOrDie( env, metricsClass, "mTimingData", "[J"); jclass hardwareRenderer = FindClassOrDie(env, "android/graphics/HardwareRenderer"); Loading Loading
core/jni/Android.bp +1 −0 Original line number Diff line number Diff line Loading @@ -153,6 +153,7 @@ cc_library_shared { "android_view_InputEventReceiver.cpp", "android_view_InputEventSender.cpp", "android_view_InputQueue.cpp", "android_view_FrameMetricsObserver.cpp", "android_view_KeyCharacterMap.cpp", "android_view_KeyEvent.cpp", "android_view_MotionEvent.cpp", Loading
core/jni/AndroidRuntime.cpp +2 −0 Original line number Diff line number Diff line Loading @@ -158,6 +158,7 @@ extern int register_android_graphics_text_MeasuredText(JNIEnv* env); extern int register_android_graphics_text_LineBreaker(JNIEnv *env); extern int register_android_view_DisplayEventReceiver(JNIEnv* env); extern int register_android_view_DisplayListCanvas(JNIEnv* env); extern int register_android_view_FrameMetricsObserver(JNIEnv* env); extern int register_android_view_InputApplicationHandle(JNIEnv* env); extern int register_android_view_InputWindowHandle(JNIEnv* env); extern int register_android_view_TextureLayer(JNIEnv* env); Loading Loading @@ -1464,6 +1465,7 @@ static const RegJNIRec gRegJNI[] = { REG_JNI(register_android_view_RenderNode), REG_JNI(register_android_view_RenderNodeAnimator), REG_JNI(register_android_view_DisplayListCanvas), REG_JNI(register_android_view_FrameMetricsObserver), REG_JNI(register_android_view_InputApplicationHandle), REG_JNI(register_android_view_InputWindowHandle), REG_JNI(register_android_view_TextureLayer), Loading
core/jni/android_view_FrameMetricsObserver.cpp 0 → 100644 +149 −0 Original line number Diff line number Diff line /* * Copyright (C) 2019 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. */ #include "android_view_FrameMetricsObserver.h" namespace android { struct { jfieldID frameMetrics; jfieldID timingDataBuffer; jfieldID messageQueue; jmethodID callback; } gFrameMetricsObserverClassInfo; static JNIEnv* getenv(JavaVM* vm) { JNIEnv* env; if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) { LOG_ALWAYS_FATAL("Failed to get JNIEnv for JavaVM: %p", vm); } return env; } static jlongArray get_metrics_buffer(JNIEnv* env, jobject observer) { jobject frameMetrics = env->GetObjectField( observer, gFrameMetricsObserverClassInfo.frameMetrics); LOG_ALWAYS_FATAL_IF(frameMetrics == nullptr, "unable to retrieve data sink object"); jobject buffer = env->GetObjectField( frameMetrics, gFrameMetricsObserverClassInfo.timingDataBuffer); LOG_ALWAYS_FATAL_IF(buffer == nullptr, "unable to retrieve data sink buffer"); return reinterpret_cast<jlongArray>(buffer); } class NotifyHandler : public MessageHandler { public: NotifyHandler(JavaVM* vm, FrameMetricsObserverProxy* observer) : mVm(vm), mObserver(observer) {} virtual void handleMessage(const Message& message); private: JavaVM* const mVm; FrameMetricsObserverProxy* const mObserver; }; void NotifyHandler::handleMessage(const Message& message) { JNIEnv* env = getenv(mVm); jobject target = env->NewLocalRef(mObserver->getObserverReference()); if (target != nullptr) { jlongArray javaBuffer = get_metrics_buffer(env, target); int dropCount = 0; while (mObserver->getNextBuffer(env, javaBuffer, &dropCount)) { env->CallVoidMethod(target, gFrameMetricsObserverClassInfo.callback, dropCount); } env->DeleteLocalRef(target); } mObserver->decStrong(nullptr); } FrameMetricsObserverProxy::FrameMetricsObserverProxy(JavaVM *vm, jobject observer) : mVm(vm) { JNIEnv* env = getenv(mVm); mObserverWeak = env->NewWeakGlobalRef(observer); LOG_ALWAYS_FATAL_IF(mObserverWeak == nullptr, "unable to create frame stats observer reference"); jlongArray buffer = get_metrics_buffer(env, observer); jsize bufferSize = env->GetArrayLength(reinterpret_cast<jarray>(buffer)); LOG_ALWAYS_FATAL_IF(bufferSize != kBufferSize, "Mismatched Java/Native FrameMetrics data format."); jobject messageQueueLocal = env->GetObjectField( observer, gFrameMetricsObserverClassInfo.messageQueue); mMessageQueue = android_os_MessageQueue_getMessageQueue(env, messageQueueLocal); LOG_ALWAYS_FATAL_IF(mMessageQueue == nullptr, "message queue not available"); mMessageHandler = new NotifyHandler(mVm, this); LOG_ALWAYS_FATAL_IF(mMessageHandler == nullptr, "OOM: unable to allocate NotifyHandler"); } FrameMetricsObserverProxy::~FrameMetricsObserverProxy() { JNIEnv* env = getenv(mVm); env->DeleteWeakGlobalRef(mObserverWeak); } bool FrameMetricsObserverProxy::getNextBuffer(JNIEnv* env, jlongArray sink, int* dropCount) { FrameMetricsNotification& elem = mRingBuffer[mNextInQueue]; if (elem.hasData.load()) { env->SetLongArrayRegion(sink, 0, kBufferSize, elem.buffer); *dropCount = elem.dropCount; mNextInQueue = (mNextInQueue + 1) % kRingSize; elem.hasData = false; return true; } return false; } void FrameMetricsObserverProxy::notify(const int64_t* stats) { FrameMetricsNotification& elem = mRingBuffer[mNextFree]; if (!elem.hasData.load()) { memcpy(elem.buffer, stats, kBufferSize * sizeof(stats[0])); elem.dropCount = mDroppedReports; mDroppedReports = 0; incStrong(nullptr); mNextFree = (mNextFree + 1) % kRingSize; elem.hasData = true; mMessageQueue->getLooper()->sendMessage(mMessageHandler, mMessage); } else { mDroppedReports++; } } int register_android_view_FrameMetricsObserver(JNIEnv* env) { jclass observerClass = FindClassOrDie(env, "android/view/FrameMetricsObserver"); gFrameMetricsObserverClassInfo.frameMetrics = GetFieldIDOrDie( env, observerClass, "mFrameMetrics", "Landroid/view/FrameMetrics;"); gFrameMetricsObserverClassInfo.messageQueue = GetFieldIDOrDie( env, observerClass, "mMessageQueue", "Landroid/os/MessageQueue;"); gFrameMetricsObserverClassInfo.callback = GetMethodIDOrDie( env, observerClass, "notifyDataAvailable", "(I)V"); jclass metricsClass = FindClassOrDie(env, "android/view/FrameMetrics"); gFrameMetricsObserverClassInfo.timingDataBuffer = GetFieldIDOrDie( env, metricsClass, "mTimingData", "[J"); return JNI_OK; } } // namespace android No newline at end of file
core/jni/android_view_FrameMetricsObserver.h 0 → 100644 +71 −0 Original line number Diff line number Diff line /* * Copyright (C) 2019 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. */ #include "jni.h" #include "core_jni_helpers.h" #include "android_os_MessageQueue.h" #include <FrameInfo.h> #include <FrameMetricsObserver.h> namespace android { /* * Implements JNI layer for hwui frame metrics reporting. */ class FrameMetricsObserverProxy : public uirenderer::FrameMetricsObserver { public: FrameMetricsObserverProxy(JavaVM *vm, jobject observer); ~FrameMetricsObserverProxy(); jweak getObserverReference() { return mObserverWeak; } bool getNextBuffer(JNIEnv* env, jlongArray sink, int* dropCount); virtual void notify(const int64_t* stats); private: static const int kBufferSize = static_cast<int>(uirenderer::FrameInfoIndex::NumIndexes); static constexpr int kRingSize = 3; class FrameMetricsNotification { public: FrameMetricsNotification() : hasData(false) {} std::atomic_bool hasData; int64_t buffer[kBufferSize]; int dropCount = 0; }; JavaVM* const mVm; jweak mObserverWeak; sp<MessageQueue> mMessageQueue; sp<MessageHandler> mMessageHandler; Message mMessage; int mNextFree = 0; int mNextInQueue = 0; FrameMetricsNotification mRingBuffer[kRingSize]; int mDroppedReports = 0; }; } // namespace android
core/jni/android_view_ThreadedRenderer.cpp +3 −158 Original line number Diff line number Diff line Loading @@ -30,6 +30,8 @@ #include <gui/BufferQueue.h> #include <gui/Surface.h> #include "android_view_FrameMetricsObserver.h" #include <private/EGL/cache.h> #include <utils/RefBase.h> Loading @@ -39,10 +41,7 @@ #include <android_runtime/android_view_Surface.h> #include <system/window.h> #include "android_os_MessageQueue.h" #include <FrameInfo.h> #include <FrameMetricsObserver.h> #include <IContextFactory.h> #include <Picture.h> #include <Properties.h> Loading @@ -59,13 +58,6 @@ namespace android { using namespace android::uirenderer; using namespace android::uirenderer::renderthread; struct { jfieldID frameMetrics; jfieldID timingDataBuffer; jfieldID messageQueue; jmethodID callback; } gFrameMetricsObserverClassInfo; struct { jclass clazz; jmethodID invokePictureCapturedCallback; Loading Loading @@ -133,142 +125,6 @@ private: } }; class ObserverProxy; class NotifyHandler : public MessageHandler { public: NotifyHandler(JavaVM* vm, ObserverProxy* observer) : mVm(vm), mObserver(observer) {} virtual void handleMessage(const Message& message); private: JavaVM* const mVm; ObserverProxy* const mObserver; }; static jlongArray get_metrics_buffer(JNIEnv* env, jobject observer) { jobject frameMetrics = env->GetObjectField( observer, gFrameMetricsObserverClassInfo.frameMetrics); LOG_ALWAYS_FATAL_IF(frameMetrics == nullptr, "unable to retrieve data sink object"); jobject buffer = env->GetObjectField( frameMetrics, gFrameMetricsObserverClassInfo.timingDataBuffer); LOG_ALWAYS_FATAL_IF(buffer == nullptr, "unable to retrieve data sink buffer"); return reinterpret_cast<jlongArray>(buffer); } /* * Implements JNI layer for hwui frame metrics reporting. */ class ObserverProxy : public FrameMetricsObserver { public: ObserverProxy(JavaVM *vm, jobject observer) : mVm(vm) { JNIEnv* env = getenv(mVm); mObserverWeak = env->NewWeakGlobalRef(observer); LOG_ALWAYS_FATAL_IF(mObserverWeak == nullptr, "unable to create frame stats observer reference"); jlongArray buffer = get_metrics_buffer(env, observer); jsize bufferSize = env->GetArrayLength(reinterpret_cast<jarray>(buffer)); LOG_ALWAYS_FATAL_IF(bufferSize != kBufferSize, "Mismatched Java/Native FrameMetrics data format."); jobject messageQueueLocal = env->GetObjectField( observer, gFrameMetricsObserverClassInfo.messageQueue); mMessageQueue = android_os_MessageQueue_getMessageQueue(env, messageQueueLocal); LOG_ALWAYS_FATAL_IF(mMessageQueue == nullptr, "message queue not available"); mMessageHandler = new NotifyHandler(mVm, this); LOG_ALWAYS_FATAL_IF(mMessageHandler == nullptr, "OOM: unable to allocate NotifyHandler"); } ~ObserverProxy() { JNIEnv* env = getenv(mVm); env->DeleteWeakGlobalRef(mObserverWeak); } jweak getObserverReference() { return mObserverWeak; } bool getNextBuffer(JNIEnv* env, jlongArray sink, int* dropCount) { FrameMetricsNotification& elem = mRingBuffer[mNextInQueue]; if (elem.hasData.load()) { env->SetLongArrayRegion(sink, 0, kBufferSize, elem.buffer); *dropCount = elem.dropCount; mNextInQueue = (mNextInQueue + 1) % kRingSize; elem.hasData = false; return true; } return false; } virtual void notify(const int64_t* stats) { FrameMetricsNotification& elem = mRingBuffer[mNextFree]; if (!elem.hasData.load()) { memcpy(elem.buffer, stats, kBufferSize * sizeof(stats[0])); elem.dropCount = mDroppedReports; mDroppedReports = 0; incStrong(nullptr); mNextFree = (mNextFree + 1) % kRingSize; elem.hasData = true; mMessageQueue->getLooper()->sendMessage(mMessageHandler, mMessage); } else { mDroppedReports++; } } private: static const int kBufferSize = static_cast<int>(FrameInfoIndex::NumIndexes); static constexpr int kRingSize = 3; class FrameMetricsNotification { public: FrameMetricsNotification() : hasData(false) {} std::atomic_bool hasData; int64_t buffer[kBufferSize]; int dropCount = 0; }; JavaVM* const mVm; jweak mObserverWeak; sp<MessageQueue> mMessageQueue; sp<NotifyHandler> mMessageHandler; Message mMessage; int mNextFree = 0; int mNextInQueue = 0; FrameMetricsNotification mRingBuffer[kRingSize]; int mDroppedReports = 0; }; void NotifyHandler::handleMessage(const Message& message) { JNIEnv* env = getenv(mVm); jobject target = env->NewLocalRef(mObserver->getObserverReference()); if (target != nullptr) { jlongArray javaBuffer = get_metrics_buffer(env, target); int dropCount = 0; while (mObserver->getNextBuffer(env, javaBuffer, &dropCount)) { env->CallVoidMethod(target, gFrameMetricsObserverClassInfo.callback, dropCount); } env->DeleteLocalRef(target); } mObserver->decStrong(nullptr); } static void android_view_ThreadedRenderer_rotateProcessStatsBuffer(JNIEnv* env, jobject clazz) { RenderProxy::rotateProcessStatsBuffer(); } Loading Loading @@ -734,7 +590,7 @@ static jlong android_view_ThreadedRenderer_addFrameMetricsObserver(JNIEnv* env, renderthread::RenderProxy* renderProxy = reinterpret_cast<renderthread::RenderProxy*>(proxyPtr); FrameMetricsObserver* observer = new ObserverProxy(vm, fso); FrameMetricsObserver* observer = new FrameMetricsObserverProxy(vm, fso); renderProxy->addFrameMetricsObserver(observer); return reinterpret_cast<jlong>(observer); } Loading Loading @@ -853,17 +709,6 @@ static void attachRenderThreadToJvm(const char* name) { int register_android_view_ThreadedRenderer(JNIEnv* env) { env->GetJavaVM(&mJvm); RenderThread::setOnStartHook(&attachRenderThreadToJvm); jclass observerClass = FindClassOrDie(env, "android/view/FrameMetricsObserver"); gFrameMetricsObserverClassInfo.frameMetrics = GetFieldIDOrDie( env, observerClass, "mFrameMetrics", "Landroid/view/FrameMetrics;"); gFrameMetricsObserverClassInfo.messageQueue = GetFieldIDOrDie( env, observerClass, "mMessageQueue", "Landroid/os/MessageQueue;"); gFrameMetricsObserverClassInfo.callback = GetMethodIDOrDie( env, observerClass, "notifyDataAvailable", "(I)V"); jclass metricsClass = FindClassOrDie(env, "android/view/FrameMetrics"); gFrameMetricsObserverClassInfo.timingDataBuffer = GetFieldIDOrDie( env, metricsClass, "mTimingData", "[J"); jclass hardwareRenderer = FindClassOrDie(env, "android/graphics/HardwareRenderer"); Loading