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 "anomaly/AnomalyTracker.h" 21 #include "condition/ConditionTimer.h" 22 #include "condition/ConditionTracker.h" 23 #include "external/PullDataReceiver.h" 24 #include "external/StatsPullerManager.h" 25 #include "matchers/EventMatcherWizard.h" 26 #include "stats_log_util.h" 27 #include "MetricProducer.h" 28 #include "src/statsd_config.pb.h" 29 30 namespace android { 31 namespace os { 32 namespace statsd { 33 34 struct PastValueBucket { 35 int64_t mBucketStartNs; 36 int64_t mBucketEndNs; 37 std::vector<int> valueIndex; 38 std::vector<Value> values; 39 // If the metric has no condition, then this field is just wasted. 40 // When we tune statsd memory usage in the future, this is a candidate to optimize. 41 int64_t mConditionTrueNs; 42 }; 43 44 // Aggregates values within buckets. 45 // 46 // There are different events that might complete a bucket 47 // - a condition change 48 // - an app upgrade 49 // - an alarm set to the end of the bucket 50 class ValueMetricProducer : public MetricProducer, public virtual PullDataReceiver { 51 public: 52 ValueMetricProducer( 53 const ConfigKey& key, const ValueMetric& valueMetric, const int conditionIndex, 54 const vector<ConditionState>& initialConditionCache, 55 const sp<ConditionWizard>& conditionWizard, const uint64_t protoHash, 56 const int whatMatcherIndex, const sp<EventMatcherWizard>& matcherWizard, 57 const int pullTagId, const int64_t timeBaseNs, const int64_t startTimeNs, 58 const sp<StatsPullerManager>& pullerManager, 59 const std::unordered_map<int, std::shared_ptr<Activation>>& eventActivationMap = {}, 60 const std::unordered_map<int, std::vector<std::shared_ptr<Activation>>>& 61 eventDeactivationMap = {}, 62 const vector<int>& slicedStateAtoms = {}, 63 const unordered_map<int, unordered_map<int, int64_t>>& stateGroupMap = {}); 64 65 virtual ~ValueMetricProducer(); 66 67 // Process data pulled on bucket boundary. 68 void onDataPulled(const std::vector<std::shared_ptr<LogEvent>>& data, 69 bool pullSuccess, int64_t originalPullTimeNs) override; 70 71 // ValueMetric needs special logic if it's a pulled atom. 72 void notifyAppUpgrade(const int64_t& eventTimeNs) override { 73 std::lock_guard<std::mutex> lock(mMutex); 74 if (!mSplitBucketForAppUpgrade) { 75 return; 76 } 77 if (mIsPulled && mCondition == ConditionState::kTrue) { 78 pullAndMatchEventsLocked(eventTimeNs); 79 } 80 flushCurrentBucketLocked(eventTimeNs, eventTimeNs); 81 }; 82 83 // ValueMetric needs special logic if it's a pulled atom. 84 void onStatsdInitCompleted(const int64_t& eventTimeNs) override { 85 std::lock_guard<std::mutex> lock(mMutex); 86 if (mIsPulled && mCondition == ConditionState::kTrue) { 87 pullAndMatchEventsLocked(eventTimeNs); 88 } 89 flushCurrentBucketLocked(eventTimeNs, eventTimeNs); 90 }; 91 92 void onStateChanged(int64_t eventTimeNs, int32_t atomId, const HashableDimensionKey& primaryKey, 93 const FieldValue& oldState, const FieldValue& newState) override; 94 95 MetricType getMetricType() const override { 96 return METRIC_TYPE_VALUE; 97 } 98 99 protected: 100 void onMatchedLogEventInternalLocked( 101 const size_t matcherIndex, const MetricDimensionKey& eventKey, 102 const ConditionKey& conditionKey, bool condition, const LogEvent& event, 103 const std::map<int, HashableDimensionKey>& statePrimaryKeys) override; 104 105 private: 106 void onDumpReportLocked(const int64_t dumpTimeNs, 107 const bool include_current_partial_bucket, 108 const bool erase_data, 109 const DumpLatency dumpLatency, 110 std::set<string> *str_set, 111 android::util::ProtoOutputStream* protoOutput) override; 112 void clearPastBucketsLocked(const int64_t dumpTimeNs) override; 113 114 // Internal interface to handle active state change. 115 void onActiveStateChangedLocked(const int64_t& eventTimeNs) override; 116 117 // Internal interface to handle condition change. 118 void onConditionChangedLocked(const bool conditionMet, const int64_t eventTime) override; 119 120 // Internal interface to handle sliced condition change. 121 void onSlicedConditionMayChangeLocked(bool overallCondition, const int64_t eventTime) override; 122 123 // Internal function to calculate the current used bytes. 124 size_t byteSizeLocked() const override; 125 126 void dumpStatesLocked(FILE* out, bool verbose) const override; 127 128 // For pulled metrics, this method should only be called if a pull has be done. Else we will 129 // not have complete data for the bucket. 130 void flushIfNeededLocked(const int64_t& eventTime) override; 131 132 // For pulled metrics, this method should only be called if a pulled have be done. Else we will 133 // not have complete data for the bucket. 134 void flushCurrentBucketLocked(const int64_t& eventTimeNs, 135 const int64_t& nextBucketStartTimeNs) override; 136 137 void prepareFirstBucketLocked() override; 138 139 void dropDataLocked(const int64_t dropTimeNs) override; 140 141 // Calculate previous bucket end time based on current time. 142 int64_t calcPreviousBucketEndTime(const int64_t currentTimeNs); 143 144 // Calculate how many buckets are present between the current bucket and eventTimeNs. 145 int64_t calcBucketsForwardCount(const int64_t& eventTimeNs) const; 146 147 // Mark the data as invalid. 148 void invalidateCurrentBucket(const int64_t dropTimeNs, const BucketDropReason reason); 149 150 void invalidateCurrentBucketWithoutResetBase(const int64_t dropTimeNs, 151 const BucketDropReason reason); 152 153 // Skips the current bucket without notifying StatsdStats of the skipped bucket. 154 // This should only be called from #flushCurrentBucketLocked. Otherwise, a future event that 155 // causes the bucket to be invalidated will not notify StatsdStats. 156 void skipCurrentBucket(const int64_t dropTimeNs, const BucketDropReason reason); 157 158 bool onConfigUpdatedLocked( 159 const StatsdConfig& config, const int configIndex, const int metricIndex, 160 const std::vector<sp<AtomMatchingTracker>>& allAtomMatchingTrackers, 161 const std::unordered_map<int64_t, int>& oldAtomMatchingTrackerMap, 162 const std::unordered_map<int64_t, int>& newAtomMatchingTrackerMap, 163 const sp<EventMatcherWizard>& matcherWizard, 164 const std::vector<sp<ConditionTracker>>& allConditionTrackers, 165 const std::unordered_map<int64_t, int>& conditionTrackerMap, 166 const sp<ConditionWizard>& wizard, 167 const std::unordered_map<int64_t, int>& metricToActivationMap, 168 std::unordered_map<int, std::vector<int>>& trackerToMetricMap, 169 std::unordered_map<int, std::vector<int>>& conditionToMetricMap, 170 std::unordered_map<int, std::vector<int>>& activationAtomTrackerToMetricMap, 171 std::unordered_map<int, std::vector<int>>& deactivationAtomTrackerToMetricMap, 172 std::vector<int>& metricsWithActivation) override; 173 174 int mWhatMatcherIndex; 175 176 sp<EventMatcherWizard> mEventMatcherWizard; 177 178 sp<StatsPullerManager> mPullerManager; 179 180 // Value fields for matching. 181 std::vector<Matcher> mFieldMatchers; 182 183 // Value fields for matching. 184 std::set<HashableDimensionKey> mMatchedMetricDimensionKeys; 185 186 // Holds the atom id, primary key pair from a state change. 187 pair<int32_t, HashableDimensionKey> mStateChangePrimaryKey; 188 189 // tagId for pulled data. -1 if this is not pulled 190 const int mPullTagId; 191 192 // if this is pulled metric 193 const bool mIsPulled; 194 195 // Tracks the value information of one value field. 196 typedef struct { 197 // Index in multi value aggregation. 198 int valueIndex; 199 // Current value, depending on the aggregation type. 200 Value value; 201 // Number of samples collected. 202 int sampleSize; 203 // If this dimension has any non-tainted value. If not, don't report the 204 // dimension. 205 bool hasValue = false; 206 // Whether new data is seen in the bucket. 207 bool seenNewData = false; 208 } Interval; 209 210 // Internal state of an ongoing aggregation bucket. 211 typedef struct CurrentValueBucket { 212 // If the `MetricDimensionKey` state key is the current state key, then 213 // the condition timer will be updated later (e.g. condition/state/active 214 // state change) with the correct condition and time. 215 CurrentValueBucket() : intervals(), conditionTimer(ConditionTimer(false, 0)) {} 216 // Value information for each value field of the metric. 217 std::vector<Interval> intervals; 218 // Tracks how long the condition is true. 219 ConditionTimer conditionTimer; 220 } CurrentValueBucket; 221 222 // Holds base information for diffing values from one value field. 223 typedef struct { 224 // Holds current base value of the dimension. Take diff and update if necessary. 225 Value base; 226 // Whether there is a base to diff to. 227 bool hasBase; 228 } BaseInfo; 229 230 // State key and base information for a specific DimensionsInWhat key. 231 typedef struct DimensionsInWhatInfo { 232 DimensionsInWhatInfo(const HashableDimensionKey& stateKey) 233 : baseInfos(), currentState(stateKey), hasCurrentState(false) { 234 } 235 std::vector<BaseInfo> baseInfos; 236 // Last seen state value(s). 237 HashableDimensionKey currentState; 238 // Whether this dimensions in what key has a current state key. 239 bool hasCurrentState; 240 } DimensionsInWhatInfo; 241 242 // Tracks the internal state in the ongoing aggregation bucket for each DimensionsInWhat 243 // key and StateValuesKey pair. 244 std::unordered_map<MetricDimensionKey, CurrentValueBucket> mCurrentSlicedBucket; 245 246 // Tracks current state key and base information for each DimensionsInWhat key. 247 std::unordered_map<HashableDimensionKey, DimensionsInWhatInfo> mCurrentBaseInfo; 248 249 std::unordered_map<MetricDimensionKey, int64_t> mCurrentFullBucket; 250 251 // Save the past buckets and we can clear when the StatsLogReport is dumped. 252 std::unordered_map<MetricDimensionKey, std::vector<PastValueBucket>> mPastBuckets; 253 254 const int64_t mMinBucketSizeNs; 255 256 // Util function to check whether the specified dimension hits the guardrail. 257 bool hitGuardRailLocked(const MetricDimensionKey& newKey); 258 259 bool hasReachedGuardRailLimit() const; 260 261 bool hitFullBucketGuardRailLocked(const MetricDimensionKey& newKey); 262 263 void pullAndMatchEventsLocked(const int64_t timestampNs); 264 265 bool multipleBucketsSkipped(const int64_t numBucketsForward); 266 267 void accumulateEvents(const std::vector<std::shared_ptr<LogEvent>>& allData, 268 int64_t originalPullTimeNs, int64_t eventElapsedTimeNs); 269 270 PastValueBucket buildPartialBucket(int64_t bucketEndTime, 271 const std::vector<Interval>& intervals); 272 273 void initCurrentSlicedBucket(int64_t nextBucketStartTimeNs); 274 275 void appendToFullBucket(const bool isFullBucketReached); 276 277 // Reset diff base and mHasGlobalBase 278 void resetBase(); 279 280 // Updates the condition timers in the current sliced bucket when there is a 281 // condition change or an active state change. 282 void updateCurrentSlicedBucketConditionTimers(bool newCondition, int64_t eventTimeNs); 283 284 bool valuePassesThreshold(const Interval& interval); 285 286 Value getFinalValue(const Interval& interval); 287 288 static const size_t kBucketSize = sizeof(PastValueBucket{}); 289 290 const size_t mDimensionSoftLimit; 291 292 const size_t mDimensionHardLimit; 293 294 const bool mUseAbsoluteValueOnReset; 295 296 const ValueMetric::AggregationType mAggregationType; 297 298 const bool mUseDiff; 299 300 const ValueMetric::ValueDirection mValueDirection; 301 302 const bool mSkipZeroDiffOutput; 303 304 // If true, use a zero value as base to compute the diff. 305 // This is used for new keys which are present in the new data but was not 306 // present in the base data. 307 // The default base will only be used if we have a global base. 308 const bool mUseZeroDefaultBase; 309 310 // For pulled metrics, this is always set to true whenever a pull succeeds. 311 // It is set to false when a pull fails, or upon condition change to false. 312 // This is used to decide if we have the right base data to compute the 313 // diff against. 314 bool mHasGlobalBase; 315 316 // This is to track whether or not the bucket is skipped for any of the reasons listed in 317 // BucketDropReason, many of which make the bucket potentially invalid. 318 bool mCurrentBucketIsSkipped; 319 320 const int64_t mMaxPullDelayNs; 321 322 const bool mSplitBucketForAppUpgrade; 323 324 ConditionTimer mConditionTimer; 325 326 FRIEND_TEST(ValueMetricProducerTest, TestAnomalyDetection); 327 FRIEND_TEST(ValueMetricProducerTest, TestBaseSetOnConditionChange); 328 FRIEND_TEST(ValueMetricProducerTest, TestBucketBoundariesOnConditionChange); 329 FRIEND_TEST(ValueMetricProducerTest, TestBucketBoundaryNoCondition); 330 FRIEND_TEST(ValueMetricProducerTest, TestBucketBoundaryWithCondition); 331 FRIEND_TEST(ValueMetricProducerTest, TestBucketBoundaryWithCondition2); 332 FRIEND_TEST(ValueMetricProducerTest, TestBucketInvalidIfGlobalBaseIsNotSet); 333 FRIEND_TEST(ValueMetricProducerTest, TestCalcPreviousBucketEndTime); 334 FRIEND_TEST(ValueMetricProducerTest, TestDataIsNotUpdatedWhenNoConditionChanged); 335 FRIEND_TEST(ValueMetricProducerTest, TestEmptyDataResetsBase_onBucketBoundary); 336 FRIEND_TEST(ValueMetricProducerTest, TestEmptyDataResetsBase_onConditionChanged); 337 FRIEND_TEST(ValueMetricProducerTest, TestEmptyDataResetsBase_onDataPulled); 338 FRIEND_TEST(ValueMetricProducerTest, TestEventsWithNonSlicedCondition); 339 FRIEND_TEST(ValueMetricProducerTest, TestFirstBucket); 340 FRIEND_TEST(ValueMetricProducerTest, TestLateOnDataPulledWithDiff); 341 FRIEND_TEST(ValueMetricProducerTest, TestLateOnDataPulledWithoutDiff); 342 FRIEND_TEST(ValueMetricProducerTest, TestPartialResetOnBucketBoundaries); 343 FRIEND_TEST(ValueMetricProducerTest, TestPulledData_noDiff_bucketBoundaryFalse); 344 FRIEND_TEST(ValueMetricProducerTest, TestPulledData_noDiff_bucketBoundaryTrue); 345 FRIEND_TEST(ValueMetricProducerTest, TestPulledData_noDiff_withFailure); 346 FRIEND_TEST(ValueMetricProducerTest, TestPulledData_noDiff_withMultipleConditionChanges); 347 FRIEND_TEST(ValueMetricProducerTest, TestPulledData_noDiff_withoutCondition); 348 FRIEND_TEST(ValueMetricProducerTest, TestPulledEventsNoCondition); 349 FRIEND_TEST(ValueMetricProducerTest, TestPulledEventsTakeAbsoluteValueOnReset); 350 FRIEND_TEST(ValueMetricProducerTest, TestPulledEventsTakeZeroOnReset); 351 FRIEND_TEST(ValueMetricProducerTest, TestPulledEventsWithFiltering); 352 FRIEND_TEST(ValueMetricProducerTest, TestPulledWithAppUpgradeDisabled); 353 FRIEND_TEST(ValueMetricProducerTest, TestPushedAggregateAvg); 354 FRIEND_TEST(ValueMetricProducerTest, TestPushedAggregateMax); 355 FRIEND_TEST(ValueMetricProducerTest, TestPushedAggregateMin); 356 FRIEND_TEST(ValueMetricProducerTest, TestPushedAggregateSum); 357 FRIEND_TEST(ValueMetricProducerTest, TestPushedEventsWithCondition); 358 FRIEND_TEST(ValueMetricProducerTest, TestPushedEventsWithoutCondition); 359 FRIEND_TEST(ValueMetricProducerTest, TestResetBaseOnPullDelayExceeded); 360 FRIEND_TEST(ValueMetricProducerTest, TestResetBaseOnPullFailAfterConditionChange); 361 FRIEND_TEST(ValueMetricProducerTest, TestResetBaseOnPullFailAfterConditionChange_EndOfBucket); 362 FRIEND_TEST(ValueMetricProducerTest, TestResetBaseOnPullFailBeforeConditionChange); 363 FRIEND_TEST(ValueMetricProducerTest, TestResetBaseOnPullTooLate); 364 FRIEND_TEST(ValueMetricProducerTest, TestSkipZeroDiffOutput); 365 FRIEND_TEST(ValueMetricProducerTest, TestSkipZeroDiffOutputMultiValue); 366 FRIEND_TEST(ValueMetricProducerTest, TestSlicedState); 367 FRIEND_TEST(ValueMetricProducerTest, TestSlicedStateWithMap); 368 FRIEND_TEST(ValueMetricProducerTest, TestSlicedStateWithPrimaryField_WithDimensions); 369 FRIEND_TEST(ValueMetricProducerTest, TestSlicedStateWithCondition); 370 FRIEND_TEST(ValueMetricProducerTest, TestTrimUnusedDimensionKey); 371 FRIEND_TEST(ValueMetricProducerTest, TestUseZeroDefaultBase); 372 FRIEND_TEST(ValueMetricProducerTest, TestUseZeroDefaultBaseWithPullFailures); 373 FRIEND_TEST(ValueMetricProducerTest, TestSlicedStateWithMultipleDimensions); 374 FRIEND_TEST(ValueMetricProducerTest, TestSlicedStateWithMissingDataInStateChange); 375 FRIEND_TEST(ValueMetricProducerTest, TestSlicedStateWithDataMissingInConditionChange); 376 FRIEND_TEST(ValueMetricProducerTest, TestSlicedStateWithMissingDataThenFlushBucket); 377 FRIEND_TEST(ValueMetricProducerTest, TestSlicedStateWithNoPullOnBucketBoundary); 378 FRIEND_TEST(ValueMetricProducerTest, TestUploadThreshold); 379 380 FRIEND_TEST(ValueMetricProducerTest_BucketDrop, TestInvalidBucketWhenOneConditionFailed); 381 FRIEND_TEST(ValueMetricProducerTest_BucketDrop, TestInvalidBucketWhenInitialPullFailed); 382 FRIEND_TEST(ValueMetricProducerTest_BucketDrop, TestInvalidBucketWhenLastPullFailed); 383 FRIEND_TEST(ValueMetricProducerTest_BucketDrop, TestInvalidBucketWhenGuardRailHit); 384 FRIEND_TEST(ValueMetricProducerTest_BucketDrop, 385 TestInvalidBucketWhenAccumulateEventWrongBucket); 386 387 FRIEND_TEST(ValueMetricProducerTest_PartialBucket, TestBucketBoundariesOnPartialBucket); 388 FRIEND_TEST(ValueMetricProducerTest_PartialBucket, TestFullBucketResetWhenLastBucketInvalid); 389 FRIEND_TEST(ValueMetricProducerTest_PartialBucket, TestPartialBucketCreated); 390 FRIEND_TEST(ValueMetricProducerTest_PartialBucket, TestPushedEvents); 391 FRIEND_TEST(ValueMetricProducerTest_PartialBucket, TestPulledValue); 392 FRIEND_TEST(ValueMetricProducerTest_PartialBucket, TestPulledValueWhileConditionFalse); 393 394 FRIEND_TEST(ConfigUpdateTest, TestUpdateValueMetrics); 395 396 friend class ValueMetricProducerTestHelper; 397 }; 398 399 } // namespace statsd 400 } // namespace os 401 } // namespace android 402