blob: cf1d2f32694897778e01c9521dfc749b17d894fb [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
36using std::map;
37
Muhammad Qureshi844694b2019-04-05 10:10:40 -070038// for ActiveMetric
39const int FIELD_ID_ACTIVE_METRIC_ID = 1;
40const int FIELD_ID_ACTIVE_METRIC_ACTIVATION = 2;
41
42// for ActiveEventActivation
43const int FIELD_ID_ACTIVE_EVENT_ACTIVATION_ATOM_MATCHER_INDEX = 1;
44const int FIELD_ID_ACTIVE_EVENT_ACTIVATION_REMAINING_TTL_NANOS = 2;
Tej Singhf53d4452019-05-09 18:17:59 -070045const int FIELD_ID_ACTIVE_EVENT_ACTIVATION_STATE = 3;
Muhammad Qureshi844694b2019-04-05 10:10:40 -070046
Ruchir Rastogi21a287b2019-10-02 12:04:33 -070047MetricProducer::MetricProducer(
48 const int64_t& metricId, const ConfigKey& key, const int64_t timeBaseNs,
49 const int conditionIndex, const sp<ConditionWizard>& wizard,
50 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),
60 mCondition(initialCondition(conditionIndex)),
61 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
124 getMappedStateValue(atomId, statePrimaryKeys[atomId], &value);
125 } else {
126 // if no MetricStateLinks exist for this state atom,
127 // query using the default dimension key (empty HashableDimensionKey)
128 getMappedStateValue(atomId, DEFAULT_DIMENSION_KEY, &value);
129 }
130 stateValuesKey.addValue(value);
131 }
132
Yangster-mace06cfd72018-03-10 23:22:59 -0800133 HashableDimensionKey dimensionInWhat;
134 filterValues(mDimensionsInWhat, event.getValues(), &dimensionInWhat);
tsaichristine69000e62019-10-18 17:34:52 -0700135 MetricDimensionKey metricKey(dimensionInWhat, stateValuesKey);
tsaichristine76853372019-08-06 17:17:03 -0700136 onMatchedLogEventInternalLocked(
137 matcherIndex, metricKey, conditionKey, condition, event);
Yangster-mac849dfdc22018-10-12 15:41:45 -0700138}
Yangster13fb7e42018-03-07 17:30:49 -0800139
Yangster-mac849dfdc22018-10-12 15:41:45 -0700140bool MetricProducer::evaluateActiveStateLocked(int64_t elapsedTimestampNs) {
141 bool isActive = mEventActivationMap.empty();
142 for (auto& it : mEventActivationMap) {
Muhammad Qureshi3a5ebf52019-03-28 12:38:21 -0700143 if (it.second->state == ActivationState::kActive &&
Muhammad Qureshi844694b2019-04-05 10:10:40 -0700144 elapsedTimestampNs > it.second->ttl_ns + it.second->start_ns) {
Muhammad Qureshi3a5ebf52019-03-28 12:38:21 -0700145 it.second->state = ActivationState::kNotActive;
Yangster-mac849dfdc22018-10-12 15:41:45 -0700146 }
Muhammad Qureshi3a5ebf52019-03-28 12:38:21 -0700147 if (it.second->state == ActivationState::kActive) {
Yangster-mac849dfdc22018-10-12 15:41:45 -0700148 isActive = true;
149 }
150 }
151 return isActive;
152}
153
154void MetricProducer::flushIfExpire(int64_t elapsedTimestampNs) {
155 std::lock_guard<std::mutex> lock(mMutex);
156 if (!mIsActive) {
157 return;
158 }
159 mIsActive = evaluateActiveStateLocked(elapsedTimestampNs);
160 if (!mIsActive) {
Muhammad Qureshi18e46922019-05-24 16:38:49 -0700161 onActiveStateChangedLocked(elapsedTimestampNs);
Yangster-mac849dfdc22018-10-12 15:41:45 -0700162 }
163}
164
Yangster-mac849dfdc22018-10-12 15:41:45 -0700165void MetricProducer::activateLocked(int activationTrackerIndex, int64_t elapsedTimestampNs) {
166 auto it = mEventActivationMap.find(activationTrackerIndex);
167 if (it == mEventActivationMap.end()) {
168 return;
169 }
Muhammad Qureshi15f8da92019-04-05 10:10:40 -0700170 auto& activation = it->second;
171 if (ACTIVATE_ON_BOOT == activation->activationType) {
172 if (ActivationState::kNotActive == activation->state) {
173 activation->state = ActivationState::kActiveOnBoot;
174 }
175 // If the Activation is already active or set to kActiveOnBoot, do nothing.
Chenjie Yua9a310e2019-02-06 13:40:10 -0800176 return;
177 }
Muhammad Qureshi15f8da92019-04-05 10:10:40 -0700178 activation->start_ns = elapsedTimestampNs;
179 activation->state = ActivationState::kActive;
Muhammad Qureshi18e46922019-05-24 16:38:49 -0700180 bool oldActiveState = mIsActive;
Yangster-mac849dfdc22018-10-12 15:41:45 -0700181 mIsActive = true;
Muhammad Qureshi18e46922019-05-24 16:38:49 -0700182 if (!oldActiveState) { // Metric went from not active to active.
183 onActiveStateChangedLocked(elapsedTimestampNs);
184 }
Yangster-mac849dfdc22018-10-12 15:41:45 -0700185}
186
Muhammad Qureshi3a5ebf52019-03-28 12:38:21 -0700187void MetricProducer::cancelEventActivationLocked(int deactivationTrackerIndex) {
188 auto it = mEventDeactivationMap.find(deactivationTrackerIndex);
189 if (it == mEventDeactivationMap.end()) {
190 return;
191 }
Tej Singhee4495e2019-06-03 18:37:35 -0700192 for (auto activationToCancelIt : it->second) {
193 activationToCancelIt->state = ActivationState::kNotActive;
194 }
Muhammad Qureshi3a5ebf52019-03-28 12:38:21 -0700195}
196
Muhammad Qureshi844694b2019-04-05 10:10:40 -0700197void MetricProducer::loadActiveMetricLocked(const ActiveMetric& activeMetric,
198 int64_t currentTimeNs) {
Chenjie Yuc7939cb2019-02-04 17:25:45 -0800199 if (mEventActivationMap.size() == 0) {
200 return;
201 }
Muhammad Qureshi844694b2019-04-05 10:10:40 -0700202 for (int i = 0; i < activeMetric.activation_size(); i++) {
203 const auto& activeEventActivation = activeMetric.activation(i);
204 auto it = mEventActivationMap.find(activeEventActivation.atom_matcher_index());
205 if (it == mEventActivationMap.end()) {
206 ALOGE("Saved event activation not found");
207 continue;
Chenjie Yua9a310e2019-02-06 13:40:10 -0800208 }
Muhammad Qureshi844694b2019-04-05 10:10:40 -0700209 auto& activation = it->second;
Tej Singhcbf2c642019-06-07 17:23:30 -0700210 // If the event activation does not have a state, assume it is active.
211 if (!activeEventActivation.has_state() ||
212 activeEventActivation.state() == ActiveEventActivation::ACTIVE) {
Tej Singhf53d4452019-05-09 18:17:59 -0700213 // We don't want to change the ttl for future activations, so we set the start_ns
214 // such that start_ns + ttl_ns == currentTimeNs + remaining_ttl_nanos
215 activation->start_ns =
216 currentTimeNs + activeEventActivation.remaining_ttl_nanos() - activation->ttl_ns;
217 activation->state = ActivationState::kActive;
218 mIsActive = true;
219 } else if (activeEventActivation.state() == ActiveEventActivation::ACTIVATE_ON_BOOT) {
220 activation->state = ActivationState::kActiveOnBoot;
221 }
Chenjie Yua9a310e2019-02-06 13:40:10 -0800222 }
Chenjie Yuc7939cb2019-02-04 17:25:45 -0800223}
224
Muhammad Qureshi844694b2019-04-05 10:10:40 -0700225void MetricProducer::writeActiveMetricToProtoOutputStream(
Tej Singhf53d4452019-05-09 18:17:59 -0700226 int64_t currentTimeNs, const DumpReportReason reason, ProtoOutputStream* proto) {
Muhammad Qureshi844694b2019-04-05 10:10:40 -0700227 proto->write(FIELD_TYPE_INT64 | FIELD_ID_ACTIVE_METRIC_ID, (long long)mMetricId);
228 for (auto& it : mEventActivationMap) {
229 const int atom_matcher_index = it.first;
230 const std::shared_ptr<Activation>& activation = it.second;
Yao Chenb7041772017-10-20 16:59:25 -0700231
Muhammad Qureshi844694b2019-04-05 10:10:40 -0700232 if (ActivationState::kNotActive == activation->state ||
233 (ActivationState::kActive == activation->state &&
234 activation->start_ns + activation->ttl_ns < currentTimeNs)) {
235 continue;
Chenjie Yua9a310e2019-02-06 13:40:10 -0800236 }
Muhammad Qureshi844694b2019-04-05 10:10:40 -0700237
238 const uint64_t activationToken = proto->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED |
239 FIELD_ID_ACTIVE_METRIC_ACTIVATION);
240 proto->write(FIELD_TYPE_INT32 | FIELD_ID_ACTIVE_EVENT_ACTIVATION_ATOM_MATCHER_INDEX,
241 atom_matcher_index);
242 if (ActivationState::kActive == activation->state) {
243 const int64_t remainingTtlNs =
244 activation->start_ns + activation->ttl_ns - currentTimeNs;
245 proto->write(FIELD_TYPE_INT64 | FIELD_ID_ACTIVE_EVENT_ACTIVATION_REMAINING_TTL_NANOS,
246 (long long)remainingTtlNs);
Tej Singhf53d4452019-05-09 18:17:59 -0700247 proto->write(FIELD_TYPE_ENUM | FIELD_ID_ACTIVE_EVENT_ACTIVATION_STATE,
248 ActiveEventActivation::ACTIVE);
249
Muhammad Qureshi844694b2019-04-05 10:10:40 -0700250 } else if (ActivationState::kActiveOnBoot == activation->state) {
Tej Singhf53d4452019-05-09 18:17:59 -0700251 if (reason == DEVICE_SHUTDOWN || reason == TERMINATION_SIGNAL_RECEIVED) {
252 proto->write(
253 FIELD_TYPE_INT64 | FIELD_ID_ACTIVE_EVENT_ACTIVATION_REMAINING_TTL_NANOS,
254 (long long)activation->ttl_ns);
255 proto->write(FIELD_TYPE_ENUM | FIELD_ID_ACTIVE_EVENT_ACTIVATION_STATE,
256 ActiveEventActivation::ACTIVE);
257 } else if (reason == STATSCOMPANION_DIED) {
258 // We are saving because of system server death, not due to a device shutdown.
259 // Next time we load, we do not want to activate metrics that activate on boot.
260 proto->write(FIELD_TYPE_ENUM | FIELD_ID_ACTIVE_EVENT_ACTIVATION_STATE,
261 ActiveEventActivation::ACTIVATE_ON_BOOT);
262 }
Muhammad Qureshi844694b2019-04-05 10:10:40 -0700263 }
264 proto->end(activationToken);
Chenjie Yua9a310e2019-02-06 13:40:10 -0800265 }
266}
267
tsaichristine69000e62019-10-18 17:34:52 -0700268void MetricProducer::getMappedStateValue(const int32_t atomId, const HashableDimensionKey& queryKey,
269 FieldValue* value) {
270 if (!StateManager::getInstance().getStateValue(atomId, queryKey, value)) {
271 value->mValue = Value(StateTracker::kStateUnknown);
272 ALOGW("StateTracker not found for state atom %d", atomId);
273 return;
274 }
275
276 // check if there is a state map for this atom
277 auto atomIt = mStateGroupMap.find(atomId);
278 if (atomIt == mStateGroupMap.end()) {
279 return;
280 }
281 auto valueIt = atomIt->second.find(value->mValue.int_value);
282 if (valueIt == atomIt->second.end()) {
283 // state map exists, but value was not put in a state group
284 // so set mValue to kStateUnknown
285 // TODO(tsaichristine): handle incomplete state maps
286 value->mValue.setInt(StateTracker::kStateUnknown);
287 } else {
288 // set mValue to group_id
289 value->mValue.setLong(valueIt->second);
290 }
291}
292
tsaichristineb87ca152019-12-09 15:19:41 -0800293DropEvent MetricProducer::buildDropEvent(const int64_t dropTimeNs, const BucketDropReason reason) {
294 DropEvent event;
295 event.reason = reason;
296 event.dropTimeNs = dropTimeNs;
297 return event;
298}
299
300bool MetricProducer::maxDropEventsReached() {
301 return mCurrentSkippedBucket.dropEvents.size() >= StatsdStats::kMaxLoggedBucketDropEvents;
302}
303
Yao Chenb7041772017-10-20 16:59:25 -0700304} // namespace statsd
305} // namespace os
yro2b0f8862017-11-06 14:27:31 -0800306} // namespace android