• Home
  • 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 <gtest/gtest_prod.h>
20 #include <utils/threads.h>
21 #include <list>
22 #include "../anomaly/AnomalyTracker.h"
23 #include "../condition/ConditionTracker.h"
24 #include "../external/PullDataReceiver.h"
25 #include "../external/StatsPullerManager.h"
26 #include "MetricProducer.h"
27 #include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
28 
29 namespace android {
30 namespace os {
31 namespace statsd {
32 
33 struct ValueBucket {
34     int64_t mBucketStartNs;
35     int64_t mBucketEndNs;
36     int64_t mValue;
37 };
38 
39 class ValueMetricProducer : public virtual MetricProducer, public virtual PullDataReceiver {
40 public:
41     ValueMetricProducer(const ConfigKey& key, const ValueMetric& valueMetric,
42                         const int conditionIndex, const sp<ConditionWizard>& wizard,
43                         const int pullTagId, const int64_t timeBaseNs, const int64_t startTimeNs);
44 
45     virtual ~ValueMetricProducer();
46 
47     void onDataPulled(const std::vector<std::shared_ptr<LogEvent>>& data) override;
48 
49     // ValueMetric needs special logic if it's a pulled atom.
notifyAppUpgrade(const int64_t & eventTimeNs,const string & apk,const int uid,const int64_t version)50     void notifyAppUpgrade(const int64_t& eventTimeNs, const string& apk, const int uid,
51                           const int64_t version) override {
52         std::lock_guard<std::mutex> lock(mMutex);
53 
54         if (mPullTagId != -1 && (mCondition == true || mConditionTrackerIndex < 0) ) {
55             vector<shared_ptr<LogEvent>> allData;
56             mStatsPullerManager->Pull(mPullTagId, eventTimeNs, &allData);
57             if (allData.size() == 0) {
58                 // This shouldn't happen since this valuemetric is not useful now.
59             }
60 
61             // Pretend the pulled data occurs right before the app upgrade event.
62             mCondition = false;
63             for (const auto& data : allData) {
64                 data->setElapsedTimestampNs(eventTimeNs - 1);
65                 onMatchedLogEventLocked(0, *data);
66             }
67 
68             flushCurrentBucketLocked(eventTimeNs);
69             mCurrentBucketStartTimeNs = eventTimeNs;
70 
71             mCondition = true;
72             for (const auto& data : allData) {
73                 data->setElapsedTimestampNs(eventTimeNs);
74                 onMatchedLogEventLocked(0, *data);
75             }
76         } else {
77             // For pushed value metric or pulled metric where condition is not true,
78             // we simply flush and reset the current bucket start.
79             flushCurrentBucketLocked(eventTimeNs);
80             mCurrentBucketStartTimeNs = eventTimeNs;
81         }
82     };
83 
84 protected:
85     void onMatchedLogEventInternalLocked(
86             const size_t matcherIndex, const MetricDimensionKey& eventKey,
87             const ConditionKey& conditionKey, bool condition,
88             const LogEvent& event) override;
89 
90 private:
91     void onDumpReportLocked(const int64_t dumpTimeNs,
92                             const bool include_current_partial_bucket,
93                             std::set<string> *str_set,
94                             android::util::ProtoOutputStream* protoOutput) override;
95     void clearPastBucketsLocked(const int64_t dumpTimeNs) override;
96 
97     // Internal interface to handle condition change.
98     void onConditionChangedLocked(const bool conditionMet, const int64_t eventTime) override;
99 
100     // Internal interface to handle sliced condition change.
101     void onSlicedConditionMayChangeLocked(bool overallCondition, const int64_t eventTime) override;
102 
103     // Internal function to calculate the current used bytes.
104     size_t byteSizeLocked() const override;
105 
106     void dumpStatesLocked(FILE* out, bool verbose) const override;
107 
108     // Util function to flush the old packet.
109     void flushIfNeededLocked(const int64_t& eventTime) override;
110 
111     void flushCurrentBucketLocked(const int64_t& eventTimeNs) override;
112 
113     void dropDataLocked(const int64_t dropTimeNs) override;
114 
115     const FieldMatcher mValueField;
116 
117     std::shared_ptr<StatsPullerManager> mStatsPullerManager;
118 
119     // for testing
120     ValueMetricProducer(const ConfigKey& key, const ValueMetric& valueMetric,
121                         const int conditionIndex, const sp<ConditionWizard>& wizard,
122                         const int pullTagId, const int64_t timeBaseNs, const int64_t startTimeNs,
123                         std::shared_ptr<StatsPullerManager> statsPullerManager);
124 
125     // tagId for pulled data. -1 if this is not pulled
126     const int mPullTagId;
127 
128     int mField;
129 
130     // internal state of a bucket.
131     typedef struct {
132         // Pulled data always come in pair of <start, end>. This holds the value
133         // for start. The diff (end - start) is added to sum.
134         int64_t start;
135         // Whether the start data point is updated
136         bool startUpdated;
137         // If end data point comes before the start, record this pair as tainted
138         // and the value is not added to the running sum.
139         int tainted;
140         // Running sum of known pairs in this bucket
141         int64_t sum;
142         // If this dimension has any non-tainted value. If not, don't report the
143         // dimension.
144         bool hasValue;
145     } Interval;
146 
147     std::unordered_map<MetricDimensionKey, Interval> mCurrentSlicedBucket;
148 
149     std::unordered_map<MetricDimensionKey, int64_t> mCurrentFullBucket;
150 
151     // Save the past buckets and we can clear when the StatsLogReport is dumped.
152     // TODO: Add a lock to mPastBuckets.
153     std::unordered_map<MetricDimensionKey, std::vector<ValueBucket>> mPastBuckets;
154 
155     // Pairs of (elapsed start, elapsed end) denoting buckets that were skipped.
156     std::list<std::pair<int64_t, int64_t>> mSkippedBuckets;
157 
158     const int64_t mMinBucketSizeNs;
159 
160     // Util function to check whether the specified dimension hits the guardrail.
161     bool hitGuardRailLocked(const MetricDimensionKey& newKey);
162 
163     static const size_t kBucketSize = sizeof(ValueBucket{});
164 
165     const size_t mDimensionSoftLimit;
166 
167     const size_t mDimensionHardLimit;
168 
169     const bool mUseAbsoluteValueOnReset;
170 
171     FRIEND_TEST(ValueMetricProducerTest, TestNonDimensionalEvents);
172     FRIEND_TEST(ValueMetricProducerTest, TestPulledEventsTakeAbsoluteValueOnReset);
173     FRIEND_TEST(ValueMetricProducerTest, TestPulledEventsTakeZeroOnReset);
174     FRIEND_TEST(ValueMetricProducerTest, TestEventsWithNonSlicedCondition);
175     FRIEND_TEST(ValueMetricProducerTest, TestPushedEventsWithUpgrade);
176     FRIEND_TEST(ValueMetricProducerTest, TestPulledValueWithUpgrade);
177     FRIEND_TEST(ValueMetricProducerTest, TestPulledValueWithUpgradeWhileConditionFalse);
178     FRIEND_TEST(ValueMetricProducerTest, TestPushedEventsWithoutCondition);
179     FRIEND_TEST(ValueMetricProducerTest, TestPushedEventsWithCondition);
180     FRIEND_TEST(ValueMetricProducerTest, TestAnomalyDetection);
181     FRIEND_TEST(ValueMetricProducerTest, TestBucketBoundaryNoCondition);
182     FRIEND_TEST(ValueMetricProducerTest, TestBucketBoundaryWithCondition);
183     FRIEND_TEST(ValueMetricProducerTest, TestBucketBoundaryWithCondition2);
184     FRIEND_TEST(ValueMetricProducerTest, TestBucketBoundaryWithCondition3);
185 };
186 
187 }  // namespace statsd
188 }  // namespace os
189 }  // namespace android
190