Merge "Check mInputEventReceiver before sending timeline -- 2" into sc-dev am: 234adf7cb2
Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/14350504 Change-Id: I6c8c1670ead483b5dcb3cab3f8a018e6fcfcfc04
This commit is contained in:
committed by
Automerger Merge Worker
commit
12318a45bd
@@ -1201,8 +1201,7 @@ public final class ViewRootImpl implements ViewParent,
|
|||||||
Looper.myLooper());
|
Looper.myLooper());
|
||||||
|
|
||||||
if (mAttachInfo.mThreadedRenderer != null) {
|
if (mAttachInfo.mThreadedRenderer != null) {
|
||||||
InputMetricsListener listener =
|
InputMetricsListener listener = new InputMetricsListener();
|
||||||
new InputMetricsListener(mInputEventReceiver);
|
|
||||||
mHardwareRendererObserver = new HardwareRendererObserver(
|
mHardwareRendererObserver = new HardwareRendererObserver(
|
||||||
listener, listener.data, mHandler, true /*waitForPresentTime*/);
|
listener, listener.data, mHandler, true /*waitForPresentTime*/);
|
||||||
mAttachInfo.mThreadedRenderer.addObserver(mHardwareRendererObserver);
|
mAttachInfo.mThreadedRenderer.addObserver(mHardwareRendererObserver);
|
||||||
@@ -1414,6 +1413,9 @@ public final class ViewRootImpl implements ViewParent,
|
|||||||
if (mAttachInfo.mThreadedRenderer != null) {
|
if (mAttachInfo.mThreadedRenderer != null) {
|
||||||
mAttachInfo.mHardwareAccelerated =
|
mAttachInfo.mHardwareAccelerated =
|
||||||
mAttachInfo.mHardwareAccelerationRequested = true;
|
mAttachInfo.mHardwareAccelerationRequested = true;
|
||||||
|
if (mHardwareRendererObserver != null) {
|
||||||
|
mAttachInfo.mThreadedRenderer.addObserver(mHardwareRendererObserver);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -8118,6 +8120,9 @@ public final class ViewRootImpl implements ViewParent,
|
|||||||
ThreadedRenderer hardwareRenderer = mAttachInfo.mThreadedRenderer;
|
ThreadedRenderer hardwareRenderer = mAttachInfo.mThreadedRenderer;
|
||||||
|
|
||||||
if (hardwareRenderer != null) {
|
if (hardwareRenderer != null) {
|
||||||
|
if (mHardwareRendererObserver != null) {
|
||||||
|
hardwareRenderer.removeObserver(mHardwareRendererObserver);
|
||||||
|
}
|
||||||
if (mView != null) {
|
if (mView != null) {
|
||||||
hardwareRenderer.destroyHardwareResources(mView);
|
hardwareRenderer.destroyHardwareResources(mView);
|
||||||
}
|
}
|
||||||
@@ -8619,18 +8624,12 @@ public final class ViewRootImpl implements ViewParent,
|
|||||||
super.dispose();
|
super.dispose();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
WindowInputEventReceiver mInputEventReceiver;
|
private WindowInputEventReceiver mInputEventReceiver;
|
||||||
|
|
||||||
final class InputMetricsListener
|
final class InputMetricsListener
|
||||||
implements HardwareRendererObserver.OnFrameMetricsAvailableListener {
|
implements HardwareRendererObserver.OnFrameMetricsAvailableListener {
|
||||||
public long[] data = new long[FrameMetrics.Index.FRAME_STATS_COUNT];
|
public long[] data = new long[FrameMetrics.Index.FRAME_STATS_COUNT];
|
||||||
|
|
||||||
private InputEventReceiver mReceiver;
|
|
||||||
|
|
||||||
InputMetricsListener(InputEventReceiver receiver) {
|
|
||||||
mReceiver = receiver;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onFrameMetricsAvailable(int dropCountSinceLastInvocation) {
|
public void onFrameMetricsAvailable(int dropCountSinceLastInvocation) {
|
||||||
final int inputEventId = (int) data[FrameMetrics.Index.INPUT_EVENT_ID];
|
final int inputEventId = (int) data[FrameMetrics.Index.INPUT_EVENT_ID];
|
||||||
@@ -8643,6 +8642,20 @@ public final class ViewRootImpl implements ViewParent,
|
|||||||
// available, we cannot compute end-to-end input latency metrics.
|
// available, we cannot compute end-to-end input latency metrics.
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
final long gpuCompletedTime = data[FrameMetrics.Index.GPU_COMPLETED];
|
||||||
|
if (mInputEventReceiver == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (gpuCompletedTime >= presentTime) {
|
||||||
|
final double discrepancyMs = (gpuCompletedTime - presentTime) * 1E-6;
|
||||||
|
final long vsyncId = data[FrameMetrics.Index.FRAME_TIMELINE_VSYNC_ID];
|
||||||
|
Log.w(TAG, "Not reporting timeline because gpuCompletedTime is " + discrepancyMs
|
||||||
|
+ "ms ahead of presentTime. FRAME_TIMELINE_VSYNC_ID=" + vsyncId
|
||||||
|
+ ", INPUT_EVENT_ID=" + inputEventId);
|
||||||
|
// TODO(b/186664409): figure out why this sometimes happens
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
mInputEventReceiver.reportTimeline(inputEventId, gpuCompletedTime, presentTime);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
HardwareRendererObserver mHardwareRendererObserver;
|
HardwareRendererObserver mHardwareRendererObserver;
|
||||||
|
|||||||
@@ -241,13 +241,13 @@ status_t NativeInputEventReceiver::processOutboundEvents() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Some other error. Give up
|
// Some other error. Give up
|
||||||
ALOGW("Failed to send outbound event on channel '%s'. status=%d",
|
ALOGW("Failed to send outbound event on channel '%s'. status=%s(%d)",
|
||||||
getInputChannelName().c_str(), status);
|
getInputChannelName().c_str(), statusToString(status).c_str(), status);
|
||||||
if (status != DEAD_OBJECT) {
|
if (status != DEAD_OBJECT) {
|
||||||
JNIEnv* env = AndroidRuntime::getJNIEnv();
|
JNIEnv* env = AndroidRuntime::getJNIEnv();
|
||||||
std::string message =
|
std::string message =
|
||||||
android::base::StringPrintf("Failed to send outbound event. status=%d",
|
android::base::StringPrintf("Failed to send outbound event. status=%s(%d)",
|
||||||
status);
|
statusToString(status).c_str(), status);
|
||||||
jniThrowRuntimeException(env, message.c_str());
|
jniThrowRuntimeException(env, message.c_str());
|
||||||
mMessageQueue->raiseAndClearException(env, "finishInputEvent");
|
mMessageQueue->raiseAndClearException(env, "finishInputEvent");
|
||||||
}
|
}
|
||||||
@@ -319,8 +319,8 @@ status_t NativeInputEventReceiver::consumeEvents(JNIEnv* env,
|
|||||||
status_t status = mInputConsumer.consume(&mInputEventFactory,
|
status_t status = mInputConsumer.consume(&mInputEventFactory,
|
||||||
consumeBatches, frameTime, &seq, &inputEvent);
|
consumeBatches, frameTime, &seq, &inputEvent);
|
||||||
if (status != OK && status != WOULD_BLOCK) {
|
if (status != OK && status != WOULD_BLOCK) {
|
||||||
ALOGE("channel '%s' ~ Failed to consume input event. status=%d",
|
ALOGE("channel '%s' ~ Failed to consume input event. status=%s(%d)",
|
||||||
getInputChannelName().c_str(), status);
|
getInputChannelName().c_str(), statusToString(status).c_str(), status);
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -502,9 +502,9 @@ static jlong nativeInit(JNIEnv* env, jclass clazz, jobject receiverWeak,
|
|||||||
receiverWeak, inputChannel, messageQueue);
|
receiverWeak, inputChannel, messageQueue);
|
||||||
status_t status = receiver->initialize();
|
status_t status = receiver->initialize();
|
||||||
if (status) {
|
if (status) {
|
||||||
std::string message =
|
std::string message = android::base::
|
||||||
android::base::StringPrintf("Failed to initialize input event receiver. status=%d",
|
StringPrintf("Failed to initialize input event receiver. status=%s(%d)",
|
||||||
status);
|
statusToString(status).c_str(), status);
|
||||||
jniThrowRuntimeException(env, message.c_str());
|
jniThrowRuntimeException(env, message.c_str());
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -531,7 +531,7 @@ static void nativeFinishInputEvent(JNIEnv* env, jclass clazz, jlong receiverPtr,
|
|||||||
if (status != DEAD_OBJECT) {
|
if (status != DEAD_OBJECT) {
|
||||||
std::string message =
|
std::string message =
|
||||||
android::base::StringPrintf("Failed to finish input event. status=%s(%d)",
|
android::base::StringPrintf("Failed to finish input event. status=%s(%d)",
|
||||||
strerror(-status), status);
|
statusToString(status).c_str(), status);
|
||||||
jniThrowRuntimeException(env, message.c_str());
|
jniThrowRuntimeException(env, message.c_str());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -564,8 +564,8 @@ static jboolean nativeConsumeBatchedInputEvents(JNIEnv* env, jclass clazz, jlong
|
|||||||
&consumedBatch);
|
&consumedBatch);
|
||||||
if (status && status != DEAD_OBJECT && !env->ExceptionCheck()) {
|
if (status && status != DEAD_OBJECT && !env->ExceptionCheck()) {
|
||||||
std::string message =
|
std::string message =
|
||||||
android::base::StringPrintf("Failed to consume batched input event. status=%d",
|
android::base::StringPrintf("Failed to consume batched input event. status=%s(%d)",
|
||||||
status);
|
statusToString(status).c_str(), status);
|
||||||
jniThrowRuntimeException(env, message.c_str());
|
jniThrowRuntimeException(env, message.c_str());
|
||||||
return JNI_FALSE;
|
return JNI_FALSE;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -145,4 +145,21 @@ class InputEventSenderAndReceiverTest {
|
|||||||
val received = mSender.getTimeline()
|
val received = mSender.getTimeline()
|
||||||
assertEquals(sent, received)
|
assertEquals(sent, received)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If an invalid timeline is sent, the channel should get closed. This helps surface any
|
||||||
|
// app-originating bugs early, and forces the work-around to happen in the early stages of the
|
||||||
|
// event processing.
|
||||||
|
@Test
|
||||||
|
fun testSendAndReceiveInvalidTimeline() {
|
||||||
|
val sent = TestInputEventSender.Timeline(
|
||||||
|
inputEventId = 1, gpuCompletedTime = 3, presentTime = 2)
|
||||||
|
mReceiver.reportTimeline(sent.inputEventId, sent.gpuCompletedTime, sent.presentTime)
|
||||||
|
val received = mSender.getTimeline()
|
||||||
|
assertEquals(null, received)
|
||||||
|
// Sender will no longer receive callbacks for this fd, even if receiver sends a valid
|
||||||
|
// timeline later
|
||||||
|
mReceiver.reportTimeline(2 /*inputEventId*/, 3 /*gpuCompletedTime*/, 4 /*presentTime*/)
|
||||||
|
val receivedSecondTimeline = mSender.getTimeline()
|
||||||
|
assertEquals(null, receivedSecondTimeline)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user