blob: cdd20cdd70f9cd0c151c1c0aa7242fe29beda025 [file] [log] [blame]
Yao Chenb7041772017-10-20 16:59:25 -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 */
Yao Chenb7041772017-10-20 16:59:25 -070016
Yangster-mac754e29e2018-05-02 12:23:17 -070017#define DEBUG false // STOPSHIP if true
Yao Chen8a8d16c2018-02-08 14:50:40 -080018#include "Log.h"
tsaichristine69000e62019-10-18 17:34:52 -070019
Yao Chen8a8d16c2018-02-08 14:50:40 -080020#include "MetricProducer.h"
Yangster-mac93694462018-01-22 20:49:31 -080021
tsaichristineb87ca152019-12-09 15:19:41 -080022#include "../guardrail/StatsdStats.h"
tsaichristine69000e62019-10-18 17:34:52 -070023#include "state/StateTracker.h"
24
Muhammad Qureshi844694b2019-04-05 10:10:40 -070025using android::util::FIELD_COUNT_REPEATED;
Tej Singhf53d4452019-05-09 18:17:59 -070026using android::util::FIELD_TYPE_ENUM;
Muhammad Qureshi844694b2019-04-05 10:10:40 -070027using android::util::FIELD_TYPE_INT32;
28using android::util::FIELD_TYPE_INT64;
29using android::util::FIELD_TYPE_MESSAGE;
30using android::util::ProtoOutputStream;
31
Yao Chenb7041772017-10-20 16:59:25 -070032namespace android {
33namespace os {
34namespace statsd {
35
Yao Chenb7041772017-10-20 16:59:25 -070036
Muhammad Qureshi844694b2019-04-05 10:10:40 -070037// for ActiveMetric
38const int FIELD_ID_ACTIVE_METRIC_ID = 1;
39const int FIELD_ID_ACTIVE_METRIC_ACTIVATION = 2;
40
41// for ActiveEventActivation
42const int FIELD_ID_ACTIVE_EVENT_ACTIVATION_ATOM_MATCHER_INDEX = 1;
43const int FIELD_ID_ACTIVE_EVENT_ACTIVATION_REMAINING_TTL_NANOS = 2;
Tej Singhf53d4452019-05-09 18:17:59 -070044const int FIELD_ID_ACTIVE_EVENT_ACTIVATION_STATE = 3;
Muhammad Qureshi844694b2019-04-05 10:10:40 -070045
Ruchir Rastogi21a287b2019-10-02 12:04:33 -070046MetricProducer::MetricProducer(
47 const int64_t& metricId, const ConfigKey& key, const int64_t timeBaseNs,
tsaichristine6e2e92d2020-05-18 14:39:45 -070048 const int conditionIndex, const vector<ConditionState>& initialConditionCache,
49 const sp<ConditionWizard>& wizard,
Ruchir Rastogi21a287b2019-10-02 12:04:33 -070050 const std::unordered_map<int, std::shared_ptr<Activation>>& eventActivationMap,
51 const std::unordered_map<int, std::vector<std::shared_ptr<Activation>>>&
tsaichristined21aacf2019-10-07 14:47:38 -070052 eventDeactivationMap,
53 const vector<int>& slicedStateAtoms,
54 const unordered_map<int, unordered_map<int, int64_t>>& stateGroupMap)
55 : mMetricId(metricId),
56 mConfigKey(key),
57 mTimeBaseNs(timeBaseNs),
58 mCurrentBucketStartTimeNs(timeBaseNs),
59 mCurrentBucketNum(0),
tsaichristine6e2e92d2020-05-18 14:39:45 -070060 mCondition(initialCondition(conditionIndex, initialConditionCache)),
tsaichristined21aacf2019-10-07 14:47:38 -070061 mConditionTrackerIndex(conditionIndex),
62 mConditionSliced(false),
63 mWizard(wizard),
64 mContainANYPositionInDimensionsInWhat(false),
65 mSliceByPositionALL(false),
66 mHasLinksToAllConditionDimensionsInTracker(false),
67 mEventActivationMap(eventActivationMap),
68 mEventDeactivationMap(eventDeactivationMap),
69 mIsActive(mEventActivationMap.empty()),
70 mSlicedStateAtoms(slicedStateAtoms),
71 mStateGroupMap(stateGroupMap) {
72}
Ruchir Rastogi21a287b2019-10-02 12:04:33 -070073
Chenjie Yua7259ab2017-12-10 08:31:05 -080074void MetricProducer::onMatchedLogEventLocked(const size_t matcherIndex, const LogEvent& event) {
Tej Singh597c7162019-04-17 16:41:45 -070075 if (!mIsActive) {
76 return;
77 }
Yangster-macb142cc82018-03-30 15:22:08 -070078 int64_t eventTimeNs = event.GetElapsedTimestampNs();
Yao Chenb7041772017-10-20 16:59:25 -070079 // this is old event, maybe statsd restarted?
Yangster-mac15f6bbc2018-04-08 11:52:26 -070080 if (eventTimeNs < mTimeBaseNs) {
Yao Chenb7041772017-10-20 16:59:25 -070081 return;
82 }
83
Yao Chenb7041772017-10-20 16:59:25 -070084 bool condition;
Yangster-mac94e197c2018-01-02 16:03:03 -080085 ConditionKey conditionKey;
Yao Chenb7041772017-10-20 16:59:25 -070086 if (mConditionSliced) {
Yao Chen8a8d16c2018-02-08 14:50:40 -080087 for (const auto& link : mMetric2ConditionLinks) {
Yangster-mac53928882018-02-25 23:02:56 -080088 getDimensionForCondition(event.getValues(), link, &conditionKey[link.conditionId]);
Yao Chenb7041772017-10-20 16:59:25 -070089 }
Yangster-mac93694462018-01-22 20:49:31 -080090 auto conditionState =
tsaichristine76853372019-08-06 17:17:03 -070091 mWizard->query(mConditionTrackerIndex, conditionKey,
92 !mHasLinksToAllConditionDimensionsInTracker);
Yangster-mac93694462018-01-22 20:49:31 -080093 condition = (conditionState == ConditionState::kTrue);
Yao Chenb7041772017-10-20 16:59:25 -070094 } else {
Olivier Gaillarde63d9e02019-02-12 14:43:59 +000095 // TODO: The unknown condition state is not handled here, we should fix it.
96 condition = mCondition == ConditionState::kTrue;
Yao Chenb7041772017-10-20 16:59:25 -070097 }
Yangster-mac20877162017-12-22 17:19:39 -080098
tsaichristine69000e62019-10-18 17:34:52 -070099 // Stores atom id to primary key pairs for each state atom that the metric is
100 // sliced by.
101 std::map<int, HashableDimensionKey> statePrimaryKeys;
102
103 // For states with primary fields, use MetricStateLinks to get the primary
104 // field values from the log event. These values will form a primary key
105 // that will be used to query StateTracker for the correct state value.
106 for (const auto& stateLink : mMetric2StateLinks) {
107 getDimensionForState(event.getValues(), stateLink,
108 &statePrimaryKeys[stateLink.stateAtomId]);
109 }
110
111 // For each sliced state, query StateTracker for the state value using
112 // either the primary key from the previous step or the DEFAULT_DIMENSION_KEY.
113 //
114 // Expected functionality: for any case where the MetricStateLinks are
115 // initialized incorrectly (ex. # of state links != # of primary fields, no
116 // links are provided for a state with primary fields, links are provided
117 // in the wrong order, etc.), StateTracker will simply return kStateUnknown
118 // when queried using an incorrect key.
119 HashableDimensionKey stateValuesKey;
120 for (auto atomId : mSlicedStateAtoms) {
121 FieldValue value;
122 if (statePrimaryKeys.find(atomId) != statePrimaryKeys.end()) {
123 // found a primary key for this state, query using the key
tsaichristine1449fa42020-01-02 12:12:05 -0800124 queryStateValue(atomId, statePrimaryKeys[atomId], &value);
tsaichristine69000e62019-10-18 17:34:52 -0700125 } else {
126 // if no MetricStateLinks exist for this state atom,
127 // query using the default dimension key (empty HashableDimensionKey)
tsaichristine1449fa42020-01-02 12:12:05 -0800128 queryStateValue(atomId, DEFAULT_DIMENSION_KEY, &value);
tsaichristine69000e62019-10-18 17:34:52 -0700129 }
tsaichristine1449fa42020-01-02 12:12:05 -0800130 mapStateValue(atomId, &value);
tsaichristine69000e62019-10-18 17:34:52 -0700131 stateValuesKey.addValue(value);
132 }
133
Yangster-mace06cfd72018-03-10 23:22:59 -0800134 HashableDimensionKey dimensionInWhat;
135 filterValues(mDimensionsInWhat, event.getValues(), &dimensionInWhat);
tsaichristine69000e62019-10-18 17:34:52 -0700136 MetricDimensionKey metricKey(dimensionInWhat, stateValuesKey);
tsaichristinec876b492019-12-10 13:47:05 -0800137 onMatchedLogEventInternalLocked(matcherIndex, metricKey, conditionKey, condition, event,
138 statePrimaryKeys);
Yangster-mac849dfdc22018-10-12 15:41:45 -0700139}
Yangster13fb7e42018-03-07 17:30:49 -0800140
Yangster-mac849dfdc22018-10-12 15:41:45 -0700141bool MetricProducer::evaluateActiveStateLocked(int64_t elapsedTimestampNs) {
142 bool isActive = mEventActivationMap.empty();
143 for (auto& it : mEventActivationMap) {
Muhammad Qureshi3a5ebf52019-03-28 12:38:21 -0700144 if (it.second->state == ActivationState::kActive &&
Muhammad Qureshi844694b2019-04-05 10:10:40 -0700145 elapsedTimestampNs > it.second->ttl_ns + it.second->start_ns) {
Muhammad Qureshi3a5ebf52019-03-28 12:38:21 -0700146 it.second->state = ActivationState::kNotActive;
Yangster-mac849dfdc22018-10-12 15:41:45 -0700147 }
Muhammad Qureshi3a5ebf52019-03-28 12:38:21 -0700148 if (it.second->state == ActivationState::kActive) {
Yangster-mac849dfdc22018-10-12 15:41:45 -0700149 isActive = true;
150 }
151 }
152 return isActive;
153}
154
155void MetricProducer::flushIfExpire(int64_t elapsedTimestampNs) {
156 std::lock_guard<std::mutex> lock(mMutex);
157 if (!mIsActive) {
158 return;
159 }
160 mIsActive = evaluateActiveStateLocked(elapsedTimestampNs);
161 if (!mIsActive) {
Muhammad Qureshi18e46922019-05-24 16:38:49 -0700162 onActiveStateChangedLocked(elapsedTimestampNs);
Yangster-mac849dfdc22018-10-12 15:41:45 -0700163 }
164}
165
Yangster-mac849dfdc22018-10-12 15:41:45 -0700166void MetricProducer::activateLocked(int activationTrackerIndex, int64_t elapsedTimestampNs) {
167 auto it = mEventActivationMap.find(activationTrackerIndex);
168 if (it == mEventActivationMap.end()) {
169 return;
170 }
Muhammad Qureshi15f8da92019-04-05 10:10:40 -0700171 auto& activation = it->second;
172 if (ACTIVATE_ON_BOOT == activation->activationType) {
173 if (ActivationState::kNotActive == activation->state) {
174 activation->state = ActivationState::kActiveOnBoot;
175 }
176 // If the Activation is already active or set to kActiveOnBoot, do nothing.
Chenjie Yua9a310e2019-02-06 13:40:10 -0800177 return;
178 }
Muhammad Qureshi15f8da92019-04-05 10:10:40 -0700179 activation->start_ns = elapsedTimestampNs;
180 activation->state = ActivationState::kActive;
Muhammad Qureshi18e46922019-05-24 16:38:49 -0700181 bool oldActiveState = mIsActive;
Yangster-mac849dfdc22018-10-12 15:41:45 -0700182 mIsActive = true;
Muhammad Qureshi18e46922019-05-24 16:38:49 -0700183 if (!oldActiveState) { // Metric went from not active to active.
184 onActiveStateChangedLocked(elapsedTimestampNs);
185 }
Yangster-mac849dfdc22018-10-12 15:41:45 -0700186}
187
Muhammad Qureshi3a5ebf52019-03-28 12:38:21 -0700188void MetricProducer::cancelEventActivationLocked(int deactivationTrackerIndex) {
189 auto it = mEventDeactivationMap.find(deactivationTrackerIndex);
190 if (it == mEventDeactivationMap.end()) {
191 return;
192 }
Tej Singhee4495e2019-06-03 18:37:35 -0700193 for (auto activationToCancelIt : it->second) {
194 activationToCancelIt->state = ActivationState::kNotActive;
195 }
Muhammad Qureshi3a5ebf52019-03-28 12:38:21 -0700196}
197
Muhammad Qureshi844694b2019-04-05 10:10:40 -0700198void MetricProducer::loadActiveMetricLocked(const ActiveMetric& activeMetric,
199 int64_t currentTimeNs) {
Chenjie Yuc7939cb2019-02-04 17:25:45 -0800200 if (mEventActivationMap.size() == 0) {
201 return;
202 }
Muhammad Qureshi844694b2019-04-05 10:10:40 -0700203 for (int i = 0; i < activeMetric.activation_size(); i++) {
204 const auto& activeEventActivation = activeMetric.activation(i);
205 auto it = mEventActivationMap.find(activeEventActivation.atom_matcher_index());
206 if (it == mEventActivationMap.end()) {
207 ALOGE("Saved event activation not found");
208 continue;
Chenjie Yua9a310e2019-02-06 13:40:10 -0800209 }
Muhammad Qureshi844694b2019-04-05 10:10:40 -0700210 auto& activation = it->second;
Tej Singhcbf2c642019-06-07 17:23:30 -0700211 // If the event activation does not have a state, assume it is active.
212 if (!activeEventActivation.has_state() ||
213 activeEventActivation.state() == ActiveEventActivation::ACTIVE) {
Tej Singhf53d4452019-05-09 18:17:59 -0700214 // We don't want to change the ttl for future activations, so we set the start_ns
215 // such that start_ns + ttl_ns == currentTimeNs + remaining_ttl_nanos
216 activation->start_ns =
217 currentTimeNs + activeEventActivation.remaining_ttl_nanos() - activation->ttl_ns;
218 activation->state = ActivationState::kActive;
219 mIsActive = true;
220 } else if (activeEventActivation.state() == ActiveEventActivation::ACTIVATE_ON_BOOT) {
221 activation->state = ActivationState::kActiveOnBoot;
222 }
Chenjie Yua9a310e2019-02-06 13:40:10 -0800223 }
Chenjie Yuc7939cb2019-02-04 17:25:45 -0800224}
225
Muhammad Qureshi844694b2019-04-05 10:10:40 -0700226void MetricProducer::writeActiveMetricToProtoOutputStream(
Tej Singhf53d4452019-05-09 18:17:59 -0700227 int64_t currentTimeNs, const DumpReportReason reason, ProtoOutputStream* proto) {
Muhammad Qureshi844694b2019-04-05 10:10:40 -0700228 proto->write(FIELD_TYPE_INT64 | FIELD_ID_ACTIVE_METRIC_ID, (long long)mMetricId);
229 for (auto& it : mEventActivationMap) {
230 const int atom_matcher_index = it.first;
231 const std::shared_ptr<Activation>& activation = it.second;
Yao Chenb7041772017-10-20 16:59:25 -0700232
Muhammad Qureshi844694b2019-04-05 10:10:40 -0700233 if (ActivationState::kNotActive == activation->state ||
234 (ActivationState::kActive == activation->state &&
235 activation->start_ns + activation->ttl_ns < currentTimeNs)) {
236 continue;
Chenjie Yua9a310e2019-02-06 13:40:10 -0800237 }
Muhammad Qureshi844694b2019-04-05 10:10:40 -0700238
239 const uint64_t activationToken = proto->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED |
240 FIELD_ID_ACTIVE_METRIC_ACTIVATION);
241 proto->write(FIELD_TYPE_INT32 | FIELD_ID_ACTIVE_EVENT_ACTIVATION_ATOM_MATCHER_INDEX,
242 atom_matcher_index);
243 if (ActivationState::kActive == activation->state) {
244 const int64_t remainingTtlNs =
245 activation->start_ns + activation->ttl_ns - currentTimeNs;
246 proto->write(FIELD_TYPE_INT64 | FIELD_ID_ACTIVE_EVENT_ACTIVATION_REMAINING_TTL_NANOS,
247 (long long)remainingTtlNs);
Tej Singhf53d4452019-05-09 18:17:59 -0700248 proto->write(FIELD_TYPE_ENUM | FIELD_ID_ACTIVE_EVENT_ACTIVATION_STATE,
249 ActiveEventActivation::ACTIVE);
250
Muhammad Qureshi844694b2019-04-05 10:10:40 -0700251 } else if (ActivationState::kActiveOnBoot == activation->state) {
Tej Singhf53d4452019-05-09 18:17:59 -0700252 if (reason == DEVICE_SHUTDOWN || reason == TERMINATION_SIGNAL_RECEIVED) {
253 proto->write(
254 FIELD_TYPE_INT64 | FIELD_ID_ACTIVE_EVENT_ACTIVATION_REMAINING_TTL_NANOS,
255 (long long)activation->ttl_ns);
256 proto->write(FIELD_TYPE_ENUM | FIELD_ID_ACTIVE_EVENT_ACTIVATION_STATE,
257 ActiveEventActivation::ACTIVE);
258 } else if (reason == STATSCOMPANION_DIED) {
259 // We are saving because of system server death, not due to a device shutdown.
260 // Next time we load, we do not want to activate metrics that activate on boot.
261 proto->write(FIELD_TYPE_ENUM | FIELD_ID_ACTIVE_EVENT_ACTIVATION_STATE,
262 ActiveEventActivation::ACTIVATE_ON_BOOT);
263 }
Muhammad Qureshi844694b2019-04-05 10:10:40 -0700264 }
265 proto->end(activationToken);
Chenjie Yua9a310e2019-02-06 13:40:10 -0800266 }
267}
268
tsaichristine1449fa42020-01-02 12:12:05 -0800269void MetricProducer::queryStateValue(const int32_t atomId, const HashableDimensionKey& queryKey,
270 FieldValue* value) {
tsaichristine69000e62019-10-18 17:34:52 -0700271 if (!StateManager::getInstance().getStateValue(atomId, queryKey, value)) {
272 value->mValue = Value(StateTracker::kStateUnknown);
tsaichristinec876b492019-12-10 13:47:05 -0800273 value->mField.setTag(atomId);
tsaichristine69000e62019-10-18 17:34:52 -0700274 ALOGW("StateTracker not found for state atom %d", atomId);
275 return;
276 }
tsaichristine1449fa42020-01-02 12:12:05 -0800277}
tsaichristine69000e62019-10-18 17:34:52 -0700278
tsaichristine1449fa42020-01-02 12:12:05 -0800279void MetricProducer::mapStateValue(const int32_t atomId, FieldValue* value) {
tsaichristine69000e62019-10-18 17:34:52 -0700280 // check if there is a state map for this atom
281 auto atomIt = mStateGroupMap.find(atomId);
282 if (atomIt == mStateGroupMap.end()) {
283 return;
284 }
285 auto valueIt = atomIt->second.find(value->mValue.int_value);
286 if (valueIt == atomIt->second.end()) {
287 // state map exists, but value was not put in a state group
288 // so set mValue to kStateUnknown
289 // TODO(tsaichristine): handle incomplete state maps
290 value->mValue.setInt(StateTracker::kStateUnknown);
291 } else {
292 // set mValue to group_id
293 value->mValue.setLong(valueIt->second);
294 }
295}
296
tsaichristine5088e722020-05-28 10:06:41 -0700297HashableDimensionKey MetricProducer::getUnknownStateKey() {
298 HashableDimensionKey stateKey;
299 for (auto atom : mSlicedStateAtoms) {
300 FieldValue fieldValue;
301 fieldValue.mField.setTag(atom);
302 fieldValue.mValue.setInt(StateTracker::kStateUnknown);
303 stateKey.addValue(fieldValue);
304 }
305 return stateKey;
306}
307
tsaichristineb87ca152019-12-09 15:19:41 -0800308DropEvent MetricProducer::buildDropEvent(const int64_t dropTimeNs, const BucketDropReason reason) {
309 DropEvent event;
310 event.reason = reason;
311 event.dropTimeNs = dropTimeNs;
312 return event;
313}
314
315bool MetricProducer::maxDropEventsReached() {
316 return mCurrentSkippedBucket.dropEvents.size() >= StatsdStats::kMaxLoggedBucketDropEvents;
317}
318
Yao Chenb7041772017-10-20 16:59:25 -0700319} // namespace statsd
320} // namespace os
yro2b0f8862017-11-06 14:27:31 -0800321} // namespace android