Home | History | Annotate | Download | only in doze
      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     static final SimpleDateFormat FORMAT = new SimpleDateFormat("MM-dd HH:mm:ss.SSS");
     37 
     38     private static final int PULSE_REASONS = 5;
     39 
     40     public static final int PULSE_REASON_NONE = -1;
     41     public static final int PULSE_REASON_INTENT = 0;
     42     public static final int PULSE_REASON_NOTIFICATION = 1;
     43     public static final int PULSE_REASON_SENSOR_SIGMOTION = 2;
     44     public static final int PULSE_REASON_SENSOR_PICKUP = 3;
     45     public static final int PULSE_REASON_SENSOR_DOUBLE_TAP = 4;
     46 
     47     private static boolean sRegisterKeyguardCallback = true;
     48 
     49     private static long[] sTimes;
     50     private static String[] sMessages;
     51     private static int sPosition;
     52     private static int sCount;
     53     private static boolean sPulsing;
     54 
     55     private static long sSince;
     56     private static SummaryStats sPickupPulseNearVibrationStats;
     57     private static SummaryStats sPickupPulseNotNearVibrationStats;
     58     private static SummaryStats sNotificationPulseStats;
     59     private static SummaryStats sScreenOnPulsingStats;
     60     private static SummaryStats sScreenOnNotPulsingStats;
     61     private static SummaryStats sEmergencyCallStats;
     62     private static SummaryStats[][] sProxStats; // [reason][near/far]
     63 
     64     public static void tracePickupPulse(Context context, boolean withinVibrationThreshold) {
     65         if (!ENABLED) return;
     66         init(context);
     67         log("pickupPulse withinVibrationThreshold=" + withinVibrationThreshold);
     68         (withinVibrationThreshold ? sPickupPulseNearVibrationStats
     69                 : sPickupPulseNotNearVibrationStats).append();
     70     }
     71 
     72     public static void tracePulseStart(int reason) {
     73         if (!ENABLED) return;
     74         sPulsing = true;
     75         log("pulseStart reason=" + pulseReasonToString(reason));
     76     }
     77 
     78     public static void tracePulseFinish() {
     79         if (!ENABLED) return;
     80         sPulsing = false;
     81         log("pulseFinish");
     82     }
     83 
     84     public static void traceNotificationPulse(Context context) {
     85         if (!ENABLED) return;
     86         init(context);
     87         log("notificationPulse");
     88         sNotificationPulseStats.append();
     89     }
     90 
     91     private static void init(Context context) {
     92         synchronized (DozeLog.class) {
     93             if (sMessages == null) {
     94                 sTimes = new long[SIZE];
     95                 sMessages = new String[SIZE];
     96                 sSince = System.currentTimeMillis();
     97                 sPickupPulseNearVibrationStats = new SummaryStats();
     98                 sPickupPulseNotNearVibrationStats = new SummaryStats();
     99                 sNotificationPulseStats = new SummaryStats();
    100                 sScreenOnPulsingStats = new SummaryStats();
    101                 sScreenOnNotPulsingStats = new SummaryStats();
    102                 sEmergencyCallStats = new SummaryStats();
    103                 sProxStats = new SummaryStats[PULSE_REASONS][2];
    104                 for (int i = 0; i < PULSE_REASONS; i++) {
    105                     sProxStats[i][0] = new SummaryStats();
    106                     sProxStats[i][1] = new SummaryStats();
    107                 }
    108                 log("init");
    109                 if (sRegisterKeyguardCallback) {
    110                     KeyguardUpdateMonitor.getInstance(context).registerCallback(sKeyguardCallback);
    111                 }
    112             }
    113         }
    114     }
    115 
    116     public static void traceDozing(Context context, boolean dozing) {
    117         if (!ENABLED) return;
    118         sPulsing = false;
    119         init(context);
    120         log("dozing " + dozing);
    121     }
    122 
    123     public static void traceFling(boolean expand, boolean aboveThreshold, boolean thresholdNeeded,
    124             boolean screenOnFromTouch) {
    125         if (!ENABLED) return;
    126         log("fling expand=" + expand + " aboveThreshold=" + aboveThreshold + " thresholdNeeded="
    127                 + thresholdNeeded + " screenOnFromTouch=" + screenOnFromTouch);
    128     }
    129 
    130     public static void traceEmergencyCall() {
    131         if (!ENABLED) return;
    132         log("emergencyCall");
    133         sEmergencyCallStats.append();
    134     }
    135 
    136     public static void traceKeyguardBouncerChanged(boolean showing) {
    137         if (!ENABLED) return;
    138         log("bouncer " + showing);
    139     }
    140 
    141     public static void traceScreenOn() {
    142         if (!ENABLED) return;
    143         log("screenOn pulsing=" + sPulsing);
    144         (sPulsing ? sScreenOnPulsingStats : sScreenOnNotPulsingStats).append();
    145         sPulsing = false;
    146     }
    147 
    148     public static void traceScreenOff(int why) {
    149         if (!ENABLED) return;
    150         log("screenOff why=" + why);
    151     }
    152 
    153     public static void traceMissedTick(String delay) {
    154         if (!ENABLED) return;
    155         log("missedTick by=" + delay);
    156     }
    157 
    158     public static void traceKeyguard(boolean showing) {
    159         if (!ENABLED) return;
    160         log("keyguard " + showing);
    161         if (!showing) {
    162             sPulsing = false;
    163         }
    164     }
    165 
    166     public static void traceProximityResult(Context context, boolean near, long millis,
    167             int pulseReason) {
    168         if (!ENABLED) return;
    169         init(context);
    170         log("proximityResult reason=" + pulseReasonToString(pulseReason) + " near=" + near
    171                 + " millis=" + millis);
    172         sProxStats[pulseReason][near ? 0 : 1].append();
    173     }
    174 
    175     public static String pulseReasonToString(int pulseReason) {
    176         switch (pulseReason) {
    177             case PULSE_REASON_INTENT: return "intent";
    178             case PULSE_REASON_NOTIFICATION: return "notification";
    179             case PULSE_REASON_SENSOR_SIGMOTION: return "sigmotion";
    180             case PULSE_REASON_SENSOR_PICKUP: return "pickup";
    181             case PULSE_REASON_SENSOR_DOUBLE_TAP: return "doubletap";
    182             default: throw new IllegalArgumentException("bad reason: " + pulseReason);
    183         }
    184     }
    185 
    186     public static void dump(PrintWriter pw) {
    187         synchronized (DozeLog.class) {
    188             if (sMessages == null) return;
    189             pw.println("  Doze log:");
    190             final int start = (sPosition - sCount + SIZE) % SIZE;
    191             for (int i = 0; i < sCount; i++) {
    192                 final int j = (start + i) % SIZE;
    193                 pw.print("    ");
    194                 pw.print(FORMAT.format(new Date(sTimes[j])));
    195                 pw.print(' ');
    196                 pw.println(sMessages[j]);
    197             }
    198             pw.print("  Doze summary stats (for ");
    199             TimeUtils.formatDuration(System.currentTimeMillis() - sSince, pw);
    200             pw.println("):");
    201             sPickupPulseNearVibrationStats.dump(pw, "Pickup pulse (near vibration)");
    202             sPickupPulseNotNearVibrationStats.dump(pw, "Pickup pulse (not near vibration)");
    203             sNotificationPulseStats.dump(pw, "Notification pulse");
    204             sScreenOnPulsingStats.dump(pw, "Screen on (pulsing)");
    205             sScreenOnNotPulsingStats.dump(pw, "Screen on (not pulsing)");
    206             sEmergencyCallStats.dump(pw, "Emergency call");
    207             for (int i = 0; i < PULSE_REASONS; i++) {
    208                 final String reason = pulseReasonToString(i);
    209                 sProxStats[i][0].dump(pw, "Proximity near (" + reason + ")");
    210                 sProxStats[i][1].dump(pw, "Proximity far (" + reason + ")");
    211             }
    212         }
    213     }
    214 
    215     private static void log(String msg) {
    216         synchronized (DozeLog.class) {
    217             if (sMessages == null) return;
    218             sTimes[sPosition] = System.currentTimeMillis();
    219             sMessages[sPosition] = msg;
    220             sPosition = (sPosition + 1) % SIZE;
    221             sCount = Math.min(sCount + 1, SIZE);
    222         }
    223         if (DEBUG) Log.d(TAG, msg);
    224     }
    225 
    226     public static void tracePulseDropped(Context context, boolean pulsePending,
    227             DozeMachine.State state, boolean blocked) {
    228         if (!ENABLED) return;
    229         init(context);
    230         log("pulseDropped pulsePending=" + pulsePending + " state="
    231                 + state + " blocked=" + blocked);
    232     }
    233 
    234     public static void tracePulseCanceledByProx(Context context) {
    235         if (!ENABLED) return;
    236         init(context);
    237         log("pulseCanceledByProx");
    238     }
    239 
    240     public static void setRegisterKeyguardCallback(boolean registerKeyguardCallback) {
    241         if (!ENABLED) return;
    242         synchronized (DozeLog.class) {
    243             if (sRegisterKeyguardCallback != registerKeyguardCallback && sMessages != null) {
    244                 throw new IllegalStateException("Cannot change setRegisterKeyguardCallback "
    245                         + "after init()");
    246             }
    247             sRegisterKeyguardCallback = registerKeyguardCallback;
    248         }
    249     }
    250 
    251     private static class SummaryStats {
    252         private int mCount;
    253 
    254         public void append() {
    255             mCount++;
    256         }
    257 
    258         public void dump(PrintWriter pw, String type) {
    259             if (mCount == 0) return;
    260             pw.print("    ");
    261             pw.print(type);
    262             pw.print(": n=");
    263             pw.print(mCount);
    264             pw.print(" (");
    265             final double perHr = (double) mCount / (System.currentTimeMillis() - sSince)
    266                     * 1000 * 60 * 60;
    267             pw.print(perHr);
    268             pw.print("/hr)");
    269             pw.println();
    270         }
    271     }
    272 
    273     private static final KeyguardUpdateMonitorCallback sKeyguardCallback =
    274             new KeyguardUpdateMonitorCallback() {
    275         @Override
    276         public void onEmergencyCallAction() {
    277             traceEmergencyCall();
    278         }
    279 
    280         @Override
    281         public void onKeyguardBouncerChanged(boolean bouncer) {
    282             traceKeyguardBouncerChanged(bouncer);
    283         }
    284 
    285         @Override
    286         public void onStartedWakingUp() {
    287             traceScreenOn();
    288         }
    289 
    290         @Override
    291         public void onFinishedGoingToSleep(int why) {
    292             traceScreenOff(why);
    293         }
    294 
    295         @Override
    296         public void onKeyguardVisibilityChanged(boolean showing) {
    297             traceKeyguard(showing);
    298         }
    299     };
    300 }
    301