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 STATSD_DEBUG false // STOPSHIP if true
18 #include "Log.h"
19
20 #include "metrics_manager_util.h"
21
22 #include <inttypes.h>
23
24 #include "FieldValue.h"
25 #include "condition/CombinationConditionTracker.h"
26 #include "condition/SimpleConditionTracker.h"
27 #include "external/StatsPullerManager.h"
28 #include "guardrail/StatsdStats.h"
29 #include "hash.h"
30 #include "matchers/CombinationAtomMatchingTracker.h"
31 #include "matchers/EventMatcherWizard.h"
32 #include "matchers/SimpleAtomMatchingTracker.h"
33 #include "metrics/CountMetricProducer.h"
34 #include "metrics/DurationMetricProducer.h"
35 #include "metrics/EventMetricProducer.h"
36 #include "metrics/GaugeMetricProducer.h"
37 #include "metrics/KllMetricProducer.h"
38 #include "metrics/MetricProducer.h"
39 #include "metrics/NumericValueMetricProducer.h"
40 #include "metrics/RestrictedEventMetricProducer.h"
41 #include "state/StateManager.h"
42 #include "stats_util.h"
43
44 using google::protobuf::MessageLite;
45 using std::set;
46 using std::unordered_map;
47 using std::vector;
48
49 namespace android {
50 namespace os {
51 namespace statsd {
52
53 namespace {
54
hasLeafNode(const FieldMatcher & matcher)55 bool hasLeafNode(const FieldMatcher& matcher) {
56 if (!matcher.has_field()) {
57 return false;
58 }
59 for (int i = 0; i < matcher.child_size(); ++i) {
60 if (hasLeafNode(matcher.child(i))) {
61 return true;
62 }
63 }
64 return true;
65 }
66
67 // DFS for ensuring there is no
68 // 1. value matching in the FieldValueMatcher tree with Position::ALL.
69 // 2. string replacement in the FieldValueMatcher tree without a value matcher with Position::ANY.
70 // Using vector to keep track of visited FieldValueMatchers since we expect number of
71 // FieldValueMatchers to be low.
validateFvmPositionAllAndAny(const FieldValueMatcher & fvm,bool inPositionAll,bool inPositionAny,vector<FieldValueMatcher const * > & visited)72 optional<InvalidConfigReasonEnum> validateFvmPositionAllAndAny(
73 const FieldValueMatcher& fvm, bool inPositionAll, bool inPositionAny,
74 vector<FieldValueMatcher const*>& visited) {
75 visited.push_back(&fvm);
76 inPositionAll = inPositionAll || fvm.position() == Position::ALL;
77 inPositionAny = inPositionAny || fvm.position() == Position::ANY;
78 if (fvm.value_matcher_case() == FieldValueMatcher::kMatchesTuple) {
79 for (const FieldValueMatcher& childFvm : fvm.matches_tuple().field_value_matcher()) {
80 if (std::find(visited.cbegin(), visited.cend(), &childFvm) != visited.cend()) {
81 continue;
82 }
83 const optional<InvalidConfigReasonEnum> reasonEnum =
84 validateFvmPositionAllAndAny(childFvm, inPositionAll, inPositionAny, visited);
85 if (reasonEnum != nullopt) {
86 return reasonEnum;
87 }
88 }
89 return nullopt;
90 }
91 if (inPositionAll && fvm.value_matcher_case() != FieldValueMatcher::VALUE_MATCHER_NOT_SET) {
92 // value_matcher is set to something other than matches_tuple with Position::ALL
93 return INVALID_CONFIG_REASON_MATCHER_VALUE_MATCHER_WITH_POSITION_ALL;
94 }
95 if (inPositionAny && fvm.value_matcher_case() == FieldValueMatcher::VALUE_MATCHER_NOT_SET &&
96 fvm.has_replace_string()) {
97 // value_matcher is not set and there is a string replacement with Position::ANY
98 return INVALID_CONFIG_REASON_MATCHER_STRING_REPLACE_WITH_NO_VALUE_MATCHER_WITH_POSITION_ANY;
99 }
100 return nullopt;
101 }
102
validateSimpleAtomMatcher(int64_t matcherId,const SimpleAtomMatcher & simpleMatcher)103 optional<InvalidConfigReason> validateSimpleAtomMatcher(int64_t matcherId,
104 const SimpleAtomMatcher& simpleMatcher) {
105 for (const FieldValueMatcher& fvm : simpleMatcher.field_value_matcher()) {
106 if (fvm.value_matcher_case() == FieldValueMatcher::VALUE_MATCHER_NOT_SET &&
107 !fvm.has_replace_string()) {
108 return createInvalidConfigReasonWithMatcher(
109 INVALID_CONFIG_REASON_MATCHER_NO_VALUE_MATCHER_NOR_STRING_REPLACER, matcherId);
110 } else if (fvm.has_replace_string() &&
111 !(fvm.value_matcher_case() == FieldValueMatcher::VALUE_MATCHER_NOT_SET ||
112 fvm.value_matcher_case() == FieldValueMatcher::kEqString ||
113 fvm.value_matcher_case() == FieldValueMatcher::kEqAnyString ||
114 fvm.value_matcher_case() == FieldValueMatcher::kNeqAnyString ||
115 fvm.value_matcher_case() == FieldValueMatcher::kEqWildcardString ||
116 fvm.value_matcher_case() == FieldValueMatcher::kEqAnyWildcardString ||
117 fvm.value_matcher_case() == FieldValueMatcher::kNeqAnyWildcardString)) {
118 return createInvalidConfigReasonWithMatcher(
119 INVALID_CONFIG_REASON_MATCHER_INVALID_VALUE_MATCHER_WITH_STRING_REPLACE,
120 matcherId);
121 }
122 vector<FieldValueMatcher const*> visited;
123 const optional<InvalidConfigReasonEnum> reasonEnum = validateFvmPositionAllAndAny(
124 fvm, false /* inPositionAll */, false /* inPositionAny */, visited);
125 if (reasonEnum != nullopt) {
126 return createInvalidConfigReasonWithMatcher(*reasonEnum, matcherId);
127 }
128 }
129 return nullopt;
130 }
131
132 } // namespace
133
createAtomMatchingTracker(const AtomMatcher & logMatcher,const sp<UidMap> & uidMap,optional<InvalidConfigReason> & invalidConfigReason)134 sp<AtomMatchingTracker> createAtomMatchingTracker(
135 const AtomMatcher& logMatcher, const sp<UidMap>& uidMap,
136 optional<InvalidConfigReason>& invalidConfigReason) {
137 string serializedMatcher;
138 if (!logMatcher.SerializeToString(&serializedMatcher)) {
139 ALOGE("Unable to serialize matcher %lld", (long long)logMatcher.id());
140 invalidConfigReason = createInvalidConfigReasonWithMatcher(
141 INVALID_CONFIG_REASON_MATCHER_SERIALIZATION_FAILED, logMatcher.id());
142 return nullptr;
143 }
144 uint64_t protoHash = Hash64(serializedMatcher);
145 switch (logMatcher.contents_case()) {
146 case AtomMatcher::ContentsCase::kSimpleAtomMatcher: {
147 invalidConfigReason =
148 validateSimpleAtomMatcher(logMatcher.id(), logMatcher.simple_atom_matcher());
149 if (invalidConfigReason != nullopt) {
150 ALOGE("Matcher \"%lld\" malformed", (long long)logMatcher.id());
151 return nullptr;
152 }
153 sp<AtomMatchingTracker> simpleAtomMatcher = new SimpleAtomMatchingTracker(
154 logMatcher.id(), protoHash, logMatcher.simple_atom_matcher(), uidMap);
155 return simpleAtomMatcher;
156 }
157 case AtomMatcher::ContentsCase::kCombination:
158 return new CombinationAtomMatchingTracker(logMatcher.id(), protoHash);
159 default:
160 ALOGE("Matcher \"%lld\" malformed", (long long)logMatcher.id());
161 invalidConfigReason = createInvalidConfigReasonWithMatcher(
162 INVALID_CONFIG_REASON_MATCHER_MALFORMED_CONTENTS_CASE, logMatcher.id());
163 return nullptr;
164 }
165 }
166
createConditionTracker(const ConfigKey & key,const Predicate & predicate,const int index,const unordered_map<int64_t,int> & atomMatchingTrackerMap,optional<InvalidConfigReason> & invalidConfigReason)167 sp<ConditionTracker> createConditionTracker(
168 const ConfigKey& key, const Predicate& predicate, const int index,
169 const unordered_map<int64_t, int>& atomMatchingTrackerMap,
170 optional<InvalidConfigReason>& invalidConfigReason) {
171 string serializedPredicate;
172 if (!predicate.SerializeToString(&serializedPredicate)) {
173 ALOGE("Unable to serialize predicate %lld", (long long)predicate.id());
174 invalidConfigReason = createInvalidConfigReasonWithPredicate(
175 INVALID_CONFIG_REASON_CONDITION_SERIALIZATION_FAILED, predicate.id());
176 return nullptr;
177 }
178 uint64_t protoHash = Hash64(serializedPredicate);
179 switch (predicate.contents_case()) {
180 case Predicate::ContentsCase::kSimplePredicate: {
181 return new SimpleConditionTracker(key, predicate.id(), protoHash, index,
182 predicate.simple_predicate(), atomMatchingTrackerMap);
183 }
184 case Predicate::ContentsCase::kCombination: {
185 return new CombinationConditionTracker(predicate.id(), index, protoHash);
186 }
187 default:
188 ALOGE("Predicate \"%lld\" malformed", (long long)predicate.id());
189 invalidConfigReason = createInvalidConfigReasonWithPredicate(
190 INVALID_CONFIG_REASON_CONDITION_MALFORMED_CONTENTS_CASE, predicate.id());
191 return nullptr;
192 }
193 }
194
getMetricProtoHash(const StatsdConfig & config,const MessageLite & metric,const int64_t id,const unordered_map<int64_t,int> & metricToActivationMap,uint64_t & metricHash)195 optional<InvalidConfigReason> getMetricProtoHash(
196 const StatsdConfig& config, const MessageLite& metric, const int64_t id,
197 const unordered_map<int64_t, int>& metricToActivationMap, uint64_t& metricHash) {
198 string serializedMetric;
199 if (!metric.SerializeToString(&serializedMetric)) {
200 ALOGE("Unable to serialize metric %lld", (long long)id);
201 return InvalidConfigReason(INVALID_CONFIG_REASON_METRIC_SERIALIZATION_FAILED, id);
202 }
203 metricHash = Hash64(serializedMetric);
204
205 // Combine with activation hash, if applicable
206 const auto& metricActivationIt = metricToActivationMap.find(id);
207 if (metricActivationIt != metricToActivationMap.end()) {
208 string serializedActivation;
209 const MetricActivation& activation = config.metric_activation(metricActivationIt->second);
210 if (!activation.SerializeToString(&serializedActivation)) {
211 ALOGE("Unable to serialize metric activation for metric %lld", (long long)id);
212 return InvalidConfigReason(INVALID_CONFIG_REASON_METRIC_ACTIVATION_SERIALIZATION_FAILED,
213 id);
214 }
215 metricHash = Hash64(to_string(metricHash).append(to_string(Hash64(serializedActivation))));
216 }
217 return nullopt;
218 }
219
handleMetricWithAtomMatchingTrackers(const int64_t matcherId,const int64_t metricId,const int metricIndex,const bool enforceOneAtom,const vector<sp<AtomMatchingTracker>> & allAtomMatchingTrackers,const unordered_map<int64_t,int> & atomMatchingTrackerMap,unordered_map<int,vector<int>> & trackerToMetricMap,int & logTrackerIndex)220 optional<InvalidConfigReason> handleMetricWithAtomMatchingTrackers(
221 const int64_t matcherId, const int64_t metricId, const int metricIndex,
222 const bool enforceOneAtom, const vector<sp<AtomMatchingTracker>>& allAtomMatchingTrackers,
223 const unordered_map<int64_t, int>& atomMatchingTrackerMap,
224 unordered_map<int, vector<int>>& trackerToMetricMap, int& logTrackerIndex) {
225 auto logTrackerIt = atomMatchingTrackerMap.find(matcherId);
226 if (logTrackerIt == atomMatchingTrackerMap.end()) {
227 ALOGW("cannot find the AtomMatcher \"%lld\" in config", (long long)matcherId);
228 return createInvalidConfigReasonWithMatcher(INVALID_CONFIG_REASON_METRIC_MATCHER_NOT_FOUND,
229 metricId, matcherId);
230 }
231 if (enforceOneAtom && allAtomMatchingTrackers[logTrackerIt->second]->getAtomIds().size() > 1) {
232 ALOGE("AtomMatcher \"%lld\" has more than one tag ids. When a metric has dimension, "
233 "the \"what\" can only be about one atom type. trigger_event matchers can also only "
234 "be about one atom type.",
235 (long long)matcherId);
236 return createInvalidConfigReasonWithMatcher(
237 INVALID_CONFIG_REASON_METRIC_MATCHER_MORE_THAN_ONE_ATOM, metricId, matcherId);
238 }
239 logTrackerIndex = logTrackerIt->second;
240 auto& metric_list = trackerToMetricMap[logTrackerIndex];
241 metric_list.push_back(metricIndex);
242 return nullopt;
243 }
244
handleMetricWithConditions(const int64_t condition,const int64_t metricId,const int metricIndex,const unordered_map<int64_t,int> & conditionTrackerMap,const::google::protobuf::RepeatedPtrField<MetricConditionLink> & links,const vector<sp<ConditionTracker>> & allConditionTrackers,int & conditionIndex,unordered_map<int,vector<int>> & conditionToMetricMap)245 optional<InvalidConfigReason> handleMetricWithConditions(
246 const int64_t condition, const int64_t metricId, const int metricIndex,
247 const unordered_map<int64_t, int>& conditionTrackerMap,
248 const ::google::protobuf::RepeatedPtrField<MetricConditionLink>& links,
249 const vector<sp<ConditionTracker>>& allConditionTrackers, int& conditionIndex,
250 unordered_map<int, vector<int>>& conditionToMetricMap) {
251 auto condition_it = conditionTrackerMap.find(condition);
252 if (condition_it == conditionTrackerMap.end()) {
253 ALOGW("cannot find Predicate \"%lld\" in the config", (long long)condition);
254 return createInvalidConfigReasonWithPredicate(
255 INVALID_CONFIG_REASON_METRIC_CONDITION_NOT_FOUND, metricId, condition);
256 }
257 for (const auto& link : links) {
258 auto it = conditionTrackerMap.find(link.condition());
259 if (it == conditionTrackerMap.end()) {
260 ALOGW("cannot find Predicate \"%lld\" in the config", (long long)link.condition());
261 return createInvalidConfigReasonWithPredicate(
262 INVALID_CONFIG_REASON_METRIC_CONDITION_LINK_NOT_FOUND, metricId,
263 link.condition());
264 }
265 }
266 conditionIndex = condition_it->second;
267
268 // will create new vector if not exist before.
269 auto& metricList = conditionToMetricMap[condition_it->second];
270 metricList.push_back(metricIndex);
271 return nullopt;
272 }
273
274 // Initializes state data structures for a metric.
275 // input:
276 // [config]: the input config
277 // [stateIds]: the slice_by_state ids for this metric
278 // [stateAtomIdMap]: this map contains the mapping from all state ids to atom ids
279 // [allStateGroupMaps]: this map contains the mapping from state ids and state
280 // values to state group ids for all states
281 // output:
282 // [slicedStateAtoms]: a vector of atom ids of all the slice_by_states
283 // [stateGroupMap]: this map should contain the mapping from states ids and state
284 // values to state group ids for all states that this metric
285 // is interested in
handleMetricWithStates(const StatsdConfig & config,const int64_t metricId,const::google::protobuf::RepeatedField<int64_t> & stateIds,const unordered_map<int64_t,int> & stateAtomIdMap,const unordered_map<int64_t,unordered_map<int,int64_t>> & allStateGroupMaps,vector<int> & slicedStateAtoms,unordered_map<int,unordered_map<int,int64_t>> & stateGroupMap)286 optional<InvalidConfigReason> handleMetricWithStates(
287 const StatsdConfig& config, const int64_t metricId,
288 const ::google::protobuf::RepeatedField<int64_t>& stateIds,
289 const unordered_map<int64_t, int>& stateAtomIdMap,
290 const unordered_map<int64_t, unordered_map<int, int64_t>>& allStateGroupMaps,
291 vector<int>& slicedStateAtoms,
292 unordered_map<int, unordered_map<int, int64_t>>& stateGroupMap) {
293 for (const auto& stateId : stateIds) {
294 auto it = stateAtomIdMap.find(stateId);
295 if (it == stateAtomIdMap.end()) {
296 ALOGW("cannot find State %" PRId64 " in the config", stateId);
297 return createInvalidConfigReasonWithState(INVALID_CONFIG_REASON_METRIC_STATE_NOT_FOUND,
298 metricId, stateId);
299 }
300 int atomId = it->second;
301 slicedStateAtoms.push_back(atomId);
302
303 auto stateIt = allStateGroupMaps.find(stateId);
304 if (stateIt != allStateGroupMaps.end()) {
305 stateGroupMap[atomId] = stateIt->second;
306 }
307 }
308 return nullopt;
309 }
310
handleMetricWithStateLink(const int64_t metricId,const FieldMatcher & stateMatcher,const vector<Matcher> & dimensionsInWhat)311 optional<InvalidConfigReason> handleMetricWithStateLink(const int64_t metricId,
312 const FieldMatcher& stateMatcher,
313 const vector<Matcher>& dimensionsInWhat) {
314 vector<Matcher> stateMatchers;
315 translateFieldMatcher(stateMatcher, &stateMatchers);
316 if (!subsetDimensions(stateMatchers, dimensionsInWhat)) {
317 return InvalidConfigReason(INVALID_CONFIG_REASON_METRIC_STATELINKS_NOT_SUBSET_DIM_IN_WHAT,
318 metricId);
319 }
320 return nullopt;
321 }
322
handleMetricWithDimensionalSampling(const int64_t metricId,const DimensionalSamplingInfo & dimSamplingInfo,const vector<Matcher> & dimensionsInWhat,SamplingInfo & samplingInfo)323 optional<InvalidConfigReason> handleMetricWithDimensionalSampling(
324 const int64_t metricId, const DimensionalSamplingInfo& dimSamplingInfo,
325 const vector<Matcher>& dimensionsInWhat, SamplingInfo& samplingInfo) {
326 if (!dimSamplingInfo.has_sampled_what_field()) {
327 ALOGE("metric DimensionalSamplingInfo missing sampledWhatField");
328 return InvalidConfigReason(
329 INVALID_CONFIG_REASON_METRIC_DIMENSIONAL_SAMPLING_INFO_MISSING_SAMPLED_FIELD,
330 metricId);
331 }
332
333 if (dimSamplingInfo.shard_count() <= 1) {
334 ALOGE("metric shardCount must be > 1");
335 return InvalidConfigReason(
336 INVALID_CONFIG_REASON_METRIC_DIMENSIONAL_SAMPLING_INFO_INCORRECT_SHARD_COUNT,
337 metricId);
338 }
339 samplingInfo.shardCount = dimSamplingInfo.shard_count();
340
341 if (HasPositionALL(dimSamplingInfo.sampled_what_field()) ||
342 HasPositionANY(dimSamplingInfo.sampled_what_field())) {
343 ALOGE("metric has repeated field with position ALL or ANY as the sampled dimension");
344 return InvalidConfigReason(INVALID_CONFIG_REASON_METRIC_SAMPLED_FIELD_INCORRECT_SIZE,
345 metricId);
346 }
347
348 translateFieldMatcher(dimSamplingInfo.sampled_what_field(), &samplingInfo.sampledWhatFields);
349 if (samplingInfo.sampledWhatFields.size() != 1) {
350 ALOGE("metric has incorrect number of sampled dimension fields");
351 return InvalidConfigReason(INVALID_CONFIG_REASON_METRIC_SAMPLED_FIELD_INCORRECT_SIZE,
352 metricId);
353 }
354 if (!subsetDimensions(samplingInfo.sampledWhatFields, dimensionsInWhat)) {
355 return InvalidConfigReason(
356 INVALID_CONFIG_REASON_METRIC_SAMPLED_FIELDS_NOT_SUBSET_DIM_IN_WHAT, metricId);
357 }
358 return nullopt;
359 }
360
361 // Validates a metricActivation and populates state.
362 // EventActivationMap and EventDeactivationMap are supplied to a MetricProducer
363 // to provide the producer with state about its activators and deactivators.
364 // Returns false if there are errors.
handleMetricActivation(const StatsdConfig & config,const int64_t metricId,const int metricIndex,const unordered_map<int64_t,int> & metricToActivationMap,const unordered_map<int64_t,int> & atomMatchingTrackerMap,unordered_map<int,vector<int>> & activationAtomTrackerToMetricMap,unordered_map<int,vector<int>> & deactivationAtomTrackerToMetricMap,vector<int> & metricsWithActivation,unordered_map<int,shared_ptr<Activation>> & eventActivationMap,unordered_map<int,vector<shared_ptr<Activation>>> & eventDeactivationMap)365 optional<InvalidConfigReason> handleMetricActivation(
366 const StatsdConfig& config, const int64_t metricId, const int metricIndex,
367 const unordered_map<int64_t, int>& metricToActivationMap,
368 const unordered_map<int64_t, int>& atomMatchingTrackerMap,
369 unordered_map<int, vector<int>>& activationAtomTrackerToMetricMap,
370 unordered_map<int, vector<int>>& deactivationAtomTrackerToMetricMap,
371 vector<int>& metricsWithActivation,
372 unordered_map<int, shared_ptr<Activation>>& eventActivationMap,
373 unordered_map<int, vector<shared_ptr<Activation>>>& eventDeactivationMap) {
374 // Check if metric has an associated activation
375 auto itr = metricToActivationMap.find(metricId);
376 if (itr == metricToActivationMap.end()) {
377 return nullopt;
378 }
379
380 int activationIndex = itr->second;
381 const MetricActivation& metricActivation = config.metric_activation(activationIndex);
382
383 for (int i = 0; i < metricActivation.event_activation_size(); i++) {
384 const EventActivation& activation = metricActivation.event_activation(i);
385
386 auto itr = atomMatchingTrackerMap.find(activation.atom_matcher_id());
387 if (itr == atomMatchingTrackerMap.end()) {
388 ALOGE("Atom matcher not found for event activation.");
389 return createInvalidConfigReasonWithMatcher(
390 INVALID_CONFIG_REASON_METRIC_ACTIVATION_MATCHER_NOT_FOUND, metricId,
391 activation.atom_matcher_id());
392 }
393
394 ActivationType activationType = (activation.has_activation_type())
395 ? activation.activation_type()
396 : metricActivation.activation_type();
397 std::shared_ptr<Activation> activationWrapper =
398 std::make_shared<Activation>(activationType, activation.ttl_seconds() * NS_PER_SEC);
399
400 int atomMatcherIndex = itr->second;
401 activationAtomTrackerToMetricMap[atomMatcherIndex].push_back(metricIndex);
402 eventActivationMap.emplace(atomMatcherIndex, activationWrapper);
403
404 if (activation.has_deactivation_atom_matcher_id()) {
405 itr = atomMatchingTrackerMap.find(activation.deactivation_atom_matcher_id());
406 if (itr == atomMatchingTrackerMap.end()) {
407 ALOGE("Atom matcher not found for event deactivation.");
408 return createInvalidConfigReasonWithMatcher(
409 INVALID_CONFIG_REASON_METRIC_DEACTIVATION_MATCHER_NOT_FOUND, metricId,
410 activation.deactivation_atom_matcher_id());
411 }
412 int deactivationAtomMatcherIndex = itr->second;
413 deactivationAtomTrackerToMetricMap[deactivationAtomMatcherIndex].push_back(metricIndex);
414 eventDeactivationMap[deactivationAtomMatcherIndex].push_back(activationWrapper);
415 }
416 }
417
418 metricsWithActivation.push_back(metricIndex);
419 return nullopt;
420 }
421
422 // Validates a metricActivation and populates state.
423 // Fills the new event activation/deactivation maps, preserving the existing activations
424 // Returns false if there are errors.
handleMetricActivationOnConfigUpdate(const StatsdConfig & config,const int64_t metricId,const int metricIndex,const unordered_map<int64_t,int> & metricToActivationMap,const unordered_map<int64_t,int> & oldAtomMatchingTrackerMap,const unordered_map<int64_t,int> & newAtomMatchingTrackerMap,const unordered_map<int,shared_ptr<Activation>> & oldEventActivationMap,unordered_map<int,vector<int>> & activationAtomTrackerToMetricMap,unordered_map<int,vector<int>> & deactivationAtomTrackerToMetricMap,vector<int> & metricsWithActivation,unordered_map<int,shared_ptr<Activation>> & newEventActivationMap,unordered_map<int,vector<shared_ptr<Activation>>> & newEventDeactivationMap)425 optional<InvalidConfigReason> handleMetricActivationOnConfigUpdate(
426 const StatsdConfig& config, const int64_t metricId, const int metricIndex,
427 const unordered_map<int64_t, int>& metricToActivationMap,
428 const unordered_map<int64_t, int>& oldAtomMatchingTrackerMap,
429 const unordered_map<int64_t, int>& newAtomMatchingTrackerMap,
430 const unordered_map<int, shared_ptr<Activation>>& oldEventActivationMap,
431 unordered_map<int, vector<int>>& activationAtomTrackerToMetricMap,
432 unordered_map<int, vector<int>>& deactivationAtomTrackerToMetricMap,
433 vector<int>& metricsWithActivation,
434 unordered_map<int, shared_ptr<Activation>>& newEventActivationMap,
435 unordered_map<int, vector<shared_ptr<Activation>>>& newEventDeactivationMap) {
436 // Check if metric has an associated activation.
437 const auto& itr = metricToActivationMap.find(metricId);
438 if (itr == metricToActivationMap.end()) {
439 return nullopt;
440 }
441
442 int activationIndex = itr->second;
443 const MetricActivation& metricActivation = config.metric_activation(activationIndex);
444
445 for (int i = 0; i < metricActivation.event_activation_size(); i++) {
446 const int64_t activationMatcherId = metricActivation.event_activation(i).atom_matcher_id();
447
448 const auto& newActivationIt = newAtomMatchingTrackerMap.find(activationMatcherId);
449 if (newActivationIt == newAtomMatchingTrackerMap.end()) {
450 ALOGE("Atom matcher not found in new config for event activation.");
451 return createInvalidConfigReasonWithMatcher(
452 INVALID_CONFIG_REASON_METRIC_ACTIVATION_MATCHER_NOT_FOUND_NEW, metricId,
453 activationMatcherId);
454 }
455 int newActivationMatcherIndex = newActivationIt->second;
456
457 // Find the old activation struct and copy it over.
458 const auto& oldActivationIt = oldAtomMatchingTrackerMap.find(activationMatcherId);
459 if (oldActivationIt == oldAtomMatchingTrackerMap.end()) {
460 ALOGE("Atom matcher not found in existing config for event activation.");
461 return createInvalidConfigReasonWithMatcher(
462 INVALID_CONFIG_REASON_METRIC_ACTIVATION_MATCHER_NOT_FOUND_EXISTING, metricId,
463 activationMatcherId);
464 }
465 int oldActivationMatcherIndex = oldActivationIt->second;
466 const auto& oldEventActivationIt = oldEventActivationMap.find(oldActivationMatcherIndex);
467 if (oldEventActivationIt == oldEventActivationMap.end()) {
468 ALOGE("Could not find existing event activation to update");
469 return createInvalidConfigReasonWithMatcher(
470 INVALID_CONFIG_REASON_METRIC_ACTIVATION_NOT_FOUND_EXISTING, metricId,
471 activationMatcherId);
472 }
473 newEventActivationMap.emplace(newActivationMatcherIndex, oldEventActivationIt->second);
474 activationAtomTrackerToMetricMap[newActivationMatcherIndex].push_back(metricIndex);
475
476 if (metricActivation.event_activation(i).has_deactivation_atom_matcher_id()) {
477 const int64_t deactivationMatcherId =
478 metricActivation.event_activation(i).deactivation_atom_matcher_id();
479 const auto& newDeactivationIt = newAtomMatchingTrackerMap.find(deactivationMatcherId);
480 if (newDeactivationIt == newAtomMatchingTrackerMap.end()) {
481 ALOGE("Deactivation atom matcher not found in new config for event activation.");
482 return createInvalidConfigReasonWithMatcher(
483 INVALID_CONFIG_REASON_METRIC_DEACTIVATION_MATCHER_NOT_FOUND_NEW, metricId,
484 deactivationMatcherId);
485 }
486 int newDeactivationMatcherIndex = newDeactivationIt->second;
487 newEventDeactivationMap[newDeactivationMatcherIndex].push_back(
488 oldEventActivationIt->second);
489 deactivationAtomTrackerToMetricMap[newDeactivationMatcherIndex].push_back(metricIndex);
490 }
491 }
492
493 metricsWithActivation.push_back(metricIndex);
494 return nullopt;
495 }
496
createCountMetricProducerAndUpdateMetadata(const ConfigKey & key,const StatsdConfig & config,const int64_t timeBaseNs,const int64_t currentTimeNs,const CountMetric & metric,const int metricIndex,const vector<sp<AtomMatchingTracker>> & allAtomMatchingTrackers,const unordered_map<int64_t,int> & atomMatchingTrackerMap,vector<sp<ConditionTracker>> & allConditionTrackers,const unordered_map<int64_t,int> & conditionTrackerMap,const vector<ConditionState> & initialConditionCache,const sp<ConditionWizard> & wizard,const unordered_map<int64_t,int> & stateAtomIdMap,const unordered_map<int64_t,unordered_map<int,int64_t>> & allStateGroupMaps,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,optional<InvalidConfigReason> & invalidConfigReason,const wp<ConfigMetadataProvider> configMetadataProvider)497 optional<sp<MetricProducer>> createCountMetricProducerAndUpdateMetadata(
498 const ConfigKey& key, const StatsdConfig& config, const int64_t timeBaseNs,
499 const int64_t currentTimeNs, const CountMetric& metric, const int metricIndex,
500 const vector<sp<AtomMatchingTracker>>& allAtomMatchingTrackers,
501 const unordered_map<int64_t, int>& atomMatchingTrackerMap,
502 vector<sp<ConditionTracker>>& allConditionTrackers,
503 const unordered_map<int64_t, int>& conditionTrackerMap,
504 const vector<ConditionState>& initialConditionCache, const sp<ConditionWizard>& wizard,
505 const unordered_map<int64_t, int>& stateAtomIdMap,
506 const unordered_map<int64_t, unordered_map<int, int64_t>>& allStateGroupMaps,
507 const unordered_map<int64_t, int>& metricToActivationMap,
508 unordered_map<int, vector<int>>& trackerToMetricMap,
509 unordered_map<int, vector<int>>& conditionToMetricMap,
510 unordered_map<int, vector<int>>& activationAtomTrackerToMetricMap,
511 unordered_map<int, vector<int>>& deactivationAtomTrackerToMetricMap,
512 vector<int>& metricsWithActivation, optional<InvalidConfigReason>& invalidConfigReason,
513 const wp<ConfigMetadataProvider> configMetadataProvider) {
514 if (!metric.has_id() || !metric.has_what()) {
515 ALOGE("cannot find metric id or \"what\" in CountMetric \"%lld\"", (long long)metric.id());
516 invalidConfigReason =
517 InvalidConfigReason(INVALID_CONFIG_REASON_METRIC_MISSING_ID_OR_WHAT, metric.id());
518 return nullopt;
519 }
520 int trackerIndex;
521 invalidConfigReason = handleMetricWithAtomMatchingTrackers(
522 metric.what(), metric.id(), metricIndex, metric.has_dimensions_in_what(),
523 allAtomMatchingTrackers, atomMatchingTrackerMap, trackerToMetricMap, trackerIndex);
524 if (invalidConfigReason.has_value()) {
525 return nullopt;
526 }
527
528 int conditionIndex = -1;
529 if (metric.has_condition()) {
530 invalidConfigReason = handleMetricWithConditions(
531 metric.condition(), metric.id(), metricIndex, conditionTrackerMap, metric.links(),
532 allConditionTrackers, conditionIndex, conditionToMetricMap);
533 if (invalidConfigReason.has_value()) {
534 return nullopt;
535 }
536 } else {
537 if (metric.links_size() > 0) {
538 ALOGW("metrics has a MetricConditionLink but doesn't have a condition");
539 invalidConfigReason = InvalidConfigReason(
540 INVALID_CONFIG_REASON_METRIC_CONDITIONLINK_NO_CONDITION, metric.id());
541 return nullopt;
542 }
543 }
544
545 std::vector<int> slicedStateAtoms;
546 unordered_map<int, unordered_map<int, int64_t>> stateGroupMap;
547 if (metric.slice_by_state_size() > 0) {
548 invalidConfigReason =
549 handleMetricWithStates(config, metric.id(), metric.slice_by_state(), stateAtomIdMap,
550 allStateGroupMaps, slicedStateAtoms, stateGroupMap);
551 if (invalidConfigReason.has_value()) {
552 return nullopt;
553 }
554 } else {
555 if (metric.state_link_size() > 0) {
556 ALOGW("CountMetric has a MetricStateLink but doesn't have a slice_by_state");
557 invalidConfigReason = InvalidConfigReason(
558 INVALID_CONFIG_REASON_METRIC_STATELINK_NO_STATE, metric.id());
559 return nullopt;
560 }
561 }
562
563 // Check that all metric state links are a subset of dimensions_in_what fields.
564 std::vector<Matcher> dimensionsInWhat;
565 translateFieldMatcher(metric.dimensions_in_what(), &dimensionsInWhat);
566 for (const auto& stateLink : metric.state_link()) {
567 invalidConfigReason = handleMetricWithStateLink(metric.id(), stateLink.fields_in_what(),
568 dimensionsInWhat);
569 if (invalidConfigReason.has_value()) {
570 ALOGW("CountMetric's MetricStateLinks must be a subset of dimensions in what");
571 return nullopt;
572 }
573 }
574
575 unordered_map<int, shared_ptr<Activation>> eventActivationMap;
576 unordered_map<int, vector<shared_ptr<Activation>>> eventDeactivationMap;
577 invalidConfigReason = handleMetricActivation(
578 config, metric.id(), metricIndex, metricToActivationMap, atomMatchingTrackerMap,
579 activationAtomTrackerToMetricMap, deactivationAtomTrackerToMetricMap,
580 metricsWithActivation, eventActivationMap, eventDeactivationMap);
581 if (invalidConfigReason.has_value()) {
582 return nullopt;
583 }
584
585 uint64_t metricHash;
586 invalidConfigReason =
587 getMetricProtoHash(config, metric, metric.id(), metricToActivationMap, metricHash);
588 if (invalidConfigReason.has_value()) {
589 return nullopt;
590 }
591
592 if (metric.has_threshold() &&
593 (metric.threshold().value_comparison_case() == UploadThreshold::kLtFloat ||
594 metric.threshold().value_comparison_case() == UploadThreshold::kGtFloat)) {
595 ALOGW("Count metric incorrect upload threshold type or no type used");
596 invalidConfigReason =
597 InvalidConfigReason(INVALID_CONFIG_REASON_METRIC_BAD_THRESHOLD, metric.id());
598 return nullopt;
599 }
600
601 sp<MetricProducer> metricProducer = new CountMetricProducer(
602 key, metric, conditionIndex, initialConditionCache, wizard, metricHash, timeBaseNs,
603 currentTimeNs, configMetadataProvider, eventActivationMap, eventDeactivationMap,
604 slicedStateAtoms, stateGroupMap);
605
606 SamplingInfo samplingInfo;
607 if (metric.has_dimensional_sampling_info()) {
608 invalidConfigReason = handleMetricWithDimensionalSampling(
609 metric.id(), metric.dimensional_sampling_info(), dimensionsInWhat, samplingInfo);
610 if (invalidConfigReason.has_value()) {
611 return nullopt;
612 }
613 metricProducer->setSamplingInfo(samplingInfo);
614 }
615
616 return metricProducer;
617 }
618
createDurationMetricProducerAndUpdateMetadata(const ConfigKey & key,const StatsdConfig & config,const int64_t timeBaseNs,const int64_t currentTimeNs,const DurationMetric & metric,const int metricIndex,const vector<sp<AtomMatchingTracker>> & allAtomMatchingTrackers,const unordered_map<int64_t,int> & atomMatchingTrackerMap,vector<sp<ConditionTracker>> & allConditionTrackers,const unordered_map<int64_t,int> & conditionTrackerMap,const vector<ConditionState> & initialConditionCache,const sp<ConditionWizard> & wizard,const unordered_map<int64_t,int> & stateAtomIdMap,const unordered_map<int64_t,unordered_map<int,int64_t>> & allStateGroupMaps,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,optional<InvalidConfigReason> & invalidConfigReason,const wp<ConfigMetadataProvider> configMetadataProvider)619 optional<sp<MetricProducer>> createDurationMetricProducerAndUpdateMetadata(
620 const ConfigKey& key, const StatsdConfig& config, const int64_t timeBaseNs,
621 const int64_t currentTimeNs, const DurationMetric& metric, const int metricIndex,
622 const vector<sp<AtomMatchingTracker>>& allAtomMatchingTrackers,
623 const unordered_map<int64_t, int>& atomMatchingTrackerMap,
624 vector<sp<ConditionTracker>>& allConditionTrackers,
625 const unordered_map<int64_t, int>& conditionTrackerMap,
626 const vector<ConditionState>& initialConditionCache, const sp<ConditionWizard>& wizard,
627 const unordered_map<int64_t, int>& stateAtomIdMap,
628 const unordered_map<int64_t, unordered_map<int, int64_t>>& allStateGroupMaps,
629 const unordered_map<int64_t, int>& metricToActivationMap,
630 unordered_map<int, vector<int>>& trackerToMetricMap,
631 unordered_map<int, vector<int>>& conditionToMetricMap,
632 unordered_map<int, vector<int>>& activationAtomTrackerToMetricMap,
633 unordered_map<int, vector<int>>& deactivationAtomTrackerToMetricMap,
634 vector<int>& metricsWithActivation, optional<InvalidConfigReason>& invalidConfigReason,
635 const wp<ConfigMetadataProvider> configMetadataProvider) {
636 if (!metric.has_id() || !metric.has_what()) {
637 ALOGE("cannot find metric id or \"what\" in DurationMetric \"%lld\"",
638 (long long)metric.id());
639 invalidConfigReason =
640 InvalidConfigReason(INVALID_CONFIG_REASON_METRIC_MISSING_ID_OR_WHAT, metric.id());
641 return nullopt;
642 }
643 const auto& what_it = conditionTrackerMap.find(metric.what());
644 if (what_it == conditionTrackerMap.end()) {
645 ALOGE("DurationMetric's \"what\" is not present in the condition trackers");
646 invalidConfigReason = createInvalidConfigReasonWithPredicate(
647 INVALID_CONFIG_REASON_DURATION_METRIC_WHAT_NOT_FOUND, metric.id(), metric.what());
648 return nullopt;
649 }
650
651 const int whatIndex = what_it->second;
652 const Predicate& durationWhat = config.predicate(whatIndex);
653 if (durationWhat.contents_case() != Predicate::ContentsCase::kSimplePredicate) {
654 ALOGE("DurationMetric's \"what\" must be a simple condition");
655 invalidConfigReason = createInvalidConfigReasonWithPredicate(
656 INVALID_CONFIG_REASON_DURATION_METRIC_WHAT_NOT_SIMPLE, metric.id(), metric.what());
657 return nullopt;
658 }
659
660 const SimplePredicate& simplePredicate = durationWhat.simple_predicate();
661 bool nesting = simplePredicate.count_nesting();
662
663 int startIndex = -1, stopIndex = -1, stopAllIndex = -1;
664 if (!simplePredicate.has_start()) {
665 ALOGE("Duration metrics must specify a valid start event matcher");
666 invalidConfigReason = createInvalidConfigReasonWithPredicate(
667 INVALID_CONFIG_REASON_DURATION_METRIC_MISSING_START, metric.id(), metric.what());
668 return nullopt;
669 }
670 invalidConfigReason = handleMetricWithAtomMatchingTrackers(
671 simplePredicate.start(), metric.id(), metricIndex, metric.has_dimensions_in_what(),
672 allAtomMatchingTrackers, atomMatchingTrackerMap, trackerToMetricMap, startIndex);
673 if (invalidConfigReason.has_value()) {
674 return nullopt;
675 }
676
677 if (simplePredicate.has_stop()) {
678 invalidConfigReason = handleMetricWithAtomMatchingTrackers(
679 simplePredicate.stop(), metric.id(), metricIndex, metric.has_dimensions_in_what(),
680 allAtomMatchingTrackers, atomMatchingTrackerMap, trackerToMetricMap, stopIndex);
681 if (invalidConfigReason.has_value()) {
682 return nullopt;
683 }
684 }
685
686 if (simplePredicate.has_stop_all()) {
687 invalidConfigReason = handleMetricWithAtomMatchingTrackers(
688 simplePredicate.stop_all(), metric.id(), metricIndex,
689 metric.has_dimensions_in_what(), allAtomMatchingTrackers, atomMatchingTrackerMap,
690 trackerToMetricMap, stopAllIndex);
691 if (invalidConfigReason.has_value()) {
692 return nullopt;
693 }
694 }
695
696 const FieldMatcher& internalDimensions = simplePredicate.dimensions();
697
698 int conditionIndex = -1;
699 if (metric.has_condition()) {
700 invalidConfigReason = handleMetricWithConditions(
701 metric.condition(), metric.id(), metricIndex, conditionTrackerMap, metric.links(),
702 allConditionTrackers, conditionIndex, conditionToMetricMap);
703 if (invalidConfigReason.has_value()) {
704 return nullopt;
705 }
706 } else if (metric.links_size() > 0) {
707 ALOGW("metrics has a MetricConditionLink but doesn't have a condition");
708 invalidConfigReason = InvalidConfigReason(
709 INVALID_CONFIG_REASON_METRIC_CONDITIONLINK_NO_CONDITION, metric.id());
710 return nullopt;
711 }
712
713 std::vector<int> slicedStateAtoms;
714 unordered_map<int, unordered_map<int, int64_t>> stateGroupMap;
715 if (metric.slice_by_state_size() > 0) {
716 if (metric.aggregation_type() == DurationMetric::MAX_SPARSE) {
717 ALOGE("DurationMetric with aggregation type MAX_SPARSE cannot be sliced by state");
718 invalidConfigReason = InvalidConfigReason(
719 INVALID_CONFIG_REASON_DURATION_METRIC_MAX_SPARSE_HAS_SLICE_BY_STATE,
720 metric.id());
721 return nullopt;
722 }
723 invalidConfigReason =
724 handleMetricWithStates(config, metric.id(), metric.slice_by_state(), stateAtomIdMap,
725 allStateGroupMaps, slicedStateAtoms, stateGroupMap);
726 if (invalidConfigReason.has_value()) {
727 return nullopt;
728 }
729 } else if (metric.state_link_size() > 0) {
730 ALOGW("DurationMetric has a MetricStateLink but doesn't have a sliced state");
731 invalidConfigReason =
732 InvalidConfigReason(INVALID_CONFIG_REASON_METRIC_STATELINK_NO_STATE, metric.id());
733 return nullopt;
734 }
735
736 // Check that all metric state links are a subset of dimensions_in_what fields.
737 std::vector<Matcher> dimensionsInWhat;
738 translateFieldMatcher(metric.dimensions_in_what(), &dimensionsInWhat);
739 for (const auto& stateLink : metric.state_link()) {
740 invalidConfigReason = handleMetricWithStateLink(metric.id(), stateLink.fields_in_what(),
741 dimensionsInWhat);
742 if (invalidConfigReason.has_value()) {
743 ALOGW("DurationMetric's MetricStateLinks must be a subset of dimensions in what");
744 return nullopt;
745 }
746 }
747
748 unordered_map<int, shared_ptr<Activation>> eventActivationMap;
749 unordered_map<int, vector<shared_ptr<Activation>>> eventDeactivationMap;
750 invalidConfigReason = handleMetricActivation(
751 config, metric.id(), metricIndex, metricToActivationMap, atomMatchingTrackerMap,
752 activationAtomTrackerToMetricMap, deactivationAtomTrackerToMetricMap,
753 metricsWithActivation, eventActivationMap, eventDeactivationMap);
754 if (invalidConfigReason.has_value()) {
755 return nullopt;
756 }
757
758 uint64_t metricHash;
759 invalidConfigReason =
760 getMetricProtoHash(config, metric, metric.id(), metricToActivationMap, metricHash);
761 if (invalidConfigReason.has_value()) {
762 return nullopt;
763 }
764
765 if (metric.has_threshold()) {
766 switch (metric.threshold().value_comparison_case()) {
767 case UploadThreshold::kLtInt:
768 case UploadThreshold::kGtInt:
769 case UploadThreshold::kLteInt:
770 case UploadThreshold::kGteInt:
771 break;
772 default:
773 ALOGE("Duration metric incorrect upload threshold type or no type used");
774 invalidConfigReason = InvalidConfigReason(
775 INVALID_CONFIG_REASON_METRIC_BAD_THRESHOLD, metric.id());
776 return nullopt;
777 }
778 }
779
780 sp<MetricProducer> metricProducer = new DurationMetricProducer(
781 key, metric, conditionIndex, initialConditionCache, whatIndex, startIndex, stopIndex,
782 stopAllIndex, nesting, wizard, metricHash, internalDimensions, timeBaseNs,
783 currentTimeNs, configMetadataProvider, eventActivationMap, eventDeactivationMap,
784 slicedStateAtoms, stateGroupMap);
785 if (!metricProducer->isValid()) {
786 // TODO: Remove once invalidConfigReason is added to the DurationMetricProducer constructor
787 invalidConfigReason = InvalidConfigReason(
788 INVALID_CONFIG_REASON_DURATION_METRIC_PRODUCER_INVALID, metric.id());
789 return nullopt;
790 }
791
792 SamplingInfo samplingInfo;
793 if (metric.has_dimensional_sampling_info()) {
794 invalidConfigReason = handleMetricWithDimensionalSampling(
795 metric.id(), metric.dimensional_sampling_info(), dimensionsInWhat, samplingInfo);
796 if (invalidConfigReason.has_value()) {
797 return nullopt;
798 }
799 metricProducer->setSamplingInfo(samplingInfo);
800 }
801
802 return metricProducer;
803 }
804
createEventMetricProducerAndUpdateMetadata(const ConfigKey & key,const StatsdConfig & config,const int64_t timeBaseNs,const EventMetric & metric,const int metricIndex,const vector<sp<AtomMatchingTracker>> & allAtomMatchingTrackers,const unordered_map<int64_t,int> & atomMatchingTrackerMap,vector<sp<ConditionTracker>> & allConditionTrackers,const unordered_map<int64_t,int> & conditionTrackerMap,const vector<ConditionState> & initialConditionCache,const sp<ConditionWizard> & wizard,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,optional<InvalidConfigReason> & invalidConfigReason,const wp<ConfigMetadataProvider> configMetadataProvider)805 optional<sp<MetricProducer>> createEventMetricProducerAndUpdateMetadata(
806 const ConfigKey& key, const StatsdConfig& config, const int64_t timeBaseNs,
807 const EventMetric& metric, const int metricIndex,
808 const vector<sp<AtomMatchingTracker>>& allAtomMatchingTrackers,
809 const unordered_map<int64_t, int>& atomMatchingTrackerMap,
810 vector<sp<ConditionTracker>>& allConditionTrackers,
811 const unordered_map<int64_t, int>& conditionTrackerMap,
812 const vector<ConditionState>& initialConditionCache, const sp<ConditionWizard>& wizard,
813 const unordered_map<int64_t, int>& metricToActivationMap,
814 unordered_map<int, vector<int>>& trackerToMetricMap,
815 unordered_map<int, vector<int>>& conditionToMetricMap,
816 unordered_map<int, vector<int>>& activationAtomTrackerToMetricMap,
817 unordered_map<int, vector<int>>& deactivationAtomTrackerToMetricMap,
818 vector<int>& metricsWithActivation, optional<InvalidConfigReason>& invalidConfigReason,
819 const wp<ConfigMetadataProvider> configMetadataProvider) {
820 if (!metric.has_id() || !metric.has_what()) {
821 ALOGE("cannot find the metric name or what in config");
822 invalidConfigReason =
823 InvalidConfigReason(INVALID_CONFIG_REASON_METRIC_MISSING_ID_OR_WHAT, metric.id());
824 return nullopt;
825 }
826 int trackerIndex;
827 invalidConfigReason = handleMetricWithAtomMatchingTrackers(
828 metric.what(), metric.id(), metricIndex, false, allAtomMatchingTrackers,
829 atomMatchingTrackerMap, trackerToMetricMap, trackerIndex);
830 if (invalidConfigReason.has_value()) {
831 return nullopt;
832 }
833
834 int conditionIndex = -1;
835 if (metric.has_condition()) {
836 invalidConfigReason = handleMetricWithConditions(
837 metric.condition(), metric.id(), metricIndex, conditionTrackerMap, metric.links(),
838 allConditionTrackers, conditionIndex, conditionToMetricMap);
839 if (invalidConfigReason.has_value()) {
840 return nullopt;
841 }
842 } else {
843 if (metric.links_size() > 0) {
844 ALOGW("metrics has a MetricConditionLink but doesn't have a condition");
845 invalidConfigReason = InvalidConfigReason(
846 INVALID_CONFIG_REASON_METRIC_CONDITIONLINK_NO_CONDITION, metric.id());
847 return nullopt;
848 }
849 }
850
851 if (metric.sampling_percentage() < 1 || metric.sampling_percentage() > 100) {
852 invalidConfigReason = InvalidConfigReason(
853 INVALID_CONFIG_REASON_METRIC_INCORRECT_SAMPLING_PERCENTAGE, metric.id());
854 return nullopt;
855 }
856
857 unordered_map<int, shared_ptr<Activation>> eventActivationMap;
858 unordered_map<int, vector<shared_ptr<Activation>>> eventDeactivationMap;
859 invalidConfigReason = handleMetricActivation(
860 config, metric.id(), metricIndex, metricToActivationMap, atomMatchingTrackerMap,
861 activationAtomTrackerToMetricMap, deactivationAtomTrackerToMetricMap,
862 metricsWithActivation, eventActivationMap, eventDeactivationMap);
863 if (invalidConfigReason.has_value()) return nullptr;
864
865 uint64_t metricHash;
866 invalidConfigReason =
867 getMetricProtoHash(config, metric, metric.id(), metricToActivationMap, metricHash);
868 if (invalidConfigReason.has_value()) {
869 return nullopt;
870 }
871
872 if (config.has_restricted_metrics_delegate_package_name()) {
873 return {new RestrictedEventMetricProducer(
874 key, metric, conditionIndex, initialConditionCache, wizard, metricHash, timeBaseNs,
875 configMetadataProvider, eventActivationMap, eventDeactivationMap)};
876 }
877 return {new EventMetricProducer(key, metric, conditionIndex, initialConditionCache, wizard,
878 metricHash, timeBaseNs, configMetadataProvider,
879 eventActivationMap, eventDeactivationMap)};
880 }
881
createNumericValueMetricProducerAndUpdateMetadata(const ConfigKey & key,const StatsdConfig & config,const int64_t timeBaseNs,const int64_t currentTimeNs,const sp<StatsPullerManager> & pullerManager,const ValueMetric & metric,const int metricIndex,const vector<sp<AtomMatchingTracker>> & allAtomMatchingTrackers,const unordered_map<int64_t,int> & atomMatchingTrackerMap,vector<sp<ConditionTracker>> & allConditionTrackers,const unordered_map<int64_t,int> & conditionTrackerMap,const vector<ConditionState> & initialConditionCache,const sp<ConditionWizard> & wizard,const sp<EventMatcherWizard> & matcherWizard,const unordered_map<int64_t,int> & stateAtomIdMap,const unordered_map<int64_t,unordered_map<int,int64_t>> & allStateGroupMaps,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,optional<InvalidConfigReason> & invalidConfigReason,const wp<ConfigMetadataProvider> configMetadataProvider)882 optional<sp<MetricProducer>> createNumericValueMetricProducerAndUpdateMetadata(
883 const ConfigKey& key, const StatsdConfig& config, const int64_t timeBaseNs,
884 const int64_t currentTimeNs, const sp<StatsPullerManager>& pullerManager,
885 const ValueMetric& metric, const int metricIndex,
886 const vector<sp<AtomMatchingTracker>>& allAtomMatchingTrackers,
887 const unordered_map<int64_t, int>& atomMatchingTrackerMap,
888 vector<sp<ConditionTracker>>& allConditionTrackers,
889 const unordered_map<int64_t, int>& conditionTrackerMap,
890 const vector<ConditionState>& initialConditionCache, const sp<ConditionWizard>& wizard,
891 const sp<EventMatcherWizard>& matcherWizard,
892 const unordered_map<int64_t, int>& stateAtomIdMap,
893 const unordered_map<int64_t, unordered_map<int, int64_t>>& allStateGroupMaps,
894 const unordered_map<int64_t, int>& metricToActivationMap,
895 unordered_map<int, vector<int>>& trackerToMetricMap,
896 unordered_map<int, vector<int>>& conditionToMetricMap,
897 unordered_map<int, vector<int>>& activationAtomTrackerToMetricMap,
898 unordered_map<int, vector<int>>& deactivationAtomTrackerToMetricMap,
899 vector<int>& metricsWithActivation, optional<InvalidConfigReason>& invalidConfigReason,
900 const wp<ConfigMetadataProvider> configMetadataProvider) {
901 if (!metric.has_id() || !metric.has_what()) {
902 ALOGE("cannot find metric id or \"what\" in ValueMetric \"%lld\"", (long long)metric.id());
903 invalidConfigReason =
904 InvalidConfigReason(INVALID_CONFIG_REASON_METRIC_MISSING_ID_OR_WHAT, metric.id());
905 return nullopt;
906 }
907 if (!metric.has_value_field()) {
908 ALOGE("cannot find \"value_field\" in ValueMetric \"%lld\"", (long long)metric.id());
909 invalidConfigReason = InvalidConfigReason(
910 INVALID_CONFIG_REASON_VALUE_METRIC_MISSING_VALUE_FIELD, metric.id());
911 return nullopt;
912 }
913 if (HasPositionALL(metric.value_field())) {
914 ALOGE("value field with position ALL is not supported. ValueMetric \"%lld\"",
915 (long long)metric.id());
916 invalidConfigReason = InvalidConfigReason(
917 INVALID_CONFIG_REASON_VALUE_METRIC_VALUE_FIELD_HAS_POSITION_ALL, metric.id());
918 return nullopt;
919 }
920 std::vector<Matcher> fieldMatchers;
921 translateFieldMatcher(metric.value_field(), &fieldMatchers);
922 if (fieldMatchers.size() < 1) {
923 ALOGE("incorrect \"value_field\" in ValueMetric \"%lld\"", (long long)metric.id());
924 invalidConfigReason = InvalidConfigReason(
925 INVALID_CONFIG_REASON_VALUE_METRIC_HAS_INCORRECT_VALUE_FIELD, metric.id());
926 return nullopt;
927 }
928
929 std::vector<ValueMetric::AggregationType> aggregationTypes;
930 if (!metric.aggregation_types().empty()) {
931 if (metric.has_aggregation_type()) {
932 invalidConfigReason = InvalidConfigReason(
933 INVALID_CONFIG_REASON_VALUE_METRIC_DEFINES_SINGLE_AND_MULTIPLE_AGG_TYPES,
934 metric.id());
935 return nullopt;
936 }
937 if (metric.aggregation_types_size() != (int)fieldMatchers.size()) {
938 invalidConfigReason = InvalidConfigReason(
939 INVALID_CONFIG_REASON_VALUE_METRIC_AGG_TYPES_DNE_VALUE_FIELDS_SIZE,
940 metric.id());
941 return nullopt;
942 }
943 for (int i = 0; i < metric.aggregation_types_size(); i++) {
944 aggregationTypes.push_back(metric.aggregation_types(i));
945 }
946 } else { // aggregation_type() is set or default is used.
947 aggregationTypes.push_back(metric.aggregation_type());
948 }
949
950 int trackerIndex;
951 invalidConfigReason = handleMetricWithAtomMatchingTrackers(
952 metric.what(), metric.id(), metricIndex,
953 /*enforceOneAtom=*/true, allAtomMatchingTrackers, atomMatchingTrackerMap,
954 trackerToMetricMap, trackerIndex);
955 if (invalidConfigReason.has_value()) {
956 return nullopt;
957 }
958
959 const sp<AtomMatchingTracker>& atomMatcher = allAtomMatchingTrackers.at(trackerIndex);
960 int atomTagId = *(atomMatcher->getAtomIds().begin());
961 int pullTagId = pullerManager->PullerForMatcherExists(atomTagId) ? atomTagId : -1;
962
963 int conditionIndex = -1;
964 if (metric.has_condition()) {
965 invalidConfigReason = handleMetricWithConditions(
966 metric.condition(), metric.id(), metricIndex, conditionTrackerMap, metric.links(),
967 allConditionTrackers, conditionIndex, conditionToMetricMap);
968 if (invalidConfigReason.has_value()) {
969 return nullopt;
970 }
971 } else if (metric.links_size() > 0) {
972 ALOGE("metrics has a MetricConditionLink but doesn't have a condition");
973 invalidConfigReason = InvalidConfigReason(
974 INVALID_CONFIG_REASON_METRIC_CONDITIONLINK_NO_CONDITION, metric.id());
975 return nullopt;
976 }
977
978 std::vector<int> slicedStateAtoms;
979 unordered_map<int, unordered_map<int, int64_t>> stateGroupMap;
980 if (metric.slice_by_state_size() > 0) {
981 invalidConfigReason =
982 handleMetricWithStates(config, metric.id(), metric.slice_by_state(), stateAtomIdMap,
983 allStateGroupMaps, slicedStateAtoms, stateGroupMap);
984 if (invalidConfigReason.has_value()) {
985 return nullopt;
986 }
987 } else if (metric.state_link_size() > 0) {
988 ALOGE("ValueMetric has a MetricStateLink but doesn't have a sliced state");
989 invalidConfigReason =
990 InvalidConfigReason(INVALID_CONFIG_REASON_METRIC_STATELINK_NO_STATE, metric.id());
991 return nullopt;
992 }
993
994 // Check that all metric state links are a subset of dimensions_in_what fields.
995 std::vector<Matcher> dimensionsInWhat;
996 translateFieldMatcher(metric.dimensions_in_what(), &dimensionsInWhat);
997 for (const auto& stateLink : metric.state_link()) {
998 invalidConfigReason = handleMetricWithStateLink(metric.id(), stateLink.fields_in_what(),
999 dimensionsInWhat);
1000 if (invalidConfigReason.has_value()) {
1001 ALOGW("ValueMetric's MetricStateLinks must be a subset of the dimensions in what");
1002 return nullopt;
1003 }
1004 }
1005
1006 unordered_map<int, shared_ptr<Activation>> eventActivationMap;
1007 unordered_map<int, vector<shared_ptr<Activation>>> eventDeactivationMap;
1008 invalidConfigReason = handleMetricActivation(
1009 config, metric.id(), metricIndex, metricToActivationMap, atomMatchingTrackerMap,
1010 activationAtomTrackerToMetricMap, deactivationAtomTrackerToMetricMap,
1011 metricsWithActivation, eventActivationMap, eventDeactivationMap);
1012 if (invalidConfigReason.has_value()) {
1013 return nullopt;
1014 }
1015
1016 uint64_t metricHash;
1017 invalidConfigReason =
1018 getMetricProtoHash(config, metric, metric.id(), metricToActivationMap, metricHash);
1019 if (invalidConfigReason.has_value()) {
1020 return nullopt;
1021 }
1022
1023 const TimeUnit bucketSizeTimeUnit =
1024 metric.bucket() == TIME_UNIT_UNSPECIFIED ? ONE_HOUR : metric.bucket();
1025 const int64_t bucketSizeNs =
1026 MillisToNano(TimeUnitToBucketSizeInMillisGuardrailed(key.GetUid(), bucketSizeTimeUnit));
1027
1028 const bool containsAnyPositionInDimensionsInWhat = HasPositionANY(metric.dimensions_in_what());
1029 const bool shouldUseNestedDimensions = ShouldUseNestedDimensions(metric.dimensions_in_what());
1030
1031 const auto [dimensionSoftLimit, dimensionHardLimit] =
1032 StatsdStats::getAtomDimensionKeySizeLimits(
1033 pullTagId,
1034 StatsdStats::clampDimensionKeySizeLimit(metric.max_dimensions_per_bucket()));
1035
1036 // get the condition_correction_threshold_nanos value
1037 const optional<int64_t> conditionCorrectionThresholdNs =
1038 metric.has_condition_correction_threshold_nanos()
1039 ? optional<int64_t>(metric.condition_correction_threshold_nanos())
1040 : nullopt;
1041
1042 sp<MetricProducer> metricProducer = new NumericValueMetricProducer(
1043 key, metric, metricHash, {pullTagId, pullerManager},
1044 {timeBaseNs, currentTimeNs, bucketSizeNs, metric.min_bucket_size_nanos(),
1045 conditionCorrectionThresholdNs, getAppUpgradeBucketSplit(metric)},
1046 {containsAnyPositionInDimensionsInWhat, shouldUseNestedDimensions, trackerIndex,
1047 matcherWizard, metric.dimensions_in_what(), fieldMatchers, aggregationTypes},
1048 {conditionIndex, metric.links(), initialConditionCache, wizard},
1049 {metric.state_link(), slicedStateAtoms, stateGroupMap},
1050 {eventActivationMap, eventDeactivationMap}, {dimensionSoftLimit, dimensionHardLimit},
1051 configMetadataProvider);
1052
1053 SamplingInfo samplingInfo;
1054 if (metric.has_dimensional_sampling_info()) {
1055 invalidConfigReason = handleMetricWithDimensionalSampling(
1056 metric.id(), metric.dimensional_sampling_info(), dimensionsInWhat, samplingInfo);
1057 if (invalidConfigReason.has_value()) {
1058 return nullopt;
1059 }
1060 metricProducer->setSamplingInfo(samplingInfo);
1061 }
1062
1063 return metricProducer;
1064 }
1065
createKllMetricProducerAndUpdateMetadata(const ConfigKey & key,const StatsdConfig & config,const int64_t timeBaseNs,const int64_t currentTimeNs,const sp<StatsPullerManager> & pullerManager,const KllMetric & metric,const int metricIndex,const vector<sp<AtomMatchingTracker>> & allAtomMatchingTrackers,const unordered_map<int64_t,int> & atomMatchingTrackerMap,vector<sp<ConditionTracker>> & allConditionTrackers,const unordered_map<int64_t,int> & conditionTrackerMap,const vector<ConditionState> & initialConditionCache,const sp<ConditionWizard> & wizard,const sp<EventMatcherWizard> & matcherWizard,const unordered_map<int64_t,int> & stateAtomIdMap,const unordered_map<int64_t,unordered_map<int,int64_t>> & allStateGroupMaps,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,optional<InvalidConfigReason> & invalidConfigReason,const wp<ConfigMetadataProvider> configMetadataProvider)1066 optional<sp<MetricProducer>> createKllMetricProducerAndUpdateMetadata(
1067 const ConfigKey& key, const StatsdConfig& config, const int64_t timeBaseNs,
1068 const int64_t currentTimeNs, const sp<StatsPullerManager>& pullerManager,
1069 const KllMetric& metric, const int metricIndex,
1070 const vector<sp<AtomMatchingTracker>>& allAtomMatchingTrackers,
1071 const unordered_map<int64_t, int>& atomMatchingTrackerMap,
1072 vector<sp<ConditionTracker>>& allConditionTrackers,
1073 const unordered_map<int64_t, int>& conditionTrackerMap,
1074 const vector<ConditionState>& initialConditionCache, const sp<ConditionWizard>& wizard,
1075 const sp<EventMatcherWizard>& matcherWizard,
1076 const unordered_map<int64_t, int>& stateAtomIdMap,
1077 const unordered_map<int64_t, unordered_map<int, int64_t>>& allStateGroupMaps,
1078 const unordered_map<int64_t, int>& metricToActivationMap,
1079 unordered_map<int, vector<int>>& trackerToMetricMap,
1080 unordered_map<int, vector<int>>& conditionToMetricMap,
1081 unordered_map<int, vector<int>>& activationAtomTrackerToMetricMap,
1082 unordered_map<int, vector<int>>& deactivationAtomTrackerToMetricMap,
1083 vector<int>& metricsWithActivation, optional<InvalidConfigReason>& invalidConfigReason,
1084 const wp<ConfigMetadataProvider> configMetadataProvider) {
1085 if (!metric.has_id() || !metric.has_what()) {
1086 ALOGE("cannot find metric id or \"what\" in KllMetric \"%lld\"", (long long)metric.id());
1087 invalidConfigReason =
1088 InvalidConfigReason(INVALID_CONFIG_REASON_METRIC_MISSING_ID_OR_WHAT, metric.id());
1089 return nullopt;
1090 }
1091 if (!metric.has_kll_field()) {
1092 ALOGE("cannot find \"kll_field\" in KllMetric \"%lld\"", (long long)metric.id());
1093 invalidConfigReason = InvalidConfigReason(
1094 INVALID_CONFIG_REASON_KLL_METRIC_MISSING_KLL_FIELD, metric.id());
1095 return nullopt;
1096 }
1097 if (HasPositionALL(metric.kll_field())) {
1098 ALOGE("kll field with position ALL is not supported. KllMetric \"%lld\"",
1099 (long long)metric.id());
1100 invalidConfigReason = InvalidConfigReason(
1101 INVALID_CONFIG_REASON_KLL_METRIC_KLL_FIELD_HAS_POSITION_ALL, metric.id());
1102 return nullopt;
1103 }
1104 std::vector<Matcher> fieldMatchers;
1105 translateFieldMatcher(metric.kll_field(), &fieldMatchers);
1106 if (fieldMatchers.empty()) {
1107 ALOGE("incorrect \"kll_field\" in KllMetric \"%lld\"", (long long)metric.id());
1108 invalidConfigReason = InvalidConfigReason(
1109 INVALID_CONFIG_REASON_KLL_METRIC_HAS_INCORRECT_KLL_FIELD, metric.id());
1110 return nullopt;
1111 }
1112
1113 int trackerIndex;
1114 invalidConfigReason = handleMetricWithAtomMatchingTrackers(
1115 metric.what(), metric.id(), metricIndex,
1116 /*enforceOneAtom=*/true, allAtomMatchingTrackers, atomMatchingTrackerMap,
1117 trackerToMetricMap, trackerIndex);
1118 if (invalidConfigReason.has_value()) {
1119 return nullopt;
1120 }
1121
1122 int conditionIndex = -1;
1123 if (metric.has_condition()) {
1124 invalidConfigReason = handleMetricWithConditions(
1125 metric.condition(), metric.id(), metricIndex, conditionTrackerMap, metric.links(),
1126 allConditionTrackers, conditionIndex, conditionToMetricMap);
1127 if (invalidConfigReason.has_value()) {
1128 return nullopt;
1129 }
1130 } else if (metric.links_size() > 0) {
1131 ALOGE("metrics has a MetricConditionLink but doesn't have a condition");
1132 invalidConfigReason = InvalidConfigReason(
1133 INVALID_CONFIG_REASON_METRIC_CONDITIONLINK_NO_CONDITION, metric.id());
1134 return nullopt;
1135 }
1136
1137 std::vector<int> slicedStateAtoms;
1138 unordered_map<int, unordered_map<int, int64_t>> stateGroupMap;
1139 if (metric.slice_by_state_size() > 0) {
1140 invalidConfigReason =
1141 handleMetricWithStates(config, metric.id(), metric.slice_by_state(), stateAtomIdMap,
1142 allStateGroupMaps, slicedStateAtoms, stateGroupMap);
1143 if (invalidConfigReason.has_value()) {
1144 return nullopt;
1145 }
1146 } else if (metric.state_link_size() > 0) {
1147 ALOGE("KllMetric has a MetricStateLink but doesn't have a sliced state");
1148 invalidConfigReason =
1149 InvalidConfigReason(INVALID_CONFIG_REASON_METRIC_STATELINK_NO_STATE, metric.id());
1150 return nullopt;
1151 }
1152
1153 // Check that all metric state links are a subset of dimensions_in_what fields.
1154 std::vector<Matcher> dimensionsInWhat;
1155 translateFieldMatcher(metric.dimensions_in_what(), &dimensionsInWhat);
1156 for (const auto& stateLink : metric.state_link()) {
1157 invalidConfigReason = handleMetricWithStateLink(metric.id(), stateLink.fields_in_what(),
1158 dimensionsInWhat);
1159 if (invalidConfigReason.has_value()) {
1160 ALOGW("KllMetric's MetricStateLinks must be a subset of the dimensions in what");
1161 return nullopt;
1162 }
1163 }
1164
1165 unordered_map<int, shared_ptr<Activation>> eventActivationMap;
1166 unordered_map<int, vector<shared_ptr<Activation>>> eventDeactivationMap;
1167 invalidConfigReason = handleMetricActivation(
1168 config, metric.id(), metricIndex, metricToActivationMap, atomMatchingTrackerMap,
1169 activationAtomTrackerToMetricMap, deactivationAtomTrackerToMetricMap,
1170 metricsWithActivation, eventActivationMap, eventDeactivationMap);
1171 if (invalidConfigReason.has_value()) {
1172 return nullopt;
1173 }
1174
1175 uint64_t metricHash;
1176 invalidConfigReason =
1177 getMetricProtoHash(config, metric, metric.id(), metricToActivationMap, metricHash);
1178 if (invalidConfigReason.has_value()) {
1179 return nullopt;
1180 }
1181
1182 const TimeUnit bucketSizeTimeUnit =
1183 metric.bucket() == TIME_UNIT_UNSPECIFIED ? ONE_HOUR : metric.bucket();
1184 const int64_t bucketSizeNs =
1185 MillisToNano(TimeUnitToBucketSizeInMillisGuardrailed(key.GetUid(), bucketSizeTimeUnit));
1186
1187 const bool containsAnyPositionInDimensionsInWhat = HasPositionANY(metric.dimensions_in_what());
1188 const bool shouldUseNestedDimensions = ShouldUseNestedDimensions(metric.dimensions_in_what());
1189
1190 const sp<AtomMatchingTracker>& atomMatcher = allAtomMatchingTrackers.at(trackerIndex);
1191 const int atomTagId = *(atomMatcher->getAtomIds().begin());
1192 const auto [dimensionSoftLimit, dimensionHardLimit] =
1193 StatsdStats::getAtomDimensionKeySizeLimits(
1194 atomTagId,
1195 StatsdStats::clampDimensionKeySizeLimit(metric.max_dimensions_per_bucket()));
1196
1197 sp<MetricProducer> metricProducer = new KllMetricProducer(
1198 key, metric, metricHash, {/*pullTagId=*/-1, pullerManager},
1199 {timeBaseNs, currentTimeNs, bucketSizeNs, metric.min_bucket_size_nanos(),
1200 /*conditionCorrectionThresholdNs=*/nullopt, getAppUpgradeBucketSplit(metric)},
1201 {containsAnyPositionInDimensionsInWhat,
1202 shouldUseNestedDimensions,
1203 trackerIndex,
1204 matcherWizard,
1205 metric.dimensions_in_what(),
1206 fieldMatchers,
1207 {}},
1208 {conditionIndex, metric.links(), initialConditionCache, wizard},
1209 {metric.state_link(), slicedStateAtoms, stateGroupMap},
1210 {eventActivationMap, eventDeactivationMap}, {dimensionSoftLimit, dimensionHardLimit},
1211 configMetadataProvider);
1212
1213 SamplingInfo samplingInfo;
1214 if (metric.has_dimensional_sampling_info()) {
1215 invalidConfigReason = handleMetricWithDimensionalSampling(
1216 metric.id(), metric.dimensional_sampling_info(), dimensionsInWhat, samplingInfo);
1217 if (invalidConfigReason.has_value()) {
1218 return nullopt;
1219 }
1220 metricProducer->setSamplingInfo(samplingInfo);
1221 }
1222
1223 return metricProducer;
1224 }
1225
createGaugeMetricProducerAndUpdateMetadata(const ConfigKey & key,const StatsdConfig & config,const int64_t timeBaseNs,const int64_t currentTimeNs,const sp<StatsPullerManager> & pullerManager,const GaugeMetric & metric,const int metricIndex,const vector<sp<AtomMatchingTracker>> & allAtomMatchingTrackers,const unordered_map<int64_t,int> & atomMatchingTrackerMap,vector<sp<ConditionTracker>> & allConditionTrackers,const unordered_map<int64_t,int> & conditionTrackerMap,const vector<ConditionState> & initialConditionCache,const sp<ConditionWizard> & wizard,const sp<EventMatcherWizard> & matcherWizard,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,optional<InvalidConfigReason> & invalidConfigReason,const wp<ConfigMetadataProvider> configMetadataProvider)1226 optional<sp<MetricProducer>> createGaugeMetricProducerAndUpdateMetadata(
1227 const ConfigKey& key, const StatsdConfig& config, const int64_t timeBaseNs,
1228 const int64_t currentTimeNs, const sp<StatsPullerManager>& pullerManager,
1229 const GaugeMetric& metric, const int metricIndex,
1230 const vector<sp<AtomMatchingTracker>>& allAtomMatchingTrackers,
1231 const unordered_map<int64_t, int>& atomMatchingTrackerMap,
1232 vector<sp<ConditionTracker>>& allConditionTrackers,
1233 const unordered_map<int64_t, int>& conditionTrackerMap,
1234 const vector<ConditionState>& initialConditionCache, const sp<ConditionWizard>& wizard,
1235 const sp<EventMatcherWizard>& matcherWizard,
1236 const unordered_map<int64_t, int>& metricToActivationMap,
1237 unordered_map<int, vector<int>>& trackerToMetricMap,
1238 unordered_map<int, vector<int>>& conditionToMetricMap,
1239 unordered_map<int, vector<int>>& activationAtomTrackerToMetricMap,
1240 unordered_map<int, vector<int>>& deactivationAtomTrackerToMetricMap,
1241 vector<int>& metricsWithActivation, optional<InvalidConfigReason>& invalidConfigReason,
1242 const wp<ConfigMetadataProvider> configMetadataProvider) {
1243 if (!metric.has_id() || !metric.has_what()) {
1244 ALOGE("cannot find metric id or \"what\" in GaugeMetric \"%lld\"", (long long)metric.id());
1245 invalidConfigReason =
1246 InvalidConfigReason(INVALID_CONFIG_REASON_METRIC_MISSING_ID_OR_WHAT, metric.id());
1247 return nullopt;
1248 }
1249
1250 if ((!metric.gauge_fields_filter().has_include_all() ||
1251 (metric.gauge_fields_filter().include_all() == false)) &&
1252 !hasLeafNode(metric.gauge_fields_filter().fields())) {
1253 ALOGW("Incorrect field filter setting in GaugeMetric %lld", (long long)metric.id());
1254 invalidConfigReason = InvalidConfigReason(
1255 INVALID_CONFIG_REASON_GAUGE_METRIC_INCORRECT_FIELD_FILTER, metric.id());
1256 return nullopt;
1257 }
1258 if ((metric.gauge_fields_filter().has_include_all() &&
1259 metric.gauge_fields_filter().include_all() == true) &&
1260 hasLeafNode(metric.gauge_fields_filter().fields())) {
1261 ALOGW("Incorrect field filter setting in GaugeMetric %lld", (long long)metric.id());
1262 invalidConfigReason = InvalidConfigReason(
1263 INVALID_CONFIG_REASON_GAUGE_METRIC_INCORRECT_FIELD_FILTER, metric.id());
1264 return nullopt;
1265 }
1266
1267 int trackerIndex;
1268 invalidConfigReason = handleMetricWithAtomMatchingTrackers(
1269 metric.what(), metric.id(), metricIndex, true, allAtomMatchingTrackers,
1270 atomMatchingTrackerMap, trackerToMetricMap, trackerIndex);
1271 if (invalidConfigReason.has_value()) {
1272 return nullopt;
1273 }
1274
1275 const sp<AtomMatchingTracker>& atomMatcher = allAtomMatchingTrackers.at(trackerIndex);
1276 int atomTagId = *(atomMatcher->getAtomIds().begin());
1277 int pullTagId = pullerManager->PullerForMatcherExists(atomTagId) ? atomTagId : -1;
1278
1279 int triggerTrackerIndex;
1280 int triggerAtomId = -1;
1281 if (metric.has_trigger_event()) {
1282 if (pullTagId == -1) {
1283 ALOGW("Pull atom not specified for trigger");
1284 invalidConfigReason = InvalidConfigReason(
1285 INVALID_CONFIG_REASON_GAUGE_METRIC_TRIGGER_NO_PULL_ATOM, metric.id());
1286 return nullopt;
1287 }
1288 // trigger_event should be used with FIRST_N_SAMPLES
1289 if (metric.sampling_type() != GaugeMetric::FIRST_N_SAMPLES) {
1290 ALOGW("Gauge Metric with trigger event must have sampling type FIRST_N_SAMPLES");
1291 invalidConfigReason = InvalidConfigReason(
1292 INVALID_CONFIG_REASON_GAUGE_METRIC_TRIGGER_NO_FIRST_N_SAMPLES, metric.id());
1293 return nullopt;
1294 }
1295 invalidConfigReason = handleMetricWithAtomMatchingTrackers(
1296 metric.trigger_event(), metric.id(), metricIndex,
1297 /*enforceOneAtom=*/true, allAtomMatchingTrackers, atomMatchingTrackerMap,
1298 trackerToMetricMap, triggerTrackerIndex);
1299 if (invalidConfigReason.has_value()) {
1300 return nullopt;
1301 }
1302 const sp<AtomMatchingTracker>& triggerAtomMatcher =
1303 allAtomMatchingTrackers.at(triggerTrackerIndex);
1304 triggerAtomId = *(triggerAtomMatcher->getAtomIds().begin());
1305 }
1306
1307 int conditionIndex = -1;
1308 if (metric.has_condition()) {
1309 invalidConfigReason = handleMetricWithConditions(
1310 metric.condition(), metric.id(), metricIndex, conditionTrackerMap, metric.links(),
1311 allConditionTrackers, conditionIndex, conditionToMetricMap);
1312 if (invalidConfigReason.has_value()) {
1313 return nullopt;
1314 }
1315 } else {
1316 if (metric.links_size() > 0) {
1317 ALOGW("metrics has a MetricConditionLink but doesn't have a condition");
1318 invalidConfigReason = InvalidConfigReason(
1319 INVALID_CONFIG_REASON_METRIC_CONDITIONLINK_NO_CONDITION, metric.id());
1320 return nullopt;
1321 }
1322 }
1323
1324 if (pullTagId != -1 && metric.sampling_percentage() != 100) {
1325 invalidConfigReason = InvalidConfigReason(
1326 INVALID_CONFIG_REASON_GAUGE_METRIC_PULLED_WITH_SAMPLING, metric.id());
1327 return nullopt;
1328 }
1329
1330 if (metric.sampling_percentage() < 1 || metric.sampling_percentage() > 100) {
1331 invalidConfigReason = InvalidConfigReason(
1332 INVALID_CONFIG_REASON_METRIC_INCORRECT_SAMPLING_PERCENTAGE, metric.id());
1333 return nullopt;
1334 }
1335
1336 if (metric.pull_probability() < 1 || metric.pull_probability() > 100) {
1337 invalidConfigReason = InvalidConfigReason(
1338 INVALID_CONFIG_REASON_METRIC_INCORRECT_PULL_PROBABILITY, metric.id());
1339 return nullopt;
1340 }
1341
1342 if (metric.pull_probability() != 100) {
1343 if (pullTagId == -1) {
1344 invalidConfigReason = InvalidConfigReason(
1345 INVALID_CONFIG_REASON_GAUGE_METRIC_PUSHED_WITH_PULL_PROBABILITY, metric.id());
1346 return nullopt;
1347 }
1348 if (metric.sampling_type() == GaugeMetric::RANDOM_ONE_SAMPLE) {
1349 invalidConfigReason = InvalidConfigReason(
1350 INVALID_CONFIG_REASON_GAUGE_METRIC_RANDOM_ONE_SAMPLE_WITH_PULL_PROBABILITY,
1351 metric.id());
1352 return nullopt;
1353 }
1354 }
1355
1356 unordered_map<int, shared_ptr<Activation>> eventActivationMap;
1357 unordered_map<int, vector<shared_ptr<Activation>>> eventDeactivationMap;
1358 invalidConfigReason = handleMetricActivation(
1359 config, metric.id(), metricIndex, metricToActivationMap, atomMatchingTrackerMap,
1360 activationAtomTrackerToMetricMap, deactivationAtomTrackerToMetricMap,
1361 metricsWithActivation, eventActivationMap, eventDeactivationMap);
1362 if (invalidConfigReason.has_value()) {
1363 return nullopt;
1364 }
1365
1366 uint64_t metricHash;
1367 invalidConfigReason =
1368 getMetricProtoHash(config, metric, metric.id(), metricToActivationMap, metricHash);
1369 if (invalidConfigReason.has_value()) {
1370 return nullopt;
1371 }
1372
1373 const auto [dimensionSoftLimit, dimensionHardLimit] =
1374 StatsdStats::getAtomDimensionKeySizeLimits(
1375 pullTagId,
1376 StatsdStats::clampDimensionKeySizeLimit(metric.max_dimensions_per_bucket()));
1377
1378 sp<MetricProducer> metricProducer = new GaugeMetricProducer(
1379 key, metric, conditionIndex, initialConditionCache, wizard, metricHash, trackerIndex,
1380 matcherWizard, pullTagId, triggerAtomId, atomTagId, timeBaseNs, currentTimeNs,
1381 pullerManager, configMetadataProvider, eventActivationMap, eventDeactivationMap,
1382 dimensionSoftLimit, dimensionHardLimit);
1383
1384 SamplingInfo samplingInfo;
1385 std::vector<Matcher> dimensionsInWhat;
1386 translateFieldMatcher(metric.dimensions_in_what(), &dimensionsInWhat);
1387 if (metric.has_dimensional_sampling_info()) {
1388 invalidConfigReason = handleMetricWithDimensionalSampling(
1389 metric.id(), metric.dimensional_sampling_info(), dimensionsInWhat, samplingInfo);
1390 if (invalidConfigReason.has_value()) {
1391 return nullopt;
1392 }
1393 metricProducer->setSamplingInfo(samplingInfo);
1394 }
1395
1396 return metricProducer;
1397 }
1398
createAnomalyTracker(const Alert & alert,const sp<AlarmMonitor> & anomalyAlarmMonitor,const UpdateStatus & updateStatus,const int64_t currentTimeNs,const unordered_map<int64_t,int> & metricProducerMap,vector<sp<MetricProducer>> & allMetricProducers,optional<InvalidConfigReason> & invalidConfigReason)1399 optional<sp<AnomalyTracker>> createAnomalyTracker(
1400 const Alert& alert, const sp<AlarmMonitor>& anomalyAlarmMonitor,
1401 const UpdateStatus& updateStatus, const int64_t currentTimeNs,
1402 const unordered_map<int64_t, int>& metricProducerMap,
1403 vector<sp<MetricProducer>>& allMetricProducers,
1404 optional<InvalidConfigReason>& invalidConfigReason) {
1405 const auto& itr = metricProducerMap.find(alert.metric_id());
1406 if (itr == metricProducerMap.end()) {
1407 ALOGW("alert \"%lld\" has unknown metric id: \"%lld\"", (long long)alert.id(),
1408 (long long)alert.metric_id());
1409 invalidConfigReason = createInvalidConfigReasonWithAlert(
1410 INVALID_CONFIG_REASON_ALERT_METRIC_NOT_FOUND, alert.metric_id(), alert.id());
1411 return nullopt;
1412 }
1413 if (!alert.has_trigger_if_sum_gt()) {
1414 ALOGW("invalid alert: missing threshold");
1415 invalidConfigReason = createInvalidConfigReasonWithAlert(
1416 INVALID_CONFIG_REASON_ALERT_THRESHOLD_MISSING, alert.id());
1417 return nullopt;
1418 }
1419 if (alert.trigger_if_sum_gt() < 0 || alert.num_buckets() <= 0) {
1420 ALOGW("invalid alert: threshold=%f num_buckets= %d", alert.trigger_if_sum_gt(),
1421 alert.num_buckets());
1422 invalidConfigReason = createInvalidConfigReasonWithAlert(
1423 INVALID_CONFIG_REASON_ALERT_INVALID_TRIGGER_OR_NUM_BUCKETS, alert.id());
1424 return nullopt;
1425 }
1426 const int metricIndex = itr->second;
1427 sp<MetricProducer> metric = allMetricProducers[metricIndex];
1428 sp<AnomalyTracker> anomalyTracker =
1429 metric->addAnomalyTracker(alert, anomalyAlarmMonitor, updateStatus, currentTimeNs);
1430 if (anomalyTracker == nullptr) {
1431 // The ALOGW for this invalid alert was already displayed in addAnomalyTracker().
1432 invalidConfigReason = createInvalidConfigReasonWithAlert(
1433 INVALID_CONFIG_REASON_ALERT_CANNOT_ADD_ANOMALY, alert.metric_id(), alert.id());
1434 return nullopt;
1435 }
1436 return {anomalyTracker};
1437 }
1438
initAtomMatchingTrackers(const StatsdConfig & config,const sp<UidMap> & uidMap,unordered_map<int64_t,int> & atomMatchingTrackerMap,vector<sp<AtomMatchingTracker>> & allAtomMatchingTrackers,unordered_map<int,vector<int>> & allTagIdsToMatchersMap)1439 optional<InvalidConfigReason> initAtomMatchingTrackers(
1440 const StatsdConfig& config, const sp<UidMap>& uidMap,
1441 unordered_map<int64_t, int>& atomMatchingTrackerMap,
1442 vector<sp<AtomMatchingTracker>>& allAtomMatchingTrackers,
1443 unordered_map<int, vector<int>>& allTagIdsToMatchersMap) {
1444 vector<AtomMatcher> matcherConfigs;
1445 const int atomMatcherCount = config.atom_matcher_size();
1446 matcherConfigs.reserve(atomMatcherCount);
1447 allAtomMatchingTrackers.reserve(atomMatcherCount);
1448 optional<InvalidConfigReason> invalidConfigReason;
1449
1450 for (int i = 0; i < atomMatcherCount; i++) {
1451 const AtomMatcher& logMatcher = config.atom_matcher(i);
1452 sp<AtomMatchingTracker> tracker =
1453 createAtomMatchingTracker(logMatcher, uidMap, invalidConfigReason);
1454 if (tracker == nullptr) {
1455 return invalidConfigReason;
1456 }
1457 allAtomMatchingTrackers.push_back(tracker);
1458 if (atomMatchingTrackerMap.find(logMatcher.id()) != atomMatchingTrackerMap.end()) {
1459 ALOGE("Duplicate AtomMatcher found!");
1460 return createInvalidConfigReasonWithMatcher(INVALID_CONFIG_REASON_MATCHER_DUPLICATE,
1461 logMatcher.id());
1462 }
1463 atomMatchingTrackerMap[logMatcher.id()] = i;
1464 matcherConfigs.push_back(logMatcher);
1465 }
1466
1467 vector<uint8_t> stackTracker2(allAtomMatchingTrackers.size(), false);
1468 for (size_t matcherIndex = 0; matcherIndex < allAtomMatchingTrackers.size(); matcherIndex++) {
1469 auto& matcher = allAtomMatchingTrackers[matcherIndex];
1470 const auto [invalidConfigReason, _] =
1471 matcher->init(matcherIndex, matcherConfigs, allAtomMatchingTrackers,
1472 atomMatchingTrackerMap, stackTracker2);
1473 if (invalidConfigReason.has_value()) {
1474 return invalidConfigReason;
1475 }
1476
1477 // Collect all the tag ids that are interesting. TagIds exist in leaf nodes only.
1478 const set<int>& tagIds = matcher->getAtomIds();
1479 for (int atomId : tagIds) {
1480 auto& matchers = allTagIdsToMatchersMap[atomId];
1481 // Performance note:
1482 // For small amount of elements linear search in vector will be
1483 // faster then look up in a set:
1484 // - we do not expect matchers vector per atom id will have significant size (< 10)
1485 // - iteration via vector is the fastest way compared to other containers (set, etc.)
1486 // in the hot path MetricsManager::onLogEvent()
1487 // - vector<T> will have the smallest memory footprint compared to any other
1488 // std containers implementation
1489 if (find(matchers.begin(), matchers.end(), matcherIndex) == matchers.end()) {
1490 matchers.push_back(matcherIndex);
1491 }
1492 }
1493 }
1494
1495 return nullopt;
1496 }
1497
initConditions(const ConfigKey & key,const StatsdConfig & config,const unordered_map<int64_t,int> & atomMatchingTrackerMap,unordered_map<int64_t,int> & conditionTrackerMap,vector<sp<ConditionTracker>> & allConditionTrackers,unordered_map<int,std::vector<int>> & trackerToConditionMap,vector<ConditionState> & initialConditionCache)1498 optional<InvalidConfigReason> initConditions(
1499 const ConfigKey& key, const StatsdConfig& config,
1500 const unordered_map<int64_t, int>& atomMatchingTrackerMap,
1501 unordered_map<int64_t, int>& conditionTrackerMap,
1502 vector<sp<ConditionTracker>>& allConditionTrackers,
1503 unordered_map<int, std::vector<int>>& trackerToConditionMap,
1504 vector<ConditionState>& initialConditionCache) {
1505 vector<Predicate> conditionConfigs;
1506 const int conditionTrackerCount = config.predicate_size();
1507 conditionConfigs.reserve(conditionTrackerCount);
1508 allConditionTrackers.reserve(conditionTrackerCount);
1509 initialConditionCache.assign(conditionTrackerCount, ConditionState::kNotEvaluated);
1510 optional<InvalidConfigReason> invalidConfigReason;
1511
1512 for (int i = 0; i < conditionTrackerCount; i++) {
1513 const Predicate& condition = config.predicate(i);
1514 sp<ConditionTracker> tracker = createConditionTracker(
1515 key, condition, i, atomMatchingTrackerMap, invalidConfigReason);
1516 if (tracker == nullptr) {
1517 return invalidConfigReason;
1518 }
1519 allConditionTrackers.push_back(tracker);
1520 if (conditionTrackerMap.find(condition.id()) != conditionTrackerMap.end()) {
1521 ALOGE("Duplicate Predicate found!");
1522 return createInvalidConfigReasonWithPredicate(INVALID_CONFIG_REASON_CONDITION_DUPLICATE,
1523 condition.id());
1524 }
1525 conditionTrackerMap[condition.id()] = i;
1526 conditionConfigs.push_back(condition);
1527 }
1528
1529 vector<uint8_t> stackTracker(allConditionTrackers.size(), false);
1530 for (size_t i = 0; i < allConditionTrackers.size(); i++) {
1531 auto& conditionTracker = allConditionTrackers[i];
1532 invalidConfigReason =
1533 conditionTracker->init(conditionConfigs, allConditionTrackers, conditionTrackerMap,
1534 stackTracker, initialConditionCache);
1535 if (invalidConfigReason.has_value()) {
1536 return invalidConfigReason;
1537 }
1538 for (const int trackerIndex : conditionTracker->getAtomMatchingTrackerIndex()) {
1539 auto& conditionList = trackerToConditionMap[trackerIndex];
1540 conditionList.push_back(i);
1541 }
1542 }
1543 return nullopt;
1544 }
1545
initStates(const StatsdConfig & config,unordered_map<int64_t,int> & stateAtomIdMap,unordered_map<int64_t,unordered_map<int,int64_t>> & allStateGroupMaps,map<int64_t,uint64_t> & stateProtoHashes)1546 optional<InvalidConfigReason> initStates(
1547 const StatsdConfig& config, unordered_map<int64_t, int>& stateAtomIdMap,
1548 unordered_map<int64_t, unordered_map<int, int64_t>>& allStateGroupMaps,
1549 map<int64_t, uint64_t>& stateProtoHashes) {
1550 for (int i = 0; i < config.state_size(); i++) {
1551 const State& state = config.state(i);
1552 const int64_t stateId = state.id();
1553 stateAtomIdMap[stateId] = state.atom_id();
1554
1555 string serializedState;
1556 if (!state.SerializeToString(&serializedState)) {
1557 ALOGE("Unable to serialize state %lld", (long long)stateId);
1558 return createInvalidConfigReasonWithState(
1559 INVALID_CONFIG_REASON_STATE_SERIALIZATION_FAILED, state.id(), state.atom_id());
1560 }
1561 stateProtoHashes[stateId] = Hash64(serializedState);
1562
1563 const StateMap& stateMap = state.map();
1564 for (const auto& group : stateMap.group()) {
1565 for (const auto& value : group.value()) {
1566 allStateGroupMaps[stateId][value] = group.group_id();
1567 }
1568 }
1569 }
1570
1571 return nullopt;
1572 }
1573
initMetrics(const ConfigKey & key,const StatsdConfig & config,const int64_t timeBaseTimeNs,const int64_t currentTimeNs,const sp<StatsPullerManager> & pullerManager,const unordered_map<int64_t,int> & atomMatchingTrackerMap,const unordered_map<int64_t,int> & conditionTrackerMap,const vector<sp<AtomMatchingTracker>> & allAtomMatchingTrackers,const unordered_map<int64_t,int> & stateAtomIdMap,const unordered_map<int64_t,unordered_map<int,int64_t>> & allStateGroupMaps,vector<sp<ConditionTracker>> & allConditionTrackers,const vector<ConditionState> & initialConditionCache,vector<sp<MetricProducer>> & allMetricProducers,unordered_map<int,vector<int>> & conditionToMetricMap,unordered_map<int,vector<int>> & trackerToMetricMap,unordered_map<int64_t,int> & metricMap,std::set<int64_t> & noReportMetricIds,unordered_map<int,vector<int>> & activationAtomTrackerToMetricMap,unordered_map<int,vector<int>> & deactivationAtomTrackerToMetricMap,vector<int> & metricsWithActivation,const wp<ConfigMetadataProvider> configMetadataProvider)1574 optional<InvalidConfigReason> initMetrics(
1575 const ConfigKey& key, const StatsdConfig& config, const int64_t timeBaseTimeNs,
1576 const int64_t currentTimeNs, const sp<StatsPullerManager>& pullerManager,
1577 const unordered_map<int64_t, int>& atomMatchingTrackerMap,
1578 const unordered_map<int64_t, int>& conditionTrackerMap,
1579 const vector<sp<AtomMatchingTracker>>& allAtomMatchingTrackers,
1580 const unordered_map<int64_t, int>& stateAtomIdMap,
1581 const unordered_map<int64_t, unordered_map<int, int64_t>>& allStateGroupMaps,
1582 vector<sp<ConditionTracker>>& allConditionTrackers,
1583 const vector<ConditionState>& initialConditionCache,
1584 vector<sp<MetricProducer>>& allMetricProducers,
1585 unordered_map<int, vector<int>>& conditionToMetricMap,
1586 unordered_map<int, vector<int>>& trackerToMetricMap, unordered_map<int64_t, int>& metricMap,
1587 std::set<int64_t>& noReportMetricIds,
1588 unordered_map<int, vector<int>>& activationAtomTrackerToMetricMap,
1589 unordered_map<int, vector<int>>& deactivationAtomTrackerToMetricMap,
1590 vector<int>& metricsWithActivation,
1591 const wp<ConfigMetadataProvider> configMetadataProvider) {
1592 sp<ConditionWizard> wizard = new ConditionWizard(allConditionTrackers);
1593 sp<EventMatcherWizard> matcherWizard = new EventMatcherWizard(allAtomMatchingTrackers);
1594 const int allMetricsCount = config.count_metric_size() + config.duration_metric_size() +
1595 config.event_metric_size() + config.gauge_metric_size() +
1596 config.value_metric_size() + config.kll_metric_size();
1597 allMetricProducers.reserve(allMetricsCount);
1598 optional<InvalidConfigReason> invalidConfigReason;
1599
1600 if (config.has_restricted_metrics_delegate_package_name() &&
1601 allMetricsCount != config.event_metric_size()) {
1602 ALOGE("Restricted metrics only support event metric");
1603 return InvalidConfigReason(INVALID_CONFIG_REASON_RESTRICTED_METRIC_NOT_SUPPORTED);
1604 }
1605
1606 // Construct map from metric id to metric activation index. The map will be used to determine
1607 // the metric activation corresponding to a metric.
1608 unordered_map<int64_t, int> metricToActivationMap;
1609 for (int i = 0; i < config.metric_activation_size(); i++) {
1610 const MetricActivation& metricActivation = config.metric_activation(i);
1611 int64_t metricId = metricActivation.metric_id();
1612 if (metricToActivationMap.find(metricId) != metricToActivationMap.end()) {
1613 ALOGE("Metric %lld has multiple MetricActivations", (long long)metricId);
1614 return InvalidConfigReason(INVALID_CONFIG_REASON_METRIC_HAS_MULTIPLE_ACTIVATIONS,
1615 metricId);
1616 }
1617 metricToActivationMap.insert({metricId, i});
1618 }
1619
1620 // Build MetricProducers for each metric defined in config.
1621 // build CountMetricProducer
1622 for (int i = 0; i < config.count_metric_size(); i++) {
1623 int metricIndex = allMetricProducers.size();
1624 const CountMetric& metric = config.count_metric(i);
1625 metricMap.insert({metric.id(), metricIndex});
1626 optional<sp<MetricProducer>> producer = createCountMetricProducerAndUpdateMetadata(
1627 key, config, timeBaseTimeNs, currentTimeNs, metric, metricIndex,
1628 allAtomMatchingTrackers, atomMatchingTrackerMap, allConditionTrackers,
1629 conditionTrackerMap, initialConditionCache, wizard, stateAtomIdMap,
1630 allStateGroupMaps, metricToActivationMap, trackerToMetricMap, conditionToMetricMap,
1631 activationAtomTrackerToMetricMap, deactivationAtomTrackerToMetricMap,
1632 metricsWithActivation, invalidConfigReason, configMetadataProvider);
1633 if (!producer) {
1634 return invalidConfigReason;
1635 }
1636 allMetricProducers.push_back(producer.value());
1637 }
1638
1639 // build DurationMetricProducer
1640 for (int i = 0; i < config.duration_metric_size(); i++) {
1641 int metricIndex = allMetricProducers.size();
1642 const DurationMetric& metric = config.duration_metric(i);
1643 metricMap.insert({metric.id(), metricIndex});
1644
1645 optional<sp<MetricProducer>> producer = createDurationMetricProducerAndUpdateMetadata(
1646 key, config, timeBaseTimeNs, currentTimeNs, metric, metricIndex,
1647 allAtomMatchingTrackers, atomMatchingTrackerMap, allConditionTrackers,
1648 conditionTrackerMap, initialConditionCache, wizard, stateAtomIdMap,
1649 allStateGroupMaps, metricToActivationMap, trackerToMetricMap, conditionToMetricMap,
1650 activationAtomTrackerToMetricMap, deactivationAtomTrackerToMetricMap,
1651 metricsWithActivation, invalidConfigReason, configMetadataProvider);
1652 if (!producer) {
1653 return invalidConfigReason;
1654 }
1655 allMetricProducers.push_back(producer.value());
1656 }
1657
1658 // build EventMetricProducer
1659 for (int i = 0; i < config.event_metric_size(); i++) {
1660 int metricIndex = allMetricProducers.size();
1661 const EventMetric& metric = config.event_metric(i);
1662 metricMap.insert({metric.id(), metricIndex});
1663 optional<sp<MetricProducer>> producer = createEventMetricProducerAndUpdateMetadata(
1664 key, config, timeBaseTimeNs, metric, metricIndex, allAtomMatchingTrackers,
1665 atomMatchingTrackerMap, allConditionTrackers, conditionTrackerMap,
1666 initialConditionCache, wizard, metricToActivationMap, trackerToMetricMap,
1667 conditionToMetricMap, activationAtomTrackerToMetricMap,
1668 deactivationAtomTrackerToMetricMap, metricsWithActivation, invalidConfigReason,
1669 configMetadataProvider);
1670 if (!producer) {
1671 return invalidConfigReason;
1672 }
1673 allMetricProducers.push_back(producer.value());
1674 }
1675
1676 // build NumericValueMetricProducer
1677 for (int i = 0; i < config.value_metric_size(); i++) {
1678 int metricIndex = allMetricProducers.size();
1679 const ValueMetric& metric = config.value_metric(i);
1680 metricMap.insert({metric.id(), metricIndex});
1681 optional<sp<MetricProducer>> producer = createNumericValueMetricProducerAndUpdateMetadata(
1682 key, config, timeBaseTimeNs, currentTimeNs, pullerManager, metric, metricIndex,
1683 allAtomMatchingTrackers, atomMatchingTrackerMap, allConditionTrackers,
1684 conditionTrackerMap, initialConditionCache, wizard, matcherWizard, stateAtomIdMap,
1685 allStateGroupMaps, metricToActivationMap, trackerToMetricMap, conditionToMetricMap,
1686 activationAtomTrackerToMetricMap, deactivationAtomTrackerToMetricMap,
1687 metricsWithActivation, invalidConfigReason, configMetadataProvider);
1688 if (!producer) {
1689 return invalidConfigReason;
1690 }
1691 allMetricProducers.push_back(producer.value());
1692 }
1693
1694 // build KllMetricProducer
1695 for (int i = 0; i < config.kll_metric_size(); i++) {
1696 int metricIndex = allMetricProducers.size();
1697 const KllMetric& metric = config.kll_metric(i);
1698 metricMap.insert({metric.id(), metricIndex});
1699 optional<sp<MetricProducer>> producer = createKllMetricProducerAndUpdateMetadata(
1700 key, config, timeBaseTimeNs, currentTimeNs, pullerManager, metric, metricIndex,
1701 allAtomMatchingTrackers, atomMatchingTrackerMap, allConditionTrackers,
1702 conditionTrackerMap, initialConditionCache, wizard, matcherWizard, stateAtomIdMap,
1703 allStateGroupMaps, metricToActivationMap, trackerToMetricMap, conditionToMetricMap,
1704 activationAtomTrackerToMetricMap, deactivationAtomTrackerToMetricMap,
1705 metricsWithActivation, invalidConfigReason, configMetadataProvider);
1706 if (!producer) {
1707 return invalidConfigReason;
1708 }
1709 allMetricProducers.push_back(producer.value());
1710 }
1711
1712 // Gauge metrics.
1713 for (int i = 0; i < config.gauge_metric_size(); i++) {
1714 int metricIndex = allMetricProducers.size();
1715 const GaugeMetric& metric = config.gauge_metric(i);
1716 metricMap.insert({metric.id(), metricIndex});
1717 optional<sp<MetricProducer>> producer = createGaugeMetricProducerAndUpdateMetadata(
1718 key, config, timeBaseTimeNs, currentTimeNs, pullerManager, metric, metricIndex,
1719 allAtomMatchingTrackers, atomMatchingTrackerMap, allConditionTrackers,
1720 conditionTrackerMap, initialConditionCache, wizard, matcherWizard,
1721 metricToActivationMap, trackerToMetricMap, conditionToMetricMap,
1722 activationAtomTrackerToMetricMap, deactivationAtomTrackerToMetricMap,
1723 metricsWithActivation, invalidConfigReason, configMetadataProvider);
1724 if (!producer) {
1725 return invalidConfigReason;
1726 }
1727 allMetricProducers.push_back(producer.value());
1728 }
1729 for (int i = 0; i < config.no_report_metric_size(); ++i) {
1730 const auto no_report_metric = config.no_report_metric(i);
1731 if (metricMap.find(no_report_metric) == metricMap.end()) {
1732 ALOGW("no_report_metric %" PRId64 " not exist", no_report_metric);
1733 return InvalidConfigReason(INVALID_CONFIG_REASON_NO_REPORT_METRIC_NOT_FOUND,
1734 no_report_metric);
1735 }
1736 noReportMetricIds.insert(no_report_metric);
1737 }
1738
1739 const set<int> whitelistedAtomIds(config.whitelisted_atom_ids().begin(),
1740 config.whitelisted_atom_ids().end());
1741 for (const auto& it : allMetricProducers) {
1742 // Register metrics to StateTrackers
1743 for (int atomId : it->getSlicedStateAtoms()) {
1744 // Register listener for non-whitelisted atoms only. Using whitelisted atom as a sliced
1745 // state atom is not allowed.
1746 if (whitelistedAtomIds.find(atomId) == whitelistedAtomIds.end()) {
1747 StateManager::getInstance().registerListener(atomId, it);
1748 } else {
1749 return InvalidConfigReason(
1750 INVALID_CONFIG_REASON_METRIC_SLICED_STATE_ATOM_ALLOWED_FROM_ANY_UID,
1751 it->getMetricId());
1752 }
1753 }
1754 }
1755 return nullopt;
1756 }
1757
initAlerts(const StatsdConfig & config,const int64_t currentTimeNs,const unordered_map<int64_t,int> & metricProducerMap,unordered_map<int64_t,int> & alertTrackerMap,const sp<AlarmMonitor> & anomalyAlarmMonitor,vector<sp<MetricProducer>> & allMetricProducers,vector<sp<AnomalyTracker>> & allAnomalyTrackers)1758 optional<InvalidConfigReason> initAlerts(const StatsdConfig& config, const int64_t currentTimeNs,
1759 const unordered_map<int64_t, int>& metricProducerMap,
1760 unordered_map<int64_t, int>& alertTrackerMap,
1761 const sp<AlarmMonitor>& anomalyAlarmMonitor,
1762 vector<sp<MetricProducer>>& allMetricProducers,
1763 vector<sp<AnomalyTracker>>& allAnomalyTrackers) {
1764 optional<InvalidConfigReason> invalidConfigReason;
1765 for (int i = 0; i < config.alert_size(); i++) {
1766 const Alert& alert = config.alert(i);
1767 alertTrackerMap.insert(std::make_pair(alert.id(), allAnomalyTrackers.size()));
1768 optional<sp<AnomalyTracker>> anomalyTracker = createAnomalyTracker(
1769 alert, anomalyAlarmMonitor, UpdateStatus::UPDATE_NEW, currentTimeNs,
1770 metricProducerMap, allMetricProducers, invalidConfigReason);
1771 if (!anomalyTracker) {
1772 return invalidConfigReason;
1773 }
1774 allAnomalyTrackers.push_back(anomalyTracker.value());
1775 }
1776 return initSubscribersForSubscriptionType(config, Subscription::ALERT, alertTrackerMap,
1777 allAnomalyTrackers);
1778 }
1779
initAlarms(const StatsdConfig & config,const ConfigKey & key,const sp<AlarmMonitor> & periodicAlarmMonitor,const int64_t timeBaseNs,const int64_t currentTimeNs,vector<sp<AlarmTracker>> & allAlarmTrackers)1780 optional<InvalidConfigReason> initAlarms(const StatsdConfig& config, const ConfigKey& key,
1781 const sp<AlarmMonitor>& periodicAlarmMonitor,
1782 const int64_t timeBaseNs, const int64_t currentTimeNs,
1783 vector<sp<AlarmTracker>>& allAlarmTrackers) {
1784 unordered_map<int64_t, int> alarmTrackerMap;
1785 int64_t startMillis = timeBaseNs / 1000 / 1000;
1786 int64_t currentTimeMillis = currentTimeNs / 1000 / 1000;
1787 for (int i = 0; i < config.alarm_size(); i++) {
1788 const Alarm& alarm = config.alarm(i);
1789 if (alarm.offset_millis() <= 0) {
1790 ALOGW("Alarm offset_millis should be larger than 0.");
1791 return createInvalidConfigReasonWithAlarm(
1792 INVALID_CONFIG_REASON_ALARM_OFFSET_LESS_THAN_OR_EQUAL_ZERO, alarm.id());
1793 }
1794 if (alarm.period_millis() <= 0) {
1795 ALOGW("Alarm period_millis should be larger than 0.");
1796 return createInvalidConfigReasonWithAlarm(
1797 INVALID_CONFIG_REASON_ALARM_PERIOD_LESS_THAN_OR_EQUAL_ZERO, alarm.id());
1798 }
1799 alarmTrackerMap.insert(std::make_pair(alarm.id(), allAlarmTrackers.size()));
1800 allAlarmTrackers.push_back(
1801 new AlarmTracker(startMillis, currentTimeMillis, alarm, key, periodicAlarmMonitor));
1802 }
1803 return initSubscribersForSubscriptionType(config, Subscription::ALARM, alarmTrackerMap,
1804 allAlarmTrackers);
1805 }
1806
initStatsdConfig(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 wp<ConfigMetadataProvider> configMetadataProvider,std::unordered_map<int,std::vector<int>> & allTagIdsToMatchersMap,vector<sp<AtomMatchingTracker>> & allAtomMatchingTrackers,unordered_map<int64_t,int> & atomMatchingTrackerMap,vector<sp<ConditionTracker>> & allConditionTrackers,unordered_map<int64_t,int> & conditionTrackerMap,vector<sp<MetricProducer>> & allMetricProducers,unordered_map<int64_t,int> & metricProducerMap,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,unordered_map<int64_t,int> & alertTrackerMap,vector<int> & metricsWithActivation,map<int64_t,uint64_t> & stateProtoHashes,set<int64_t> & noReportMetricIds)1807 optional<InvalidConfigReason> initStatsdConfig(
1808 const ConfigKey& key, const StatsdConfig& config, const sp<UidMap>& uidMap,
1809 const sp<StatsPullerManager>& pullerManager, const sp<AlarmMonitor>& anomalyAlarmMonitor,
1810 const sp<AlarmMonitor>& periodicAlarmMonitor, const int64_t timeBaseNs,
1811 const int64_t currentTimeNs, const wp<ConfigMetadataProvider> configMetadataProvider,
1812 std::unordered_map<int, std::vector<int>>& allTagIdsToMatchersMap,
1813 vector<sp<AtomMatchingTracker>>& allAtomMatchingTrackers,
1814 unordered_map<int64_t, int>& atomMatchingTrackerMap,
1815 vector<sp<ConditionTracker>>& allConditionTrackers,
1816 unordered_map<int64_t, int>& conditionTrackerMap,
1817 vector<sp<MetricProducer>>& allMetricProducers,
1818 unordered_map<int64_t, int>& metricProducerMap,
1819 vector<sp<AnomalyTracker>>& allAnomalyTrackers,
1820 vector<sp<AlarmTracker>>& allPeriodicAlarmTrackers,
1821 unordered_map<int, std::vector<int>>& conditionToMetricMap,
1822 unordered_map<int, std::vector<int>>& trackerToMetricMap,
1823 unordered_map<int, std::vector<int>>& trackerToConditionMap,
1824 unordered_map<int, std::vector<int>>& activationAtomTrackerToMetricMap,
1825 unordered_map<int, std::vector<int>>& deactivationAtomTrackerToMetricMap,
1826 unordered_map<int64_t, int>& alertTrackerMap, vector<int>& metricsWithActivation,
1827 map<int64_t, uint64_t>& stateProtoHashes, set<int64_t>& noReportMetricIds) {
1828 vector<ConditionState> initialConditionCache;
1829 unordered_map<int64_t, int> stateAtomIdMap;
1830 unordered_map<int64_t, unordered_map<int, int64_t>> allStateGroupMaps;
1831
1832 if (config.package_certificate_hash_size_bytes() > UINT8_MAX) {
1833 ALOGE("Invalid value for package_certificate_hash_size_bytes: %d",
1834 config.package_certificate_hash_size_bytes());
1835 return InvalidConfigReason(INVALID_CONFIG_REASON_PACKAGE_CERT_HASH_SIZE_TOO_LARGE);
1836 }
1837
1838 optional<InvalidConfigReason> invalidConfigReason =
1839 initAtomMatchingTrackers(config, uidMap, atomMatchingTrackerMap,
1840 allAtomMatchingTrackers, allTagIdsToMatchersMap);
1841 if (invalidConfigReason.has_value()) {
1842 ALOGE("initAtomMatchingTrackers failed");
1843 return invalidConfigReason;
1844 }
1845 VLOG("initAtomMatchingTrackers succeed...");
1846
1847 invalidConfigReason =
1848 initConditions(key, config, atomMatchingTrackerMap, conditionTrackerMap,
1849 allConditionTrackers, trackerToConditionMap, initialConditionCache);
1850 if (invalidConfigReason.has_value()) {
1851 ALOGE("initConditionTrackers failed");
1852 return invalidConfigReason;
1853 }
1854
1855 invalidConfigReason = initStates(config, stateAtomIdMap, allStateGroupMaps, stateProtoHashes);
1856 if (invalidConfigReason.has_value()) {
1857 ALOGE("initStates failed");
1858 return invalidConfigReason;
1859 }
1860
1861 invalidConfigReason = initMetrics(
1862 key, config, timeBaseNs, currentTimeNs, pullerManager, atomMatchingTrackerMap,
1863 conditionTrackerMap, allAtomMatchingTrackers, stateAtomIdMap, allStateGroupMaps,
1864 allConditionTrackers, initialConditionCache, allMetricProducers, conditionToMetricMap,
1865 trackerToMetricMap, metricProducerMap, noReportMetricIds,
1866 activationAtomTrackerToMetricMap, deactivationAtomTrackerToMetricMap,
1867 metricsWithActivation, configMetadataProvider);
1868 if (invalidConfigReason.has_value()) {
1869 ALOGE("initMetricProducers failed");
1870 return invalidConfigReason;
1871 }
1872
1873 invalidConfigReason = initAlerts(config, currentTimeNs, metricProducerMap, alertTrackerMap,
1874 anomalyAlarmMonitor, allMetricProducers, allAnomalyTrackers);
1875 if (invalidConfigReason.has_value()) {
1876 ALOGE("initAlerts failed");
1877 return invalidConfigReason;
1878 }
1879
1880 invalidConfigReason = initAlarms(config, key, periodicAlarmMonitor, timeBaseNs, currentTimeNs,
1881 allPeriodicAlarmTrackers);
1882 if (invalidConfigReason.has_value()) {
1883 ALOGE("initAlarms failed");
1884 return invalidConfigReason;
1885 }
1886
1887 return nullopt;
1888 }
1889
1890 } // namespace statsd
1891 } // namespace os
1892 } // namespace android
1893