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 STATSD_DEBUG false // STOPSHIP if true
18 #include "Log.h"
19
20 #include "EventMetricProducer.h"
21
22 #include <limits.h>
23 #include <stdlib.h>
24
25 #include "metrics/parsing_utils/metrics_manager_util.h"
26 #include "stats_log_util.h"
27 #include "stats_util.h"
28
29 using android::util::FIELD_COUNT_REPEATED;
30 using android::util::FIELD_TYPE_BOOL;
31 using android::util::FIELD_TYPE_FLOAT;
32 using android::util::FIELD_TYPE_INT32;
33 using android::util::FIELD_TYPE_INT64;
34 using android::util::FIELD_TYPE_STRING;
35 using android::util::FIELD_TYPE_MESSAGE;
36 using android::util::ProtoOutputStream;
37 using std::map;
38 using std::string;
39 using std::unordered_map;
40 using std::vector;
41 using std::shared_ptr;
42
43 namespace android {
44 namespace os {
45 namespace statsd {
46
47 // for StatsLogReport
48 const int FIELD_ID_ID = 1;
49 const int FIELD_ID_EVENT_METRICS = 4;
50 const int FIELD_ID_IS_ACTIVE = 14;
51 const int FIELD_ID_ESTIMATED_MEMORY_BYTES = 18;
52 const int FIELD_ID_DATA_CORRUPTED_REASON = 19;
53
54 // for EventMetricDataWrapper
55 const int FIELD_ID_DATA = 1;
56 // for EventMetricData
57 const int FIELD_ID_AGGREGATED_ATOM = 4;
58 // for AggregatedAtomInfo
59 const int FIELD_ID_ATOM = 1;
60 const int FIELD_ID_ATOM_TIMESTAMPS = 2;
61
EventMetricProducer(const ConfigKey & key,const EventMetric & metric,const int conditionIndex,const vector<ConditionState> & initialConditionCache,const sp<ConditionWizard> & wizard,const uint64_t protoHash,const int64_t startTimeNs,const wp<ConfigMetadataProvider> configMetadataProvider,const unordered_map<int,shared_ptr<Activation>> & eventActivationMap,const unordered_map<int,vector<shared_ptr<Activation>>> & eventDeactivationMap,const vector<int> & slicedStateAtoms,const unordered_map<int,unordered_map<int,int64_t>> & stateGroupMap)62 EventMetricProducer::EventMetricProducer(
63 const ConfigKey& key, const EventMetric& metric, const int conditionIndex,
64 const vector<ConditionState>& initialConditionCache, const sp<ConditionWizard>& wizard,
65 const uint64_t protoHash, const int64_t startTimeNs,
66 const wp<ConfigMetadataProvider> configMetadataProvider,
67 const unordered_map<int, shared_ptr<Activation>>& eventActivationMap,
68 const unordered_map<int, vector<shared_ptr<Activation>>>& eventDeactivationMap,
69 const vector<int>& slicedStateAtoms,
70 const unordered_map<int, unordered_map<int, int64_t>>& stateGroupMap)
71 : MetricProducer(metric.id(), key, startTimeNs, conditionIndex, initialConditionCache, wizard,
72 protoHash, eventActivationMap, eventDeactivationMap, slicedStateAtoms,
73 stateGroupMap, /*splitBucketForAppUpgrade=*/nullopt, configMetadataProvider),
74 mSamplingPercentage(metric.sampling_percentage()) {
75 if (metric.links().size() > 0) {
76 for (const auto& link : metric.links()) {
77 Metric2Condition mc;
78 mc.conditionId = link.condition();
79 translateFieldMatcher(link.fields_in_what(), &mc.metricFields);
80 translateFieldMatcher(link.fields_in_condition(), &mc.conditionFields);
81 mMetric2ConditionLinks.push_back(mc);
82 }
83 mConditionSliced = true;
84 }
85
86 VLOG("metric %lld created. bucket size %lld start_time: %lld", (long long)mMetricId,
87 (long long)mBucketSizeNs, (long long)mTimeBaseNs);
88 }
89
~EventMetricProducer()90 EventMetricProducer::~EventMetricProducer() {
91 VLOG("~EventMetricProducer() called");
92 }
93
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)94 optional<InvalidConfigReason> EventMetricProducer::onConfigUpdatedLocked(
95 const StatsdConfig& config, const int configIndex, const int metricIndex,
96 const vector<sp<AtomMatchingTracker>>& allAtomMatchingTrackers,
97 const unordered_map<int64_t, int>& oldAtomMatchingTrackerMap,
98 const unordered_map<int64_t, int>& newAtomMatchingTrackerMap,
99 const sp<EventMatcherWizard>& matcherWizard,
100 const vector<sp<ConditionTracker>>& allConditionTrackers,
101 const unordered_map<int64_t, int>& conditionTrackerMap, const sp<ConditionWizard>& wizard,
102 const unordered_map<int64_t, int>& metricToActivationMap,
103 unordered_map<int, vector<int>>& trackerToMetricMap,
104 unordered_map<int, vector<int>>& conditionToMetricMap,
105 unordered_map<int, vector<int>>& activationAtomTrackerToMetricMap,
106 unordered_map<int, vector<int>>& deactivationAtomTrackerToMetricMap,
107 vector<int>& metricsWithActivation) {
108 optional<InvalidConfigReason> invalidConfigReason = MetricProducer::onConfigUpdatedLocked(
109 config, configIndex, metricIndex, allAtomMatchingTrackers, oldAtomMatchingTrackerMap,
110 newAtomMatchingTrackerMap, matcherWizard, allConditionTrackers, conditionTrackerMap,
111 wizard, metricToActivationMap, trackerToMetricMap, conditionToMetricMap,
112 activationAtomTrackerToMetricMap, deactivationAtomTrackerToMetricMap,
113 metricsWithActivation);
114 if (invalidConfigReason.has_value()) {
115 return invalidConfigReason;
116 }
117
118 const EventMetric& metric = config.event_metric(configIndex);
119 int trackerIndex;
120 // Update appropriate indices, specifically mConditionIndex and MetricsManager maps.
121 invalidConfigReason = handleMetricWithAtomMatchingTrackers(
122 metric.what(), mMetricId, metricIndex, false, allAtomMatchingTrackers,
123 newAtomMatchingTrackerMap, trackerToMetricMap, trackerIndex);
124 if (invalidConfigReason.has_value()) {
125 return invalidConfigReason;
126 }
127
128 if (metric.has_condition()) {
129 invalidConfigReason = handleMetricWithConditions(
130 metric.condition(), mMetricId, metricIndex, conditionTrackerMap, metric.links(),
131 allConditionTrackers, mConditionTrackerIndex, conditionToMetricMap);
132 if (invalidConfigReason.has_value()) {
133 return invalidConfigReason;
134 }
135 }
136 return nullopt;
137 }
138
dropDataLocked(const int64_t dropTimeNs)139 void EventMetricProducer::dropDataLocked(const int64_t dropTimeNs) {
140 mAggregatedAtoms.clear();
141 resetDataCorruptionFlagsLocked();
142 mTotalDataSize = 0;
143 StatsdStats::getInstance().noteBucketDropped(mMetricId);
144 }
145
onSlicedConditionMayChangeLocked(bool overallCondition,const int64_t eventTime)146 void EventMetricProducer::onSlicedConditionMayChangeLocked(bool overallCondition,
147 const int64_t eventTime) {
148 }
149
serializeProtoLocked(ProtoOutputStream & protoOutput)150 std::unique_ptr<std::vector<uint8_t>> serializeProtoLocked(ProtoOutputStream& protoOutput) {
151 size_t bufferSize = protoOutput.size();
152
153 std::unique_ptr<std::vector<uint8_t>> buffer(new std::vector<uint8_t>(bufferSize));
154
155 size_t pos = 0;
156 sp<android::util::ProtoReader> reader = protoOutput.data();
157 while (reader->readBuffer() != NULL) {
158 size_t toRead = reader->currentToRead();
159 std::memcpy(&((*buffer)[pos]), reader->readBuffer(), toRead);
160 pos += toRead;
161 reader->move(toRead);
162 }
163
164 return buffer;
165 }
166
clearPastBucketsLocked(const int64_t dumpTimeNs)167 void EventMetricProducer::clearPastBucketsLocked(const int64_t dumpTimeNs) {
168 mAggregatedAtoms.clear();
169 resetDataCorruptionFlagsLocked();
170 mTotalDataSize = 0;
171 }
172
onDumpReportLocked(const int64_t dumpTimeNs,const bool include_current_partial_bucket,const bool erase_data,const DumpLatency dumpLatency,std::set<string> * str_set,ProtoOutputStream * protoOutput)173 void EventMetricProducer::onDumpReportLocked(const int64_t dumpTimeNs,
174 const bool include_current_partial_bucket,
175 const bool erase_data,
176 const DumpLatency dumpLatency,
177 std::set<string> *str_set,
178 ProtoOutputStream* protoOutput) {
179 protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_ID, (long long)mMetricId);
180 protoOutput->write(FIELD_TYPE_BOOL | FIELD_ID_IS_ACTIVE, isActiveLocked());
181 // Data corrupted reason
182 writeDataCorruptedReasons(*protoOutput, FIELD_ID_DATA_CORRUPTED_REASON,
183 mDataCorruptedDueToQueueOverflow != DataCorruptionSeverity::kNone,
184 mDataCorruptedDueToSocketLoss != DataCorruptionSeverity::kNone);
185 if (!mAggregatedAtoms.empty()) {
186 protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_ESTIMATED_MEMORY_BYTES,
187 (long long)byteSizeLocked());
188 }
189 uint64_t protoToken = protoOutput->start(FIELD_TYPE_MESSAGE | FIELD_ID_EVENT_METRICS);
190 for (const auto& [atomDimensionKey, elapsedTimestampsNs] : mAggregatedAtoms) {
191 uint64_t wrapperToken =
192 protoOutput->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_DATA);
193
194 uint64_t aggregatedToken =
195 protoOutput->start(FIELD_TYPE_MESSAGE | FIELD_ID_AGGREGATED_ATOM);
196
197 uint64_t atomToken = protoOutput->start(FIELD_TYPE_MESSAGE | FIELD_ID_ATOM);
198 writeFieldValueTreeToStream(atomDimensionKey.getAtomTag(),
199 atomDimensionKey.getAtomFieldValues().getValues(), protoOutput);
200 protoOutput->end(atomToken);
201 for (int64_t timestampNs : elapsedTimestampsNs) {
202 protoOutput->write(FIELD_TYPE_INT64 | FIELD_COUNT_REPEATED | FIELD_ID_ATOM_TIMESTAMPS,
203 (long long)timestampNs);
204 }
205 protoOutput->end(aggregatedToken);
206 protoOutput->end(wrapperToken);
207 }
208
209 protoOutput->end(protoToken);
210 if (erase_data) {
211 mAggregatedAtoms.clear();
212 resetDataCorruptionFlagsLocked();
213 mTotalDataSize = 0;
214 }
215 }
216
onConditionChangedLocked(const bool conditionMet,const int64_t eventTime)217 void EventMetricProducer::onConditionChangedLocked(const bool conditionMet,
218 const int64_t eventTime) {
219 VLOG("Metric %lld onConditionChanged", (long long)mMetricId);
220 mCondition = conditionMet ? ConditionState::kTrue : ConditionState::kFalse;
221 }
222
onMatchedLogEventInternalLocked(const size_t matcherIndex,const MetricDimensionKey & eventKey,const ConditionKey & conditionKey,bool condition,const LogEvent & event,const map<int,HashableDimensionKey> & statePrimaryKeys)223 void EventMetricProducer::onMatchedLogEventInternalLocked(
224 const size_t matcherIndex, const MetricDimensionKey& eventKey,
225 const ConditionKey& conditionKey, bool condition, const LogEvent& event,
226 const map<int, HashableDimensionKey>& statePrimaryKeys) {
227 if (!condition) {
228 return;
229 }
230
231 if (mSamplingPercentage < 100 && !shouldKeepRandomSample(mSamplingPercentage)) {
232 return;
233 }
234
235 const int64_t elapsedTimeNs = truncateTimestampIfNecessary(event);
236 AtomDimensionKey key(event.GetTagId(), HashableDimensionKey(event.getValues()));
237
238 std::vector<int64_t>& aggregatedTimestampsNs = mAggregatedAtoms[key];
239 if (aggregatedTimestampsNs.empty()) {
240 sp<ConfigMetadataProvider> provider = getConfigMetadataProvider();
241 if (provider != nullptr && provider->useV2SoftMemoryCalculation()) {
242 mTotalDataSize += getFieldValuesSizeV2(key.getAtomFieldValues().getValues());
243 } else {
244 mTotalDataSize += getSize(key.getAtomFieldValues().getValues());
245 }
246 }
247 aggregatedTimestampsNs.push_back(elapsedTimeNs);
248 mTotalDataSize += sizeof(int64_t); // Add the size of the event timestamp
249 }
250
byteSizeLocked() const251 size_t EventMetricProducer::byteSizeLocked() const {
252 sp<ConfigMetadataProvider> provider = getConfigMetadataProvider();
253 if (provider != nullptr && provider->useV2SoftMemoryCalculation()) {
254 return mTotalDataSize +
255 computeOverheadSizeLocked(/*hasPastBuckets=*/false, /*dimensionGuardrailHit=*/false);
256 }
257 return mTotalDataSize;
258 }
259
determineCorruptionSeverity(DataCorruptedReason reason,LostAtomType atomType) const260 MetricProducer::DataCorruptionSeverity EventMetricProducer::determineCorruptionSeverity(
261 DataCorruptedReason reason, LostAtomType atomType) const {
262 switch (atomType) {
263 case LostAtomType::kWhat:
264 return DataCorruptionSeverity::kResetOnDump;
265 case LostAtomType::kCondition:
266 return DataCorruptionSeverity::kUnrecoverable;
267 };
268 return DataCorruptionSeverity::kNone;
269 };
270
271 } // namespace statsd
272 } // namespace os
273 } // namespace android
274