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