• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2017 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #define DEBUG false  // STOPSHIP if true
18 #include "Log.h"
19 
20 #include "MetricProducer.h"
21 
22 #include "../guardrail/StatsdStats.h"
23 #include "metrics/parsing_utils/metrics_manager_util.h"
24 #include "state/StateTracker.h"
25 
26 using android::util::FIELD_COUNT_REPEATED;
27 using android::util::FIELD_TYPE_ENUM;
28 using android::util::FIELD_TYPE_INT32;
29 using android::util::FIELD_TYPE_INT64;
30 using android::util::FIELD_TYPE_MESSAGE;
31 using android::util::ProtoOutputStream;
32 
33 namespace android {
34 namespace os {
35 namespace statsd {
36 
37 
38 // for ActiveMetric
39 const int FIELD_ID_ACTIVE_METRIC_ID = 1;
40 const int FIELD_ID_ACTIVE_METRIC_ACTIVATION = 2;
41 
42 // for ActiveEventActivation
43 const int FIELD_ID_ACTIVE_EVENT_ACTIVATION_ATOM_MATCHER_INDEX = 1;
44 const int FIELD_ID_ACTIVE_EVENT_ACTIVATION_REMAINING_TTL_NANOS = 2;
45 const int FIELD_ID_ACTIVE_EVENT_ACTIVATION_STATE = 3;
46 
MetricProducer(const int64_t & metricId,const ConfigKey & key,const int64_t timeBaseNs,const int conditionIndex,const vector<ConditionState> & initialConditionCache,const sp<ConditionWizard> & wizard,const uint64_t protoHash,const std::unordered_map<int,std::shared_ptr<Activation>> & eventActivationMap,const std::unordered_map<int,std::vector<std::shared_ptr<Activation>>> & eventDeactivationMap,const vector<int> & slicedStateAtoms,const unordered_map<int,unordered_map<int,int64_t>> & stateGroupMap)47 MetricProducer::MetricProducer(
48         const int64_t& metricId, const ConfigKey& key, const int64_t timeBaseNs,
49         const int conditionIndex, const vector<ConditionState>& initialConditionCache,
50         const sp<ConditionWizard>& wizard, const uint64_t protoHash,
51         const std::unordered_map<int, std::shared_ptr<Activation>>& eventActivationMap,
52         const std::unordered_map<int, std::vector<std::shared_ptr<Activation>>>&
53                 eventDeactivationMap,
54         const vector<int>& slicedStateAtoms,
55         const unordered_map<int, unordered_map<int, int64_t>>& stateGroupMap)
56     : mMetricId(metricId),
57       mProtoHash(protoHash),
58       mConfigKey(key),
59       mValid(true),
60       mTimeBaseNs(timeBaseNs),
61       mCurrentBucketStartTimeNs(timeBaseNs),
62       mCurrentBucketNum(0),
63       mCondition(initialCondition(conditionIndex, initialConditionCache)),
64       mConditionTrackerIndex(conditionIndex),
65       mConditionSliced(false),
66       mWizard(wizard),
67       mContainANYPositionInDimensionsInWhat(false),
68       mSliceByPositionALL(false),
69       mHasLinksToAllConditionDimensionsInTracker(false),
70       mEventActivationMap(eventActivationMap),
71       mEventDeactivationMap(eventDeactivationMap),
72       mIsActive(mEventActivationMap.empty()),
73       mSlicedStateAtoms(slicedStateAtoms),
74       mStateGroupMap(stateGroupMap) {
75 }
76 
onConfigUpdatedLocked(const StatsdConfig & config,const int configIndex,const int metricIndex,const vector<sp<AtomMatchingTracker>> & allAtomMatchingTrackers,const unordered_map<int64_t,int> & oldAtomMatchingTrackerMap,const unordered_map<int64_t,int> & newAtomMatchingTrackerMap,const sp<EventMatcherWizard> & matcherWizard,const vector<sp<ConditionTracker>> & allConditionTrackers,const unordered_map<int64_t,int> & conditionTrackerMap,const sp<ConditionWizard> & wizard,const unordered_map<int64_t,int> & metricToActivationMap,unordered_map<int,vector<int>> & trackerToMetricMap,unordered_map<int,vector<int>> & conditionToMetricMap,unordered_map<int,vector<int>> & activationAtomTrackerToMetricMap,unordered_map<int,vector<int>> & deactivationAtomTrackerToMetricMap,vector<int> & metricsWithActivation)77 bool MetricProducer::onConfigUpdatedLocked(
78         const StatsdConfig& config, const int configIndex, const int metricIndex,
79         const vector<sp<AtomMatchingTracker>>& allAtomMatchingTrackers,
80         const unordered_map<int64_t, int>& oldAtomMatchingTrackerMap,
81         const unordered_map<int64_t, int>& newAtomMatchingTrackerMap,
82         const sp<EventMatcherWizard>& matcherWizard,
83         const vector<sp<ConditionTracker>>& allConditionTrackers,
84         const unordered_map<int64_t, int>& conditionTrackerMap, const sp<ConditionWizard>& wizard,
85         const unordered_map<int64_t, int>& metricToActivationMap,
86         unordered_map<int, vector<int>>& trackerToMetricMap,
87         unordered_map<int, vector<int>>& conditionToMetricMap,
88         unordered_map<int, vector<int>>& activationAtomTrackerToMetricMap,
89         unordered_map<int, vector<int>>& deactivationAtomTrackerToMetricMap,
90         vector<int>& metricsWithActivation) {
91     sp<ConditionWizard> tmpWizard = mWizard;
92     mWizard = wizard;
93 
94     unordered_map<int, shared_ptr<Activation>> newEventActivationMap;
95     unordered_map<int, vector<shared_ptr<Activation>>> newEventDeactivationMap;
96     if (!handleMetricActivationOnConfigUpdate(
97                 config, mMetricId, metricIndex, metricToActivationMap, oldAtomMatchingTrackerMap,
98                 newAtomMatchingTrackerMap, mEventActivationMap, activationAtomTrackerToMetricMap,
99                 deactivationAtomTrackerToMetricMap, metricsWithActivation, newEventActivationMap,
100                 newEventDeactivationMap)) {
101         return false;
102     }
103     mEventActivationMap = newEventActivationMap;
104     mEventDeactivationMap = newEventDeactivationMap;
105     mAnomalyTrackers.clear();
106     return true;
107 }
108 
onMatchedLogEventLocked(const size_t matcherIndex,const LogEvent & event)109 void MetricProducer::onMatchedLogEventLocked(const size_t matcherIndex, const LogEvent& event) {
110     if (!mIsActive) {
111         return;
112     }
113     int64_t eventTimeNs = event.GetElapsedTimestampNs();
114     // this is old event, maybe statsd restarted?
115     if (eventTimeNs < mTimeBaseNs) {
116         return;
117     }
118 
119     bool condition;
120     ConditionKey conditionKey;
121     if (mConditionSliced) {
122         for (const auto& link : mMetric2ConditionLinks) {
123             getDimensionForCondition(event.getValues(), link, &conditionKey[link.conditionId]);
124         }
125         auto conditionState =
126             mWizard->query(mConditionTrackerIndex, conditionKey,
127                            !mHasLinksToAllConditionDimensionsInTracker);
128         condition = (conditionState == ConditionState::kTrue);
129     } else {
130         // TODO: The unknown condition state is not handled here, we should fix it.
131         condition = mCondition == ConditionState::kTrue;
132     }
133 
134     // Stores atom id to primary key pairs for each state atom that the metric is
135     // sliced by.
136     std::map<int32_t, HashableDimensionKey> statePrimaryKeys;
137 
138     // For states with primary fields, use MetricStateLinks to get the primary
139     // field values from the log event. These values will form a primary key
140     // that will be used to query StateTracker for the correct state value.
141     for (const auto& stateLink : mMetric2StateLinks) {
142         getDimensionForState(event.getValues(), stateLink,
143                              &statePrimaryKeys[stateLink.stateAtomId]);
144     }
145 
146     // For each sliced state, query StateTracker for the state value using
147     // either the primary key from the previous step or the DEFAULT_DIMENSION_KEY.
148     //
149     // Expected functionality: for any case where the MetricStateLinks are
150     // initialized incorrectly (ex. # of state links != # of primary fields, no
151     // links are provided for a state with primary fields, links are provided
152     // in the wrong order, etc.), StateTracker will simply return kStateUnknown
153     // when queried using an incorrect key.
154     HashableDimensionKey stateValuesKey;
155     for (auto atomId : mSlicedStateAtoms) {
156         FieldValue value;
157         if (statePrimaryKeys.find(atomId) != statePrimaryKeys.end()) {
158             // found a primary key for this state, query using the key
159             queryStateValue(atomId, statePrimaryKeys[atomId], &value);
160         } else {
161             // if no MetricStateLinks exist for this state atom,
162             // query using the default dimension key (empty HashableDimensionKey)
163             queryStateValue(atomId, DEFAULT_DIMENSION_KEY, &value);
164         }
165         mapStateValue(atomId, &value);
166         stateValuesKey.addValue(value);
167     }
168 
169     HashableDimensionKey dimensionInWhat;
170     filterValues(mDimensionsInWhat, event.getValues(), &dimensionInWhat);
171     MetricDimensionKey metricKey(dimensionInWhat, stateValuesKey);
172     onMatchedLogEventInternalLocked(matcherIndex, metricKey, conditionKey, condition, event,
173                                     statePrimaryKeys);
174 }
175 
evaluateActiveStateLocked(int64_t elapsedTimestampNs)176 bool MetricProducer::evaluateActiveStateLocked(int64_t elapsedTimestampNs) {
177     bool isActive = mEventActivationMap.empty();
178     for (auto& it : mEventActivationMap) {
179         if (it.second->state == ActivationState::kActive &&
180             elapsedTimestampNs > it.second->ttl_ns + it.second->start_ns) {
181             it.second->state = ActivationState::kNotActive;
182         }
183         if (it.second->state == ActivationState::kActive) {
184             isActive = true;
185         }
186     }
187     return isActive;
188 }
189 
flushIfExpire(int64_t elapsedTimestampNs)190 void MetricProducer::flushIfExpire(int64_t elapsedTimestampNs) {
191     std::lock_guard<std::mutex> lock(mMutex);
192     if (!mIsActive) {
193         return;
194     }
195     mIsActive = evaluateActiveStateLocked(elapsedTimestampNs);
196     if (!mIsActive) {
197         onActiveStateChangedLocked(elapsedTimestampNs);
198     }
199 }
200 
activateLocked(int activationTrackerIndex,int64_t elapsedTimestampNs)201 void MetricProducer::activateLocked(int activationTrackerIndex, int64_t elapsedTimestampNs) {
202     auto it = mEventActivationMap.find(activationTrackerIndex);
203     if (it == mEventActivationMap.end()) {
204         return;
205     }
206     auto& activation = it->second;
207     if (ACTIVATE_ON_BOOT == activation->activationType) {
208         if (ActivationState::kNotActive == activation->state) {
209             activation->state = ActivationState::kActiveOnBoot;
210         }
211         // If the Activation is already active or set to kActiveOnBoot, do nothing.
212         return;
213     }
214     activation->start_ns = elapsedTimestampNs;
215     activation->state = ActivationState::kActive;
216     bool oldActiveState = mIsActive;
217     mIsActive = true;
218     if (!oldActiveState) { // Metric went from not active to active.
219         onActiveStateChangedLocked(elapsedTimestampNs);
220     }
221 }
222 
cancelEventActivationLocked(int deactivationTrackerIndex)223 void MetricProducer::cancelEventActivationLocked(int deactivationTrackerIndex) {
224     auto it = mEventDeactivationMap.find(deactivationTrackerIndex);
225     if (it == mEventDeactivationMap.end()) {
226         return;
227     }
228     for (auto activationToCancelIt : it->second)  {
229         activationToCancelIt->state = ActivationState::kNotActive;
230     }
231 }
232 
loadActiveMetricLocked(const ActiveMetric & activeMetric,int64_t currentTimeNs)233 void MetricProducer::loadActiveMetricLocked(const ActiveMetric& activeMetric,
234                                             int64_t currentTimeNs) {
235     if (mEventActivationMap.size() == 0) {
236         return;
237     }
238     for (int i = 0; i < activeMetric.activation_size(); i++) {
239         const auto& activeEventActivation = activeMetric.activation(i);
240         auto it = mEventActivationMap.find(activeEventActivation.atom_matcher_index());
241         if (it == mEventActivationMap.end()) {
242             ALOGE("Saved event activation not found");
243             continue;
244         }
245         auto& activation = it->second;
246         // If the event activation does not have a state, assume it is active.
247         if (!activeEventActivation.has_state() ||
248                 activeEventActivation.state() == ActiveEventActivation::ACTIVE) {
249             // We don't want to change the ttl for future activations, so we set the start_ns
250             // such that start_ns + ttl_ns == currentTimeNs + remaining_ttl_nanos
251             activation->start_ns =
252                 currentTimeNs + activeEventActivation.remaining_ttl_nanos() - activation->ttl_ns;
253             activation->state = ActivationState::kActive;
254             mIsActive = true;
255         } else if (activeEventActivation.state() == ActiveEventActivation::ACTIVATE_ON_BOOT) {
256             activation->state = ActivationState::kActiveOnBoot;
257         }
258     }
259 }
260 
writeActiveMetricToProtoOutputStream(int64_t currentTimeNs,const DumpReportReason reason,ProtoOutputStream * proto)261 void MetricProducer::writeActiveMetricToProtoOutputStream(
262         int64_t currentTimeNs, const DumpReportReason reason, ProtoOutputStream* proto) {
263     proto->write(FIELD_TYPE_INT64 | FIELD_ID_ACTIVE_METRIC_ID, (long long)mMetricId);
264     for (auto& it : mEventActivationMap) {
265         const int atom_matcher_index = it.first;
266         const std::shared_ptr<Activation>& activation = it.second;
267 
268         if (ActivationState::kNotActive == activation->state ||
269                 (ActivationState::kActive == activation->state &&
270                  activation->start_ns + activation->ttl_ns < currentTimeNs)) {
271             continue;
272         }
273 
274         const uint64_t activationToken = proto->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED |
275                 FIELD_ID_ACTIVE_METRIC_ACTIVATION);
276         proto->write(FIELD_TYPE_INT32 | FIELD_ID_ACTIVE_EVENT_ACTIVATION_ATOM_MATCHER_INDEX,
277                 atom_matcher_index);
278         if (ActivationState::kActive == activation->state) {
279             const int64_t remainingTtlNs =
280                     activation->start_ns + activation->ttl_ns - currentTimeNs;
281             proto->write(FIELD_TYPE_INT64 | FIELD_ID_ACTIVE_EVENT_ACTIVATION_REMAINING_TTL_NANOS,
282                     (long long)remainingTtlNs);
283             proto->write(FIELD_TYPE_ENUM | FIELD_ID_ACTIVE_EVENT_ACTIVATION_STATE,
284                     ActiveEventActivation::ACTIVE);
285 
286         } else if (ActivationState::kActiveOnBoot == activation->state) {
287             if (reason == DEVICE_SHUTDOWN || reason == TERMINATION_SIGNAL_RECEIVED) {
288                 proto->write(
289                         FIELD_TYPE_INT64 | FIELD_ID_ACTIVE_EVENT_ACTIVATION_REMAINING_TTL_NANOS,
290                         (long long)activation->ttl_ns);
291                 proto->write(FIELD_TYPE_ENUM | FIELD_ID_ACTIVE_EVENT_ACTIVATION_STATE,
292                                     ActiveEventActivation::ACTIVE);
293             } else if (reason == STATSCOMPANION_DIED) {
294                 // We are saving because of system server death, not due to a device shutdown.
295                 // Next time we load, we do not want to activate metrics that activate on boot.
296                 proto->write(FIELD_TYPE_ENUM | FIELD_ID_ACTIVE_EVENT_ACTIVATION_STATE,
297                                                     ActiveEventActivation::ACTIVATE_ON_BOOT);
298             }
299         }
300         proto->end(activationToken);
301     }
302 }
303 
queryStateValue(const int32_t atomId,const HashableDimensionKey & queryKey,FieldValue * value)304 void MetricProducer::queryStateValue(const int32_t atomId, const HashableDimensionKey& queryKey,
305                                      FieldValue* value) {
306     if (!StateManager::getInstance().getStateValue(atomId, queryKey, value)) {
307         value->mValue = Value(StateTracker::kStateUnknown);
308         value->mField.setTag(atomId);
309         ALOGW("StateTracker not found for state atom %d", atomId);
310         return;
311     }
312 }
313 
mapStateValue(const int32_t atomId,FieldValue * value)314 void MetricProducer::mapStateValue(const int32_t atomId, FieldValue* value) {
315     // check if there is a state map for this atom
316     auto atomIt = mStateGroupMap.find(atomId);
317     if (atomIt == mStateGroupMap.end()) {
318         return;
319     }
320     auto valueIt = atomIt->second.find(value->mValue.int_value);
321     if (valueIt == atomIt->second.end()) {
322         // state map exists, but value was not put in a state group
323         // so set mValue to kStateUnknown
324         // TODO(tsaichristine): handle incomplete state maps
325         value->mValue.setInt(StateTracker::kStateUnknown);
326     } else {
327         // set mValue to group_id
328         value->mValue.setLong(valueIt->second);
329     }
330 }
331 
getUnknownStateKey()332 HashableDimensionKey MetricProducer::getUnknownStateKey() {
333     HashableDimensionKey stateKey;
334     for (auto atom : mSlicedStateAtoms) {
335         FieldValue fieldValue;
336         fieldValue.mField.setTag(atom);
337         fieldValue.mValue.setInt(StateTracker::kStateUnknown);
338         stateKey.addValue(fieldValue);
339     }
340     return stateKey;
341 }
342 
buildDropEvent(const int64_t dropTimeNs,const BucketDropReason reason)343 DropEvent MetricProducer::buildDropEvent(const int64_t dropTimeNs, const BucketDropReason reason) {
344     DropEvent event;
345     event.reason = reason;
346     event.dropTimeNs = dropTimeNs;
347     return event;
348 }
349 
maxDropEventsReached()350 bool MetricProducer::maxDropEventsReached() {
351     return mCurrentSkippedBucket.dropEvents.size() >= StatsdStats::kMaxLoggedBucketDropEvents;
352 }
353 
354 }  // namespace statsd
355 }  // namespace os
356 }  // namespace android
357