blob: ab861275073c7e0748bf99a6b8daf191bb16611a [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
tsaichristine69000e62019-10-18 17:34:52 -070028StateTracker::StateTracker(const int32_t atomId, const util::StateAtomFieldOptions& stateAtomInfo)
tsaichristine5adc7e02020-01-14 17:07:39 -080029 : mAtomId(atomId),
30 mStateField(getSimpleMatcher(atomId, stateAtomInfo.exclusiveField)),
31 mNested(stateAtomInfo.nested) {
tsaichristine10978642019-09-10 14:12:49 -070032 // create matcher for each primary field
tsaichristineed615642020-01-02 12:53:41 -080033 for (const auto& primaryField : stateAtomInfo.primaryFields) {
34 if (primaryField == util::FIRST_UID_IN_CHAIN) {
35 Matcher matcher = getFirstUidMatcher(atomId);
36 mPrimaryFields.push_back(matcher);
37 } else {
38 Matcher matcher = getSimpleMatcher(atomId, primaryField);
39 mPrimaryFields.push_back(matcher);
40 }
tsaichristine10978642019-09-10 14:12:49 -070041 }
42
tsaichristine5adc7e02020-01-14 17:07:39 -080043 if (stateAtomInfo.defaultState != util::UNSET_VALUE) {
44 mDefaultState = stateAtomInfo.defaultState;
45 }
46
47 if (stateAtomInfo.resetState != util::UNSET_VALUE) {
48 mResetState = stateAtomInfo.resetState;
49 }
tsaichristine10978642019-09-10 14:12:49 -070050}
51
52void StateTracker::onLogEvent(const LogEvent& event) {
tsaichristine8d73dc92019-12-06 02:11:02 -080053 int64_t eventTimeNs = event.GetElapsedTimestampNs();
54
55 // Parse event for primary field values i.e. primary key.
tsaichristine10978642019-09-10 14:12:49 -070056 HashableDimensionKey primaryKey;
57 if (mPrimaryFields.size() > 0) {
58 if (!filterValues(mPrimaryFields, event.getValues(), &primaryKey) ||
59 primaryKey.getValues().size() != mPrimaryFields.size()) {
60 ALOGE("StateTracker error extracting primary key from log event.");
tsaichristine8d73dc92019-12-06 02:11:02 -080061 handleReset(eventTimeNs);
tsaichristine10978642019-09-10 14:12:49 -070062 return;
63 }
64 } else {
tsaichristine8d73dc92019-12-06 02:11:02 -080065 // Use an empty HashableDimensionKey if atom has no primary fields.
tsaichristine10978642019-09-10 14:12:49 -070066 primaryKey = DEFAULT_DIMENSION_KEY;
67 }
68
tsaichristine8d73dc92019-12-06 02:11:02 -080069 // Parse event for state value.
tsaichristine69000e62019-10-18 17:34:52 -070070 FieldValue stateValue;
tsaichristine69000e62019-10-18 17:34:52 -070071 if (!filterValues(mStateField, event.getValues(), &stateValue) ||
72 stateValue.mValue.getType() != INT) {
73 ALOGE("StateTracker error extracting state from log event. Type: %d",
74 stateValue.mValue.getType());
tsaichristine8d73dc92019-12-06 02:11:02 -080075 handlePartialReset(eventTimeNs, primaryKey);
tsaichristine10978642019-09-10 14:12:49 -070076 return;
77 }
tsaichristine10978642019-09-10 14:12:49 -070078
tsaichristine5adc7e02020-01-14 17:07:39 -080079 int32_t state = stateValue.mValue.int_value;
tsaichristine69000e62019-10-18 17:34:52 -070080 if (state == mResetState) {
81 VLOG("StateTracker Reset state: %s", stateValue.mValue.toString().c_str());
tsaichristine8d73dc92019-12-06 02:11:02 -080082 handleReset(eventTimeNs);
tsaichristine5adc7e02020-01-14 17:07:39 -080083 return;
tsaichristine10978642019-09-10 14:12:49 -070084 }
85
tsaichristine8d73dc92019-12-06 02:11:02 -080086 // Track and update state.
tsaichristine10978642019-09-10 14:12:49 -070087 int32_t oldState = 0;
88 int32_t newState = 0;
tsaichristine69000e62019-10-18 17:34:52 -070089 updateState(primaryKey, state, &oldState, &newState);
tsaichristine10978642019-09-10 14:12:49 -070090
tsaichristine8d73dc92019-12-06 02:11:02 -080091 // Notify all listeners if state has changed.
tsaichristine10978642019-09-10 14:12:49 -070092 if (oldState != newState) {
93 VLOG("StateTracker updated state");
94 for (auto listener : mListeners) {
95 auto sListener = listener.promote(); // safe access to wp<>
96 if (sListener != nullptr) {
tsaichristine8d73dc92019-12-06 02:11:02 -080097 sListener->onStateChanged(eventTimeNs, mAtomId, primaryKey, oldState, newState);
tsaichristine10978642019-09-10 14:12:49 -070098 }
99 }
100 } else {
101 VLOG("StateTracker NO updated state");
102 }
103}
104
105void StateTracker::registerListener(wp<StateListener> listener) {
106 mListeners.insert(listener);
107}
108
109void StateTracker::unregisterListener(wp<StateListener> listener) {
110 mListeners.erase(listener);
111}
112
tsaichristine69000e62019-10-18 17:34:52 -0700113bool StateTracker::getStateValue(const HashableDimensionKey& queryKey, FieldValue* output) const {
114 output->mField = mStateField.mMatcher;
115
116 // Check that the query key has the correct number of primary fields.
tsaichristine10978642019-09-10 14:12:49 -0700117 if (queryKey.getValues().size() == mPrimaryFields.size()) {
118 auto it = mStateMap.find(queryKey);
119 if (it != mStateMap.end()) {
tsaichristine69000e62019-10-18 17:34:52 -0700120 output->mValue = it->second.state;
121 return true;
tsaichristine10978642019-09-10 14:12:49 -0700122 }
123 } else if (queryKey.getValues().size() > mPrimaryFields.size()) {
tsaichristine5adc7e02020-01-14 17:07:39 -0800124 ALOGE("StateTracker query key size %zu > primary key size %zu is illegal",
125 queryKey.getValues().size(), mPrimaryFields.size());
tsaichristine10978642019-09-10 14:12:49 -0700126 } else {
tsaichristine5adc7e02020-01-14 17:07:39 -0800127 ALOGE("StateTracker query key size %zu < primary key size %zu is not supported",
128 queryKey.getValues().size(), mPrimaryFields.size());
tsaichristine10978642019-09-10 14:12:49 -0700129 }
tsaichristine69000e62019-10-18 17:34:52 -0700130
tsaichristine5adc7e02020-01-14 17:07:39 -0800131 // Set the state value to default state if:
tsaichristine69000e62019-10-18 17:34:52 -0700132 // - query key size is incorrect
133 // - query key is not found in state map
tsaichristine5adc7e02020-01-14 17:07:39 -0800134 output->mValue = mDefaultState;
tsaichristine69000e62019-10-18 17:34:52 -0700135 return false;
tsaichristine10978642019-09-10 14:12:49 -0700136}
137
tsaichristine8d73dc92019-12-06 02:11:02 -0800138void StateTracker::handleReset(const int64_t eventTimeNs) {
tsaichristine10978642019-09-10 14:12:49 -0700139 VLOG("StateTracker handle reset");
140 for (const auto pair : mStateMap) {
141 for (auto l : mListeners) {
142 auto sl = l.promote();
143 if (sl != nullptr) {
tsaichristine8d73dc92019-12-06 02:11:02 -0800144 sl->onStateChanged(eventTimeNs, mAtomId, pair.first, pair.second.state,
145 mDefaultState);
tsaichristine10978642019-09-10 14:12:49 -0700146 }
147 }
148 }
149 mStateMap.clear();
150}
151
tsaichristine8d73dc92019-12-06 02:11:02 -0800152void StateTracker::handlePartialReset(const int64_t eventTimeNs,
153 const HashableDimensionKey& primaryKey) {
tsaichristine10978642019-09-10 14:12:49 -0700154 VLOG("StateTracker handle partial reset");
155 if (mStateMap.find(primaryKey) != mStateMap.end()) {
tsaichristine50f5bad2019-12-06 02:56:56 -0800156 for (auto l : mListeners) {
157 auto sl = l.promote();
158 if (sl != nullptr) {
159 sl->onStateChanged(eventTimeNs, mAtomId, primaryKey,
160 mStateMap.find(primaryKey)->second.state, mDefaultState);
161 }
162 }
tsaichristine10978642019-09-10 14:12:49 -0700163 mStateMap.erase(primaryKey);
164 }
165}
166
167void StateTracker::updateState(const HashableDimensionKey& primaryKey, const int32_t eventState,
168 int32_t* oldState, int32_t* newState) {
169 // get old state (either current state in map or default state)
170 auto it = mStateMap.find(primaryKey);
171 if (it != mStateMap.end()) {
172 *oldState = it->second.state;
173 } else {
174 *oldState = mDefaultState;
175 }
176
tsaichristine5adc7e02020-01-14 17:07:39 -0800177 // Update state map for non-nested counting case.
178 // Every state event triggers a state overwrite.
179 if (!mNested) {
180 if (eventState == mDefaultState) {
181 // remove (key, state) pair if state returns to default state
182 VLOG("\t StateTracker changed to default state")
183 mStateMap.erase(primaryKey);
184 } else {
185 mStateMap[primaryKey].state = eventState;
186 mStateMap[primaryKey].count = 1;
187 }
188 *newState = eventState;
189 return;
tsaichristine10978642019-09-10 14:12:49 -0700190 }
tsaichristine10978642019-09-10 14:12:49 -0700191
tsaichristine5adc7e02020-01-14 17:07:39 -0800192 // Update state map for nested counting case.
193 //
194 // Nested counting is only allowed for binary state events such as ON/OFF or
195 // ACQUIRE/RELEASE. For example, WakelockStateChanged might have the state
196 // events: ON, ON, OFF. The state will still be ON until we see the same
197 // number of OFF events as ON events.
198 //
199 // In atoms.proto, a state atom with nested counting enabled
200 // must only have 2 states and one of the states must be the default state.
201 it = mStateMap.find(primaryKey);
202 if (it != mStateMap.end()) {
203 *newState = it->second.state;
204 if (eventState == it->second.state) {
205 it->second.count++;
206 } else if (eventState == mDefaultState) {
207 if ((--it->second.count) == 0) {
208 mStateMap.erase(primaryKey);
209 *newState = mDefaultState;
210 }
211 } else {
212 ALOGE("StateTracker Nest counting state has a third state instead of the binary state "
213 "limit.");
214 return;
215 }
216 } else {
217 if (eventState != mDefaultState) {
218 mStateMap[primaryKey].state = eventState;
219 mStateMap[primaryKey].count = 1;
220 }
221 *newState = eventState;
222 }
tsaichristine10978642019-09-10 14:12:49 -0700223}
224
225} // namespace statsd
226} // namespace os
227} // namespace android