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