1/*
2 * Copyright (C) 2016 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
5 * use this file except in compliance with the License. You may obtain a copy of
6 * 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, WITHOUT
12 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13 * License for the specific language governing permissions and limitations under
14 * the License.
15 */
16package com.android.internal.os;
17
18import android.os.BatteryStats;
19import android.os.Parcel;
20import android.support.test.filters.SmallTest;
21
22import junit.framework.TestCase;
23
24import org.mockito.Mockito;
25
26public class BatteryStatsSamplingTimerTest extends TestCase {
27
28    @SmallTest
29    public void testSettingStalePreservesData() throws Exception {
30        final MockClocks clocks = new MockClocks();
31        final BatteryStatsImpl.SamplingTimer timer = new BatteryStatsImpl.SamplingTimer(clocks,
32                Mockito.mock(BatteryStatsImpl.TimeBase.class));
33
34        timer.onTimeStarted(100, 100, 100);
35
36        // First update is absorbed.
37        timer.update(10, 1);
38
39        timer.update(20, 2);
40
41        assertEquals(1, timer.getCountLocked(BatteryStats.STATS_SINCE_CHARGED));
42        assertEquals(10, timer.getTotalTimeLocked(200, BatteryStats.STATS_SINCE_CHARGED));
43
44        timer.endSample();
45
46        assertEquals(1, timer.getCountLocked(BatteryStats.STATS_SINCE_CHARGED));
47        assertEquals(10, timer.getTotalTimeLocked(200, BatteryStats.STATS_SINCE_CHARGED));
48
49        timer.onTimeStopped(200, 200, 200);
50
51        assertEquals(1, timer.getCountLocked(BatteryStats.STATS_SINCE_CHARGED));
52        assertEquals(10, timer.getTotalTimeLocked(200, BatteryStats.STATS_SINCE_CHARGED));
53    }
54
55    @SmallTest
56    public void testEndSampleAndContinueWhenTimeOrCountDecreases() throws Exception {
57        final MockClocks clocks = new MockClocks();
58        final BatteryStatsImpl.TimeBase timeBase = Mockito.mock(BatteryStatsImpl.TimeBase.class);
59        final BatteryStatsImpl.SamplingTimer timer = new BatteryStatsImpl.SamplingTimer(clocks,
60                timeBase);
61
62        // First once is absorbed.
63        timer.update(10, 1);
64
65        timer.add(10, 1);
66
67        assertEquals(0, timer.getCountLocked(BatteryStats.STATS_SINCE_CHARGED));
68        assertEquals(0, timer.getTotalTimeLocked(200, BatteryStats.STATS_SINCE_CHARGED));
69
70        // This is less than we currently have, so we will end the sample. Time isn't running, so
71        // nothing should happen.
72        timer.update(0, 0);
73
74        assertEquals(0, timer.getCountLocked(BatteryStats.STATS_SINCE_CHARGED));
75        assertEquals(0, timer.getTotalTimeLocked(200, BatteryStats.STATS_SINCE_CHARGED));
76
77        timer.onTimeStarted(100, 100, 100);
78
79        // This should add.
80        timer.add(100, 10);
81
82        assertEquals(100, timer.getTotalTimeLocked(200, BatteryStats.STATS_SINCE_CHARGED));
83        assertEquals(10, timer.getCountLocked(BatteryStats.STATS_SINCE_CHARGED));
84
85        // This is less than we currently have, so we should end our sample and continue with the
86        // entire amount updated here.
87        timer.update(50, 5);
88
89        assertEquals(150, timer.getTotalTimeLocked(200, BatteryStats.STATS_SINCE_CHARGED));
90        assertEquals(15, timer.getCountLocked(BatteryStats.STATS_SINCE_CHARGED));
91
92        timer.onTimeStopped(200, 200, 200);
93
94        assertEquals(150, timer.getTotalTimeLocked(200, BatteryStats.STATS_SINCE_CHARGED));
95        assertEquals(15, timer.getCountLocked(BatteryStats.STATS_SINCE_CHARGED));
96    }
97
98    @SmallTest
99    public void testFirstUpdateIsAbsorbed() throws Exception {
100        final MockClocks clocks = new MockClocks();
101        final BatteryStatsImpl.TimeBase timeBase = Mockito.mock(BatteryStatsImpl.TimeBase.class);
102
103        BatteryStatsImpl.SamplingTimer timer = new BatteryStatsImpl.SamplingTimer(clocks, timeBase);
104
105        // This should be absorbed because it is our first update and we don't know what
106        // was being counted before.
107        timer.update(10, 1);
108
109        assertEquals(0, timer.getTotalTimeLocked(10, BatteryStats.STATS_SINCE_CHARGED));
110        assertEquals(0, timer.getCountLocked(BatteryStats.STATS_SINCE_CHARGED));
111
112        timer = new BatteryStatsImpl.SamplingTimer(clocks, timeBase);
113        timer.onTimeStarted(100, 100, 100);
114
115        // This should be absorbed.
116        timer.update(10, 1);
117
118        assertEquals(0, timer.getTotalTimeLocked(100, BatteryStats.STATS_SINCE_CHARGED));
119        assertEquals(0, timer.getCountLocked(BatteryStats.STATS_SINCE_CHARGED));
120
121        // This should NOT be aborbed, since we've already done that.
122        timer.add(10, 1);
123
124        assertEquals(10, timer.getTotalTimeLocked(100, BatteryStats.STATS_SINCE_CHARGED));
125        assertEquals(1, timer.getCountLocked(BatteryStats.STATS_SINCE_CHARGED));
126
127        timer.onTimeStopped(200, 200, 200);
128        timer.onTimeStarted(300, 300, 300);
129
130        // This should NOT be absorbed.
131        timer.add(10, 1);
132
133        assertEquals(20, timer.getTotalTimeLocked(300, BatteryStats.STATS_SINCE_CHARGED));
134        assertEquals(2, timer.getCountLocked(BatteryStats.STATS_SINCE_CHARGED));
135    }
136
137    @SmallTest
138    public void testSampleTimerSummaryParceling() throws Exception {
139        final MockClocks clocks = new MockClocks();
140        clocks.realtime = 0;
141        clocks.uptime = 0;
142
143        final BatteryStatsImpl.TimeBase timeBase = new BatteryStatsImpl.TimeBase();
144        timeBase.init(clocks.uptimeMillis(), clocks.elapsedRealtime());
145
146        BatteryStatsImpl.SamplingTimer timer = new BatteryStatsImpl.SamplingTimer(clocks, timeBase);
147
148        // Start running on battery.
149        // (Note that the wrong units are used in this class. setRunning is actually supposed to
150        // take us, not the ms that clocks uses.)
151        timeBase.setRunning(true, clocks.uptimeMillis(), clocks.elapsedRealtime());
152
153        // The first update on battery consumes the values as a way of starting cleanly.
154        timer.add(10, 1);
155
156        timer.add(10, 1);
157
158        clocks.realtime = 20;
159        clocks.uptime = 20;
160
161        assertEquals(10, timer.getTotalTimeLocked(clocks.elapsedRealtime(),
162                BatteryStats.STATS_SINCE_CHARGED));
163        assertEquals(1, timer.getCountLocked(BatteryStats.STATS_SINCE_CHARGED));
164
165        // Grab a summary parcel while on battery.
166        final Parcel onBatterySummaryParcel = Parcel.obtain();
167        timer.writeSummaryFromParcelLocked(onBatterySummaryParcel, clocks.elapsedRealtime() * 1000);
168        onBatterySummaryParcel.setDataPosition(0);
169
170        // Stop running on battery.
171        timeBase.setRunning(false, clocks.uptimeMillis(), clocks.elapsedRealtime());
172
173        assertEquals(10, timer.getTotalTimeLocked(clocks.elapsedRealtime(),
174                BatteryStats.STATS_SINCE_CHARGED));
175        assertEquals(1, timer.getCountLocked(BatteryStats.STATS_SINCE_CHARGED));
176
177        // Grab a summary parcel while not on battery.
178        final Parcel offBatterySummaryParcel = Parcel.obtain();
179        timer.writeSummaryFromParcelLocked(offBatterySummaryParcel,
180                clocks.elapsedRealtime() * 1000);
181        offBatterySummaryParcel.setDataPosition(0);
182
183        // Set the timebase running again. That way any issues with tracking reported values
184        // get tested when we unparcel the timers below.
185        timeBase.setRunning(true, clocks.uptimeMillis(), clocks.elapsedRealtime());
186
187        // Read the on battery summary from the parcel.
188        BatteryStatsImpl.SamplingTimer unparceledOnBatteryTimer =
189                new BatteryStatsImpl.SamplingTimer(clocks, timeBase);
190        unparceledOnBatteryTimer.readSummaryFromParcelLocked(onBatterySummaryParcel);
191
192        assertEquals(10, unparceledOnBatteryTimer.getTotalTimeLocked(0,
193                BatteryStats.STATS_SINCE_CHARGED));
194        assertEquals(1, unparceledOnBatteryTimer.getCountLocked(BatteryStats.STATS_SINCE_CHARGED));
195
196        // Read the off battery summary from the parcel.
197        BatteryStatsImpl.SamplingTimer unparceledOffBatteryTimer =
198                new BatteryStatsImpl.SamplingTimer(clocks, timeBase);
199        unparceledOffBatteryTimer.readSummaryFromParcelLocked(offBatterySummaryParcel);
200
201        assertEquals(10, unparceledOffBatteryTimer.getTotalTimeLocked(0,
202                BatteryStats.STATS_SINCE_CHARGED));
203        assertEquals(1, unparceledOffBatteryTimer.getCountLocked(BatteryStats.STATS_SINCE_CHARGED));
204
205        // Now, just like with a fresh timer, the first update should be absorbed to account for
206        // data being collected when we weren't recording.
207        unparceledOnBatteryTimer.update(10, 10);
208
209        assertEquals(10, unparceledOnBatteryTimer.getTotalTimeLocked(0,
210                BatteryStats.STATS_SINCE_CHARGED));
211        assertEquals(1, unparceledOnBatteryTimer.getCountLocked(BatteryStats.STATS_SINCE_CHARGED));
212
213        unparceledOffBatteryTimer.update(10, 10);
214
215        assertEquals(10, unparceledOffBatteryTimer.getTotalTimeLocked(0,
216                BatteryStats.STATS_SINCE_CHARGED));
217        assertEquals(1, unparceledOffBatteryTimer.getCountLocked(BatteryStats.STATS_SINCE_CHARGED));
218    }
219}
220