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