blob: 35c6d373418ebb6b297900cc8988adc555306133 [file] [log] [blame]
Yao Chen729093d2017-10-16 10:33:26 -07001/*
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
Yao Chen3c0b95c2017-12-16 14:34:20 -080017#define DEBUG false
Yao Chen5154a3792017-10-30 22:57:06 -070018
Yao Chen729093d2017-10-16 10:33:26 -070019#include "Log.h"
Yao Chen5154a3792017-10-30 22:57:06 -070020#include "DurationMetricProducer.h"
Yao Chenb3561512017-11-21 18:07:17 -080021#include "guardrail/StatsdStats.h"
Yao Chen729093d2017-10-16 10:33:26 -070022#include "stats_util.h"
Yangster-mac20877162017-12-22 17:19:39 -080023#include "stats_log_util.h"
Yao Chen729093d2017-10-16 10:33:26 -070024
Yao Chen729093d2017-10-16 10:33:26 -070025#include <limits.h>
26#include <stdlib.h>
27
yrob0378b02017-11-09 20:36:25 -080028using android::util::FIELD_COUNT_REPEATED;
yro2b0f8862017-11-06 14:27:31 -080029using android::util::FIELD_TYPE_BOOL;
30using android::util::FIELD_TYPE_FLOAT;
31using android::util::FIELD_TYPE_INT32;
32using android::util::FIELD_TYPE_INT64;
33using android::util::FIELD_TYPE_MESSAGE;
Yangster-macd1815dc2017-11-13 21:43:15 -080034using android::util::FIELD_TYPE_STRING;
yro2b0f8862017-11-06 14:27:31 -080035using android::util::ProtoOutputStream;
Yao Chen729093d2017-10-16 10:33:26 -070036using std::string;
37using std::unordered_map;
38using std::vector;
Ruchir Rastogi21a287b2019-10-02 12:04:33 -070039using std::shared_ptr;
Yao Chen729093d2017-10-16 10:33:26 -070040
41namespace android {
42namespace os {
43namespace statsd {
44
yro2b0f8862017-11-06 14:27:31 -080045// for StatsLogReport
Yangster-mac94e197c2018-01-02 16:03:03 -080046const int FIELD_ID_ID = 1;
yro2b0f8862017-11-06 14:27:31 -080047const int FIELD_ID_DURATION_METRICS = 6;
Yangster-mac9def8e32018-04-17 13:55:51 -070048const int FIELD_ID_TIME_BASE = 9;
49const int FIELD_ID_BUCKET_SIZE = 10;
50const int FIELD_ID_DIMENSION_PATH_IN_WHAT = 11;
Howard Ro9440e092018-12-16 19:15:21 -080051const int FIELD_ID_IS_ACTIVE = 14;
yro2b0f8862017-11-06 14:27:31 -080052// for DurationMetricDataWrapper
53const int FIELD_ID_DATA = 1;
54// for DurationMetricData
Yangster-mac468ff042018-01-17 12:26:34 -080055const int FIELD_ID_DIMENSION_IN_WHAT = 1;
Yangster-mac468ff042018-01-17 12:26:34 -080056const int FIELD_ID_BUCKET_INFO = 3;
Yangster-mac9def8e32018-04-17 13:55:51 -070057const int FIELD_ID_DIMENSION_LEAF_IN_WHAT = 4;
yro2b0f8862017-11-06 14:27:31 -080058// for DurationBucketInfo
yro2b0f8862017-11-06 14:27:31 -080059const int FIELD_ID_DURATION = 3;
Yangster-mac9def8e32018-04-17 13:55:51 -070060const int FIELD_ID_BUCKET_NUM = 4;
61const int FIELD_ID_START_BUCKET_ELAPSED_MILLIS = 5;
62const int FIELD_ID_END_BUCKET_ELAPSED_MILLIS = 6;
yro2b0f8862017-11-06 14:27:31 -080063
Ruchir Rastogi21a287b2019-10-02 12:04:33 -070064DurationMetricProducer::DurationMetricProducer(
65 const ConfigKey& key, const DurationMetric& metric, const int conditionIndex,
66 const size_t startIndex, const size_t stopIndex, const size_t stopAllIndex,
67 const bool nesting, const sp<ConditionWizard>& wizard,
68 const FieldMatcher& internalDimensions, const int64_t timeBaseNs, const int64_t startTimeNs,
69 const unordered_map<int, shared_ptr<Activation>>& eventActivationMap,
tsaichristined21aacf2019-10-07 14:47:38 -070070 const unordered_map<int, vector<shared_ptr<Activation>>>& eventDeactivationMap,
71 const vector<int>& slicedStateAtoms,
72 const unordered_map<int, unordered_map<int, int64_t>>& stateGroupMap)
Ruchir Rastogi21a287b2019-10-02 12:04:33 -070073 : MetricProducer(metric.id(), key, timeBaseNs, conditionIndex, wizard, eventActivationMap,
tsaichristined21aacf2019-10-07 14:47:38 -070074 eventDeactivationMap, slicedStateAtoms, stateGroupMap),
Yao Chenf09569f2017-12-13 17:00:51 -080075 mAggregationType(metric.aggregation_type()),
Yao Chen729093d2017-10-16 10:33:26 -070076 mStartIndex(startIndex),
77 mStopIndex(stopIndex),
Yao Chen5154a3792017-10-30 22:57:06 -070078 mStopAllIndex(stopAllIndex),
Yangster13fb7e42018-03-07 17:30:49 -080079 mNested(nesting),
80 mContainANYPositionInInternalDimensions(false) {
Yangster-macb8144812018-01-04 10:56:23 -080081 if (metric.has_bucket()) {
yro59cc24d2018-02-13 20:17:32 -080082 mBucketSizeNs =
83 TimeUnitToBucketSizeInMillisGuardrailed(key.GetUid(), metric.bucket()) * 1000000;
Yao Chen729093d2017-10-16 10:33:26 -070084 } else {
85 mBucketSizeNs = LLONG_MAX;
86 }
87
Yao Chen8a8d16c2018-02-08 14:50:40 -080088 if (metric.has_dimensions_in_what()) {
89 translateFieldMatcher(metric.dimensions_in_what(), &mDimensionsInWhat);
Yangster13fb7e42018-03-07 17:30:49 -080090 mContainANYPositionInDimensionsInWhat = HasPositionANY(metric.dimensions_in_what());
Yao Chen8a8d16c2018-02-08 14:50:40 -080091 }
92
93 if (internalDimensions.has_field()) {
94 translateFieldMatcher(internalDimensions, &mInternalDimensions);
Yangster13fb7e42018-03-07 17:30:49 -080095 mContainANYPositionInInternalDimensions = HasPositionANY(internalDimensions);
Yao Chen8a8d16c2018-02-08 14:50:40 -080096 }
Yangster-mace06cfd72018-03-10 23:22:59 -080097 if (mContainANYPositionInInternalDimensions) {
98 ALOGE("Position ANY in internal dimension not supported.");
99 }
100 if (mContainANYPositionInDimensionsInWhat) {
101 ALOGE("Position ANY in dimension_in_what not supported.");
102 }
Yao Chen8a8d16c2018-02-08 14:50:40 -0800103
tsaichristine76853372019-08-06 17:17:03 -0700104 mSliceByPositionALL = HasPositionALL(metric.dimensions_in_what());
Yangster-mac9def8e32018-04-17 13:55:51 -0700105
Yao Chen729093d2017-10-16 10:33:26 -0700106 if (metric.links().size() > 0) {
Yao Chen8a8d16c2018-02-08 14:50:40 -0800107 for (const auto& link : metric.links()) {
108 Metric2Condition mc;
109 mc.conditionId = link.condition();
110 translateFieldMatcher(link.fields_in_what(), &mc.metricFields);
111 translateFieldMatcher(link.fields_in_condition(), &mc.conditionFields);
112 mMetric2ConditionLinks.push_back(mc);
113 }
tsaichristine76853372019-08-06 17:17:03 -0700114 mConditionSliced = true;
Yao Chen729093d2017-10-16 10:33:26 -0700115 }
Yangster13fb7e42018-03-07 17:30:49 -0800116 mUnSlicedPartCondition = ConditionState::kUnknown;
Yao Chen729093d2017-10-16 10:33:26 -0700117
Yangster13fb7e42018-03-07 17:30:49 -0800118 mUseWhatDimensionAsInternalDimension = equalDimensions(mDimensionsInWhat, mInternalDimensions);
tsaichristine76853372019-08-06 17:17:03 -0700119 if (mWizard != nullptr && mConditionTrackerIndex >= 0 &&
120 mMetric2ConditionLinks.size() == 1) {
tsaichristine69000e62019-10-18 17:34:52 -0700121 mHasLinksToAllConditionDimensionsInTracker = mWizard->equalOutputDimensions(
122 mConditionTrackerIndex, mMetric2ConditionLinks.begin()->conditionFields);
Yangster-mac53928882018-02-25 23:02:56 -0800123 }
Chenjie Yue1361ed2018-07-23 17:33:09 -0700124 flushIfNeededLocked(startTimeNs);
125 // Adjust start for partial bucket
126 mCurrentBucketStartTimeNs = startTimeNs;
Yangster-mac94e197c2018-01-02 16:03:03 -0800127 VLOG("metric %lld created. bucket size %lld start_time: %lld", (long long)metric.id(),
Yangster-mac15f6bbc2018-04-08 11:52:26 -0700128 (long long)mBucketSizeNs, (long long)mTimeBaseNs);
Yao Chen729093d2017-10-16 10:33:26 -0700129}
130
131DurationMetricProducer::~DurationMetricProducer() {
132 VLOG("~DurationMetric() called");
133}
134
Yangster-mac932ecec2018-02-01 10:23:52 -0800135sp<AnomalyTracker> DurationMetricProducer::addAnomalyTracker(
136 const Alert &alert, const sp<AlarmMonitor>& anomalyAlarmMonitor) {
Bookatz857aaa52017-12-19 15:29:06 -0800137 std::lock_guard<std::mutex> lock(mMutex);
Bookatz423f7532018-03-08 15:45:14 -0800138 if (mAggregationType == DurationMetric_AggregationType_SUM) {
139 if (alert.trigger_if_sum_gt() > alert.num_buckets() * mBucketSizeNs) {
140 ALOGW("invalid alert for SUM: threshold (%f) > possible recordable value (%d x %lld)",
141 alert.trigger_if_sum_gt(), alert.num_buckets(), (long long)mBucketSizeNs);
142 return nullptr;
143 }
144 }
Yangster-mac932ecec2018-02-01 10:23:52 -0800145 sp<DurationAnomalyTracker> anomalyTracker =
146 new DurationAnomalyTracker(alert, mConfigKey, anomalyAlarmMonitor);
Bookatz857aaa52017-12-19 15:29:06 -0800147 if (anomalyTracker != nullptr) {
148 mAnomalyTrackers.push_back(anomalyTracker);
149 }
150 return anomalyTracker;
Bookatz450099d2017-11-30 17:09:30 -0800151}
152
Yao Chen5154a3792017-10-30 22:57:06 -0700153unique_ptr<DurationTracker> DurationMetricProducer::createDurationTracker(
Yangster-mac93694462018-01-22 20:49:31 -0800154 const MetricDimensionKey& eventKey) const {
Yao Chenf09569f2017-12-13 17:00:51 -0800155 switch (mAggregationType) {
Stefan Lafoncfed20b2017-11-18 09:26:53 -0800156 case DurationMetric_AggregationType_SUM:
Yao Chenb3561512017-11-21 18:07:17 -0800157 return make_unique<OringDurationTracker>(
Yangster-mac93694462018-01-22 20:49:31 -0800158 mConfigKey, mMetricId, eventKey, mWizard, mConditionTrackerIndex,
tsaichristine76853372019-08-06 17:17:03 -0700159 mNested, mCurrentBucketStartTimeNs, mCurrentBucketNum,
Yangster-mac15f6bbc2018-04-08 11:52:26 -0700160 mTimeBaseNs, mBucketSizeNs, mConditionSliced,
Yangster13fb7e42018-03-07 17:30:49 -0800161 mHasLinksToAllConditionDimensionsInTracker, mAnomalyTrackers);
Stefan Lafoncfed20b2017-11-18 09:26:53 -0800162 case DurationMetric_AggregationType_MAX_SPARSE:
Yao Chenb3561512017-11-21 18:07:17 -0800163 return make_unique<MaxDurationTracker>(
Yangster-mac93694462018-01-22 20:49:31 -0800164 mConfigKey, mMetricId, eventKey, mWizard, mConditionTrackerIndex,
tsaichristine76853372019-08-06 17:17:03 -0700165 mNested, mCurrentBucketStartTimeNs, mCurrentBucketNum,
Yangster-mac15f6bbc2018-04-08 11:52:26 -0700166 mTimeBaseNs, mBucketSizeNs, mConditionSliced,
Yangster13fb7e42018-03-07 17:30:49 -0800167 mHasLinksToAllConditionDimensionsInTracker, mAnomalyTrackers);
168 }
169}
170
171// SlicedConditionChange optimization case 1:
172// 1. If combination condition, logical operation is AND, only one sliced child predicate.
tsaichristine76853372019-08-06 17:17:03 -0700173// 2. The links covers all dimension fields in the sliced child condition predicate.
Yao Chen427d3722018-03-22 15:21:52 -0700174void DurationMetricProducer::onSlicedConditionMayChangeLocked_opt1(bool condition,
Yangster-macb142cc82018-03-30 15:22:08 -0700175 const int64_t eventTime) {
Yangster13fb7e42018-03-07 17:30:49 -0800176 if (mMetric2ConditionLinks.size() != 1 ||
tsaichristine76853372019-08-06 17:17:03 -0700177 !mHasLinksToAllConditionDimensionsInTracker) {
Yangster13fb7e42018-03-07 17:30:49 -0800178 return;
179 }
180
181 bool currentUnSlicedPartCondition = true;
182 if (!mWizard->IsSimpleCondition(mConditionTrackerIndex)) {
183 ConditionState unslicedPartState =
184 mWizard->getUnSlicedPartConditionState(mConditionTrackerIndex);
185 // When the unsliced part is still false, return directly.
186 if (mUnSlicedPartCondition == ConditionState::kFalse &&
187 unslicedPartState == ConditionState::kFalse) {
188 return;
189 }
190 mUnSlicedPartCondition = unslicedPartState;
191 currentUnSlicedPartCondition = mUnSlicedPartCondition > 0;
192 }
193
194 auto dimensionsChangedToTrue = mWizard->getChangedToTrueDimensions(mConditionTrackerIndex);
195 auto dimensionsChangedToFalse = mWizard->getChangedToFalseDimensions(mConditionTrackerIndex);
196
197 // The condition change is from the unsliced predicates.
198 // We need to find out the true dimensions from the sliced predicate and flip their condition
199 // state based on the new unsliced condition state.
200 if (dimensionsChangedToTrue == nullptr || dimensionsChangedToFalse == nullptr ||
201 (dimensionsChangedToTrue->empty() && dimensionsChangedToFalse->empty())) {
202 std::set<HashableDimensionKey> trueConditionDimensions;
203 mWizard->getTrueSlicedDimensions(mConditionTrackerIndex, &trueConditionDimensions);
204 for (auto& whatIt : mCurrentSlicedDurationTrackerMap) {
205 HashableDimensionKey linkedConditionDimensionKey;
tsaichristine69000e62019-10-18 17:34:52 -0700206 getDimensionForCondition(whatIt.first.getValues(), mMetric2ConditionLinks[0],
Yangster13fb7e42018-03-07 17:30:49 -0800207 &linkedConditionDimensionKey);
208 if (trueConditionDimensions.find(linkedConditionDimensionKey) !=
209 trueConditionDimensions.end()) {
210 for (auto& condIt : whatIt.second) {
211 condIt.second->onConditionChanged(
Muhammad Qureshi18e46922019-05-24 16:38:49 -0700212 currentUnSlicedPartCondition, eventTime);
Yangster13fb7e42018-03-07 17:30:49 -0800213 }
214 }
215 }
216 } else {
217 // Handle the condition change from the sliced predicate.
218 if (currentUnSlicedPartCondition) {
219 for (auto& whatIt : mCurrentSlicedDurationTrackerMap) {
220 HashableDimensionKey linkedConditionDimensionKey;
tsaichristine69000e62019-10-18 17:34:52 -0700221 getDimensionForCondition(whatIt.first.getValues(), mMetric2ConditionLinks[0],
Yangster13fb7e42018-03-07 17:30:49 -0800222 &linkedConditionDimensionKey);
223 if (dimensionsChangedToTrue->find(linkedConditionDimensionKey) !=
224 dimensionsChangedToTrue->end()) {
225 for (auto& condIt : whatIt.second) {
226 condIt.second->onConditionChanged(true, eventTime);
227 }
228 }
229 if (dimensionsChangedToFalse->find(linkedConditionDimensionKey) !=
230 dimensionsChangedToFalse->end()) {
231 for (auto& condIt : whatIt.second) {
232 condIt.second->onConditionChanged(false, eventTime);
233 }
234 }
235 }
236 }
237 }
238}
239
Muhammad Qureshi18e46922019-05-24 16:38:49 -0700240void DurationMetricProducer::onSlicedConditionMayChangeInternalLocked(bool overallCondition,
241 const int64_t eventTimeNs) {
Yangster13fb7e42018-03-07 17:30:49 -0800242 bool changeDimTrackable = mWizard->IsChangedDimensionTrackable(mConditionTrackerIndex);
tsaichristine76853372019-08-06 17:17:03 -0700243 if (changeDimTrackable && mHasLinksToAllConditionDimensionsInTracker) {
Muhammad Qureshi18e46922019-05-24 16:38:49 -0700244 onSlicedConditionMayChangeLocked_opt1(overallCondition, eventTimeNs);
Yangster13fb7e42018-03-07 17:30:49 -0800245 return;
246 }
247
Yao Chen729093d2017-10-16 10:33:26 -0700248 // Now for each of the on-going event, check if the condition has changed for them.
Yangster-mac53928882018-02-25 23:02:56 -0800249 for (auto& whatIt : mCurrentSlicedDurationTrackerMap) {
250 for (auto& pair : whatIt.second) {
Muhammad Qureshi18e46922019-05-24 16:38:49 -0700251 pair.second->onSlicedConditionMayChange(overallCondition, eventTimeNs);
Yangster-mac53928882018-02-25 23:02:56 -0800252 }
Yao Chen729093d2017-10-16 10:33:26 -0700253 }
254}
255
Muhammad Qureshi18e46922019-05-24 16:38:49 -0700256void DurationMetricProducer::onSlicedConditionMayChangeLocked(bool overallCondition,
257 const int64_t eventTime) {
258 VLOG("Metric %lld onSlicedConditionMayChange", (long long)mMetricId);
259
260 if (!mIsActive) {
261 return;
262 }
263
264 flushIfNeededLocked(eventTime);
265
266 if (!mConditionSliced) {
267 return;
268 }
269
270 onSlicedConditionMayChangeInternalLocked(overallCondition, eventTime);
271}
272
273void DurationMetricProducer::onActiveStateChangedLocked(const int64_t& eventTimeNs) {
274 MetricProducer::onActiveStateChangedLocked(eventTimeNs);
275
276 if (!mConditionSliced) {
277 if (ConditionState::kTrue != mCondition) {
278 return;
279 }
280
281 if (mIsActive) {
282 flushIfNeededLocked(eventTimeNs);
283 }
284
285 for (auto& whatIt : mCurrentSlicedDurationTrackerMap) {
286 for (auto& pair : whatIt.second) {
287 pair.second->onConditionChanged(mIsActive, eventTimeNs);
288 }
289 }
290 } else if (mIsActive) {
291 flushIfNeededLocked(eventTimeNs);
292 onSlicedConditionMayChangeInternalLocked(mIsActive, eventTimeNs);
293 } else { // mConditionSliced == true && !mIsActive
294 for (auto& whatIt : mCurrentSlicedDurationTrackerMap) {
295 for (auto& pair : whatIt.second) {
296 pair.second->onConditionChanged(mIsActive, eventTimeNs);
297 }
298 }
299 }
300}
301
Yangsterf2bee6f2017-11-29 12:01:05 -0800302void DurationMetricProducer::onConditionChangedLocked(const bool conditionMet,
Yangster-macb142cc82018-03-30 15:22:08 -0700303 const int64_t eventTime) {
Yangster-mac94e197c2018-01-02 16:03:03 -0800304 VLOG("Metric %lld onConditionChanged", (long long)mMetricId);
Olivier Gaillarde63d9e02019-02-12 14:43:59 +0000305 mCondition = conditionMet ? ConditionState::kTrue : ConditionState::kFalse;
Muhammad Qureshi18e46922019-05-24 16:38:49 -0700306
307 if (!mIsActive) {
308 return;
309 }
310
Yangsterf2bee6f2017-11-29 12:01:05 -0800311 flushIfNeededLocked(eventTime);
Yangster-mac53928882018-02-25 23:02:56 -0800312 for (auto& whatIt : mCurrentSlicedDurationTrackerMap) {
313 for (auto& pair : whatIt.second) {
314 pair.second->onConditionChanged(conditionMet, eventTime);
315 }
Yao Chen729093d2017-10-16 10:33:26 -0700316 }
317}
318
Yangster-macb142cc82018-03-30 15:22:08 -0700319void DurationMetricProducer::dropDataLocked(const int64_t dropTimeNs) {
Yao Chen06dba5d2018-01-26 13:38:16 -0800320 flushIfNeededLocked(dropTimeNs);
Olivier Gaillard320952b2019-02-06 13:57:24 +0000321 StatsdStats::getInstance().noteBucketDropped(mMetricId);
Yao Chen06dba5d2018-01-26 13:38:16 -0800322 mPastBuckets.clear();
323}
324
Yangster-maca802d732018-04-24 07:50:38 -0700325void DurationMetricProducer::clearPastBucketsLocked(const int64_t dumpTimeNs) {
326 flushIfNeededLocked(dumpTimeNs);
327 mPastBuckets.clear();
328}
329
Yangster-macb142cc82018-03-30 15:22:08 -0700330void DurationMetricProducer::onDumpReportLocked(const int64_t dumpTimeNs,
Yangster-mace68f3a52018-04-04 00:01:43 -0700331 const bool include_current_partial_bucket,
Bookatzff71cad2018-09-20 17:17:49 -0700332 const bool erase_data,
Olivier Gaillard6c75ecd2019-02-20 09:57:33 +0000333 const DumpLatency dumpLatency,
Yangster-mac9def8e32018-04-17 13:55:51 -0700334 std::set<string> *str_set,
Yao Chen288c6002017-12-12 13:43:18 -0800335 ProtoOutputStream* protoOutput) {
Yangster-mace68f3a52018-04-04 00:01:43 -0700336 if (include_current_partial_bucket) {
337 flushLocked(dumpTimeNs);
338 } else {
339 flushIfNeededLocked(dumpTimeNs);
340 }
Yang Lub4722912018-11-15 11:02:03 -0800341 protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_ID, (long long)mMetricId);
Howard Ro07e23ff2018-12-17 17:28:07 -0800342 protoOutput->write(FIELD_TYPE_BOOL | FIELD_ID_IS_ACTIVE, isActiveLocked());
Yang Lub4722912018-11-15 11:02:03 -0800343
Yangster-mac635b4b32018-01-23 20:17:35 -0800344 if (mPastBuckets.empty()) {
Yao Chen8a8d16c2018-02-08 14:50:40 -0800345 VLOG(" Duration metric, empty return");
Yangster-mac635b4b32018-01-23 20:17:35 -0800346 return;
347 }
Yao Chen6a8c7992017-11-29 20:02:07 +0000348
Yangster-mac9def8e32018-04-17 13:55:51 -0700349 protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_TIME_BASE, (long long)mTimeBaseNs);
350 protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_BUCKET_SIZE, (long long)mBucketSizeNs);
351
352 if (!mSliceByPositionALL) {
353 if (!mDimensionsInWhat.empty()) {
354 uint64_t dimenPathToken = protoOutput->start(
355 FIELD_TYPE_MESSAGE | FIELD_ID_DIMENSION_PATH_IN_WHAT);
356 writeDimensionPathToProto(mDimensionsInWhat, protoOutput);
357 protoOutput->end(dimenPathToken);
358 }
Yangster-mac9def8e32018-04-17 13:55:51 -0700359 }
360
Yi Jin5ee07872018-03-05 18:18:27 -0800361 uint64_t protoToken = protoOutput->start(FIELD_TYPE_MESSAGE | FIELD_ID_DURATION_METRICS);
Yao Chen288c6002017-12-12 13:43:18 -0800362
Yao Chen8a8d16c2018-02-08 14:50:40 -0800363 VLOG("Duration metric %lld dump report now...", (long long)mMetricId);
Yao Chen6a8c7992017-11-29 20:02:07 +0000364
Yao Chen729093d2017-10-16 10:33:26 -0700365 for (const auto& pair : mPastBuckets) {
Yangster-mac93694462018-01-22 20:49:31 -0800366 const MetricDimensionKey& dimensionKey = pair.first;
Yangster13fb7e42018-03-07 17:30:49 -0800367 VLOG(" dimension key %s", dimensionKey.toString().c_str());
Yao Chen1ff4f432017-11-16 17:01:40 -0800368
Yi Jin5ee07872018-03-05 18:18:27 -0800369 uint64_t wrapperToken =
Yao Chen288c6002017-12-12 13:43:18 -0800370 protoOutput->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_DATA);
yro2b0f8862017-11-06 14:27:31 -0800371
Yangster-mac20877162017-12-22 17:19:39 -0800372 // First fill dimension.
Yangster-mac9def8e32018-04-17 13:55:51 -0700373 if (mSliceByPositionALL) {
374 uint64_t dimensionToken = protoOutput->start(
375 FIELD_TYPE_MESSAGE | FIELD_ID_DIMENSION_IN_WHAT);
376 writeDimensionToProto(dimensionKey.getDimensionKeyInWhat(), str_set, protoOutput);
377 protoOutput->end(dimensionToken);
Yangster-mac9def8e32018-04-17 13:55:51 -0700378 } else {
379 writeDimensionLeafNodesToProto(dimensionKey.getDimensionKeyInWhat(),
380 FIELD_ID_DIMENSION_LEAF_IN_WHAT, str_set, protoOutput);
Yangster-mac93694462018-01-22 20:49:31 -0800381 }
yro2b0f8862017-11-06 14:27:31 -0800382 // Then fill bucket_info (DurationBucketInfo).
383 for (const auto& bucket : pair.second) {
Yi Jin5ee07872018-03-05 18:18:27 -0800384 uint64_t bucketInfoToken = protoOutput->start(
Yao Chen288c6002017-12-12 13:43:18 -0800385 FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_BUCKET_INFO);
Yangster-mac9def8e32018-04-17 13:55:51 -0700386 if (bucket.mBucketEndNs - bucket.mBucketStartNs != mBucketSizeNs) {
387 protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_START_BUCKET_ELAPSED_MILLIS,
388 (long long)NanoToMillis(bucket.mBucketStartNs));
389 protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_END_BUCKET_ELAPSED_MILLIS,
390 (long long)NanoToMillis(bucket.mBucketEndNs));
391 } else {
392 protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_BUCKET_NUM,
393 (long long)(getBucketNumFromEndTimeNs(bucket.mBucketEndNs)));
394 }
Yao Chen288c6002017-12-12 13:43:18 -0800395 protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_DURATION, (long long)bucket.mDuration);
396 protoOutput->end(bucketInfoToken);
yro2b0f8862017-11-06 14:27:31 -0800397 VLOG("\t bucket [%lld - %lld] duration: %lld", (long long)bucket.mBucketStartNs,
398 (long long)bucket.mBucketEndNs, (long long)bucket.mDuration);
399 }
400
Yao Chen288c6002017-12-12 13:43:18 -0800401 protoOutput->end(wrapperToken);
Yao Chen729093d2017-10-16 10:33:26 -0700402 }
yro2b0f8862017-11-06 14:27:31 -0800403
Yao Chen288c6002017-12-12 13:43:18 -0800404 protoOutput->end(protoToken);
Bookatzff71cad2018-09-20 17:17:49 -0700405 if (erase_data) {
406 mPastBuckets.clear();
407 }
yro2b0f8862017-11-06 14:27:31 -0800408}
Yao Chen729093d2017-10-16 10:33:26 -0700409
Yangster-macb142cc82018-03-30 15:22:08 -0700410void DurationMetricProducer::flushIfNeededLocked(const int64_t& eventTimeNs) {
411 int64_t currentBucketEndTimeNs = getCurrentBucketEndTimeNs();
David Chen27785a82018-01-19 17:06:45 -0800412
413 if (currentBucketEndTimeNs > eventTimeNs) {
Yao Chen729093d2017-10-16 10:33:26 -0700414 return;
415 }
Yao Chen5154a3792017-10-30 22:57:06 -0700416 VLOG("flushing...........");
David Chen27785a82018-01-19 17:06:45 -0800417 int numBucketsForward = 1 + (eventTimeNs - currentBucketEndTimeNs) / mBucketSizeNs;
Muhammad Qureshi902529a2019-03-14 16:03:21 -0700418 int64_t nextBucketNs = currentBucketEndTimeNs + (numBucketsForward - 1) * mBucketSizeNs;
419 flushCurrentBucketLocked(eventTimeNs, nextBucketNs);
420
Yangster-mace2cd6d52017-11-09 20:38:30 -0800421 mCurrentBucketNum += numBucketsForward;
Yao Chen5154a3792017-10-30 22:57:06 -0700422}
423
Olivier Gaillard6c75ecd2019-02-20 09:57:33 +0000424void DurationMetricProducer::flushCurrentBucketLocked(const int64_t& eventTimeNs,
425 const int64_t& nextBucketStartTimeNs) {
Yangster-mac53928882018-02-25 23:02:56 -0800426 for (auto whatIt = mCurrentSlicedDurationTrackerMap.begin();
427 whatIt != mCurrentSlicedDurationTrackerMap.end();) {
428 for (auto it = whatIt->second.begin(); it != whatIt->second.end();) {
429 if (it->second->flushCurrentBucket(eventTimeNs, &mPastBuckets)) {
Yangster13fb7e42018-03-07 17:30:49 -0800430 VLOG("erase bucket for key %s %s", whatIt->first.toString().c_str(),
431 it->first.toString().c_str());
Yangster-mac53928882018-02-25 23:02:56 -0800432 it = whatIt->second.erase(it);
433 } else {
434 ++it;
435 }
436 }
437 if (whatIt->second.empty()) {
438 whatIt = mCurrentSlicedDurationTrackerMap.erase(whatIt);
David Chen27785a82018-01-19 17:06:45 -0800439 } else {
Yangster-mac53928882018-02-25 23:02:56 -0800440 whatIt++;
David Chen27785a82018-01-19 17:06:45 -0800441 }
442 }
Olivier Gaillardf248c0d2019-02-21 15:56:58 +0000443 StatsdStats::getInstance().noteBucketCount(mMetricId);
Muhammad Qureshi902529a2019-03-14 16:03:21 -0700444 mCurrentBucketStartTimeNs = nextBucketStartTimeNs;
David Chen27785a82018-01-19 17:06:45 -0800445}
446
Yao Chen884c8c12018-01-26 10:36:25 -0800447void DurationMetricProducer::dumpStatesLocked(FILE* out, bool verbose) const {
Yangster-mac93694462018-01-22 20:49:31 -0800448 if (mCurrentSlicedDurationTrackerMap.size() == 0) {
Yao Chen884c8c12018-01-26 10:36:25 -0800449 return;
450 }
451
452 fprintf(out, "DurationMetric %lld dimension size %lu\n", (long long)mMetricId,
Yangster-mac93694462018-01-22 20:49:31 -0800453 (unsigned long)mCurrentSlicedDurationTrackerMap.size());
Yao Chen884c8c12018-01-26 10:36:25 -0800454 if (verbose) {
Yangster-mac53928882018-02-25 23:02:56 -0800455 for (const auto& whatIt : mCurrentSlicedDurationTrackerMap) {
456 for (const auto& slice : whatIt.second) {
tsaichristine69000e62019-10-18 17:34:52 -0700457 fprintf(out, "\t(what)%s\t(states)%s\n", whatIt.first.toString().c_str(),
Yangster13fb7e42018-03-07 17:30:49 -0800458 slice.first.toString().c_str());
Yangster-mac53928882018-02-25 23:02:56 -0800459 slice.second->dumpStates(out, verbose);
460 }
Yao Chen884c8c12018-01-26 10:36:25 -0800461 }
462 }
463}
464
Yangster-mac93694462018-01-22 20:49:31 -0800465bool DurationMetricProducer::hitGuardRailLocked(const MetricDimensionKey& newKey) {
Yangster-mac306ccc22018-03-24 15:03:40 -0700466 auto whatIt = mCurrentSlicedDurationTrackerMap.find(newKey.getDimensionKeyInWhat());
467 if (whatIt != mCurrentSlicedDurationTrackerMap.end()) {
tsaichristine69000e62019-10-18 17:34:52 -0700468 auto stateIt = whatIt->second.find(newKey.getStateValuesKey());
469 if (stateIt != whatIt->second.end()) {
Yangster-mac306ccc22018-03-24 15:03:40 -0700470 return false;
471 }
472 if (whatIt->second.size() > StatsdStats::kDimensionKeySizeSoftLimit - 1) {
473 size_t newTupleCount = whatIt->second.size() + 1;
474 StatsdStats::getInstance().noteMetricDimensionInConditionSize(
475 mConfigKey, mMetricId, newTupleCount);
476 // 2. Don't add more tuples, we are above the allowed threshold. Drop the data.
477 if (newTupleCount > StatsdStats::kDimensionKeySizeHardLimit) {
tsaichristine69000e62019-10-18 17:34:52 -0700478 ALOGE("DurationMetric %lld dropping data for state values key %s",
479 (long long)mMetricId, newKey.getStateValuesKey().toString().c_str());
Muhammad Qureshi87348a62019-02-14 16:17:52 -0800480 StatsdStats::getInstance().noteHardDimensionLimitReached(mMetricId);
Yangster-mac306ccc22018-03-24 15:03:40 -0700481 return true;
482 }
483 }
484 } else {
485 // 1. Report the tuple count if the tuple count > soft limit
486 if (mCurrentSlicedDurationTrackerMap.size() > StatsdStats::kDimensionKeySizeSoftLimit - 1) {
487 size_t newTupleCount = mCurrentSlicedDurationTrackerMap.size() + 1;
488 StatsdStats::getInstance().noteMetricDimensionSize(
489 mConfigKey, mMetricId, newTupleCount);
490 // 2. Don't add more tuples, we are above the allowed threshold. Drop the data.
491 if (newTupleCount > StatsdStats::kDimensionKeySizeHardLimit) {
492 ALOGE("DurationMetric %lld dropping data for what dimension key %s",
493 (long long)mMetricId, newKey.getDimensionKeyInWhat().toString().c_str());
Muhammad Qureshi87348a62019-02-14 16:17:52 -0800494 StatsdStats::getInstance().noteHardDimensionLimitReached(mMetricId);
Yangster-mac306ccc22018-03-24 15:03:40 -0700495 return true;
496 }
Yao Chenb3561512017-11-21 18:07:17 -0800497 }
498 }
499 return false;
500}
501
Yangster-mac53928882018-02-25 23:02:56 -0800502void DurationMetricProducer::handleStartEvent(const MetricDimensionKey& eventKey,
503 const ConditionKey& conditionKeys,
504 bool condition, const LogEvent& event) {
505 const auto& whatKey = eventKey.getDimensionKeyInWhat();
tsaichristine69000e62019-10-18 17:34:52 -0700506 const auto& stateKey = eventKey.getStateValuesKey();
Yao Chen5154a3792017-10-30 22:57:06 -0700507
Yangster-mac53928882018-02-25 23:02:56 -0800508 auto whatIt = mCurrentSlicedDurationTrackerMap.find(whatKey);
509 if (whatIt == mCurrentSlicedDurationTrackerMap.end()) {
Yangsterf2bee6f2017-11-29 12:01:05 -0800510 if (hitGuardRailLocked(eventKey)) {
Yao Chenb3561512017-11-21 18:07:17 -0800511 return;
512 }
tsaichristine69000e62019-10-18 17:34:52 -0700513 mCurrentSlicedDurationTrackerMap[whatKey][stateKey] = createDurationTracker(eventKey);
Yangster-mac53928882018-02-25 23:02:56 -0800514 } else {
tsaichristine69000e62019-10-18 17:34:52 -0700515 if (whatIt->second.find(stateKey) == whatIt->second.end()) {
Yangster-mac53928882018-02-25 23:02:56 -0800516 if (hitGuardRailLocked(eventKey)) {
517 return;
518 }
tsaichristine69000e62019-10-18 17:34:52 -0700519 mCurrentSlicedDurationTrackerMap[whatKey][stateKey] = createDurationTracker(eventKey);
Yangster-mac53928882018-02-25 23:02:56 -0800520 }
Yao Chen6a8c7992017-11-29 20:02:07 +0000521 }
Yao Chen5154a3792017-10-30 22:57:06 -0700522
tsaichristine69000e62019-10-18 17:34:52 -0700523 auto it = mCurrentSlicedDurationTrackerMap.find(whatKey)->second.find(stateKey);
Yangster-mac53928882018-02-25 23:02:56 -0800524 if (mUseWhatDimensionAsInternalDimension) {
525 it->second->noteStart(whatKey, condition,
526 event.GetElapsedTimestampNs(), conditionKeys);
527 return;
528 }
Yao Chen5154a3792017-10-30 22:57:06 -0700529
Yangster13fb7e42018-03-07 17:30:49 -0800530 if (mInternalDimensions.empty()) {
Yangster-mac53928882018-02-25 23:02:56 -0800531 it->second->noteStart(DEFAULT_DIMENSION_KEY, condition,
532 event.GetElapsedTimestampNs(), conditionKeys);
Yangster-mac20877162017-12-22 17:19:39 -0800533 } else {
Yangster-mace06cfd72018-03-10 23:22:59 -0800534 HashableDimensionKey dimensionKey = DEFAULT_DIMENSION_KEY;
535 filterValues(mInternalDimensions, event.getValues(), &dimensionKey);
536 it->second->noteStart(
537 dimensionKey, condition, event.GetElapsedTimestampNs(), conditionKeys);
Yao Chen5154a3792017-10-30 22:57:06 -0700538 }
Yangster-mac20877162017-12-22 17:19:39 -0800539
Yao Chen729093d2017-10-16 10:33:26 -0700540}
541
Yangster-mac53928882018-02-25 23:02:56 -0800542void DurationMetricProducer::onMatchedLogEventInternalLocked(
543 const size_t matcherIndex, const MetricDimensionKey& eventKey,
tsaichristinec876b492019-12-10 13:47:05 -0800544 const ConditionKey& conditionKeys, bool condition, const LogEvent& event,
545 const map<int, HashableDimensionKey>& statePrimaryKeys) {
Yangster-mac53928882018-02-25 23:02:56 -0800546 ALOGW("Not used in duration tracker.");
547}
548
Yangster-mace06cfd72018-03-10 23:22:59 -0800549void DurationMetricProducer::onMatchedLogEventLocked(const size_t matcherIndex,
550 const LogEvent& event) {
Yangster-macb142cc82018-03-30 15:22:08 -0700551 int64_t eventTimeNs = event.GetElapsedTimestampNs();
Yangster-mac15f6bbc2018-04-08 11:52:26 -0700552 if (eventTimeNs < mTimeBaseNs) {
Yangster13fb7e42018-03-07 17:30:49 -0800553 return;
554 }
555
Muhammad Qureshi18e46922019-05-24 16:38:49 -0700556 if (mIsActive) {
557 flushIfNeededLocked(event.GetElapsedTimestampNs());
558 }
Yangster13fb7e42018-03-07 17:30:49 -0800559
560 // Handles Stopall events.
561 if (matcherIndex == mStopAllIndex) {
562 for (auto& whatIt : mCurrentSlicedDurationTrackerMap) {
563 for (auto& pair : whatIt.second) {
564 pair.second->noteStopAll(event.GetElapsedTimestampNs());
565 }
566 }
567 return;
568 }
569
570 HashableDimensionKey dimensionInWhat;
571 if (!mDimensionsInWhat.empty()) {
572 filterValues(mDimensionsInWhat, event.getValues(), &dimensionInWhat);
573 } else {
574 dimensionInWhat = DEFAULT_DIMENSION_KEY;
575 }
576
577 // Handles Stop events.
578 if (matcherIndex == mStopIndex) {
579 if (mUseWhatDimensionAsInternalDimension) {
580 auto whatIt = mCurrentSlicedDurationTrackerMap.find(dimensionInWhat);
581 if (whatIt != mCurrentSlicedDurationTrackerMap.end()) {
tsaichristine69000e62019-10-18 17:34:52 -0700582 for (const auto& stateIt : whatIt->second) {
583 stateIt.second->noteStop(dimensionInWhat, event.GetElapsedTimestampNs(), false);
Yangster13fb7e42018-03-07 17:30:49 -0800584 }
585 }
586 return;
587 }
588
589 HashableDimensionKey internalDimensionKey = DEFAULT_DIMENSION_KEY;
590 if (!mInternalDimensions.empty()) {
591 filterValues(mInternalDimensions, event.getValues(), &internalDimensionKey);
592 }
593
594 auto whatIt = mCurrentSlicedDurationTrackerMap.find(dimensionInWhat);
595 if (whatIt != mCurrentSlicedDurationTrackerMap.end()) {
tsaichristine69000e62019-10-18 17:34:52 -0700596 for (const auto& stateIt : whatIt->second) {
597 stateIt.second->noteStop(internalDimensionKey, event.GetElapsedTimestampNs(),
598 false);
Yangster13fb7e42018-03-07 17:30:49 -0800599 }
600 }
601 return;
602 }
603
604 bool condition;
605 ConditionKey conditionKey;
Yangster13fb7e42018-03-07 17:30:49 -0800606 if (mConditionSliced) {
607 for (const auto& link : mMetric2ConditionLinks) {
608 getDimensionForCondition(event.getValues(), link, &conditionKey[link.conditionId]);
609 }
610
611 auto conditionState =
tsaichristine76853372019-08-06 17:17:03 -0700612 mWizard->query(mConditionTrackerIndex, conditionKey,
613 !mHasLinksToAllConditionDimensionsInTracker);
Olivier Gaillarde63d9e02019-02-12 14:43:59 +0000614 condition = conditionState == ConditionState::kTrue;
Yangster13fb7e42018-03-07 17:30:49 -0800615 } else {
Olivier Gaillarde63d9e02019-02-12 14:43:59 +0000616 // TODO: The unknown condition state is not handled here, we should fix it.
617 condition = mCondition == ConditionState::kTrue;
Yangster13fb7e42018-03-07 17:30:49 -0800618 }
619
Muhammad Qureshi18e46922019-05-24 16:38:49 -0700620 condition = condition && mIsActive;
621
tsaichristine76853372019-08-06 17:17:03 -0700622 handleStartEvent(MetricDimensionKey(dimensionInWhat, DEFAULT_DIMENSION_KEY),
623 conditionKey, condition, event);
Yangster13fb7e42018-03-07 17:30:49 -0800624}
625
Yangsterf2bee6f2017-11-29 12:01:05 -0800626size_t DurationMetricProducer::byteSizeLocked() const {
Yangster7c334a12017-11-22 14:24:24 -0800627 size_t totalSize = 0;
628 for (const auto& pair : mPastBuckets) {
629 totalSize += pair.second.size() * kBucketSize;
630 }
631 return totalSize;
yro69007c82017-10-26 20:42:57 -0700632}
633
Yao Chen729093d2017-10-16 10:33:26 -0700634} // namespace statsd
635} // namespace os
636} // namespace android