Merge "Include the display's resolution in the Jank reports."
This commit is contained in:
committed by
Android (Google) Code Review
commit
7d3ae07e6c
@@ -0,0 +1,162 @@
|
||||
/*
|
||||
* Copyright (C) 2022 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.internal.jank;
|
||||
|
||||
import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__DISPLAY_RESOLUTION__FHD;
|
||||
import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__DISPLAY_RESOLUTION__HD;
|
||||
import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__DISPLAY_RESOLUTION__QHD;
|
||||
import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__DISPLAY_RESOLUTION__SD;
|
||||
import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__DISPLAY_RESOLUTION__UNKNOWN_RESOLUTION;
|
||||
|
||||
import android.annotation.IntDef;
|
||||
import android.annotation.Nullable;
|
||||
import android.hardware.display.DisplayManager;
|
||||
import android.hardware.display.DisplayManagerGlobal;
|
||||
import android.os.Handler;
|
||||
import android.util.SparseArray;
|
||||
import android.view.DisplayInfo;
|
||||
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
|
||||
/**
|
||||
* A class that tracks the display resolutions.
|
||||
* @hide
|
||||
*/
|
||||
public class DisplayResolutionTracker {
|
||||
private static final String TAG = DisplayResolutionTracker.class.getSimpleName();
|
||||
|
||||
public static final int RESOLUTION_UNKNOWN =
|
||||
UIINTERACTION_FRAME_INFO_REPORTED__DISPLAY_RESOLUTION__UNKNOWN_RESOLUTION;
|
||||
public static final int RESOLUTION_SD =
|
||||
UIINTERACTION_FRAME_INFO_REPORTED__DISPLAY_RESOLUTION__SD;
|
||||
public static final int RESOLUTION_HD =
|
||||
UIINTERACTION_FRAME_INFO_REPORTED__DISPLAY_RESOLUTION__HD;
|
||||
public static final int RESOLUTION_FHD =
|
||||
UIINTERACTION_FRAME_INFO_REPORTED__DISPLAY_RESOLUTION__FHD;
|
||||
public static final int RESOLUTION_QHD =
|
||||
UIINTERACTION_FRAME_INFO_REPORTED__DISPLAY_RESOLUTION__QHD;
|
||||
|
||||
/** @hide */
|
||||
@IntDef({
|
||||
RESOLUTION_UNKNOWN,
|
||||
RESOLUTION_SD,
|
||||
RESOLUTION_HD,
|
||||
RESOLUTION_FHD,
|
||||
RESOLUTION_QHD,
|
||||
})
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
public @interface Resolution {
|
||||
}
|
||||
|
||||
private final DisplayInterface mManager;
|
||||
private final SparseArray<Integer> mResolutions = new SparseArray<>();
|
||||
private final Object mLock = new Object();
|
||||
|
||||
public DisplayResolutionTracker(@Nullable Handler handler) {
|
||||
this(DisplayInterface.getDefault(handler));
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
public DisplayResolutionTracker(DisplayInterface manager) {
|
||||
mManager = manager;
|
||||
mManager.registerDisplayListener(new DisplayManager.DisplayListener() {
|
||||
@Override
|
||||
public void onDisplayAdded(int displayId) {
|
||||
updateDisplay(displayId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDisplayChanged(int displayId) {
|
||||
updateDisplay(displayId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDisplayRemoved(int displayId) {
|
||||
// Not in the event mask below, won't be called.
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void updateDisplay(int displayId) {
|
||||
DisplayInfo info = mManager.getDisplayInfo(displayId);
|
||||
@Resolution int resolution = getResolution(info);
|
||||
|
||||
synchronized (mLock) {
|
||||
mResolutions.put(displayId, resolution);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the (cached) resolution of the display with the given ID.
|
||||
*/
|
||||
@Resolution
|
||||
public int getResolution(int displayId) {
|
||||
return mResolutions.get(displayId, RESOLUTION_UNKNOWN);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the resolution of the given {@link DisplayInfo}.
|
||||
*/
|
||||
@VisibleForTesting
|
||||
@Resolution
|
||||
public static int getResolution(DisplayInfo info) {
|
||||
int smaller = Math.min(info.logicalWidth, info.logicalHeight);
|
||||
int larger = Math.max(info.logicalWidth, info.logicalHeight);
|
||||
if (smaller < 720 || larger < 1280) {
|
||||
return RESOLUTION_SD;
|
||||
} else if (smaller < 1080 || larger < 1920) {
|
||||
return RESOLUTION_HD;
|
||||
} else if (smaller < 1440 || larger < 2560) {
|
||||
return RESOLUTION_FHD;
|
||||
} else {
|
||||
return RESOLUTION_QHD;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper around the final {@link DisplayManagerGlobal} class.
|
||||
* @hide
|
||||
*/
|
||||
@VisibleForTesting
|
||||
public interface DisplayInterface {
|
||||
/** Reurns an implementation wrapping {@link DisplayManagerGlobal}. */
|
||||
static DisplayInterface getDefault(@Nullable Handler handler) {
|
||||
DisplayManagerGlobal manager = DisplayManagerGlobal.getInstance();
|
||||
return new DisplayInterface() {
|
||||
@Override
|
||||
public void registerDisplayListener(DisplayManager.DisplayListener listener) {
|
||||
manager.registerDisplayListener(listener, handler,
|
||||
DisplayManager.EVENT_FLAG_DISPLAY_ADDED
|
||||
| DisplayManager.EVENT_FLAG_DISPLAY_CHANGED);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DisplayInfo getDisplayInfo(int displayId) {
|
||||
return manager.getDisplayInfo(displayId);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/** {@see DisplayManagerGlobal#registerDisplayListener} */
|
||||
void registerDisplayListener(DisplayManager.DisplayListener listener);
|
||||
/** {@see DisplayManagerGlobal#getDisplayInfo} */
|
||||
DisplayInfo getDisplayInfo(int displayId);
|
||||
}
|
||||
}
|
||||
@@ -100,6 +100,7 @@ public class FrameTracker extends SurfaceControl.OnJankDataListener
|
||||
private final Session mSession;
|
||||
private final ViewRootWrapper mViewRoot;
|
||||
private final SurfaceControlWrapper mSurfaceControlWrapper;
|
||||
private final int mDisplayId;
|
||||
private final ViewRootImpl.SurfaceChangedCallback mSurfaceChangedCallback;
|
||||
private final Handler mHandler;
|
||||
private final ChoreographerWrapper mChoreographer;
|
||||
@@ -213,6 +214,7 @@ public class FrameTracker extends SurfaceControl.OnJankDataListener
|
||||
mTraceThresholdMissedFrames = traceThresholdMissedFrames;
|
||||
mTraceThresholdFrameTimeMillis = traceThresholdFrameTimeMillis;
|
||||
mListener = listener;
|
||||
mDisplayId = config.getDisplayId();
|
||||
|
||||
if (mSurfaceOnly) {
|
||||
mSurfaceControl = config.getSurfaceControl();
|
||||
@@ -625,6 +627,7 @@ public class FrameTracker extends SurfaceControl.OnJankDataListener
|
||||
if (mSession.logToStatsd()) {
|
||||
mStatsLog.write(
|
||||
FrameworkStatsLog.UI_INTERACTION_FRAME_INFO_REPORTED,
|
||||
mDisplayId,
|
||||
mSession.getStatsdInteractionType(),
|
||||
totalFramesCount,
|
||||
missedFramesCount,
|
||||
@@ -785,9 +788,17 @@ public class FrameTracker extends SurfaceControl.OnJankDataListener
|
||||
}
|
||||
|
||||
public static class StatsLogWrapper {
|
||||
public void write(int code,
|
||||
private final DisplayResolutionTracker mDisplayResolutionTracker;
|
||||
|
||||
public StatsLogWrapper(DisplayResolutionTracker displayResolutionTracker) {
|
||||
mDisplayResolutionTracker = displayResolutionTracker;
|
||||
}
|
||||
|
||||
/** {@see FrameworkStatsLog#write) */
|
||||
public void write(int code, int displayId,
|
||||
int arg1, long arg2, long arg3, long arg4, long arg5, long arg6, long arg7) {
|
||||
FrameworkStatsLog.write(code, arg1, arg2, arg3, arg4, arg5, arg6, arg7);
|
||||
FrameworkStatsLog.write(code, arg1, arg2, arg3, arg4, arg5, arg6, arg7,
|
||||
mDisplayResolutionTracker.getResolution(displayId));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -306,6 +306,7 @@ public class InteractionJankMonitor {
|
||||
@GuardedBy("mLock")
|
||||
private final SparseArray<Runnable> mTimeoutActions;
|
||||
private final HandlerThread mWorker;
|
||||
private final DisplayResolutionTracker mDisplayResolutionTracker;
|
||||
private final Object mLock = new Object();
|
||||
|
||||
private volatile boolean mEnabled = DEFAULT_ENABLED;
|
||||
@@ -408,6 +409,7 @@ public class InteractionJankMonitor {
|
||||
mWorker = worker;
|
||||
mWorker.start();
|
||||
mSamplingInterval = DEFAULT_SAMPLING_INTERVAL;
|
||||
mDisplayResolutionTracker = new DisplayResolutionTracker(worker.getThreadHandler());
|
||||
|
||||
// Post initialization to the background in case we're running on the main
|
||||
// thread.
|
||||
@@ -443,7 +445,8 @@ public class InteractionJankMonitor {
|
||||
final FrameMetricsWrapper frameMetrics = new FrameMetricsWrapper();
|
||||
|
||||
return new FrameTracker(this, session, config.getHandler(), threadedRenderer, viewRoot,
|
||||
surfaceControl, choreographer, frameMetrics, new FrameTracker.StatsLogWrapper(),
|
||||
surfaceControl, choreographer, frameMetrics,
|
||||
new FrameTracker.StatsLogWrapper(mDisplayResolutionTracker),
|
||||
mTraceThresholdMissedFrames, mTraceThresholdFrameTimeMillis,
|
||||
eventsListener, config);
|
||||
}
|
||||
@@ -1098,6 +1101,14 @@ public class InteractionJankMonitor {
|
||||
public Handler getHandler() {
|
||||
return mHandler;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the ID of the display this interaction in on.
|
||||
*/
|
||||
@VisibleForTesting
|
||||
public int getDisplayId() {
|
||||
return (mSurfaceOnly ? mContext.getDisplay() : mView.getDisplay()).getDisplayId();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* Copyright (C) 2020 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.internal.jank;
|
||||
|
||||
import static com.android.internal.jank.DisplayResolutionTracker.getResolution;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.hardware.display.DisplayManager;
|
||||
import android.view.DisplayInfo;
|
||||
|
||||
import androidx.test.filters.SmallTest;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
|
||||
@SmallTest
|
||||
public class DisplayResolutionTrackerTest {
|
||||
private static final DisplayInfo SD = makeDisplayInfo(800, 600);
|
||||
private static final DisplayInfo HD = makeDisplayInfo(720, 1280);
|
||||
private static final DisplayInfo FHD = makeDisplayInfo(2340, 1080);
|
||||
private static final DisplayInfo QHD = makeDisplayInfo(3120, 1440);
|
||||
|
||||
private DisplayResolutionTracker.DisplayInterface mDisplayManager;
|
||||
private ArgumentCaptor<DisplayManager.DisplayListener> mListenerCaptor;
|
||||
private DisplayResolutionTracker mTracker;
|
||||
|
||||
@Before
|
||||
public void setup() throws Exception {
|
||||
mDisplayManager = mock(DisplayResolutionTracker.DisplayInterface.class);
|
||||
mListenerCaptor = ArgumentCaptor.forClass(DisplayManager.DisplayListener.class);
|
||||
|
||||
mTracker = new DisplayResolutionTracker(mDisplayManager);
|
||||
|
||||
verify(mDisplayManager).registerDisplayListener(mListenerCaptor.capture());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testResolutionMapping() {
|
||||
assertThat(getResolution(SD)).isEqualTo(DisplayResolutionTracker.RESOLUTION_SD);
|
||||
assertThat(getResolution(HD)).isEqualTo(DisplayResolutionTracker.RESOLUTION_HD);
|
||||
assertThat(getResolution(FHD)).isEqualTo(DisplayResolutionTracker.RESOLUTION_FHD);
|
||||
assertThat(getResolution(QHD)).isEqualTo(DisplayResolutionTracker.RESOLUTION_QHD);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testResolutionUpdatesOnDisplayChanges() throws Exception {
|
||||
assertThat(mTracker.getResolution(42))
|
||||
.isEqualTo(DisplayResolutionTracker.RESOLUTION_UNKNOWN);
|
||||
|
||||
when(mDisplayManager.getDisplayInfo(42)).thenReturn(FHD, QHD);
|
||||
|
||||
mListenerCaptor.getValue().onDisplayAdded(42);
|
||||
assertThat(mTracker.getResolution(42))
|
||||
.isEqualTo(DisplayResolutionTracker.RESOLUTION_FHD);
|
||||
mListenerCaptor.getValue().onDisplayChanged(42);
|
||||
assertThat(mTracker.getResolution(42))
|
||||
.isEqualTo(DisplayResolutionTracker.RESOLUTION_QHD);
|
||||
}
|
||||
|
||||
private static DisplayInfo makeDisplayInfo(int width, int height) {
|
||||
DisplayInfo info = new DisplayInfo();
|
||||
info.logicalWidth = width;
|
||||
info.logicalHeight = height;
|
||||
return info;
|
||||
}
|
||||
}
|
||||
@@ -124,6 +124,7 @@ public class FrameTrackerTest {
|
||||
when(config.isSurfaceOnly()).thenReturn(surfaceOnly);
|
||||
when(config.getSurfaceControl()).thenReturn(mSurfaceControl);
|
||||
when(config.shouldDeferMonitor()).thenReturn(true);
|
||||
when(config.getDisplayId()).thenReturn(42);
|
||||
View view = mRule.getActivity().getWindow().getDecorView();
|
||||
Handler spyHandler = spy(new Handler(handler.getLooper()));
|
||||
when(config.getView()).thenReturn(surfaceOnly ? null : view);
|
||||
@@ -168,6 +169,7 @@ public class FrameTrackerTest {
|
||||
verify(tracker).removeObservers();
|
||||
verify(tracker, never()).triggerPerfetto();
|
||||
verify(mStatsLog).write(eq(UI_INTERACTION_FRAME_INFO_REPORTED),
|
||||
eq(42), /* displayId */
|
||||
eq(CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE]),
|
||||
eq(2L) /* totalFrames */,
|
||||
eq(0L) /* missedFrames */,
|
||||
@@ -204,6 +206,7 @@ public class FrameTrackerTest {
|
||||
verify(tracker).triggerPerfetto();
|
||||
|
||||
verify(mStatsLog).write(eq(UI_INTERACTION_FRAME_INFO_REPORTED),
|
||||
eq(42), /* displayId */
|
||||
eq(CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE]),
|
||||
eq(2L) /* totalFrames */,
|
||||
eq(1L) /* missedFrames */,
|
||||
@@ -240,6 +243,7 @@ public class FrameTrackerTest {
|
||||
verify(tracker, never()).triggerPerfetto();
|
||||
|
||||
verify(mStatsLog).write(eq(UI_INTERACTION_FRAME_INFO_REPORTED),
|
||||
eq(42), /* displayId */
|
||||
eq(CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE]),
|
||||
eq(2L) /* totalFrames */,
|
||||
eq(0L) /* missedFrames */,
|
||||
@@ -276,6 +280,7 @@ public class FrameTrackerTest {
|
||||
verify(tracker).triggerPerfetto();
|
||||
|
||||
verify(mStatsLog).write(eq(UI_INTERACTION_FRAME_INFO_REPORTED),
|
||||
eq(42), /* displayId */
|
||||
eq(CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE]),
|
||||
eq(2L) /* totalFrames */,
|
||||
eq(1L) /* missedFrames */,
|
||||
@@ -315,6 +320,7 @@ public class FrameTrackerTest {
|
||||
verify(tracker).triggerPerfetto();
|
||||
|
||||
verify(mStatsLog).write(eq(UI_INTERACTION_FRAME_INFO_REPORTED),
|
||||
eq(42), /* displayId */
|
||||
eq(CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE]),
|
||||
eq(2L) /* totalFrames */,
|
||||
eq(1L) /* missedFrames */,
|
||||
@@ -356,6 +362,7 @@ public class FrameTrackerTest {
|
||||
verify(tracker).removeObservers();
|
||||
verify(tracker, never()).triggerPerfetto();
|
||||
verify(mStatsLog).write(eq(UI_INTERACTION_FRAME_INFO_REPORTED),
|
||||
eq(42), /* displayId */
|
||||
eq(CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE]),
|
||||
eq(2L) /* totalFrames */,
|
||||
eq(0L) /* missedFrames */,
|
||||
@@ -483,6 +490,7 @@ public class FrameTrackerTest {
|
||||
verify(tracker).triggerPerfetto();
|
||||
|
||||
verify(mStatsLog).write(eq(UI_INTERACTION_FRAME_INFO_REPORTED),
|
||||
eq(42), /* displayId */
|
||||
eq(CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_WALLPAPER_TRANSITION]),
|
||||
eq(2L) /* totalFrames */,
|
||||
eq(1L) /* missedFrames */,
|
||||
@@ -519,6 +527,7 @@ public class FrameTrackerTest {
|
||||
verify(tracker, never()).triggerPerfetto();
|
||||
|
||||
verify(mStatsLog).write(eq(UI_INTERACTION_FRAME_INFO_REPORTED),
|
||||
eq(42), /* displayId */
|
||||
eq(CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_WALLPAPER_TRANSITION]),
|
||||
eq(2L) /* totalFrames */,
|
||||
eq(0L) /* missedFrames */,
|
||||
@@ -555,6 +564,7 @@ public class FrameTrackerTest {
|
||||
verify(tracker, never()).triggerPerfetto();
|
||||
|
||||
verify(mStatsLog).write(eq(UI_INTERACTION_FRAME_INFO_REPORTED),
|
||||
eq(42), /* displayId */
|
||||
eq(CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_WALLPAPER_TRANSITION]),
|
||||
eq(2L) /* totalFrames */,
|
||||
eq(0L) /* missedFrames */,
|
||||
@@ -585,6 +595,7 @@ public class FrameTrackerTest {
|
||||
verify(mSurfaceControlWrapper).removeJankStatsListener(any());
|
||||
verify(tracker).triggerPerfetto();
|
||||
verify(mStatsLog).write(eq(UI_INTERACTION_FRAME_INFO_REPORTED),
|
||||
eq(42), /* displayId */
|
||||
eq(CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_WALLPAPER_TRANSITION]),
|
||||
eq(6L) /* totalFrames */,
|
||||
eq(5L) /* missedFrames */,
|
||||
|
||||
@@ -354,10 +354,11 @@ public class InteractionJankMonitorTest {
|
||||
when(configuration.isSurfaceOnly()).thenReturn(false);
|
||||
when(configuration.getView()).thenReturn(mView);
|
||||
when(configuration.getHandler()).thenReturn(mView.getHandler());
|
||||
when(configuration.getDisplayId()).thenReturn(42);
|
||||
|
||||
FrameTracker tracker = spy(new FrameTracker(monitor, session, mWorker.getThreadHandler(),
|
||||
threadedRenderer, viewRoot, surfaceControl, choreographer,
|
||||
new FrameMetricsWrapper(), new StatsLogWrapper(),
|
||||
new FrameMetricsWrapper(), new StatsLogWrapper(null),
|
||||
/* traceThresholdMissedFrames= */ 1,
|
||||
/* traceThresholdFrameTimeMillis= */ -1, listener, configuration));
|
||||
|
||||
|
||||
Reference in New Issue
Block a user