xref: /aosp_15_r20/frameworks/native/libs/battery/MultiStateCounter.h (revision 38e8c45f13ce32b0dcecb25141ffecaf386fa17f)
1*38e8c45fSAndroid Build Coastguard Worker /*
2*38e8c45fSAndroid Build Coastguard Worker  * Copyright (C) 2021 The Android Open Source Project
3*38e8c45fSAndroid Build Coastguard Worker  * Android BPF library - public API
4*38e8c45fSAndroid Build Coastguard Worker  *
5*38e8c45fSAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
6*38e8c45fSAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
7*38e8c45fSAndroid Build Coastguard Worker  * You may obtain a copy of the License at
8*38e8c45fSAndroid Build Coastguard Worker  *
9*38e8c45fSAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
10*38e8c45fSAndroid Build Coastguard Worker  *
11*38e8c45fSAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
12*38e8c45fSAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
13*38e8c45fSAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14*38e8c45fSAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
15*38e8c45fSAndroid Build Coastguard Worker  * limitations under the License.
16*38e8c45fSAndroid Build Coastguard Worker  */
17*38e8c45fSAndroid Build Coastguard Worker 
18*38e8c45fSAndroid Build Coastguard Worker #pragma once
19*38e8c45fSAndroid Build Coastguard Worker 
20*38e8c45fSAndroid Build Coastguard Worker #include <inttypes.h>
21*38e8c45fSAndroid Build Coastguard Worker #include <log/log.h>
22*38e8c45fSAndroid Build Coastguard Worker #include <time.h>
23*38e8c45fSAndroid Build Coastguard Worker #include <sstream>
24*38e8c45fSAndroid Build Coastguard Worker #include <string>
25*38e8c45fSAndroid Build Coastguard Worker 
26*38e8c45fSAndroid Build Coastguard Worker /**
27*38e8c45fSAndroid Build Coastguard Worker  * An object that can track changes of some value over time, taking into account an additional
28*38e8c45fSAndroid Build Coastguard Worker  * dimension: the object's state.  As the tracked value changes, the deltas are distributed
29*38e8c45fSAndroid Build Coastguard Worker  * among the object states in accordance with the time spent in those states.
30*38e8c45fSAndroid Build Coastguard Worker  */
31*38e8c45fSAndroid Build Coastguard Worker namespace android {
32*38e8c45fSAndroid Build Coastguard Worker namespace battery {
33*38e8c45fSAndroid Build Coastguard Worker 
34*38e8c45fSAndroid Build Coastguard Worker #define REPORTED_INVALID_TIMESTAMP_DELTA_MS 60000
35*38e8c45fSAndroid Build Coastguard Worker 
36*38e8c45fSAndroid Build Coastguard Worker typedef uint16_t state_t;
37*38e8c45fSAndroid Build Coastguard Worker 
38*38e8c45fSAndroid Build Coastguard Worker template <class T, class V>
39*38e8c45fSAndroid Build Coastguard Worker class MultiStateCounter {
40*38e8c45fSAndroid Build Coastguard Worker     const uint16_t stateCount;
41*38e8c45fSAndroid Build Coastguard Worker     const V emptyValue;
42*38e8c45fSAndroid Build Coastguard Worker     state_t currentState;
43*38e8c45fSAndroid Build Coastguard Worker     time_t lastStateChangeTimestamp;
44*38e8c45fSAndroid Build Coastguard Worker     T lastValue;
45*38e8c45fSAndroid Build Coastguard Worker     time_t lastUpdateTimestamp;
46*38e8c45fSAndroid Build Coastguard Worker     T deltaValue;
47*38e8c45fSAndroid Build Coastguard Worker     bool isEnabled;
48*38e8c45fSAndroid Build Coastguard Worker 
49*38e8c45fSAndroid Build Coastguard Worker     struct State {
50*38e8c45fSAndroid Build Coastguard Worker         time_t timeInStateSinceUpdate;
51*38e8c45fSAndroid Build Coastguard Worker         T counter;
52*38e8c45fSAndroid Build Coastguard Worker     };
53*38e8c45fSAndroid Build Coastguard Worker 
54*38e8c45fSAndroid Build Coastguard Worker     State* states;
55*38e8c45fSAndroid Build Coastguard Worker 
56*38e8c45fSAndroid Build Coastguard Worker public:
57*38e8c45fSAndroid Build Coastguard Worker     MultiStateCounter(uint16_t stateCount, const V& emptyValue);
58*38e8c45fSAndroid Build Coastguard Worker 
59*38e8c45fSAndroid Build Coastguard Worker     virtual ~MultiStateCounter();
60*38e8c45fSAndroid Build Coastguard Worker 
61*38e8c45fSAndroid Build Coastguard Worker     void setEnabled(bool enabled, time_t timestamp);
62*38e8c45fSAndroid Build Coastguard Worker 
63*38e8c45fSAndroid Build Coastguard Worker     void setState(state_t state, time_t timestamp);
64*38e8c45fSAndroid Build Coastguard Worker 
65*38e8c45fSAndroid Build Coastguard Worker     /**
66*38e8c45fSAndroid Build Coastguard Worker      * Copies the current state and accumulated times-in-state from the source. Resets
67*38e8c45fSAndroid Build Coastguard Worker      * the accumulated value.
68*38e8c45fSAndroid Build Coastguard Worker      */
69*38e8c45fSAndroid Build Coastguard Worker     void copyStatesFrom(const MultiStateCounter<T, V> &source);
70*38e8c45fSAndroid Build Coastguard Worker 
71*38e8c45fSAndroid Build Coastguard Worker     void setValue(state_t state, const V& value);
72*38e8c45fSAndroid Build Coastguard Worker 
73*38e8c45fSAndroid Build Coastguard Worker     /**
74*38e8c45fSAndroid Build Coastguard Worker      * Updates the value by distributing the delta from the previously set value
75*38e8c45fSAndroid Build Coastguard Worker      * among states according to their respective time-in-state.
76*38e8c45fSAndroid Build Coastguard Worker      * Returns the delta from the previously set value.
77*38e8c45fSAndroid Build Coastguard Worker      */
78*38e8c45fSAndroid Build Coastguard Worker     const V& updateValue(const V& value, time_t timestamp);
79*38e8c45fSAndroid Build Coastguard Worker 
80*38e8c45fSAndroid Build Coastguard Worker     /**
81*38e8c45fSAndroid Build Coastguard Worker      * Updates the value by distributing the specified increment among states according
82*38e8c45fSAndroid Build Coastguard Worker      * to their respective time-in-state.
83*38e8c45fSAndroid Build Coastguard Worker      */
84*38e8c45fSAndroid Build Coastguard Worker     void incrementValue(const V& increment, time_t timestamp);
85*38e8c45fSAndroid Build Coastguard Worker 
86*38e8c45fSAndroid Build Coastguard Worker     /**
87*38e8c45fSAndroid Build Coastguard Worker      * Adds the specified increment to the value for the current state, without affecting
88*38e8c45fSAndroid Build Coastguard Worker      * the last updated value or timestamp.  Ignores partial time-in-state: the entirety of
89*38e8c45fSAndroid Build Coastguard Worker      * the increment is given to the current state.
90*38e8c45fSAndroid Build Coastguard Worker      */
91*38e8c45fSAndroid Build Coastguard Worker     void addValue(const V& increment);
92*38e8c45fSAndroid Build Coastguard Worker 
93*38e8c45fSAndroid Build Coastguard Worker     void reset();
94*38e8c45fSAndroid Build Coastguard Worker 
95*38e8c45fSAndroid Build Coastguard Worker     uint16_t getStateCount();
96*38e8c45fSAndroid Build Coastguard Worker 
97*38e8c45fSAndroid Build Coastguard Worker     const V& getCount(state_t state);
98*38e8c45fSAndroid Build Coastguard Worker 
99*38e8c45fSAndroid Build Coastguard Worker     std::string toString();
100*38e8c45fSAndroid Build Coastguard Worker 
101*38e8c45fSAndroid Build Coastguard Worker private:
102*38e8c45fSAndroid Build Coastguard Worker     /**
103*38e8c45fSAndroid Build Coastguard Worker      * Subtracts previousValue from newValue and returns the result in outValue.
104*38e8c45fSAndroid Build Coastguard Worker      * Returns true iff the combination of previousValue and newValue is valid
105*38e8c45fSAndroid Build Coastguard Worker      * (newValue >= prevValue)
106*38e8c45fSAndroid Build Coastguard Worker      */
107*38e8c45fSAndroid Build Coastguard Worker     bool delta(const T& previousValue, const V& newValue, T* outValue) const;
108*38e8c45fSAndroid Build Coastguard Worker 
109*38e8c45fSAndroid Build Coastguard Worker     /**
110*38e8c45fSAndroid Build Coastguard Worker      * Adds value2 to value1 and stores the result in value1.  Denominator is
111*38e8c45fSAndroid Build Coastguard Worker      * guaranteed to be non-zero.
112*38e8c45fSAndroid Build Coastguard Worker      */
113*38e8c45fSAndroid Build Coastguard Worker     void add(T* value1, const V& value2, const uint64_t numerator,
114*38e8c45fSAndroid Build Coastguard Worker              const uint64_t denominator) const;
115*38e8c45fSAndroid Build Coastguard Worker };
116*38e8c45fSAndroid Build Coastguard Worker 
117*38e8c45fSAndroid Build Coastguard Worker // ---------------------- MultiStateCounter Implementation -------------------------
118*38e8c45fSAndroid Build Coastguard Worker // Since MultiStateCounter is a template, the implementation must be inlined.
119*38e8c45fSAndroid Build Coastguard Worker 
120*38e8c45fSAndroid Build Coastguard Worker template <class T, class V>
MultiStateCounter(uint16_t stateCount,const V & emptyValue)121*38e8c45fSAndroid Build Coastguard Worker MultiStateCounter<T, V>::MultiStateCounter(uint16_t stateCount, const V& emptyValue)
122*38e8c45fSAndroid Build Coastguard Worker       : stateCount(stateCount),
123*38e8c45fSAndroid Build Coastguard Worker         emptyValue(emptyValue),
124*38e8c45fSAndroid Build Coastguard Worker         currentState(0),
125*38e8c45fSAndroid Build Coastguard Worker         lastStateChangeTimestamp(-1),
126*38e8c45fSAndroid Build Coastguard Worker         lastValue(emptyValue),
127*38e8c45fSAndroid Build Coastguard Worker         lastUpdateTimestamp(-1),
128*38e8c45fSAndroid Build Coastguard Worker         deltaValue(emptyValue),
129*38e8c45fSAndroid Build Coastguard Worker         isEnabled(true) {
130*38e8c45fSAndroid Build Coastguard Worker     states = new State[stateCount];
131*38e8c45fSAndroid Build Coastguard Worker     for (int i = 0; i < stateCount; i++) {
132*38e8c45fSAndroid Build Coastguard Worker         states[i].timeInStateSinceUpdate = 0;
133*38e8c45fSAndroid Build Coastguard Worker         states[i].counter = emptyValue;
134*38e8c45fSAndroid Build Coastguard Worker     }
135*38e8c45fSAndroid Build Coastguard Worker }
136*38e8c45fSAndroid Build Coastguard Worker 
137*38e8c45fSAndroid Build Coastguard Worker template <class T, class V>
~MultiStateCounter()138*38e8c45fSAndroid Build Coastguard Worker MultiStateCounter<T, V>::~MultiStateCounter() {
139*38e8c45fSAndroid Build Coastguard Worker     delete[] states;
140*38e8c45fSAndroid Build Coastguard Worker };
141*38e8c45fSAndroid Build Coastguard Worker 
142*38e8c45fSAndroid Build Coastguard Worker template <class T, class V>
setEnabled(bool enabled,time_t timestamp)143*38e8c45fSAndroid Build Coastguard Worker void MultiStateCounter<T, V>::setEnabled(bool enabled, time_t timestamp) {
144*38e8c45fSAndroid Build Coastguard Worker     if (enabled == isEnabled) {
145*38e8c45fSAndroid Build Coastguard Worker         return;
146*38e8c45fSAndroid Build Coastguard Worker     }
147*38e8c45fSAndroid Build Coastguard Worker 
148*38e8c45fSAndroid Build Coastguard Worker     if (isEnabled) {
149*38e8c45fSAndroid Build Coastguard Worker         // Confirm the current state for the side-effect of updating the time-in-state
150*38e8c45fSAndroid Build Coastguard Worker         // counter for the current state.
151*38e8c45fSAndroid Build Coastguard Worker         setState(currentState, timestamp);
152*38e8c45fSAndroid Build Coastguard Worker         isEnabled = false;
153*38e8c45fSAndroid Build Coastguard Worker     } else {
154*38e8c45fSAndroid Build Coastguard Worker         // If the counter is being enabled with an out-of-order timestamp, just push back
155*38e8c45fSAndroid Build Coastguard Worker         // the timestamp to avoid having the situation where
156*38e8c45fSAndroid Build Coastguard Worker         // timeInStateSinceUpdate > timeSinceUpdate
157*38e8c45fSAndroid Build Coastguard Worker         if (timestamp < lastUpdateTimestamp) {
158*38e8c45fSAndroid Build Coastguard Worker             timestamp = lastUpdateTimestamp;
159*38e8c45fSAndroid Build Coastguard Worker         }
160*38e8c45fSAndroid Build Coastguard Worker 
161*38e8c45fSAndroid Build Coastguard Worker         if (lastStateChangeTimestamp >= 0) {
162*38e8c45fSAndroid Build Coastguard Worker             lastStateChangeTimestamp = timestamp;
163*38e8c45fSAndroid Build Coastguard Worker         }
164*38e8c45fSAndroid Build Coastguard Worker         isEnabled = true;
165*38e8c45fSAndroid Build Coastguard Worker     }
166*38e8c45fSAndroid Build Coastguard Worker }
167*38e8c45fSAndroid Build Coastguard Worker 
168*38e8c45fSAndroid Build Coastguard Worker template <class T, class V>
setState(state_t state,time_t timestamp)169*38e8c45fSAndroid Build Coastguard Worker void MultiStateCounter<T, V>::setState(state_t state, time_t timestamp) {
170*38e8c45fSAndroid Build Coastguard Worker     if (isEnabled && lastStateChangeTimestamp >= 0 && lastUpdateTimestamp >= 0) {
171*38e8c45fSAndroid Build Coastguard Worker         // If the update arrived out-of-order, just push back the timestamp to
172*38e8c45fSAndroid Build Coastguard Worker         // avoid having the situation where timeInStateSinceUpdate > timeSinceUpdate
173*38e8c45fSAndroid Build Coastguard Worker         if (timestamp < lastUpdateTimestamp) {
174*38e8c45fSAndroid Build Coastguard Worker             timestamp = lastUpdateTimestamp;
175*38e8c45fSAndroid Build Coastguard Worker         }
176*38e8c45fSAndroid Build Coastguard Worker 
177*38e8c45fSAndroid Build Coastguard Worker         if (timestamp >= lastStateChangeTimestamp) {
178*38e8c45fSAndroid Build Coastguard Worker             states[currentState].timeInStateSinceUpdate += timestamp - lastStateChangeTimestamp;
179*38e8c45fSAndroid Build Coastguard Worker         } else {
180*38e8c45fSAndroid Build Coastguard Worker             if (timestamp < lastStateChangeTimestamp - REPORTED_INVALID_TIMESTAMP_DELTA_MS) {
181*38e8c45fSAndroid Build Coastguard Worker                 ALOGE("setState is called with an earlier timestamp: %lu, "
182*38e8c45fSAndroid Build Coastguard Worker                       "previous timestamp: %lu\n",
183*38e8c45fSAndroid Build Coastguard Worker                       (unsigned long)timestamp, (unsigned long)lastStateChangeTimestamp);
184*38e8c45fSAndroid Build Coastguard Worker             }
185*38e8c45fSAndroid Build Coastguard Worker 
186*38e8c45fSAndroid Build Coastguard Worker             // The accumulated durations have become unreliable. For example, if the timestamp
187*38e8c45fSAndroid Build Coastguard Worker             // sequence was 1000, 2000, 1000, 3000, if we accumulated the positive deltas,
188*38e8c45fSAndroid Build Coastguard Worker             // we would get 4000, which is greater than (last - first). This could lead to
189*38e8c45fSAndroid Build Coastguard Worker             // counts exceeding 100%.
190*38e8c45fSAndroid Build Coastguard Worker             for (int i = 0; i < stateCount; i++) {
191*38e8c45fSAndroid Build Coastguard Worker                 states[i].timeInStateSinceUpdate = 0;
192*38e8c45fSAndroid Build Coastguard Worker             }
193*38e8c45fSAndroid Build Coastguard Worker         }
194*38e8c45fSAndroid Build Coastguard Worker     }
195*38e8c45fSAndroid Build Coastguard Worker     currentState = state;
196*38e8c45fSAndroid Build Coastguard Worker     lastStateChangeTimestamp = timestamp;
197*38e8c45fSAndroid Build Coastguard Worker }
198*38e8c45fSAndroid Build Coastguard Worker 
199*38e8c45fSAndroid Build Coastguard Worker template <class T, class V>
copyStatesFrom(const MultiStateCounter<T,V> & source)200*38e8c45fSAndroid Build Coastguard Worker void MultiStateCounter<T, V>::copyStatesFrom(const MultiStateCounter<T, V>& source) {
201*38e8c45fSAndroid Build Coastguard Worker     if (stateCount != source.stateCount) {
202*38e8c45fSAndroid Build Coastguard Worker         ALOGE("State count mismatch: %u vs. %u\n", stateCount, source.stateCount);
203*38e8c45fSAndroid Build Coastguard Worker         return;
204*38e8c45fSAndroid Build Coastguard Worker     }
205*38e8c45fSAndroid Build Coastguard Worker 
206*38e8c45fSAndroid Build Coastguard Worker     currentState = source.currentState;
207*38e8c45fSAndroid Build Coastguard Worker     for (int i = 0; i < stateCount; i++) {
208*38e8c45fSAndroid Build Coastguard Worker         states[i].timeInStateSinceUpdate = source.states[i].timeInStateSinceUpdate;
209*38e8c45fSAndroid Build Coastguard Worker         states[i].counter = emptyValue;
210*38e8c45fSAndroid Build Coastguard Worker     }
211*38e8c45fSAndroid Build Coastguard Worker     lastStateChangeTimestamp = source.lastStateChangeTimestamp;
212*38e8c45fSAndroid Build Coastguard Worker     lastUpdateTimestamp = source.lastUpdateTimestamp;
213*38e8c45fSAndroid Build Coastguard Worker }
214*38e8c45fSAndroid Build Coastguard Worker 
215*38e8c45fSAndroid Build Coastguard Worker template <class T, class V>
setValue(state_t state,const V & value)216*38e8c45fSAndroid Build Coastguard Worker void MultiStateCounter<T, V>::setValue(state_t state, const V& value) {
217*38e8c45fSAndroid Build Coastguard Worker     states[state].counter = value;
218*38e8c45fSAndroid Build Coastguard Worker }
219*38e8c45fSAndroid Build Coastguard Worker 
220*38e8c45fSAndroid Build Coastguard Worker template <class T, class V>
updateValue(const V & value,time_t timestamp)221*38e8c45fSAndroid Build Coastguard Worker const V& MultiStateCounter<T, V>::updateValue(const V& value, time_t timestamp) {
222*38e8c45fSAndroid Build Coastguard Worker     const V* returnValue = &emptyValue;
223*38e8c45fSAndroid Build Coastguard Worker 
224*38e8c45fSAndroid Build Coastguard Worker     // If the counter is disabled, we ignore the update, except when the counter got disabled after
225*38e8c45fSAndroid Build Coastguard Worker     // the previous update, in which case we still need to pick up the residual delta.
226*38e8c45fSAndroid Build Coastguard Worker     if (isEnabled || lastUpdateTimestamp < lastStateChangeTimestamp) {
227*38e8c45fSAndroid Build Coastguard Worker         // If the update arrived out of order, just push back the timestamp to
228*38e8c45fSAndroid Build Coastguard Worker         // avoid having the situation where timeInStateSinceUpdate > timeSinceUpdate
229*38e8c45fSAndroid Build Coastguard Worker         if (timestamp < lastStateChangeTimestamp) {
230*38e8c45fSAndroid Build Coastguard Worker             timestamp = lastStateChangeTimestamp;
231*38e8c45fSAndroid Build Coastguard Worker         }
232*38e8c45fSAndroid Build Coastguard Worker 
233*38e8c45fSAndroid Build Coastguard Worker         // Confirm the current state for the side-effect of updating the time-in-state
234*38e8c45fSAndroid Build Coastguard Worker         // counter for the current state.
235*38e8c45fSAndroid Build Coastguard Worker         setState(currentState, timestamp);
236*38e8c45fSAndroid Build Coastguard Worker 
237*38e8c45fSAndroid Build Coastguard Worker         if (lastUpdateTimestamp >= 0) {
238*38e8c45fSAndroid Build Coastguard Worker             if (timestamp > lastUpdateTimestamp) {
239*38e8c45fSAndroid Build Coastguard Worker                 if (delta(lastValue, value, &deltaValue)) {
240*38e8c45fSAndroid Build Coastguard Worker                     returnValue = &deltaValue;
241*38e8c45fSAndroid Build Coastguard Worker                     time_t timeSinceUpdate = timestamp - lastUpdateTimestamp;
242*38e8c45fSAndroid Build Coastguard Worker                     for (int i = 0; i < stateCount; i++) {
243*38e8c45fSAndroid Build Coastguard Worker                         time_t timeInState = states[i].timeInStateSinceUpdate;
244*38e8c45fSAndroid Build Coastguard Worker                         if (timeInState) {
245*38e8c45fSAndroid Build Coastguard Worker                             add(&states[i].counter, deltaValue, timeInState, timeSinceUpdate);
246*38e8c45fSAndroid Build Coastguard Worker                             states[i].timeInStateSinceUpdate = 0;
247*38e8c45fSAndroid Build Coastguard Worker                         }
248*38e8c45fSAndroid Build Coastguard Worker                     }
249*38e8c45fSAndroid Build Coastguard Worker                 } else {
250*38e8c45fSAndroid Build Coastguard Worker                     std::stringstream str;
251*38e8c45fSAndroid Build Coastguard Worker                     str << "updateValue is called with a value " << value
252*38e8c45fSAndroid Build Coastguard Worker                         << ", which is lower than the previous value " << lastValue
253*38e8c45fSAndroid Build Coastguard Worker                         << "\n";
254*38e8c45fSAndroid Build Coastguard Worker                     ALOGE("%s", str.str().c_str());
255*38e8c45fSAndroid Build Coastguard Worker 
256*38e8c45fSAndroid Build Coastguard Worker                     for (int i = 0; i < stateCount; i++) {
257*38e8c45fSAndroid Build Coastguard Worker                         states[i].timeInStateSinceUpdate = 0;
258*38e8c45fSAndroid Build Coastguard Worker                     }
259*38e8c45fSAndroid Build Coastguard Worker                 }
260*38e8c45fSAndroid Build Coastguard Worker             } else if (timestamp < lastUpdateTimestamp) {
261*38e8c45fSAndroid Build Coastguard Worker                 if (timestamp < lastUpdateTimestamp - REPORTED_INVALID_TIMESTAMP_DELTA_MS) {
262*38e8c45fSAndroid Build Coastguard Worker                     ALOGE("updateValue is called with an earlier timestamp: %lu, previous: %lu\n",
263*38e8c45fSAndroid Build Coastguard Worker                           (unsigned long)timestamp, (unsigned long)lastUpdateTimestamp);
264*38e8c45fSAndroid Build Coastguard Worker                 }
265*38e8c45fSAndroid Build Coastguard Worker 
266*38e8c45fSAndroid Build Coastguard Worker                 for (int i = 0; i < stateCount; i++) {
267*38e8c45fSAndroid Build Coastguard Worker                     states[i].timeInStateSinceUpdate = 0;
268*38e8c45fSAndroid Build Coastguard Worker                 }
269*38e8c45fSAndroid Build Coastguard Worker             }
270*38e8c45fSAndroid Build Coastguard Worker         }
271*38e8c45fSAndroid Build Coastguard Worker     }
272*38e8c45fSAndroid Build Coastguard Worker     lastValue = value;
273*38e8c45fSAndroid Build Coastguard Worker     lastUpdateTimestamp = timestamp;
274*38e8c45fSAndroid Build Coastguard Worker     return *returnValue;
275*38e8c45fSAndroid Build Coastguard Worker }
276*38e8c45fSAndroid Build Coastguard Worker 
277*38e8c45fSAndroid Build Coastguard Worker template <class T, class V>
incrementValue(const V & increment,time_t timestamp)278*38e8c45fSAndroid Build Coastguard Worker void MultiStateCounter<T, V>::incrementValue(const V& increment, time_t timestamp) {
279*38e8c45fSAndroid Build Coastguard Worker //    T newValue;
280*38e8c45fSAndroid Build Coastguard Worker //    newValue = lastValue; // Copy assignment, not initialization.
281*38e8c45fSAndroid Build Coastguard Worker     T newValue = lastValue;
282*38e8c45fSAndroid Build Coastguard Worker     add(&newValue, increment, 1 /* numerator */, 1 /* denominator */);
283*38e8c45fSAndroid Build Coastguard Worker     updateValue(newValue, timestamp);
284*38e8c45fSAndroid Build Coastguard Worker }
285*38e8c45fSAndroid Build Coastguard Worker 
286*38e8c45fSAndroid Build Coastguard Worker template <class T, class V>
addValue(const V & value)287*38e8c45fSAndroid Build Coastguard Worker void MultiStateCounter<T, V>::addValue(const V& value) {
288*38e8c45fSAndroid Build Coastguard Worker     if (!isEnabled) {
289*38e8c45fSAndroid Build Coastguard Worker         return;
290*38e8c45fSAndroid Build Coastguard Worker     }
291*38e8c45fSAndroid Build Coastguard Worker     add(&states[currentState].counter, value, 1 /* numerator */, 1 /* denominator */);
292*38e8c45fSAndroid Build Coastguard Worker }
293*38e8c45fSAndroid Build Coastguard Worker 
294*38e8c45fSAndroid Build Coastguard Worker template <class T, class V>
reset()295*38e8c45fSAndroid Build Coastguard Worker void MultiStateCounter<T, V>::reset() {
296*38e8c45fSAndroid Build Coastguard Worker     lastStateChangeTimestamp = -1;
297*38e8c45fSAndroid Build Coastguard Worker     lastUpdateTimestamp = -1;
298*38e8c45fSAndroid Build Coastguard Worker     for (int i = 0; i < stateCount; i++) {
299*38e8c45fSAndroid Build Coastguard Worker         states[i].timeInStateSinceUpdate = 0;
300*38e8c45fSAndroid Build Coastguard Worker         states[i].counter = emptyValue;
301*38e8c45fSAndroid Build Coastguard Worker     }
302*38e8c45fSAndroid Build Coastguard Worker }
303*38e8c45fSAndroid Build Coastguard Worker 
304*38e8c45fSAndroid Build Coastguard Worker template <class T, class V>
getStateCount()305*38e8c45fSAndroid Build Coastguard Worker uint16_t MultiStateCounter<T, V>::getStateCount() {
306*38e8c45fSAndroid Build Coastguard Worker     return stateCount;
307*38e8c45fSAndroid Build Coastguard Worker }
308*38e8c45fSAndroid Build Coastguard Worker 
309*38e8c45fSAndroid Build Coastguard Worker template <class T, class V>
getCount(state_t state)310*38e8c45fSAndroid Build Coastguard Worker const V& MultiStateCounter<T, V>::getCount(state_t state) {
311*38e8c45fSAndroid Build Coastguard Worker     return states[state].counter;
312*38e8c45fSAndroid Build Coastguard Worker }
313*38e8c45fSAndroid Build Coastguard Worker 
314*38e8c45fSAndroid Build Coastguard Worker template <class T, class V>
toString()315*38e8c45fSAndroid Build Coastguard Worker std::string MultiStateCounter<T, V>::toString() {
316*38e8c45fSAndroid Build Coastguard Worker     std::stringstream str;
317*38e8c45fSAndroid Build Coastguard Worker //    str << "LAST VALUE: " << valueToString(lastValue);
318*38e8c45fSAndroid Build Coastguard Worker     str << "[";
319*38e8c45fSAndroid Build Coastguard Worker     for (int i = 0; i < stateCount; i++) {
320*38e8c45fSAndroid Build Coastguard Worker         if (i != 0) {
321*38e8c45fSAndroid Build Coastguard Worker             str << ", ";
322*38e8c45fSAndroid Build Coastguard Worker         }
323*38e8c45fSAndroid Build Coastguard Worker         str << i << ": " << states[i].counter;
324*38e8c45fSAndroid Build Coastguard Worker         if (states[i].timeInStateSinceUpdate > 0) {
325*38e8c45fSAndroid Build Coastguard Worker             str << " timeInStateSinceUpdate: " << states[i].timeInStateSinceUpdate;
326*38e8c45fSAndroid Build Coastguard Worker         }
327*38e8c45fSAndroid Build Coastguard Worker     }
328*38e8c45fSAndroid Build Coastguard Worker     str << "]";
329*38e8c45fSAndroid Build Coastguard Worker     if (lastUpdateTimestamp >= 0) {
330*38e8c45fSAndroid Build Coastguard Worker         str << " updated: " << lastUpdateTimestamp;
331*38e8c45fSAndroid Build Coastguard Worker     }
332*38e8c45fSAndroid Build Coastguard Worker     if (lastStateChangeTimestamp >= 0) {
333*38e8c45fSAndroid Build Coastguard Worker         str << " currentState: " << currentState;
334*38e8c45fSAndroid Build Coastguard Worker         if (lastStateChangeTimestamp > lastUpdateTimestamp) {
335*38e8c45fSAndroid Build Coastguard Worker             str << " stateChanged: " << lastStateChangeTimestamp;
336*38e8c45fSAndroid Build Coastguard Worker         }
337*38e8c45fSAndroid Build Coastguard Worker     } else {
338*38e8c45fSAndroid Build Coastguard Worker         str << " currentState: none";
339*38e8c45fSAndroid Build Coastguard Worker     }
340*38e8c45fSAndroid Build Coastguard Worker     if (!isEnabled) {
341*38e8c45fSAndroid Build Coastguard Worker         str << " disabled";
342*38e8c45fSAndroid Build Coastguard Worker     }
343*38e8c45fSAndroid Build Coastguard Worker     return str.str();
344*38e8c45fSAndroid Build Coastguard Worker }
345*38e8c45fSAndroid Build Coastguard Worker 
346*38e8c45fSAndroid Build Coastguard Worker } // namespace battery
347*38e8c45fSAndroid Build Coastguard Worker } // namespace android
348