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     public static final int REASONS = 10;
     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 REASON_SENSOR_PICKUP = 3;
     45     public static final int REASON_SENSOR_DOUBLE_TAP = 4;
     46     public static final int PULSE_REASON_SENSOR_LONG_PRESS = 5;
     47     public static final int PULSE_REASON_DOCKING = 6;
     48     public static final int REASON_SENSOR_WAKE_UP = 7;
     49     public static final int PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN = 8;
     50     public static final int REASON_SENSOR_TAP = 9;
     51 
     52     private static boolean sRegisterKeyguardCallback = true;
     53 
     54     private static long[] sTimes;
     55     private static String[] sMessages;
     56     private static int sPosition;
     57     private static int sCount;
     58     private static boolean sPulsing;
     59 
     60     private static long sSince;
     61     private static SummaryStats sPickupPulseNearVibrationStats;
     62     private static SummaryStats sPickupPulseNotNearVibrationStats;
     63     private static SummaryStats sNotificationPulseStats;
     64     private static SummaryStats sScreenOnPulsingStats;
     65     private static SummaryStats sScreenOnNotPulsingStats;
     66     private static SummaryStats sEmergencyCallStats;
     67     private static SummaryStats[][] sProxStats; // [reason][near/far]
     68 
     69     public static void tracePickupWakeUp(Context context, boolean withinVibrationThreshold) {
     70         if (!ENABLED) return;
     71         init(context);
     72         log("pickupWakeUp withinVibrationThreshold=" + withinVibrationThreshold);
     73         (withinVibrationThreshold ? sPickupPulseNearVibrationStats
     74                 : sPickupPulseNotNearVibrationStats).append();
     75     }
     76 
     77     public static void tracePulseStart(int reason) {
     78         if (!ENABLED) return;
     79         sPulsing = true;
     80         log("pulseStart reason=" + reasonToString(reason));
     81     }
     82 
     83     public static void tracePulseFinish() {
     84         if (!ENABLED) return;
     85         sPulsing = false;
     86         log("pulseFinish");
     87     }
     88 
     89     public static void traceNotificationPulse(Context context) {
     90         if (!ENABLED) return;
     91         init(context);
     92         log("notificationPulse");
     93         sNotificationPulseStats.append();
     94     }
     95 
     96     private static void init(Context context) {
     97         synchronized (DozeLog.class) {
     98             if (sMessages == null) {
     99                 sTimes = new long[SIZE];
    100                 sMessages = new String[SIZE];
    101                 sSince = System.currentTimeMillis();
    102                 sPickupPulseNearVibrationStats = new SummaryStats();
    103                 sPickupPulseNotNearVibrationStats = new SummaryStats();
    104                 sNotificationPulseStats = new SummaryStats();
    105                 sScreenOnPulsingStats = new SummaryStats();
    106                 sScreenOnNotPulsingStats = new SummaryStats();
    107                 sEmergencyCallStats = new SummaryStats();
    108                 sProxStats = new SummaryStats[REASONS][2];
    109                 for (int i = 0; i < REASONS; i++) {
    110                     sProxStats[i][0] = new SummaryStats();
    111                     sProxStats[i][1] = new SummaryStats();
    112                 }
    113                 log("init");
    114                 if (sRegisterKeyguardCallback) {
    115                     KeyguardUpdateMonitor.getInstance(context).registerCallback(sKeyguardCallback);
    116                 }
    117             }
    118         }
    119     }
    120 
    121     public static void traceDozing(Context context, boolean dozing) {
    122         if (!ENABLED) return;
    123         sPulsing = false;
    124         init(context);
    125         log("dozing " + dozing);
    126     }
    127 
    128     public static void traceFling(boolean expand, boolean aboveThreshold, boolean thresholdNeeded,
    129             boolean screenOnFromTouch) {
    130         if (!ENABLED) return;
    131         log("fling expand=" + expand + " aboveThreshold=" + aboveThreshold + " thresholdNeeded="
    132                 + thresholdNeeded + " screenOnFromTouch=" + screenOnFromTouch);
    133     }
    134 
    135     public static void traceEmergencyCall() {
    136         if (!ENABLED) return;
    137         log("emergencyCall");
    138         sEmergencyCallStats.append();
    139     }
    140 
    141     public static void traceKeyguardBouncerChanged(boolean showing) {
    142         if (!ENABLED) return;
    143         log("bouncer " + showing);
    144     }
    145 
    146     public static void traceScreenOn() {
    147         if (!ENABLED) return;
    148         log("screenOn pulsing=" + sPulsing);
    149         (sPulsing ? sScreenOnPulsingStats : sScreenOnNotPulsingStats).append();
    150         sPulsing = false;
    151     }
    152 
    153     public static void traceScreenOff(int why) {
    154         if (!ENABLED) return;
    155         log("screenOff why=" + why);
    156     }
    157 
    158     public static void traceMissedTick(String delay) {
    159         if (!ENABLED) return;
    160         log("missedTick by=" + delay);
    161     }
    162 
    163     public static void traceTimeTickScheduled(long when, long triggerAt) {
    164         if (!ENABLED) return;
    165         log("timeTickScheduled at=" + FORMAT.format(new Date(when)) + " triggerAt="
    166                 + FORMAT.format(new Date(triggerAt)));
    167     }
    168 
    169     public static void traceKeyguard(boolean showing) {
    170         if (!ENABLED) return;
    171         log("keyguard " + showing);
    172         if (!showing) {
    173             sPulsing = false;
    174         }
    175     }
    176 
    177     public static void traceState(DozeMachine.State state) {
    178         if (!ENABLED) return;
    179         log("state " + state);
    180     }
    181 
    182     /**
    183      * Appends wake-display event to the logs.
    184      * @param wake if we're waking up or sleeping.
    185      */
    186     public static void traceWakeDisplay(boolean wake) {
    187         if (!ENABLED) return;
    188         log("wakeDisplay " + wake);
    189     }
    190 
    191     public static void traceProximityResult(Context context, boolean near, long millis,
    192             int reason) {
    193         if (!ENABLED) return;
    194         init(context);
    195         log("proximityResult reason=" + reasonToString(reason) + " near=" + near
    196                 + " millis=" + millis);
    197         sProxStats[reason][near ? 0 : 1].append();
    198     }
    199 
    200     public static String reasonToString(int pulseReason) {
    201         switch (pulseReason) {
    202             case PULSE_REASON_INTENT: return "intent";
    203             case PULSE_REASON_NOTIFICATION: return "notification";
    204             case PULSE_REASON_SENSOR_SIGMOTION: return "sigmotion";
    205             case REASON_SENSOR_PICKUP: return "pickup";
    206             case REASON_SENSOR_DOUBLE_TAP: return "doubletap";
    207             case PULSE_REASON_SENSOR_LONG_PRESS: return "longpress";
    208             case PULSE_REASON_DOCKING: return "docking";
    209             case PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN: return "wakelockscreen";
    210             case REASON_SENSOR_WAKE_UP: return "wakeup";
    211             case REASON_SENSOR_TAP: return "tap";
    212             default: throw new IllegalArgumentException("bad reason: " + pulseReason);
    213         }
    214     }
    215 
    216     public static void dump(PrintWriter pw) {
    217         synchronized (DozeLog.class) {
    218             if (sMessages == null) return;
    219             pw.println("  Doze log:");
    220             final int start = (sPosition - sCount + SIZE) % SIZE;
    221             for (int i = 0; i < sCount; i++) {
    222                 final int j = (start + i) % SIZE;
    223                 pw.print("    ");
    224                 pw.print(FORMAT.format(new Date(sTimes[j])));
    225                 pw.print(' ');
    226                 pw.println(sMessages[j]);
    227             }
    228             pw.print("  Doze summary stats (for ");
    229             TimeUtils.formatDuration(System.currentTimeMillis() - sSince, pw);
    230             pw.println("):");
    231             sPickupPulseNearVibrationStats.dump(pw, "Pickup pulse (near vibration)");
    232             sPickupPulseNotNearVibrationStats.dump(pw, "Pickup pulse (not near vibration)");
    233             sNotificationPulseStats.dump(pw, "Notification pulse");
    234             sScreenOnPulsingStats.dump(pw, "Screen on (pulsing)");
    235             sScreenOnNotPulsingStats.dump(pw, "Screen on (not pulsing)");
    236             sEmergencyCallStats.dump(pw, "Emergency call");
    237             for (int i = 0; i < REASONS; i++) {
    238                 final String reason = reasonToString(i);
    239                 sProxStats[i][0].dump(pw, "Proximity near (" + reason + ")");
    240                 sProxStats[i][1].dump(pw, "Proximity far (" + reason + ")");
    241             }
    242         }
    243     }
    244 
    245     private static void log(String msg) {
    246         synchronized (DozeLog.class) {
    247             if (sMessages == null) return;
    248             sTimes[sPosition] = System.currentTimeMillis();
    249             sMessages[sPosition] = msg;
    250             sPosition = (sPosition + 1) % SIZE;
    251             sCount = Math.min(sCount + 1, SIZE);
    252         }
    253         if (DEBUG) Log.d(TAG, msg);
    254     }
    255 
    256     public static void tracePulseDropped(Context context, boolean pulsePending,
    257             DozeMachine.State state, boolean blocked) {
    258         if (!ENABLED) return;
    259         init(context);
    260         log("pulseDropped pulsePending=" + pulsePending + " state="
    261                 + state + " blocked=" + blocked);
    262     }
    263 
    264     public static void tracePulseTouchDisabledByProx(Context context, boolean disabled) {
    265         if (!ENABLED) return;
    266         init(context);
    267         log("pulseTouchDisabledByProx " + disabled);
    268     }
    269 
    270     public static void setRegisterKeyguardCallback(boolean registerKeyguardCallback) {
    271         if (!ENABLED) return;
    272         synchronized (DozeLog.class) {
    273             if (sRegisterKeyguardCallback != registerKeyguardCallback && sMessages != null) {
    274                 throw new IllegalStateException("Cannot change setRegisterKeyguardCallback "
    275                         + "after init()");
    276             }
    277             sRegisterKeyguardCallback = registerKeyguardCallback;
    278         }
    279     }
    280 
    281     public static void traceSensor(Context context, int reason) {
    282         if (!ENABLED) return;
    283         init(context);
    284         log("sensor type=" + reasonToString(reason));
    285     }
    286 
    287     private static class SummaryStats {
    288         private int mCount;
    289 
    290         public void append() {
    291             mCount++;
    292         }
    293 
    294         public void dump(PrintWriter pw, String type) {
    295             if (mCount == 0) return;
    296             pw.print("    ");
    297             pw.print(type);
    298             pw.print(": n=");
    299             pw.print(mCount);
    300             pw.print(" (");
    301             final double perHr = (double) mCount / (System.currentTimeMillis() - sSince)
    302                     * 1000 * 60 * 60;
    303             pw.print(perHr);
    304             pw.print("/hr)");
    305             pw.println();
    306         }
    307     }
    308 
    309     private static final KeyguardUpdateMonitorCallback sKeyguardCallback =
    310             new KeyguardUpdateMonitorCallback() {
    311         @Override
    312         public void onEmergencyCallAction() {
    313             traceEmergencyCall();
    314         }
    315 
    316         @Override
    317         public void onKeyguardBouncerChanged(boolean bouncer) {
    318             traceKeyguardBouncerChanged(bouncer);
    319         }
    320 
    321         @Override
    322         public void onStartedWakingUp() {
    323             traceScreenOn();
    324         }
    325 
    326         @Override
    327         public void onFinishedGoingToSleep(int why) {
    328             traceScreenOff(why);
    329         }
    330 
    331         @Override
    332         public void onKeyguardVisibilityChanged(boolean showing) {
    333             traceKeyguard(showing);
    334         }
    335     };
    336 }
    337