Fix potential memory leak of FrameTracker

If begin and end invocations are at the same frame, the end vsync id
will be smaller than the begin vsync id, results in zero size jank info
array, the finish call will be missed as well, a leak happens.

Bug: 192140966
Test: atest FrameTrackerTest InteractionJankMonitorTest
Change-Id: I388558e60bdb84ad248a9afabe7776c4e6e67c57
This commit is contained in:
Ahan Wu
2021-07-19 09:53:41 -08:00
committed by Wu Ahan
parent 6b43ea0a73
commit 65a3d5dfa4
3 changed files with 26 additions and 9 deletions

View File

@@ -251,7 +251,7 @@ public class FrameTracker extends SurfaceControl.OnJankDataListener
// 2. The session never begun.
if (mBeginVsyncId == INVALID_ID) {
cancel(REASON_CANCEL_NOT_BEGUN);
} else if (mEndVsyncId == mBeginVsyncId) {
} else if (mEndVsyncId <= mBeginVsyncId) {
cancel(REASON_CANCEL_SAME_VSYNC);
} else {
if (DEBUG) {

View File

@@ -257,21 +257,14 @@ public class FrameTrackerTest {
}
@Test
public void testRemoveObserversWhenCancelledInEnd() {
public void testCancelIfEndVsyncIdEqualsToBeginVsyncId() {
when(mChoreographer.getVsyncId()).thenReturn(100L);
mTracker.begin();
verify(mRenderer, only()).addObserver(any());
// send first frame - not janky
sendFrame(4, JANK_NONE, 100L);
// send another frame - should be considered janky
sendFrame(40, JANK_APP_DEADLINE_MISSED, 101L);
// end the trace session
when(mChoreographer.getVsyncId()).thenReturn(101L);
mTracker.end(FrameTracker.REASON_END_NORMAL);
sendFrame(4, JANK_NONE, 102L);
// Since the begin vsync id (101) equals to the end vsync id (101), will be treat as cancel.
verify(mTracker).cancel(FrameTracker.REASON_CANCEL_SAME_VSYNC);
@@ -283,6 +276,26 @@ public class FrameTrackerTest {
verify(mTracker, never()).triggerPerfetto();
}
@Test
public void testCancelIfEndVsyncIdLessThanBeginVsyncId() {
when(mChoreographer.getVsyncId()).thenReturn(100L);
mTracker.begin();
verify(mRenderer, only()).addObserver(any());
// end the trace session at the same vsync id, end vsync id will less than the begin one.
// Because the begin vsync id is supposed to the next frame,
mTracker.end(FrameTracker.REASON_END_NORMAL);
// The begin vsync id (101) is larger than the end one (100), will be treat as cancel.
verify(mTracker).cancel(FrameTracker.REASON_CANCEL_SAME_VSYNC);
// Observers should be removed in this case, or FrameTracker object will be leaked.
verify(mTracker).removeObservers();
// Should never trigger Perfetto since it is a cancel.
verify(mTracker, never()).triggerPerfetto();
}
@Test
public void testCancelWhenSessionNeverBegun() {
mTracker.cancel(FrameTracker.REASON_CANCEL_NORMAL);

View File

@@ -99,6 +99,8 @@ public class InteractionJankMonitorTest {
new FrameMetricsWrapper(), /*traceThresholdMissedFrames=*/ 1,
/*traceThresholdFrameTimeMillis=*/ -1, null));
doReturn(tracker).when(monitor).createFrameTracker(any(), any());
doNothing().when(tracker).triggerPerfetto();
doNothing().when(tracker).postTraceStartMarker();
// Simulate a trace session and see if begin / end are invoked.
assertThat(monitor.begin(mView, session.getCuj())).isTrue();
@@ -146,6 +148,8 @@ public class InteractionJankMonitorTest {
new FrameMetricsWrapper(), /*traceThresholdMissedFrames=*/ 1,
/*traceThresholdFrameTimeMillis=*/ -1, null));
doReturn(tracker).when(monitor).createFrameTracker(any(), any());
doNothing().when(tracker).triggerPerfetto();
doNothing().when(tracker).postTraceStartMarker();
assertThat(monitor.begin(mView, session.getCuj())).isTrue();
verify(tracker).begin();