blob: 0de92f3d9f477e6a065d2c9e9400edb76cc4161d [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 Chen5154a372017-10-30 22:57:06 -070018
Yao Chen729093d2017-10-16 10:33:26 -070019#include "Log.h"
Yao Chen5154a372017-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;
tsaichristine1449fa42020-01-02 12:12:05 -080058const int FIELD_ID_SLICE_BY_STATE = 6;
yro2b0f8862017-11-06 14:27:31 -080059// for DurationBucketInfo
yro2b0f8862017-11-06 14:27:31 -080060const int FIELD_ID_DURATION = 3;
Yangster-mac9def8e32018-04-17 13:55:51 -070061const int FIELD_ID_BUCKET_NUM = 4;
62const int FIELD_ID_START_BUCKET_ELAPSED_MILLIS = 5;
63const int FIELD_ID_END_BUCKET_ELAPSED_MILLIS = 6;
yro2b0f8862017-11-06 14:27:31 -080064
Ruchir Rastogi21a287b2019-10-02 12:04:33 -070065DurationMetricProducer::DurationMetricProducer(
66 const ConfigKey& key, const DurationMetric& metric, const int conditionIndex,
67 const size_t startIndex, const size_t stopIndex, const size_t stopAllIndex,
68 const bool nesting, const sp<ConditionWizard>& wizard,
69 const FieldMatcher& internalDimensions, const int64_t timeBaseNs, const int64_t startTimeNs,
70 const unordered_map<int, shared_ptr<Activation>>& eventActivationMap,
tsaichristined21aacf2019-10-07 14:47:38 -070071 const unordered_map<int, vector<shared_ptr<Activation>>>& eventDeactivationMap,
72 const vector<int>& slicedStateAtoms,
73 const unordered_map<int, unordered_map<int, int64_t>>& stateGroupMap)
Ruchir Rastogi21a287b2019-10-02 12:04:33 -070074 : MetricProducer(metric.id(), key, timeBaseNs, conditionIndex, wizard, eventActivationMap,
tsaichristined21aacf2019-10-07 14:47:38 -070075 eventDeactivationMap, slicedStateAtoms, stateGroupMap),
Yao Chenf09569f2017-12-13 17:00:51 -080076 mAggregationType(metric.aggregation_type()),
Yao Chen729093d2017-10-16 10:33:26 -070077 mStartIndex(startIndex),
78 mStopIndex(stopIndex),
Yao Chen5154a372017-10-30 22:57:06 -070079 mStopAllIndex(stopAllIndex),
Yangster13fb7e42018-03-07 17:30:49 -080080 mNested(nesting),
81 mContainANYPositionInInternalDimensions(false) {
Yangster-macb8144812018-01-04 10:56:23 -080082 if (metric.has_bucket()) {
yro59cc24d2018-02-13 20:17:32 -080083 mBucketSizeNs =
84 TimeUnitToBucketSizeInMillisGuardrailed(key.GetUid(), metric.bucket()) * 1000000;
Yao Chen729093d2017-10-16 10:33:26 -070085 } else {
86 mBucketSizeNs = LLONG_MAX;
87 }
88
Yao Chen8a8d16c2018-02-08 14:50:40 -080089 if (metric.has_dimensions_in_what()) {
90 translateFieldMatcher(metric.dimensions_in_what(), &mDimensionsInWhat);
Yangster13fb7e42018-03-07 17:30:49 -080091 mContainANYPositionInDimensionsInWhat = HasPositionANY(metric.dimensions_in_what());
Yao Chen8a8d16c2018-02-08 14:50:40 -080092 }
93
94 if (internalDimensions.has_field()) {
95 translateFieldMatcher(internalDimensions, &mInternalDimensions);
Yangster13fb7e42018-03-07 17:30:49 -080096 mContainANYPositionInInternalDimensions = HasPositionANY(internalDimensions);
Yao Chen8a8d16c2018-02-08 14:50:40 -080097 }
Yangster-mace06cfd72018-03-10 23:22:59 -080098 if (mContainANYPositionInInternalDimensions) {
99 ALOGE("Position ANY in internal dimension not supported.");
100 }
101 if (mContainANYPositionInDimensionsInWhat) {
102 ALOGE("Position ANY in dimension_in_what not supported.");
103 }
Yao Chen8a8d16c2018-02-08 14:50:40 -0800104
tsaichristine76853372019-08-06 17:17:03 -0700105 mSliceByPositionALL = HasPositionALL(metric.dimensions_in_what());
Yangster-mac9def8e32018-04-17 13:55:51 -0700106
Yao Chen729093d2017-10-16 10:33:26 -0700107 if (metric.links().size() > 0) {
Yao Chen8a8d16c2018-02-08 14:50:40 -0800108 for (const auto& link : metric.links()) {
109 Metric2Condition mc;
110 mc.conditionId = link.condition();
111 translateFieldMatcher(link.fields_in_what(), &mc.metricFields);
112 translateFieldMatcher(link.fields_in_condition(), &mc.conditionFields);
113 mMetric2ConditionLinks.push_back(mc);
114 }
tsaichristine76853372019-08-06 17:17:03 -0700115 mConditionSliced = true;
Yao Chen729093d2017-10-16 10:33:26 -0700116 }
Yangster13fb7e42018-03-07 17:30:49 -0800117 mUnSlicedPartCondition = ConditionState::kUnknown;
Yao Chen729093d2017-10-16 10:33:26 -0700118
tsaichristine1449fa42020-01-02 12:12:05 -0800119 for (const auto& stateLink : metric.state_link()) {
120 Metric2State ms;
121 ms.stateAtomId = stateLink.state_atom_id();
122 translateFieldMatcher(stateLink.fields_in_what(), &ms.metricFields);
123 translateFieldMatcher(stateLink.fields_in_state(), &ms.stateFields);
124 mMetric2StateLinks.push_back(ms);
125 }
126
Yangster13fb7e42018-03-07 17:30:49 -0800127 mUseWhatDimensionAsInternalDimension = equalDimensions(mDimensionsInWhat, mInternalDimensions);
tsaichristine76853372019-08-06 17:17:03 -0700128 if (mWizard != nullptr && mConditionTrackerIndex >= 0 &&
129 mMetric2ConditionLinks.size() == 1) {
tsaichristine69000e62019-10-18 17:34:52 -0700130 mHasLinksToAllConditionDimensionsInTracker = mWizard->equalOutputDimensions(
131 mConditionTrackerIndex, mMetric2ConditionLinks.begin()->conditionFields);
Yangster-mac53928882018-02-25 23:02:56 -0800132 }
Chenjie Yue1361ed2018-07-23 17:33:09 -0700133 flushIfNeededLocked(startTimeNs);
134 // Adjust start for partial bucket
135 mCurrentBucketStartTimeNs = startTimeNs;
Yangster-mac94e197c2018-01-02 16:03:03 -0800136 VLOG("metric %lld created. bucket size %lld start_time: %lld", (long long)metric.id(),
Yangster-mac15f6bbc2018-04-08 11:52:26 -0700137 (long long)mBucketSizeNs, (long long)mTimeBaseNs);
Yao Chen729093d2017-10-16 10:33:26 -0700138}
139
140DurationMetricProducer::~DurationMetricProducer() {
141 VLOG("~DurationMetric() called");
142}
143
Yangster-mac932ecec2018-02-01 10:23:52 -0800144sp<AnomalyTracker> DurationMetricProducer::addAnomalyTracker(
145 const Alert &alert, const sp<AlarmMonitor>& anomalyAlarmMonitor) {
Bookatz857aaa52017-12-19 15:29:06 -0800146 std::lock_guard<std::mutex> lock(mMutex);
Bookatz423f7532018-03-08 15:45:14 -0800147 if (mAggregationType == DurationMetric_AggregationType_SUM) {
148 if (alert.trigger_if_sum_gt() > alert.num_buckets() * mBucketSizeNs) {
149 ALOGW("invalid alert for SUM: threshold (%f) > possible recordable value (%d x %lld)",
150 alert.trigger_if_sum_gt(), alert.num_buckets(), (long long)mBucketSizeNs);
151 return nullptr;
152 }
153 }
Yangster-mac932ecec2018-02-01 10:23:52 -0800154 sp<DurationAnomalyTracker> anomalyTracker =
155 new DurationAnomalyTracker(alert, mConfigKey, anomalyAlarmMonitor);
Bookatz857aaa52017-12-19 15:29:06 -0800156 if (anomalyTracker != nullptr) {
157 mAnomalyTrackers.push_back(anomalyTracker);
158 }
159 return anomalyTracker;
Bookatz450099d2017-11-30 17:09:30 -0800160}
161
tsaichristine1449fa42020-01-02 12:12:05 -0800162void DurationMetricProducer::onStateChanged(const int64_t eventTimeNs, const int32_t atomId,
163 const HashableDimensionKey& primaryKey,
164 const int32_t oldState, const int32_t newState) {
165 // Create a FieldValue object to hold the new state.
166 FieldValue value;
167 value.mValue.setInt(newState);
168 // Check if this metric has a StateMap. If so, map the new state value to
169 // the correct state group id.
170 mapStateValue(atomId, &value);
171
172 flushIfNeededLocked(eventTimeNs);
173
174 // Each duration tracker is mapped to a different whatKey (a set of values from the
175 // dimensionsInWhat fields). We notify all trackers iff the primaryKey field values from the
176 // state change event are a subset of the tracker's whatKey field values.
177 //
178 // Ex. For a duration metric dimensioned on uid and tag:
179 // DurationTracker1 whatKey = uid: 1001, tag: 1
180 // DurationTracker2 whatKey = uid: 1002, tag 1
181 //
182 // If the state change primaryKey = uid: 1001, we only notify DurationTracker1 of a state
183 // change.
184 for (auto& whatIt : mCurrentSlicedDurationTrackerMap) {
185 if (!containsLinkedStateValues(whatIt.first, primaryKey, mMetric2StateLinks, atomId)) {
186 continue;
187 }
188 whatIt.second->onStateChanged(eventTimeNs, atomId, value);
189 }
190}
191
Yao Chen5154a372017-10-30 22:57:06 -0700192unique_ptr<DurationTracker> DurationMetricProducer::createDurationTracker(
Yangster-mac93694462018-01-22 20:49:31 -0800193 const MetricDimensionKey& eventKey) const {
Yao Chenf09569f2017-12-13 17:00:51 -0800194 switch (mAggregationType) {
Stefan Lafoncfed20b2017-11-18 09:26:53 -0800195 case DurationMetric_AggregationType_SUM:
Yao Chenb3561512017-11-21 18:07:17 -0800196 return make_unique<OringDurationTracker>(
tsaichristine1449fa42020-01-02 12:12:05 -0800197 mConfigKey, mMetricId, eventKey, mWizard, mConditionTrackerIndex, mNested,
198 mCurrentBucketStartTimeNs, mCurrentBucketNum, mTimeBaseNs, mBucketSizeNs,
199 mConditionSliced, mHasLinksToAllConditionDimensionsInTracker, mAnomalyTrackers);
Stefan Lafoncfed20b2017-11-18 09:26:53 -0800200 case DurationMetric_AggregationType_MAX_SPARSE:
Yao Chenb3561512017-11-21 18:07:17 -0800201 return make_unique<MaxDurationTracker>(
tsaichristine1449fa42020-01-02 12:12:05 -0800202 mConfigKey, mMetricId, eventKey, mWizard, mConditionTrackerIndex, mNested,
203 mCurrentBucketStartTimeNs, mCurrentBucketNum, mTimeBaseNs, mBucketSizeNs,
204 mConditionSliced, mHasLinksToAllConditionDimensionsInTracker, mAnomalyTrackers);
Yangster13fb7e42018-03-07 17:30:49 -0800205 }
206}
207
208// SlicedConditionChange optimization case 1:
209// 1. If combination condition, logical operation is AND, only one sliced child predicate.
tsaichristine76853372019-08-06 17:17:03 -0700210// 2. The links covers all dimension fields in the sliced child condition predicate.
Yao Chen427d3722018-03-22 15:21:52 -0700211void DurationMetricProducer::onSlicedConditionMayChangeLocked_opt1(bool condition,
Yangster-macb142cc82018-03-30 15:22:08 -0700212 const int64_t eventTime) {
Yangster13fb7e42018-03-07 17:30:49 -0800213 if (mMetric2ConditionLinks.size() != 1 ||
tsaichristine76853372019-08-06 17:17:03 -0700214 !mHasLinksToAllConditionDimensionsInTracker) {
Yangster13fb7e42018-03-07 17:30:49 -0800215 return;
216 }
217
218 bool currentUnSlicedPartCondition = true;
219 if (!mWizard->IsSimpleCondition(mConditionTrackerIndex)) {
220 ConditionState unslicedPartState =
221 mWizard->getUnSlicedPartConditionState(mConditionTrackerIndex);
222 // When the unsliced part is still false, return directly.
223 if (mUnSlicedPartCondition == ConditionState::kFalse &&
224 unslicedPartState == ConditionState::kFalse) {
225 return;
226 }
227 mUnSlicedPartCondition = unslicedPartState;
228 currentUnSlicedPartCondition = mUnSlicedPartCondition > 0;
229 }
230
231 auto dimensionsChangedToTrue = mWizard->getChangedToTrueDimensions(mConditionTrackerIndex);
232 auto dimensionsChangedToFalse = mWizard->getChangedToFalseDimensions(mConditionTrackerIndex);
233
234 // The condition change is from the unsliced predicates.
235 // We need to find out the true dimensions from the sliced predicate and flip their condition
236 // state based on the new unsliced condition state.
237 if (dimensionsChangedToTrue == nullptr || dimensionsChangedToFalse == nullptr ||
238 (dimensionsChangedToTrue->empty() && dimensionsChangedToFalse->empty())) {
239 std::set<HashableDimensionKey> trueConditionDimensions;
240 mWizard->getTrueSlicedDimensions(mConditionTrackerIndex, &trueConditionDimensions);
241 for (auto& whatIt : mCurrentSlicedDurationTrackerMap) {
242 HashableDimensionKey linkedConditionDimensionKey;
tsaichristine69000e62019-10-18 17:34:52 -0700243 getDimensionForCondition(whatIt.first.getValues(), mMetric2ConditionLinks[0],
Yangster13fb7e42018-03-07 17:30:49 -0800244 &linkedConditionDimensionKey);
245 if (trueConditionDimensions.find(linkedConditionDimensionKey) !=
246 trueConditionDimensions.end()) {
tsaichristine81899f12020-01-08 12:42:12 -0800247 whatIt.second->onConditionChanged(currentUnSlicedPartCondition, eventTime);
Yangster13fb7e42018-03-07 17:30:49 -0800248 }
249 }
250 } else {
251 // Handle the condition change from the sliced predicate.
252 if (currentUnSlicedPartCondition) {
253 for (auto& whatIt : mCurrentSlicedDurationTrackerMap) {
254 HashableDimensionKey linkedConditionDimensionKey;
tsaichristine69000e62019-10-18 17:34:52 -0700255 getDimensionForCondition(whatIt.first.getValues(), mMetric2ConditionLinks[0],
Yangster13fb7e42018-03-07 17:30:49 -0800256 &linkedConditionDimensionKey);
257 if (dimensionsChangedToTrue->find(linkedConditionDimensionKey) !=
258 dimensionsChangedToTrue->end()) {
tsaichristine81899f12020-01-08 12:42:12 -0800259 whatIt.second->onConditionChanged(true, eventTime);
Yangster13fb7e42018-03-07 17:30:49 -0800260 }
261 if (dimensionsChangedToFalse->find(linkedConditionDimensionKey) !=
262 dimensionsChangedToFalse->end()) {
tsaichristine81899f12020-01-08 12:42:12 -0800263 whatIt.second->onConditionChanged(false, eventTime);
Yangster13fb7e42018-03-07 17:30:49 -0800264 }
265 }
266 }
267 }
268}
269
Muhammad Qureshi18e46922019-05-24 16:38:49 -0700270void DurationMetricProducer::onSlicedConditionMayChangeInternalLocked(bool overallCondition,
271 const int64_t eventTimeNs) {
Yangster13fb7e42018-03-07 17:30:49 -0800272 bool changeDimTrackable = mWizard->IsChangedDimensionTrackable(mConditionTrackerIndex);
tsaichristine76853372019-08-06 17:17:03 -0700273 if (changeDimTrackable && mHasLinksToAllConditionDimensionsInTracker) {
Muhammad Qureshi18e46922019-05-24 16:38:49 -0700274 onSlicedConditionMayChangeLocked_opt1(overallCondition, eventTimeNs);
Yangster13fb7e42018-03-07 17:30:49 -0800275 return;
276 }
277
Yao Chen729093d2017-10-16 10:33:26 -0700278 // Now for each of the on-going event, check if the condition has changed for them.
Yangster-mac53928882018-02-25 23:02:56 -0800279 for (auto& whatIt : mCurrentSlicedDurationTrackerMap) {
tsaichristine81899f12020-01-08 12:42:12 -0800280 whatIt.second->onSlicedConditionMayChange(overallCondition, eventTimeNs);
Yao Chen729093d2017-10-16 10:33:26 -0700281 }
282}
283
Muhammad Qureshi18e46922019-05-24 16:38:49 -0700284void DurationMetricProducer::onSlicedConditionMayChangeLocked(bool overallCondition,
285 const int64_t eventTime) {
286 VLOG("Metric %lld onSlicedConditionMayChange", (long long)mMetricId);
287
288 if (!mIsActive) {
289 return;
290 }
291
292 flushIfNeededLocked(eventTime);
293
294 if (!mConditionSliced) {
295 return;
296 }
297
298 onSlicedConditionMayChangeInternalLocked(overallCondition, eventTime);
299}
300
301void DurationMetricProducer::onActiveStateChangedLocked(const int64_t& eventTimeNs) {
302 MetricProducer::onActiveStateChangedLocked(eventTimeNs);
303
304 if (!mConditionSliced) {
305 if (ConditionState::kTrue != mCondition) {
306 return;
307 }
308
309 if (mIsActive) {
310 flushIfNeededLocked(eventTimeNs);
311 }
312
313 for (auto& whatIt : mCurrentSlicedDurationTrackerMap) {
tsaichristine81899f12020-01-08 12:42:12 -0800314 whatIt.second->onConditionChanged(mIsActive, eventTimeNs);
Muhammad Qureshi18e46922019-05-24 16:38:49 -0700315 }
316 } else if (mIsActive) {
317 flushIfNeededLocked(eventTimeNs);
318 onSlicedConditionMayChangeInternalLocked(mIsActive, eventTimeNs);
319 } else { // mConditionSliced == true && !mIsActive
320 for (auto& whatIt : mCurrentSlicedDurationTrackerMap) {
tsaichristine81899f12020-01-08 12:42:12 -0800321 whatIt.second->onConditionChanged(mIsActive, eventTimeNs);
Muhammad Qureshi18e46922019-05-24 16:38:49 -0700322 }
323 }
324}
325
Yangsterf2bee6f2017-11-29 12:01:05 -0800326void DurationMetricProducer::onConditionChangedLocked(const bool conditionMet,
Yangster-macb142cc82018-03-30 15:22:08 -0700327 const int64_t eventTime) {
Yangster-mac94e197c2018-01-02 16:03:03 -0800328 VLOG("Metric %lld onConditionChanged", (long long)mMetricId);
Olivier Gaillarde63d9e02019-02-12 14:43:59 +0000329 mCondition = conditionMet ? ConditionState::kTrue : ConditionState::kFalse;
Muhammad Qureshi18e46922019-05-24 16:38:49 -0700330
331 if (!mIsActive) {
332 return;
333 }
334
Yangsterf2bee6f2017-11-29 12:01:05 -0800335 flushIfNeededLocked(eventTime);
Yangster-mac53928882018-02-25 23:02:56 -0800336 for (auto& whatIt : mCurrentSlicedDurationTrackerMap) {
tsaichristine81899f12020-01-08 12:42:12 -0800337 whatIt.second->onConditionChanged(conditionMet, eventTime);
Yao Chen729093d2017-10-16 10:33:26 -0700338 }
339}
340
Yangster-macb142cc82018-03-30 15:22:08 -0700341void DurationMetricProducer::dropDataLocked(const int64_t dropTimeNs) {
Yao Chen06dba5d2018-01-26 13:38:16 -0800342 flushIfNeededLocked(dropTimeNs);
Olivier Gaillard320952b2019-02-06 13:57:24 +0000343 StatsdStats::getInstance().noteBucketDropped(mMetricId);
Yao Chen06dba5d2018-01-26 13:38:16 -0800344 mPastBuckets.clear();
345}
346
Yangster-maca802d732018-04-24 07:50:38 -0700347void DurationMetricProducer::clearPastBucketsLocked(const int64_t dumpTimeNs) {
348 flushIfNeededLocked(dumpTimeNs);
349 mPastBuckets.clear();
350}
351
Yangster-macb142cc82018-03-30 15:22:08 -0700352void DurationMetricProducer::onDumpReportLocked(const int64_t dumpTimeNs,
Yangster-mace68f3a52018-04-04 00:01:43 -0700353 const bool include_current_partial_bucket,
Bookatzff71cad2018-09-20 17:17:49 -0700354 const bool erase_data,
Olivier Gaillard6c75ecd2019-02-20 09:57:33 +0000355 const DumpLatency dumpLatency,
Yangster-mac9def8e32018-04-17 13:55:51 -0700356 std::set<string> *str_set,
Yao Chen288c6002017-12-12 13:43:18 -0800357 ProtoOutputStream* protoOutput) {
Yangster-mace68f3a52018-04-04 00:01:43 -0700358 if (include_current_partial_bucket) {
359 flushLocked(dumpTimeNs);
360 } else {
361 flushIfNeededLocked(dumpTimeNs);
362 }
Yang Lub4722912018-11-15 11:02:03 -0800363 protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_ID, (long long)mMetricId);
Howard Ro07e23ff2018-12-17 17:28:07 -0800364 protoOutput->write(FIELD_TYPE_BOOL | FIELD_ID_IS_ACTIVE, isActiveLocked());
Yang Lub4722912018-11-15 11:02:03 -0800365
Yangster-mac635b4b32018-01-23 20:17:35 -0800366 if (mPastBuckets.empty()) {
Yao Chen8a8d16c2018-02-08 14:50:40 -0800367 VLOG(" Duration metric, empty return");
Yangster-mac635b4b32018-01-23 20:17:35 -0800368 return;
369 }
Yao Chen6a8c7992017-11-29 20:02:07 +0000370
Yangster-mac9def8e32018-04-17 13:55:51 -0700371 protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_TIME_BASE, (long long)mTimeBaseNs);
372 protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_BUCKET_SIZE, (long long)mBucketSizeNs);
373
374 if (!mSliceByPositionALL) {
375 if (!mDimensionsInWhat.empty()) {
376 uint64_t dimenPathToken = protoOutput->start(
377 FIELD_TYPE_MESSAGE | FIELD_ID_DIMENSION_PATH_IN_WHAT);
378 writeDimensionPathToProto(mDimensionsInWhat, protoOutput);
379 protoOutput->end(dimenPathToken);
380 }
Yangster-mac9def8e32018-04-17 13:55:51 -0700381 }
382
Yi Jin5ee07872018-03-05 18:18:27 -0800383 uint64_t protoToken = protoOutput->start(FIELD_TYPE_MESSAGE | FIELD_ID_DURATION_METRICS);
Yao Chen288c6002017-12-12 13:43:18 -0800384
Yao Chen8a8d16c2018-02-08 14:50:40 -0800385 VLOG("Duration metric %lld dump report now...", (long long)mMetricId);
Yao Chen6a8c7992017-11-29 20:02:07 +0000386
Yao Chen729093d2017-10-16 10:33:26 -0700387 for (const auto& pair : mPastBuckets) {
Yangster-mac93694462018-01-22 20:49:31 -0800388 const MetricDimensionKey& dimensionKey = pair.first;
Yangster13fb7e42018-03-07 17:30:49 -0800389 VLOG(" dimension key %s", dimensionKey.toString().c_str());
Yao Chen1ff4f432017-11-16 17:01:40 -0800390
Yi Jin5ee07872018-03-05 18:18:27 -0800391 uint64_t wrapperToken =
Yao Chen288c6002017-12-12 13:43:18 -0800392 protoOutput->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_DATA);
yro2b0f8862017-11-06 14:27:31 -0800393
Yangster-mac20877162017-12-22 17:19:39 -0800394 // First fill dimension.
Yangster-mac9def8e32018-04-17 13:55:51 -0700395 if (mSliceByPositionALL) {
396 uint64_t dimensionToken = protoOutput->start(
397 FIELD_TYPE_MESSAGE | FIELD_ID_DIMENSION_IN_WHAT);
398 writeDimensionToProto(dimensionKey.getDimensionKeyInWhat(), str_set, protoOutput);
399 protoOutput->end(dimensionToken);
Yangster-mac9def8e32018-04-17 13:55:51 -0700400 } else {
401 writeDimensionLeafNodesToProto(dimensionKey.getDimensionKeyInWhat(),
402 FIELD_ID_DIMENSION_LEAF_IN_WHAT, str_set, protoOutput);
Yangster-mac93694462018-01-22 20:49:31 -0800403 }
tsaichristine1449fa42020-01-02 12:12:05 -0800404 // Then fill slice_by_state.
405 for (auto state : dimensionKey.getStateValuesKey().getValues()) {
406 uint64_t stateToken = protoOutput->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED |
407 FIELD_ID_SLICE_BY_STATE);
408 writeStateToProto(state, protoOutput);
409 protoOutput->end(stateToken);
410 }
yro2b0f8862017-11-06 14:27:31 -0800411 // Then fill bucket_info (DurationBucketInfo).
412 for (const auto& bucket : pair.second) {
Yi Jin5ee07872018-03-05 18:18:27 -0800413 uint64_t bucketInfoToken = protoOutput->start(
Yao Chen288c6002017-12-12 13:43:18 -0800414 FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_BUCKET_INFO);
Yangster-mac9def8e32018-04-17 13:55:51 -0700415 if (bucket.mBucketEndNs - bucket.mBucketStartNs != mBucketSizeNs) {
416 protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_START_BUCKET_ELAPSED_MILLIS,
417 (long long)NanoToMillis(bucket.mBucketStartNs));
418 protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_END_BUCKET_ELAPSED_MILLIS,
419 (long long)NanoToMillis(bucket.mBucketEndNs));
420 } else {
421 protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_BUCKET_NUM,
422 (long long)(getBucketNumFromEndTimeNs(bucket.mBucketEndNs)));
423 }
Yao Chen288c6002017-12-12 13:43:18 -0800424 protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_DURATION, (long long)bucket.mDuration);
425 protoOutput->end(bucketInfoToken);
yro2b0f8862017-11-06 14:27:31 -0800426 VLOG("\t bucket [%lld - %lld] duration: %lld", (long long)bucket.mBucketStartNs,
427 (long long)bucket.mBucketEndNs, (long long)bucket.mDuration);
428 }
429
Yao Chen288c6002017-12-12 13:43:18 -0800430 protoOutput->end(wrapperToken);
Yao Chen729093d2017-10-16 10:33:26 -0700431 }
yro2b0f8862017-11-06 14:27:31 -0800432
Yao Chen288c6002017-12-12 13:43:18 -0800433 protoOutput->end(protoToken);
Bookatzff71cad2018-09-20 17:17:49 -0700434 if (erase_data) {
435 mPastBuckets.clear();
436 }
yro2b0f8862017-11-06 14:27:31 -0800437}
Yao Chen729093d2017-10-16 10:33:26 -0700438
Yangster-macb142cc82018-03-30 15:22:08 -0700439void DurationMetricProducer::flushIfNeededLocked(const int64_t& eventTimeNs) {
440 int64_t currentBucketEndTimeNs = getCurrentBucketEndTimeNs();
David Chen27785a82018-01-19 17:06:45 -0800441
442 if (currentBucketEndTimeNs > eventTimeNs) {
Yao Chen729093d2017-10-16 10:33:26 -0700443 return;
444 }
Yao Chen5154a372017-10-30 22:57:06 -0700445 VLOG("flushing...........");
David Chen27785a82018-01-19 17:06:45 -0800446 int numBucketsForward = 1 + (eventTimeNs - currentBucketEndTimeNs) / mBucketSizeNs;
Muhammad Qureshi902529a2019-03-14 16:03:21 -0700447 int64_t nextBucketNs = currentBucketEndTimeNs + (numBucketsForward - 1) * mBucketSizeNs;
448 flushCurrentBucketLocked(eventTimeNs, nextBucketNs);
449
Yangster-mace2cd6d52017-11-09 20:38:30 -0800450 mCurrentBucketNum += numBucketsForward;
Yao Chen5154a372017-10-30 22:57:06 -0700451}
452
Olivier Gaillard6c75ecd2019-02-20 09:57:33 +0000453void DurationMetricProducer::flushCurrentBucketLocked(const int64_t& eventTimeNs,
454 const int64_t& nextBucketStartTimeNs) {
Yangster-mac53928882018-02-25 23:02:56 -0800455 for (auto whatIt = mCurrentSlicedDurationTrackerMap.begin();
456 whatIt != mCurrentSlicedDurationTrackerMap.end();) {
tsaichristine81899f12020-01-08 12:42:12 -0800457 if (whatIt->second->flushCurrentBucket(eventTimeNs, &mPastBuckets)) {
458 VLOG("erase bucket for key %s", whatIt->first.toString().c_str());
Yangster-mac53928882018-02-25 23:02:56 -0800459 whatIt = mCurrentSlicedDurationTrackerMap.erase(whatIt);
David Chen27785a82018-01-19 17:06:45 -0800460 } else {
tsaichristine81899f12020-01-08 12:42:12 -0800461 ++whatIt;
David Chen27785a82018-01-19 17:06:45 -0800462 }
463 }
Olivier Gaillardf248c0d2019-02-21 15:56:58 +0000464 StatsdStats::getInstance().noteBucketCount(mMetricId);
Muhammad Qureshi902529a2019-03-14 16:03:21 -0700465 mCurrentBucketStartTimeNs = nextBucketStartTimeNs;
David Chen27785a82018-01-19 17:06:45 -0800466}
467
Yao Chen884c8c12018-01-26 10:36:25 -0800468void DurationMetricProducer::dumpStatesLocked(FILE* out, bool verbose) const {
Yangster-mac93694462018-01-22 20:49:31 -0800469 if (mCurrentSlicedDurationTrackerMap.size() == 0) {
Yao Chen884c8c12018-01-26 10:36:25 -0800470 return;
471 }
472
473 fprintf(out, "DurationMetric %lld dimension size %lu\n", (long long)mMetricId,
Yangster-mac93694462018-01-22 20:49:31 -0800474 (unsigned long)mCurrentSlicedDurationTrackerMap.size());
Yao Chen884c8c12018-01-26 10:36:25 -0800475 if (verbose) {
Yangster-mac53928882018-02-25 23:02:56 -0800476 for (const auto& whatIt : mCurrentSlicedDurationTrackerMap) {
tsaichristine81899f12020-01-08 12:42:12 -0800477 fprintf(out, "\t(what)%s\n", whatIt.first.toString().c_str());
478 whatIt.second->dumpStates(out, verbose);
Yao Chen884c8c12018-01-26 10:36:25 -0800479 }
480 }
481}
482
Yangster-mac93694462018-01-22 20:49:31 -0800483bool DurationMetricProducer::hitGuardRailLocked(const MetricDimensionKey& newKey) {
Yangster-mac306ccc22018-03-24 15:03:40 -0700484 auto whatIt = mCurrentSlicedDurationTrackerMap.find(newKey.getDimensionKeyInWhat());
tsaichristine81899f12020-01-08 12:42:12 -0800485 if (whatIt == mCurrentSlicedDurationTrackerMap.end()) {
Yangster-mac306ccc22018-03-24 15:03:40 -0700486 // 1. Report the tuple count if the tuple count > soft limit
487 if (mCurrentSlicedDurationTrackerMap.size() > StatsdStats::kDimensionKeySizeSoftLimit - 1) {
488 size_t newTupleCount = mCurrentSlicedDurationTrackerMap.size() + 1;
489 StatsdStats::getInstance().noteMetricDimensionSize(
490 mConfigKey, mMetricId, newTupleCount);
491 // 2. Don't add more tuples, we are above the allowed threshold. Drop the data.
492 if (newTupleCount > StatsdStats::kDimensionKeySizeHardLimit) {
493 ALOGE("DurationMetric %lld dropping data for what dimension key %s",
494 (long long)mMetricId, newKey.getDimensionKeyInWhat().toString().c_str());
Muhammad Qureshi87348a62019-02-14 16:17:52 -0800495 StatsdStats::getInstance().noteHardDimensionLimitReached(mMetricId);
Yangster-mac306ccc22018-03-24 15:03:40 -0700496 return true;
497 }
Yao Chenb3561512017-11-21 18:07:17 -0800498 }
499 }
500 return false;
501}
502
Yangster-mac53928882018-02-25 23:02:56 -0800503void DurationMetricProducer::handleStartEvent(const MetricDimensionKey& eventKey,
504 const ConditionKey& conditionKeys,
505 bool condition, const LogEvent& event) {
506 const auto& whatKey = eventKey.getDimensionKeyInWhat();
Yangster-mac53928882018-02-25 23:02:56 -0800507 auto whatIt = mCurrentSlicedDurationTrackerMap.find(whatKey);
508 if (whatIt == mCurrentSlicedDurationTrackerMap.end()) {
Yangsterf2bee6f2017-11-29 12:01:05 -0800509 if (hitGuardRailLocked(eventKey)) {
Yao Chenb3561512017-11-21 18:07:17 -0800510 return;
511 }
tsaichristine81899f12020-01-08 12:42:12 -0800512 mCurrentSlicedDurationTrackerMap[whatKey] = createDurationTracker(eventKey);
Yao Chen6a8c7992017-11-29 20:02:07 +0000513 }
Yao Chen5154a372017-10-30 22:57:06 -0700514
tsaichristine81899f12020-01-08 12:42:12 -0800515 auto it = mCurrentSlicedDurationTrackerMap.find(whatKey);
Yangster-mac53928882018-02-25 23:02:56 -0800516 if (mUseWhatDimensionAsInternalDimension) {
tsaichristine1449fa42020-01-02 12:12:05 -0800517 it->second->noteStart(whatKey, condition, event.GetElapsedTimestampNs(), conditionKeys);
Yangster-mac53928882018-02-25 23:02:56 -0800518 return;
519 }
Yao Chen5154a372017-10-30 22:57:06 -0700520
Yangster13fb7e42018-03-07 17:30:49 -0800521 if (mInternalDimensions.empty()) {
tsaichristine1449fa42020-01-02 12:12:05 -0800522 it->second->noteStart(DEFAULT_DIMENSION_KEY, condition, event.GetElapsedTimestampNs(),
523 conditionKeys);
Yangster-mac20877162017-12-22 17:19:39 -0800524 } else {
Yangster-mace06cfd72018-03-10 23:22:59 -0800525 HashableDimensionKey dimensionKey = DEFAULT_DIMENSION_KEY;
526 filterValues(mInternalDimensions, event.getValues(), &dimensionKey);
tsaichristine1449fa42020-01-02 12:12:05 -0800527 it->second->noteStart(dimensionKey, condition, event.GetElapsedTimestampNs(),
528 conditionKeys);
Yao Chen5154a372017-10-30 22:57:06 -0700529 }
Yangster-mac20877162017-12-22 17:19:39 -0800530
Yao Chen729093d2017-10-16 10:33:26 -0700531}
532
Yangster-mac53928882018-02-25 23:02:56 -0800533void DurationMetricProducer::onMatchedLogEventInternalLocked(
534 const size_t matcherIndex, const MetricDimensionKey& eventKey,
tsaichristinec876b492019-12-10 13:47:05 -0800535 const ConditionKey& conditionKeys, bool condition, const LogEvent& event,
536 const map<int, HashableDimensionKey>& statePrimaryKeys) {
Yangster-mac53928882018-02-25 23:02:56 -0800537 ALOGW("Not used in duration tracker.");
538}
539
Yangster-mace06cfd72018-03-10 23:22:59 -0800540void DurationMetricProducer::onMatchedLogEventLocked(const size_t matcherIndex,
541 const LogEvent& event) {
Yangster-macb142cc82018-03-30 15:22:08 -0700542 int64_t eventTimeNs = event.GetElapsedTimestampNs();
Yangster-mac15f6bbc2018-04-08 11:52:26 -0700543 if (eventTimeNs < mTimeBaseNs) {
Yangster13fb7e42018-03-07 17:30:49 -0800544 return;
545 }
546
Muhammad Qureshi18e46922019-05-24 16:38:49 -0700547 if (mIsActive) {
548 flushIfNeededLocked(event.GetElapsedTimestampNs());
549 }
Yangster13fb7e42018-03-07 17:30:49 -0800550
551 // Handles Stopall events.
552 if (matcherIndex == mStopAllIndex) {
553 for (auto& whatIt : mCurrentSlicedDurationTrackerMap) {
tsaichristine81899f12020-01-08 12:42:12 -0800554 whatIt.second->noteStopAll(event.GetElapsedTimestampNs());
Yangster13fb7e42018-03-07 17:30:49 -0800555 }
556 return;
557 }
558
tsaichristine81899f12020-01-08 12:42:12 -0800559 HashableDimensionKey dimensionInWhat = DEFAULT_DIMENSION_KEY;
Yangster13fb7e42018-03-07 17:30:49 -0800560 if (!mDimensionsInWhat.empty()) {
561 filterValues(mDimensionsInWhat, event.getValues(), &dimensionInWhat);
Yangster13fb7e42018-03-07 17:30:49 -0800562 }
563
tsaichristine1449fa42020-01-02 12:12:05 -0800564 // Stores atom id to primary key pairs for each state atom that the metric is
565 // sliced by.
566 std::map<int, HashableDimensionKey> statePrimaryKeys;
567
568 // For states with primary fields, use MetricStateLinks to get the primary
569 // field values from the log event. These values will form a primary key
570 // that will be used to query StateTracker for the correct state value.
571 for (const auto& stateLink : mMetric2StateLinks) {
572 getDimensionForState(event.getValues(), stateLink,
573 &statePrimaryKeys[stateLink.stateAtomId]);
574 }
575
576 // For each sliced state, query StateTracker for the state value using
577 // either the primary key from the previous step or the DEFAULT_DIMENSION_KEY.
578 //
579 // Expected functionality: for any case where the MetricStateLinks are
580 // initialized incorrectly (ex. # of state links != # of primary fields, no
581 // links are provided for a state with primary fields, links are provided
582 // in the wrong order, etc.), StateTracker will simply return kStateUnknown
583 // when queried using an incorrect key.
584 HashableDimensionKey stateValuesKey = DEFAULT_DIMENSION_KEY;
585 for (auto atomId : mSlicedStateAtoms) {
586 FieldValue value;
587 if (statePrimaryKeys.find(atomId) != statePrimaryKeys.end()) {
588 // found a primary key for this state, query using the key
589 queryStateValue(atomId, statePrimaryKeys[atomId], &value);
590 } else {
591 // if no MetricStateLinks exist for this state atom,
592 // query using the default dimension key (empty HashableDimensionKey)
593 queryStateValue(atomId, DEFAULT_DIMENSION_KEY, &value);
594 }
595 mapStateValue(atomId, &value);
596 stateValuesKey.addValue(value);
597 }
598
Yangster13fb7e42018-03-07 17:30:49 -0800599 // Handles Stop events.
600 if (matcherIndex == mStopIndex) {
601 if (mUseWhatDimensionAsInternalDimension) {
602 auto whatIt = mCurrentSlicedDurationTrackerMap.find(dimensionInWhat);
603 if (whatIt != mCurrentSlicedDurationTrackerMap.end()) {
tsaichristine81899f12020-01-08 12:42:12 -0800604 whatIt->second->noteStop(dimensionInWhat, event.GetElapsedTimestampNs(), false);
Yangster13fb7e42018-03-07 17:30:49 -0800605 }
606 return;
607 }
608
609 HashableDimensionKey internalDimensionKey = DEFAULT_DIMENSION_KEY;
610 if (!mInternalDimensions.empty()) {
611 filterValues(mInternalDimensions, event.getValues(), &internalDimensionKey);
612 }
613
614 auto whatIt = mCurrentSlicedDurationTrackerMap.find(dimensionInWhat);
615 if (whatIt != mCurrentSlicedDurationTrackerMap.end()) {
tsaichristine81899f12020-01-08 12:42:12 -0800616 whatIt->second->noteStop(internalDimensionKey, event.GetElapsedTimestampNs(), false);
Yangster13fb7e42018-03-07 17:30:49 -0800617 }
618 return;
619 }
620
621 bool condition;
622 ConditionKey conditionKey;
Yangster13fb7e42018-03-07 17:30:49 -0800623 if (mConditionSliced) {
624 for (const auto& link : mMetric2ConditionLinks) {
625 getDimensionForCondition(event.getValues(), link, &conditionKey[link.conditionId]);
626 }
627
628 auto conditionState =
tsaichristine76853372019-08-06 17:17:03 -0700629 mWizard->query(mConditionTrackerIndex, conditionKey,
630 !mHasLinksToAllConditionDimensionsInTracker);
Olivier Gaillarde63d9e02019-02-12 14:43:59 +0000631 condition = conditionState == ConditionState::kTrue;
Yangster13fb7e42018-03-07 17:30:49 -0800632 } else {
Olivier Gaillarde63d9e02019-02-12 14:43:59 +0000633 // TODO: The unknown condition state is not handled here, we should fix it.
634 condition = mCondition == ConditionState::kTrue;
Yangster13fb7e42018-03-07 17:30:49 -0800635 }
636
Muhammad Qureshi18e46922019-05-24 16:38:49 -0700637 condition = condition && mIsActive;
638
tsaichristine1449fa42020-01-02 12:12:05 -0800639 handleStartEvent(MetricDimensionKey(dimensionInWhat, stateValuesKey), conditionKey, condition,
640 event);
Yangster13fb7e42018-03-07 17:30:49 -0800641}
642
Yangsterf2bee6f2017-11-29 12:01:05 -0800643size_t DurationMetricProducer::byteSizeLocked() const {
Yangster7c334a12017-11-22 14:24:24 -0800644 size_t totalSize = 0;
645 for (const auto& pair : mPastBuckets) {
646 totalSize += pair.second.size() * kBucketSize;
647 }
648 return totalSize;
yro69007c82017-10-26 20:42:57 -0700649}
650
Yao Chen729093d2017-10-16 10:33:26 -0700651} // namespace statsd
652} // namespace os
653} // namespace android