blob: 41e525c343baee53a4617734374725678510795d [file] [log] [blame]
tsaichristine10978642019-09-10 14:12:49 -07001/*
2 * Copyright (C) 2019, 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#define DEBUG true // STOPSHIP if true
18#include "Log.h"
19
20#include "stats_util.h"
21
22#include "StateTracker.h"
23
24namespace android {
25namespace os {
26namespace statsd {
27
Muhammad Qureshibfc4bdb2020-04-08 06:26:49 -070028StateTracker::StateTracker(const int32_t atomId) : mField(atomId, 0) {
tsaichristine10978642019-09-10 14:12:49 -070029}
30
31void StateTracker::onLogEvent(const LogEvent& event) {
Muhammad Qureshibfc4bdb2020-04-08 06:26:49 -070032 const int64_t eventTimeNs = event.GetElapsedTimestampNs();
tsaichristine8d73dc92019-12-06 02:11:02 -080033
34 // Parse event for primary field values i.e. primary key.
tsaichristine10978642019-09-10 14:12:49 -070035 HashableDimensionKey primaryKey;
Muhammad Qureshibfc4bdb2020-04-08 06:26:49 -070036 filterPrimaryKey(event.getValues(), &primaryKey);
37
tsaichristine9f951052020-05-13 14:32:37 -070038 FieldValue newState;
39 if (!getStateFieldValueFromLogEvent(event, &newState)) {
Muhammad Qureshibfc4bdb2020-04-08 06:26:49 -070040 ALOGE("StateTracker error extracting state from log event. Missing exclusive state field.");
41 clearStateForPrimaryKey(eventTimeNs, primaryKey);
42 return;
tsaichristine10978642019-09-10 14:12:49 -070043 }
44
tsaichristine9f951052020-05-13 14:32:37 -070045 mField.setField(newState.mField.getField());
Muhammad Qureshibfc4bdb2020-04-08 06:26:49 -070046
tsaichristine9f951052020-05-13 14:32:37 -070047 if (newState.mValue.getType() != INT) {
tsaichristine69000e62019-10-18 17:34:52 -070048 ALOGE("StateTracker error extracting state from log event. Type: %d",
tsaichristine9f951052020-05-13 14:32:37 -070049 newState.mValue.getType());
Muhammad Qureshibfc4bdb2020-04-08 06:26:49 -070050 clearStateForPrimaryKey(eventTimeNs, primaryKey);
tsaichristine10978642019-09-10 14:12:49 -070051 return;
52 }
tsaichristine10978642019-09-10 14:12:49 -070053
tsaichristine9f951052020-05-13 14:32:37 -070054 if (int resetState = event.getResetState(); resetState != -1) {
Muhammad Qureshibfc4bdb2020-04-08 06:26:49 -070055 VLOG("StateTracker new reset state: %d", resetState);
tsaichristine9f951052020-05-13 14:32:37 -070056 const FieldValue resetStateFieldValue(mField, Value(resetState));
57 handleReset(eventTimeNs, resetStateFieldValue);
tsaichristine5adc7e02020-01-14 17:07:39 -080058 return;
tsaichristine10978642019-09-10 14:12:49 -070059 }
60
tsaichristine9f951052020-05-13 14:32:37 -070061 const bool nested = newState.mAnnotations.isNested();
Muhammad Qureshibfc4bdb2020-04-08 06:26:49 -070062 StateValueInfo* stateValueInfo = &mStateMap[primaryKey];
63 updateStateForPrimaryKey(eventTimeNs, primaryKey, newState, nested, stateValueInfo);
tsaichristine10978642019-09-10 14:12:49 -070064}
65
66void StateTracker::registerListener(wp<StateListener> listener) {
67 mListeners.insert(listener);
68}
69
70void StateTracker::unregisterListener(wp<StateListener> listener) {
71 mListeners.erase(listener);
72}
73
tsaichristine69000e62019-10-18 17:34:52 -070074bool StateTracker::getStateValue(const HashableDimensionKey& queryKey, FieldValue* output) const {
Muhammad Qureshibfc4bdb2020-04-08 06:26:49 -070075 output->mField = mField;
tsaichristine69000e62019-10-18 17:34:52 -070076
Muhammad Qureshibfc4bdb2020-04-08 06:26:49 -070077 if (const auto it = mStateMap.find(queryKey); it != mStateMap.end()) {
78 output->mValue = it->second.state;
79 return true;
tsaichristine10978642019-09-10 14:12:49 -070080 }
tsaichristine69000e62019-10-18 17:34:52 -070081
Muhammad Qureshibfc4bdb2020-04-08 06:26:49 -070082 // Set the state value to kStateUnknown if query key is not found in state map.
83 output->mValue = kStateUnknown;
tsaichristine69000e62019-10-18 17:34:52 -070084 return false;
tsaichristine10978642019-09-10 14:12:49 -070085}
86
tsaichristine9f951052020-05-13 14:32:37 -070087void StateTracker::handleReset(const int64_t eventTimeNs, const FieldValue& newState) {
tsaichristine10978642019-09-10 14:12:49 -070088 VLOG("StateTracker handle reset");
Muhammad Qureshibfc4bdb2020-04-08 06:26:49 -070089 for (auto& [primaryKey, stateValueInfo] : mStateMap) {
90 updateStateForPrimaryKey(eventTimeNs, primaryKey, newState,
91 false /* nested; treat this state change as not nested */,
92 &stateValueInfo);
tsaichristine10978642019-09-10 14:12:49 -070093 }
94}
95
Muhammad Qureshibfc4bdb2020-04-08 06:26:49 -070096void StateTracker::clearStateForPrimaryKey(const int64_t eventTimeNs,
97 const HashableDimensionKey& primaryKey) {
98 VLOG("StateTracker clear state for primary key");
99 const std::unordered_map<HashableDimensionKey, StateValueInfo>::iterator it =
100 mStateMap.find(primaryKey);
101
102 // If there is no entry for the primaryKey in mStateMap, then the state is already
103 // kStateUnknown.
tsaichristine9f951052020-05-13 14:32:37 -0700104 const FieldValue state(mField, Value(kStateUnknown));
tsaichristine10978642019-09-10 14:12:49 -0700105 if (it != mStateMap.end()) {
tsaichristine9f951052020-05-13 14:32:37 -0700106 updateStateForPrimaryKey(eventTimeNs, primaryKey, state,
Muhammad Qureshibfc4bdb2020-04-08 06:26:49 -0700107 false /* nested; treat this state change as not nested */,
108 &it->second);
109 }
110}
111
112void StateTracker::updateStateForPrimaryKey(const int64_t eventTimeNs,
113 const HashableDimensionKey& primaryKey,
tsaichristine9f951052020-05-13 14:32:37 -0700114 const FieldValue& newState, const bool nested,
Muhammad Qureshibfc4bdb2020-04-08 06:26:49 -0700115 StateValueInfo* stateValueInfo) {
tsaichristine9f951052020-05-13 14:32:37 -0700116 FieldValue oldState;
117 oldState.mField = mField;
118 oldState.mValue.setInt(stateValueInfo->state);
119 const int32_t oldStateValue = stateValueInfo->state;
120 const int32_t newStateValue = newState.mValue.int_value;
Muhammad Qureshibfc4bdb2020-04-08 06:26:49 -0700121
tsaichristine9f951052020-05-13 14:32:37 -0700122 if (kStateUnknown == newStateValue) {
Muhammad Qureshibfc4bdb2020-04-08 06:26:49 -0700123 mStateMap.erase(primaryKey);
tsaichristine10978642019-09-10 14:12:49 -0700124 }
125
tsaichristine5adc7e02020-01-14 17:07:39 -0800126 // Update state map for non-nested counting case.
127 // Every state event triggers a state overwrite.
Muhammad Qureshibfc4bdb2020-04-08 06:26:49 -0700128 if (!nested) {
tsaichristine9f951052020-05-13 14:32:37 -0700129 stateValueInfo->state = newStateValue;
Muhammad Qureshibfc4bdb2020-04-08 06:26:49 -0700130 stateValueInfo->count = 1;
131
132 // Notify listeners if state has changed.
tsaichristine9f951052020-05-13 14:32:37 -0700133 if (oldStateValue != newStateValue) {
Muhammad Qureshibfc4bdb2020-04-08 06:26:49 -0700134 notifyListeners(eventTimeNs, primaryKey, oldState, newState);
tsaichristine5adc7e02020-01-14 17:07:39 -0800135 }
tsaichristine5adc7e02020-01-14 17:07:39 -0800136 return;
tsaichristine10978642019-09-10 14:12:49 -0700137 }
tsaichristine10978642019-09-10 14:12:49 -0700138
tsaichristine5adc7e02020-01-14 17:07:39 -0800139 // Update state map for nested counting case.
140 //
141 // Nested counting is only allowed for binary state events such as ON/OFF or
142 // ACQUIRE/RELEASE. For example, WakelockStateChanged might have the state
143 // events: ON, ON, OFF. The state will still be ON until we see the same
144 // number of OFF events as ON events.
145 //
146 // In atoms.proto, a state atom with nested counting enabled
Muhammad Qureshibfc4bdb2020-04-08 06:26:49 -0700147 // must only have 2 states. There is no enforcemnt here of this requirement.
148 // The atom must be logged correctly.
tsaichristine9f951052020-05-13 14:32:37 -0700149 if (kStateUnknown == newStateValue) {
150 if (kStateUnknown != oldStateValue) {
Muhammad Qureshibfc4bdb2020-04-08 06:26:49 -0700151 notifyListeners(eventTimeNs, primaryKey, oldState, newState);
tsaichristine5adc7e02020-01-14 17:07:39 -0800152 }
tsaichristine9f951052020-05-13 14:32:37 -0700153 } else if (oldStateValue == kStateUnknown) {
154 stateValueInfo->state = newStateValue;
Muhammad Qureshibfc4bdb2020-04-08 06:26:49 -0700155 stateValueInfo->count = 1;
156 notifyListeners(eventTimeNs, primaryKey, oldState, newState);
tsaichristine9f951052020-05-13 14:32:37 -0700157 } else if (oldStateValue == newStateValue) {
Muhammad Qureshibfc4bdb2020-04-08 06:26:49 -0700158 stateValueInfo->count++;
159 } else if (--stateValueInfo->count == 0) {
tsaichristine9f951052020-05-13 14:32:37 -0700160 stateValueInfo->state = newStateValue;
Muhammad Qureshibfc4bdb2020-04-08 06:26:49 -0700161 stateValueInfo->count = 1;
162 notifyListeners(eventTimeNs, primaryKey, oldState, newState);
tsaichristine5adc7e02020-01-14 17:07:39 -0800163 }
tsaichristine10978642019-09-10 14:12:49 -0700164}
165
Muhammad Qureshibfc4bdb2020-04-08 06:26:49 -0700166void StateTracker::notifyListeners(const int64_t eventTimeNs,
tsaichristine9f951052020-05-13 14:32:37 -0700167 const HashableDimensionKey& primaryKey,
168 const FieldValue& oldState, const FieldValue& newState) {
Muhammad Qureshibfc4bdb2020-04-08 06:26:49 -0700169 for (auto l : mListeners) {
170 auto sl = l.promote();
171 if (sl != nullptr) {
172 sl->onStateChanged(eventTimeNs, mField.getTag(), primaryKey, oldState, newState);
173 }
174 }
175}
176
177bool getStateFieldValueFromLogEvent(const LogEvent& event, FieldValue* output) {
178 const int exclusiveStateFieldIndex = event.getExclusiveStateFieldIndex();
179 if (-1 == exclusiveStateFieldIndex) {
180 ALOGE("error extracting state from log event. Missing exclusive state field.");
181 return false;
182 }
183
184 *output = event.getValues()[exclusiveStateFieldIndex];
185 return true;
186}
187
tsaichristine10978642019-09-10 14:12:49 -0700188} // namespace statsd
189} // namespace os
190} // namespace android