summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/java/android/view/FrameMetricsObserver.java3
-rw-r--r--core/java/android/view/InputEventReceiver.java10
-rw-r--r--core/java/android/view/ViewRootImpl.java38
-rw-r--r--core/java/com/android/internal/jank/FrameTracker.java3
-rw-r--r--graphics/java/android/graphics/HardwareRendererObserver.java6
-rw-r--r--libs/hwui/FrameMetricsObserver.h18
-rw-r--r--libs/hwui/FrameMetricsReporter.h15
-rw-r--r--libs/hwui/jni/android_graphics_HardwareRendererObserver.cpp18
-rw-r--r--libs/hwui/jni/android_graphics_HardwareRendererObserver.h2
-rw-r--r--libs/hwui/renderthread/CanvasContext.cpp36
-rw-r--r--libs/hwui/renderthread/CanvasContext.h6
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;