1 /*
2  * Copyright (C) 2021 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 #pragma once
18 
19 #include <android/util/ProtoOutputStream.h>
20 #include <gtest/gtest_prod.h>
21 #include <kll.h>
22 
23 #include <optional>
24 
25 #include "MetricProducer.h"
26 #include "ValueMetricProducer.h"
27 #include "condition/ConditionTimer.h"
28 #include "condition/ConditionTracker.h"
29 #include "matchers/EventMatcherWizard.h"
30 #include "src/statsd_config.pb.h"
31 #include "stats_log_util.h"
32 
33 using dist_proc::aggregation::KllQuantile;
34 
35 namespace android {
36 namespace os {
37 namespace statsd {
38 
39 // Uses KllQuantile to aggregate values within buckets.
40 //
41 // There are different events that might complete a bucket
42 // - a condition change
43 // - an app upgrade
44 // - an alarm set to the end of the bucket
45 class KllMetricProducer : public ValueMetricProducer<std::unique_ptr<KllQuantile>, Empty> {
46 public:
47     KllMetricProducer(const ConfigKey& key, const KllMetric& kllMetric, const uint64_t protoHash,
48                       const PullOptions& pullOptions, const BucketOptions& bucketOptions,
49                       const WhatOptions& whatOptions, const ConditionOptions& conditionOptions,
50                       const StateOptions& stateOptions, const ActivationOptions& activationOptions,
51                       const GuardrailOptions& guardrailOptions,
52                       const wp<ConfigMetadataProvider> configMetadataProvider);
53 
getMetricType()54     inline MetricType getMetricType() const override {
55         return METRIC_TYPE_KLL;
56     }
57 
58 protected:
59 private:
getConditionIdForMetric(const StatsdConfig & config,const int configIndex)60     inline optional<int64_t> getConditionIdForMetric(const StatsdConfig& config,
61                                                      const int configIndex) const override {
62         const KllMetric& metric = config.kll_metric(configIndex);
63         return metric.has_condition() ? make_optional(metric.condition()) : nullopt;
64     }
65 
getWhatAtomMatcherIdForMetric(const StatsdConfig & config,const int configIndex)66     inline int64_t getWhatAtomMatcherIdForMetric(const StatsdConfig& config,
67                                                  const int configIndex) const override {
68         return config.kll_metric(configIndex).what();
69     }
70 
getConditionLinksForMetric(const StatsdConfig & config,const int configIndex)71     inline ConditionLinks getConditionLinksForMetric(const StatsdConfig& config,
72                                                      const int configIndex) const override {
73         return config.kll_metric(configIndex).links();
74     }
75 
76     // Determine whether or not a LogEvent can be skipped.
canSkipLogEventLocked(const MetricDimensionKey & eventKey,bool condition,int64_t eventTimeNs,const std::map<int,HashableDimensionKey> & statePrimaryKeys)77     inline bool canSkipLogEventLocked(
78             const MetricDimensionKey& eventKey, bool condition, int64_t eventTimeNs,
79             const std::map<int, HashableDimensionKey>& statePrimaryKeys) const override {
80         // Can only skip if the condition is false.
81         // We assume metric is pushed since KllMetric doesn't support pulled metrics.
82         return !condition;
83     }
84 
85     DumpProtoFields getDumpProtoFields() const override;
86 
aggregatedValueToString(const std::unique_ptr<KllQuantile> & aggregate)87     inline std::string aggregatedValueToString(
88             const std::unique_ptr<KllQuantile>& aggregate) const override {
89         return std::to_string(aggregate->num_values()) + " values";
90     }
91 
multipleBucketsSkipped(const int64_t numBucketsForward)92     inline bool multipleBucketsSkipped(const int64_t numBucketsForward) const override {
93         // Always false because we assume KllMetric is pushed only for now.
94         return false;
95     }
96 
97     // The KllQuantile ptr ownership is transferred to newly created PastBuckets from Intervals.
98     PastBucket<std::unique_ptr<KllQuantile>> buildPartialBucket(
99             int64_t bucketEndTime, std::vector<Interval>& intervals) override;
100 
101     void writePastBucketAggregateToProto(const int aggIndex,
102                                          const std::unique_ptr<KllQuantile>& kll,
103                                          const int sampleSize,
104                                          ProtoOutputStream* const protoOutput) const override;
105 
106     size_t getAggregatedValueSize(const std::unique_ptr<KllQuantile>& kll) const override;
107 
108     bool aggregateFields(const int64_t eventTimeNs, const MetricDimensionKey& eventKey,
109                          const LogEvent& event, std::vector<Interval>& intervals,
110                          Empty& empty) override;
111 
112     // Internal function to calculate the current used bytes.
113     size_t byteSizeLocked() const override;
114 
115     FRIEND_TEST(KllMetricProducerTest, TestByteSize);
116     FRIEND_TEST(KllMetricProducerTest, TestPushedEventsWithoutCondition);
117     FRIEND_TEST(KllMetricProducerTest, TestPushedEventsWithCondition);
118     FRIEND_TEST(KllMetricProducerTest, TestForcedBucketSplitWhenConditionUnknownSkipsBucket);
119 
120     FRIEND_TEST(KllMetricProducerTest_BucketDrop, TestInvalidBucketWhenConditionUnknown);
121     FRIEND_TEST(KllMetricProducerTest_BucketDrop, TestBucketDropWhenBucketTooSmall);
122     FRIEND_TEST(KllMetricProducerTest_BucketDrop, TestBucketDropWhenDataUnavailable);
123 
124     FRIEND_TEST(KllMetricProducerTest_PartialBucket, TestPushedEventsMultipleBuckets);
125 
126     FRIEND_TEST(ConfigUpdateTest, TestUpdateKllMetrics);
127 
128     FRIEND_TEST(MetricsManagerUtilDimLimitTest, TestDimLimit);
129 
130     FRIEND_TEST(ConfigUpdateDimLimitTest, TestDimLimit);
131 };
132 
133 }  // namespace statsd
134 }  // namespace os
135 }  // namespace android
136