diff options
-rw-r--r-- | core/java/android/view/FrameMetricsObserver.java | 3 | ||||
-rw-r--r-- | core/java/android/view/InputEventReceiver.java | 10 | ||||
-rw-r--r-- | core/java/android/view/ViewRootImpl.java | 38 | ||||
-rw-r--r-- | core/java/com/android/internal/jank/FrameTracker.java | 3 | ||||
-rw-r--r-- | graphics/java/android/graphics/HardwareRendererObserver.java | 6 | ||||
-rw-r--r-- | libs/hwui/FrameMetricsObserver.h | 18 | ||||
-rw-r--r-- | libs/hwui/FrameMetricsReporter.h | 15 | ||||
-rw-r--r-- | libs/hwui/jni/android_graphics_HardwareRendererObserver.cpp | 18 | ||||
-rw-r--r-- | libs/hwui/jni/android_graphics_HardwareRendererObserver.h | 2 | ||||
-rw-r--r-- | libs/hwui/renderthread/CanvasContext.cpp | 36 | ||||
-rw-r--r-- | libs/hwui/renderthread/CanvasContext.h | 6 |
11 files changed, 139 insertions, 16 deletions
diff --git a/core/java/android/view/FrameMetricsObserver.java b/core/java/android/view/FrameMetricsObserver.java index 41bc9a742752..35d95be0b57b 100644 --- a/core/java/android/view/FrameMetricsObserver.java +++ b/core/java/android/view/FrameMetricsObserver.java @@ -45,7 +45,8 @@ public class FrameMetricsObserver mWindow = new WeakReference<>(window); mListener = listener; mFrameMetrics = new FrameMetrics(); - mObserver = new HardwareRendererObserver(this, mFrameMetrics.mTimingData, handler); + mObserver = new HardwareRendererObserver(this, mFrameMetrics.mTimingData, handler, + false /*waitForPresentTime*/); } /** diff --git a/core/java/android/view/InputEventReceiver.java b/core/java/android/view/InputEventReceiver.java index 7d1adc36964b..79d8c14aa0df 100644 --- a/core/java/android/view/InputEventReceiver.java +++ b/core/java/android/view/InputEventReceiver.java @@ -21,6 +21,7 @@ import android.os.Build; import android.os.IBinder; import android.os.Looper; import android.os.MessageQueue; +import android.os.Trace; import android.util.Log; import android.util.SparseIntArray; @@ -198,6 +199,15 @@ public abstract class InputEventReceiver { } /** + * Report the latency information for a specific input event. + */ + public final void reportLatencyInfo(int inputEventId, long gpuCompletedTime, long presentTime) { + Trace.traceBegin(Trace.TRACE_TAG_INPUT, "reportLatencyInfo"); + // TODO(b/169866723) : send this data to InputDispatcher via InputChannel + Trace.traceEnd(Trace.TRACE_TAG_INPUT); + } + + /** * Consumes all pending batched input events. * Must be called on the same Looper thread to which the receiver is attached. * diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index 390e3ae78143..9fc415d6401f 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -16,6 +16,7 @@ package android.view; +import static android.os.IInputConstants.INVALID_INPUT_EVENT_ID; import static android.view.Display.DEFAULT_DISPLAY; import static android.view.Display.INVALID_DISPLAY; import static android.view.InputDevice.SOURCE_CLASS_NONE; @@ -105,6 +106,7 @@ import android.graphics.Color; import android.graphics.FrameInfo; import android.graphics.HardwareRenderer; import android.graphics.HardwareRenderer.FrameDrawingCallback; +import android.graphics.HardwareRendererObserver; import android.graphics.Insets; import android.graphics.Matrix; import android.graphics.PixelFormat; @@ -1191,6 +1193,14 @@ public final class ViewRootImpl implements ViewParent, } mInputEventReceiver = new WindowInputEventReceiver(inputChannel, Looper.myLooper()); + + if (mAttachInfo.mThreadedRenderer != null) { + InputMetricsListener listener = + new InputMetricsListener(mInputEventReceiver); + mHardwareRendererObserver = new HardwareRendererObserver( + listener, listener.data, mHandler, true /*waitForPresentTime*/); + mAttachInfo.mThreadedRenderer.addObserver(mHardwareRendererObserver); + } } view.assignParent(this); @@ -8569,6 +8579,34 @@ public final class ViewRootImpl implements ViewParent, } WindowInputEventReceiver mInputEventReceiver; + final class InputMetricsListener + implements HardwareRendererObserver.OnFrameMetricsAvailableListener { + public long[] data = new long[FrameMetrics.Index.FRAME_STATS_COUNT]; + + private InputEventReceiver mReceiver; + + InputMetricsListener(InputEventReceiver receiver) { + mReceiver = receiver; + } + + @Override + public void onFrameMetricsAvailable(int dropCountSinceLastInvocation) { + final int inputEventId = (int) data[FrameMetrics.Index.INPUT_EVENT_ID]; + if (inputEventId == INVALID_INPUT_EVENT_ID) { + return; + } + final long presentTime = data[FrameMetrics.Index.DISPLAY_PRESENT_TIME]; + if (presentTime <= 0) { + // Present time is not available for this frame. If the present time is not + // available, we cannot compute end-to-end input latency metrics. + return; + } + final long gpuCompletedTime = data[FrameMetrics.Index.GPU_COMPLETED]; + mReceiver.reportLatencyInfo(inputEventId, gpuCompletedTime, presentTime); + } + } + HardwareRendererObserver mHardwareRendererObserver; + final class ConsumeBatchedInputRunnable implements Runnable { @Override public void run() { diff --git a/core/java/com/android/internal/jank/FrameTracker.java b/core/java/com/android/internal/jank/FrameTracker.java index 33ee8f04d83e..48e5455b8b7f 100644 --- a/core/java/com/android/internal/jank/FrameTracker.java +++ b/core/java/com/android/internal/jank/FrameTracker.java @@ -121,7 +121,8 @@ public class FrameTracker extends SurfaceControl.OnJankDataListener mChoreographer = choreographer; mSurfaceControlWrapper = surfaceControlWrapper; mHandler = handler; - mObserver = new HardwareRendererObserver(this, mMetricsWrapper.getTiming(), handler); + mObserver = new HardwareRendererObserver( + this, mMetricsWrapper.getTiming(), handler, false /*waitForPresentTime*/); mTraceThresholdMissedFrames = traceThresholdMissedFrames; mTraceThresholdFrameTimeMillis = traceThresholdFrameTimeMillis; mListener = listener; diff --git a/graphics/java/android/graphics/HardwareRendererObserver.java b/graphics/java/android/graphics/HardwareRendererObserver.java index da9d03c639f7..e2a05723166f 100644 --- a/graphics/java/android/graphics/HardwareRendererObserver.java +++ b/graphics/java/android/graphics/HardwareRendererObserver.java @@ -62,7 +62,7 @@ public class HardwareRendererObserver { * @param handler the Handler to use when invoking callbacks */ public HardwareRendererObserver(@NonNull OnFrameMetricsAvailableListener listener, - @NonNull long[] frameMetrics, @NonNull Handler handler) { + @NonNull long[] frameMetrics, @NonNull Handler handler, boolean waitForPresentTime) { if (handler == null || handler.getLooper() == null) { throw new NullPointerException("handler and its looper cannot be null"); } @@ -74,7 +74,7 @@ public class HardwareRendererObserver { mFrameMetrics = frameMetrics; mHandler = handler; mListener = listener; - mNativePtr = new VirtualRefBasePtr(nCreateObserver()); + mNativePtr = new VirtualRefBasePtr(nCreateObserver(waitForPresentTime)); } /*package*/ long getNativeInstance() { @@ -98,6 +98,6 @@ public class HardwareRendererObserver { }); } - private native long nCreateObserver(); + private native long nCreateObserver(boolean waitForPresentTime); private static native int nGetNextBuffer(long nativePtr, long[] data); } diff --git a/libs/hwui/FrameMetricsObserver.h b/libs/hwui/FrameMetricsObserver.h index b93f07853242..ef1f5aabcbd8 100644 --- a/libs/hwui/FrameMetricsObserver.h +++ b/libs/hwui/FrameMetricsObserver.h @@ -24,6 +24,24 @@ namespace uirenderer { class FrameMetricsObserver : public VirtualLightRefBase { public: virtual void notify(const int64_t* buffer) = 0; + bool waitForPresentTime() const { return mWaitForPresentTime; }; + + /** + * Create a new metrics observer. An observer that watches present time gets notified at a + * different time than the observer that doesn't. + * + * The observer that doesn't want present time is notified about metrics just after the frame + * is completed. This is the default behaviour that's used by public API's. + * + * An observer that watches present time is notified about metrics after the actual display + * present time is known. + * WARNING! This observer may not receive metrics for the last several frames that the app + * produces. + */ + FrameMetricsObserver(bool waitForPresentTime) : mWaitForPresentTime(waitForPresentTime) {} + +private: + const bool mWaitForPresentTime; }; } // namespace uirenderer diff --git a/libs/hwui/FrameMetricsReporter.h b/libs/hwui/FrameMetricsReporter.h index 0643e790d00b..3f2dc1244085 100644 --- a/libs/hwui/FrameMetricsReporter.h +++ b/libs/hwui/FrameMetricsReporter.h @@ -55,13 +55,24 @@ public: return mObservers.size() > 0; } - void reportFrameMetrics(const int64_t* stats) { + /** + * Notify observers about the metrics contained in 'stats'. + * If an observer is waiting for present time, notify when 'stats' has present time. + * + * If an observer does not want present time, only notify when 'hasPresentTime' is false. + * Never notify both types of observers from the same callback, because the callback with + * 'hasPresentTime' is sent at a different time than the one without. + */ + void reportFrameMetrics(const int64_t* stats, bool hasPresentTime) { FatVector<sp<FrameMetricsObserver>, 10> copy; { std::lock_guard lock(mObserversLock); copy.reserve(mObservers.size()); for (size_t i = 0; i < mObservers.size(); i++) { - copy.push_back(mObservers[i]); + const bool wantsPresentTime = mObservers[i]->waitForPresentTime(); + if (hasPresentTime == wantsPresentTime) { + copy.push_back(mObservers[i]); + } } } for (size_t i = 0; i < copy.size(); i++) { diff --git a/libs/hwui/jni/android_graphics_HardwareRendererObserver.cpp b/libs/hwui/jni/android_graphics_HardwareRendererObserver.cpp index 5b3e65648981..e5d5e75d0f3b 100644 --- a/libs/hwui/jni/android_graphics_HardwareRendererObserver.cpp +++ b/libs/hwui/jni/android_graphics_HardwareRendererObserver.cpp @@ -35,7 +35,9 @@ static JNIEnv* getenv(JavaVM* vm) { return env; } -HardwareRendererObserver::HardwareRendererObserver(JavaVM *vm, jobject observer) : mVm(vm) { +HardwareRendererObserver::HardwareRendererObserver(JavaVM* vm, jobject observer, + bool waitForPresentTime) + : uirenderer::FrameMetricsObserver(waitForPresentTime), mVm(vm) { mObserverWeak = getenv(mVm)->NewWeakGlobalRef(observer); LOG_ALWAYS_FATAL_IF(mObserverWeak == nullptr, "unable to create frame stats observer reference"); @@ -86,14 +88,16 @@ void HardwareRendererObserver::notify(const int64_t* stats) { } static jlong android_graphics_HardwareRendererObserver_createObserver(JNIEnv* env, - jobject observerObj) { + jobject observerObj, + jboolean waitForPresentTime) { 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); + HardwareRendererObserver* observer = + new HardwareRendererObserver(vm, observerObj, waitForPresentTime); return reinterpret_cast<jlong>(observer); } @@ -110,10 +114,10 @@ static jint android_graphics_HardwareRendererObserver_getNextBuffer(JNIEnv* env, } 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), + MAKE_JNI_NATIVE_METHOD("nCreateObserver", "(Z)J", + android_graphics_HardwareRendererObserver_createObserver), + MAKE_JNI_NATIVE_METHOD("nGetNextBuffer", "(J[J)I", + android_graphics_HardwareRendererObserver_getNextBuffer), }; int register_android_graphics_HardwareRendererObserver(JNIEnv* env) { diff --git a/libs/hwui/jni/android_graphics_HardwareRendererObserver.h b/libs/hwui/jni/android_graphics_HardwareRendererObserver.h index 62111fd7d7a1..d3076140541b 100644 --- a/libs/hwui/jni/android_graphics_HardwareRendererObserver.h +++ b/libs/hwui/jni/android_graphics_HardwareRendererObserver.h @@ -26,7 +26,7 @@ namespace android { */ class HardwareRendererObserver : public uirenderer::FrameMetricsObserver { public: - HardwareRendererObserver(JavaVM *vm, jobject observer); + HardwareRendererObserver(JavaVM* vm, jobject observer, bool waitForPresentTime); ~HardwareRendererObserver(); /** diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp index f69ddacf7ca1..9793300b406d 100644 --- a/libs/hwui/renderthread/CanvasContext.cpp +++ b/libs/hwui/renderthread/CanvasContext.cpp @@ -599,10 +599,41 @@ void CanvasContext::finishFrame(FrameInfo* frameInfo) { // TODO (b/169858044): Move this into JankTracker to adjust deadline when queue is // double-stuffed. if (CC_UNLIKELY(mFrameMetricsReporter.get() != nullptr)) { - mFrameMetricsReporter->reportFrameMetrics(frameInfo->data()); + mFrameMetricsReporter->reportFrameMetrics(frameInfo->data(), false /*hasPresentTime*/); } } +void CanvasContext::reportMetricsWithPresentTime() { + if (mFrameMetricsReporter == nullptr) { + return; + } + if (mNativeSurface == nullptr) { + return; + } + FrameInfo* forthBehind; + int64_t frameNumber; + { // acquire lock + std::scoped_lock lock(mLast4FrameInfosMutex); + if (mLast4FrameInfos.size() != mLast4FrameInfos.capacity()) { + // Not enough frames yet + return; + } + // Surface object keeps stats for the last 8 frames. + std::tie(forthBehind, frameNumber) = mLast4FrameInfos.front(); + } // release lock + + nsecs_t presentTime = 0; + native_window_get_frame_timestamps( + mNativeSurface->getNativeWindow(), frameNumber, nullptr /*outRequestedPresentTime*/, + nullptr /*outAcquireTime*/, nullptr /*outLatchTime*/, + nullptr /*outFirstRefreshStartTime*/, nullptr /*outLastRefreshStartTime*/, + nullptr /*outGpuCompositionDoneTime*/, &presentTime, nullptr /*outDequeueReadyTime*/, + nullptr /*outReleaseTime*/); + + forthBehind->set(FrameInfoIndex::DisplayPresentTime) = presentTime; + mFrameMetricsReporter->reportFrameMetrics(forthBehind->data(), true /*hasPresentTime*/); +} + void CanvasContext::onSurfaceStatsAvailable(void* context, ASurfaceControl* control, ASurfaceControlStats* stats) { @@ -624,6 +655,9 @@ void CanvasContext::onSurfaceStatsAvailable(void* context, ASurfaceControl* cont } } } + + instance->reportMetricsWithPresentTime(); + if (frameInfo != nullptr) { if (gpuCompleteTime == -1) { gpuCompleteTime = frameInfo->get(FrameInfoIndex::SwapBuffersCompleted); diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h index 2e7b2f618a8a..74f426ead912 100644 --- a/libs/hwui/renderthread/CanvasContext.h +++ b/libs/hwui/renderthread/CanvasContext.h @@ -219,6 +219,12 @@ private: SkRect computeDirtyRect(const Frame& frame, SkRect* dirty); void finishFrame(FrameInfo* frameInfo); + /** + * Invoke 'reportFrameMetrics' on the last frame stored in 'mLast4FrameInfos'. + * Populate the 'presentTime' field before calling. + */ + void reportMetricsWithPresentTime(); + // The same type as Frame.mWidth and Frame.mHeight int32_t mLastFrameWidth = 0; int32_t mLastFrameHeight = 0; |