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