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 "../condition/CombinationConditionTracker.h"
23 #include "../condition/SimpleConditionTracker.h"
24 #include "../condition/StateTracker.h"
25 #include "../external/StatsPullerManager.h"
26 #include "../matchers/CombinationLogMatchingTracker.h"
27 #include "../matchers/SimpleLogMatchingTracker.h"
28 #include "../matchers/EventMatcherWizard.h"
29 #include "../metrics/CountMetricProducer.h"
30 #include "../metrics/DurationMetricProducer.h"
31 #include "../metrics/EventMetricProducer.h"
32 #include "../metrics/GaugeMetricProducer.h"
33 #include "../metrics/ValueMetricProducer.h"
34
35 #include "atoms_info.h"
36 #include "stats_util.h"
37
38 #include <inttypes.h>
39
40 using std::set;
41 using std::unordered_map;
42 using std::vector;
43
44 namespace android {
45 namespace os {
46 namespace statsd {
47
48 namespace {
49
hasLeafNode(const FieldMatcher & matcher)50 bool hasLeafNode(const FieldMatcher& matcher) {
51 if (!matcher.has_field()) {
52 return false;
53 }
54 for (int i = 0; i < matcher.child_size(); ++i) {
55 if (hasLeafNode(matcher.child(i))) {
56 return true;
57 }
58 }
59 return true;
60 }
61
62 } // namespace
63
handleMetricWithLogTrackers(const int64_t what,const int metricIndex,const bool usedForDimension,const vector<sp<LogMatchingTracker>> & allAtomMatchers,const unordered_map<int64_t,int> & logTrackerMap,unordered_map<int,std::vector<int>> & trackerToMetricMap,int & logTrackerIndex)64 bool handleMetricWithLogTrackers(const int64_t what, const int metricIndex,
65 const bool usedForDimension,
66 const vector<sp<LogMatchingTracker>>& allAtomMatchers,
67 const unordered_map<int64_t, int>& logTrackerMap,
68 unordered_map<int, std::vector<int>>& trackerToMetricMap,
69 int& logTrackerIndex) {
70 auto logTrackerIt = logTrackerMap.find(what);
71 if (logTrackerIt == logTrackerMap.end()) {
72 ALOGW("cannot find the AtomMatcher \"%lld\" in config", (long long)what);
73 return false;
74 }
75 if (usedForDimension && allAtomMatchers[logTrackerIt->second]->getAtomIds().size() > 1) {
76 ALOGE("AtomMatcher \"%lld\" has more than one tag ids. When a metric has dimension, "
77 "the \"what\" can only about one atom type.",
78 (long long)what);
79 return false;
80 }
81 logTrackerIndex = logTrackerIt->second;
82 auto& metric_list = trackerToMetricMap[logTrackerIndex];
83 metric_list.push_back(metricIndex);
84 return true;
85 }
86
handlePullMetricTriggerWithLogTrackers(const int64_t trigger,const int metricIndex,const vector<sp<LogMatchingTracker>> & allAtomMatchers,const unordered_map<int64_t,int> & logTrackerMap,unordered_map<int,std::vector<int>> & trackerToMetricMap,int & logTrackerIndex)87 bool handlePullMetricTriggerWithLogTrackers(
88 const int64_t trigger, const int metricIndex,
89 const vector<sp<LogMatchingTracker>>& allAtomMatchers,
90 const unordered_map<int64_t, int>& logTrackerMap,
91 unordered_map<int, std::vector<int>>& trackerToMetricMap, int& logTrackerIndex) {
92 auto logTrackerIt = logTrackerMap.find(trigger);
93 if (logTrackerIt == logTrackerMap.end()) {
94 ALOGW("cannot find the AtomMatcher \"%lld\" in config", (long long)trigger);
95 return false;
96 }
97 if (allAtomMatchers[logTrackerIt->second]->getAtomIds().size() > 1) {
98 ALOGE("AtomMatcher \"%lld\" has more than one tag ids."
99 "Trigger can only be one atom type.",
100 (long long)trigger);
101 return false;
102 }
103 logTrackerIndex = logTrackerIt->second;
104 auto& metric_list = trackerToMetricMap[logTrackerIndex];
105 metric_list.push_back(metricIndex);
106 return true;
107 }
108
handleMetricWithConditions(const int64_t condition,const int metricIndex,const unordered_map<int64_t,int> & conditionTrackerMap,const::google::protobuf::RepeatedPtrField<::android::os::statsd::MetricConditionLink> & links,vector<sp<ConditionTracker>> & allConditionTrackers,int & conditionIndex,unordered_map<int,std::vector<int>> & conditionToMetricMap)109 bool handleMetricWithConditions(
110 const int64_t condition, const int metricIndex,
111 const unordered_map<int64_t, int>& conditionTrackerMap,
112 const ::google::protobuf::RepeatedPtrField<::android::os::statsd::MetricConditionLink>&
113 links,
114 vector<sp<ConditionTracker>>& allConditionTrackers, int& conditionIndex,
115 unordered_map<int, std::vector<int>>& conditionToMetricMap) {
116 auto condition_it = conditionTrackerMap.find(condition);
117 if (condition_it == conditionTrackerMap.end()) {
118 ALOGW("cannot find Predicate \"%lld\" in the config", (long long)condition);
119 return false;
120 }
121
122 for (const auto& link : links) {
123 auto it = conditionTrackerMap.find(link.condition());
124 if (it == conditionTrackerMap.end()) {
125 ALOGW("cannot find Predicate \"%lld\" in the config", (long long)link.condition());
126 return false;
127 }
128 allConditionTrackers[condition_it->second]->setSliced(true);
129 allConditionTrackers[it->second]->setSliced(true);
130 }
131 conditionIndex = condition_it->second;
132
133 // will create new vector if not exist before.
134 auto& metricList = conditionToMetricMap[condition_it->second];
135 metricList.push_back(metricIndex);
136 return true;
137 }
138
initLogTrackers(const StatsdConfig & config,const UidMap & uidMap,unordered_map<int64_t,int> & logTrackerMap,vector<sp<LogMatchingTracker>> & allAtomMatchers,set<int> & allTagIds)139 bool initLogTrackers(const StatsdConfig& config, const UidMap& uidMap,
140 unordered_map<int64_t, int>& logTrackerMap,
141 vector<sp<LogMatchingTracker>>& allAtomMatchers, set<int>& allTagIds) {
142 vector<AtomMatcher> matcherConfigs;
143 const int atomMatcherCount = config.atom_matcher_size();
144 matcherConfigs.reserve(atomMatcherCount);
145 allAtomMatchers.reserve(atomMatcherCount);
146
147 for (int i = 0; i < atomMatcherCount; i++) {
148 const AtomMatcher& logMatcher = config.atom_matcher(i);
149
150 int index = allAtomMatchers.size();
151 switch (logMatcher.contents_case()) {
152 case AtomMatcher::ContentsCase::kSimpleAtomMatcher:
153 allAtomMatchers.push_back(new SimpleLogMatchingTracker(
154 logMatcher.id(), index, logMatcher.simple_atom_matcher(), uidMap));
155 break;
156 case AtomMatcher::ContentsCase::kCombination:
157 allAtomMatchers.push_back(
158 new CombinationLogMatchingTracker(logMatcher.id(), index));
159 break;
160 default:
161 ALOGE("Matcher \"%lld\" malformed", (long long)logMatcher.id());
162 return false;
163 // continue;
164 }
165 if (logTrackerMap.find(logMatcher.id()) != logTrackerMap.end()) {
166 ALOGE("Duplicate AtomMatcher found!");
167 return false;
168 }
169 logTrackerMap[logMatcher.id()] = index;
170 matcherConfigs.push_back(logMatcher);
171 }
172
173 vector<bool> stackTracker2(allAtomMatchers.size(), false);
174 for (auto& matcher : allAtomMatchers) {
175 if (!matcher->init(matcherConfigs, allAtomMatchers, logTrackerMap, stackTracker2)) {
176 return false;
177 }
178 // Collect all the tag ids that are interesting. TagIds exist in leaf nodes only.
179 const set<int>& tagIds = matcher->getAtomIds();
180 allTagIds.insert(tagIds.begin(), tagIds.end());
181 }
182 return true;
183 }
184
185 /**
186 * A StateTracker is built from a SimplePredicate which has only "start", and no "stop"
187 * or "stop_all". The start must be an atom matcher that matches a state atom. It must
188 * have dimension, the dimension must be the state atom's primary fields plus exclusive state
189 * field. For example, the StateTracker is used in tracking UidProcessState and ScreenState.
190 *
191 */
isStateTracker(const SimplePredicate & simplePredicate,vector<Matcher> * primaryKeys)192 bool isStateTracker(const SimplePredicate& simplePredicate, vector<Matcher>* primaryKeys) {
193 // 1. must not have "stop". must have "dimension"
194 if (!simplePredicate.has_stop() && simplePredicate.has_dimensions()) {
195 auto it = android::util::AtomsInfo::kStateAtomsFieldOptions.find(
196 simplePredicate.dimensions().field());
197 // 2. must be based on a state atom.
198 if (it != android::util::AtomsInfo::kStateAtomsFieldOptions.end()) {
199 // 3. dimension must be primary fields + state field IN ORDER
200 size_t expectedDimensionCount = it->second.primaryFields.size() + 1;
201 vector<Matcher> dimensions;
202 translateFieldMatcher(simplePredicate.dimensions(), &dimensions);
203 if (dimensions.size() != expectedDimensionCount) {
204 return false;
205 }
206 // 3.1 check the primary fields first.
207 size_t index = 0;
208 for (const auto& field : it->second.primaryFields) {
209 Matcher matcher = getSimpleMatcher(it->first, field);
210 if (!(matcher == dimensions[index])) {
211 return false;
212 }
213 primaryKeys->push_back(matcher);
214 index++;
215 }
216 Matcher stateFieldMatcher =
217 getSimpleMatcher(it->first, it->second.exclusiveField);
218 // 3.2 last dimension should be the exclusive field.
219 if (!(dimensions.back() == stateFieldMatcher)) {
220 return false;
221 }
222 return true;
223 }
224 }
225 return false;
226 } // namespace statsd
227
initConditions(const ConfigKey & key,const StatsdConfig & config,const unordered_map<int64_t,int> & logTrackerMap,unordered_map<int64_t,int> & conditionTrackerMap,vector<sp<ConditionTracker>> & allConditionTrackers,unordered_map<int,std::vector<int>> & trackerToConditionMap)228 bool initConditions(const ConfigKey& key, const StatsdConfig& config,
229 const unordered_map<int64_t, int>& logTrackerMap,
230 unordered_map<int64_t, int>& conditionTrackerMap,
231 vector<sp<ConditionTracker>>& allConditionTrackers,
232 unordered_map<int, std::vector<int>>& trackerToConditionMap) {
233 vector<Predicate> conditionConfigs;
234 const int conditionTrackerCount = config.predicate_size();
235 conditionConfigs.reserve(conditionTrackerCount);
236 allConditionTrackers.reserve(conditionTrackerCount);
237
238 for (int i = 0; i < conditionTrackerCount; i++) {
239 const Predicate& condition = config.predicate(i);
240 int index = allConditionTrackers.size();
241 switch (condition.contents_case()) {
242 case Predicate::ContentsCase::kSimplePredicate: {
243 vector<Matcher> primaryKeys;
244 if (isStateTracker(condition.simple_predicate(), &primaryKeys)) {
245 allConditionTrackers.push_back(new StateTracker(key, condition.id(), index,
246 condition.simple_predicate(),
247 logTrackerMap, primaryKeys));
248 } else {
249 allConditionTrackers.push_back(new SimpleConditionTracker(
250 key, condition.id(), index, condition.simple_predicate(),
251 logTrackerMap));
252 }
253 break;
254 }
255 case Predicate::ContentsCase::kCombination: {
256 allConditionTrackers.push_back(
257 new CombinationConditionTracker(condition.id(), index));
258 break;
259 }
260 default:
261 ALOGE("Predicate \"%lld\" malformed", (long long)condition.id());
262 return false;
263 }
264 if (conditionTrackerMap.find(condition.id()) != conditionTrackerMap.end()) {
265 ALOGE("Duplicate Predicate found!");
266 return false;
267 }
268 conditionTrackerMap[condition.id()] = index;
269 conditionConfigs.push_back(condition);
270 }
271
272 vector<bool> stackTracker(allConditionTrackers.size(), false);
273 for (size_t i = 0; i < allConditionTrackers.size(); i++) {
274 auto& conditionTracker = allConditionTrackers[i];
275 if (!conditionTracker->init(conditionConfigs, allConditionTrackers, conditionTrackerMap,
276 stackTracker)) {
277 return false;
278 }
279 for (const int trackerIndex : conditionTracker->getLogTrackerIndex()) {
280 auto& conditionList = trackerToConditionMap[trackerIndex];
281 conditionList.push_back(i);
282 }
283 }
284 return true;
285 }
286
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> & logTrackerMap,const unordered_map<int64_t,int> & conditionTrackerMap,const vector<sp<LogMatchingTracker>> & allAtomMatchers,vector<sp<ConditionTracker>> & allConditionTrackers,vector<sp<MetricProducer>> & allMetricProducers,unordered_map<int,std::vector<int>> & conditionToMetricMap,unordered_map<int,std::vector<int>> & trackerToMetricMap,unordered_map<int64_t,int> & metricMap,std::set<int64_t> & noReportMetricIds)287 bool initMetrics(const ConfigKey& key, const StatsdConfig& config, const int64_t timeBaseTimeNs,
288 const int64_t currentTimeNs,
289 const sp<StatsPullerManager>& pullerManager,
290 const unordered_map<int64_t, int>& logTrackerMap,
291 const unordered_map<int64_t, int>& conditionTrackerMap,
292 const vector<sp<LogMatchingTracker>>& allAtomMatchers,
293 vector<sp<ConditionTracker>>& allConditionTrackers,
294 vector<sp<MetricProducer>>& allMetricProducers,
295 unordered_map<int, std::vector<int>>& conditionToMetricMap,
296 unordered_map<int, std::vector<int>>& trackerToMetricMap,
297 unordered_map<int64_t, int>& metricMap, std::set<int64_t>& noReportMetricIds) {
298 sp<ConditionWizard> wizard = new ConditionWizard(allConditionTrackers);
299 sp<EventMatcherWizard> matcherWizard = new EventMatcherWizard(allAtomMatchers);
300 const int allMetricsCount = config.count_metric_size() + config.duration_metric_size() +
301 config.event_metric_size() + config.value_metric_size();
302 allMetricProducers.reserve(allMetricsCount);
303 StatsPullerManager statsPullerManager;
304
305 // Build MetricProducers for each metric defined in config.
306 // build CountMetricProducer
307 for (int i = 0; i < config.count_metric_size(); i++) {
308 const CountMetric& metric = config.count_metric(i);
309 if (!metric.has_what()) {
310 ALOGW("cannot find \"what\" in CountMetric \"%lld\"", (long long)metric.id());
311 return false;
312 }
313
314 int metricIndex = allMetricProducers.size();
315 metricMap.insert({metric.id(), metricIndex});
316 int trackerIndex;
317 if (!handleMetricWithLogTrackers(metric.what(), metricIndex,
318 metric.has_dimensions_in_what(),
319 allAtomMatchers, logTrackerMap, trackerToMetricMap,
320 trackerIndex)) {
321 return false;
322 }
323
324 int conditionIndex = -1;
325 if (metric.has_condition()) {
326 bool good = handleMetricWithConditions(
327 metric.condition(), metricIndex, conditionTrackerMap, metric.links(),
328 allConditionTrackers, conditionIndex, conditionToMetricMap);
329 if (!good) {
330 return false;
331 }
332 } else {
333 if (metric.links_size() > 0) {
334 ALOGW("metrics has a MetricConditionLink but doesn't have a condition");
335 return false;
336 }
337 }
338
339 sp<MetricProducer> countProducer =
340 new CountMetricProducer(key, metric, conditionIndex, wizard, timeBaseTimeNs, currentTimeNs);
341 allMetricProducers.push_back(countProducer);
342 }
343
344 // build DurationMetricProducer
345 for (int i = 0; i < config.duration_metric_size(); i++) {
346 int metricIndex = allMetricProducers.size();
347 const DurationMetric& metric = config.duration_metric(i);
348 metricMap.insert({metric.id(), metricIndex});
349
350 auto what_it = conditionTrackerMap.find(metric.what());
351 if (what_it == conditionTrackerMap.end()) {
352 ALOGE("DurationMetric's \"what\" is invalid");
353 return false;
354 }
355
356 const Predicate& durationWhat = config.predicate(what_it->second);
357
358 if (durationWhat.contents_case() != Predicate::ContentsCase::kSimplePredicate) {
359 ALOGE("DurationMetric's \"what\" must be a simple condition");
360 return false;
361 }
362
363 const auto& simplePredicate = durationWhat.simple_predicate();
364
365 bool nesting = simplePredicate.count_nesting();
366
367 int trackerIndices[3] = {-1, -1, -1};
368 if (!simplePredicate.has_start() ||
369 !handleMetricWithLogTrackers(simplePredicate.start(), metricIndex,
370 metric.has_dimensions_in_what(), allAtomMatchers,
371 logTrackerMap, trackerToMetricMap, trackerIndices[0])) {
372 ALOGE("Duration metrics must specify a valid the start event matcher");
373 return false;
374 }
375
376 if (simplePredicate.has_stop() &&
377 !handleMetricWithLogTrackers(simplePredicate.stop(), metricIndex,
378 metric.has_dimensions_in_what(), allAtomMatchers,
379 logTrackerMap, trackerToMetricMap, trackerIndices[1])) {
380 return false;
381 }
382
383 if (simplePredicate.has_stop_all() &&
384 !handleMetricWithLogTrackers(simplePredicate.stop_all(), metricIndex,
385 metric.has_dimensions_in_what(), allAtomMatchers,
386 logTrackerMap, trackerToMetricMap, trackerIndices[2])) {
387 return false;
388 }
389
390 FieldMatcher internalDimensions = simplePredicate.dimensions();
391
392 int conditionIndex = -1;
393
394 if (metric.has_condition()) {
395 bool good = handleMetricWithConditions(
396 metric.condition(), metricIndex, conditionTrackerMap, metric.links(),
397 allConditionTrackers, conditionIndex, conditionToMetricMap);
398 if (!good) {
399 return false;
400 }
401 } else {
402 if (metric.links_size() > 0) {
403 ALOGW("metrics has a MetricConditionLink but doesn't have a condition");
404 return false;
405 }
406 }
407
408 sp<MetricProducer> durationMetric = new DurationMetricProducer(
409 key, metric, conditionIndex, trackerIndices[0], trackerIndices[1],
410 trackerIndices[2], nesting, wizard, internalDimensions, timeBaseTimeNs, currentTimeNs);
411
412 allMetricProducers.push_back(durationMetric);
413 }
414
415 // build EventMetricProducer
416 for (int i = 0; i < config.event_metric_size(); i++) {
417 int metricIndex = allMetricProducers.size();
418 const EventMetric& metric = config.event_metric(i);
419 metricMap.insert({metric.id(), metricIndex});
420 if (!metric.has_id() || !metric.has_what()) {
421 ALOGW("cannot find the metric name or what in config");
422 return false;
423 }
424 int trackerIndex;
425 if (!handleMetricWithLogTrackers(metric.what(), metricIndex, false, allAtomMatchers,
426 logTrackerMap, trackerToMetricMap, trackerIndex)) {
427 return false;
428 }
429
430 int conditionIndex = -1;
431 if (metric.has_condition()) {
432 bool good = handleMetricWithConditions(
433 metric.condition(), metricIndex, conditionTrackerMap, metric.links(),
434 allConditionTrackers, conditionIndex, conditionToMetricMap);
435 if (!good) {
436 return false;
437 }
438 } else {
439 if (metric.links_size() > 0) {
440 ALOGW("metrics has a MetricConditionLink but doesn't have a condition");
441 return false;
442 }
443 }
444
445 sp<MetricProducer> eventMetric =
446 new EventMetricProducer(key, metric, conditionIndex, wizard, timeBaseTimeNs);
447
448 allMetricProducers.push_back(eventMetric);
449 }
450
451 // build ValueMetricProducer
452 for (int i = 0; i < config.value_metric_size(); i++) {
453 const ValueMetric& metric = config.value_metric(i);
454 if (!metric.has_what()) {
455 ALOGW("cannot find \"what\" in ValueMetric \"%lld\"", (long long)metric.id());
456 return false;
457 }
458 if (!metric.has_value_field()) {
459 ALOGW("cannot find \"value_field\" in ValueMetric \"%lld\"", (long long)metric.id());
460 return false;
461 }
462 std::vector<Matcher> fieldMatchers;
463 translateFieldMatcher(metric.value_field(), &fieldMatchers);
464 if (fieldMatchers.size() < 1) {
465 ALOGW("incorrect \"value_field\" in ValueMetric \"%lld\"", (long long)metric.id());
466 return false;
467 }
468
469 int metricIndex = allMetricProducers.size();
470 metricMap.insert({metric.id(), metricIndex});
471 int trackerIndex;
472 if (!handleMetricWithLogTrackers(metric.what(), metricIndex,
473 metric.has_dimensions_in_what(),
474 allAtomMatchers, logTrackerMap, trackerToMetricMap,
475 trackerIndex)) {
476 return false;
477 }
478
479 sp<LogMatchingTracker> atomMatcher = allAtomMatchers.at(trackerIndex);
480 // If it is pulled atom, it should be simple matcher with one tagId.
481 if (atomMatcher->getAtomIds().size() != 1) {
482 return false;
483 }
484 int atomTagId = *(atomMatcher->getAtomIds().begin());
485 int pullTagId = statsPullerManager.PullerForMatcherExists(atomTagId) ? atomTagId : -1;
486
487 int conditionIndex = -1;
488 if (metric.has_condition()) {
489 bool good = handleMetricWithConditions(
490 metric.condition(), metricIndex, conditionTrackerMap, metric.links(),
491 allConditionTrackers, conditionIndex, conditionToMetricMap);
492 if (!good) {
493 return false;
494 }
495 } else {
496 if (metric.links_size() > 0) {
497 ALOGW("metrics has a MetricConditionLink but doesn't have a condition");
498 return false;
499 }
500 }
501
502 sp<MetricProducer> valueProducer = new ValueMetricProducer(
503 key, metric, conditionIndex, wizard, trackerIndex, matcherWizard, pullTagId,
504 timeBaseTimeNs, currentTimeNs, pullerManager);
505 allMetricProducers.push_back(valueProducer);
506 }
507
508 // Gauge metrics.
509 for (int i = 0; i < config.gauge_metric_size(); i++) {
510 const GaugeMetric& metric = config.gauge_metric(i);
511 if (!metric.has_what()) {
512 ALOGW("cannot find \"what\" in GaugeMetric \"%lld\"", (long long)metric.id());
513 return false;
514 }
515
516 if ((!metric.gauge_fields_filter().has_include_all() ||
517 (metric.gauge_fields_filter().include_all() == false)) &&
518 !hasLeafNode(metric.gauge_fields_filter().fields())) {
519 ALOGW("Incorrect field filter setting in GaugeMetric %lld", (long long)metric.id());
520 return false;
521 }
522 if ((metric.gauge_fields_filter().has_include_all() &&
523 metric.gauge_fields_filter().include_all() == true) &&
524 hasLeafNode(metric.gauge_fields_filter().fields())) {
525 ALOGW("Incorrect field filter setting in GaugeMetric %lld", (long long)metric.id());
526 return false;
527 }
528
529 int metricIndex = allMetricProducers.size();
530 metricMap.insert({metric.id(), metricIndex});
531 int trackerIndex;
532 if (!handleMetricWithLogTrackers(metric.what(), metricIndex,
533 metric.has_dimensions_in_what(),
534 allAtomMatchers, logTrackerMap, trackerToMetricMap,
535 trackerIndex)) {
536 return false;
537 }
538
539 sp<LogMatchingTracker> atomMatcher = allAtomMatchers.at(trackerIndex);
540 // For GaugeMetric atom, it should be simple matcher with one tagId.
541 if (atomMatcher->getAtomIds().size() != 1) {
542 return false;
543 }
544 int atomTagId = *(atomMatcher->getAtomIds().begin());
545 int pullTagId = statsPullerManager.PullerForMatcherExists(atomTagId) ? atomTagId : -1;
546
547 int triggerTrackerIndex;
548 int triggerAtomId = -1;
549 if (metric.has_trigger_event()) {
550 if (pullTagId == -1) {
551 ALOGW("Pull atom not specified for trigger");
552 return false;
553 }
554 // event_trigger should be used with FIRST_N_SAMPLES
555 if (metric.sampling_type() != GaugeMetric::FIRST_N_SAMPLES) {
556 return false;
557 }
558 if (!handlePullMetricTriggerWithLogTrackers(metric.trigger_event(), metricIndex,
559 allAtomMatchers, logTrackerMap,
560 trackerToMetricMap, triggerTrackerIndex)) {
561 return false;
562 }
563 sp<LogMatchingTracker> triggerAtomMatcher = allAtomMatchers.at(triggerTrackerIndex);
564 triggerAtomId = *(triggerAtomMatcher->getAtomIds().begin());
565 }
566
567 if (!metric.has_trigger_event() && pullTagId != -1 &&
568 metric.sampling_type() == GaugeMetric::FIRST_N_SAMPLES) {
569 ALOGW("FIRST_N_SAMPLES is only for pushed event or pull_on_trigger");
570 return false;
571 }
572
573 int conditionIndex = -1;
574 if (metric.has_condition()) {
575 bool good = handleMetricWithConditions(
576 metric.condition(), metricIndex, conditionTrackerMap, metric.links(),
577 allConditionTrackers, conditionIndex, conditionToMetricMap);
578 if (!good) {
579 return false;
580 }
581 } else {
582 if (metric.links_size() > 0) {
583 ALOGW("metrics has a MetricConditionLink but doesn't have a condition");
584 return false;
585 }
586 }
587
588 sp<MetricProducer> gaugeProducer = new GaugeMetricProducer(
589 key, metric, conditionIndex, wizard,
590 trackerIndex, matcherWizard, pullTagId, triggerAtomId, atomTagId,
591 timeBaseTimeNs, currentTimeNs, pullerManager);
592 allMetricProducers.push_back(gaugeProducer);
593 }
594 for (int i = 0; i < config.no_report_metric_size(); ++i) {
595 const auto no_report_metric = config.no_report_metric(i);
596 if (metricMap.find(no_report_metric) == metricMap.end()) {
597 ALOGW("no_report_metric %" PRId64 " not exist", no_report_metric);
598 return false;
599 }
600 noReportMetricIds.insert(no_report_metric);
601 }
602 return true;
603 }
604
initAlerts(const StatsdConfig & config,const unordered_map<int64_t,int> & metricProducerMap,const sp<AlarmMonitor> & anomalyAlarmMonitor,vector<sp<MetricProducer>> & allMetricProducers,vector<sp<AnomalyTracker>> & allAnomalyTrackers)605 bool initAlerts(const StatsdConfig& config,
606 const unordered_map<int64_t, int>& metricProducerMap,
607 const sp<AlarmMonitor>& anomalyAlarmMonitor,
608 vector<sp<MetricProducer>>& allMetricProducers,
609 vector<sp<AnomalyTracker>>& allAnomalyTrackers) {
610 unordered_map<int64_t, int> anomalyTrackerMap;
611 for (int i = 0; i < config.alert_size(); i++) {
612 const Alert& alert = config.alert(i);
613 const auto& itr = metricProducerMap.find(alert.metric_id());
614 if (itr == metricProducerMap.end()) {
615 ALOGW("alert \"%lld\" has unknown metric id: \"%lld\"", (long long)alert.id(),
616 (long long)alert.metric_id());
617 return false;
618 }
619 if (!alert.has_trigger_if_sum_gt()) {
620 ALOGW("invalid alert: missing threshold");
621 return false;
622 }
623 if (alert.trigger_if_sum_gt() < 0 || alert.num_buckets() <= 0) {
624 ALOGW("invalid alert: threshold=%f num_buckets= %d",
625 alert.trigger_if_sum_gt(), alert.num_buckets());
626 return false;
627 }
628 const int metricIndex = itr->second;
629 sp<MetricProducer> metric = allMetricProducers[metricIndex];
630 sp<AnomalyTracker> anomalyTracker = metric->addAnomalyTracker(alert, anomalyAlarmMonitor);
631 if (anomalyTracker == nullptr) {
632 // The ALOGW for this invalid alert was already displayed in addAnomalyTracker().
633 return false;
634 }
635 anomalyTrackerMap.insert(std::make_pair(alert.id(), allAnomalyTrackers.size()));
636 allAnomalyTrackers.push_back(anomalyTracker);
637 }
638 for (int i = 0; i < config.subscription_size(); ++i) {
639 const Subscription& subscription = config.subscription(i);
640 if (subscription.rule_type() != Subscription::ALERT) {
641 continue;
642 }
643 if (subscription.subscriber_information_case() ==
644 Subscription::SubscriberInformationCase::SUBSCRIBER_INFORMATION_NOT_SET) {
645 ALOGW("subscription \"%lld\" has no subscriber info.\"",
646 (long long)subscription.id());
647 return false;
648 }
649 const auto& itr = anomalyTrackerMap.find(subscription.rule_id());
650 if (itr == anomalyTrackerMap.end()) {
651 ALOGW("subscription \"%lld\" has unknown rule id: \"%lld\"",
652 (long long)subscription.id(), (long long)subscription.rule_id());
653 return false;
654 }
655 const int anomalyTrackerIndex = itr->second;
656 allAnomalyTrackers[anomalyTrackerIndex]->addSubscription(subscription);
657 }
658 return true;
659 }
660
initAlarms(const StatsdConfig & config,const ConfigKey & key,const sp<AlarmMonitor> & periodicAlarmMonitor,const int64_t timeBaseNs,const int64_t currentTimeNs,vector<sp<AlarmTracker>> & allAlarmTrackers)661 bool initAlarms(const StatsdConfig& config, const ConfigKey& key,
662 const sp<AlarmMonitor>& periodicAlarmMonitor,
663 const int64_t timeBaseNs, const int64_t currentTimeNs,
664 vector<sp<AlarmTracker>>& allAlarmTrackers) {
665 unordered_map<int64_t, int> alarmTrackerMap;
666 int64_t startMillis = timeBaseNs / 1000 / 1000;
667 int64_t currentTimeMillis = currentTimeNs / 1000 /1000;
668 for (int i = 0; i < config.alarm_size(); i++) {
669 const Alarm& alarm = config.alarm(i);
670 if (alarm.offset_millis() <= 0) {
671 ALOGW("Alarm offset_millis should be larger than 0.");
672 return false;
673 }
674 if (alarm.period_millis() <= 0) {
675 ALOGW("Alarm period_millis should be larger than 0.");
676 return false;
677 }
678 alarmTrackerMap.insert(std::make_pair(alarm.id(), allAlarmTrackers.size()));
679 allAlarmTrackers.push_back(
680 new AlarmTracker(startMillis, currentTimeMillis,
681 alarm, key, periodicAlarmMonitor));
682 }
683 for (int i = 0; i < config.subscription_size(); ++i) {
684 const Subscription& subscription = config.subscription(i);
685 if (subscription.rule_type() != Subscription::ALARM) {
686 continue;
687 }
688 if (subscription.subscriber_information_case() ==
689 Subscription::SubscriberInformationCase::SUBSCRIBER_INFORMATION_NOT_SET) {
690 ALOGW("subscription \"%lld\" has no subscriber info.\"",
691 (long long)subscription.id());
692 return false;
693 }
694 const auto& itr = alarmTrackerMap.find(subscription.rule_id());
695 if (itr == alarmTrackerMap.end()) {
696 ALOGW("subscription \"%lld\" has unknown rule id: \"%lld\"",
697 (long long)subscription.id(), (long long)subscription.rule_id());
698 return false;
699 }
700 const int trackerIndex = itr->second;
701 allAlarmTrackers[trackerIndex]->addSubscription(subscription);
702 }
703 return true;
704 }
705
initMetricActivations(const ConfigKey & key,const StatsdConfig & config,const int64_t currentTimeNs,const unordered_map<int64_t,int> & logEventTrackerMap,const unordered_map<int64_t,int> & metricProducerMap,vector<sp<MetricProducer>> & allMetricProducers,unordered_map<int,std::vector<int>> & activationAtomTrackerToMetricMap,unordered_map<int,std::vector<int>> & deactivationAtomTrackerToMetricMap,vector<int> & metricsWithActivation)706 bool initMetricActivations(const ConfigKey& key, const StatsdConfig& config,
707 const int64_t currentTimeNs,
708 const unordered_map<int64_t, int> &logEventTrackerMap,
709 const unordered_map<int64_t, int> &metricProducerMap,
710 vector<sp<MetricProducer>>& allMetricProducers,
711 unordered_map<int, std::vector<int>>& activationAtomTrackerToMetricMap,
712 unordered_map<int, std::vector<int>>& deactivationAtomTrackerToMetricMap,
713 vector<int>& metricsWithActivation) {
714 for (int i = 0; i < config.metric_activation_size(); ++i) {
715 const MetricActivation& metric_activation = config.metric_activation(i);
716 auto itr = metricProducerMap.find(metric_activation.metric_id());
717 if (itr == metricProducerMap.end()) {
718 ALOGE("Metric id not found in metric activation: %lld",
719 (long long)metric_activation.metric_id());
720 return false;
721 }
722 const int metricTrackerIndex = itr->second;
723 if (metricTrackerIndex < 0 || metricTrackerIndex >= (int)allMetricProducers.size()) {
724 ALOGE("Invalid metric tracker index.");
725 return false;
726 }
727 const sp<MetricProducer>& metric = allMetricProducers[metricTrackerIndex];
728 metricsWithActivation.push_back(metricTrackerIndex);
729 for (int j = 0; j < metric_activation.event_activation_size(); ++j) {
730 const EventActivation& activation = metric_activation.event_activation(j);
731 auto logTrackerIt = logEventTrackerMap.find(activation.atom_matcher_id());
732 if (logTrackerIt == logEventTrackerMap.end()) {
733 ALOGE("Atom matcher not found for event activation.");
734 return false;
735 }
736 const int atomMatcherIndex = logTrackerIt->second;
737 activationAtomTrackerToMetricMap[atomMatcherIndex].push_back(
738 metricTrackerIndex);
739
740 ActivationType activationType;
741 if (activation.has_activation_type()) {
742 activationType = activation.activation_type();
743 } else {
744 activationType = metric_activation.activation_type();
745 }
746
747 if (activation.has_deactivation_atom_matcher_id()) {
748 auto deactivationAtomMatcherIt =
749 logEventTrackerMap.find(activation.deactivation_atom_matcher_id());
750 if (deactivationAtomMatcherIt == logEventTrackerMap.end()) {
751 ALOGE("Atom matcher not found for event deactivation.");
752 return false;
753 }
754 const int deactivationMatcherIndex = deactivationAtomMatcherIt->second;
755 deactivationAtomTrackerToMetricMap[deactivationMatcherIndex]
756 .push_back(metricTrackerIndex);
757 metric->addActivation(atomMatcherIndex, activationType, activation.ttl_seconds(),
758 deactivationMatcherIndex);
759 } else {
760 metric->addActivation(atomMatcherIndex, activationType, activation.ttl_seconds());
761 }
762 }
763 }
764 return true;
765 }
766
prepareFirstBucket(const vector<sp<MetricProducer>> & allMetricProducers)767 void prepareFirstBucket(const vector<sp<MetricProducer>>& allMetricProducers) {
768 for (const auto& metric: allMetricProducers) {
769 metric->prepareFirstBucket();
770 }
771 }
772
initStatsdConfig(const ConfigKey & key,const StatsdConfig & config,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<LogMatchingTracker>> & allAtomMatchers,vector<sp<ConditionTracker>> & allConditionTrackers,vector<sp<MetricProducer>> & allMetricProducers,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,vector<int> & metricsWithActivation,std::set<int64_t> & noReportMetricIds)773 bool initStatsdConfig(const ConfigKey& key, const StatsdConfig& config, UidMap& uidMap,
774 const sp<StatsPullerManager>& pullerManager,
775 const sp<AlarmMonitor>& anomalyAlarmMonitor,
776 const sp<AlarmMonitor>& periodicAlarmMonitor, const int64_t timeBaseNs,
777 const int64_t currentTimeNs, set<int>& allTagIds,
778 vector<sp<LogMatchingTracker>>& allAtomMatchers,
779 vector<sp<ConditionTracker>>& allConditionTrackers,
780 vector<sp<MetricProducer>>& allMetricProducers,
781 vector<sp<AnomalyTracker>>& allAnomalyTrackers,
782 vector<sp<AlarmTracker>>& allPeriodicAlarmTrackers,
783 unordered_map<int, std::vector<int>>& conditionToMetricMap,
784 unordered_map<int, std::vector<int>>& trackerToMetricMap,
785 unordered_map<int, std::vector<int>>& trackerToConditionMap,
786 unordered_map<int, std::vector<int>>& activationAtomTrackerToMetricMap,
787 unordered_map<int, std::vector<int>>& deactivationAtomTrackerToMetricMap,
788 vector<int>& metricsWithActivation,
789 std::set<int64_t>& noReportMetricIds) {
790 unordered_map<int64_t, int> logTrackerMap;
791 unordered_map<int64_t, int> conditionTrackerMap;
792 unordered_map<int64_t, int> metricProducerMap;
793
794 if (!initLogTrackers(config, uidMap, logTrackerMap, allAtomMatchers, allTagIds)) {
795 ALOGE("initLogMatchingTrackers failed");
796 return false;
797 }
798 VLOG("initLogMatchingTrackers succeed...");
799
800 if (!initConditions(key, config, logTrackerMap, conditionTrackerMap, allConditionTrackers,
801 trackerToConditionMap)) {
802 ALOGE("initConditionTrackers failed");
803 return false;
804 }
805
806 if (!initMetrics(key, config, timeBaseNs, currentTimeNs, pullerManager, logTrackerMap,
807 conditionTrackerMap, allAtomMatchers, allConditionTrackers, allMetricProducers,
808 conditionToMetricMap, trackerToMetricMap, metricProducerMap,
809 noReportMetricIds)) {
810 ALOGE("initMetricProducers failed");
811 return false;
812 }
813 if (!initAlerts(config, metricProducerMap, anomalyAlarmMonitor, allMetricProducers,
814 allAnomalyTrackers)) {
815 ALOGE("initAlerts failed");
816 return false;
817 }
818 if (!initAlarms(config, key, periodicAlarmMonitor,
819 timeBaseNs, currentTimeNs, allPeriodicAlarmTrackers)) {
820 ALOGE("initAlarms failed");
821 return false;
822 }
823 if (!initMetricActivations(key, config, currentTimeNs, logTrackerMap, metricProducerMap,
824 allMetricProducers, activationAtomTrackerToMetricMap,
825 deactivationAtomTrackerToMetricMap, metricsWithActivation)) {
826 ALOGE("initMetricActivations failed");
827 return false;
828 }
829
830 prepareFirstBucket(allMetricProducers);
831
832 return true;
833 }
834
835 } // namespace statsd
836 } // namespace os
837 } // namespace android
838