1 /*
2 * Copyright (C) 2017 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 false // STOPSHIP if true
18 #include "Log.h"
19
20 #include "MetricProducer.h"
21
22 #include "../guardrail/StatsdStats.h"
23 #include "metrics/parsing_utils/metrics_manager_util.h"
24 #include "state/StateTracker.h"
25
26 using android::util::FIELD_COUNT_REPEATED;
27 using android::util::FIELD_TYPE_ENUM;
28 using android::util::FIELD_TYPE_INT32;
29 using android::util::FIELD_TYPE_INT64;
30 using android::util::FIELD_TYPE_MESSAGE;
31 using android::util::ProtoOutputStream;
32
33 namespace android {
34 namespace os {
35 namespace statsd {
36
37
38 // for ActiveMetric
39 const int FIELD_ID_ACTIVE_METRIC_ID = 1;
40 const int FIELD_ID_ACTIVE_METRIC_ACTIVATION = 2;
41
42 // for ActiveEventActivation
43 const int FIELD_ID_ACTIVE_EVENT_ACTIVATION_ATOM_MATCHER_INDEX = 1;
44 const int FIELD_ID_ACTIVE_EVENT_ACTIVATION_REMAINING_TTL_NANOS = 2;
45 const int FIELD_ID_ACTIVE_EVENT_ACTIVATION_STATE = 3;
46
MetricProducer(const int64_t & metricId,const ConfigKey & key,const int64_t timeBaseNs,const int conditionIndex,const vector<ConditionState> & initialConditionCache,const sp<ConditionWizard> & wizard,const uint64_t protoHash,const std::unordered_map<int,std::shared_ptr<Activation>> & eventActivationMap,const std::unordered_map<int,std::vector<std::shared_ptr<Activation>>> & eventDeactivationMap,const vector<int> & slicedStateAtoms,const unordered_map<int,unordered_map<int,int64_t>> & stateGroupMap)47 MetricProducer::MetricProducer(
48 const int64_t& metricId, const ConfigKey& key, const int64_t timeBaseNs,
49 const int conditionIndex, const vector<ConditionState>& initialConditionCache,
50 const sp<ConditionWizard>& wizard, const uint64_t protoHash,
51 const std::unordered_map<int, std::shared_ptr<Activation>>& eventActivationMap,
52 const std::unordered_map<int, std::vector<std::shared_ptr<Activation>>>&
53 eventDeactivationMap,
54 const vector<int>& slicedStateAtoms,
55 const unordered_map<int, unordered_map<int, int64_t>>& stateGroupMap)
56 : mMetricId(metricId),
57 mProtoHash(protoHash),
58 mConfigKey(key),
59 mValid(true),
60 mTimeBaseNs(timeBaseNs),
61 mCurrentBucketStartTimeNs(timeBaseNs),
62 mCurrentBucketNum(0),
63 mCondition(initialCondition(conditionIndex, initialConditionCache)),
64 mConditionTrackerIndex(conditionIndex),
65 mConditionSliced(false),
66 mWizard(wizard),
67 mContainANYPositionInDimensionsInWhat(false),
68 mSliceByPositionALL(false),
69 mHasLinksToAllConditionDimensionsInTracker(false),
70 mEventActivationMap(eventActivationMap),
71 mEventDeactivationMap(eventDeactivationMap),
72 mIsActive(mEventActivationMap.empty()),
73 mSlicedStateAtoms(slicedStateAtoms),
74 mStateGroupMap(stateGroupMap) {
75 }
76
onConfigUpdatedLocked(const StatsdConfig & config,const int configIndex,const int metricIndex,const vector<sp<AtomMatchingTracker>> & allAtomMatchingTrackers,const unordered_map<int64_t,int> & oldAtomMatchingTrackerMap,const unordered_map<int64_t,int> & newAtomMatchingTrackerMap,const sp<EventMatcherWizard> & matcherWizard,const vector<sp<ConditionTracker>> & allConditionTrackers,const unordered_map<int64_t,int> & conditionTrackerMap,const sp<ConditionWizard> & wizard,const unordered_map<int64_t,int> & metricToActivationMap,unordered_map<int,vector<int>> & trackerToMetricMap,unordered_map<int,vector<int>> & conditionToMetricMap,unordered_map<int,vector<int>> & activationAtomTrackerToMetricMap,unordered_map<int,vector<int>> & deactivationAtomTrackerToMetricMap,vector<int> & metricsWithActivation)77 bool MetricProducer::onConfigUpdatedLocked(
78 const StatsdConfig& config, const int configIndex, const int metricIndex,
79 const vector<sp<AtomMatchingTracker>>& allAtomMatchingTrackers,
80 const unordered_map<int64_t, int>& oldAtomMatchingTrackerMap,
81 const unordered_map<int64_t, int>& newAtomMatchingTrackerMap,
82 const sp<EventMatcherWizard>& matcherWizard,
83 const vector<sp<ConditionTracker>>& allConditionTrackers,
84 const unordered_map<int64_t, int>& conditionTrackerMap, const sp<ConditionWizard>& wizard,
85 const unordered_map<int64_t, int>& metricToActivationMap,
86 unordered_map<int, vector<int>>& trackerToMetricMap,
87 unordered_map<int, vector<int>>& conditionToMetricMap,
88 unordered_map<int, vector<int>>& activationAtomTrackerToMetricMap,
89 unordered_map<int, vector<int>>& deactivationAtomTrackerToMetricMap,
90 vector<int>& metricsWithActivation) {
91 sp<ConditionWizard> tmpWizard = mWizard;
92 mWizard = wizard;
93
94 unordered_map<int, shared_ptr<Activation>> newEventActivationMap;
95 unordered_map<int, vector<shared_ptr<Activation>>> newEventDeactivationMap;
96 if (!handleMetricActivationOnConfigUpdate(
97 config, mMetricId, metricIndex, metricToActivationMap, oldAtomMatchingTrackerMap,
98 newAtomMatchingTrackerMap, mEventActivationMap, activationAtomTrackerToMetricMap,
99 deactivationAtomTrackerToMetricMap, metricsWithActivation, newEventActivationMap,
100 newEventDeactivationMap)) {
101 return false;
102 }
103 mEventActivationMap = newEventActivationMap;
104 mEventDeactivationMap = newEventDeactivationMap;
105 mAnomalyTrackers.clear();
106 return true;
107 }
108
onMatchedLogEventLocked(const size_t matcherIndex,const LogEvent & event)109 void MetricProducer::onMatchedLogEventLocked(const size_t matcherIndex, const LogEvent& event) {
110 if (!mIsActive) {
111 return;
112 }
113 int64_t eventTimeNs = event.GetElapsedTimestampNs();
114 // this is old event, maybe statsd restarted?
115 if (eventTimeNs < mTimeBaseNs) {
116 return;
117 }
118
119 bool condition;
120 ConditionKey conditionKey;
121 if (mConditionSliced) {
122 for (const auto& link : mMetric2ConditionLinks) {
123 getDimensionForCondition(event.getValues(), link, &conditionKey[link.conditionId]);
124 }
125 auto conditionState =
126 mWizard->query(mConditionTrackerIndex, conditionKey,
127 !mHasLinksToAllConditionDimensionsInTracker);
128 condition = (conditionState == ConditionState::kTrue);
129 } else {
130 // TODO: The unknown condition state is not handled here, we should fix it.
131 condition = mCondition == ConditionState::kTrue;
132 }
133
134 // Stores atom id to primary key pairs for each state atom that the metric is
135 // sliced by.
136 std::map<int32_t, HashableDimensionKey> statePrimaryKeys;
137
138 // For states with primary fields, use MetricStateLinks to get the primary
139 // field values from the log event. These values will form a primary key
140 // that will be used to query StateTracker for the correct state value.
141 for (const auto& stateLink : mMetric2StateLinks) {
142 getDimensionForState(event.getValues(), stateLink,
143 &statePrimaryKeys[stateLink.stateAtomId]);
144 }
145
146 // For each sliced state, query StateTracker for the state value using
147 // either the primary key from the previous step or the DEFAULT_DIMENSION_KEY.
148 //
149 // Expected functionality: for any case where the MetricStateLinks are
150 // initialized incorrectly (ex. # of state links != # of primary fields, no
151 // links are provided for a state with primary fields, links are provided
152 // in the wrong order, etc.), StateTracker will simply return kStateUnknown
153 // when queried using an incorrect key.
154 HashableDimensionKey stateValuesKey;
155 for (auto atomId : mSlicedStateAtoms) {
156 FieldValue value;
157 if (statePrimaryKeys.find(atomId) != statePrimaryKeys.end()) {
158 // found a primary key for this state, query using the key
159 queryStateValue(atomId, statePrimaryKeys[atomId], &value);
160 } else {
161 // if no MetricStateLinks exist for this state atom,
162 // query using the default dimension key (empty HashableDimensionKey)
163 queryStateValue(atomId, DEFAULT_DIMENSION_KEY, &value);
164 }
165 mapStateValue(atomId, &value);
166 stateValuesKey.addValue(value);
167 }
168
169 HashableDimensionKey dimensionInWhat;
170 filterValues(mDimensionsInWhat, event.getValues(), &dimensionInWhat);
171 MetricDimensionKey metricKey(dimensionInWhat, stateValuesKey);
172 onMatchedLogEventInternalLocked(matcherIndex, metricKey, conditionKey, condition, event,
173 statePrimaryKeys);
174 }
175
evaluateActiveStateLocked(int64_t elapsedTimestampNs)176 bool MetricProducer::evaluateActiveStateLocked(int64_t elapsedTimestampNs) {
177 bool isActive = mEventActivationMap.empty();
178 for (auto& it : mEventActivationMap) {
179 if (it.second->state == ActivationState::kActive &&
180 elapsedTimestampNs > it.second->ttl_ns + it.second->start_ns) {
181 it.second->state = ActivationState::kNotActive;
182 }
183 if (it.second->state == ActivationState::kActive) {
184 isActive = true;
185 }
186 }
187 return isActive;
188 }
189
flushIfExpire(int64_t elapsedTimestampNs)190 void MetricProducer::flushIfExpire(int64_t elapsedTimestampNs) {
191 std::lock_guard<std::mutex> lock(mMutex);
192 if (!mIsActive) {
193 return;
194 }
195 mIsActive = evaluateActiveStateLocked(elapsedTimestampNs);
196 if (!mIsActive) {
197 onActiveStateChangedLocked(elapsedTimestampNs);
198 }
199 }
200
activateLocked(int activationTrackerIndex,int64_t elapsedTimestampNs)201 void MetricProducer::activateLocked(int activationTrackerIndex, int64_t elapsedTimestampNs) {
202 auto it = mEventActivationMap.find(activationTrackerIndex);
203 if (it == mEventActivationMap.end()) {
204 return;
205 }
206 auto& activation = it->second;
207 if (ACTIVATE_ON_BOOT == activation->activationType) {
208 if (ActivationState::kNotActive == activation->state) {
209 activation->state = ActivationState::kActiveOnBoot;
210 }
211 // If the Activation is already active or set to kActiveOnBoot, do nothing.
212 return;
213 }
214 activation->start_ns = elapsedTimestampNs;
215 activation->state = ActivationState::kActive;
216 bool oldActiveState = mIsActive;
217 mIsActive = true;
218 if (!oldActiveState) { // Metric went from not active to active.
219 onActiveStateChangedLocked(elapsedTimestampNs);
220 }
221 }
222
cancelEventActivationLocked(int deactivationTrackerIndex)223 void MetricProducer::cancelEventActivationLocked(int deactivationTrackerIndex) {
224 auto it = mEventDeactivationMap.find(deactivationTrackerIndex);
225 if (it == mEventDeactivationMap.end()) {
226 return;
227 }
228 for (auto activationToCancelIt : it->second) {
229 activationToCancelIt->state = ActivationState::kNotActive;
230 }
231 }
232
loadActiveMetricLocked(const ActiveMetric & activeMetric,int64_t currentTimeNs)233 void MetricProducer::loadActiveMetricLocked(const ActiveMetric& activeMetric,
234 int64_t currentTimeNs) {
235 if (mEventActivationMap.size() == 0) {
236 return;
237 }
238 for (int i = 0; i < activeMetric.activation_size(); i++) {
239 const auto& activeEventActivation = activeMetric.activation(i);
240 auto it = mEventActivationMap.find(activeEventActivation.atom_matcher_index());
241 if (it == mEventActivationMap.end()) {
242 ALOGE("Saved event activation not found");
243 continue;
244 }
245 auto& activation = it->second;
246 // If the event activation does not have a state, assume it is active.
247 if (!activeEventActivation.has_state() ||
248 activeEventActivation.state() == ActiveEventActivation::ACTIVE) {
249 // We don't want to change the ttl for future activations, so we set the start_ns
250 // such that start_ns + ttl_ns == currentTimeNs + remaining_ttl_nanos
251 activation->start_ns =
252 currentTimeNs + activeEventActivation.remaining_ttl_nanos() - activation->ttl_ns;
253 activation->state = ActivationState::kActive;
254 mIsActive = true;
255 } else if (activeEventActivation.state() == ActiveEventActivation::ACTIVATE_ON_BOOT) {
256 activation->state = ActivationState::kActiveOnBoot;
257 }
258 }
259 }
260
writeActiveMetricToProtoOutputStream(int64_t currentTimeNs,const DumpReportReason reason,ProtoOutputStream * proto)261 void MetricProducer::writeActiveMetricToProtoOutputStream(
262 int64_t currentTimeNs, const DumpReportReason reason, ProtoOutputStream* proto) {
263 proto->write(FIELD_TYPE_INT64 | FIELD_ID_ACTIVE_METRIC_ID, (long long)mMetricId);
264 for (auto& it : mEventActivationMap) {
265 const int atom_matcher_index = it.first;
266 const std::shared_ptr<Activation>& activation = it.second;
267
268 if (ActivationState::kNotActive == activation->state ||
269 (ActivationState::kActive == activation->state &&
270 activation->start_ns + activation->ttl_ns < currentTimeNs)) {
271 continue;
272 }
273
274 const uint64_t activationToken = proto->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED |
275 FIELD_ID_ACTIVE_METRIC_ACTIVATION);
276 proto->write(FIELD_TYPE_INT32 | FIELD_ID_ACTIVE_EVENT_ACTIVATION_ATOM_MATCHER_INDEX,
277 atom_matcher_index);
278 if (ActivationState::kActive == activation->state) {
279 const int64_t remainingTtlNs =
280 activation->start_ns + activation->ttl_ns - currentTimeNs;
281 proto->write(FIELD_TYPE_INT64 | FIELD_ID_ACTIVE_EVENT_ACTIVATION_REMAINING_TTL_NANOS,
282 (long long)remainingTtlNs);
283 proto->write(FIELD_TYPE_ENUM | FIELD_ID_ACTIVE_EVENT_ACTIVATION_STATE,
284 ActiveEventActivation::ACTIVE);
285
286 } else if (ActivationState::kActiveOnBoot == activation->state) {
287 if (reason == DEVICE_SHUTDOWN || reason == TERMINATION_SIGNAL_RECEIVED) {
288 proto->write(
289 FIELD_TYPE_INT64 | FIELD_ID_ACTIVE_EVENT_ACTIVATION_REMAINING_TTL_NANOS,
290 (long long)activation->ttl_ns);
291 proto->write(FIELD_TYPE_ENUM | FIELD_ID_ACTIVE_EVENT_ACTIVATION_STATE,
292 ActiveEventActivation::ACTIVE);
293 } else if (reason == STATSCOMPANION_DIED) {
294 // We are saving because of system server death, not due to a device shutdown.
295 // Next time we load, we do not want to activate metrics that activate on boot.
296 proto->write(FIELD_TYPE_ENUM | FIELD_ID_ACTIVE_EVENT_ACTIVATION_STATE,
297 ActiveEventActivation::ACTIVATE_ON_BOOT);
298 }
299 }
300 proto->end(activationToken);
301 }
302 }
303
queryStateValue(const int32_t atomId,const HashableDimensionKey & queryKey,FieldValue * value)304 void MetricProducer::queryStateValue(const int32_t atomId, const HashableDimensionKey& queryKey,
305 FieldValue* value) {
306 if (!StateManager::getInstance().getStateValue(atomId, queryKey, value)) {
307 value->mValue = Value(StateTracker::kStateUnknown);
308 value->mField.setTag(atomId);
309 ALOGW("StateTracker not found for state atom %d", atomId);
310 return;
311 }
312 }
313
mapStateValue(const int32_t atomId,FieldValue * value)314 void MetricProducer::mapStateValue(const int32_t atomId, FieldValue* value) {
315 // check if there is a state map for this atom
316 auto atomIt = mStateGroupMap.find(atomId);
317 if (atomIt == mStateGroupMap.end()) {
318 return;
319 }
320 auto valueIt = atomIt->second.find(value->mValue.int_value);
321 if (valueIt == atomIt->second.end()) {
322 // state map exists, but value was not put in a state group
323 // so set mValue to kStateUnknown
324 // TODO(tsaichristine): handle incomplete state maps
325 value->mValue.setInt(StateTracker::kStateUnknown);
326 } else {
327 // set mValue to group_id
328 value->mValue.setLong(valueIt->second);
329 }
330 }
331
getUnknownStateKey()332 HashableDimensionKey MetricProducer::getUnknownStateKey() {
333 HashableDimensionKey stateKey;
334 for (auto atom : mSlicedStateAtoms) {
335 FieldValue fieldValue;
336 fieldValue.mField.setTag(atom);
337 fieldValue.mValue.setInt(StateTracker::kStateUnknown);
338 stateKey.addValue(fieldValue);
339 }
340 return stateKey;
341 }
342
buildDropEvent(const int64_t dropTimeNs,const BucketDropReason reason)343 DropEvent MetricProducer::buildDropEvent(const int64_t dropTimeNs, const BucketDropReason reason) {
344 DropEvent event;
345 event.reason = reason;
346 event.dropTimeNs = dropTimeNs;
347 return event;
348 }
349
maxDropEventsReached()350 bool MetricProducer::maxDropEventsReached() {
351 return mCurrentSkippedBucket.dropEvents.size() >= StatsdStats::kMaxLoggedBucketDropEvents;
352 }
353
354 } // namespace statsd
355 } // namespace os
356 } // namespace android
357