Add multi-user jank monitoring
Created CUJ for monitoring jank when switching users, including guest users, but excluding the "Add User" user journey. Bug: 200160966 Test: switch users manually, look at logs Test: atest KeyguardUpdateMonitorTest Test: atest UserSwitcherControllerTest Change-Id: I5570133a1f96a58d39a8f053f9f480cdaada8df1
This commit is contained in:
@@ -59,6 +59,7 @@ import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_IN
|
||||
import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SHADE_ROW_SWIPE;
|
||||
import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SHADE_SCROLL_FLING;
|
||||
import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__STATUS_BAR_APP_LAUNCH_FROM_CALL_CHIP;
|
||||
import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__USER_SWITCH;
|
||||
import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__WALLPAPER_TRANSITION;
|
||||
|
||||
import android.annotation.IntDef;
|
||||
@@ -171,6 +172,7 @@ public class InteractionJankMonitor {
|
||||
public static final int CUJ_STATUS_BAR_APP_LAUNCH_FROM_CALL_CHIP = 34;
|
||||
public static final int CUJ_PIP_TRANSITION = 35;
|
||||
public static final int CUJ_WALLPAPER_TRANSITION = 36;
|
||||
public static final int CUJ_USER_SWITCH = 37;
|
||||
|
||||
private static final int NO_STATSD_LOGGING = -1;
|
||||
|
||||
@@ -216,6 +218,7 @@ public class InteractionJankMonitor {
|
||||
UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__STATUS_BAR_APP_LAUNCH_FROM_CALL_CHIP,
|
||||
UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__PIP_TRANSITION,
|
||||
UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__WALLPAPER_TRANSITION,
|
||||
UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__USER_SWITCH,
|
||||
};
|
||||
|
||||
private static volatile InteractionJankMonitor sInstance;
|
||||
@@ -272,6 +275,7 @@ public class InteractionJankMonitor {
|
||||
CUJ_STATUS_BAR_APP_LAUNCH_FROM_CALL_CHIP,
|
||||
CUJ_PIP_TRANSITION,
|
||||
CUJ_WALLPAPER_TRANSITION,
|
||||
CUJ_USER_SWITCH,
|
||||
})
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
public @interface CujType {
|
||||
@@ -642,6 +646,8 @@ public class InteractionJankMonitor {
|
||||
return "PIP_TRANSITION";
|
||||
case CUJ_WALLPAPER_TRANSITION:
|
||||
return "WALLPAPER_TRANSITION";
|
||||
case CUJ_USER_SWITCH:
|
||||
return "USER_SWITCH";
|
||||
}
|
||||
return "UNKNOWN";
|
||||
}
|
||||
|
||||
@@ -90,6 +90,7 @@ import androidx.annotation.Nullable;
|
||||
import androidx.lifecycle.Observer;
|
||||
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
import com.android.internal.jank.InteractionJankMonitor;
|
||||
import com.android.internal.widget.LockPatternUtils;
|
||||
import com.android.settingslib.WirelessUtils;
|
||||
import com.android.settingslib.fuelgauge.BatteryStatus;
|
||||
@@ -321,6 +322,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
|
||||
private boolean mIsDreaming;
|
||||
private final DevicePolicyManager mDevicePolicyManager;
|
||||
private final BroadcastDispatcher mBroadcastDispatcher;
|
||||
private final InteractionJankMonitor mInteractionJankMonitor;
|
||||
private boolean mLogoutEnabled;
|
||||
// cached value to avoid IPCs
|
||||
private boolean mIsUdfpsEnrolled;
|
||||
@@ -1770,6 +1772,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
|
||||
AuthController authController,
|
||||
TelephonyListenerManager telephonyListenerManager,
|
||||
FeatureFlags featureFlags,
|
||||
InteractionJankMonitor interactionJankMonitor,
|
||||
@Nullable Vibrator vibrator) {
|
||||
mContext = context;
|
||||
mSubscriptionManager = SubscriptionManager.from(context);
|
||||
@@ -1778,6 +1781,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
|
||||
mStrongAuthTracker = new StrongAuthTracker(context, this::notifyStrongAuthStateChanged);
|
||||
mBackgroundExecutor = backgroundExecutor;
|
||||
mBroadcastDispatcher = broadcastDispatcher;
|
||||
mInteractionJankMonitor = interactionJankMonitor;
|
||||
mRingerModeTracker = ringerModeTracker;
|
||||
mStatusBarStateController = statusBarStateController;
|
||||
mStatusBarStateController.addCallback(mStatusBarStateControllerListener);
|
||||
@@ -2637,7 +2641,8 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
|
||||
/**
|
||||
* Handle {@link #MSG_USER_SWITCH_COMPLETE}
|
||||
*/
|
||||
private void handleUserSwitchComplete(int userId) {
|
||||
@VisibleForTesting
|
||||
void handleUserSwitchComplete(int userId) {
|
||||
Assert.isMainThread();
|
||||
for (int i = 0; i < mCallbacks.size(); i++) {
|
||||
KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
|
||||
@@ -2645,6 +2650,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
|
||||
cb.onUserSwitchComplete(userId);
|
||||
}
|
||||
}
|
||||
mInteractionJankMonitor.end(InteractionJankMonitor.CUJ_USER_SWITCH);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -74,6 +74,7 @@ import android.view.inputmethod.InputMethodManager;
|
||||
|
||||
import com.android.internal.app.IBatteryStats;
|
||||
import com.android.internal.appwidget.IAppWidgetService;
|
||||
import com.android.internal.jank.InteractionJankMonitor;
|
||||
import com.android.internal.statusbar.IStatusBarService;
|
||||
import com.android.internal.util.LatencyTracker;
|
||||
import com.android.systemui.dagger.qualifiers.DisplayId;
|
||||
@@ -218,6 +219,12 @@ public class FrameworkServicesModule {
|
||||
return context.getSystemService(FingerprintManager.class);
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
static InteractionJankMonitor provideInteractionJankMonitor() {
|
||||
return InteractionJankMonitor.getInstance();
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
static InputMethodManager provideInputMethodManager(Context context) {
|
||||
|
||||
@@ -1139,6 +1139,8 @@ public class StatusBar extends SystemUI implements
|
||||
mNotificationPanelViewController.addExpansionListener(
|
||||
this::dispatchPanelExpansionForKeyguardDismiss);
|
||||
|
||||
mUserSwitcherController.init(mNotificationShadeWindowView);
|
||||
|
||||
// Allow plugins to reference DarkIconDispatcher and StatusBarStateController
|
||||
mPluginDependencyProvider.allowPluginDependency(DarkIconDispatcher.class);
|
||||
mPluginDependencyProvider.allowPluginDependency(StatusBarStateController.class);
|
||||
|
||||
@@ -25,6 +25,7 @@ import android.annotation.UserIdInt;
|
||||
import android.app.ActivityManager;
|
||||
import android.app.AlertDialog;
|
||||
import android.app.Dialog;
|
||||
import android.app.IActivityManager;
|
||||
import android.app.IActivityTaskManager;
|
||||
import android.app.admin.DevicePolicyManager;
|
||||
import android.content.BroadcastReceiver;
|
||||
@@ -55,6 +56,7 @@ import android.view.WindowManagerGlobal;
|
||||
import android.widget.BaseAdapter;
|
||||
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
import com.android.internal.jank.InteractionJankMonitor;
|
||||
import com.android.internal.logging.UiEventLogger;
|
||||
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
|
||||
import com.android.settingslib.RestrictedLockUtilsInternal;
|
||||
@@ -75,6 +77,7 @@ import com.android.systemui.plugins.qs.DetailAdapter;
|
||||
import com.android.systemui.qs.QSUserSwitcherEvent;
|
||||
import com.android.systemui.qs.tiles.UserDetailView;
|
||||
import com.android.systemui.settings.UserTracker;
|
||||
import com.android.systemui.statusbar.phone.NotificationShadeWindowView;
|
||||
import com.android.systemui.statusbar.phone.SystemUIDialog;
|
||||
import com.android.systemui.telephony.TelephonyListenerManager;
|
||||
import com.android.systemui.user.CreateUserActivity;
|
||||
@@ -107,6 +110,7 @@ public class UserSwitcherController implements Dumpable {
|
||||
private static final int PAUSE_REFRESH_USERS_TIMEOUT_MS = 3000;
|
||||
|
||||
private static final String PERMISSION_SELF = "com.android.systemui.permission.SELF";
|
||||
private static final long MULTI_USER_JOURNEY_TIMEOUT = 20000l;
|
||||
|
||||
protected final Context mContext;
|
||||
protected final UserTracker mUserTracker;
|
||||
@@ -123,6 +127,7 @@ public class UserSwitcherController implements Dumpable {
|
||||
private final BroadcastDispatcher mBroadcastDispatcher;
|
||||
private final TelephonyListenerManager mTelephonyListenerManager;
|
||||
private final IActivityTaskManager mActivityTaskManager;
|
||||
private final InteractionJankMonitor mInteractionJankMonitor;
|
||||
|
||||
private ArrayList<UserRecord> mUsers = new ArrayList<>();
|
||||
@VisibleForTesting
|
||||
@@ -141,15 +146,18 @@ public class UserSwitcherController implements Dumpable {
|
||||
private Intent mSecondaryUserServiceIntent;
|
||||
private SparseBooleanArray mForcePictureLoadForUserId = new SparseBooleanArray(2);
|
||||
private final UiEventLogger mUiEventLogger;
|
||||
private final IActivityManager mActivityManager;
|
||||
public final DetailAdapter mUserDetailAdapter;
|
||||
private final Executor mBgExecutor;
|
||||
private final boolean mGuestUserAutoCreated;
|
||||
private final AtomicBoolean mGuestIsResetting;
|
||||
private final AtomicBoolean mGuestCreationScheduled;
|
||||
private FalsingManager mFalsingManager;
|
||||
private NotificationShadeWindowView mRootView;
|
||||
|
||||
@Inject
|
||||
public UserSwitcherController(Context context,
|
||||
IActivityManager activityManager,
|
||||
UserManager userManager,
|
||||
UserTracker userTracker,
|
||||
KeyguardStateController keyguardStateController,
|
||||
@@ -165,14 +173,17 @@ public class UserSwitcherController implements Dumpable {
|
||||
UserDetailAdapter userDetailAdapter,
|
||||
SecureSettings secureSettings,
|
||||
@Background Executor bgExecutor,
|
||||
InteractionJankMonitor interactionJankMonitor,
|
||||
DumpManager dumpManager) {
|
||||
mContext = context;
|
||||
mActivityManager = activityManager;
|
||||
mUserTracker = userTracker;
|
||||
mBroadcastDispatcher = broadcastDispatcher;
|
||||
mTelephonyListenerManager = telephonyListenerManager;
|
||||
mActivityTaskManager = activityTaskManager;
|
||||
mUiEventLogger = uiEventLogger;
|
||||
mFalsingManager = falsingManager;
|
||||
mInteractionJankMonitor = interactionJankMonitor;
|
||||
mGuestResumeSessionReceiver = new GuestResumeSessionReceiver(
|
||||
this, mUserTracker, mUiEventLogger, secureSettings);
|
||||
mUserDetailAdapter = userDetailAdapter;
|
||||
@@ -485,8 +496,11 @@ public class UserSwitcherController implements Dumpable {
|
||||
|
||||
protected void switchToUserId(int id) {
|
||||
try {
|
||||
mInteractionJankMonitor.begin(InteractionJankMonitor.Configuration.Builder
|
||||
.withView(InteractionJankMonitor.CUJ_USER_SWITCH, mRootView)
|
||||
.setTimeout(MULTI_USER_JOURNEY_TIMEOUT));
|
||||
pauseRefreshUsers();
|
||||
ActivityManager.getService().switchUser(id);
|
||||
mActivityManager.switchUser(id);
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "Couldn't switch user.", e);
|
||||
}
|
||||
@@ -793,6 +807,10 @@ public class UserSwitcherController implements Dumpable {
|
||||
return guest.id;
|
||||
}
|
||||
|
||||
public void init(NotificationShadeWindowView notificationShadeWindowView) {
|
||||
mRootView = notificationShadeWindowView;
|
||||
}
|
||||
|
||||
public static abstract class BaseUserAdapter extends BaseAdapter {
|
||||
|
||||
final UserSwitcherController mController;
|
||||
|
||||
@@ -78,6 +78,7 @@ import androidx.lifecycle.LiveData;
|
||||
import androidx.lifecycle.Observer;
|
||||
|
||||
import com.android.dx.mockito.inline.extended.ExtendedMockito;
|
||||
import com.android.internal.jank.InteractionJankMonitor;
|
||||
import com.android.internal.telephony.TelephonyIntents;
|
||||
import com.android.internal.widget.ILockSettings;
|
||||
import com.android.internal.widget.LockPatternUtils;
|
||||
@@ -171,6 +172,8 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
|
||||
@Mock
|
||||
private FeatureFlags mFeatureFlags;
|
||||
@Mock
|
||||
private InteractionJankMonitor mInteractionJankMonitor;
|
||||
@Mock
|
||||
private Vibrator mVibrator;
|
||||
@Captor
|
||||
private ArgumentCaptor<StatusBarStateController.StateListener> mStatusBarStateListenerCaptor;
|
||||
@@ -736,6 +739,16 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
|
||||
assertThat(mKeyguardUpdateMonitor.mUserFaceAuthenticated.size()).isEqualTo(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMultiUserJankMonitor_whenUserSwitches() throws Exception {
|
||||
final IRemoteCallback reply = new IRemoteCallback.Stub() {
|
||||
@Override
|
||||
public void sendResult(Bundle data) {} // do nothing
|
||||
};
|
||||
mKeyguardUpdateMonitor.handleUserSwitchComplete(10 /* user */);
|
||||
verify(mInteractionJankMonitor).end(eq(InteractionJankMonitor.CUJ_USER_SWITCH));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetUserCanSkipBouncer_whenTrust() {
|
||||
int user = KeyguardUpdateMonitor.getCurrentUser();
|
||||
@@ -1051,7 +1064,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
|
||||
mRingerModeTracker, mBackgroundExecutor,
|
||||
mStatusBarStateController, mLockPatternUtils,
|
||||
mAuthController, mTelephonyListenerManager, mFeatureFlags,
|
||||
mVibrator);
|
||||
mInteractionJankMonitor, mVibrator);
|
||||
setStrongAuthTracker(KeyguardUpdateMonitorTest.this.mStrongAuthTracker);
|
||||
}
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
package com.android.systemui.statusbar.policy
|
||||
|
||||
import android.app.IActivityManager
|
||||
import android.app.IActivityTaskManager
|
||||
import android.app.admin.DevicePolicyManager
|
||||
import android.content.Context
|
||||
@@ -31,6 +32,7 @@ import android.os.UserManager
|
||||
import android.testing.AndroidTestingRunner
|
||||
import android.testing.TestableLooper
|
||||
import androidx.test.filters.SmallTest
|
||||
import com.android.internal.jank.InteractionJankMonitor
|
||||
import com.android.internal.logging.testing.UiEventLoggerFake
|
||||
import com.android.internal.util.UserIcons
|
||||
import com.android.systemui.GuestResumeSessionReceiver
|
||||
@@ -54,10 +56,11 @@ import org.junit.runner.RunWith
|
||||
import org.mockito.ArgumentMatchers.anyInt
|
||||
import org.mockito.ArgumentMatchers.eq
|
||||
import org.mockito.Mock
|
||||
import org.mockito.Mockito.`when`
|
||||
import org.mockito.Mockito.any
|
||||
import org.mockito.Mockito.anyString
|
||||
import org.mockito.Mockito.mock
|
||||
import org.mockito.Mockito.`when`
|
||||
import org.mockito.Mockito.verify
|
||||
import org.mockito.MockitoAnnotations
|
||||
|
||||
@RunWith(AndroidTestingRunner::class)
|
||||
@@ -65,6 +68,7 @@ import org.mockito.MockitoAnnotations
|
||||
@SmallTest
|
||||
class UserSwitcherControllerTest : SysuiTestCase() {
|
||||
@Mock private lateinit var keyguardStateController: KeyguardStateController
|
||||
@Mock private lateinit var activityManager: IActivityManager
|
||||
@Mock private lateinit var deviceProvisionedController: DeviceProvisionedController
|
||||
@Mock private lateinit var devicePolicyManager: DevicePolicyManager
|
||||
@Mock private lateinit var handler: Handler
|
||||
@@ -78,6 +82,7 @@ class UserSwitcherControllerTest : SysuiTestCase() {
|
||||
@Mock private lateinit var secureSettings: SecureSettings
|
||||
@Mock private lateinit var falsingManager: FalsingManager
|
||||
@Mock private lateinit var dumpManager: DumpManager
|
||||
@Mock private lateinit var interactionJankMonitor: InteractionJankMonitor
|
||||
private lateinit var testableLooper: TestableLooper
|
||||
private lateinit var uiBgExecutor: FakeExecutor
|
||||
private lateinit var uiEventLogger: UiEventLoggerFake
|
||||
@@ -110,6 +115,7 @@ class UserSwitcherControllerTest : SysuiTestCase() {
|
||||
|
||||
userSwitcherController = UserSwitcherController(
|
||||
context,
|
||||
activityManager,
|
||||
userManager,
|
||||
userTracker,
|
||||
keyguardStateController,
|
||||
@@ -125,6 +131,7 @@ class UserSwitcherControllerTest : SysuiTestCase() {
|
||||
userDetailAdapter,
|
||||
secureSettings,
|
||||
uiBgExecutor,
|
||||
interactionJankMonitor,
|
||||
dumpManager)
|
||||
userSwitcherController.mPauseRefreshUsers = true
|
||||
|
||||
@@ -132,7 +139,7 @@ class UserSwitcherControllerTest : SysuiTestCase() {
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testAddGuest_okButtonPressed_isLogged() {
|
||||
fun testAddGuest_okButtonPressed() {
|
||||
val emptyGuestUserRecord = UserSwitcherController.UserRecord(
|
||||
null,
|
||||
null,
|
||||
@@ -148,6 +155,8 @@ class UserSwitcherControllerTest : SysuiTestCase() {
|
||||
|
||||
userSwitcherController.onUserListItemClicked(emptyGuestUserRecord)
|
||||
testableLooper.processAllMessages()
|
||||
verify(interactionJankMonitor).begin(any())
|
||||
verify(activityManager).switchUser(guestInfo.id)
|
||||
assertEquals(1, uiEventLogger.numLogs())
|
||||
assertEquals(QSUserSwitcherEvent.QS_USER_GUEST_ADD.id, uiEventLogger.eventId(0))
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user