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