| /* |
| * Copyright (C) 2020 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 STATSD_DEBUG false // STOPSHIP if true |
| #include "Log.h" |
| |
| #include "config_update_utils.h" |
| |
| #include "external/StatsPullerManager.h" |
| #include "hash.h" |
| #include "matchers/EventMatcherWizard.h" |
| #include "metrics_manager_util.h" |
| |
| using google::protobuf::MessageLite; |
| |
| namespace android { |
| namespace os { |
| namespace statsd { |
| |
| // Recursive function to determine if a matcher needs to be updated. Populates matcherToUpdate. |
| // Returns whether the function was successful or not. |
| bool determineMatcherUpdateStatus(const StatsdConfig& config, const int matcherIdx, |
| const unordered_map<int64_t, int>& oldAtomMatchingTrackerMap, |
| const vector<sp<AtomMatchingTracker>>& oldAtomMatchingTrackers, |
| const unordered_map<int64_t, int>& newAtomMatchingTrackerMap, |
| vector<UpdateStatus>& matchersToUpdate, |
| vector<bool>& cycleTracker) { |
| // Have already examined this matcher. |
| if (matchersToUpdate[matcherIdx] != UPDATE_UNKNOWN) { |
| return true; |
| } |
| |
| const AtomMatcher& matcher = config.atom_matcher(matcherIdx); |
| int64_t id = matcher.id(); |
| // Check if new matcher. |
| const auto& oldAtomMatchingTrackerIt = oldAtomMatchingTrackerMap.find(id); |
| if (oldAtomMatchingTrackerIt == oldAtomMatchingTrackerMap.end()) { |
| matchersToUpdate[matcherIdx] = UPDATE_NEW; |
| return true; |
| } |
| |
| // This is an existing matcher. Check if it has changed. |
| string serializedMatcher; |
| if (!matcher.SerializeToString(&serializedMatcher)) { |
| ALOGE("Unable to serialize matcher %lld", (long long)id); |
| return false; |
| } |
| uint64_t newProtoHash = Hash64(serializedMatcher); |
| if (newProtoHash != oldAtomMatchingTrackers[oldAtomMatchingTrackerIt->second]->getProtoHash()) { |
| matchersToUpdate[matcherIdx] = UPDATE_REPLACE; |
| return true; |
| } |
| |
| switch (matcher.contents_case()) { |
| case AtomMatcher::ContentsCase::kSimpleAtomMatcher: { |
| matchersToUpdate[matcherIdx] = UPDATE_PRESERVE; |
| return true; |
| } |
| case AtomMatcher::ContentsCase::kCombination: { |
| // Recurse to check if children have changed. |
| cycleTracker[matcherIdx] = true; |
| UpdateStatus status = UPDATE_PRESERVE; |
| for (const int64_t childMatcherId : matcher.combination().matcher()) { |
| const auto& childIt = newAtomMatchingTrackerMap.find(childMatcherId); |
| if (childIt == newAtomMatchingTrackerMap.end()) { |
| ALOGW("Matcher %lld not found in the config", (long long)childMatcherId); |
| return false; |
| } |
| const int childIdx = childIt->second; |
| if (cycleTracker[childIdx]) { |
| ALOGE("Cycle detected in matcher config"); |
| return false; |
| } |
| if (!determineMatcherUpdateStatus( |
| config, childIdx, oldAtomMatchingTrackerMap, oldAtomMatchingTrackers, |
| newAtomMatchingTrackerMap, matchersToUpdate, cycleTracker)) { |
| return false; |
| } |
| |
| if (matchersToUpdate[childIdx] == UPDATE_REPLACE) { |
| status = UPDATE_REPLACE; |
| break; |
| } |
| } |
| matchersToUpdate[matcherIdx] = status; |
| cycleTracker[matcherIdx] = false; |
| return true; |
| } |
| default: { |
| ALOGE("Matcher \"%lld\" malformed", (long long)id); |
| return false; |
| } |
| } |
| return true; |
| } |
| |
| bool updateAtomMatchingTrackers(const StatsdConfig& config, const sp<UidMap>& uidMap, |
| const unordered_map<int64_t, int>& oldAtomMatchingTrackerMap, |
| const vector<sp<AtomMatchingTracker>>& oldAtomMatchingTrackers, |
| set<int>& allTagIds, |
| unordered_map<int64_t, int>& newAtomMatchingTrackerMap, |
| vector<sp<AtomMatchingTracker>>& newAtomMatchingTrackers, |
| set<int64_t>& replacedMatchers) { |
| const int atomMatcherCount = config.atom_matcher_size(); |
| vector<AtomMatcher> matcherProtos; |
| matcherProtos.reserve(atomMatcherCount); |
| newAtomMatchingTrackers.reserve(atomMatcherCount); |
| |
| // Maps matcher id to their position in the config. For fast lookup of dependencies. |
| for (int i = 0; i < atomMatcherCount; i++) { |
| const AtomMatcher& matcher = config.atom_matcher(i); |
| if (newAtomMatchingTrackerMap.find(matcher.id()) != newAtomMatchingTrackerMap.end()) { |
| ALOGE("Duplicate atom matcher found for id %lld", (long long)matcher.id()); |
| return false; |
| } |
| newAtomMatchingTrackerMap[matcher.id()] = i; |
| matcherProtos.push_back(matcher); |
| } |
| |
| // For combination matchers, we need to determine if any children need to be updated. |
| vector<UpdateStatus> matchersToUpdate(atomMatcherCount, UPDATE_UNKNOWN); |
| vector<bool> cycleTracker(atomMatcherCount, false); |
| for (int i = 0; i < atomMatcherCount; i++) { |
| if (!determineMatcherUpdateStatus(config, i, oldAtomMatchingTrackerMap, |
| oldAtomMatchingTrackers, newAtomMatchingTrackerMap, |
| matchersToUpdate, cycleTracker)) { |
| return false; |
| } |
| } |
| |
| for (int i = 0; i < atomMatcherCount; i++) { |
| const AtomMatcher& matcher = config.atom_matcher(i); |
| const int64_t id = matcher.id(); |
| switch (matchersToUpdate[i]) { |
| case UPDATE_PRESERVE: { |
| const auto& oldAtomMatchingTrackerIt = oldAtomMatchingTrackerMap.find(id); |
| if (oldAtomMatchingTrackerIt == oldAtomMatchingTrackerMap.end()) { |
| ALOGE("Could not find AtomMatcher %lld in the previous config, but expected it " |
| "to be there", |
| (long long)id); |
| return false; |
| } |
| const sp<AtomMatchingTracker>& tracker = |
| oldAtomMatchingTrackers[oldAtomMatchingTrackerIt->second]; |
| if (!tracker->onConfigUpdated(matcherProtos[i], i, newAtomMatchingTrackerMap)) { |
| ALOGW("Config update failed for matcher %lld", (long long)id); |
| return false; |
| } |
| newAtomMatchingTrackers.push_back(tracker); |
| break; |
| } |
| case UPDATE_REPLACE: |
| replacedMatchers.insert(id); |
| [[fallthrough]]; // Intentionally fallthrough to create the new matcher. |
| case UPDATE_NEW: { |
| sp<AtomMatchingTracker> tracker = createAtomMatchingTracker(matcher, i, uidMap); |
| if (tracker == nullptr) { |
| return false; |
| } |
| newAtomMatchingTrackers.push_back(tracker); |
| break; |
| } |
| default: { |
| ALOGE("Matcher \"%lld\" update state is unknown. This should never happen", |
| (long long)id); |
| return false; |
| } |
| } |
| } |
| |
| std::fill(cycleTracker.begin(), cycleTracker.end(), false); |
| for (auto& matcher : newAtomMatchingTrackers) { |
| if (!matcher->init(matcherProtos, newAtomMatchingTrackers, newAtomMatchingTrackerMap, |
| cycleTracker)) { |
| 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; |
| } |
| |
| // Recursive function to determine if a condition needs to be updated. Populates conditionsToUpdate. |
| // Returns whether the function was successful or not. |
| bool determineConditionUpdateStatus(const StatsdConfig& config, const int conditionIdx, |
| const unordered_map<int64_t, int>& oldConditionTrackerMap, |
| const vector<sp<ConditionTracker>>& oldConditionTrackers, |
| const unordered_map<int64_t, int>& newConditionTrackerMap, |
| const set<int64_t>& replacedMatchers, |
| vector<UpdateStatus>& conditionsToUpdate, |
| vector<bool>& cycleTracker) { |
| // Have already examined this condition. |
| if (conditionsToUpdate[conditionIdx] != UPDATE_UNKNOWN) { |
| return true; |
| } |
| |
| const Predicate& predicate = config.predicate(conditionIdx); |
| int64_t id = predicate.id(); |
| // Check if new condition. |
| const auto& oldConditionTrackerIt = oldConditionTrackerMap.find(id); |
| if (oldConditionTrackerIt == oldConditionTrackerMap.end()) { |
| conditionsToUpdate[conditionIdx] = UPDATE_NEW; |
| return true; |
| } |
| |
| // This is an existing condition. Check if it has changed. |
| string serializedCondition; |
| if (!predicate.SerializeToString(&serializedCondition)) { |
| ALOGE("Unable to serialize matcher %lld", (long long)id); |
| return false; |
| } |
| uint64_t newProtoHash = Hash64(serializedCondition); |
| if (newProtoHash != oldConditionTrackers[oldConditionTrackerIt->second]->getProtoHash()) { |
| conditionsToUpdate[conditionIdx] = UPDATE_REPLACE; |
| return true; |
| } |
| |
| switch (predicate.contents_case()) { |
| case Predicate::ContentsCase::kSimplePredicate: { |
| // Need to check if any of the underlying matchers changed. |
| const SimplePredicate& simplePredicate = predicate.simple_predicate(); |
| if (simplePredicate.has_start()) { |
| if (replacedMatchers.find(simplePredicate.start()) != replacedMatchers.end()) { |
| conditionsToUpdate[conditionIdx] = UPDATE_REPLACE; |
| return true; |
| } |
| } |
| if (simplePredicate.has_stop()) { |
| if (replacedMatchers.find(simplePredicate.stop()) != replacedMatchers.end()) { |
| conditionsToUpdate[conditionIdx] = UPDATE_REPLACE; |
| return true; |
| } |
| } |
| if (simplePredicate.has_stop_all()) { |
| if (replacedMatchers.find(simplePredicate.stop_all()) != replacedMatchers.end()) { |
| conditionsToUpdate[conditionIdx] = UPDATE_REPLACE; |
| return true; |
| } |
| } |
| conditionsToUpdate[conditionIdx] = UPDATE_PRESERVE; |
| return true; |
| } |
| case Predicate::ContentsCase::kCombination: { |
| // Need to recurse on the children to see if any of the child predicates changed. |
| cycleTracker[conditionIdx] = true; |
| UpdateStatus status = UPDATE_PRESERVE; |
| for (const int64_t childPredicateId : predicate.combination().predicate()) { |
| const auto& childIt = newConditionTrackerMap.find(childPredicateId); |
| if (childIt == newConditionTrackerMap.end()) { |
| ALOGW("Predicate %lld not found in the config", (long long)childPredicateId); |
| return false; |
| } |
| const int childIdx = childIt->second; |
| if (cycleTracker[childIdx]) { |
| ALOGE("Cycle detected in predicate config"); |
| return false; |
| } |
| if (!determineConditionUpdateStatus(config, childIdx, oldConditionTrackerMap, |
| oldConditionTrackers, newConditionTrackerMap, |
| replacedMatchers, conditionsToUpdate, |
| cycleTracker)) { |
| return false; |
| } |
| |
| if (conditionsToUpdate[childIdx] == UPDATE_REPLACE) { |
| status = UPDATE_REPLACE; |
| break; |
| } |
| } |
| conditionsToUpdate[conditionIdx] = status; |
| cycleTracker[conditionIdx] = false; |
| return true; |
| } |
| default: { |
| ALOGE("Predicate \"%lld\" malformed", (long long)id); |
| return false; |
| } |
| } |
| |
| return true; |
| } |
| |
| bool updateConditions(const ConfigKey& key, const StatsdConfig& config, |
| const unordered_map<int64_t, int>& atomMatchingTrackerMap, |
| const set<int64_t>& replacedMatchers, |
| const unordered_map<int64_t, int>& oldConditionTrackerMap, |
| const vector<sp<ConditionTracker>>& oldConditionTrackers, |
| unordered_map<int64_t, int>& newConditionTrackerMap, |
| vector<sp<ConditionTracker>>& newConditionTrackers, |
| unordered_map<int, vector<int>>& trackerToConditionMap, |
| vector<ConditionState>& conditionCache, set<int64_t>& replacedConditions) { |
| vector<Predicate> conditionProtos; |
| const int conditionTrackerCount = config.predicate_size(); |
| conditionProtos.reserve(conditionTrackerCount); |
| newConditionTrackers.reserve(conditionTrackerCount); |
| conditionCache.assign(conditionTrackerCount, ConditionState::kNotEvaluated); |
| |
| for (int i = 0; i < conditionTrackerCount; i++) { |
| const Predicate& condition = config.predicate(i); |
| if (newConditionTrackerMap.find(condition.id()) != newConditionTrackerMap.end()) { |
| ALOGE("Duplicate Predicate found!"); |
| return false; |
| } |
| newConditionTrackerMap[condition.id()] = i; |
| conditionProtos.push_back(condition); |
| } |
| |
| vector<UpdateStatus> conditionsToUpdate(conditionTrackerCount, UPDATE_UNKNOWN); |
| vector<bool> cycleTracker(conditionTrackerCount, false); |
| for (int i = 0; i < conditionTrackerCount; i++) { |
| if (!determineConditionUpdateStatus(config, i, oldConditionTrackerMap, oldConditionTrackers, |
| newConditionTrackerMap, replacedMatchers, |
| conditionsToUpdate, cycleTracker)) { |
| return false; |
| } |
| } |
| |
| // Update status has been determined for all conditions. Now perform the update. |
| set<int> preservedConditions; |
| for (int i = 0; i < conditionTrackerCount; i++) { |
| const Predicate& predicate = config.predicate(i); |
| const int64_t id = predicate.id(); |
| switch (conditionsToUpdate[i]) { |
| case UPDATE_PRESERVE: { |
| preservedConditions.insert(i); |
| const auto& oldConditionTrackerIt = oldConditionTrackerMap.find(id); |
| if (oldConditionTrackerIt == oldConditionTrackerMap.end()) { |
| ALOGE("Could not find Predicate %lld in the previous config, but expected it " |
| "to be there", |
| (long long)id); |
| return false; |
| } |
| const int oldIndex = oldConditionTrackerIt->second; |
| newConditionTrackers.push_back(oldConditionTrackers[oldIndex]); |
| break; |
| } |
| case UPDATE_REPLACE: |
| replacedConditions.insert(id); |
| [[fallthrough]]; // Intentionally fallthrough to create the new condition tracker. |
| case UPDATE_NEW: { |
| sp<ConditionTracker> tracker = |
| createConditionTracker(key, predicate, i, atomMatchingTrackerMap); |
| if (tracker == nullptr) { |
| return false; |
| } |
| newConditionTrackers.push_back(tracker); |
| break; |
| } |
| default: { |
| ALOGE("Condition \"%lld\" update state is unknown. This should never happen", |
| (long long)id); |
| return false; |
| } |
| } |
| } |
| |
| // Update indices of preserved predicates. |
| for (const int conditionIndex : preservedConditions) { |
| if (!newConditionTrackers[conditionIndex]->onConfigUpdated( |
| conditionProtos, conditionIndex, newConditionTrackers, atomMatchingTrackerMap, |
| newConditionTrackerMap)) { |
| ALOGE("Failed to update condition %lld", |
| (long long)newConditionTrackers[conditionIndex]->getConditionId()); |
| return false; |
| } |
| } |
| |
| std::fill(cycleTracker.begin(), cycleTracker.end(), false); |
| for (int conditionIndex = 0; conditionIndex < conditionTrackerCount; conditionIndex++) { |
| const sp<ConditionTracker>& conditionTracker = newConditionTrackers[conditionIndex]; |
| // Calling init on preserved conditions is OK. It is needed to fill the condition cache. |
| if (!conditionTracker->init(conditionProtos, newConditionTrackers, newConditionTrackerMap, |
| cycleTracker, conditionCache)) { |
| return false; |
| } |
| for (const int trackerIndex : conditionTracker->getAtomMatchingTrackerIndex()) { |
| vector<int>& conditionList = trackerToConditionMap[trackerIndex]; |
| conditionList.push_back(conditionIndex); |
| } |
| } |
| return true; |
| } |
| |
| bool updateStates(const StatsdConfig& config, const map<int64_t, uint64_t>& oldStateProtoHashes, |
| unordered_map<int64_t, int>& stateAtomIdMap, |
| unordered_map<int64_t, unordered_map<int, int64_t>>& allStateGroupMaps, |
| map<int64_t, uint64_t>& newStateProtoHashes, set<int64_t>& replacedStates) { |
| // Share with metrics_manager_util. |
| if (!initStates(config, stateAtomIdMap, allStateGroupMaps, newStateProtoHashes)) { |
| return false; |
| } |
| |
| for (const auto& [stateId, stateHash] : oldStateProtoHashes) { |
| const auto& it = newStateProtoHashes.find(stateId); |
| if (it != newStateProtoHashes.end() && it->second != stateHash) { |
| replacedStates.insert(stateId); |
| } |
| } |
| return true; |
| } |
| // Returns true if any matchers in the metric activation were replaced. |
| bool metricActivationDepsChange(const StatsdConfig& config, |
| const unordered_map<int64_t, int>& metricToActivationMap, |
| const int64_t metricId, const set<int64_t>& replacedMatchers) { |
| const auto& metricActivationIt = metricToActivationMap.find(metricId); |
| if (metricActivationIt == metricToActivationMap.end()) { |
| return false; |
| } |
| const MetricActivation& metricActivation = config.metric_activation(metricActivationIt->second); |
| for (int i = 0; i < metricActivation.event_activation_size(); i++) { |
| const EventActivation& activation = metricActivation.event_activation(i); |
| if (replacedMatchers.find(activation.atom_matcher_id()) != replacedMatchers.end()) { |
| return true; |
| } |
| if (activation.has_deactivation_atom_matcher_id()) { |
| if (replacedMatchers.find(activation.deactivation_atom_matcher_id()) != |
| replacedMatchers.end()) { |
| return true; |
| } |
| } |
| } |
| return false; |
| } |
| |
| bool determineMetricUpdateStatus( |
| const StatsdConfig& config, const MessageLite& metric, const int64_t metricId, |
| const MetricType metricType, const set<int64_t>& matcherDependencies, |
| const set<int64_t>& conditionDependencies, |
| const ::google::protobuf::RepeatedField<int64_t>& stateDependencies, |
| const ::google::protobuf::RepeatedPtrField<MetricConditionLink>& conditionLinks, |
| const unordered_map<int64_t, int>& oldMetricProducerMap, |
| const vector<sp<MetricProducer>>& oldMetricProducers, |
| const unordered_map<int64_t, int>& metricToActivationMap, |
| const set<int64_t>& replacedMatchers, const set<int64_t>& replacedConditions, |
| const set<int64_t>& replacedStates, UpdateStatus& updateStatus) { |
| // Check if new metric |
| const auto& oldMetricProducerIt = oldMetricProducerMap.find(metricId); |
| if (oldMetricProducerIt == oldMetricProducerMap.end()) { |
| updateStatus = UPDATE_NEW; |
| return true; |
| } |
| |
| // This is an existing metric, check if it has changed. |
| uint64_t metricHash; |
| if (!getMetricProtoHash(config, metric, metricId, metricToActivationMap, metricHash)) { |
| return false; |
| } |
| const sp<MetricProducer> oldMetricProducer = oldMetricProducers[oldMetricProducerIt->second]; |
| if (oldMetricProducer->getMetricType() != metricType || |
| oldMetricProducer->getProtoHash() != metricHash) { |
| updateStatus = UPDATE_REPLACE; |
| return true; |
| } |
| |
| // Take intersections of the matchers/predicates/states that the metric |
| // depends on with those that have been replaced. If a metric depends on any |
| // replaced component, it too must be replaced. |
| set<int64_t> intersection; |
| set_intersection(matcherDependencies.begin(), matcherDependencies.end(), |
| replacedMatchers.begin(), replacedMatchers.end(), |
| inserter(intersection, intersection.begin())); |
| if (intersection.size() > 0) { |
| updateStatus = UPDATE_REPLACE; |
| return true; |
| } |
| set_intersection(conditionDependencies.begin(), conditionDependencies.end(), |
| replacedConditions.begin(), replacedConditions.end(), |
| inserter(intersection, intersection.begin())); |
| if (intersection.size() > 0) { |
| updateStatus = UPDATE_REPLACE; |
| return true; |
| } |
| set_intersection(stateDependencies.begin(), stateDependencies.end(), replacedStates.begin(), |
| replacedStates.end(), inserter(intersection, intersection.begin())); |
| if (intersection.size() > 0) { |
| updateStatus = UPDATE_REPLACE; |
| return true; |
| } |
| |
| for (const auto& metricConditionLink : conditionLinks) { |
| if (replacedConditions.find(metricConditionLink.condition()) != replacedConditions.end()) { |
| updateStatus = UPDATE_REPLACE; |
| return true; |
| } |
| } |
| |
| if (metricActivationDepsChange(config, metricToActivationMap, metricId, replacedMatchers)) { |
| updateStatus = UPDATE_REPLACE; |
| return true; |
| } |
| |
| updateStatus = UPDATE_PRESERVE; |
| return true; |
| } |
| |
| bool determineAllMetricUpdateStatuses(const StatsdConfig& config, |
| const unordered_map<int64_t, int>& oldMetricProducerMap, |
| const vector<sp<MetricProducer>>& oldMetricProducers, |
| const unordered_map<int64_t, int>& metricToActivationMap, |
| const set<int64_t>& replacedMatchers, |
| const set<int64_t>& replacedConditions, |
| const set<int64_t>& replacedStates, |
| vector<UpdateStatus>& metricsToUpdate) { |
| int metricIndex = 0; |
| for (int i = 0; i < config.count_metric_size(); i++, metricIndex++) { |
| const CountMetric& metric = config.count_metric(i); |
| set<int64_t> conditionDependencies; |
| if (metric.has_condition()) { |
| conditionDependencies.insert(metric.condition()); |
| } |
| if (!determineMetricUpdateStatus( |
| config, metric, metric.id(), METRIC_TYPE_COUNT, {metric.what()}, |
| conditionDependencies, metric.slice_by_state(), metric.links(), |
| oldMetricProducerMap, oldMetricProducers, metricToActivationMap, |
| replacedMatchers, replacedConditions, replacedStates, |
| metricsToUpdate[metricIndex])) { |
| return false; |
| } |
| } |
| for (int i = 0; i < config.duration_metric_size(); i++, metricIndex++) { |
| const DurationMetric& metric = config.duration_metric(i); |
| set<int64_t> conditionDependencies({metric.what()}); |
| if (metric.has_condition()) { |
| conditionDependencies.insert(metric.condition()); |
| } |
| if (!determineMetricUpdateStatus( |
| config, metric, metric.id(), METRIC_TYPE_DURATION, /*matcherDependencies=*/{}, |
| conditionDependencies, metric.slice_by_state(), metric.links(), |
| oldMetricProducerMap, oldMetricProducers, metricToActivationMap, |
| replacedMatchers, replacedConditions, replacedStates, |
| metricsToUpdate[metricIndex])) { |
| return false; |
| } |
| } |
| for (int i = 0; i < config.event_metric_size(); i++, metricIndex++) { |
| const EventMetric& metric = config.event_metric(i); |
| set<int64_t> conditionDependencies; |
| if (metric.has_condition()) { |
| conditionDependencies.insert(metric.condition()); |
| } |
| if (!determineMetricUpdateStatus( |
| config, metric, metric.id(), METRIC_TYPE_EVENT, {metric.what()}, |
| conditionDependencies, ::google::protobuf::RepeatedField<int64_t>(), |
| metric.links(), oldMetricProducerMap, oldMetricProducers, metricToActivationMap, |
| replacedMatchers, replacedConditions, replacedStates, |
| metricsToUpdate[metricIndex])) { |
| return false; |
| } |
| } |
| for (int i = 0; i < config.value_metric_size(); i++, metricIndex++) { |
| const ValueMetric& metric = config.value_metric(i); |
| set<int64_t> conditionDependencies; |
| if (metric.has_condition()) { |
| conditionDependencies.insert(metric.condition()); |
| } |
| if (!determineMetricUpdateStatus( |
| config, metric, metric.id(), METRIC_TYPE_VALUE, {metric.what()}, |
| conditionDependencies, metric.slice_by_state(), metric.links(), |
| oldMetricProducerMap, oldMetricProducers, metricToActivationMap, |
| replacedMatchers, replacedConditions, replacedStates, |
| metricsToUpdate[metricIndex])) { |
| return false; |
| } |
| } |
| for (int i = 0; i < config.gauge_metric_size(); i++, metricIndex++) { |
| const GaugeMetric& metric = config.gauge_metric(i); |
| set<int64_t> conditionDependencies; |
| if (metric.has_condition()) { |
| conditionDependencies.insert(metric.condition()); |
| } |
| set<int64_t> matcherDependencies({metric.what()}); |
| if (metric.has_trigger_event()) { |
| matcherDependencies.insert(metric.trigger_event()); |
| } |
| if (!determineMetricUpdateStatus( |
| config, metric, metric.id(), METRIC_TYPE_GAUGE, matcherDependencies, |
| conditionDependencies, ::google::protobuf::RepeatedField<int64_t>(), |
| metric.links(), oldMetricProducerMap, oldMetricProducers, metricToActivationMap, |
| replacedMatchers, replacedConditions, replacedStates, |
| metricsToUpdate[metricIndex])) { |
| return false; |
| } |
| } |
| |
| for (int i = 0; i < config.kll_metric_size(); i++, metricIndex++) { |
| const KllMetric& metric = config.kll_metric(i); |
| set<int64_t> conditionDependencies; |
| if (metric.has_condition()) { |
| conditionDependencies.insert(metric.condition()); |
| } |
| if (!determineMetricUpdateStatus( |
| config, metric, metric.id(), METRIC_TYPE_KLL, {metric.what()}, |
| conditionDependencies, metric.slice_by_state(), metric.links(), |
| oldMetricProducerMap, oldMetricProducers, metricToActivationMap, |
| replacedMatchers, replacedConditions, replacedStates, |
| metricsToUpdate[metricIndex])) { |
| return false; |
| } |
| } |
| |
| return true; |
| } |
| |
| // Called when a metric is preserved during a config update. Finds the metric in oldMetricProducers |
| // and calls onConfigUpdated to update all indices. |
| optional<sp<MetricProducer>> updateMetric( |
| const StatsdConfig& config, const int configIndex, const int metricIndex, |
| const int64_t metricId, const vector<sp<AtomMatchingTracker>>& allAtomMatchingTrackers, |
| const unordered_map<int64_t, int>& oldAtomMatchingTrackerMap, |
| const unordered_map<int64_t, int>& newAtomMatchingTrackerMap, |
| const sp<EventMatcherWizard>& matcherWizard, |
| const vector<sp<ConditionTracker>>& allConditionTrackers, |
| const unordered_map<int64_t, int>& conditionTrackerMap, const sp<ConditionWizard>& wizard, |
| const unordered_map<int64_t, int>& oldMetricProducerMap, |
| const vector<sp<MetricProducer>>& oldMetricProducers, |
| const unordered_map<int64_t, int>& metricToActivationMap, |
| unordered_map<int, vector<int>>& trackerToMetricMap, |
| unordered_map<int, vector<int>>& conditionToMetricMap, |
| unordered_map<int, vector<int>>& activationAtomTrackerToMetricMap, |
| unordered_map<int, vector<int>>& deactivationAtomTrackerToMetricMap, |
| vector<int>& metricsWithActivation) { |
| const auto& oldMetricProducerIt = oldMetricProducerMap.find(metricId); |
| if (oldMetricProducerIt == oldMetricProducerMap.end()) { |
| ALOGE("Could not find Metric %lld in the previous config, but expected it " |
| "to be there", |
| (long long)metricId); |
| return nullopt; |
| } |
| const int oldIndex = oldMetricProducerIt->second; |
| sp<MetricProducer> producer = oldMetricProducers[oldIndex]; |
| if (!producer->onConfigUpdated(config, configIndex, metricIndex, allAtomMatchingTrackers, |
| oldAtomMatchingTrackerMap, newAtomMatchingTrackerMap, |
| matcherWizard, allConditionTrackers, conditionTrackerMap, wizard, |
| metricToActivationMap, trackerToMetricMap, conditionToMetricMap, |
| activationAtomTrackerToMetricMap, |
| deactivationAtomTrackerToMetricMap, metricsWithActivation)) { |
| return nullopt; |
| } |
| return {producer}; |
| } |
| |
| bool updateMetrics(const ConfigKey& key, const StatsdConfig& config, const int64_t timeBaseNs, |
| const int64_t currentTimeNs, const sp<StatsPullerManager>& pullerManager, |
| const unordered_map<int64_t, int>& oldAtomMatchingTrackerMap, |
| const unordered_map<int64_t, int>& newAtomMatchingTrackerMap, |
| const set<int64_t>& replacedMatchers, |
| const vector<sp<AtomMatchingTracker>>& allAtomMatchingTrackers, |
| const unordered_map<int64_t, int>& conditionTrackerMap, |
| const set<int64_t>& replacedConditions, |
| vector<sp<ConditionTracker>>& allConditionTrackers, |
| const vector<ConditionState>& initialConditionCache, |
| const unordered_map<int64_t, int>& stateAtomIdMap, |
| const unordered_map<int64_t, unordered_map<int, int64_t>>& allStateGroupMaps, |
| const set<int64_t>& replacedStates, |
| const unordered_map<int64_t, int>& oldMetricProducerMap, |
| const vector<sp<MetricProducer>>& oldMetricProducers, |
| unordered_map<int64_t, int>& newMetricProducerMap, |
| vector<sp<MetricProducer>>& newMetricProducers, |
| unordered_map<int, vector<int>>& conditionToMetricMap, |
| unordered_map<int, vector<int>>& trackerToMetricMap, |
| set<int64_t>& noReportMetricIds, |
| unordered_map<int, vector<int>>& activationAtomTrackerToMetricMap, |
| unordered_map<int, vector<int>>& deactivationAtomTrackerToMetricMap, |
| vector<int>& metricsWithActivation, set<int64_t>& replacedMetrics) { |
| sp<ConditionWizard> wizard = new ConditionWizard(allConditionTrackers); |
| sp<EventMatcherWizard> matcherWizard = new EventMatcherWizard(allAtomMatchingTrackers); |
| const int allMetricsCount = config.count_metric_size() + config.duration_metric_size() + |
| config.event_metric_size() + config.gauge_metric_size() + |
| config.value_metric_size() + config.kll_metric_size(); |
| newMetricProducers.reserve(allMetricsCount); |
| |
| // Construct map from metric id to metric activation index. The map will be used to determine |
| // the metric activation corresponding to a metric. |
| unordered_map<int64_t, int> metricToActivationMap; |
| for (int i = 0; i < config.metric_activation_size(); i++) { |
| const MetricActivation& metricActivation = config.metric_activation(i); |
| int64_t metricId = metricActivation.metric_id(); |
| if (metricToActivationMap.find(metricId) != metricToActivationMap.end()) { |
| ALOGE("Metric %lld has multiple MetricActivations", (long long)metricId); |
| return false; |
| } |
| metricToActivationMap.insert({metricId, i}); |
| } |
| |
| vector<UpdateStatus> metricsToUpdate(allMetricsCount, UPDATE_UNKNOWN); |
| if (!determineAllMetricUpdateStatuses(config, oldMetricProducerMap, oldMetricProducers, |
| metricToActivationMap, replacedMatchers, |
| replacedConditions, replacedStates, metricsToUpdate)) { |
| return false; |
| } |
| |
| // Now, perform the update. Must iterate the metric types in the same order |
| int metricIndex = 0; |
| for (int i = 0; i < config.count_metric_size(); i++, metricIndex++) { |
| const CountMetric& metric = config.count_metric(i); |
| newMetricProducerMap[metric.id()] = metricIndex; |
| optional<sp<MetricProducer>> producer; |
| switch (metricsToUpdate[metricIndex]) { |
| case UPDATE_PRESERVE: { |
| producer = updateMetric( |
| config, i, metricIndex, metric.id(), allAtomMatchingTrackers, |
| oldAtomMatchingTrackerMap, newAtomMatchingTrackerMap, matcherWizard, |
| allConditionTrackers, conditionTrackerMap, wizard, oldMetricProducerMap, |
| oldMetricProducers, metricToActivationMap, trackerToMetricMap, |
| conditionToMetricMap, activationAtomTrackerToMetricMap, |
| deactivationAtomTrackerToMetricMap, metricsWithActivation); |
| break; |
| } |
| case UPDATE_REPLACE: |
| replacedMetrics.insert(metric.id()); |
| [[fallthrough]]; // Intentionally fallthrough to create the new metric producer. |
| case UPDATE_NEW: { |
| producer = createCountMetricProducerAndUpdateMetadata( |
| key, config, timeBaseNs, currentTimeNs, metric, metricIndex, |
| allAtomMatchingTrackers, newAtomMatchingTrackerMap, allConditionTrackers, |
| conditionTrackerMap, initialConditionCache, wizard, stateAtomIdMap, |
| allStateGroupMaps, metricToActivationMap, trackerToMetricMap, |
| conditionToMetricMap, activationAtomTrackerToMetricMap, |
| deactivationAtomTrackerToMetricMap, metricsWithActivation); |
| break; |
| } |
| default: { |
| ALOGE("Metric \"%lld\" update state is unknown. This should never happen", |
| (long long)metric.id()); |
| return false; |
| } |
| } |
| if (!producer) { |
| return false; |
| } |
| newMetricProducers.push_back(producer.value()); |
| } |
| for (int i = 0; i < config.duration_metric_size(); i++, metricIndex++) { |
| const DurationMetric& metric = config.duration_metric(i); |
| newMetricProducerMap[metric.id()] = metricIndex; |
| optional<sp<MetricProducer>> producer; |
| switch (metricsToUpdate[metricIndex]) { |
| case UPDATE_PRESERVE: { |
| producer = updateMetric( |
| config, i, metricIndex, metric.id(), allAtomMatchingTrackers, |
| oldAtomMatchingTrackerMap, newAtomMatchingTrackerMap, matcherWizard, |
| allConditionTrackers, conditionTrackerMap, wizard, oldMetricProducerMap, |
| oldMetricProducers, metricToActivationMap, trackerToMetricMap, |
| conditionToMetricMap, activationAtomTrackerToMetricMap, |
| deactivationAtomTrackerToMetricMap, metricsWithActivation); |
| break; |
| } |
| case UPDATE_REPLACE: |
| replacedMetrics.insert(metric.id()); |
| [[fallthrough]]; // Intentionally fallthrough to create the new metric producer. |
| case UPDATE_NEW: { |
| producer = createDurationMetricProducerAndUpdateMetadata( |
| key, config, timeBaseNs, currentTimeNs, metric, metricIndex, |
| allAtomMatchingTrackers, newAtomMatchingTrackerMap, allConditionTrackers, |
| conditionTrackerMap, initialConditionCache, wizard, stateAtomIdMap, |
| allStateGroupMaps, metricToActivationMap, trackerToMetricMap, |
| conditionToMetricMap, activationAtomTrackerToMetricMap, |
| deactivationAtomTrackerToMetricMap, metricsWithActivation); |
| break; |
| } |
| default: { |
| ALOGE("Metric \"%lld\" update state is unknown. This should never happen", |
| (long long)metric.id()); |
| return false; |
| } |
| } |
| if (!producer) { |
| return false; |
| } |
| newMetricProducers.push_back(producer.value()); |
| } |
| for (int i = 0; i < config.event_metric_size(); i++, metricIndex++) { |
| const EventMetric& metric = config.event_metric(i); |
| newMetricProducerMap[metric.id()] = metricIndex; |
| optional<sp<MetricProducer>> producer; |
| switch (metricsToUpdate[metricIndex]) { |
| case UPDATE_PRESERVE: { |
| producer = updateMetric( |
| config, i, metricIndex, metric.id(), allAtomMatchingTrackers, |
| oldAtomMatchingTrackerMap, newAtomMatchingTrackerMap, matcherWizard, |
| allConditionTrackers, conditionTrackerMap, wizard, oldMetricProducerMap, |
| oldMetricProducers, metricToActivationMap, trackerToMetricMap, |
| conditionToMetricMap, activationAtomTrackerToMetricMap, |
| deactivationAtomTrackerToMetricMap, metricsWithActivation); |
| break; |
| } |
| case UPDATE_REPLACE: |
| replacedMetrics.insert(metric.id()); |
| [[fallthrough]]; // Intentionally fallthrough to create the new metric producer. |
| case UPDATE_NEW: { |
| producer = createEventMetricProducerAndUpdateMetadata( |
| key, config, timeBaseNs, metric, metricIndex, allAtomMatchingTrackers, |
| newAtomMatchingTrackerMap, allConditionTrackers, conditionTrackerMap, |
| initialConditionCache, wizard, metricToActivationMap, trackerToMetricMap, |
| conditionToMetricMap, activationAtomTrackerToMetricMap, |
| deactivationAtomTrackerToMetricMap, metricsWithActivation); |
| break; |
| } |
| default: { |
| ALOGE("Metric \"%lld\" update state is unknown. This should never happen", |
| (long long)metric.id()); |
| return false; |
| } |
| } |
| if (!producer) { |
| return false; |
| } |
| newMetricProducers.push_back(producer.value()); |
| } |
| |
| for (int i = 0; i < config.value_metric_size(); i++, metricIndex++) { |
| const ValueMetric& metric = config.value_metric(i); |
| newMetricProducerMap[metric.id()] = metricIndex; |
| optional<sp<MetricProducer>> producer; |
| switch (metricsToUpdate[metricIndex]) { |
| case UPDATE_PRESERVE: { |
| producer = updateMetric( |
| config, i, metricIndex, metric.id(), allAtomMatchingTrackers, |
| oldAtomMatchingTrackerMap, newAtomMatchingTrackerMap, matcherWizard, |
| allConditionTrackers, conditionTrackerMap, wizard, oldMetricProducerMap, |
| oldMetricProducers, metricToActivationMap, trackerToMetricMap, |
| conditionToMetricMap, activationAtomTrackerToMetricMap, |
| deactivationAtomTrackerToMetricMap, metricsWithActivation); |
| break; |
| } |
| case UPDATE_REPLACE: |
| replacedMetrics.insert(metric.id()); |
| [[fallthrough]]; // Intentionally fallthrough to create the new metric producer. |
| case UPDATE_NEW: { |
| producer = createNumericValueMetricProducerAndUpdateMetadata( |
| key, config, timeBaseNs, currentTimeNs, pullerManager, metric, metricIndex, |
| allAtomMatchingTrackers, newAtomMatchingTrackerMap, allConditionTrackers, |
| conditionTrackerMap, initialConditionCache, wizard, matcherWizard, |
| stateAtomIdMap, allStateGroupMaps, metricToActivationMap, |
| trackerToMetricMap, conditionToMetricMap, activationAtomTrackerToMetricMap, |
| deactivationAtomTrackerToMetricMap, metricsWithActivation); |
| break; |
| } |
| default: { |
| ALOGE("Metric \"%lld\" update state is unknown. This should never happen", |
| (long long)metric.id()); |
| return false; |
| } |
| } |
| if (!producer) { |
| return false; |
| } |
| newMetricProducers.push_back(producer.value()); |
| } |
| |
| for (int i = 0; i < config.gauge_metric_size(); i++, metricIndex++) { |
| const GaugeMetric& metric = config.gauge_metric(i); |
| newMetricProducerMap[metric.id()] = metricIndex; |
| optional<sp<MetricProducer>> producer; |
| switch (metricsToUpdate[metricIndex]) { |
| case UPDATE_PRESERVE: { |
| producer = updateMetric( |
| config, i, metricIndex, metric.id(), allAtomMatchingTrackers, |
| oldAtomMatchingTrackerMap, newAtomMatchingTrackerMap, matcherWizard, |
| allConditionTrackers, conditionTrackerMap, wizard, oldMetricProducerMap, |
| oldMetricProducers, metricToActivationMap, trackerToMetricMap, |
| conditionToMetricMap, activationAtomTrackerToMetricMap, |
| deactivationAtomTrackerToMetricMap, metricsWithActivation); |
| break; |
| } |
| case UPDATE_REPLACE: |
| replacedMetrics.insert(metric.id()); |
| [[fallthrough]]; // Intentionally fallthrough to create the new metric producer. |
| case UPDATE_NEW: { |
| producer = createGaugeMetricProducerAndUpdateMetadata( |
| key, config, timeBaseNs, currentTimeNs, pullerManager, metric, metricIndex, |
| allAtomMatchingTrackers, newAtomMatchingTrackerMap, allConditionTrackers, |
| conditionTrackerMap, initialConditionCache, wizard, matcherWizard, |
| metricToActivationMap, trackerToMetricMap, conditionToMetricMap, |
| activationAtomTrackerToMetricMap, deactivationAtomTrackerToMetricMap, |
| metricsWithActivation); |
| break; |
| } |
| default: { |
| ALOGE("Metric \"%lld\" update state is unknown. This should never happen", |
| (long long)metric.id()); |
| return false; |
| } |
| } |
| if (!producer) { |
| return false; |
| } |
| newMetricProducers.push_back(producer.value()); |
| } |
| |
| for (int i = 0; i < config.kll_metric_size(); i++, metricIndex++) { |
| const KllMetric& metric = config.kll_metric(i); |
| newMetricProducerMap[metric.id()] = metricIndex; |
| optional<sp<MetricProducer>> producer; |
| switch (metricsToUpdate[metricIndex]) { |
| case UPDATE_PRESERVE: { |
| producer = updateMetric( |
| config, i, metricIndex, metric.id(), allAtomMatchingTrackers, |
| oldAtomMatchingTrackerMap, newAtomMatchingTrackerMap, matcherWizard, |
| allConditionTrackers, conditionTrackerMap, wizard, oldMetricProducerMap, |
| oldMetricProducers, metricToActivationMap, trackerToMetricMap, |
| conditionToMetricMap, activationAtomTrackerToMetricMap, |
| deactivationAtomTrackerToMetricMap, metricsWithActivation); |
| break; |
| } |
| case UPDATE_REPLACE: |
| replacedMetrics.insert(metric.id()); |
| [[fallthrough]]; // Intentionally fallthrough to create the new metric |
| // producer. |
| case UPDATE_NEW: { |
| producer = createKllMetricProducerAndUpdateMetadata( |
| key, config, timeBaseNs, currentTimeNs, pullerManager, metric, metricIndex, |
| allAtomMatchingTrackers, newAtomMatchingTrackerMap, allConditionTrackers, |
| conditionTrackerMap, initialConditionCache, wizard, matcherWizard, |
| stateAtomIdMap, allStateGroupMaps, metricToActivationMap, |
| trackerToMetricMap, conditionToMetricMap, activationAtomTrackerToMetricMap, |
| deactivationAtomTrackerToMetricMap, metricsWithActivation); |
| break; |
| } |
| default: { |
| ALOGE("Metric \"%lld\" update state is unknown. This should never happen", |
| (long long)metric.id()); |
| return false; |
| } |
| } |
| if (!producer) { |
| return false; |
| } |
| newMetricProducers.push_back(producer.value()); |
| } |
| |
| for (int i = 0; i < config.no_report_metric_size(); ++i) { |
| const int64_t noReportMetric = config.no_report_metric(i); |
| if (newMetricProducerMap.find(noReportMetric) == newMetricProducerMap.end()) { |
| ALOGW("no_report_metric %" PRId64 " not exist", noReportMetric); |
| return false; |
| } |
| noReportMetricIds.insert(noReportMetric); |
| } |
| const set<int> atomsAllowedFromAnyUid(config.whitelisted_atom_ids().begin(), |
| config.whitelisted_atom_ids().end()); |
| for (int i = 0; i < allMetricsCount; i++) { |
| sp<MetricProducer> producer = newMetricProducers[i]; |
| // Register metrics to StateTrackers |
| for (int atomId : producer->getSlicedStateAtoms()) { |
| // Register listener for atoms that use allowed_log_sources. |
| // Using atoms allowed from any uid as a sliced state atom is not allowed. |
| // Redo this check for all metrics in case the atoms allowed from any uid changed. |
| if (atomsAllowedFromAnyUid.find(atomId) != atomsAllowedFromAnyUid.end()) { |
| return false; |
| // Preserved metrics should've already registered.` |
| } else if (metricsToUpdate[i] != UPDATE_PRESERVE) { |
| StateManager::getInstance().registerListener(atomId, producer); |
| } |
| } |
| } |
| |
| // Init new/replaced metrics. |
| for (size_t i = 0; i < newMetricProducers.size(); i++) { |
| if (metricsToUpdate[i] == UPDATE_REPLACE || metricsToUpdate[i] == UPDATE_NEW) { |
| newMetricProducers[i]->prepareFirstBucket(); |
| } |
| } |
| return true; |
| } |
| |
| bool determineAlertUpdateStatus(const Alert& alert, |
| const unordered_map<int64_t, int>& oldAlertTrackerMap, |
| const vector<sp<AnomalyTracker>>& oldAnomalyTrackers, |
| const set<int64_t>& replacedMetrics, UpdateStatus& updateStatus) { |
| // Check if new alert. |
| const auto& oldAnomalyTrackerIt = oldAlertTrackerMap.find(alert.id()); |
| if (oldAnomalyTrackerIt == oldAlertTrackerMap.end()) { |
| updateStatus = UPDATE_NEW; |
| return true; |
| } |
| |
| // This is an existing alert, check if it has changed. |
| string serializedAlert; |
| if (!alert.SerializeToString(&serializedAlert)) { |
| ALOGW("Unable to serialize alert %lld", (long long)alert.id()); |
| return false; |
| } |
| uint64_t newProtoHash = Hash64(serializedAlert); |
| const auto [success, oldProtoHash] = |
| oldAnomalyTrackers[oldAnomalyTrackerIt->second]->getProtoHash(); |
| if (!success) { |
| return false; |
| } |
| if (newProtoHash != oldProtoHash) { |
| updateStatus = UPDATE_REPLACE; |
| return true; |
| } |
| |
| // Check if the metric this alert relies on has changed. |
| if (replacedMetrics.find(alert.metric_id()) != replacedMetrics.end()) { |
| updateStatus = UPDATE_REPLACE; |
| return true; |
| } |
| |
| updateStatus = UPDATE_PRESERVE; |
| return true; |
| } |
| |
| bool updateAlerts(const StatsdConfig& config, const int64_t currentTimeNs, |
| const unordered_map<int64_t, int>& metricProducerMap, |
| const set<int64_t>& replacedMetrics, |
| const unordered_map<int64_t, int>& oldAlertTrackerMap, |
| const vector<sp<AnomalyTracker>>& oldAnomalyTrackers, |
| const sp<AlarmMonitor>& anomalyAlarmMonitor, |
| vector<sp<MetricProducer>>& allMetricProducers, |
| unordered_map<int64_t, int>& newAlertTrackerMap, |
| vector<sp<AnomalyTracker>>& newAnomalyTrackers) { |
| int alertCount = config.alert_size(); |
| vector<UpdateStatus> alertUpdateStatuses(alertCount); |
| for (int i = 0; i < alertCount; i++) { |
| if (!determineAlertUpdateStatus(config.alert(i), oldAlertTrackerMap, oldAnomalyTrackers, |
| replacedMetrics, alertUpdateStatuses[i])) { |
| return false; |
| } |
| } |
| |
| for (int i = 0; i < alertCount; i++) { |
| const Alert& alert = config.alert(i); |
| newAlertTrackerMap[alert.id()] = newAnomalyTrackers.size(); |
| switch (alertUpdateStatuses[i]) { |
| case UPDATE_PRESERVE: { |
| // Find the alert and update it. |
| const auto& oldAnomalyTrackerIt = oldAlertTrackerMap.find(alert.id()); |
| if (oldAnomalyTrackerIt == oldAlertTrackerMap.end()) { |
| ALOGW("Could not find AnomalyTracker %lld in the previous config, but " |
| "expected it to be there", |
| (long long)alert.id()); |
| return false; |
| } |
| sp<AnomalyTracker> anomalyTracker = oldAnomalyTrackers[oldAnomalyTrackerIt->second]; |
| anomalyTracker->onConfigUpdated(); |
| // Add the alert to the relevant metric. |
| const auto& metricProducerIt = metricProducerMap.find(alert.metric_id()); |
| if (metricProducerIt == metricProducerMap.end()) { |
| ALOGW("alert \"%lld\" has unknown metric id: \"%lld\"", (long long)alert.id(), |
| (long long)alert.metric_id()); |
| return false; |
| } |
| allMetricProducers[metricProducerIt->second]->addAnomalyTracker(anomalyTracker, |
| currentTimeNs); |
| newAnomalyTrackers.push_back(anomalyTracker); |
| break; |
| } |
| case UPDATE_REPLACE: |
| case UPDATE_NEW: { |
| optional<sp<AnomalyTracker>> anomalyTracker = |
| createAnomalyTracker(alert, anomalyAlarmMonitor, alertUpdateStatuses[i], |
| currentTimeNs, metricProducerMap, allMetricProducers); |
| if (!anomalyTracker) { |
| return false; |
| } |
| newAnomalyTrackers.push_back(anomalyTracker.value()); |
| break; |
| } |
| default: { |
| ALOGE("Alert \"%lld\" update state is unknown. This should never happen", |
| (long long)alert.id()); |
| return false; |
| } |
| } |
| } |
| if (!initSubscribersForSubscriptionType(config, Subscription::ALERT, newAlertTrackerMap, |
| newAnomalyTrackers)) { |
| return false; |
| } |
| return true; |
| } |
| |
| bool updateStatsdConfig(const ConfigKey& key, const StatsdConfig& config, const sp<UidMap>& uidMap, |
| const sp<StatsPullerManager>& pullerManager, |
| const sp<AlarmMonitor>& anomalyAlarmMonitor, |
| const sp<AlarmMonitor>& periodicAlarmMonitor, const int64_t timeBaseNs, |
| const int64_t currentTimeNs, |
| const vector<sp<AtomMatchingTracker>>& oldAtomMatchingTrackers, |
| const unordered_map<int64_t, int>& oldAtomMatchingTrackerMap, |
| const vector<sp<ConditionTracker>>& oldConditionTrackers, |
| const unordered_map<int64_t, int>& oldConditionTrackerMap, |
| const vector<sp<MetricProducer>>& oldMetricProducers, |
| const unordered_map<int64_t, int>& oldMetricProducerMap, |
| const vector<sp<AnomalyTracker>>& oldAnomalyTrackers, |
| const unordered_map<int64_t, int>& oldAlertTrackerMap, |
| const map<int64_t, uint64_t>& oldStateProtoHashes, set<int>& allTagIds, |
| vector<sp<AtomMatchingTracker>>& newAtomMatchingTrackers, |
| unordered_map<int64_t, int>& newAtomMatchingTrackerMap, |
| vector<sp<ConditionTracker>>& newConditionTrackers, |
| unordered_map<int64_t, int>& newConditionTrackerMap, |
| vector<sp<MetricProducer>>& newMetricProducers, |
| unordered_map<int64_t, int>& newMetricProducerMap, |
| vector<sp<AnomalyTracker>>& newAnomalyTrackers, |
| unordered_map<int64_t, int>& newAlertTrackerMap, |
| vector<sp<AlarmTracker>>& newPeriodicAlarmTrackers, |
| unordered_map<int, vector<int>>& conditionToMetricMap, |
| unordered_map<int, vector<int>>& trackerToMetricMap, |
| unordered_map<int, vector<int>>& trackerToConditionMap, |
| unordered_map<int, vector<int>>& activationTrackerToMetricMap, |
| unordered_map<int, vector<int>>& deactivationTrackerToMetricMap, |
| vector<int>& metricsWithActivation, |
| map<int64_t, uint64_t>& newStateProtoHashes, |
| set<int64_t>& noReportMetricIds) { |
| set<int64_t> replacedMatchers; |
| set<int64_t> replacedConditions; |
| set<int64_t> replacedStates; |
| set<int64_t> replacedMetrics; |
| vector<ConditionState> conditionCache; |
| unordered_map<int64_t, int> stateAtomIdMap; |
| unordered_map<int64_t, unordered_map<int, int64_t>> allStateGroupMaps; |
| |
| if (!updateAtomMatchingTrackers(config, uidMap, oldAtomMatchingTrackerMap, |
| oldAtomMatchingTrackers, allTagIds, newAtomMatchingTrackerMap, |
| newAtomMatchingTrackers, replacedMatchers)) { |
| ALOGE("updateAtomMatchingTrackers failed"); |
| return false; |
| } |
| |
| if (!updateConditions(key, config, newAtomMatchingTrackerMap, replacedMatchers, |
| oldConditionTrackerMap, oldConditionTrackers, newConditionTrackerMap, |
| newConditionTrackers, trackerToConditionMap, conditionCache, |
| replacedConditions)) { |
| ALOGE("updateConditions failed"); |
| return false; |
| } |
| |
| if (!updateStates(config, oldStateProtoHashes, stateAtomIdMap, allStateGroupMaps, |
| newStateProtoHashes, replacedStates)) { |
| ALOGE("updateStates failed"); |
| return false; |
| } |
| if (!updateMetrics(key, config, timeBaseNs, currentTimeNs, pullerManager, |
| oldAtomMatchingTrackerMap, newAtomMatchingTrackerMap, replacedMatchers, |
| newAtomMatchingTrackers, newConditionTrackerMap, replacedConditions, |
| newConditionTrackers, conditionCache, stateAtomIdMap, allStateGroupMaps, |
| replacedStates, oldMetricProducerMap, oldMetricProducers, |
| newMetricProducerMap, newMetricProducers, conditionToMetricMap, |
| trackerToMetricMap, noReportMetricIds, activationTrackerToMetricMap, |
| deactivationTrackerToMetricMap, metricsWithActivation, replacedMetrics)) { |
| ALOGE("updateMetrics failed"); |
| return false; |
| } |
| |
| if (!updateAlerts(config, currentTimeNs, newMetricProducerMap, replacedMetrics, |
| oldAlertTrackerMap, oldAnomalyTrackers, anomalyAlarmMonitor, |
| newMetricProducers, newAlertTrackerMap, newAnomalyTrackers)) { |
| ALOGE("updateAlerts failed"); |
| return false; |
| } |
| |
| // Alarms do not have any state, so we can reuse the initialization logic. |
| if (!initAlarms(config, key, periodicAlarmMonitor, timeBaseNs, currentTimeNs, |
| newPeriodicAlarmTrackers)) { |
| ALOGE("initAlarms failed"); |
| return false; |
| } |
| return true; |
| } |
| |
| } // namespace statsd |
| } // namespace os |
| } // namespace android |