blob: 46442b57126c9a752742d0cd26d84a15f4a819b5 [file] [log] [blame]
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#define DEBUG false // STOPSHIP if true
#include "Log.h"
#include "metrics_manager_util.h"
#include "../condition/CombinationConditionTracker.h"
#include "../condition/SimpleConditionTracker.h"
#include "../condition/StateTracker.h"
#include "../external/StatsPullerManager.h"
#include "../matchers/CombinationLogMatchingTracker.h"
#include "../matchers/SimpleLogMatchingTracker.h"
#include "../matchers/EventMatcherWizard.h"
#include "../metrics/CountMetricProducer.h"
#include "../metrics/DurationMetricProducer.h"
#include "../metrics/EventMetricProducer.h"
#include "../metrics/GaugeMetricProducer.h"
#include "../metrics/ValueMetricProducer.h"
#include "atoms_info.h"
#include "stats_util.h"
#include <inttypes.h>
using std::set;
using std::string;
using std::unordered_map;
using std::vector;
namespace android {
namespace os {
namespace statsd {
namespace {
bool hasLeafNode(const FieldMatcher& matcher) {
if (!matcher.has_field()) {
return false;
}
for (int i = 0; i < matcher.child_size(); ++i) {
if (hasLeafNode(matcher.child(i))) {
return true;
}
}
return true;
}
} // namespace
bool 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) {
auto logTrackerIt = logTrackerMap.find(what);
if (logTrackerIt == logTrackerMap.end()) {
ALOGW("cannot find the AtomMatcher \"%lld\" in config", (long long)what);
return false;
}
if (usedForDimension && allAtomMatchers[logTrackerIt->second]->getAtomIds().size() > 1) {
ALOGE("AtomMatcher \"%lld\" has more than one tag ids. When a metric has dimension, "
"the \"what\" can only about one atom type.",
(long long)what);
return false;
}
logTrackerIndex = logTrackerIt->second;
auto& metric_list = trackerToMetricMap[logTrackerIndex];
metric_list.push_back(metricIndex);
return true;
}
bool 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) {
auto logTrackerIt = logTrackerMap.find(trigger);
if (logTrackerIt == logTrackerMap.end()) {
ALOGW("cannot find the AtomMatcher \"%lld\" in config", (long long)trigger);
return false;
}
if (allAtomMatchers[logTrackerIt->second]->getAtomIds().size() > 1) {
ALOGE("AtomMatcher \"%lld\" has more than one tag ids."
"Trigger can only be one atom type.",
(long long)trigger);
return false;
}
logTrackerIndex = logTrackerIt->second;
auto& metric_list = trackerToMetricMap[logTrackerIndex];
metric_list.push_back(metricIndex);
return true;
}
bool 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) {
auto condition_it = conditionTrackerMap.find(condition);
if (condition_it == conditionTrackerMap.end()) {
ALOGW("cannot find Predicate \"%lld\" in the config", (long long)condition);
return false;
}
for (const auto& link : links) {
auto it = conditionTrackerMap.find(link.condition());
if (it == conditionTrackerMap.end()) {
ALOGW("cannot find Predicate \"%lld\" in the config", (long long)link.condition());
return false;
}
allConditionTrackers[condition_it->second]->setSliced(true);
allConditionTrackers[it->second]->setSliced(true);
}
conditionIndex = condition_it->second;
// will create new vector if not exist before.
auto& metricList = conditionToMetricMap[condition_it->second];
metricList.push_back(metricIndex);
return true;
}
bool initLogTrackers(const StatsdConfig& config, const UidMap& uidMap,
unordered_map<int64_t, int>& logTrackerMap,
vector<sp<LogMatchingTracker>>& allAtomMatchers, set<int>& allTagIds) {
vector<AtomMatcher> matcherConfigs;
const int atomMatcherCount = config.atom_matcher_size();
matcherConfigs.reserve(atomMatcherCount);
allAtomMatchers.reserve(atomMatcherCount);
for (int i = 0; i < atomMatcherCount; i++) {
const AtomMatcher& logMatcher = config.atom_matcher(i);
int index = allAtomMatchers.size();
switch (logMatcher.contents_case()) {
case AtomMatcher::ContentsCase::kSimpleAtomMatcher:
allAtomMatchers.push_back(new SimpleLogMatchingTracker(
logMatcher.id(), index, logMatcher.simple_atom_matcher(), uidMap));
break;
case AtomMatcher::ContentsCase::kCombination:
allAtomMatchers.push_back(
new CombinationLogMatchingTracker(logMatcher.id(), index));
break;
default:
ALOGE("Matcher \"%lld\" malformed", (long long)logMatcher.id());
return false;
// continue;
}
if (logTrackerMap.find(logMatcher.id()) != logTrackerMap.end()) {
ALOGE("Duplicate AtomMatcher found!");
return false;
}
logTrackerMap[logMatcher.id()] = index;
matcherConfigs.push_back(logMatcher);
}
vector<bool> stackTracker2(allAtomMatchers.size(), false);
for (auto& matcher : allAtomMatchers) {
if (!matcher->init(matcherConfigs, allAtomMatchers, logTrackerMap, stackTracker2)) {
return false;
}
// Collect all the tag ids that are interesting. TagIds exist in leaf nodes only.
const set<int>& tagIds = matcher->getAtomIds();
allTagIds.insert(tagIds.begin(), tagIds.end());
}
return true;
}
/**
* A StateTracker is built from a SimplePredicate which has only "start", and no "stop"
* or "stop_all". The start must be an atom matcher that matches a state atom. It must
* have dimension, the dimension must be the state atom's primary fields plus exclusive state
* field. For example, the StateTracker is used in tracking UidProcessState and ScreenState.
*
*/
bool isStateTracker(const SimplePredicate& simplePredicate, vector<Matcher>* primaryKeys) {
// 1. must not have "stop". must have "dimension"
if (!simplePredicate.has_stop() && simplePredicate.has_dimensions()) {
auto it = android::util::AtomsInfo::kStateAtomsFieldOptions.find(
simplePredicate.dimensions().field());
// 2. must be based on a state atom.
if (it != android::util::AtomsInfo::kStateAtomsFieldOptions.end()) {
// 3. dimension must be primary fields + state field IN ORDER
size_t expectedDimensionCount = it->second.primaryFields.size() + 1;
vector<Matcher> dimensions;
translateFieldMatcher(simplePredicate.dimensions(), &dimensions);
if (dimensions.size() != expectedDimensionCount) {
return false;
}
// 3.1 check the primary fields first.
size_t index = 0;
for (const auto& field : it->second.primaryFields) {
Matcher matcher = getSimpleMatcher(it->first, field);
if (!(matcher == dimensions[index])) {
return false;
}
primaryKeys->push_back(matcher);
index++;
}
Matcher stateFieldMatcher =
getSimpleMatcher(it->first, it->second.exclusiveField);
// 3.2 last dimension should be the exclusive field.
if (!(dimensions.back() == stateFieldMatcher)) {
return false;
}
return true;
}
}
return false;
} // namespace statsd
bool 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) {
vector<Predicate> conditionConfigs;
const int conditionTrackerCount = config.predicate_size();
conditionConfigs.reserve(conditionTrackerCount);
allConditionTrackers.reserve(conditionTrackerCount);
for (int i = 0; i < conditionTrackerCount; i++) {
const Predicate& condition = config.predicate(i);
int index = allConditionTrackers.size();
switch (condition.contents_case()) {
case Predicate::ContentsCase::kSimplePredicate: {
vector<Matcher> primaryKeys;
if (isStateTracker(condition.simple_predicate(), &primaryKeys)) {
allConditionTrackers.push_back(new StateTracker(key, condition.id(), index,
condition.simple_predicate(),
logTrackerMap, primaryKeys));
} else {
allConditionTrackers.push_back(new SimpleConditionTracker(
key, condition.id(), index, condition.simple_predicate(),
logTrackerMap));
}
break;
}
case Predicate::ContentsCase::kCombination: {
allConditionTrackers.push_back(
new CombinationConditionTracker(condition.id(), index));
break;
}
default:
ALOGE("Predicate \"%lld\" malformed", (long long)condition.id());
return false;
}
if (conditionTrackerMap.find(condition.id()) != conditionTrackerMap.end()) {
ALOGE("Duplicate Predicate found!");
return false;
}
conditionTrackerMap[condition.id()] = index;
conditionConfigs.push_back(condition);
}
vector<bool> stackTracker(allConditionTrackers.size(), false);
for (size_t i = 0; i < allConditionTrackers.size(); i++) {
auto& conditionTracker = allConditionTrackers[i];
if (!conditionTracker->init(conditionConfigs, allConditionTrackers, conditionTrackerMap,
stackTracker)) {
return false;
}
for (const int trackerIndex : conditionTracker->getLogTrackerIndex()) {
auto& conditionList = trackerToConditionMap[trackerIndex];
conditionList.push_back(i);
}
}
return true;
}
bool 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) {
sp<ConditionWizard> wizard = new ConditionWizard(allConditionTrackers);
sp<EventMatcherWizard> matcherWizard = new EventMatcherWizard(allAtomMatchers);
const int allMetricsCount = config.count_metric_size() + config.duration_metric_size() +
config.event_metric_size() + config.value_metric_size();
allMetricProducers.reserve(allMetricsCount);
StatsPullerManager statsPullerManager;
// Build MetricProducers for each metric defined in config.
// build CountMetricProducer
for (int i = 0; i < config.count_metric_size(); i++) {
const CountMetric& metric = config.count_metric(i);
if (!metric.has_what()) {
ALOGW("cannot find \"what\" in CountMetric \"%lld\"", (long long)metric.id());
return false;
}
int metricIndex = allMetricProducers.size();
metricMap.insert({metric.id(), metricIndex});
int trackerIndex;
if (!handleMetricWithLogTrackers(metric.what(), metricIndex,
metric.has_dimensions_in_what(),
allAtomMatchers, logTrackerMap, trackerToMetricMap,
trackerIndex)) {
return false;
}
int conditionIndex = -1;
if (metric.has_condition()) {
bool good = handleMetricWithConditions(
metric.condition(), metricIndex, conditionTrackerMap, metric.links(),
allConditionTrackers, conditionIndex, conditionToMetricMap);
if (!good) {
return false;
}
} else {
if (metric.links_size() > 0) {
ALOGW("metrics has a MetricConditionLink but doesn't have a condition");
return false;
}
}
sp<MetricProducer> countProducer =
new CountMetricProducer(key, metric, conditionIndex, wizard, timeBaseTimeNs, currentTimeNs);
allMetricProducers.push_back(countProducer);
}
// build DurationMetricProducer
for (int i = 0; i < config.duration_metric_size(); i++) {
int metricIndex = allMetricProducers.size();
const DurationMetric& metric = config.duration_metric(i);
metricMap.insert({metric.id(), metricIndex});
auto what_it = conditionTrackerMap.find(metric.what());
if (what_it == conditionTrackerMap.end()) {
ALOGE("DurationMetric's \"what\" is invalid");
return false;
}
const Predicate& durationWhat = config.predicate(what_it->second);
if (durationWhat.contents_case() != Predicate::ContentsCase::kSimplePredicate) {
ALOGE("DurationMetric's \"what\" must be a simple condition");
return false;
}
const auto& simplePredicate = durationWhat.simple_predicate();
bool nesting = simplePredicate.count_nesting();
int trackerIndices[3] = {-1, -1, -1};
if (!simplePredicate.has_start() ||
!handleMetricWithLogTrackers(simplePredicate.start(), metricIndex,
metric.has_dimensions_in_what(), allAtomMatchers,
logTrackerMap, trackerToMetricMap, trackerIndices[0])) {
ALOGE("Duration metrics must specify a valid the start event matcher");
return false;
}
if (simplePredicate.has_stop() &&
!handleMetricWithLogTrackers(simplePredicate.stop(), metricIndex,
metric.has_dimensions_in_what(), allAtomMatchers,
logTrackerMap, trackerToMetricMap, trackerIndices[1])) {
return false;
}
if (simplePredicate.has_stop_all() &&
!handleMetricWithLogTrackers(simplePredicate.stop_all(), metricIndex,
metric.has_dimensions_in_what(), allAtomMatchers,
logTrackerMap, trackerToMetricMap, trackerIndices[2])) {
return false;
}
FieldMatcher internalDimensions = simplePredicate.dimensions();
int conditionIndex = -1;
if (metric.has_condition()) {
bool good = handleMetricWithConditions(
metric.condition(), metricIndex, conditionTrackerMap, metric.links(),
allConditionTrackers, conditionIndex, conditionToMetricMap);
if (!good) {
return false;
}
} else {
if (metric.links_size() > 0) {
ALOGW("metrics has a MetricConditionLink but doesn't have a condition");
return false;
}
}
sp<MetricProducer> durationMetric = new DurationMetricProducer(
key, metric, conditionIndex, trackerIndices[0], trackerIndices[1],
trackerIndices[2], nesting, wizard, internalDimensions, timeBaseTimeNs, currentTimeNs);
allMetricProducers.push_back(durationMetric);
}
// build EventMetricProducer
for (int i = 0; i < config.event_metric_size(); i++) {
int metricIndex = allMetricProducers.size();
const EventMetric& metric = config.event_metric(i);
metricMap.insert({metric.id(), metricIndex});
if (!metric.has_id() || !metric.has_what()) {
ALOGW("cannot find the metric name or what in config");
return false;
}
int trackerIndex;
if (!handleMetricWithLogTrackers(metric.what(), metricIndex, false, allAtomMatchers,
logTrackerMap, trackerToMetricMap, trackerIndex)) {
return false;
}
int conditionIndex = -1;
if (metric.has_condition()) {
bool good = handleMetricWithConditions(
metric.condition(), metricIndex, conditionTrackerMap, metric.links(),
allConditionTrackers, conditionIndex, conditionToMetricMap);
if (!good) {
return false;
}
} else {
if (metric.links_size() > 0) {
ALOGW("metrics has a MetricConditionLink but doesn't have a condition");
return false;
}
}
sp<MetricProducer> eventMetric =
new EventMetricProducer(key, metric, conditionIndex, wizard, timeBaseTimeNs);
allMetricProducers.push_back(eventMetric);
}
// build ValueMetricProducer
for (int i = 0; i < config.value_metric_size(); i++) {
const ValueMetric& metric = config.value_metric(i);
if (!metric.has_what()) {
ALOGW("cannot find \"what\" in ValueMetric \"%lld\"", (long long)metric.id());
return false;
}
if (!metric.has_value_field()) {
ALOGW("cannot find \"value_field\" in ValueMetric \"%lld\"", (long long)metric.id());
return false;
}
std::vector<Matcher> fieldMatchers;
translateFieldMatcher(metric.value_field(), &fieldMatchers);
if (fieldMatchers.size() < 1) {
ALOGW("incorrect \"value_field\" in ValueMetric \"%lld\"", (long long)metric.id());
return false;
}
int metricIndex = allMetricProducers.size();
metricMap.insert({metric.id(), metricIndex});
int trackerIndex;
if (!handleMetricWithLogTrackers(metric.what(), metricIndex,
metric.has_dimensions_in_what(),
allAtomMatchers, logTrackerMap, trackerToMetricMap,
trackerIndex)) {
return false;
}
sp<LogMatchingTracker> atomMatcher = allAtomMatchers.at(trackerIndex);
// If it is pulled atom, it should be simple matcher with one tagId.
if (atomMatcher->getAtomIds().size() != 1) {
return false;
}
int atomTagId = *(atomMatcher->getAtomIds().begin());
int pullTagId = statsPullerManager.PullerForMatcherExists(atomTagId) ? atomTagId : -1;
int conditionIndex = -1;
if (metric.has_condition()) {
bool good = handleMetricWithConditions(
metric.condition(), metricIndex, conditionTrackerMap, metric.links(),
allConditionTrackers, conditionIndex, conditionToMetricMap);
if (!good) {
return false;
}
} else {
if (metric.links_size() > 0) {
ALOGW("metrics has a MetricConditionLink but doesn't have a condition");
return false;
}
}
sp<MetricProducer> valueProducer = new ValueMetricProducer(
key, metric, conditionIndex, wizard, trackerIndex, matcherWizard, pullTagId,
timeBaseTimeNs, currentTimeNs, pullerManager);
allMetricProducers.push_back(valueProducer);
}
// Gauge metrics.
for (int i = 0; i < config.gauge_metric_size(); i++) {
const GaugeMetric& metric = config.gauge_metric(i);
if (!metric.has_what()) {
ALOGW("cannot find \"what\" in GaugeMetric \"%lld\"", (long long)metric.id());
return false;
}
if ((!metric.gauge_fields_filter().has_include_all() ||
(metric.gauge_fields_filter().include_all() == false)) &&
!hasLeafNode(metric.gauge_fields_filter().fields())) {
ALOGW("Incorrect field filter setting in GaugeMetric %lld", (long long)metric.id());
return false;
}
if ((metric.gauge_fields_filter().has_include_all() &&
metric.gauge_fields_filter().include_all() == true) &&
hasLeafNode(metric.gauge_fields_filter().fields())) {
ALOGW("Incorrect field filter setting in GaugeMetric %lld", (long long)metric.id());
return false;
}
int metricIndex = allMetricProducers.size();
metricMap.insert({metric.id(), metricIndex});
int trackerIndex;
if (!handleMetricWithLogTrackers(metric.what(), metricIndex,
metric.has_dimensions_in_what(),
allAtomMatchers, logTrackerMap, trackerToMetricMap,
trackerIndex)) {
return false;
}
sp<LogMatchingTracker> atomMatcher = allAtomMatchers.at(trackerIndex);
// For GaugeMetric atom, it should be simple matcher with one tagId.
if (atomMatcher->getAtomIds().size() != 1) {
return false;
}
int atomTagId = *(atomMatcher->getAtomIds().begin());
int pullTagId = statsPullerManager.PullerForMatcherExists(atomTagId) ? atomTagId : -1;
int triggerTrackerIndex;
int triggerAtomId = -1;
if (metric.has_trigger_event()) {
if (pullTagId == -1) {
ALOGW("Pull atom not specified for trigger");
return false;
}
// event_trigger should be used with FIRST_N_SAMPLES
if (metric.sampling_type() != GaugeMetric::FIRST_N_SAMPLES) {
return false;
}
if (!handlePullMetricTriggerWithLogTrackers(metric.trigger_event(), metricIndex,
allAtomMatchers, logTrackerMap,
trackerToMetricMap, triggerTrackerIndex)) {
return false;
}
sp<LogMatchingTracker> triggerAtomMatcher = allAtomMatchers.at(triggerTrackerIndex);
triggerAtomId = *(triggerAtomMatcher->getAtomIds().begin());
}
if (!metric.has_trigger_event() && pullTagId != -1 &&
metric.sampling_type() == GaugeMetric::FIRST_N_SAMPLES) {
ALOGW("FIRST_N_SAMPLES is only for pushed event or pull_on_trigger");
return false;
}
int conditionIndex = -1;
if (metric.has_condition()) {
bool good = handleMetricWithConditions(
metric.condition(), metricIndex, conditionTrackerMap, metric.links(),
allConditionTrackers, conditionIndex, conditionToMetricMap);
if (!good) {
return false;
}
} else {
if (metric.links_size() > 0) {
ALOGW("metrics has a MetricConditionLink but doesn't have a condition");
return false;
}
}
sp<MetricProducer> gaugeProducer = new GaugeMetricProducer(
key, metric, conditionIndex, wizard,
trackerIndex, matcherWizard, pullTagId, triggerAtomId, atomTagId,
timeBaseTimeNs, currentTimeNs, pullerManager);
allMetricProducers.push_back(gaugeProducer);
}
for (int i = 0; i < config.no_report_metric_size(); ++i) {
const auto no_report_metric = config.no_report_metric(i);
if (metricMap.find(no_report_metric) == metricMap.end()) {
ALOGW("no_report_metric %" PRId64 " not exist", no_report_metric);
return false;
}
noReportMetricIds.insert(no_report_metric);
}
for (const auto& it : allMetricProducers) {
uidMap.addListener(it);
}
return true;
}
bool initAlerts(const StatsdConfig& config,
const unordered_map<int64_t, int>& metricProducerMap,
const sp<AlarmMonitor>& anomalyAlarmMonitor,
vector<sp<MetricProducer>>& allMetricProducers,
vector<sp<AnomalyTracker>>& allAnomalyTrackers) {
unordered_map<int64_t, int> anomalyTrackerMap;
for (int i = 0; i < config.alert_size(); i++) {
const Alert& alert = config.alert(i);
const auto& itr = metricProducerMap.find(alert.metric_id());
if (itr == metricProducerMap.end()) {
ALOGW("alert \"%lld\" has unknown metric id: \"%lld\"", (long long)alert.id(),
(long long)alert.metric_id());
return false;
}
if (!alert.has_trigger_if_sum_gt()) {
ALOGW("invalid alert: missing threshold");
return false;
}
if (alert.trigger_if_sum_gt() < 0 || alert.num_buckets() <= 0) {
ALOGW("invalid alert: threshold=%f num_buckets= %d",
alert.trigger_if_sum_gt(), alert.num_buckets());
return false;
}
const int metricIndex = itr->second;
sp<MetricProducer> metric = allMetricProducers[metricIndex];
sp<AnomalyTracker> anomalyTracker = metric->addAnomalyTracker(alert, anomalyAlarmMonitor);
if (anomalyTracker == nullptr) {
// The ALOGW for this invalid alert was already displayed in addAnomalyTracker().
return false;
}
anomalyTrackerMap.insert(std::make_pair(alert.id(), allAnomalyTrackers.size()));
allAnomalyTrackers.push_back(anomalyTracker);
}
for (int i = 0; i < config.subscription_size(); ++i) {
const Subscription& subscription = config.subscription(i);
if (subscription.rule_type() != Subscription::ALERT) {
continue;
}
if (subscription.subscriber_information_case() ==
Subscription::SubscriberInformationCase::SUBSCRIBER_INFORMATION_NOT_SET) {
ALOGW("subscription \"%lld\" has no subscriber info.\"",
(long long)subscription.id());
return false;
}
const auto& itr = anomalyTrackerMap.find(subscription.rule_id());
if (itr == anomalyTrackerMap.end()) {
ALOGW("subscription \"%lld\" has unknown rule id: \"%lld\"",
(long long)subscription.id(), (long long)subscription.rule_id());
return false;
}
const int anomalyTrackerIndex = itr->second;
allAnomalyTrackers[anomalyTrackerIndex]->addSubscription(subscription);
}
return true;
}
bool initAlarms(const StatsdConfig& config, const ConfigKey& key,
const sp<AlarmMonitor>& periodicAlarmMonitor,
const int64_t timeBaseNs, const int64_t currentTimeNs,
vector<sp<AlarmTracker>>& allAlarmTrackers) {
unordered_map<int64_t, int> alarmTrackerMap;
int64_t startMillis = timeBaseNs / 1000 / 1000;
int64_t currentTimeMillis = currentTimeNs / 1000 /1000;
for (int i = 0; i < config.alarm_size(); i++) {
const Alarm& alarm = config.alarm(i);
if (alarm.offset_millis() <= 0) {
ALOGW("Alarm offset_millis should be larger than 0.");
return false;
}
if (alarm.period_millis() <= 0) {
ALOGW("Alarm period_millis should be larger than 0.");
return false;
}
alarmTrackerMap.insert(std::make_pair(alarm.id(), allAlarmTrackers.size()));
allAlarmTrackers.push_back(
new AlarmTracker(startMillis, currentTimeMillis,
alarm, key, periodicAlarmMonitor));
}
for (int i = 0; i < config.subscription_size(); ++i) {
const Subscription& subscription = config.subscription(i);
if (subscription.rule_type() != Subscription::ALARM) {
continue;
}
if (subscription.subscriber_information_case() ==
Subscription::SubscriberInformationCase::SUBSCRIBER_INFORMATION_NOT_SET) {
ALOGW("subscription \"%lld\" has no subscriber info.\"",
(long long)subscription.id());
return false;
}
const auto& itr = alarmTrackerMap.find(subscription.rule_id());
if (itr == alarmTrackerMap.end()) {
ALOGW("subscription \"%lld\" has unknown rule id: \"%lld\"",
(long long)subscription.id(), (long long)subscription.rule_id());
return false;
}
const int trackerIndex = itr->second;
allAlarmTrackers[trackerIndex]->addSubscription(subscription);
}
return true;
}
bool 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) {
for (int i = 0; i < config.metric_activation_size(); ++i) {
const MetricActivation& metric_activation = config.metric_activation(i);
auto itr = metricProducerMap.find(metric_activation.metric_id());
if (itr == metricProducerMap.end()) {
ALOGE("Metric id not found in metric activation: %lld",
(long long)metric_activation.metric_id());
return false;
}
const int metricTrackerIndex = itr->second;
if (metricTrackerIndex < 0 || metricTrackerIndex >= (int)allMetricProducers.size()) {
ALOGE("Invalid metric tracker index.");
return false;
}
const sp<MetricProducer>& metric = allMetricProducers[metricTrackerIndex];
metricsWithActivation.push_back(metricTrackerIndex);
for (int j = 0; j < metric_activation.event_activation_size(); ++j) {
const EventActivation& activation = metric_activation.event_activation(j);
auto logTrackerIt = logEventTrackerMap.find(activation.atom_matcher_id());
if (logTrackerIt == logEventTrackerMap.end()) {
ALOGE("Atom matcher not found for event activation.");
return false;
}
const int atomMatcherIndex = logTrackerIt->second;
activationAtomTrackerToMetricMap[atomMatcherIndex].push_back(
metricTrackerIndex);
ActivationType activationType;
if (activation.has_activation_type()) {
activationType = activation.activation_type();
} else {
activationType = metric_activation.activation_type();
}
if (activation.has_deactivation_atom_matcher_id()) {
auto deactivationAtomMatcherIt =
logEventTrackerMap.find(activation.deactivation_atom_matcher_id());
if (deactivationAtomMatcherIt == logEventTrackerMap.end()) {
ALOGE("Atom matcher not found for event deactivation.");
return false;
}
const int deactivationMatcherIndex = deactivationAtomMatcherIt->second;
deactivationAtomTrackerToMetricMap[deactivationMatcherIndex]
.push_back(metricTrackerIndex);
metric->addActivation(atomMatcherIndex, activationType, activation.ttl_seconds(),
deactivationMatcherIndex);
} else {
metric->addActivation(atomMatcherIndex, activationType, activation.ttl_seconds());
}
}
}
return true;
}
void prepareFirstBucket(const vector<sp<MetricProducer>>& allMetricProducers) {
for (const auto& metric: allMetricProducers) {
metric->prepareFirstBucket();
}
}
bool 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) {
unordered_map<int64_t, int> logTrackerMap;
unordered_map<int64_t, int> conditionTrackerMap;
unordered_map<int64_t, int> metricProducerMap;
if (!initLogTrackers(config, uidMap, logTrackerMap, allAtomMatchers, allTagIds)) {
ALOGE("initLogMatchingTrackers failed");
return false;
}
VLOG("initLogMatchingTrackers succeed...");
if (!initConditions(key, config, logTrackerMap, conditionTrackerMap, allConditionTrackers,
trackerToConditionMap)) {
ALOGE("initConditionTrackers failed");
return false;
}
if (!initMetrics(key, config, timeBaseNs, currentTimeNs, uidMap, pullerManager, logTrackerMap,
conditionTrackerMap, allAtomMatchers, allConditionTrackers, allMetricProducers,
conditionToMetricMap, trackerToMetricMap, metricProducerMap,
noReportMetricIds)) {
ALOGE("initMetricProducers failed");
return false;
}
if (!initAlerts(config, metricProducerMap, anomalyAlarmMonitor, allMetricProducers,
allAnomalyTrackers)) {
ALOGE("initAlerts failed");
return false;
}
if (!initAlarms(config, key, periodicAlarmMonitor,
timeBaseNs, currentTimeNs, allPeriodicAlarmTrackers)) {
ALOGE("initAlarms failed");
return false;
}
if (!initMetricActivations(key, config, currentTimeNs, logTrackerMap, metricProducerMap,
allMetricProducers, activationAtomTrackerToMetricMap,
deactivationAtomTrackerToMetricMap, metricsWithActivation)) {
ALOGE("initMetricActivations failed");
return false;
}
prepareFirstBucket(allMetricProducers);
return true;
}
} // namespace statsd
} // namespace os
} // namespace android