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