1 /* 2 * Copyright (C) 2014 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.systemui.doze; 18 19 import android.content.Context; 20 import android.os.Build; 21 import android.util.Log; 22 import android.util.TimeUtils; 23 24 import com.android.keyguard.KeyguardUpdateMonitor; 25 import com.android.keyguard.KeyguardUpdateMonitorCallback; 26 27 import java.io.PrintWriter; 28 import java.text.SimpleDateFormat; 29 import java.util.Date; 30 31 public class DozeLog { 32 private static final String TAG = "DozeLog"; 33 private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); 34 private static final boolean ENABLED = true; 35 private static final int SIZE = Build.IS_DEBUGGABLE ? 400 : 50; 36 private static final SimpleDateFormat FORMAT = new SimpleDateFormat("MM-dd HH:mm:ss.SSS"); 37 38 private static long[] sTimes; 39 private static String[] sMessages; 40 private static int sPosition; 41 private static int sCount; 42 private static boolean sPulsing; 43 44 private static long sSince; 45 private static SummaryStats sPickupPulseNearVibrationStats; 46 private static SummaryStats sPickupPulseNotNearVibrationStats; 47 private static SummaryStats sNotificationPulseStats; 48 private static SummaryStats sScreenOnPulsingStats; 49 private static SummaryStats sScreenOnNotPulsingStats; 50 private static SummaryStats sEmergencyCallStats; 51 private static SummaryStats sProxNearStats; 52 private static SummaryStats sProxFarStats; 53 54 public static void tracePickupPulse(boolean withinVibrationThreshold) { 55 if (!ENABLED) return; 56 log("pickupPulse withinVibrationThreshold=" + withinVibrationThreshold); 57 (withinVibrationThreshold ? sPickupPulseNearVibrationStats 58 : sPickupPulseNotNearVibrationStats).append(); 59 } 60 61 public static void tracePulseStart() { 62 if (!ENABLED) return; 63 sPulsing = true; 64 log("pulseStart"); 65 } 66 67 public static void tracePulseFinish() { 68 if (!ENABLED) return; 69 sPulsing = false; 70 log("pulseFinish"); 71 } 72 73 public static void traceNotificationPulse(long instance) { 74 if (!ENABLED) return; 75 log("notificationPulse instance=" + instance); 76 sNotificationPulseStats.append(); 77 } 78 79 public static void traceDozing(Context context, boolean dozing) { 80 if (!ENABLED) return; 81 sPulsing = false; 82 synchronized (DozeLog.class) { 83 if (dozing && sMessages == null) { 84 sTimes = new long[SIZE]; 85 sMessages = new String[SIZE]; 86 sSince = System.currentTimeMillis(); 87 sPickupPulseNearVibrationStats = new SummaryStats(); 88 sPickupPulseNotNearVibrationStats = new SummaryStats(); 89 sNotificationPulseStats = new SummaryStats(); 90 sScreenOnPulsingStats = new SummaryStats(); 91 sScreenOnNotPulsingStats = new SummaryStats(); 92 sEmergencyCallStats = new SummaryStats(); 93 sProxNearStats = new SummaryStats(); 94 sProxFarStats = new SummaryStats(); 95 log("init"); 96 KeyguardUpdateMonitor.getInstance(context).registerCallback(sKeyguardCallback); 97 } 98 } 99 log("dozing " + dozing); 100 } 101 102 public static void traceFling(boolean expand, boolean aboveThreshold, boolean thresholdNeeded, 103 boolean screenOnFromTouch) { 104 if (!ENABLED) return; 105 log("fling expand=" + expand + " aboveThreshold=" + aboveThreshold + " thresholdNeeded=" 106 + thresholdNeeded + " screenOnFromTouch=" + screenOnFromTouch); 107 } 108 109 public static void traceEmergencyCall() { 110 if (!ENABLED) return; 111 log("emergencyCall"); 112 sEmergencyCallStats.append(); 113 } 114 115 public static void traceKeyguardBouncerChanged(boolean showing) { 116 if (!ENABLED) return; 117 log("bouncer " + showing); 118 } 119 120 public static void traceScreenOn() { 121 if (!ENABLED) return; 122 log("screenOn pulsing=" + sPulsing); 123 (sPulsing ? sScreenOnPulsingStats : sScreenOnNotPulsingStats).append(); 124 sPulsing = false; 125 } 126 127 public static void traceScreenOff(int why) { 128 if (!ENABLED) return; 129 log("screenOff why=" + why); 130 } 131 132 public static void traceKeyguard(boolean showing) { 133 if (!ENABLED) return; 134 log("keyguard " + showing); 135 if (!showing) { 136 sPulsing = false; 137 } 138 } 139 140 public static void traceProximityResult(boolean near, long millis) { 141 if (!ENABLED) return; 142 log("proximityResult near=" + near + " millis=" + millis); 143 (near ? sProxNearStats : sProxFarStats).append(); 144 } 145 146 public static void dump(PrintWriter pw) { 147 synchronized (DozeLog.class) { 148 if (sMessages == null) return; 149 pw.println(" Doze log:"); 150 final int start = (sPosition - sCount + SIZE) % SIZE; 151 for (int i = 0; i < sCount; i++) { 152 final int j = (start + i) % SIZE; 153 pw.print(" "); 154 pw.print(FORMAT.format(new Date(sTimes[j]))); 155 pw.print(' '); 156 pw.println(sMessages[j]); 157 } 158 pw.print(" Doze summary stats (for "); 159 TimeUtils.formatDuration(System.currentTimeMillis() - sSince, pw); 160 pw.println("):"); 161 sPickupPulseNearVibrationStats.dump(pw, "Pickup pulse (near vibration)"); 162 sPickupPulseNotNearVibrationStats.dump(pw, "Pickup pulse (not near vibration)"); 163 sNotificationPulseStats.dump(pw, "Notification pulse"); 164 sScreenOnPulsingStats.dump(pw, "Screen on (pulsing)"); 165 sScreenOnNotPulsingStats.dump(pw, "Screen on (not pulsing)"); 166 sEmergencyCallStats.dump(pw, "Emergency call"); 167 sProxNearStats.dump(pw, "Proximity (near)"); 168 sProxFarStats.dump(pw, "Proximity (far)"); 169 } 170 } 171 172 private static void log(String msg) { 173 synchronized (DozeLog.class) { 174 if (sMessages == null) return; 175 sTimes[sPosition] = System.currentTimeMillis(); 176 sMessages[sPosition] = msg; 177 sPosition = (sPosition + 1) % SIZE; 178 sCount = Math.min(sCount + 1, SIZE); 179 } 180 if (DEBUG) Log.d(TAG, msg); 181 } 182 183 private static class SummaryStats { 184 private int mCount; 185 186 public void append() { 187 mCount++; 188 } 189 190 public void dump(PrintWriter pw, String type) { 191 pw.print(" "); 192 pw.print(type); 193 pw.print(": n="); 194 pw.print(mCount); 195 pw.print(" ("); 196 final double perHr = (double) mCount / (System.currentTimeMillis() - sSince) 197 * 1000 * 60 * 60; 198 pw.print(perHr); 199 pw.print("/hr)"); 200 pw.println(); 201 } 202 } 203 204 private static final KeyguardUpdateMonitorCallback sKeyguardCallback = 205 new KeyguardUpdateMonitorCallback() { 206 @Override 207 public void onEmergencyCallAction() { 208 traceEmergencyCall(); 209 } 210 211 @Override 212 public void onKeyguardBouncerChanged(boolean bouncer) { 213 traceKeyguardBouncerChanged(bouncer); 214 } 215 216 @Override 217 public void onScreenTurnedOn() { 218 traceScreenOn(); 219 } 220 221 @Override 222 public void onScreenTurnedOff(int why) { 223 traceScreenOff(why); 224 } 225 226 @Override 227 public void onKeyguardVisibilityChanged(boolean showing) { 228 traceKeyguard(showing); 229 } 230 }; 231 } 232