• Home
  • History
  • Annotate
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #pragma once
18 
19 #include <unordered_map>
20 
21 #include <android/util/ProtoOutputStream.h>
22 #include <gtest/gtest_prod.h>
23 #include "../condition/ConditionTracker.h"
24 #include "../external/PullDataReceiver.h"
25 #include "../external/StatsPullerManager.h"
26 #include "../matchers/matcher_util.h"
27 #include "../matchers/EventMatcherWizard.h"
28 #include "MetricProducer.h"
29 #include "src/statsd_config.pb.h"
30 #include "../stats_util.h"
31 
32 namespace android {
33 namespace os {
34 namespace statsd {
35 
36 struct GaugeAtom {
37     GaugeAtom(std::shared_ptr<vector<FieldValue>> fields, int64_t elapsedTimeNs)
38         : mFields(fields), mElapsedTimestampNs(elapsedTimeNs) {
39     }
40     std::shared_ptr<vector<FieldValue>> mFields;
41     int64_t mElapsedTimestampNs;
42 };
43 
44 struct GaugeBucket {
45     int64_t mBucketStartNs;
46     int64_t mBucketEndNs;
47     std::vector<GaugeAtom> mGaugeAtoms;
48 };
49 
50 typedef std::unordered_map<MetricDimensionKey, std::vector<GaugeAtom>>
51     DimToGaugeAtomsMap;
52 
53 // This gauge metric producer first register the puller to automatically pull the gauge at the
54 // beginning of each bucket. If the condition is met, insert it to the bucket info. Otherwise
55 // proactively pull the gauge when the condition is changed to be true. Therefore, the gauge metric
56 // producer always reports the gauge at the earliest time of the bucket when the condition is met.
57 class GaugeMetricProducer : public MetricProducer, public virtual PullDataReceiver {
58 public:
59     GaugeMetricProducer(
60             const ConfigKey& key, const GaugeMetric& gaugeMetric, const int conditionIndex,
61             const vector<ConditionState>& initialConditionCache,
62             const sp<ConditionWizard>& conditionWizard, const uint64_t protoHash,
63             const int whatMatcherIndex, const sp<EventMatcherWizard>& matcherWizard,
64             const int pullTagId, const int triggerAtomId, const int atomId,
65             const int64_t timeBaseNs, const int64_t startTimeNs,
66             const sp<StatsPullerManager>& pullerManager,
67             const std::unordered_map<int, std::shared_ptr<Activation>>& eventActivationMap = {},
68             const std::unordered_map<int, std::vector<std::shared_ptr<Activation>>>&
69                     eventDeactivationMap = {});
70 
71     virtual ~GaugeMetricProducer();
72 
73     // Handles when the pulled data arrives.
74     void onDataPulled(const std::vector<std::shared_ptr<LogEvent>>& data,
75                       bool pullSuccess, int64_t originalPullTimeNs) override;
76 
77     // GaugeMetric needs to immediately trigger another pull when we create the partial bucket.
78     void notifyAppUpgrade(const int64_t& eventTimeNs) override {
79         std::lock_guard<std::mutex> lock(mMutex);
80 
81         if (!mSplitBucketForAppUpgrade) {
82             return;
83         }
84         flushLocked(eventTimeNs);
85         if (mIsPulled && mSamplingType == GaugeMetric::RANDOM_ONE_SAMPLE) {
86             pullAndMatchEventsLocked(eventTimeNs);
87         }
88     };
89 
90     // GaugeMetric needs to immediately trigger another pull when we create the partial bucket.
91     void onStatsdInitCompleted(const int64_t& eventTimeNs) override {
92         std::lock_guard<std::mutex> lock(mMutex);
93 
94         flushLocked(eventTimeNs);
95         if (mIsPulled && mSamplingType == GaugeMetric::RANDOM_ONE_SAMPLE) {
96             pullAndMatchEventsLocked(eventTimeNs);
97         }
98     };
99 
100     MetricType getMetricType() const override {
101         return METRIC_TYPE_GAUGE;
102     }
103 
104 protected:
105     void onMatchedLogEventInternalLocked(
106             const size_t matcherIndex, const MetricDimensionKey& eventKey,
107             const ConditionKey& conditionKey, bool condition, const LogEvent& event,
108             const std::map<int, HashableDimensionKey>& statePrimaryKeys) override;
109 
110 private:
111     void onDumpReportLocked(const int64_t dumpTimeNs,
112                             const bool include_current_partial_bucket,
113                             const bool erase_data,
114                             const DumpLatency dumpLatency,
115                             std::set<string> *str_set,
116                             android::util::ProtoOutputStream* protoOutput) override;
117     void clearPastBucketsLocked(const int64_t dumpTimeNs) override;
118 
119     // Internal interface to handle condition change.
120     void onConditionChangedLocked(const bool conditionMet, const int64_t eventTime) override;
121 
122     // Internal interface to handle active state change.
123     void onActiveStateChangedLocked(const int64_t& eventTimeNs) override;
124 
125     // Internal interface to handle sliced condition change.
126     void onSlicedConditionMayChangeLocked(bool overallCondition, const int64_t eventTime) override;
127 
128     // Internal function to calculate the current used bytes.
129     size_t byteSizeLocked() const override;
130 
131     void dumpStatesLocked(FILE* out, bool verbose) const override;
132 
133     void dropDataLocked(const int64_t dropTimeNs) override;
134 
135     // Util function to flush the old packet.
136     void flushIfNeededLocked(const int64_t& eventTime) override;
137 
138     void flushCurrentBucketLocked(const int64_t& eventTimeNs,
139                                   const int64_t& nextBucketStartTimeNs) override;
140 
141     void prepareFirstBucketLocked() override;
142 
143     void pullAndMatchEventsLocked(const int64_t timestampNs);
144 
145     bool onConfigUpdatedLocked(
146             const StatsdConfig& config, const int configIndex, const int metricIndex,
147             const std::vector<sp<AtomMatchingTracker>>& allAtomMatchingTrackers,
148             const std::unordered_map<int64_t, int>& oldAtomMatchingTrackerMap,
149             const std::unordered_map<int64_t, int>& newAtomMatchingTrackerMap,
150             const sp<EventMatcherWizard>& matcherWizard,
151             const std::vector<sp<ConditionTracker>>& allConditionTrackers,
152             const std::unordered_map<int64_t, int>& conditionTrackerMap,
153             const sp<ConditionWizard>& wizard,
154             const std::unordered_map<int64_t, int>& metricToActivationMap,
155             std::unordered_map<int, std::vector<int>>& trackerToMetricMap,
156             std::unordered_map<int, std::vector<int>>& conditionToMetricMap,
157             std::unordered_map<int, std::vector<int>>& activationAtomTrackerToMetricMap,
158             std::unordered_map<int, std::vector<int>>& deactivationAtomTrackerToMetricMap,
159             std::vector<int>& metricsWithActivation) override;
160 
161     int mWhatMatcherIndex;
162 
163     sp<EventMatcherWizard> mEventMatcherWizard;
164 
165     sp<StatsPullerManager> mPullerManager;
166     // tagId for pulled data. -1 if this is not pulled
167     const int mPullTagId;
168 
169     // tagId for atoms that trigger the pulling, if any
170     const int mTriggerAtomId;
171 
172     // tagId for output atom
173     const int mAtomId;
174 
175     // if this is pulled metric
176     const bool mIsPulled;
177 
178     // Save the past buckets and we can clear when the StatsLogReport is dumped.
179     std::unordered_map<MetricDimensionKey, std::vector<GaugeBucket>> mPastBuckets;
180 
181     // The current partial bucket.
182     std::shared_ptr<DimToGaugeAtomsMap> mCurrentSlicedBucket;
183 
184     // The current full bucket for anomaly detection. This is updated to the latest value seen for
185     // this slice (ie, for partial buckets, we use the last partial bucket in this full bucket).
186     std::shared_ptr<DimToValMap> mCurrentSlicedBucketForAnomaly;
187 
188     const int64_t mMinBucketSizeNs;
189 
190     // Translate Atom based bucket to single numeric value bucket for anomaly and updates the map
191     // for each slice with the latest value.
192     void updateCurrentSlicedBucketForAnomaly();
193 
194     // Allowlist of fields to report. Empty means all are reported.
195     std::vector<Matcher> mFieldMatchers;
196 
197     GaugeMetric::SamplingType mSamplingType;
198 
199     const int64_t mMaxPullDelayNs;
200 
201     // apply an allowlist on the original input
202     std::shared_ptr<vector<FieldValue>> getGaugeFields(const LogEvent& event);
203 
204     // Util function to check whether the specified dimension hits the guardrail.
205     bool hitGuardRailLocked(const MetricDimensionKey& newKey);
206 
207     static const size_t kBucketSize = sizeof(GaugeBucket{});
208 
209     const size_t mDimensionSoftLimit;
210 
211     const size_t mDimensionHardLimit;
212 
213     const size_t mGaugeAtomsPerDimensionLimit;
214 
215     const bool mSplitBucketForAppUpgrade;
216 
217     FRIEND_TEST(GaugeMetricProducerTest, TestPulledEventsWithCondition);
218     FRIEND_TEST(GaugeMetricProducerTest, TestPulledEventsWithSlicedCondition);
219     FRIEND_TEST(GaugeMetricProducerTest, TestPulledEventsNoCondition);
220     FRIEND_TEST(GaugeMetricProducerTest, TestPulledWithAppUpgradeDisabled);
221     FRIEND_TEST(GaugeMetricProducerTest, TestPulledEventsAnomalyDetection);
222     FRIEND_TEST(GaugeMetricProducerTest, TestFirstBucket);
223     FRIEND_TEST(GaugeMetricProducerTest, TestPullOnTrigger);
224     FRIEND_TEST(GaugeMetricProducerTest, TestRemoveDimensionInOutput);
225 
226     FRIEND_TEST(GaugeMetricProducerTest_PartialBucket, TestPushedEvents);
227     FRIEND_TEST(GaugeMetricProducerTest_PartialBucket, TestPulled);
228 
229     FRIEND_TEST(ConfigUpdateTest, TestUpdateGaugeMetrics);
230 };
231 
232 }  // namespace statsd
233 }  // namespace os
234 }  // namespace android
235