Pass actual present time to ViewRootImpl
To measure end-to-end touch latency, we need to report the actual
present time to ViewRootImpl. ViewRootImpl, in turn, will report this
information to InputDispatcher. Finally, InputDispatcher will combine
all known information for a specific input event, and will report this
data to westworld.
In another patch, we will add a new call, 'reportLatencyInfo', to
InputPublisher. This call will allow the app to send this latency data
to InputDispatcher.
Bug: 169866723
Test: printed the input event present times inside ViewRootImpl
Change-Id: Ibd3a2cfeb1a340eb15cd2165071df1f8589634af
diff --git a/libs/hwui/FrameMetricsObserver.h b/libs/hwui/FrameMetricsObserver.h
index b93f078..ef1f5aa 100644
--- a/libs/hwui/FrameMetricsObserver.h
+++ b/libs/hwui/FrameMetricsObserver.h
@@ -24,6 +24,24 @@
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 0643e79..3f2dc12 100644
--- a/libs/hwui/FrameMetricsReporter.h
+++ b/libs/hwui/FrameMetricsReporter.h
@@ -55,13 +55,24 @@
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 5b3e656..e5d5e75 100644
--- a/libs/hwui/jni/android_graphics_HardwareRendererObserver.cpp
+++ b/libs/hwui/jni/android_graphics_HardwareRendererObserver.cpp
@@ -35,7 +35,9 @@
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 @@
}
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 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 62111fd..d307614 100644
--- a/libs/hwui/jni/android_graphics_HardwareRendererObserver.h
+++ b/libs/hwui/jni/android_graphics_HardwareRendererObserver.h
@@ -26,7 +26,7 @@
*/
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 f69ddac..9793300 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -599,10 +599,41 @@
// 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 @@
}
}
}
+
+ 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 2e7b2f6..74f426e 100644
--- a/libs/hwui/renderthread/CanvasContext.h
+++ b/libs/hwui/renderthread/CanvasContext.h
@@ -219,6 +219,12 @@
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;