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 29namespace android { 30namespace os { 31namespace statsd { 32 33struct ValueBucket { 34 int64_t mBucketStartNs; 35 int64_t mBucketEndNs; 36 int64_t mValue; 37}; 38 39class ValueMetricProducer : public virtual MetricProducer, public virtual PullDataReceiver { 40public: 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. 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 84protected: 85 void onMatchedLogEventInternalLocked( 86 const size_t matcherIndex, const MetricDimensionKey& eventKey, 87 const ConditionKey& conditionKey, bool condition, 88 const LogEvent& event) override; 89 90private: 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