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 "metrics_manager_util.h"
21
22 #include <inttypes.h>
23
24 #include "FieldValue.h"
25 #include "condition/CombinationConditionTracker.h"
26 #include "condition/SimpleConditionTracker.h"
27 #include "external/StatsPullerManager.h"
28 #include "hash.h"
29 #include "matchers/CombinationAtomMatchingTracker.h"
30 #include "matchers/EventMatcherWizard.h"
31 #include "matchers/SimpleAtomMatchingTracker.h"
32 #include "metrics/CountMetricProducer.h"
33 #include "metrics/DurationMetricProducer.h"
34 #include "metrics/EventMetricProducer.h"
35 #include "metrics/GaugeMetricProducer.h"
36 #include "metrics/MetricProducer.h"
37 #include "metrics/ValueMetricProducer.h"
38 #include "state/StateManager.h"
39 #include "stats_util.h"
40
41 using google::protobuf::MessageLite;
42 using std::set;
43 using std::unordered_map;
44 using std::vector;
45
46 namespace android {
47 namespace os {
48 namespace statsd {
49
50 namespace {
51
hasLeafNode(const FieldMatcher & matcher)52 bool hasLeafNode(const FieldMatcher& matcher) {
53 if (!matcher.has_field()) {
54 return false;
55 }
56 for (int i = 0; i < matcher.child_size(); ++i) {
57 if (hasLeafNode(matcher.child(i))) {
58 return true;
59 }
60 }
61 return true;
62 }
63
64 } // namespace
65
createAtomMatchingTracker(const AtomMatcher & logMatcher,const int index,const sp<UidMap> & uidMap)66 sp<AtomMatchingTracker> createAtomMatchingTracker(const AtomMatcher& logMatcher, const int index,
67 const sp<UidMap>& uidMap) {
68 string serializedMatcher;
69 if (!logMatcher.SerializeToString(&serializedMatcher)) {
70 ALOGE("Unable to serialize matcher %lld", (long long)logMatcher.id());
71 return nullptr;
72 }
73 uint64_t protoHash = Hash64(serializedMatcher);
74 switch (logMatcher.contents_case()) {
75 case AtomMatcher::ContentsCase::kSimpleAtomMatcher:
76 return new SimpleAtomMatchingTracker(logMatcher.id(), index, protoHash,
77 logMatcher.simple_atom_matcher(), uidMap);
78 case AtomMatcher::ContentsCase::kCombination:
79 return new CombinationAtomMatchingTracker(logMatcher.id(), index, protoHash);
80 default:
81 ALOGE("Matcher \"%lld\" malformed", (long long)logMatcher.id());
82 return nullptr;
83 }
84 }
85
createConditionTracker(const ConfigKey & key,const Predicate & predicate,const int index,const unordered_map<int64_t,int> & atomMatchingTrackerMap)86 sp<ConditionTracker> createConditionTracker(
87 const ConfigKey& key, const Predicate& predicate, const int index,
88 const unordered_map<int64_t, int>& atomMatchingTrackerMap) {
89 string serializedPredicate;
90 if (!predicate.SerializeToString(&serializedPredicate)) {
91 ALOGE("Unable to serialize predicate %lld", (long long)predicate.id());
92 return nullptr;
93 }
94 uint64_t protoHash = Hash64(serializedPredicate);
95 switch (predicate.contents_case()) {
96 case Predicate::ContentsCase::kSimplePredicate: {
97 return new SimpleConditionTracker(key, predicate.id(), protoHash, index,
98 predicate.simple_predicate(), atomMatchingTrackerMap);
99 }
100 case Predicate::ContentsCase::kCombination: {
101 return new CombinationConditionTracker(predicate.id(), index, protoHash);
102 }
103 default:
104 ALOGE("Predicate \"%lld\" malformed", (long long)predicate.id());
105 return nullptr;
106 }
107 }
108
getMetricProtoHash(const StatsdConfig & config,const MessageLite & metric,const int64_t id,const unordered_map<int64_t,int> & metricToActivationMap,uint64_t & metricHash)109 bool getMetricProtoHash(const StatsdConfig& config, const MessageLite& metric, const int64_t id,
110 const unordered_map<int64_t, int>& metricToActivationMap,
111 uint64_t& metricHash) {
112 string serializedMetric;
113 if (!metric.SerializeToString(&serializedMetric)) {
114 ALOGE("Unable to serialize metric %lld", (long long)id);
115 return false;
116 }
117 metricHash = Hash64(serializedMetric);
118
119 // Combine with activation hash, if applicable
120 const auto& metricActivationIt = metricToActivationMap.find(id);
121 if (metricActivationIt != metricToActivationMap.end()) {
122 string serializedActivation;
123 const MetricActivation& activation = config.metric_activation(metricActivationIt->second);
124 if (!activation.SerializeToString(&serializedActivation)) {
125 ALOGE("Unable to serialize metric activation for metric %lld", (long long)id);
126 return false;
127 }
128 metricHash = Hash64(to_string(metricHash).append(to_string(Hash64(serializedActivation))));
129 }
130 return true;
131 }
132
handleMetricWithAtomMatchingTrackers(const int64_t matcherId,const int metricIndex,const bool enforceOneAtom,const vector<sp<AtomMatchingTracker>> & allAtomMatchingTrackers,const unordered_map<int64_t,int> & atomMatchingTrackerMap,unordered_map<int,vector<int>> & trackerToMetricMap,int & logTrackerIndex)133 bool handleMetricWithAtomMatchingTrackers(
134 const int64_t matcherId, const int metricIndex, const bool enforceOneAtom,
135 const vector<sp<AtomMatchingTracker>>& allAtomMatchingTrackers,
136 const unordered_map<int64_t, int>& atomMatchingTrackerMap,
137 unordered_map<int, vector<int>>& trackerToMetricMap, int& logTrackerIndex) {
138 auto logTrackerIt = atomMatchingTrackerMap.find(matcherId);
139 if (logTrackerIt == atomMatchingTrackerMap.end()) {
140 ALOGW("cannot find the AtomMatcher \"%lld\" in config", (long long)matcherId);
141 return false;
142 }
143 if (enforceOneAtom && allAtomMatchingTrackers[logTrackerIt->second]->getAtomIds().size() > 1) {
144 ALOGE("AtomMatcher \"%lld\" has more than one tag ids. When a metric has dimension, "
145 "the \"what\" can only be about one atom type. trigger_event matchers can also only "
146 "be about one atom type.",
147 (long long)matcherId);
148 return false;
149 }
150 logTrackerIndex = logTrackerIt->second;
151 auto& metric_list = trackerToMetricMap[logTrackerIndex];
152 metric_list.push_back(metricIndex);
153 return true;
154 }
155
handleMetricWithConditions(const int64_t condition,const int metricIndex,const unordered_map<int64_t,int> & conditionTrackerMap,const::google::protobuf::RepeatedPtrField<::android::os::statsd::MetricConditionLink> & links,const vector<sp<ConditionTracker>> & allConditionTrackers,int & conditionIndex,unordered_map<int,vector<int>> & conditionToMetricMap)156 bool handleMetricWithConditions(
157 const int64_t condition, const int metricIndex,
158 const unordered_map<int64_t, int>& conditionTrackerMap,
159 const ::google::protobuf::RepeatedPtrField<::android::os::statsd::MetricConditionLink>&
160 links,
161 const vector<sp<ConditionTracker>>& allConditionTrackers, int& conditionIndex,
162 unordered_map<int, vector<int>>& conditionToMetricMap) {
163 auto condition_it = conditionTrackerMap.find(condition);
164 if (condition_it == conditionTrackerMap.end()) {
165 ALOGW("cannot find Predicate \"%lld\" in the config", (long long)condition);
166 return false;
167 }
168
169 for (const auto& link : links) {
170 auto it = conditionTrackerMap.find(link.condition());
171 if (it == conditionTrackerMap.end()) {
172 ALOGW("cannot find Predicate \"%lld\" in the config", (long long)link.condition());
173 return false;
174 }
175 }
176 conditionIndex = condition_it->second;
177
178 // will create new vector if not exist before.
179 auto& metricList = conditionToMetricMap[condition_it->second];
180 metricList.push_back(metricIndex);
181 return true;
182 }
183
184 // Initializes state data structures for a metric.
185 // input:
186 // [config]: the input config
187 // [stateIds]: the slice_by_state ids for this metric
188 // [stateAtomIdMap]: this map contains the mapping from all state ids to atom ids
189 // [allStateGroupMaps]: this map contains the mapping from state ids and state
190 // values to state group ids for all states
191 // output:
192 // [slicedStateAtoms]: a vector of atom ids of all the slice_by_states
193 // [stateGroupMap]: this map should contain the mapping from states ids and state
194 // values to state group ids for all states that this metric
195 // is interested in
handleMetricWithStates(const StatsdConfig & config,const::google::protobuf::RepeatedField<int64_t> & stateIds,const unordered_map<int64_t,int> & stateAtomIdMap,const unordered_map<int64_t,unordered_map<int,int64_t>> & allStateGroupMaps,vector<int> & slicedStateAtoms,unordered_map<int,unordered_map<int,int64_t>> & stateGroupMap)196 bool handleMetricWithStates(
197 const StatsdConfig& config, const ::google::protobuf::RepeatedField<int64_t>& stateIds,
198 const unordered_map<int64_t, int>& stateAtomIdMap,
199 const unordered_map<int64_t, unordered_map<int, int64_t>>& allStateGroupMaps,
200 vector<int>& slicedStateAtoms,
201 unordered_map<int, unordered_map<int, int64_t>>& stateGroupMap) {
202 for (const auto& stateId : stateIds) {
203 auto it = stateAtomIdMap.find(stateId);
204 if (it == stateAtomIdMap.end()) {
205 ALOGW("cannot find State %" PRId64 " in the config", stateId);
206 return false;
207 }
208 int atomId = it->second;
209 slicedStateAtoms.push_back(atomId);
210
211 auto stateIt = allStateGroupMaps.find(stateId);
212 if (stateIt != allStateGroupMaps.end()) {
213 stateGroupMap[atomId] = stateIt->second;
214 }
215 }
216 return true;
217 }
218
handleMetricWithStateLink(const FieldMatcher & stateMatcher,const vector<Matcher> & dimensionsInWhat)219 bool handleMetricWithStateLink(const FieldMatcher& stateMatcher,
220 const vector<Matcher>& dimensionsInWhat) {
221 vector<Matcher> stateMatchers;
222 translateFieldMatcher(stateMatcher, &stateMatchers);
223
224 return subsetDimensions(stateMatchers, dimensionsInWhat);
225 }
226
227 // Validates a metricActivation and populates state.
228 // EventActivationMap and EventDeactivationMap are supplied to a MetricProducer
229 // to provide the producer with state about its activators and deactivators.
230 // Returns false if there are errors.
handleMetricActivation(const StatsdConfig & config,const int64_t metricId,const int metricIndex,const unordered_map<int64_t,int> & metricToActivationMap,const unordered_map<int64_t,int> & atomMatchingTrackerMap,unordered_map<int,vector<int>> & activationAtomTrackerToMetricMap,unordered_map<int,vector<int>> & deactivationAtomTrackerToMetricMap,vector<int> & metricsWithActivation,unordered_map<int,shared_ptr<Activation>> & eventActivationMap,unordered_map<int,vector<shared_ptr<Activation>>> & eventDeactivationMap)231 bool handleMetricActivation(
232 const StatsdConfig& config, const int64_t metricId, const int metricIndex,
233 const unordered_map<int64_t, int>& metricToActivationMap,
234 const unordered_map<int64_t, int>& atomMatchingTrackerMap,
235 unordered_map<int, vector<int>>& activationAtomTrackerToMetricMap,
236 unordered_map<int, vector<int>>& deactivationAtomTrackerToMetricMap,
237 vector<int>& metricsWithActivation,
238 unordered_map<int, shared_ptr<Activation>>& eventActivationMap,
239 unordered_map<int, vector<shared_ptr<Activation>>>& eventDeactivationMap) {
240 // Check if metric has an associated activation
241 auto itr = metricToActivationMap.find(metricId);
242 if (itr == metricToActivationMap.end()) {
243 return true;
244 }
245
246 int activationIndex = itr->second;
247 const MetricActivation& metricActivation = config.metric_activation(activationIndex);
248
249 for (int i = 0; i < metricActivation.event_activation_size(); i++) {
250 const EventActivation& activation = metricActivation.event_activation(i);
251
252 auto itr = atomMatchingTrackerMap.find(activation.atom_matcher_id());
253 if (itr == atomMatchingTrackerMap.end()) {
254 ALOGE("Atom matcher not found for event activation.");
255 return false;
256 }
257
258 ActivationType activationType = (activation.has_activation_type())
259 ? activation.activation_type()
260 : metricActivation.activation_type();
261 std::shared_ptr<Activation> activationWrapper =
262 std::make_shared<Activation>(activationType, activation.ttl_seconds() * NS_PER_SEC);
263
264 int atomMatcherIndex = itr->second;
265 activationAtomTrackerToMetricMap[atomMatcherIndex].push_back(metricIndex);
266 eventActivationMap.emplace(atomMatcherIndex, activationWrapper);
267
268 if (activation.has_deactivation_atom_matcher_id()) {
269 itr = atomMatchingTrackerMap.find(activation.deactivation_atom_matcher_id());
270 if (itr == atomMatchingTrackerMap.end()) {
271 ALOGE("Atom matcher not found for event deactivation.");
272 return false;
273 }
274 int deactivationAtomMatcherIndex = itr->second;
275 deactivationAtomTrackerToMetricMap[deactivationAtomMatcherIndex].push_back(metricIndex);
276 eventDeactivationMap[deactivationAtomMatcherIndex].push_back(activationWrapper);
277 }
278 }
279
280 metricsWithActivation.push_back(metricIndex);
281 return true;
282 }
283
284 // Validates a metricActivation and populates state.
285 // Fills the new event activation/deactivation maps, preserving the existing activations
286 // Returns false if there are errors.
handleMetricActivationOnConfigUpdate(const StatsdConfig & config,const int64_t metricId,const int metricIndex,const unordered_map<int64_t,int> & metricToActivationMap,const unordered_map<int64_t,int> & oldAtomMatchingTrackerMap,const unordered_map<int64_t,int> & newAtomMatchingTrackerMap,const unordered_map<int,shared_ptr<Activation>> & oldEventActivationMap,unordered_map<int,vector<int>> & activationAtomTrackerToMetricMap,unordered_map<int,vector<int>> & deactivationAtomTrackerToMetricMap,vector<int> & metricsWithActivation,unordered_map<int,shared_ptr<Activation>> & newEventActivationMap,unordered_map<int,vector<shared_ptr<Activation>>> & newEventDeactivationMap)287 bool handleMetricActivationOnConfigUpdate(
288 const StatsdConfig& config, const int64_t metricId, const int metricIndex,
289 const unordered_map<int64_t, int>& metricToActivationMap,
290 const unordered_map<int64_t, int>& oldAtomMatchingTrackerMap,
291 const unordered_map<int64_t, int>& newAtomMatchingTrackerMap,
292 const unordered_map<int, shared_ptr<Activation>>& oldEventActivationMap,
293 unordered_map<int, vector<int>>& activationAtomTrackerToMetricMap,
294 unordered_map<int, vector<int>>& deactivationAtomTrackerToMetricMap,
295 vector<int>& metricsWithActivation,
296 unordered_map<int, shared_ptr<Activation>>& newEventActivationMap,
297 unordered_map<int, vector<shared_ptr<Activation>>>& newEventDeactivationMap) {
298 // Check if metric has an associated activation.
299 const auto& itr = metricToActivationMap.find(metricId);
300 if (itr == metricToActivationMap.end()) {
301 return true;
302 }
303
304 int activationIndex = itr->second;
305 const MetricActivation& metricActivation = config.metric_activation(activationIndex);
306
307 for (int i = 0; i < metricActivation.event_activation_size(); i++) {
308 const int64_t activationMatcherId = metricActivation.event_activation(i).atom_matcher_id();
309
310 const auto& newActivationIt = newAtomMatchingTrackerMap.find(activationMatcherId);
311 if (newActivationIt == newAtomMatchingTrackerMap.end()) {
312 ALOGE("Atom matcher not found in new config for event activation.");
313 return false;
314 }
315 int newActivationMatcherIndex = newActivationIt->second;
316
317 // Find the old activation struct and copy it over.
318 const auto& oldActivationIt = oldAtomMatchingTrackerMap.find(activationMatcherId);
319 if (oldActivationIt == oldAtomMatchingTrackerMap.end()) {
320 ALOGE("Atom matcher not found in existing config for event activation.");
321 return false;
322 }
323 int oldActivationMatcherIndex = oldActivationIt->second;
324 const auto& oldEventActivationIt = oldEventActivationMap.find(oldActivationMatcherIndex);
325 if (oldEventActivationIt == oldEventActivationMap.end()) {
326 ALOGE("Could not find existing event activation to update");
327 return false;
328 }
329 newEventActivationMap.emplace(newActivationMatcherIndex, oldEventActivationIt->second);
330 activationAtomTrackerToMetricMap[newActivationMatcherIndex].push_back(metricIndex);
331
332 if (metricActivation.event_activation(i).has_deactivation_atom_matcher_id()) {
333 const int64_t deactivationMatcherId =
334 metricActivation.event_activation(i).deactivation_atom_matcher_id();
335 const auto& newDeactivationIt = newAtomMatchingTrackerMap.find(deactivationMatcherId);
336 if (newDeactivationIt == newAtomMatchingTrackerMap.end()) {
337 ALOGE("Deactivation atom matcher not found in new config for event activation.");
338 return false;
339 }
340 int newDeactivationMatcherIndex = newDeactivationIt->second;
341 newEventDeactivationMap[newDeactivationMatcherIndex].push_back(
342 oldEventActivationIt->second);
343 deactivationAtomTrackerToMetricMap[newDeactivationMatcherIndex].push_back(metricIndex);
344 }
345 }
346
347 metricsWithActivation.push_back(metricIndex);
348 return true;
349 }
350
createCountMetricProducerAndUpdateMetadata(const ConfigKey & key,const StatsdConfig & config,const int64_t timeBaseNs,const int64_t currentTimeNs,const CountMetric & metric,const int metricIndex,const vector<sp<AtomMatchingTracker>> & allAtomMatchingTrackers,const unordered_map<int64_t,int> & atomMatchingTrackerMap,vector<sp<ConditionTracker>> & allConditionTrackers,const unordered_map<int64_t,int> & conditionTrackerMap,const vector<ConditionState> & initialConditionCache,const sp<ConditionWizard> & wizard,const unordered_map<int64_t,int> & stateAtomIdMap,const unordered_map<int64_t,unordered_map<int,int64_t>> & allStateGroupMaps,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)351 optional<sp<MetricProducer>> createCountMetricProducerAndUpdateMetadata(
352 const ConfigKey& key, const StatsdConfig& config, const int64_t timeBaseNs,
353 const int64_t currentTimeNs, const CountMetric& metric, const int metricIndex,
354 const vector<sp<AtomMatchingTracker>>& allAtomMatchingTrackers,
355 const unordered_map<int64_t, int>& atomMatchingTrackerMap,
356 vector<sp<ConditionTracker>>& allConditionTrackers,
357 const unordered_map<int64_t, int>& conditionTrackerMap,
358 const vector<ConditionState>& initialConditionCache, const sp<ConditionWizard>& wizard,
359 const unordered_map<int64_t, int>& stateAtomIdMap,
360 const unordered_map<int64_t, unordered_map<int, int64_t>>& allStateGroupMaps,
361 const unordered_map<int64_t, int>& metricToActivationMap,
362 unordered_map<int, vector<int>>& trackerToMetricMap,
363 unordered_map<int, vector<int>>& conditionToMetricMap,
364 unordered_map<int, vector<int>>& activationAtomTrackerToMetricMap,
365 unordered_map<int, vector<int>>& deactivationAtomTrackerToMetricMap,
366 vector<int>& metricsWithActivation) {
367 if (!metric.has_id() || !metric.has_what()) {
368 ALOGE("cannot find metric id or \"what\" in CountMetric \"%lld\"", (long long)metric.id());
369 return nullopt;
370 }
371 int trackerIndex;
372 if (!handleMetricWithAtomMatchingTrackers(metric.what(), metricIndex,
373 metric.has_dimensions_in_what(),
374 allAtomMatchingTrackers, atomMatchingTrackerMap,
375 trackerToMetricMap, trackerIndex)) {
376 return nullopt;
377 }
378
379 int conditionIndex = -1;
380 if (metric.has_condition()) {
381 if (!handleMetricWithConditions(metric.condition(), metricIndex, conditionTrackerMap,
382 metric.links(), allConditionTrackers, conditionIndex,
383 conditionToMetricMap)) {
384 return nullopt;
385 }
386 } else {
387 if (metric.links_size() > 0) {
388 ALOGW("metrics has a MetricConditionLink but doesn't have a condition");
389 return nullopt;
390 }
391 }
392
393 std::vector<int> slicedStateAtoms;
394 unordered_map<int, unordered_map<int, int64_t>> stateGroupMap;
395 if (metric.slice_by_state_size() > 0) {
396 if (!handleMetricWithStates(config, metric.slice_by_state(), stateAtomIdMap,
397 allStateGroupMaps, slicedStateAtoms, stateGroupMap)) {
398 return nullopt;
399 }
400 } else {
401 if (metric.state_link_size() > 0) {
402 ALOGW("CountMetric has a MetricStateLink but doesn't have a slice_by_state");
403 return nullopt;
404 }
405 }
406
407 unordered_map<int, shared_ptr<Activation>> eventActivationMap;
408 unordered_map<int, vector<shared_ptr<Activation>>> eventDeactivationMap;
409 if (!handleMetricActivation(config, metric.id(), metricIndex, metricToActivationMap,
410 atomMatchingTrackerMap, activationAtomTrackerToMetricMap,
411 deactivationAtomTrackerToMetricMap, metricsWithActivation,
412 eventActivationMap, eventDeactivationMap)) {
413 return nullopt;
414 }
415
416 uint64_t metricHash;
417 if (!getMetricProtoHash(config, metric, metric.id(), metricToActivationMap, metricHash)) {
418 return nullopt;
419 }
420
421 if (metric.has_threshold() &&
422 (metric.threshold().value_comparison_case() == UploadThreshold::kLtFloat ||
423 metric.threshold().value_comparison_case() == UploadThreshold::kGtFloat)) {
424 ALOGW("Count metric incorrect upload threshold type or no type used");
425 return nullopt;
426 }
427
428 return {new CountMetricProducer(key, metric, conditionIndex, initialConditionCache, wizard,
429 metricHash, timeBaseNs, currentTimeNs, eventActivationMap,
430 eventDeactivationMap, slicedStateAtoms, stateGroupMap)};
431 }
432
createDurationMetricProducerAndUpdateMetadata(const ConfigKey & key,const StatsdConfig & config,const int64_t timeBaseNs,const int64_t currentTimeNs,const DurationMetric & metric,const int metricIndex,const vector<sp<AtomMatchingTracker>> & allAtomMatchingTrackers,const unordered_map<int64_t,int> & atomMatchingTrackerMap,vector<sp<ConditionTracker>> & allConditionTrackers,const unordered_map<int64_t,int> & conditionTrackerMap,const vector<ConditionState> & initialConditionCache,const sp<ConditionWizard> & wizard,const unordered_map<int64_t,int> & stateAtomIdMap,const unordered_map<int64_t,unordered_map<int,int64_t>> & allStateGroupMaps,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)433 optional<sp<MetricProducer>> createDurationMetricProducerAndUpdateMetadata(
434 const ConfigKey& key, const StatsdConfig& config, const int64_t timeBaseNs,
435 const int64_t currentTimeNs, const DurationMetric& metric, const int metricIndex,
436 const vector<sp<AtomMatchingTracker>>& allAtomMatchingTrackers,
437 const unordered_map<int64_t, int>& atomMatchingTrackerMap,
438 vector<sp<ConditionTracker>>& allConditionTrackers,
439 const unordered_map<int64_t, int>& conditionTrackerMap,
440 const vector<ConditionState>& initialConditionCache, const sp<ConditionWizard>& wizard,
441 const unordered_map<int64_t, int>& stateAtomIdMap,
442 const unordered_map<int64_t, unordered_map<int, int64_t>>& allStateGroupMaps,
443 const unordered_map<int64_t, int>& metricToActivationMap,
444 unordered_map<int, vector<int>>& trackerToMetricMap,
445 unordered_map<int, vector<int>>& conditionToMetricMap,
446 unordered_map<int, vector<int>>& activationAtomTrackerToMetricMap,
447 unordered_map<int, vector<int>>& deactivationAtomTrackerToMetricMap,
448 vector<int>& metricsWithActivation) {
449 if (!metric.has_id() || !metric.has_what()) {
450 ALOGE("cannot find metric id or \"what\" in DurationMetric \"%lld\"",
451 (long long)metric.id());
452 return nullopt;
453 }
454 const auto& what_it = conditionTrackerMap.find(metric.what());
455 if (what_it == conditionTrackerMap.end()) {
456 ALOGE("DurationMetric's \"what\" is not present in the condition trackers");
457 return nullopt;
458 }
459
460 const int whatIndex = what_it->second;
461 const Predicate& durationWhat = config.predicate(whatIndex);
462 if (durationWhat.contents_case() != Predicate::ContentsCase::kSimplePredicate) {
463 ALOGE("DurationMetric's \"what\" must be a simple condition");
464 return nullopt;
465 }
466
467 const SimplePredicate& simplePredicate = durationWhat.simple_predicate();
468 bool nesting = simplePredicate.count_nesting();
469
470 int startIndex = -1, stopIndex = -1, stopAllIndex = -1;
471 if (!simplePredicate.has_start() ||
472 !handleMetricWithAtomMatchingTrackers(
473 simplePredicate.start(), metricIndex, metric.has_dimensions_in_what(),
474 allAtomMatchingTrackers, atomMatchingTrackerMap, trackerToMetricMap, startIndex)) {
475 ALOGE("Duration metrics must specify a valid start event matcher");
476 return nullopt;
477 }
478
479 if (simplePredicate.has_stop() &&
480 !handleMetricWithAtomMatchingTrackers(
481 simplePredicate.stop(), metricIndex, metric.has_dimensions_in_what(),
482 allAtomMatchingTrackers, atomMatchingTrackerMap, trackerToMetricMap, stopIndex)) {
483 return nullopt;
484 }
485
486 if (simplePredicate.has_stop_all() &&
487 !handleMetricWithAtomMatchingTrackers(simplePredicate.stop_all(), metricIndex,
488 metric.has_dimensions_in_what(),
489 allAtomMatchingTrackers, atomMatchingTrackerMap,
490 trackerToMetricMap, stopAllIndex)) {
491 return nullopt;
492 }
493
494 FieldMatcher internalDimensions = simplePredicate.dimensions();
495
496 int conditionIndex = -1;
497 if (metric.has_condition()) {
498 if (!handleMetricWithConditions(metric.condition(), metricIndex, conditionTrackerMap,
499 metric.links(), allConditionTrackers, conditionIndex,
500 conditionToMetricMap)) {
501 return nullopt;
502 }
503 } else if (metric.links_size() > 0) {
504 ALOGW("metrics has a MetricConditionLink but doesn't have a condition");
505 return nullopt;
506 }
507
508 std::vector<int> slicedStateAtoms;
509 unordered_map<int, unordered_map<int, int64_t>> stateGroupMap;
510 if (metric.slice_by_state_size() > 0) {
511 if (metric.aggregation_type() == DurationMetric::MAX_SPARSE) {
512 ALOGE("DurationMetric with aggregation type MAX_SPARSE cannot be sliced by state");
513 return nullopt;
514 }
515 if (!handleMetricWithStates(config, metric.slice_by_state(), stateAtomIdMap,
516 allStateGroupMaps, slicedStateAtoms, stateGroupMap)) {
517 return nullopt;
518 }
519 } else if (metric.state_link_size() > 0) {
520 ALOGW("DurationMetric has a MetricStateLink but doesn't have a sliced state");
521 return nullopt;
522 }
523
524 // Check that all metric state links are a subset of dimensions_in_what fields.
525 std::vector<Matcher> dimensionsInWhat;
526 translateFieldMatcher(metric.dimensions_in_what(), &dimensionsInWhat);
527 for (const auto& stateLink : metric.state_link()) {
528 if (!handleMetricWithStateLink(stateLink.fields_in_what(), dimensionsInWhat)) {
529 ALOGW("DurationMetric's MetricStateLinks must be a subset of dimensions in what");
530 return nullopt;
531 }
532 }
533
534 unordered_map<int, shared_ptr<Activation>> eventActivationMap;
535 unordered_map<int, vector<shared_ptr<Activation>>> eventDeactivationMap;
536 if (!handleMetricActivation(config, metric.id(), metricIndex, metricToActivationMap,
537 atomMatchingTrackerMap, activationAtomTrackerToMetricMap,
538 deactivationAtomTrackerToMetricMap, metricsWithActivation,
539 eventActivationMap, eventDeactivationMap)) {
540 return nullopt;
541 }
542
543 uint64_t metricHash;
544 if (!getMetricProtoHash(config, metric, metric.id(), metricToActivationMap, metricHash)) {
545 return nullopt;
546 }
547
548 if (metric.has_threshold()) {
549 switch (metric.threshold().value_comparison_case()) {
550 case UploadThreshold::kLtInt:
551 case UploadThreshold::kGtInt:
552 case UploadThreshold::kLteInt:
553 case UploadThreshold::kGteInt:
554 break;
555 default:
556 ALOGE("Duration metric incorrect upload threshold type or no type used");
557 return nullopt;
558 break;
559 }
560 }
561
562 sp<MetricProducer> producer = new DurationMetricProducer(
563 key, metric, conditionIndex, initialConditionCache, whatIndex, startIndex, stopIndex,
564 stopAllIndex, nesting, wizard, metricHash, internalDimensions, timeBaseNs,
565 currentTimeNs, eventActivationMap, eventDeactivationMap, slicedStateAtoms,
566 stateGroupMap);
567 if (!producer->isValid()) {
568 return nullopt;
569 }
570 return {producer};
571 }
572
createEventMetricProducerAndUpdateMetadata(const ConfigKey & key,const StatsdConfig & config,const int64_t timeBaseNs,const EventMetric & metric,const int metricIndex,const vector<sp<AtomMatchingTracker>> & allAtomMatchingTrackers,const unordered_map<int64_t,int> & atomMatchingTrackerMap,vector<sp<ConditionTracker>> & allConditionTrackers,const unordered_map<int64_t,int> & conditionTrackerMap,const vector<ConditionState> & initialConditionCache,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)573 optional<sp<MetricProducer>> createEventMetricProducerAndUpdateMetadata(
574 const ConfigKey& key, const StatsdConfig& config, const int64_t timeBaseNs,
575 const EventMetric& metric, const int metricIndex,
576 const vector<sp<AtomMatchingTracker>>& allAtomMatchingTrackers,
577 const unordered_map<int64_t, int>& atomMatchingTrackerMap,
578 vector<sp<ConditionTracker>>& allConditionTrackers,
579 const unordered_map<int64_t, int>& conditionTrackerMap,
580 const vector<ConditionState>& initialConditionCache, const sp<ConditionWizard>& wizard,
581 const unordered_map<int64_t, int>& metricToActivationMap,
582 unordered_map<int, vector<int>>& trackerToMetricMap,
583 unordered_map<int, vector<int>>& conditionToMetricMap,
584 unordered_map<int, vector<int>>& activationAtomTrackerToMetricMap,
585 unordered_map<int, vector<int>>& deactivationAtomTrackerToMetricMap,
586 vector<int>& metricsWithActivation) {
587 if (!metric.has_id() || !metric.has_what()) {
588 ALOGE("cannot find the metric name or what in config");
589 return nullopt;
590 }
591 int trackerIndex;
592 if (!handleMetricWithAtomMatchingTrackers(metric.what(), metricIndex, false,
593 allAtomMatchingTrackers, atomMatchingTrackerMap,
594 trackerToMetricMap, trackerIndex)) {
595 return nullopt;
596 }
597
598 int conditionIndex = -1;
599 if (metric.has_condition()) {
600 if (!handleMetricWithConditions(metric.condition(), metricIndex, conditionTrackerMap,
601 metric.links(), allConditionTrackers, conditionIndex,
602 conditionToMetricMap)) {
603 return nullopt;
604 }
605 } else {
606 if (metric.links_size() > 0) {
607 ALOGW("metrics has a MetricConditionLink but doesn't have a condition");
608 return nullopt;
609 }
610 }
611
612 unordered_map<int, shared_ptr<Activation>> eventActivationMap;
613 unordered_map<int, vector<shared_ptr<Activation>>> eventDeactivationMap;
614 bool success = handleMetricActivation(config, metric.id(), metricIndex, metricToActivationMap,
615 atomMatchingTrackerMap, activationAtomTrackerToMetricMap,
616 deactivationAtomTrackerToMetricMap, metricsWithActivation,
617 eventActivationMap, eventDeactivationMap);
618 if (!success) return nullptr;
619
620 uint64_t metricHash;
621 if (!getMetricProtoHash(config, metric, metric.id(), metricToActivationMap, metricHash)) {
622 return nullopt;
623 }
624
625 return {new EventMetricProducer(key, metric, conditionIndex, initialConditionCache, wizard,
626 metricHash, timeBaseNs, eventActivationMap,
627 eventDeactivationMap)};
628 }
629
createValueMetricProducerAndUpdateMetadata(const ConfigKey & key,const StatsdConfig & config,const int64_t timeBaseNs,const int64_t currentTimeNs,const sp<StatsPullerManager> & pullerManager,const ValueMetric & metric,const int metricIndex,const vector<sp<AtomMatchingTracker>> & allAtomMatchingTrackers,const unordered_map<int64_t,int> & atomMatchingTrackerMap,vector<sp<ConditionTracker>> & allConditionTrackers,const unordered_map<int64_t,int> & conditionTrackerMap,const vector<ConditionState> & initialConditionCache,const sp<ConditionWizard> & wizard,const sp<EventMatcherWizard> & matcherWizard,const unordered_map<int64_t,int> & stateAtomIdMap,const unordered_map<int64_t,unordered_map<int,int64_t>> & allStateGroupMaps,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)630 optional<sp<MetricProducer>> createValueMetricProducerAndUpdateMetadata(
631 const ConfigKey& key, const StatsdConfig& config, const int64_t timeBaseNs,
632 const int64_t currentTimeNs, const sp<StatsPullerManager>& pullerManager,
633 const ValueMetric& metric, const int metricIndex,
634 const vector<sp<AtomMatchingTracker>>& allAtomMatchingTrackers,
635 const unordered_map<int64_t, int>& atomMatchingTrackerMap,
636 vector<sp<ConditionTracker>>& allConditionTrackers,
637 const unordered_map<int64_t, int>& conditionTrackerMap,
638 const vector<ConditionState>& initialConditionCache, const sp<ConditionWizard>& wizard,
639 const sp<EventMatcherWizard>& matcherWizard,
640 const unordered_map<int64_t, int>& stateAtomIdMap,
641 const unordered_map<int64_t, unordered_map<int, int64_t>>& allStateGroupMaps,
642 const unordered_map<int64_t, int>& metricToActivationMap,
643 unordered_map<int, vector<int>>& trackerToMetricMap,
644 unordered_map<int, vector<int>>& conditionToMetricMap,
645 unordered_map<int, vector<int>>& activationAtomTrackerToMetricMap,
646 unordered_map<int, vector<int>>& deactivationAtomTrackerToMetricMap,
647 vector<int>& metricsWithActivation) {
648 if (!metric.has_id() || !metric.has_what()) {
649 ALOGE("cannot find metric id or \"what\" in ValueMetric \"%lld\"", (long long)metric.id());
650 return nullopt;
651 }
652 if (!metric.has_value_field()) {
653 ALOGE("cannot find \"value_field\" in ValueMetric \"%lld\"", (long long)metric.id());
654 return nullopt;
655 }
656 std::vector<Matcher> fieldMatchers;
657 translateFieldMatcher(metric.value_field(), &fieldMatchers);
658 if (fieldMatchers.size() < 1) {
659 ALOGE("incorrect \"value_field\" in ValueMetric \"%lld\"", (long long)metric.id());
660 return nullopt;
661 }
662
663 int trackerIndex;
664 if (!handleMetricWithAtomMatchingTrackers(metric.what(), metricIndex,
665 metric.has_dimensions_in_what(),
666 allAtomMatchingTrackers, atomMatchingTrackerMap,
667 trackerToMetricMap, trackerIndex)) {
668 return nullopt;
669 }
670
671 sp<AtomMatchingTracker> atomMatcher = allAtomMatchingTrackers.at(trackerIndex);
672 // If it is pulled atom, it should be simple matcher with one tagId.
673 if (atomMatcher->getAtomIds().size() != 1) {
674 return nullopt;
675 }
676 int atomTagId = *(atomMatcher->getAtomIds().begin());
677 int pullTagId = pullerManager->PullerForMatcherExists(atomTagId) ? atomTagId : -1;
678
679 int conditionIndex = -1;
680 if (metric.has_condition()) {
681 if (!handleMetricWithConditions(metric.condition(), metricIndex, conditionTrackerMap,
682 metric.links(), allConditionTrackers, conditionIndex,
683 conditionToMetricMap)) {
684 return nullopt;
685 }
686 } else if (metric.links_size() > 0) {
687 ALOGE("metrics has a MetricConditionLink but doesn't have a condition");
688 return nullopt;
689 }
690
691 std::vector<int> slicedStateAtoms;
692 unordered_map<int, unordered_map<int, int64_t>> stateGroupMap;
693 if (metric.slice_by_state_size() > 0) {
694 if (!handleMetricWithStates(config, metric.slice_by_state(), stateAtomIdMap,
695 allStateGroupMaps, slicedStateAtoms, stateGroupMap)) {
696 return nullopt;
697 }
698 } else if (metric.state_link_size() > 0) {
699 ALOGE("ValueMetric has a MetricStateLink but doesn't have a sliced state");
700 return nullopt;
701 }
702
703 // Check that all metric state links are a subset of dimensions_in_what fields.
704 std::vector<Matcher> dimensionsInWhat;
705 translateFieldMatcher(metric.dimensions_in_what(), &dimensionsInWhat);
706 for (const auto& stateLink : metric.state_link()) {
707 if (!handleMetricWithStateLink(stateLink.fields_in_what(), dimensionsInWhat)) {
708 ALOGW("ValueMetric's MetricStateLinks must be a subset of the dimensions in what");
709 return nullopt;
710 }
711 }
712
713 unordered_map<int, shared_ptr<Activation>> eventActivationMap;
714 unordered_map<int, vector<shared_ptr<Activation>>> eventDeactivationMap;
715 if (!handleMetricActivation(config, metric.id(), metricIndex, metricToActivationMap,
716 atomMatchingTrackerMap, activationAtomTrackerToMetricMap,
717 deactivationAtomTrackerToMetricMap, metricsWithActivation,
718 eventActivationMap, eventDeactivationMap)) {
719 return nullopt;
720 }
721
722 uint64_t metricHash;
723 if (!getMetricProtoHash(config, metric, metric.id(), metricToActivationMap, metricHash)) {
724 return nullopt;
725 }
726
727 return {new ValueMetricProducer(key, metric, conditionIndex, initialConditionCache, wizard,
728 metricHash, trackerIndex, matcherWizard, pullTagId, timeBaseNs,
729 currentTimeNs, pullerManager, eventActivationMap,
730 eventDeactivationMap, slicedStateAtoms, stateGroupMap)};
731 }
732
createGaugeMetricProducerAndUpdateMetadata(const ConfigKey & key,const StatsdConfig & config,const int64_t timeBaseNs,const int64_t currentTimeNs,const sp<StatsPullerManager> & pullerManager,const GaugeMetric & metric,const int metricIndex,const vector<sp<AtomMatchingTracker>> & allAtomMatchingTrackers,const unordered_map<int64_t,int> & atomMatchingTrackerMap,vector<sp<ConditionTracker>> & allConditionTrackers,const unordered_map<int64_t,int> & conditionTrackerMap,const vector<ConditionState> & initialConditionCache,const sp<ConditionWizard> & wizard,const sp<EventMatcherWizard> & matcherWizard,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)733 optional<sp<MetricProducer>> createGaugeMetricProducerAndUpdateMetadata(
734 const ConfigKey& key, const StatsdConfig& config, const int64_t timeBaseNs,
735 const int64_t currentTimeNs, const sp<StatsPullerManager>& pullerManager,
736 const GaugeMetric& metric, const int metricIndex,
737 const vector<sp<AtomMatchingTracker>>& allAtomMatchingTrackers,
738 const unordered_map<int64_t, int>& atomMatchingTrackerMap,
739 vector<sp<ConditionTracker>>& allConditionTrackers,
740 const unordered_map<int64_t, int>& conditionTrackerMap,
741 const vector<ConditionState>& initialConditionCache, const sp<ConditionWizard>& wizard,
742 const sp<EventMatcherWizard>& matcherWizard,
743 const unordered_map<int64_t, int>& metricToActivationMap,
744 unordered_map<int, vector<int>>& trackerToMetricMap,
745 unordered_map<int, vector<int>>& conditionToMetricMap,
746 unordered_map<int, vector<int>>& activationAtomTrackerToMetricMap,
747 unordered_map<int, vector<int>>& deactivationAtomTrackerToMetricMap,
748 vector<int>& metricsWithActivation) {
749 if (!metric.has_id() || !metric.has_what()) {
750 ALOGE("cannot find metric id or \"what\" in GaugeMetric \"%lld\"", (long long)metric.id());
751 return nullopt;
752 }
753
754 if ((!metric.gauge_fields_filter().has_include_all() ||
755 (metric.gauge_fields_filter().include_all() == false)) &&
756 !hasLeafNode(metric.gauge_fields_filter().fields())) {
757 ALOGW("Incorrect field filter setting in GaugeMetric %lld", (long long)metric.id());
758 return nullopt;
759 }
760 if ((metric.gauge_fields_filter().has_include_all() &&
761 metric.gauge_fields_filter().include_all() == true) &&
762 hasLeafNode(metric.gauge_fields_filter().fields())) {
763 ALOGW("Incorrect field filter setting in GaugeMetric %lld", (long long)metric.id());
764 return nullopt;
765 }
766
767 int trackerIndex;
768 if (!handleMetricWithAtomMatchingTrackers(metric.what(), metricIndex,
769 metric.has_dimensions_in_what(),
770 allAtomMatchingTrackers, atomMatchingTrackerMap,
771 trackerToMetricMap, trackerIndex)) {
772 return nullopt;
773 }
774
775 sp<AtomMatchingTracker> atomMatcher = allAtomMatchingTrackers.at(trackerIndex);
776 // For GaugeMetric atom, it should be simple matcher with one tagId.
777 if (atomMatcher->getAtomIds().size() != 1) {
778 return nullopt;
779 }
780 int atomTagId = *(atomMatcher->getAtomIds().begin());
781 int pullTagId = pullerManager->PullerForMatcherExists(atomTagId) ? atomTagId : -1;
782
783 int triggerTrackerIndex;
784 int triggerAtomId = -1;
785 if (metric.has_trigger_event()) {
786 if (pullTagId == -1) {
787 ALOGW("Pull atom not specified for trigger");
788 return nullopt;
789 }
790 // trigger_event should be used with FIRST_N_SAMPLES
791 if (metric.sampling_type() != GaugeMetric::FIRST_N_SAMPLES) {
792 ALOGW("Gauge Metric with trigger event must have sampling type FIRST_N_SAMPLES");
793 return nullopt;
794 }
795 if (!handleMetricWithAtomMatchingTrackers(metric.trigger_event(), metricIndex,
796 /*enforceOneAtom=*/true, allAtomMatchingTrackers,
797 atomMatchingTrackerMap, trackerToMetricMap,
798 triggerTrackerIndex)) {
799 return nullopt;
800 }
801 sp<AtomMatchingTracker> triggerAtomMatcher =
802 allAtomMatchingTrackers.at(triggerTrackerIndex);
803 triggerAtomId = *(triggerAtomMatcher->getAtomIds().begin());
804 }
805
806 if (!metric.has_trigger_event() && pullTagId != -1 &&
807 metric.sampling_type() == GaugeMetric::FIRST_N_SAMPLES) {
808 ALOGW("FIRST_N_SAMPLES is only for pushed event or pull_on_trigger");
809 return nullopt;
810 }
811
812 int conditionIndex = -1;
813 if (metric.has_condition()) {
814 if (!handleMetricWithConditions(metric.condition(), metricIndex, conditionTrackerMap,
815 metric.links(), allConditionTrackers, conditionIndex,
816 conditionToMetricMap)) {
817 return nullopt;
818 }
819 } else {
820 if (metric.links_size() > 0) {
821 ALOGW("metrics has a MetricConditionLink but doesn't have a condition");
822 return nullopt;
823 }
824 }
825
826 unordered_map<int, shared_ptr<Activation>> eventActivationMap;
827 unordered_map<int, vector<shared_ptr<Activation>>> eventDeactivationMap;
828 if (!handleMetricActivation(config, metric.id(), metricIndex, metricToActivationMap,
829 atomMatchingTrackerMap, activationAtomTrackerToMetricMap,
830 deactivationAtomTrackerToMetricMap, metricsWithActivation,
831 eventActivationMap, eventDeactivationMap)) {
832 return nullopt;
833 }
834
835 uint64_t metricHash;
836 if (!getMetricProtoHash(config, metric, metric.id(), metricToActivationMap, metricHash)) {
837 return nullopt;
838 }
839
840 return {new GaugeMetricProducer(key, metric, conditionIndex, initialConditionCache, wizard,
841 metricHash, trackerIndex, matcherWizard, pullTagId,
842 triggerAtomId, atomTagId, timeBaseNs, currentTimeNs,
843 pullerManager, eventActivationMap, eventDeactivationMap)};
844 }
845
createAnomalyTracker(const Alert & alert,const sp<AlarmMonitor> & anomalyAlarmMonitor,const UpdateStatus & updateStatus,const int64_t currentTimeNs,const unordered_map<int64_t,int> & metricProducerMap,vector<sp<MetricProducer>> & allMetricProducers)846 optional<sp<AnomalyTracker>> createAnomalyTracker(
847 const Alert& alert, const sp<AlarmMonitor>& anomalyAlarmMonitor,
848 const UpdateStatus& updateStatus, const int64_t currentTimeNs,
849 const unordered_map<int64_t, int>& metricProducerMap,
850 vector<sp<MetricProducer>>& allMetricProducers) {
851 const auto& itr = metricProducerMap.find(alert.metric_id());
852 if (itr == metricProducerMap.end()) {
853 ALOGW("alert \"%lld\" has unknown metric id: \"%lld\"", (long long)alert.id(),
854 (long long)alert.metric_id());
855 return nullopt;
856 }
857 if (!alert.has_trigger_if_sum_gt()) {
858 ALOGW("invalid alert: missing threshold");
859 return nullopt;
860 }
861 if (alert.trigger_if_sum_gt() < 0 || alert.num_buckets() <= 0) {
862 ALOGW("invalid alert: threshold=%f num_buckets= %d", alert.trigger_if_sum_gt(),
863 alert.num_buckets());
864 return nullopt;
865 }
866 const int metricIndex = itr->second;
867 sp<MetricProducer> metric = allMetricProducers[metricIndex];
868 sp<AnomalyTracker> anomalyTracker =
869 metric->addAnomalyTracker(alert, anomalyAlarmMonitor, updateStatus, currentTimeNs);
870 if (anomalyTracker == nullptr) {
871 // The ALOGW for this invalid alert was already displayed in addAnomalyTracker().
872 return nullopt;
873 }
874 return {anomalyTracker};
875 }
876
initAtomMatchingTrackers(const StatsdConfig & config,const sp<UidMap> & uidMap,unordered_map<int64_t,int> & atomMatchingTrackerMap,vector<sp<AtomMatchingTracker>> & allAtomMatchingTrackers,set<int> & allTagIds)877 bool initAtomMatchingTrackers(const StatsdConfig& config, const sp<UidMap>& uidMap,
878 unordered_map<int64_t, int>& atomMatchingTrackerMap,
879 vector<sp<AtomMatchingTracker>>& allAtomMatchingTrackers,
880 set<int>& allTagIds) {
881 vector<AtomMatcher> matcherConfigs;
882 const int atomMatcherCount = config.atom_matcher_size();
883 matcherConfigs.reserve(atomMatcherCount);
884 allAtomMatchingTrackers.reserve(atomMatcherCount);
885
886 for (int i = 0; i < atomMatcherCount; i++) {
887 const AtomMatcher& logMatcher = config.atom_matcher(i);
888 sp<AtomMatchingTracker> tracker = createAtomMatchingTracker(logMatcher, i, uidMap);
889 if (tracker == nullptr) {
890 return false;
891 }
892 allAtomMatchingTrackers.push_back(tracker);
893 if (atomMatchingTrackerMap.find(logMatcher.id()) != atomMatchingTrackerMap.end()) {
894 ALOGE("Duplicate AtomMatcher found!");
895 return false;
896 }
897 atomMatchingTrackerMap[logMatcher.id()] = i;
898 matcherConfigs.push_back(logMatcher);
899 }
900
901 vector<bool> stackTracker2(allAtomMatchingTrackers.size(), false);
902 for (auto& matcher : allAtomMatchingTrackers) {
903 if (!matcher->init(matcherConfigs, allAtomMatchingTrackers, atomMatchingTrackerMap,
904 stackTracker2)) {
905 return false;
906 }
907 // Collect all the tag ids that are interesting. TagIds exist in leaf nodes only.
908 const set<int>& tagIds = matcher->getAtomIds();
909 allTagIds.insert(tagIds.begin(), tagIds.end());
910 }
911 return true;
912 }
913
initConditions(const ConfigKey & key,const StatsdConfig & config,const unordered_map<int64_t,int> & atomMatchingTrackerMap,unordered_map<int64_t,int> & conditionTrackerMap,vector<sp<ConditionTracker>> & allConditionTrackers,unordered_map<int,std::vector<int>> & trackerToConditionMap,vector<ConditionState> & initialConditionCache)914 bool initConditions(const ConfigKey& key, const StatsdConfig& config,
915 const unordered_map<int64_t, int>& atomMatchingTrackerMap,
916 unordered_map<int64_t, int>& conditionTrackerMap,
917 vector<sp<ConditionTracker>>& allConditionTrackers,
918 unordered_map<int, std::vector<int>>& trackerToConditionMap,
919 vector<ConditionState>& initialConditionCache) {
920 vector<Predicate> conditionConfigs;
921 const int conditionTrackerCount = config.predicate_size();
922 conditionConfigs.reserve(conditionTrackerCount);
923 allConditionTrackers.reserve(conditionTrackerCount);
924 initialConditionCache.assign(conditionTrackerCount, ConditionState::kNotEvaluated);
925
926 for (int i = 0; i < conditionTrackerCount; i++) {
927 const Predicate& condition = config.predicate(i);
928 sp<ConditionTracker> tracker =
929 createConditionTracker(key, condition, i, atomMatchingTrackerMap);
930 if (tracker == nullptr) {
931 return false;
932 }
933 allConditionTrackers.push_back(tracker);
934 if (conditionTrackerMap.find(condition.id()) != conditionTrackerMap.end()) {
935 ALOGE("Duplicate Predicate found!");
936 return false;
937 }
938 conditionTrackerMap[condition.id()] = i;
939 conditionConfigs.push_back(condition);
940 }
941
942 vector<bool> stackTracker(allConditionTrackers.size(), false);
943 for (size_t i = 0; i < allConditionTrackers.size(); i++) {
944 auto& conditionTracker = allConditionTrackers[i];
945 if (!conditionTracker->init(conditionConfigs, allConditionTrackers, conditionTrackerMap,
946 stackTracker, initialConditionCache)) {
947 return false;
948 }
949 for (const int trackerIndex : conditionTracker->getAtomMatchingTrackerIndex()) {
950 auto& conditionList = trackerToConditionMap[trackerIndex];
951 conditionList.push_back(i);
952 }
953 }
954 return true;
955 }
956
initStates(const StatsdConfig & config,unordered_map<int64_t,int> & stateAtomIdMap,unordered_map<int64_t,unordered_map<int,int64_t>> & allStateGroupMaps,map<int64_t,uint64_t> & stateProtoHashes)957 bool initStates(const StatsdConfig& config, unordered_map<int64_t, int>& stateAtomIdMap,
958 unordered_map<int64_t, unordered_map<int, int64_t>>& allStateGroupMaps,
959 map<int64_t, uint64_t>& stateProtoHashes) {
960 for (int i = 0; i < config.state_size(); i++) {
961 const State& state = config.state(i);
962 const int64_t stateId = state.id();
963 stateAtomIdMap[stateId] = state.atom_id();
964
965 string serializedState;
966 if (!state.SerializeToString(&serializedState)) {
967 ALOGE("Unable to serialize state %lld", (long long)stateId);
968 return false;
969 }
970 stateProtoHashes[stateId] = Hash64(serializedState);
971
972 const StateMap& stateMap = state.map();
973 for (auto group : stateMap.group()) {
974 for (auto value : group.value()) {
975 allStateGroupMaps[stateId][value] = group.group_id();
976 }
977 }
978 }
979
980 return true;
981 }
982
initMetrics(const ConfigKey & key,const StatsdConfig & config,const int64_t timeBaseTimeNs,const int64_t currentTimeNs,const sp<StatsPullerManager> & pullerManager,const unordered_map<int64_t,int> & atomMatchingTrackerMap,const unordered_map<int64_t,int> & conditionTrackerMap,const vector<sp<AtomMatchingTracker>> & allAtomMatchingTrackers,const unordered_map<int64_t,int> & stateAtomIdMap,const unordered_map<int64_t,unordered_map<int,int64_t>> & allStateGroupMaps,vector<sp<ConditionTracker>> & allConditionTrackers,const vector<ConditionState> & initialConditionCache,vector<sp<MetricProducer>> & allMetricProducers,unordered_map<int,vector<int>> & conditionToMetricMap,unordered_map<int,vector<int>> & trackerToMetricMap,unordered_map<int64_t,int> & metricMap,std::set<int64_t> & noReportMetricIds,unordered_map<int,vector<int>> & activationAtomTrackerToMetricMap,unordered_map<int,vector<int>> & deactivationAtomTrackerToMetricMap,vector<int> & metricsWithActivation)983 bool initMetrics(const ConfigKey& key, const StatsdConfig& config, const int64_t timeBaseTimeNs,
984 const int64_t currentTimeNs, const sp<StatsPullerManager>& pullerManager,
985 const unordered_map<int64_t, int>& atomMatchingTrackerMap,
986 const unordered_map<int64_t, int>& conditionTrackerMap,
987 const vector<sp<AtomMatchingTracker>>& allAtomMatchingTrackers,
988 const unordered_map<int64_t, int>& stateAtomIdMap,
989 const unordered_map<int64_t, unordered_map<int, int64_t>>& allStateGroupMaps,
990 vector<sp<ConditionTracker>>& allConditionTrackers,
991 const vector<ConditionState>& initialConditionCache,
992 vector<sp<MetricProducer>>& allMetricProducers,
993 unordered_map<int, vector<int>>& conditionToMetricMap,
994 unordered_map<int, vector<int>>& trackerToMetricMap,
995 unordered_map<int64_t, int>& metricMap, std::set<int64_t>& noReportMetricIds,
996 unordered_map<int, vector<int>>& activationAtomTrackerToMetricMap,
997 unordered_map<int, vector<int>>& deactivationAtomTrackerToMetricMap,
998 vector<int>& metricsWithActivation) {
999 sp<ConditionWizard> wizard = new ConditionWizard(allConditionTrackers);
1000 sp<EventMatcherWizard> matcherWizard = new EventMatcherWizard(allAtomMatchingTrackers);
1001 const int allMetricsCount = config.count_metric_size() + config.duration_metric_size() +
1002 config.event_metric_size() + config.gauge_metric_size() +
1003 config.value_metric_size();
1004 allMetricProducers.reserve(allMetricsCount);
1005
1006 // Construct map from metric id to metric activation index. The map will be used to determine
1007 // the metric activation corresponding to a metric.
1008 unordered_map<int64_t, int> metricToActivationMap;
1009 for (int i = 0; i < config.metric_activation_size(); i++) {
1010 const MetricActivation& metricActivation = config.metric_activation(i);
1011 int64_t metricId = metricActivation.metric_id();
1012 if (metricToActivationMap.find(metricId) != metricToActivationMap.end()) {
1013 ALOGE("Metric %lld has multiple MetricActivations", (long long)metricId);
1014 return false;
1015 }
1016 metricToActivationMap.insert({metricId, i});
1017 }
1018
1019 // Build MetricProducers for each metric defined in config.
1020 // build CountMetricProducer
1021 for (int i = 0; i < config.count_metric_size(); i++) {
1022 int metricIndex = allMetricProducers.size();
1023 const CountMetric& metric = config.count_metric(i);
1024 metricMap.insert({metric.id(), metricIndex});
1025 optional<sp<MetricProducer>> producer = createCountMetricProducerAndUpdateMetadata(
1026 key, config, timeBaseTimeNs, currentTimeNs, metric, metricIndex,
1027 allAtomMatchingTrackers, atomMatchingTrackerMap, allConditionTrackers,
1028 conditionTrackerMap, initialConditionCache, wizard, stateAtomIdMap,
1029 allStateGroupMaps, metricToActivationMap, trackerToMetricMap, conditionToMetricMap,
1030 activationAtomTrackerToMetricMap, deactivationAtomTrackerToMetricMap,
1031 metricsWithActivation);
1032 if (!producer) {
1033 return false;
1034 }
1035 allMetricProducers.push_back(producer.value());
1036 }
1037
1038 // build DurationMetricProducer
1039 for (int i = 0; i < config.duration_metric_size(); i++) {
1040 int metricIndex = allMetricProducers.size();
1041 const DurationMetric& metric = config.duration_metric(i);
1042 metricMap.insert({metric.id(), metricIndex});
1043
1044 optional<sp<MetricProducer>> producer = createDurationMetricProducerAndUpdateMetadata(
1045 key, config, timeBaseTimeNs, currentTimeNs, metric, metricIndex,
1046 allAtomMatchingTrackers, atomMatchingTrackerMap, allConditionTrackers,
1047 conditionTrackerMap, initialConditionCache, wizard, stateAtomIdMap,
1048 allStateGroupMaps, metricToActivationMap, trackerToMetricMap, conditionToMetricMap,
1049 activationAtomTrackerToMetricMap, deactivationAtomTrackerToMetricMap,
1050 metricsWithActivation);
1051 if (!producer) {
1052 return false;
1053 }
1054 allMetricProducers.push_back(producer.value());
1055 }
1056
1057 // build EventMetricProducer
1058 for (int i = 0; i < config.event_metric_size(); i++) {
1059 int metricIndex = allMetricProducers.size();
1060 const EventMetric& metric = config.event_metric(i);
1061 metricMap.insert({metric.id(), metricIndex});
1062 optional<sp<MetricProducer>> producer = createEventMetricProducerAndUpdateMetadata(
1063 key, config, timeBaseTimeNs, metric, metricIndex, allAtomMatchingTrackers,
1064 atomMatchingTrackerMap, allConditionTrackers, conditionTrackerMap,
1065 initialConditionCache, wizard, metricToActivationMap, trackerToMetricMap,
1066 conditionToMetricMap, activationAtomTrackerToMetricMap,
1067 deactivationAtomTrackerToMetricMap, metricsWithActivation);
1068 if (!producer) {
1069 return false;
1070 }
1071 allMetricProducers.push_back(producer.value());
1072 }
1073
1074 // build ValueMetricProducer
1075 for (int i = 0; i < config.value_metric_size(); i++) {
1076 int metricIndex = allMetricProducers.size();
1077 const ValueMetric& metric = config.value_metric(i);
1078 metricMap.insert({metric.id(), metricIndex});
1079 optional<sp<MetricProducer>> producer = createValueMetricProducerAndUpdateMetadata(
1080 key, config, timeBaseTimeNs, currentTimeNs, pullerManager, metric, metricIndex,
1081 allAtomMatchingTrackers, atomMatchingTrackerMap, allConditionTrackers,
1082 conditionTrackerMap, initialConditionCache, wizard, matcherWizard, stateAtomIdMap,
1083 allStateGroupMaps, metricToActivationMap, trackerToMetricMap, conditionToMetricMap,
1084 activationAtomTrackerToMetricMap, deactivationAtomTrackerToMetricMap,
1085 metricsWithActivation);
1086 if (!producer) {
1087 return false;
1088 }
1089 allMetricProducers.push_back(producer.value());
1090 }
1091
1092 // Gauge metrics.
1093 for (int i = 0; i < config.gauge_metric_size(); i++) {
1094 int metricIndex = allMetricProducers.size();
1095 const GaugeMetric& metric = config.gauge_metric(i);
1096 metricMap.insert({metric.id(), metricIndex});
1097 optional<sp<MetricProducer>> producer = createGaugeMetricProducerAndUpdateMetadata(
1098 key, config, timeBaseTimeNs, currentTimeNs, pullerManager, metric, metricIndex,
1099 allAtomMatchingTrackers, atomMatchingTrackerMap, allConditionTrackers,
1100 conditionTrackerMap, initialConditionCache, wizard, matcherWizard,
1101 metricToActivationMap, trackerToMetricMap, conditionToMetricMap,
1102 activationAtomTrackerToMetricMap, deactivationAtomTrackerToMetricMap,
1103 metricsWithActivation);
1104 if (!producer) {
1105 return false;
1106 }
1107 allMetricProducers.push_back(producer.value());
1108 }
1109 for (int i = 0; i < config.no_report_metric_size(); ++i) {
1110 const auto no_report_metric = config.no_report_metric(i);
1111 if (metricMap.find(no_report_metric) == metricMap.end()) {
1112 ALOGW("no_report_metric %" PRId64 " not exist", no_report_metric);
1113 return false;
1114 }
1115 noReportMetricIds.insert(no_report_metric);
1116 }
1117
1118 const set<int> whitelistedAtomIds(config.whitelisted_atom_ids().begin(),
1119 config.whitelisted_atom_ids().end());
1120 for (const auto& it : allMetricProducers) {
1121 // Register metrics to StateTrackers
1122 for (int atomId : it->getSlicedStateAtoms()) {
1123 // Register listener for non-whitelisted atoms only. Using whitelisted atom as a sliced
1124 // state atom is not allowed.
1125 if (whitelistedAtomIds.find(atomId) == whitelistedAtomIds.end()) {
1126 StateManager::getInstance().registerListener(atomId, it);
1127 } else {
1128 return false;
1129 }
1130 }
1131 }
1132 return true;
1133 }
1134
initAlerts(const StatsdConfig & config,const int64_t currentTimeNs,const unordered_map<int64_t,int> & metricProducerMap,unordered_map<int64_t,int> & alertTrackerMap,const sp<AlarmMonitor> & anomalyAlarmMonitor,vector<sp<MetricProducer>> & allMetricProducers,vector<sp<AnomalyTracker>> & allAnomalyTrackers)1135 bool initAlerts(const StatsdConfig& config, const int64_t currentTimeNs,
1136 const unordered_map<int64_t, int>& metricProducerMap,
1137 unordered_map<int64_t, int>& alertTrackerMap,
1138 const sp<AlarmMonitor>& anomalyAlarmMonitor,
1139 vector<sp<MetricProducer>>& allMetricProducers,
1140 vector<sp<AnomalyTracker>>& allAnomalyTrackers) {
1141 for (int i = 0; i < config.alert_size(); i++) {
1142 const Alert& alert = config.alert(i);
1143 alertTrackerMap.insert(std::make_pair(alert.id(), allAnomalyTrackers.size()));
1144 optional<sp<AnomalyTracker>> anomalyTracker =
1145 createAnomalyTracker(alert, anomalyAlarmMonitor, UpdateStatus::UPDATE_NEW,
1146 currentTimeNs, metricProducerMap, allMetricProducers);
1147 if (!anomalyTracker) {
1148 return false;
1149 }
1150 allAnomalyTrackers.push_back(anomalyTracker.value());
1151 }
1152 if (!initSubscribersForSubscriptionType(config, Subscription::ALERT, alertTrackerMap,
1153 allAnomalyTrackers)) {
1154 return false;
1155 }
1156 return true;
1157 }
1158
initAlarms(const StatsdConfig & config,const ConfigKey & key,const sp<AlarmMonitor> & periodicAlarmMonitor,const int64_t timeBaseNs,const int64_t currentTimeNs,vector<sp<AlarmTracker>> & allAlarmTrackers)1159 bool initAlarms(const StatsdConfig& config, const ConfigKey& key,
1160 const sp<AlarmMonitor>& periodicAlarmMonitor, const int64_t timeBaseNs,
1161 const int64_t currentTimeNs, vector<sp<AlarmTracker>>& allAlarmTrackers) {
1162 unordered_map<int64_t, int> alarmTrackerMap;
1163 int64_t startMillis = timeBaseNs / 1000 / 1000;
1164 int64_t currentTimeMillis = currentTimeNs / 1000 / 1000;
1165 for (int i = 0; i < config.alarm_size(); i++) {
1166 const Alarm& alarm = config.alarm(i);
1167 if (alarm.offset_millis() <= 0) {
1168 ALOGW("Alarm offset_millis should be larger than 0.");
1169 return false;
1170 }
1171 if (alarm.period_millis() <= 0) {
1172 ALOGW("Alarm period_millis should be larger than 0.");
1173 return false;
1174 }
1175 alarmTrackerMap.insert(std::make_pair(alarm.id(), allAlarmTrackers.size()));
1176 allAlarmTrackers.push_back(
1177 new AlarmTracker(startMillis, currentTimeMillis, alarm, key, periodicAlarmMonitor));
1178 }
1179 if (!initSubscribersForSubscriptionType(config, Subscription::ALARM, alarmTrackerMap,
1180 allAlarmTrackers)) {
1181 return false;
1182 }
1183 return true;
1184 }
1185
initStatsdConfig(const ConfigKey & key,const StatsdConfig & config,const sp<UidMap> & uidMap,const sp<StatsPullerManager> & pullerManager,const sp<AlarmMonitor> & anomalyAlarmMonitor,const sp<AlarmMonitor> & periodicAlarmMonitor,const int64_t timeBaseNs,const int64_t currentTimeNs,set<int> & allTagIds,vector<sp<AtomMatchingTracker>> & allAtomMatchingTrackers,unordered_map<int64_t,int> & atomMatchingTrackerMap,vector<sp<ConditionTracker>> & allConditionTrackers,unordered_map<int64_t,int> & conditionTrackerMap,vector<sp<MetricProducer>> & allMetricProducers,unordered_map<int64_t,int> & metricProducerMap,vector<sp<AnomalyTracker>> & allAnomalyTrackers,vector<sp<AlarmTracker>> & allPeriodicAlarmTrackers,unordered_map<int,std::vector<int>> & conditionToMetricMap,unordered_map<int,std::vector<int>> & trackerToMetricMap,unordered_map<int,std::vector<int>> & trackerToConditionMap,unordered_map<int,std::vector<int>> & activationAtomTrackerToMetricMap,unordered_map<int,std::vector<int>> & deactivationAtomTrackerToMetricMap,unordered_map<int64_t,int> & alertTrackerMap,vector<int> & metricsWithActivation,map<int64_t,uint64_t> & stateProtoHashes,set<int64_t> & noReportMetricIds)1186 bool initStatsdConfig(const ConfigKey& key, const StatsdConfig& config, const sp<UidMap>& uidMap,
1187 const sp<StatsPullerManager>& pullerManager,
1188 const sp<AlarmMonitor>& anomalyAlarmMonitor,
1189 const sp<AlarmMonitor>& periodicAlarmMonitor, const int64_t timeBaseNs,
1190 const int64_t currentTimeNs, set<int>& allTagIds,
1191 vector<sp<AtomMatchingTracker>>& allAtomMatchingTrackers,
1192 unordered_map<int64_t, int>& atomMatchingTrackerMap,
1193 vector<sp<ConditionTracker>>& allConditionTrackers,
1194 unordered_map<int64_t, int>& conditionTrackerMap,
1195 vector<sp<MetricProducer>>& allMetricProducers,
1196 unordered_map<int64_t, int>& metricProducerMap,
1197 vector<sp<AnomalyTracker>>& allAnomalyTrackers,
1198 vector<sp<AlarmTracker>>& allPeriodicAlarmTrackers,
1199 unordered_map<int, std::vector<int>>& conditionToMetricMap,
1200 unordered_map<int, std::vector<int>>& trackerToMetricMap,
1201 unordered_map<int, std::vector<int>>& trackerToConditionMap,
1202 unordered_map<int, std::vector<int>>& activationAtomTrackerToMetricMap,
1203 unordered_map<int, std::vector<int>>& deactivationAtomTrackerToMetricMap,
1204 unordered_map<int64_t, int>& alertTrackerMap,
1205 vector<int>& metricsWithActivation, map<int64_t, uint64_t>& stateProtoHashes,
1206 set<int64_t>& noReportMetricIds) {
1207 vector<ConditionState> initialConditionCache;
1208 unordered_map<int64_t, int> stateAtomIdMap;
1209 unordered_map<int64_t, unordered_map<int, int64_t>> allStateGroupMaps;
1210
1211 if (!initAtomMatchingTrackers(config, uidMap, atomMatchingTrackerMap, allAtomMatchingTrackers,
1212 allTagIds)) {
1213 ALOGE("initAtomMatchingTrackers failed");
1214 return false;
1215 }
1216 VLOG("initAtomMatchingTrackers succeed...");
1217
1218 if (!initConditions(key, config, atomMatchingTrackerMap, conditionTrackerMap,
1219 allConditionTrackers, trackerToConditionMap, initialConditionCache)) {
1220 ALOGE("initConditionTrackers failed");
1221 return false;
1222 }
1223
1224 if (!initStates(config, stateAtomIdMap, allStateGroupMaps, stateProtoHashes)) {
1225 ALOGE("initStates failed");
1226 return false;
1227 }
1228 if (!initMetrics(key, config, timeBaseNs, currentTimeNs, pullerManager, atomMatchingTrackerMap,
1229 conditionTrackerMap, allAtomMatchingTrackers, stateAtomIdMap,
1230 allStateGroupMaps, allConditionTrackers, initialConditionCache,
1231 allMetricProducers, conditionToMetricMap, trackerToMetricMap,
1232 metricProducerMap, noReportMetricIds, activationAtomTrackerToMetricMap,
1233 deactivationAtomTrackerToMetricMap, metricsWithActivation)) {
1234 ALOGE("initMetricProducers failed");
1235 return false;
1236 }
1237 if (!initAlerts(config, currentTimeNs, metricProducerMap, alertTrackerMap, anomalyAlarmMonitor,
1238 allMetricProducers, allAnomalyTrackers)) {
1239 ALOGE("initAlerts failed");
1240 return false;
1241 }
1242 if (!initAlarms(config, key, periodicAlarmMonitor, timeBaseNs, currentTimeNs,
1243 allPeriodicAlarmTrackers)) {
1244 ALOGE("initAlarms failed");
1245 return false;
1246 }
1247
1248 return true;
1249 }
1250
1251 } // namespace statsd
1252 } // namespace os
1253 } // namespace android
1254