Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c4ef2c70 authored by Derek Sollenberger's avatar Derek Sollenberger
Browse files

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
parent 3d559cbd
Loading
Loading
Loading
Loading
+25 −36
Original line number Diff line number Diff line
@@ -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;
    }
}
+5 −7
Original line number Diff line number Diff line
@@ -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");
+1 −1
Original line number Diff line number Diff line
@@ -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",
+2 −2
Original line number Diff line number Diff line
@@ -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),
};
+130 −0
Original line number Diff line number Diff line
@@ -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;
@@ -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;
@@ -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()) {
@@ -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