Move FrameMetricsObserver logic into UI Module.

Introduce HardwareRendererObserver to isolate the android.graphics
package from the android.view package.  The native code that
interacts with the observer was also moved from libandroid_runtime to
libandroid_graphics to keep it within the confines of the UI Rendering
module.

Bug: 137655431
Test: CtsUiRenderingTestCases
Change-Id: Ibccecbeda0c4d9501d86514a53eb98548233ba6a
This commit is contained in:
Derek Sollenberger
2019-12-09 12:38:59 -05:00
parent 3d559cbdc8
commit c4ef2c702a
11 changed files with 356 additions and 298 deletions

View File

@@ -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;
@@ -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;
}
}

View File

@@ -7146,10 +7146,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");
}
@@ -7158,8 +7157,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);
}
}
@@ -7181,7 +7179,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());
}
}
}
@@ -7191,7 +7189,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");

View File

@@ -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",
@@ -353,6 +352,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",

View File

@@ -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);
@@ -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);
@@ -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),
@@ -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),
};

View File

@@ -0,0 +1,130 @@
/*
* 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_graphics_HardwareRendererObserver.h"
#include "core_jni_helpers.h"
#include "nativehelper/jni_macros.h"
#include <array>
namespace android {
struct {
jmethodID callback;
} gHardwareRendererObserverClassInfo;
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;
}
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");
}
HardwareRendererObserver::~HardwareRendererObserver() {
JNIEnv* env = getenv(mVm);
env->DeleteWeakGlobalRef(mObserverWeak);
}
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(metrics, 0, kBufferSize, elem.buffer);
*dropCount = elem.dropCount;
mNextInQueue = (mNextInQueue + 1) % kRingSize;
elem.hasData = false;
return true;
}
return false;
}
void HardwareRendererObserver::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;
mNextFree = (mNextFree + 1) % kRingSize;
elem.hasData = true;
JNIEnv* env = getenv(mVm);
jobject target = env->NewLocalRef(mObserverWeak);
if (target != nullptr) {
env->CallVoidMethod(target, gHardwareRendererObserverClassInfo.callback);
env->DeleteLocalRef(target);
}
} else {
mDroppedReports++;
}
}
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

View File

@@ -0,0 +1,75 @@
/*
* 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 <FrameInfo.h>
#include <FrameMetricsObserver.h>
namespace android {
/*
* Implements JNI layer for hwui frame metrics reporting.
*/
class HardwareRendererObserver : public uirenderer::FrameMetricsObserver {
public:
HardwareRendererObserver(JavaVM *vm, jobject observer);
~HardwareRendererObserver();
/**
* Retrieves frame metrics for the oldest frame that the renderer has retained. The renderer
* will retain a buffer until it has been retrieved, via this method, or its internal storage
* is exhausted at which point it informs the caller of how many frames it has failed to store
* since the last time this method was invoked.
* @param env java env required to populate the provided buffer array
* @param metrics output parameter that represents the buffer of metrics that is to be filled
* @param dropCount output parameter that is updated to reflect the number of buffers that were
discarded since the last successful invocation of this method.
* @return true if there was data to populate the array and false otherwise. If false then
* neither the metrics buffer or dropCount will be modified.
*/
bool getNextBuffer(JNIEnv* env, jlongArray metrics, int* dropCount);
void notify(const int64_t* stats) override;
private:
static constexpr int kBufferSize = static_cast<int>(uirenderer::FrameInfoIndex::NumIndexes);
static constexpr int kRingSize = 3;
class FrameMetricsNotification {
public:
FrameMetricsNotification() {}
std::atomic_bool hasData = false;
int64_t buffer[kBufferSize];
int dropCount = 0;
private:
// non-copyable
FrameMetricsNotification(const FrameMetricsNotification&) = delete;
FrameMetricsNotification& operator=(const FrameMetricsNotification& ) = delete;
};
JavaVM* const mVm;
jweak mObserverWeak;
int mNextFree = 0;
int mNextInQueue = 0;
FrameMetricsNotification mRingBuffer[kRingSize];
int mDroppedReports = 0;
};
} // namespace android

View File

@@ -1,149 +0,0 @@
/*
* 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

View File

@@ -1,71 +0,0 @@
/*
* 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

View File

@@ -30,7 +30,7 @@
#include <gui/BufferQueue.h>
#include <gui/Surface.h>
#include "android_view_FrameMetricsObserver.h"
#include "android_graphics_HardwareRendererObserver.h"
#include <private/EGL/cache.h>
@@ -580,28 +580,21 @@ static void android_view_ThreadedRenderer_preload(JNIEnv*, jclass) {
}
// ----------------------------------------------------------------------------
// FrameMetricsObserver
// HardwareRendererObserver
// ----------------------------------------------------------------------------
static jlong android_view_ThreadedRenderer_addFrameMetricsObserver(JNIEnv* env,
jclass clazz, jlong proxyPtr, jobject fso) {
JavaVM* vm = nullptr;
if (env->GetJavaVM(&vm) != JNI_OK) {
LOG_ALWAYS_FATAL("Unable to get Java VM");
return 0;
}
static void android_view_ThreadedRenderer_addObserver(JNIEnv* env, jclass clazz,
jlong proxyPtr, jlong observerPtr) {
HardwareRendererObserver* observer = reinterpret_cast<HardwareRendererObserver*>(observerPtr);
renderthread::RenderProxy* renderProxy =
reinterpret_cast<renderthread::RenderProxy*>(proxyPtr);
FrameMetricsObserver* observer = new FrameMetricsObserverProxy(vm, fso);
renderProxy->addFrameMetricsObserver(observer);
return reinterpret_cast<jlong>(observer);
}
static void android_view_ThreadedRenderer_removeFrameMetricsObserver(JNIEnv* env, jclass clazz,
static void android_view_ThreadedRenderer_removeObserver(JNIEnv* env, jclass clazz,
jlong proxyPtr, jlong observerPtr) {
FrameMetricsObserver* observer = reinterpret_cast<FrameMetricsObserver*>(observerPtr);
HardwareRendererObserver* observer = reinterpret_cast<HardwareRendererObserver*>(observerPtr);
renderthread::RenderProxy* renderProxy =
reinterpret_cast<renderthread::RenderProxy*>(proxyPtr);
@@ -675,12 +668,8 @@ static const JNINativeMethod gMethods[] = {
(void*)android_view_ThreadedRenderer_setFrameCallback},
{ "nSetFrameCompleteCallback", "(JLandroid/graphics/HardwareRenderer$FrameCompleteCallback;)V",
(void*)android_view_ThreadedRenderer_setFrameCompleteCallback },
{ "nAddFrameMetricsObserver",
"(JLandroid/view/FrameMetricsObserver;)J",
(void*)android_view_ThreadedRenderer_addFrameMetricsObserver },
{ "nRemoveFrameMetricsObserver",
"(JJ)V",
(void*)android_view_ThreadedRenderer_removeFrameMetricsObserver },
{ "nAddObserver", "(JJ)V", (void*)android_view_ThreadedRenderer_addObserver },
{ "nRemoveObserver", "(JJ)V", (void*)android_view_ThreadedRenderer_removeObserver },
{ "nCopySurfaceInto", "(Landroid/view/Surface;IIIIJ)I",
(void*)android_view_ThreadedRenderer_copySurfaceInto },
{ "nCreateHardwareBitmap", "(JII)Landroid/graphics/Bitmap;",

View File

@@ -28,7 +28,6 @@ import android.os.RemoteException;
import android.os.ServiceManager;
import android.util.Log;
import android.util.TimeUtils;
import android.view.FrameMetricsObserver;
import android.view.IGraphicsStats;
import android.view.IGraphicsStatsCallback;
import android.view.NativeVectorDrawableAnimator;
@@ -38,8 +37,6 @@ import android.view.SurfaceHolder;
import android.view.TextureLayer;
import android.view.animation.AnimationUtils;
import com.android.internal.util.VirtualRefBasePtr;
import java.io.File;
import java.io.FileDescriptor;
import java.lang.annotation.Retention;
@@ -598,9 +595,8 @@ public class HardwareRenderer {
*
* @hide
*/
public void addFrameMetricsObserver(FrameMetricsObserver observer) {
long nativeObserver = nAddFrameMetricsObserver(mNativeProxy, observer);
observer.mNative = new VirtualRefBasePtr(nativeObserver);
public void addObserver(HardwareRendererObserver observer) {
nAddObserver(mNativeProxy, observer.getNativeInstance());
}
/**
@@ -608,9 +604,8 @@ public class HardwareRenderer {
*
* @hide
*/
public void removeFrameMetricsObserver(FrameMetricsObserver observer) {
nRemoveFrameMetricsObserver(mNativeProxy, observer.mNative.get());
observer.mNative = null;
public void removeObserver(HardwareRendererObserver observer) {
nRemoveObserver(mNativeProxy, observer.getNativeInstance());
}
/**
@@ -1170,10 +1165,9 @@ public class HardwareRenderer {
private static native void nSetFrameCompleteCallback(long nativeProxy,
FrameCompleteCallback callback);
private static native long nAddFrameMetricsObserver(long nativeProxy,
FrameMetricsObserver observer);
private static native void nAddObserver(long nativeProxy, long nativeObserver);
private static native void nRemoveFrameMetricsObserver(long nativeProxy, long nativeObserver);
private static native void nRemoveObserver(long nativeProxy, long nativeObserver);
private static native int nCopySurfaceInto(Surface surface,
int srcLeft, int srcTop, int srcRight, int srcBottom, long bitmapHandle);

View File

@@ -0,0 +1,103 @@
/*
* 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.
*/
package android.graphics;
import android.annotation.NonNull;
import android.os.Handler;
import com.android.internal.util.VirtualRefBasePtr;
/**
* Provides streaming access to frame stats information from HardwareRenderer to apps.
*
* @hide
*/
public class HardwareRendererObserver {
private final long[] mFrameMetrics;
private final Handler mHandler;
private final OnFrameMetricsAvailableListener mListener;
private VirtualRefBasePtr mNativePtr;
/**
* Interface for clients that want frame timing information for each frame rendered.
* @hide
*/
public interface OnFrameMetricsAvailableListener {
/**
* Called when information is available for the previously rendered frame.
*
* Reports can be dropped if this callback takes too long to execute, as the report producer
* cannot wait for the consumer to complete.
*
* It is highly recommended that clients copy the metrics array within this method
* and defer additional computation or storage to another thread to avoid unnecessarily
* dropping reports.
*
* @param dropCountSinceLastInvocation the number of reports dropped since the last time
* this callback was invoked.
*/
void onFrameMetricsAvailable(int dropCountSinceLastInvocation);
}
/**
* Creates a FrameMetricsObserver
*
* @param frameMetrics the available metrics. This array is reused on every call to the listener
* and thus <strong>this reference should only be used within the scope of the listener callback
* as data is not guaranteed to be valid outside the scope of that method</strong>.
* @param handler the Handler to use when invoking callbacks
*/
public HardwareRendererObserver(@NonNull OnFrameMetricsAvailableListener listener,
@NonNull long[] frameMetrics, @NonNull Handler handler) {
if (handler == null || handler.getLooper() == null) {
throw new NullPointerException("handler and its looper cannot be null");
}
if (handler.getLooper().getQueue() == null) {
throw new IllegalStateException("invalid looper, null message queue\n");
}
mFrameMetrics = frameMetrics;
mHandler = handler;
mListener = listener;
mNativePtr = new VirtualRefBasePtr(nCreateObserver());
}
/*package*/ long getNativeInstance() {
return mNativePtr.get();
}
// Called by native on the provided Handler
@SuppressWarnings("unused")
private void notifyDataAvailable() {
mHandler.post(() -> {
boolean hasMoreData = true;
while (hasMoreData) {
// a drop count of -1 is a sentinel that no more buffers are available
int dropCount = nGetNextBuffer(mNativePtr.get(), mFrameMetrics);
if (dropCount >= 0) {
mListener.onFrameMetricsAvailable(dropCount);
} else {
hasMoreData = false;
}
}
});
}
private native long nCreateObserver();
private static native int nGetNextBuffer(long nativePtr, long[] data);
}