1e05256e2a1edf6f57f9fb48ef4f98dc4261ab8a7Jorim Jaggi/* 2ea03be1056d44328b96559702791bdac2a466002Jason Monk * Copyright (C) 2017 The Android Open Source Project 3e05256e2a1edf6f57f9fb48ef4f98dc4261ab8a7Jorim Jaggi * 4ea03be1056d44328b96559702791bdac2a466002Jason Monk * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file 5ea03be1056d44328b96559702791bdac2a466002Jason Monk * except in compliance with the License. You may obtain a copy of the License at 6e05256e2a1edf6f57f9fb48ef4f98dc4261ab8a7Jorim Jaggi * 7e05256e2a1edf6f57f9fb48ef4f98dc4261ab8a7Jorim Jaggi * http://www.apache.org/licenses/LICENSE-2.0 8e05256e2a1edf6f57f9fb48ef4f98dc4261ab8a7Jorim Jaggi * 9ea03be1056d44328b96559702791bdac2a466002Jason Monk * Unless required by applicable law or agreed to in writing, software distributed under the 10ea03be1056d44328b96559702791bdac2a466002Jason Monk * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 11ea03be1056d44328b96559702791bdac2a466002Jason Monk * KIND, either express or implied. See the License for the specific language governing 12ea03be1056d44328b96559702791bdac2a466002Jason Monk * permissions and limitations under the License. 13e05256e2a1edf6f57f9fb48ef4f98dc4261ab8a7Jorim Jaggi */ 14e05256e2a1edf6f57f9fb48ef4f98dc4261ab8a7Jorim Jaggi 15ea03be1056d44328b96559702791bdac2a466002Jason Monkpackage com.android.internal.util; 16e05256e2a1edf6f57f9fb48ef4f98dc4261ab8a7Jorim Jaggi 17e05256e2a1edf6f57f9fb48ef4f98dc4261ab8a7Jorim Jaggiimport android.content.BroadcastReceiver; 18e05256e2a1edf6f57f9fb48ef4f98dc4261ab8a7Jorim Jaggiimport android.content.Context; 19e05256e2a1edf6f57f9fb48ef4f98dc4261ab8a7Jorim Jaggiimport android.content.Intent; 20e05256e2a1edf6f57f9fb48ef4f98dc4261ab8a7Jorim Jaggiimport android.content.IntentFilter; 21e05256e2a1edf6f57f9fb48ef4f98dc4261ab8a7Jorim Jaggiimport android.os.Build; 22e05256e2a1edf6f57f9fb48ef4f98dc4261ab8a7Jorim Jaggiimport android.os.SystemClock; 23e05256e2a1edf6f57f9fb48ef4f98dc4261ab8a7Jorim Jaggiimport android.os.SystemProperties; 24e05256e2a1edf6f57f9fb48ef4f98dc4261ab8a7Jorim Jaggiimport android.os.Trace; 258ec75fbef3473e6ca7b46c832319fd11503fc188Jorim Jaggiimport android.util.EventLog; 26e05256e2a1edf6f57f9fb48ef4f98dc4261ab8a7Jorim Jaggiimport android.util.Log; 27e05256e2a1edf6f57f9fb48ef4f98dc4261ab8a7Jorim Jaggiimport android.util.SparseLongArray; 28e05256e2a1edf6f57f9fb48ef4f98dc4261ab8a7Jorim Jaggi 29ea03be1056d44328b96559702791bdac2a466002Jason Monkimport com.android.internal.logging.EventLogTags; 30d05651790af7c3dced153876de6db00366f9f9e5Jorim Jaggi 31e05256e2a1edf6f57f9fb48ef4f98dc4261ab8a7Jorim Jaggi/** 32e05256e2a1edf6f57f9fb48ef4f98dc4261ab8a7Jorim Jaggi * Class to track various latencies in SystemUI. It then outputs the latency to logcat so these 33e05256e2a1edf6f57f9fb48ef4f98dc4261ab8a7Jorim Jaggi * latencies can be captured by tests and then used for dashboards. 34d05651790af7c3dced153876de6db00366f9f9e5Jorim Jaggi * <p> 35d05651790af7c3dced153876de6db00366f9f9e5Jorim Jaggi * This is currently only in Keyguard so it can be shared between SystemUI and Keyguard, but 36d05651790af7c3dced153876de6db00366f9f9e5Jorim Jaggi * eventually we'd want to merge these two packages together so Keyguard can use common classes 37d05651790af7c3dced153876de6db00366f9f9e5Jorim Jaggi * that are shared with SystemUI. 38e05256e2a1edf6f57f9fb48ef4f98dc4261ab8a7Jorim Jaggi */ 39e05256e2a1edf6f57f9fb48ef4f98dc4261ab8a7Jorim Jaggipublic class LatencyTracker { 40e05256e2a1edf6f57f9fb48ef4f98dc4261ab8a7Jorim Jaggi 41e05256e2a1edf6f57f9fb48ef4f98dc4261ab8a7Jorim Jaggi private static final String ACTION_RELOAD_PROPERTY = 42e05256e2a1edf6f57f9fb48ef4f98dc4261ab8a7Jorim Jaggi "com.android.systemui.RELOAD_LATENCY_TRACKER_PROPERTY"; 43e05256e2a1edf6f57f9fb48ef4f98dc4261ab8a7Jorim Jaggi 44e05256e2a1edf6f57f9fb48ef4f98dc4261ab8a7Jorim Jaggi private static final String TAG = "LatencyTracker"; 45e05256e2a1edf6f57f9fb48ef4f98dc4261ab8a7Jorim Jaggi 468adb30ccbc4e8a13771368872454e33abd0bc011Jorim Jaggi /** 478adb30ccbc4e8a13771368872454e33abd0bc011Jorim Jaggi * Time it takes until the first frame of the notification panel to be displayed while expanding 488adb30ccbc4e8a13771368872454e33abd0bc011Jorim Jaggi */ 49e05256e2a1edf6f57f9fb48ef4f98dc4261ab8a7Jorim Jaggi public static final int ACTION_EXPAND_PANEL = 0; 508adb30ccbc4e8a13771368872454e33abd0bc011Jorim Jaggi 518adb30ccbc4e8a13771368872454e33abd0bc011Jorim Jaggi /** 528adb30ccbc4e8a13771368872454e33abd0bc011Jorim Jaggi * Time it takes until the first frame of recents is drawn after invoking it with the button. 538adb30ccbc4e8a13771368872454e33abd0bc011Jorim Jaggi */ 54e05256e2a1edf6f57f9fb48ef4f98dc4261ab8a7Jorim Jaggi public static final int ACTION_TOGGLE_RECENTS = 1; 55e05256e2a1edf6f57f9fb48ef4f98dc4261ab8a7Jorim Jaggi 568adb30ccbc4e8a13771368872454e33abd0bc011Jorim Jaggi /** 578adb30ccbc4e8a13771368872454e33abd0bc011Jorim Jaggi * Time between we get a fingerprint acquired signal until we start with the unlock animation 588adb30ccbc4e8a13771368872454e33abd0bc011Jorim Jaggi */ 598adb30ccbc4e8a13771368872454e33abd0bc011Jorim Jaggi public static final int ACTION_FINGERPRINT_WAKE_AND_UNLOCK = 2; 608adb30ccbc4e8a13771368872454e33abd0bc011Jorim Jaggi 61d05651790af7c3dced153876de6db00366f9f9e5Jorim Jaggi /** 62d05651790af7c3dced153876de6db00366f9f9e5Jorim Jaggi * Time it takes to check PIN/Pattern/Password. 63d05651790af7c3dced153876de6db00366f9f9e5Jorim Jaggi */ 64d05651790af7c3dced153876de6db00366f9f9e5Jorim Jaggi public static final int ACTION_CHECK_CREDENTIAL = 3; 65d05651790af7c3dced153876de6db00366f9f9e5Jorim Jaggi 66d05651790af7c3dced153876de6db00366f9f9e5Jorim Jaggi /** 67d05651790af7c3dced153876de6db00366f9f9e5Jorim Jaggi * Time it takes to check fully PIN/Pattern/Password, i.e. that's the time spent including the 68d05651790af7c3dced153876de6db00366f9f9e5Jorim Jaggi * actions to unlock a user. 69d05651790af7c3dced153876de6db00366f9f9e5Jorim Jaggi */ 70d05651790af7c3dced153876de6db00366f9f9e5Jorim Jaggi public static final int ACTION_CHECK_CREDENTIAL_UNLOCKED = 4; 71d05651790af7c3dced153876de6db00366f9f9e5Jorim Jaggi 72c3fe204780fb99b1d2563a9e4bb6c082b7517aedJorim Jaggi /** 73c3fe204780fb99b1d2563a9e4bb6c082b7517aedJorim Jaggi * Time it takes to turn on the screen. 74c3fe204780fb99b1d2563a9e4bb6c082b7517aedJorim Jaggi */ 75c3fe204780fb99b1d2563a9e4bb6c082b7517aedJorim Jaggi public static final int ACTION_TURN_ON_SCREEN = 5; 76c3fe204780fb99b1d2563a9e4bb6c082b7517aedJorim Jaggi 77ea03be1056d44328b96559702791bdac2a466002Jason Monk /** 78ea03be1056d44328b96559702791bdac2a466002Jason Monk * Time it takes to rotate the screen. 79ea03be1056d44328b96559702791bdac2a466002Jason Monk */ 80ea03be1056d44328b96559702791bdac2a466002Jason Monk public static final int ACTION_ROTATE_SCREEN = 6; 81ea03be1056d44328b96559702791bdac2a466002Jason Monk 82e05256e2a1edf6f57f9fb48ef4f98dc4261ab8a7Jorim Jaggi private static final String[] NAMES = new String[] { 83e05256e2a1edf6f57f9fb48ef4f98dc4261ab8a7Jorim Jaggi "expand panel", 848adb30ccbc4e8a13771368872454e33abd0bc011Jorim Jaggi "toggle recents", 85d05651790af7c3dced153876de6db00366f9f9e5Jorim Jaggi "fingerprint wake-and-unlock", 86d05651790af7c3dced153876de6db00366f9f9e5Jorim Jaggi "check credential", 87c3fe204780fb99b1d2563a9e4bb6c082b7517aedJorim Jaggi "check credential unlocked", 88ea03be1056d44328b96559702791bdac2a466002Jason Monk "turn on screen", 89ea03be1056d44328b96559702791bdac2a466002Jason Monk "rotate the screen"}; 90e05256e2a1edf6f57f9fb48ef4f98dc4261ab8a7Jorim Jaggi 91e05256e2a1edf6f57f9fb48ef4f98dc4261ab8a7Jorim Jaggi private static LatencyTracker sLatencyTracker; 92e05256e2a1edf6f57f9fb48ef4f98dc4261ab8a7Jorim Jaggi 93e05256e2a1edf6f57f9fb48ef4f98dc4261ab8a7Jorim Jaggi private final SparseLongArray mStartRtc = new SparseLongArray(); 94e05256e2a1edf6f57f9fb48ef4f98dc4261ab8a7Jorim Jaggi private boolean mEnabled; 95e05256e2a1edf6f57f9fb48ef4f98dc4261ab8a7Jorim Jaggi 96e05256e2a1edf6f57f9fb48ef4f98dc4261ab8a7Jorim Jaggi public static LatencyTracker getInstance(Context context) { 97e05256e2a1edf6f57f9fb48ef4f98dc4261ab8a7Jorim Jaggi if (sLatencyTracker == null) { 98e05256e2a1edf6f57f9fb48ef4f98dc4261ab8a7Jorim Jaggi sLatencyTracker = new LatencyTracker(context); 99e05256e2a1edf6f57f9fb48ef4f98dc4261ab8a7Jorim Jaggi } 100e05256e2a1edf6f57f9fb48ef4f98dc4261ab8a7Jorim Jaggi return sLatencyTracker; 101e05256e2a1edf6f57f9fb48ef4f98dc4261ab8a7Jorim Jaggi } 102e05256e2a1edf6f57f9fb48ef4f98dc4261ab8a7Jorim Jaggi 103e05256e2a1edf6f57f9fb48ef4f98dc4261ab8a7Jorim Jaggi private LatencyTracker(Context context) { 104e05256e2a1edf6f57f9fb48ef4f98dc4261ab8a7Jorim Jaggi context.registerReceiver(new BroadcastReceiver() { 105e05256e2a1edf6f57f9fb48ef4f98dc4261ab8a7Jorim Jaggi @Override 106e05256e2a1edf6f57f9fb48ef4f98dc4261ab8a7Jorim Jaggi public void onReceive(Context context, Intent intent) { 107e05256e2a1edf6f57f9fb48ef4f98dc4261ab8a7Jorim Jaggi reloadProperty(); 108e05256e2a1edf6f57f9fb48ef4f98dc4261ab8a7Jorim Jaggi } 109e05256e2a1edf6f57f9fb48ef4f98dc4261ab8a7Jorim Jaggi }, new IntentFilter(ACTION_RELOAD_PROPERTY)); 110e05256e2a1edf6f57f9fb48ef4f98dc4261ab8a7Jorim Jaggi reloadProperty(); 111e05256e2a1edf6f57f9fb48ef4f98dc4261ab8a7Jorim Jaggi } 112e05256e2a1edf6f57f9fb48ef4f98dc4261ab8a7Jorim Jaggi 113e05256e2a1edf6f57f9fb48ef4f98dc4261ab8a7Jorim Jaggi private void reloadProperty() { 114e05256e2a1edf6f57f9fb48ef4f98dc4261ab8a7Jorim Jaggi mEnabled = SystemProperties.getBoolean("debug.systemui.latency_tracking", false); 115e05256e2a1edf6f57f9fb48ef4f98dc4261ab8a7Jorim Jaggi } 116e05256e2a1edf6f57f9fb48ef4f98dc4261ab8a7Jorim Jaggi 117e05256e2a1edf6f57f9fb48ef4f98dc4261ab8a7Jorim Jaggi public static boolean isEnabled(Context ctx) { 118e05256e2a1edf6f57f9fb48ef4f98dc4261ab8a7Jorim Jaggi return Build.IS_DEBUGGABLE && getInstance(ctx).mEnabled; 119e05256e2a1edf6f57f9fb48ef4f98dc4261ab8a7Jorim Jaggi } 120e05256e2a1edf6f57f9fb48ef4f98dc4261ab8a7Jorim Jaggi 121e05256e2a1edf6f57f9fb48ef4f98dc4261ab8a7Jorim Jaggi /** 122e05256e2a1edf6f57f9fb48ef4f98dc4261ab8a7Jorim Jaggi * Notifies that an action is starting. This needs to be called from the main thread. 123e05256e2a1edf6f57f9fb48ef4f98dc4261ab8a7Jorim Jaggi * 124e05256e2a1edf6f57f9fb48ef4f98dc4261ab8a7Jorim Jaggi * @param action The action to start. One of the ACTION_* values. 125e05256e2a1edf6f57f9fb48ef4f98dc4261ab8a7Jorim Jaggi */ 126e05256e2a1edf6f57f9fb48ef4f98dc4261ab8a7Jorim Jaggi public void onActionStart(int action) { 127e05256e2a1edf6f57f9fb48ef4f98dc4261ab8a7Jorim Jaggi if (!mEnabled) { 128e05256e2a1edf6f57f9fb48ef4f98dc4261ab8a7Jorim Jaggi return; 129e05256e2a1edf6f57f9fb48ef4f98dc4261ab8a7Jorim Jaggi } 130e05256e2a1edf6f57f9fb48ef4f98dc4261ab8a7Jorim Jaggi Trace.asyncTraceBegin(Trace.TRACE_TAG_APP, NAMES[action], 0); 131e05256e2a1edf6f57f9fb48ef4f98dc4261ab8a7Jorim Jaggi mStartRtc.put(action, SystemClock.elapsedRealtime()); 132e05256e2a1edf6f57f9fb48ef4f98dc4261ab8a7Jorim Jaggi } 133e05256e2a1edf6f57f9fb48ef4f98dc4261ab8a7Jorim Jaggi 134e05256e2a1edf6f57f9fb48ef4f98dc4261ab8a7Jorim Jaggi /** 135e05256e2a1edf6f57f9fb48ef4f98dc4261ab8a7Jorim Jaggi * Notifies that an action has ended. This needs to be called from the main thread. 136e05256e2a1edf6f57f9fb48ef4f98dc4261ab8a7Jorim Jaggi * 137e05256e2a1edf6f57f9fb48ef4f98dc4261ab8a7Jorim Jaggi * @param action The action to end. One of the ACTION_* values. 138e05256e2a1edf6f57f9fb48ef4f98dc4261ab8a7Jorim Jaggi */ 139e05256e2a1edf6f57f9fb48ef4f98dc4261ab8a7Jorim Jaggi public void onActionEnd(int action) { 140e05256e2a1edf6f57f9fb48ef4f98dc4261ab8a7Jorim Jaggi if (!mEnabled) { 141e05256e2a1edf6f57f9fb48ef4f98dc4261ab8a7Jorim Jaggi return; 142e05256e2a1edf6f57f9fb48ef4f98dc4261ab8a7Jorim Jaggi } 143e05256e2a1edf6f57f9fb48ef4f98dc4261ab8a7Jorim Jaggi long endRtc = SystemClock.elapsedRealtime(); 144e05256e2a1edf6f57f9fb48ef4f98dc4261ab8a7Jorim Jaggi long startRtc = mStartRtc.get(action, -1); 145e05256e2a1edf6f57f9fb48ef4f98dc4261ab8a7Jorim Jaggi if (startRtc == -1) { 146e05256e2a1edf6f57f9fb48ef4f98dc4261ab8a7Jorim Jaggi return; 147e05256e2a1edf6f57f9fb48ef4f98dc4261ab8a7Jorim Jaggi } 14896a153a3f1a833b32f9ae5f04448559af79ec52aJorim Jaggi mStartRtc.delete(action); 149e05256e2a1edf6f57f9fb48ef4f98dc4261ab8a7Jorim Jaggi Trace.asyncTraceEnd(Trace.TRACE_TAG_APP, NAMES[action], 0); 1502f4d2af93a25020175ff93f7fb6088b7360ef413Vadim Tryshev logAction(action, (int)(endRtc - startRtc)); 1512f4d2af93a25020175ff93f7fb6088b7360ef413Vadim Tryshev } 1522f4d2af93a25020175ff93f7fb6088b7360ef413Vadim Tryshev 1532f4d2af93a25020175ff93f7fb6088b7360ef413Vadim Tryshev /** 1542f4d2af93a25020175ff93f7fb6088b7360ef413Vadim Tryshev * Logs an action that has started and ended. This needs to be called from the main thread. 1552f4d2af93a25020175ff93f7fb6088b7360ef413Vadim Tryshev * 1562f4d2af93a25020175ff93f7fb6088b7360ef413Vadim Tryshev * @param action The action to end. One of the ACTION_* values. 1572f4d2af93a25020175ff93f7fb6088b7360ef413Vadim Tryshev * @param duration The duration of the action in ms. 1582f4d2af93a25020175ff93f7fb6088b7360ef413Vadim Tryshev */ 1592f4d2af93a25020175ff93f7fb6088b7360ef413Vadim Tryshev public static void logAction(int action, int duration) { 160e05256e2a1edf6f57f9fb48ef4f98dc4261ab8a7Jorim Jaggi Log.i(TAG, "action=" + action + " latency=" + duration); 1612f4d2af93a25020175ff93f7fb6088b7360ef413Vadim Tryshev EventLog.writeEvent(EventLogTags.SYSUI_LATENCY, action, duration); 162e05256e2a1edf6f57f9fb48ef4f98dc4261ab8a7Jorim Jaggi } 163e05256e2a1edf6f57f9fb48ef4f98dc4261ab8a7Jorim Jaggi} 164