Loading core/java/android/view/FrameMetricsObserver.java +25 −36 Original line number Diff line number Diff line Loading @@ -17,11 +17,8 @@ package android.view; import android.annotation.NonNull; import android.annotation.UnsupportedAppUsage; import android.os.Looper; import android.os.MessageQueue; import com.android.internal.util.VirtualRefBasePtr; import android.graphics.HardwareRendererObserver; import android.os.Handler; import java.lang.ref.WeakReference; Loading @@ -31,47 +28,39 @@ import java.lang.ref.WeakReference; * * @hide */ public class FrameMetricsObserver { @UnsupportedAppUsage private MessageQueue mMessageQueue; private WeakReference<Window> mWindow; @UnsupportedAppUsage private FrameMetrics mFrameMetrics; /* pacage */ Window.OnFrameMetricsAvailableListener mListener; /** @hide */ public VirtualRefBasePtr mNative; public class FrameMetricsObserver implements HardwareRendererObserver.OnFrameMetricsAvailableListener { private final WeakReference<Window> mWindow; private final FrameMetrics mFrameMetrics; private final HardwareRendererObserver mObserver; /*package*/ final Window.OnFrameMetricsAvailableListener mListener; /** * Creates a FrameMetricsObserver * * @param looper the looper to use when invoking callbacks * @param handler the Handler to use when invoking callbacks */ FrameMetricsObserver(@NonNull Window window, @NonNull Looper looper, FrameMetricsObserver(@NonNull Window window, @NonNull Handler handler, @NonNull Window.OnFrameMetricsAvailableListener listener) { if (looper == null) { throw new NullPointerException("looper cannot be null"); } mMessageQueue = looper.getQueue(); if (mMessageQueue == null) { throw new IllegalStateException("invalid looper, null message queue\n"); } mFrameMetrics = new FrameMetrics(); mWindow = new WeakReference<>(window); mListener = listener; mFrameMetrics = new FrameMetrics(); mObserver = new HardwareRendererObserver(this, mFrameMetrics.mTimingData, handler); } // Called by native on the provided Handler @SuppressWarnings("unused") @UnsupportedAppUsage private void notifyDataAvailable(int dropCount) { final Window window = mWindow.get(); if (window != null) { mListener.onFrameMetricsAvailable(window, mFrameMetrics, dropCount); /** * Implementation of OnFrameMetricsAvailableListener * @param dropCountSinceLastInvocation the number of reports dropped since the last time * @Override */ public void onFrameMetricsAvailable(int dropCountSinceLastInvocation) { if (mWindow.get() != null) { mListener.onFrameMetricsAvailable(mWindow.get(), mFrameMetrics, dropCountSinceLastInvocation); } } /*package*/ HardwareRendererObserver getRendererObserver() { return mObserver; } } core/java/android/view/View.java +5 −7 Original line number Diff line number Diff line Loading @@ -7147,10 +7147,9 @@ public class View implements Drawable.Callback, KeyEvent.Callback, mFrameMetricsObservers = new ArrayList<>(); } FrameMetricsObserver fmo = new FrameMetricsObserver(window, handler.getLooper(), listener); FrameMetricsObserver fmo = new FrameMetricsObserver(window, handler, listener); mFrameMetricsObservers.add(fmo); mAttachInfo.mThreadedRenderer.addFrameMetricsObserver(fmo); mAttachInfo.mThreadedRenderer.addObserver(fmo.getRendererObserver()); } else { Log.w(VIEW_LOG_TAG, "View not hardware-accelerated. Unable to observe frame stats"); } Loading @@ -7159,8 +7158,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, mFrameMetricsObservers = new ArrayList<>(); } FrameMetricsObserver fmo = new FrameMetricsObserver(window, handler.getLooper(), listener); FrameMetricsObserver fmo = new FrameMetricsObserver(window, handler, listener); mFrameMetricsObservers.add(fmo); } } Loading @@ -7182,7 +7180,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, if (mFrameMetricsObservers != null) { mFrameMetricsObservers.remove(fmo); if (renderer != null) { renderer.removeFrameMetricsObserver(fmo); renderer.removeObserver(fmo.getRendererObserver()); } } } Loading @@ -7192,7 +7190,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, ThreadedRenderer renderer = getThreadedRenderer(); if (renderer != null) { for (FrameMetricsObserver fmo : mFrameMetricsObservers) { renderer.addFrameMetricsObserver(fmo); renderer.addObserver(fmo.getRendererObserver()); } } else { Log.w(VIEW_LOG_TAG, "View not hardware-accelerated. Unable to observe frame stats"); core/jni/Android.bp +1 −1 Original line number Diff line number Diff line Loading @@ -110,7 +110,6 @@ 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 Loading @@ -351,6 +350,7 @@ cc_library_static { "android_graphics_ColorSpace.cpp", "android_graphics_drawable_AnimatedVectorDrawable.cpp", "android_graphics_drawable_VectorDrawable.cpp", "android_graphics_HardwareRendererObserver.cpp", "android_graphics_Picture.cpp", "android_nio_utils.cpp", "android_view_DisplayListCanvas.cpp", Loading core/jni/android/graphics/apex/jni_runtime.cpp +2 −2 Original line number Diff line number Diff line Loading @@ -52,6 +52,7 @@ extern int register_android_graphics_ColorFilter(JNIEnv* env); extern int register_android_graphics_ColorSpace(JNIEnv* env); extern int register_android_graphics_DrawFilter(JNIEnv* env); extern int register_android_graphics_FontFamily(JNIEnv* env); extern int register_android_graphics_HardwareRendererObserver(JNIEnv* env); extern int register_android_graphics_Matrix(JNIEnv* env); extern int register_android_graphics_Paint(JNIEnv* env); extern int register_android_graphics_Path(JNIEnv* env); Loading @@ -71,7 +72,6 @@ extern int register_android_graphics_text_LineBreaker(JNIEnv *env); extern int register_android_util_PathParser(JNIEnv* env); extern int register_android_view_DisplayListCanvas(JNIEnv* env); extern int register_android_view_FrameMetricsObserver(JNIEnv* env); extern int register_android_view_RenderNode(JNIEnv* env); extern int register_android_view_TextureLayer(JNIEnv* env); extern int register_android_view_ThreadedRenderer(JNIEnv* env); Loading Loading @@ -105,6 +105,7 @@ static const RegJNIRec gRegJNI[] = { REG_JNI(register_android_graphics_ColorFilter), REG_JNI(register_android_graphics_DrawFilter), REG_JNI(register_android_graphics_FontFamily), REG_JNI(register_android_graphics_HardwareRendererObserver), REG_JNI(register_android_graphics_ImageDecoder), REG_JNI(register_android_graphics_drawable_AnimatedImageDrawable), REG_JNI(register_android_graphics_Interpolator), Loading Loading @@ -135,7 +136,6 @@ static const RegJNIRec gRegJNI[] = { REG_JNI(register_android_util_PathParser), REG_JNI(register_android_view_RenderNode), REG_JNI(register_android_view_DisplayListCanvas), REG_JNI(register_android_view_FrameMetricsObserver), REG_JNI(register_android_view_TextureLayer), REG_JNI(register_android_view_ThreadedRenderer), }; Loading core/jni/android_view_FrameMetricsObserver.cpp→core/jni/android_graphics_HardwareRendererObserver.cpp +130 −0 Original line number Diff line number Diff line Loading @@ -14,16 +14,18 @@ * limitations under the License. */ #include "android_view_FrameMetricsObserver.h" #include "android_graphics_HardwareRendererObserver.h" #include "core_jni_helpers.h" #include "nativehelper/jni_macros.h" #include <array> namespace android { struct { jfieldID frameMetrics; jfieldID timingDataBuffer; jfieldID messageQueue; jmethodID callback; } gFrameMetricsObserverClassInfo; } gHardwareRendererObserverClassInfo; static JNIEnv* getenv(JavaVM* vm) { JNIEnv* env; Loading @@ -33,76 +35,25 @@ static JNIEnv* getenv(JavaVM* 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); HardwareRendererObserver::HardwareRendererObserver(JavaVM *vm, jobject observer) : mVm(vm) { mObserverWeak = getenv(mVm)->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() { HardwareRendererObserver::~HardwareRendererObserver() { JNIEnv* env = getenv(mVm); env->DeleteWeakGlobalRef(mObserverWeak); } bool FrameMetricsObserverProxy::getNextBuffer(JNIEnv* env, jlongArray sink, int* dropCount) { FrameMetricsNotification& elem = mRingBuffer[mNextInQueue]; bool HardwareRendererObserver::getNextBuffer(JNIEnv* env, jlongArray metrics, int* dropCount) { jsize bufferSize = env->GetArrayLength(reinterpret_cast<jarray>(metrics)); LOG_ALWAYS_FATAL_IF(bufferSize != HardwareRendererObserver::kBufferSize, "Mismatched Java/Native FrameMetrics data format."); FrameMetricsNotification& elem = mRingBuffer[mNextInQueue]; if (elem.hasData.load()) { env->SetLongArrayRegion(sink, 0, kBufferSize, elem.buffer); env->SetLongArrayRegion(metrics, 0, kBufferSize, elem.buffer); *dropCount = elem.dropCount; mNextInQueue = (mNextInQueue + 1) % kRingSize; elem.hasData = false; Loading @@ -112,7 +63,7 @@ bool FrameMetricsObserverProxy::getNextBuffer(JNIEnv* env, jlongArray sink, int* return false; } void FrameMetricsObserverProxy::notify(const int64_t* stats) { void HardwareRendererObserver::notify(const int64_t* stats) { FrameMetricsNotification& elem = mRingBuffer[mNextFree]; if (!elem.hasData.load()) { Loading @@ -120,30 +71,60 @@ void FrameMetricsObserverProxy::notify(const int64_t* stats) { elem.dropCount = mDroppedReports; mDroppedReports = 0; incStrong(nullptr); mNextFree = (mNextFree + 1) % kRingSize; elem.hasData = true; mMessageQueue->getLooper()->sendMessage(mMessageHandler, mMessage); JNIEnv* env = getenv(mVm); jobject target = env->NewLocalRef(mObserverWeak); if (target != nullptr) { env->CallVoidMethod(target, gHardwareRendererObserverClassInfo.callback); env->DeleteLocalRef(target); } } 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; static jlong android_graphics_HardwareRendererObserver_createObserver(JNIEnv* env, jobject observerObj) { JavaVM* vm = nullptr; if (env->GetJavaVM(&vm) != JNI_OK) { LOG_ALWAYS_FATAL("Unable to get Java VM"); return 0; } HardwareRendererObserver* observer = new HardwareRendererObserver(vm, observerObj); return reinterpret_cast<jlong>(observer); } static jint android_graphics_HardwareRendererObserver_getNextBuffer(JNIEnv* env, jobject, jlong observerPtr, jlongArray metrics) { HardwareRendererObserver* observer = reinterpret_cast<HardwareRendererObserver*>(observerPtr); int dropCount = 0; if (observer->getNextBuffer(env, metrics, &dropCount)) { return dropCount; } else { return -1; } } static const std::array gMethods = { MAKE_JNI_NATIVE_METHOD("nCreateObserver", "()J", android_graphics_HardwareRendererObserver_createObserver), MAKE_JNI_NATIVE_METHOD("nGetNextBuffer", "(J[J)I", android_graphics_HardwareRendererObserver_getNextBuffer), }; int register_android_graphics_HardwareRendererObserver(JNIEnv* env) { jclass observerClass = FindClassOrDie(env, "android/graphics/HardwareRendererObserver"); gHardwareRendererObserverClassInfo.callback = GetMethodIDOrDie(env, observerClass, "notifyDataAvailable", "()V"); return RegisterMethodsOrDie(env, "android/graphics/HardwareRendererObserver", gMethods.data(), gMethods.size()); } } // namespace android No newline at end of file Loading
core/java/android/view/FrameMetricsObserver.java +25 −36 Original line number Diff line number Diff line Loading @@ -17,11 +17,8 @@ package android.view; import android.annotation.NonNull; import android.annotation.UnsupportedAppUsage; import android.os.Looper; import android.os.MessageQueue; import com.android.internal.util.VirtualRefBasePtr; import android.graphics.HardwareRendererObserver; import android.os.Handler; import java.lang.ref.WeakReference; Loading @@ -31,47 +28,39 @@ import java.lang.ref.WeakReference; * * @hide */ public class FrameMetricsObserver { @UnsupportedAppUsage private MessageQueue mMessageQueue; private WeakReference<Window> mWindow; @UnsupportedAppUsage private FrameMetrics mFrameMetrics; /* pacage */ Window.OnFrameMetricsAvailableListener mListener; /** @hide */ public VirtualRefBasePtr mNative; public class FrameMetricsObserver implements HardwareRendererObserver.OnFrameMetricsAvailableListener { private final WeakReference<Window> mWindow; private final FrameMetrics mFrameMetrics; private final HardwareRendererObserver mObserver; /*package*/ final Window.OnFrameMetricsAvailableListener mListener; /** * Creates a FrameMetricsObserver * * @param looper the looper to use when invoking callbacks * @param handler the Handler to use when invoking callbacks */ FrameMetricsObserver(@NonNull Window window, @NonNull Looper looper, FrameMetricsObserver(@NonNull Window window, @NonNull Handler handler, @NonNull Window.OnFrameMetricsAvailableListener listener) { if (looper == null) { throw new NullPointerException("looper cannot be null"); } mMessageQueue = looper.getQueue(); if (mMessageQueue == null) { throw new IllegalStateException("invalid looper, null message queue\n"); } mFrameMetrics = new FrameMetrics(); mWindow = new WeakReference<>(window); mListener = listener; mFrameMetrics = new FrameMetrics(); mObserver = new HardwareRendererObserver(this, mFrameMetrics.mTimingData, handler); } // Called by native on the provided Handler @SuppressWarnings("unused") @UnsupportedAppUsage private void notifyDataAvailable(int dropCount) { final Window window = mWindow.get(); if (window != null) { mListener.onFrameMetricsAvailable(window, mFrameMetrics, dropCount); /** * Implementation of OnFrameMetricsAvailableListener * @param dropCountSinceLastInvocation the number of reports dropped since the last time * @Override */ public void onFrameMetricsAvailable(int dropCountSinceLastInvocation) { if (mWindow.get() != null) { mListener.onFrameMetricsAvailable(mWindow.get(), mFrameMetrics, dropCountSinceLastInvocation); } } /*package*/ HardwareRendererObserver getRendererObserver() { return mObserver; } }
core/java/android/view/View.java +5 −7 Original line number Diff line number Diff line Loading @@ -7147,10 +7147,9 @@ public class View implements Drawable.Callback, KeyEvent.Callback, mFrameMetricsObservers = new ArrayList<>(); } FrameMetricsObserver fmo = new FrameMetricsObserver(window, handler.getLooper(), listener); FrameMetricsObserver fmo = new FrameMetricsObserver(window, handler, listener); mFrameMetricsObservers.add(fmo); mAttachInfo.mThreadedRenderer.addFrameMetricsObserver(fmo); mAttachInfo.mThreadedRenderer.addObserver(fmo.getRendererObserver()); } else { Log.w(VIEW_LOG_TAG, "View not hardware-accelerated. Unable to observe frame stats"); } Loading @@ -7159,8 +7158,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, mFrameMetricsObservers = new ArrayList<>(); } FrameMetricsObserver fmo = new FrameMetricsObserver(window, handler.getLooper(), listener); FrameMetricsObserver fmo = new FrameMetricsObserver(window, handler, listener); mFrameMetricsObservers.add(fmo); } } Loading @@ -7182,7 +7180,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, if (mFrameMetricsObservers != null) { mFrameMetricsObservers.remove(fmo); if (renderer != null) { renderer.removeFrameMetricsObserver(fmo); renderer.removeObserver(fmo.getRendererObserver()); } } } Loading @@ -7192,7 +7190,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, ThreadedRenderer renderer = getThreadedRenderer(); if (renderer != null) { for (FrameMetricsObserver fmo : mFrameMetricsObservers) { renderer.addFrameMetricsObserver(fmo); renderer.addObserver(fmo.getRendererObserver()); } } else { Log.w(VIEW_LOG_TAG, "View not hardware-accelerated. Unable to observe frame stats");
core/jni/Android.bp +1 −1 Original line number Diff line number Diff line Loading @@ -110,7 +110,6 @@ 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 Loading @@ -351,6 +350,7 @@ cc_library_static { "android_graphics_ColorSpace.cpp", "android_graphics_drawable_AnimatedVectorDrawable.cpp", "android_graphics_drawable_VectorDrawable.cpp", "android_graphics_HardwareRendererObserver.cpp", "android_graphics_Picture.cpp", "android_nio_utils.cpp", "android_view_DisplayListCanvas.cpp", Loading
core/jni/android/graphics/apex/jni_runtime.cpp +2 −2 Original line number Diff line number Diff line Loading @@ -52,6 +52,7 @@ extern int register_android_graphics_ColorFilter(JNIEnv* env); extern int register_android_graphics_ColorSpace(JNIEnv* env); extern int register_android_graphics_DrawFilter(JNIEnv* env); extern int register_android_graphics_FontFamily(JNIEnv* env); extern int register_android_graphics_HardwareRendererObserver(JNIEnv* env); extern int register_android_graphics_Matrix(JNIEnv* env); extern int register_android_graphics_Paint(JNIEnv* env); extern int register_android_graphics_Path(JNIEnv* env); Loading @@ -71,7 +72,6 @@ extern int register_android_graphics_text_LineBreaker(JNIEnv *env); extern int register_android_util_PathParser(JNIEnv* env); extern int register_android_view_DisplayListCanvas(JNIEnv* env); extern int register_android_view_FrameMetricsObserver(JNIEnv* env); extern int register_android_view_RenderNode(JNIEnv* env); extern int register_android_view_TextureLayer(JNIEnv* env); extern int register_android_view_ThreadedRenderer(JNIEnv* env); Loading Loading @@ -105,6 +105,7 @@ static const RegJNIRec gRegJNI[] = { REG_JNI(register_android_graphics_ColorFilter), REG_JNI(register_android_graphics_DrawFilter), REG_JNI(register_android_graphics_FontFamily), REG_JNI(register_android_graphics_HardwareRendererObserver), REG_JNI(register_android_graphics_ImageDecoder), REG_JNI(register_android_graphics_drawable_AnimatedImageDrawable), REG_JNI(register_android_graphics_Interpolator), Loading Loading @@ -135,7 +136,6 @@ static const RegJNIRec gRegJNI[] = { REG_JNI(register_android_util_PathParser), REG_JNI(register_android_view_RenderNode), REG_JNI(register_android_view_DisplayListCanvas), REG_JNI(register_android_view_FrameMetricsObserver), REG_JNI(register_android_view_TextureLayer), REG_JNI(register_android_view_ThreadedRenderer), }; Loading
core/jni/android_view_FrameMetricsObserver.cpp→core/jni/android_graphics_HardwareRendererObserver.cpp +130 −0 Original line number Diff line number Diff line Loading @@ -14,16 +14,18 @@ * limitations under the License. */ #include "android_view_FrameMetricsObserver.h" #include "android_graphics_HardwareRendererObserver.h" #include "core_jni_helpers.h" #include "nativehelper/jni_macros.h" #include <array> namespace android { struct { jfieldID frameMetrics; jfieldID timingDataBuffer; jfieldID messageQueue; jmethodID callback; } gFrameMetricsObserverClassInfo; } gHardwareRendererObserverClassInfo; static JNIEnv* getenv(JavaVM* vm) { JNIEnv* env; Loading @@ -33,76 +35,25 @@ static JNIEnv* getenv(JavaVM* 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); HardwareRendererObserver::HardwareRendererObserver(JavaVM *vm, jobject observer) : mVm(vm) { mObserverWeak = getenv(mVm)->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() { HardwareRendererObserver::~HardwareRendererObserver() { JNIEnv* env = getenv(mVm); env->DeleteWeakGlobalRef(mObserverWeak); } bool FrameMetricsObserverProxy::getNextBuffer(JNIEnv* env, jlongArray sink, int* dropCount) { FrameMetricsNotification& elem = mRingBuffer[mNextInQueue]; bool HardwareRendererObserver::getNextBuffer(JNIEnv* env, jlongArray metrics, int* dropCount) { jsize bufferSize = env->GetArrayLength(reinterpret_cast<jarray>(metrics)); LOG_ALWAYS_FATAL_IF(bufferSize != HardwareRendererObserver::kBufferSize, "Mismatched Java/Native FrameMetrics data format."); FrameMetricsNotification& elem = mRingBuffer[mNextInQueue]; if (elem.hasData.load()) { env->SetLongArrayRegion(sink, 0, kBufferSize, elem.buffer); env->SetLongArrayRegion(metrics, 0, kBufferSize, elem.buffer); *dropCount = elem.dropCount; mNextInQueue = (mNextInQueue + 1) % kRingSize; elem.hasData = false; Loading @@ -112,7 +63,7 @@ bool FrameMetricsObserverProxy::getNextBuffer(JNIEnv* env, jlongArray sink, int* return false; } void FrameMetricsObserverProxy::notify(const int64_t* stats) { void HardwareRendererObserver::notify(const int64_t* stats) { FrameMetricsNotification& elem = mRingBuffer[mNextFree]; if (!elem.hasData.load()) { Loading @@ -120,30 +71,60 @@ void FrameMetricsObserverProxy::notify(const int64_t* stats) { elem.dropCount = mDroppedReports; mDroppedReports = 0; incStrong(nullptr); mNextFree = (mNextFree + 1) % kRingSize; elem.hasData = true; mMessageQueue->getLooper()->sendMessage(mMessageHandler, mMessage); JNIEnv* env = getenv(mVm); jobject target = env->NewLocalRef(mObserverWeak); if (target != nullptr) { env->CallVoidMethod(target, gHardwareRendererObserverClassInfo.callback); env->DeleteLocalRef(target); } } 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; static jlong android_graphics_HardwareRendererObserver_createObserver(JNIEnv* env, jobject observerObj) { JavaVM* vm = nullptr; if (env->GetJavaVM(&vm) != JNI_OK) { LOG_ALWAYS_FATAL("Unable to get Java VM"); return 0; } HardwareRendererObserver* observer = new HardwareRendererObserver(vm, observerObj); return reinterpret_cast<jlong>(observer); } static jint android_graphics_HardwareRendererObserver_getNextBuffer(JNIEnv* env, jobject, jlong observerPtr, jlongArray metrics) { HardwareRendererObserver* observer = reinterpret_cast<HardwareRendererObserver*>(observerPtr); int dropCount = 0; if (observer->getNextBuffer(env, metrics, &dropCount)) { return dropCount; } else { return -1; } } static const std::array gMethods = { MAKE_JNI_NATIVE_METHOD("nCreateObserver", "()J", android_graphics_HardwareRendererObserver_createObserver), MAKE_JNI_NATIVE_METHOD("nGetNextBuffer", "(J[J)I", android_graphics_HardwareRendererObserver_getNextBuffer), }; int register_android_graphics_HardwareRendererObserver(JNIEnv* env) { jclass observerClass = FindClassOrDie(env, "android/graphics/HardwareRendererObserver"); gHardwareRendererObserverClassInfo.callback = GetMethodIDOrDie(env, observerClass, "notifyDataAvailable", "()V"); return RegisterMethodsOrDie(env, "android/graphics/HardwareRendererObserver", gMethods.data(), gMethods.size()); } } // namespace android No newline at end of file