blob: fe504216b1668d4c6f71641c9621e04ad1490e53 [file] [log] [blame]
/*
* Copyright (C) 2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License
*/
package com.android.systemui.doze;
import android.util.TimeUtils;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.keyguard.KeyguardUpdateMonitorCallback;
import com.android.systemui.DumpController;
import com.android.systemui.log.SysuiLog;
import java.io.PrintWriter;
import java.util.Date;
import javax.inject.Inject;
import javax.inject.Singleton;
/**
* Logs doze events for debugging and triaging purposes. Logs are dumped in bugreports or on demand:
* adb shell dumpsys activity service com.android.systemui/.SystemUIService \
* dependency DumpController DozeLog
*/
@Singleton
public class DozeLog extends SysuiLog<DozeEvent> {
private static final String TAG = "DozeLog";
private DozeEvent mRecycledEvent;
private boolean mPulsing;
private long mSince;
private SummaryStats mPickupPulseNearVibrationStats;
private SummaryStats mPickupPulseNotNearVibrationStats;
private SummaryStats mNotificationPulseStats;
private SummaryStats mScreenOnPulsingStats;
private SummaryStats mScreenOnNotPulsingStats;
private SummaryStats mEmergencyCallStats;
private SummaryStats[][] mProxStats; // [reason][near/far]
@Inject
public DozeLog(KeyguardUpdateMonitor keyguardUpdateMonitor, DumpController dumpController) {
super(dumpController, TAG, MAX_DOZE_DEBUG_LOGS, MAX_DOZE_LOGS);
mSince = System.currentTimeMillis();
mPickupPulseNearVibrationStats = new SummaryStats();
mPickupPulseNotNearVibrationStats = new SummaryStats();
mNotificationPulseStats = new SummaryStats();
mScreenOnPulsingStats = new SummaryStats();
mScreenOnNotPulsingStats = new SummaryStats();
mEmergencyCallStats = new SummaryStats();
mProxStats = new SummaryStats[DozeEvent.TOTAL_REASONS][2];
for (int i = 0; i < DozeEvent.TOTAL_REASONS; i++) {
mProxStats[i][0] = new SummaryStats();
mProxStats[i][1] = new SummaryStats();
}
if (keyguardUpdateMonitor != null) {
keyguardUpdateMonitor.registerCallback(mKeyguardCallback);
}
}
/**
* Appends pickup wakeup event to the logs
*/
public void tracePickupWakeUp(boolean withinVibrationThreshold) {
log(DozeEvent.PICKUP_WAKEUP, "withinVibrationThreshold=" + withinVibrationThreshold);
if (mEnabled) {
(withinVibrationThreshold ? mPickupPulseNearVibrationStats
: mPickupPulseNotNearVibrationStats).append();
}
}
/**
* Appends pulse started event to the logs.
* @param reason why the pulse started
*/
public void tracePulseStart(@DozeEvent.Reason int reason) {
log(DozeEvent.PULSE_START, DozeEvent.reasonToString(reason));
if (mEnabled) mPulsing = true;
}
/**
* Appends pulse finished event to the logs
*/
public void tracePulseFinish() {
log(DozeEvent.PULSE_FINISH);
if (mEnabled) mPulsing = false;
}
/**
* Appends pulse event to the logs
*/
public void traceNotificationPulse() {
log(DozeEvent.NOTIFICATION_PULSE);
if (mEnabled) mNotificationPulseStats.append();
}
/**
* Appends dozing event to the logs
* @param dozing true if dozing, else false
*/
public void traceDozing(boolean dozing) {
log(DozeEvent.DOZING, "dozing=" + dozing);
if (mEnabled) mPulsing = false;
}
/**
* Appends fling event to the logs
*/
public void traceFling(boolean expand, boolean aboveThreshold, boolean thresholdNeeded,
boolean screenOnFromTouch) {
log(DozeEvent.FLING, "expand=" + expand
+ " aboveThreshold=" + aboveThreshold
+ " thresholdNeeded=" + thresholdNeeded
+ " screenOnFromTouch=" + screenOnFromTouch);
}
/**
* Appends emergency call event to the logs
*/
public void traceEmergencyCall() {
log(DozeEvent.EMERGENCY_CALL);
if (mEnabled) mEmergencyCallStats.append();
}
/**
* Appends keyguard bouncer changed event to the logs
* @param showing true if the keyguard bouncer is showing, else false
*/
public void traceKeyguardBouncerChanged(boolean showing) {
log(DozeEvent.KEYGUARD_BOUNCER_CHANGED, "showing=" + showing);
}
/**
* Appends screen-on event to the logs
*/
public void traceScreenOn() {
log(DozeEvent.SCREEN_ON, "pulsing=" + mPulsing);
if (mEnabled) {
(mPulsing ? mScreenOnPulsingStats : mScreenOnNotPulsingStats).append();
mPulsing = false;
}
}
/**
* Appends screen-off event to the logs
* @param why reason the screen is off
*/
public void traceScreenOff(int why) {
log(DozeEvent.SCREEN_OFF, "why=" + why);
}
/**
* Appends missed tick event to the logs
* @param delay of the missed tick
*/
public void traceMissedTick(String delay) {
log(DozeEvent.MISSED_TICK, "delay=" + delay);
}
/**
* Appends time tick scheduled event to the logs
* @param when time tick scheduled at
* @param triggerAt time tick trigger at
*/
public void traceTimeTickScheduled(long when, long triggerAt) {
log(DozeEvent.TIME_TICK_SCHEDULED,
"scheduledAt=" + DATE_FORMAT.format(new Date(when))
+ " triggerAt=" + DATE_FORMAT.format(new Date(triggerAt)));
}
/**
* Appends keyguard visibility change event to the logs
* @param showing whether the keyguard is now showing
*/
public void traceKeyguard(boolean showing) {
log(DozeEvent.KEYGUARD_VISIBILITY_CHANGE, "showing=" + showing);
if (mEnabled && !showing) mPulsing = false;
}
/**
* Appends doze state changed event to the logs
* @param state new DozeMachine state
*/
public void traceState(DozeMachine.State state) {
log(DozeEvent.DOZE_STATE_CHANGED, state.name());
}
/**
* Appends wake-display event to the logs.
* @param wake if we're waking up or sleeping.
*/
public void traceWakeDisplay(boolean wake) {
log(DozeEvent.WAKE_DISPLAY, "wake=" + wake);
}
/**
* Appends proximity result event to the logs
* @param near true if near, else false
* @param millis
* @param reason why proximity result was triggered
*/
public void traceProximityResult(boolean near, long millis, @DozeEvent.Reason int reason) {
log(DozeEvent.PROXIMITY_RESULT,
" reason=" + DozeEvent.reasonToString(reason)
+ " near=" + near
+ " millis=" + millis);
if (mEnabled) mProxStats[reason][near ? 0 : 1].append();
}
/**
* Prints doze log timeline and consolidated stats
* @param pw
*/
public void dump(PrintWriter pw) {
synchronized (DozeLog.class) {
super.dump(null, pw, null); // prints timeline
pw.print(" Doze summary stats (for ");
TimeUtils.formatDuration(System.currentTimeMillis() - mSince, pw);
pw.println("):");
mPickupPulseNearVibrationStats.dump(pw, "Pickup pulse (near vibration)");
mPickupPulseNotNearVibrationStats.dump(pw, "Pickup pulse (not near vibration)");
mNotificationPulseStats.dump(pw, "Notification pulse");
mScreenOnPulsingStats.dump(pw, "Screen on (pulsing)");
mScreenOnNotPulsingStats.dump(pw, "Screen on (not pulsing)");
mEmergencyCallStats.dump(pw, "Emergency call");
for (int i = 0; i < DozeEvent.TOTAL_REASONS; i++) {
final String reason = DozeEvent.reasonToString(i);
mProxStats[i][0].dump(pw, "Proximity near (" + reason + ")");
mProxStats[i][1].dump(pw, "Proximity far (" + reason + ")");
}
}
}
private void log(@DozeEvent.EventType int eventType) {
log(eventType, "");
}
private void log(@DozeEvent.EventType int eventType, String msg) {
if (mRecycledEvent != null) {
mRecycledEvent = log(mRecycledEvent.init(eventType, msg));
} else {
mRecycledEvent = log(new DozeEvent().init(eventType, msg));
}
}
/**
* Appends pulse dropped event to logs
*/
public void tracePulseDropped(boolean pulsePending, DozeMachine.State state, boolean blocked) {
log(DozeEvent.PULSE_DROPPED, "pulsePending=" + pulsePending + " state="
+ state.name() + " blocked=" + blocked);
}
/**
* Appends pulse dropped event to logs
* @param reason why the pulse was dropped
*/
public void tracePulseDropped(String reason) {
log(DozeEvent.PULSE_DROPPED, "why=" + reason);
}
/**
* Appends pulse touch displayed by prox sensor event to logs
* @param disabled
*/
public void tracePulseTouchDisabledByProx(boolean disabled) {
log(DozeEvent.PULSE_DISABLED_BY_PROX, "disabled=" + disabled);
}
/**
* Appends sensor triggered event to logs
* @param reason why the sensor was triggered
*/
public void traceSensor(@DozeEvent.Reason int reason) {
log(DozeEvent.SENSOR_TRIGGERED, "type=" + DozeEvent.reasonToString(reason));
}
private class SummaryStats {
private int mCount;
public void append() {
mCount++;
}
public void dump(PrintWriter pw, String type) {
if (mCount == 0) return;
pw.print(" ");
pw.print(type);
pw.print(": n=");
pw.print(mCount);
pw.print(" (");
final double perHr = (double) mCount / (System.currentTimeMillis() - mSince)
* 1000 * 60 * 60;
pw.print(perHr);
pw.print("/hr)");
pw.println();
}
}
private final KeyguardUpdateMonitorCallback mKeyguardCallback =
new KeyguardUpdateMonitorCallback() {
@Override
public void onEmergencyCallAction() {
traceEmergencyCall();
}
@Override
public void onKeyguardBouncerChanged(boolean bouncer) {
traceKeyguardBouncerChanged(bouncer);
}
@Override
public void onStartedWakingUp() {
traceScreenOn();
}
@Override
public void onFinishedGoingToSleep(int why) {
traceScreenOff(why);
}
@Override
public void onKeyguardVisibilityChanged(boolean showing) {
traceKeyguard(showing);
}
};
private static final int MAX_DOZE_DEBUG_LOGS = 400;
private static final int MAX_DOZE_LOGS = 50;
}