blob: ba61fd2597a46baf2578b7bc1384d0ace40da071 [file] [log] [blame]
/*
* Copyright (C) 2018 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.server.power.batterysaver;
import static org.junit.Assert.assertEquals;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import android.metrics.LogMaker;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.server.power.batterysaver.BatterySavingStats.BatterySaverState;
import com.android.server.power.batterysaver.BatterySavingStats.DozeState;
import com.android.server.power.batterysaver.BatterySavingStats.InteractiveState;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import java.io.ByteArrayOutputStream;
import java.io.PrintWriter;
/**
atest $ANDROID_BUILD_TOP/frameworks/base/services/tests/servicestests/src/com/android/server/power/batterysaver/BatterySavingStatsTest.java
*/
@SmallTest
@RunWith(AndroidJUnit4.class)
public class BatterySavingStatsTest {
private class BatterySavingStatsTestable extends BatterySavingStats {
private long mTime = 1_000_000; // Some random starting time.
private int mBatteryLevel = 1_000_000_000;
private BatterySavingStatsTestable() {
super(new Object(), mMetricsLogger);
}
@Override
long injectCurrentTime() {
return mTime;
}
@Override
int injectBatteryLevel() {
return mBatteryLevel;
}
@Override
int injectBatteryPercent() {
return mBatteryLevel / 10;
}
void assertDumpable() {
final ByteArrayOutputStream out = new ByteArrayOutputStream();
dump(new PrintWriter(out), ""); // Just make sure it won't crash.
}
void advanceClock(int minutes) {
mTime += 60_000 * minutes;
}
void drainBattery(int value) {
mBatteryLevel -= value;
if (mBatteryLevel < 0) {
mBatteryLevel = 0;
}
}
String toDebugString() {
final StringBuilder sb = new StringBuilder();
String sep = "";
for (int i = 0; i < mStats.size(); i++) {
sb.append(sep);
sb.append(stateToString(mStats.keyAt(i)));
sb.append(":");
sb.append(mStats.valueAt(i).toStringForTest());
sep = "\n";
}
return sb.toString();
}
}
public MetricsLogger mMetricsLogger = mock(MetricsLogger.class);
private boolean sendTronEvents;
@Test
public void testAll_withTron() {
sendTronEvents = true;
checkAll();
}
@Test
public void testAll_noTron() {
sendTronEvents = false;
checkAll();
}
private void checkAll() {
final BatterySavingStatsTestable target = new BatterySavingStatsTestable();
target.setSendTronLog(sendTronEvents);
target.assertDumpable();
target.advanceClock(1);
target.drainBattery(200);
target.transitionState(
BatterySaverState.OFF,
InteractiveState.INTERACTIVE,
DozeState.NOT_DOZING);
target.advanceClock(4);
target.drainBattery(100);
target.transitionState(
BatterySaverState.OFF,
InteractiveState.NON_INTERACTIVE,
DozeState.NOT_DOZING);
target.advanceClock(2);
target.drainBattery(500);
target.transitionState(
BatterySaverState.OFF,
InteractiveState.INTERACTIVE,
DozeState.NOT_DOZING);
target.advanceClock(4);
target.drainBattery(100);
target.transitionState(
BatterySaverState.OFF,
InteractiveState.NON_INTERACTIVE,
DozeState.NOT_DOZING);
target.advanceClock(2);
target.drainBattery(500);
target.transitionState(
BatterySaverState.OFF,
InteractiveState.INTERACTIVE,
DozeState.NOT_DOZING);
target.advanceClock(3);
target.drainBattery(100);
target.transitionState(
BatterySaverState.OFF,
InteractiveState.NON_INTERACTIVE,
DozeState.LIGHT);
target.advanceClock(5);
target.drainBattery(100);
target.transitionState(
BatterySaverState.OFF,
InteractiveState.NON_INTERACTIVE,
DozeState.DEEP);
target.advanceClock(1);
target.drainBattery(200);
target.transitionState(
BatterySaverState.ON,
InteractiveState.INTERACTIVE,
DozeState.NOT_DOZING);
target.advanceClock(1);
target.drainBattery(300);
target.transitionState(
BatterySaverState.OFF,
InteractiveState.INTERACTIVE,
DozeState.NOT_DOZING);
target.advanceClock(3);
target.drainBattery(500);
target.transitionState(
BatterySaverState.ON,
InteractiveState.INTERACTIVE,
DozeState.NOT_DOZING);
target.advanceClock(3);
target.drainBattery(500);
target.startCharging();
target.advanceClock(5);
target.drainBattery(1000);
target.transitionState(
BatterySaverState.ON,
InteractiveState.INTERACTIVE,
DozeState.NOT_DOZING);
target.advanceClock(5);
target.drainBattery(100);
target.startCharging();
target.assertDumpable();
assertEquals(
"BS=0,I=0,D=0:{4m,1000,15000.00uA/H,1500.00%}\n" +
"BS=1,I=0,D=0:{0m,0,0.00uA/H,0.00%}\n" +
"BS=0,I=1,D=0:{14m,800,3428.57uA/H,342.86%}\n" +
"BS=1,I=1,D=0:{9m,900,6000.00uA/H,600.00%}\n" +
"BS=0,I=0,D=1:{5m,100,1200.00uA/H,120.00%}\n" +
"BS=1,I=0,D=1:{0m,0,0.00uA/H,0.00%}\n" +
"BS=0,I=1,D=1:{0m,0,0.00uA/H,0.00%}\n" +
"BS=1,I=1,D=1:{0m,0,0.00uA/H,0.00%}\n" +
"BS=0,I=0,D=2:{1m,200,12000.00uA/H,1200.00%}\n" +
"BS=1,I=0,D=2:{0m,0,0.00uA/H,0.00%}\n" +
"BS=0,I=1,D=2:{0m,0,0.00uA/H,0.00%}\n" +
"BS=1,I=1,D=2:{0m,0,0.00uA/H,0.00%}",
target.toDebugString());
}
private void assertLog(boolean batterySaver, boolean interactive, long deltaTimeMs,
int deltaBatteryLevelUa, int deltaBatteryLevelPercent) {
if (sendTronEvents) {
ArgumentCaptor<LogMaker> ac = ArgumentCaptor.forClass(LogMaker.class);
verify(mMetricsLogger, times(1)).write(ac.capture());
LogMaker lm = ac.getValue();
assertEquals(MetricsEvent.BATTERY_SAVER, lm.getCategory());
assertEquals(batterySaver ? 1 : 0,
lm.getTaggedData(MetricsEvent.RESERVED_FOR_LOGBUILDER_SUBTYPE));
assertEquals(interactive ? 1 : 0, lm.getTaggedData(MetricsEvent.FIELD_INTERACTIVE));
assertEquals(deltaTimeMs, lm.getTaggedData(MetricsEvent.FIELD_DURATION_MILLIS));
assertEquals(deltaBatteryLevelUa,
(int) lm.getTaggedData(MetricsEvent.FIELD_START_BATTERY_UA)
- (int) lm.getTaggedData(MetricsEvent.FIELD_END_BATTERY_UA));
assertEquals(deltaBatteryLevelPercent,
(int) lm.getTaggedData(MetricsEvent.FIELD_START_BATTERY_PERCENT)
- (int) lm.getTaggedData(MetricsEvent.FIELD_END_BATTERY_PERCENT));
} else {
verify(mMetricsLogger, times(0)).write(any(LogMaker.class));
}
}
@Test
public void testMetricsLogger_withTron() {
sendTronEvents = true;
checkMetricsLogger();
}
@Test
public void testMetricsLogger_noTron() {
sendTronEvents = false;
checkMetricsLogger();
}
private void checkMetricsLogger() {
final BatterySavingStatsTestable target = new BatterySavingStatsTestable();
target.setSendTronLog(sendTronEvents);
target.advanceClock(1);
target.drainBattery(1000);
target.transitionState(
BatterySaverState.OFF,
InteractiveState.INTERACTIVE,
DozeState.NOT_DOZING);
verify(mMetricsLogger, times(0)).count(anyString(), anyInt());
target.advanceClock(1);
target.drainBattery(2000);
reset(mMetricsLogger);
target.transitionState(
BatterySaverState.OFF,
InteractiveState.NON_INTERACTIVE,
DozeState.NOT_DOZING);
assertLog(false, true, 60_000, 2000, 200);
target.advanceClock(1);
target.drainBattery(2000);
reset(mMetricsLogger);
target.transitionState(
BatterySaverState.OFF,
InteractiveState.NON_INTERACTIVE,
DozeState.DEEP);
target.advanceClock(1);
target.drainBattery(2000);
verify(mMetricsLogger, times(0)).count(anyString(), anyInt());
target.transitionState(
BatterySaverState.OFF,
InteractiveState.NON_INTERACTIVE,
DozeState.LIGHT);
target.advanceClock(1);
target.drainBattery(2000);
verify(mMetricsLogger, times(0)).count(anyString(), anyInt());
target.transitionState(
BatterySaverState.ON,
InteractiveState.INTERACTIVE,
DozeState.NOT_DOZING);
assertLog(false, false, 60_000 * 3, 2000 * 3, 200 * 3);
target.advanceClock(10);
target.drainBattery(10000);
reset(mMetricsLogger);
target.startCharging();
assertLog(true, true, 60_000 * 10, 10000, 1000);
target.advanceClock(1);
target.drainBattery(2000);
reset(mMetricsLogger);
target.transitionState(
BatterySaverState.ON,
InteractiveState.NON_INTERACTIVE,
DozeState.NOT_DOZING);
verify(mMetricsLogger, times(0)).count(anyString(), anyInt());
target.advanceClock(1);
target.drainBattery(2000);
target.startCharging();
assertLog(true, false, 60_000, 2000, 200);
}
}