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 #define DEBUG false // STOPSHIP if true
17 #include "Log.h"
18
19 #include "MetricsManager.h"
20
21 #include <private/android_filesystem_config.h>
22
23 #include "CountMetricProducer.h"
24 #include "condition/CombinationConditionTracker.h"
25 #include "condition/SimpleConditionTracker.h"
26 #include "guardrail/StatsdStats.h"
27 #include "matchers/CombinationAtomMatchingTracker.h"
28 #include "matchers/SimpleAtomMatchingTracker.h"
29 #include "parsing_utils/config_update_utils.h"
30 #include "parsing_utils/metrics_manager_util.h"
31 #include "state/StateManager.h"
32 #include "stats_log_util.h"
33 #include "stats_util.h"
34 #include "statslog_statsd.h"
35
36 using android::util::FIELD_COUNT_REPEATED;
37 using android::util::FIELD_TYPE_INT32;
38 using android::util::FIELD_TYPE_INT64;
39 using android::util::FIELD_TYPE_MESSAGE;
40 using android::util::FIELD_TYPE_STRING;
41 using android::util::ProtoOutputStream;
42
43 using std::set;
44 using std::string;
45 using std::vector;
46
47 namespace android {
48 namespace os {
49 namespace statsd {
50
51 const int FIELD_ID_METRICS = 1;
52 const int FIELD_ID_ANNOTATIONS = 7;
53 const int FIELD_ID_ANNOTATIONS_INT64 = 1;
54 const int FIELD_ID_ANNOTATIONS_INT32 = 2;
55
56 // for ActiveConfig
57 const int FIELD_ID_ACTIVE_CONFIG_ID = 1;
58 const int FIELD_ID_ACTIVE_CONFIG_UID = 2;
59 const int FIELD_ID_ACTIVE_CONFIG_METRIC = 3;
60
MetricsManager(const ConfigKey & key,const StatsdConfig & config,const int64_t timeBaseNs,const int64_t currentTimeNs,const sp<UidMap> & uidMap,const sp<StatsPullerManager> & pullerManager,const sp<AlarmMonitor> & anomalyAlarmMonitor,const sp<AlarmMonitor> & periodicAlarmMonitor)61 MetricsManager::MetricsManager(const ConfigKey& key, const StatsdConfig& config,
62 const int64_t timeBaseNs, const int64_t currentTimeNs,
63 const sp<UidMap>& uidMap,
64 const sp<StatsPullerManager>& pullerManager,
65 const sp<AlarmMonitor>& anomalyAlarmMonitor,
66 const sp<AlarmMonitor>& periodicAlarmMonitor)
67 : mConfigKey(key),
68 mUidMap(uidMap),
69 mTtlNs(config.has_ttl_in_seconds() ? config.ttl_in_seconds() * NS_PER_SEC : -1),
70 mTtlEndNs(-1),
71 mLastReportTimeNs(currentTimeNs),
72 mLastReportWallClockNs(getWallClockNs()),
73 mPullerManager(pullerManager),
74 mWhitelistedAtomIds(config.whitelisted_atom_ids().begin(),
75 config.whitelisted_atom_ids().end()),
76 mShouldPersistHistory(config.persist_locally()) {
77 // Init the ttl end timestamp.
78 refreshTtl(timeBaseNs);
79
80 mConfigValid = initStatsdConfig(
81 key, config, uidMap, pullerManager, anomalyAlarmMonitor, periodicAlarmMonitor,
82 timeBaseNs, currentTimeNs, mTagIds, mAllAtomMatchingTrackers, mAtomMatchingTrackerMap,
83 mAllConditionTrackers, mConditionTrackerMap, mAllMetricProducers, mMetricProducerMap,
84 mAllAnomalyTrackers, mAllPeriodicAlarmTrackers, mConditionToMetricMap,
85 mTrackerToMetricMap, mTrackerToConditionMap, mActivationAtomTrackerToMetricMap,
86 mDeactivationAtomTrackerToMetricMap, mAlertTrackerMap, mMetricIndexesWithActivation,
87 mStateProtoHashes, mNoReportMetricIds);
88
89 mHashStringsInReport = config.hash_strings_in_metric_report();
90 mVersionStringsInReport = config.version_strings_in_metric_report();
91 mInstallerInReport = config.installer_in_metric_report();
92
93 createAllLogSourcesFromConfig(config);
94 mPullerManager->RegisterPullUidProvider(mConfigKey, this);
95
96 // Store the sub-configs used.
97 for (const auto& annotation : config.annotation()) {
98 mAnnotations.emplace_back(annotation.field_int64(), annotation.field_int32());
99 }
100 verifyGuardrailsAndUpdateStatsdStats();
101 initializeConfigActiveStatus();
102 }
103
~MetricsManager()104 MetricsManager::~MetricsManager() {
105 for (auto it : mAllMetricProducers) {
106 for (int atomId : it->getSlicedStateAtoms()) {
107 StateManager::getInstance().unregisterListener(atomId, it);
108 }
109 }
110 mPullerManager->UnregisterPullUidProvider(mConfigKey, this);
111
112 VLOG("~MetricsManager()");
113 }
114
updateConfig(const StatsdConfig & config,const int64_t timeBaseNs,const int64_t currentTimeNs,const sp<AlarmMonitor> & anomalyAlarmMonitor,const sp<AlarmMonitor> & periodicAlarmMonitor)115 bool MetricsManager::updateConfig(const StatsdConfig& config, const int64_t timeBaseNs,
116 const int64_t currentTimeNs,
117 const sp<AlarmMonitor>& anomalyAlarmMonitor,
118 const sp<AlarmMonitor>& periodicAlarmMonitor) {
119 vector<sp<AtomMatchingTracker>> newAtomMatchingTrackers;
120 unordered_map<int64_t, int> newAtomMatchingTrackerMap;
121 vector<sp<ConditionTracker>> newConditionTrackers;
122 unordered_map<int64_t, int> newConditionTrackerMap;
123 map<int64_t, uint64_t> newStateProtoHashes;
124 vector<sp<MetricProducer>> newMetricProducers;
125 unordered_map<int64_t, int> newMetricProducerMap;
126 vector<sp<AnomalyTracker>> newAnomalyTrackers;
127 unordered_map<int64_t, int> newAlertTrackerMap;
128 vector<sp<AlarmTracker>> newPeriodicAlarmTrackers;
129 mTagIds.clear();
130 mConditionToMetricMap.clear();
131 mTrackerToMetricMap.clear();
132 mTrackerToConditionMap.clear();
133 mActivationAtomTrackerToMetricMap.clear();
134 mDeactivationAtomTrackerToMetricMap.clear();
135 mMetricIndexesWithActivation.clear();
136 mNoReportMetricIds.clear();
137 mConfigValid = updateStatsdConfig(
138 mConfigKey, config, mUidMap, mPullerManager, anomalyAlarmMonitor, periodicAlarmMonitor,
139 timeBaseNs, currentTimeNs, mAllAtomMatchingTrackers, mAtomMatchingTrackerMap,
140 mAllConditionTrackers, mConditionTrackerMap, mAllMetricProducers, mMetricProducerMap,
141 mAllAnomalyTrackers, mAlertTrackerMap, mStateProtoHashes, mTagIds,
142 newAtomMatchingTrackers, newAtomMatchingTrackerMap, newConditionTrackers,
143 newConditionTrackerMap, newMetricProducers, newMetricProducerMap, newAnomalyTrackers,
144 newAlertTrackerMap, newPeriodicAlarmTrackers, mConditionToMetricMap,
145 mTrackerToMetricMap, mTrackerToConditionMap, mActivationAtomTrackerToMetricMap,
146 mDeactivationAtomTrackerToMetricMap, mMetricIndexesWithActivation, newStateProtoHashes,
147 mNoReportMetricIds);
148 mAllAtomMatchingTrackers = newAtomMatchingTrackers;
149 mAtomMatchingTrackerMap = newAtomMatchingTrackerMap;
150 mAllConditionTrackers = newConditionTrackers;
151 mConditionTrackerMap = newConditionTrackerMap;
152 mAllMetricProducers = newMetricProducers;
153 mMetricProducerMap = newMetricProducerMap;
154 mStateProtoHashes = newStateProtoHashes;
155 mAllAnomalyTrackers = newAnomalyTrackers;
156 mAlertTrackerMap = newAlertTrackerMap;
157 mAllPeriodicAlarmTrackers = newPeriodicAlarmTrackers;
158
159 mTtlNs = config.has_ttl_in_seconds() ? config.ttl_in_seconds() * NS_PER_SEC : -1;
160 refreshTtl(currentTimeNs);
161
162 mHashStringsInReport = config.hash_strings_in_metric_report();
163 mVersionStringsInReport = config.version_strings_in_metric_report();
164 mInstallerInReport = config.installer_in_metric_report();
165 mWhitelistedAtomIds.clear();
166 mWhitelistedAtomIds.insert(config.whitelisted_atom_ids().begin(),
167 config.whitelisted_atom_ids().end());
168 mShouldPersistHistory = config.persist_locally();
169
170 // Store the sub-configs used.
171 mAnnotations.clear();
172 for (const auto& annotation : config.annotation()) {
173 mAnnotations.emplace_back(annotation.field_int64(), annotation.field_int32());
174 }
175
176 mAllowedUid.clear();
177 mAllowedPkg.clear();
178 mDefaultPullUids.clear();
179 mPullAtomUids.clear();
180 mPullAtomPackages.clear();
181 createAllLogSourcesFromConfig(config);
182
183 verifyGuardrailsAndUpdateStatsdStats();
184 initializeConfigActiveStatus();
185 return mConfigValid;
186 }
187
createAllLogSourcesFromConfig(const StatsdConfig & config)188 void MetricsManager::createAllLogSourcesFromConfig(const StatsdConfig& config) {
189 // Init allowed pushed atom uids.
190 if (config.allowed_log_source_size() == 0) {
191 mConfigValid = false;
192 ALOGE("Log source allowlist is empty! This config won't get any data. Suggest adding at "
193 "least AID_SYSTEM and AID_STATSD to the allowed_log_source field.");
194 } else {
195 for (const auto& source : config.allowed_log_source()) {
196 auto it = UidMap::sAidToUidMapping.find(source);
197 if (it != UidMap::sAidToUidMapping.end()) {
198 mAllowedUid.push_back(it->second);
199 } else {
200 mAllowedPkg.push_back(source);
201 }
202 }
203
204 if (mAllowedUid.size() + mAllowedPkg.size() > StatsdStats::kMaxLogSourceCount) {
205 ALOGE("Too many log sources. This is likely to be an error in the config.");
206 mConfigValid = false;
207 } else {
208 initAllowedLogSources();
209 }
210 }
211
212 // Init default allowed pull atom uids.
213 int numPullPackages = 0;
214 for (const string& pullSource : config.default_pull_packages()) {
215 auto it = UidMap::sAidToUidMapping.find(pullSource);
216 if (it != UidMap::sAidToUidMapping.end()) {
217 numPullPackages++;
218 mDefaultPullUids.insert(it->second);
219 } else {
220 ALOGE("Default pull atom packages must be in sAidToUidMapping");
221 mConfigValid = false;
222 }
223 }
224 // Init per-atom pull atom packages.
225 for (const PullAtomPackages& pullAtomPackages : config.pull_atom_packages()) {
226 int32_t atomId = pullAtomPackages.atom_id();
227 for (const string& pullPackage : pullAtomPackages.packages()) {
228 numPullPackages++;
229 auto it = UidMap::sAidToUidMapping.find(pullPackage);
230 if (it != UidMap::sAidToUidMapping.end()) {
231 mPullAtomUids[atomId].insert(it->second);
232 } else {
233 mPullAtomPackages[atomId].insert(pullPackage);
234 }
235 }
236 }
237 if (numPullPackages > StatsdStats::kMaxPullAtomPackages) {
238 ALOGE("Too many sources in default_pull_packages and pull_atom_packages. This is likely to "
239 "be an error in the config");
240 mConfigValid = false;
241 } else {
242 initPullAtomSources();
243 }
244 }
245
verifyGuardrailsAndUpdateStatsdStats()246 void MetricsManager::verifyGuardrailsAndUpdateStatsdStats() {
247 // Guardrail. Reject the config if it's too big.
248 if (mAllMetricProducers.size() > StatsdStats::kMaxMetricCountPerConfig ||
249 mAllConditionTrackers.size() > StatsdStats::kMaxConditionCountPerConfig ||
250 mAllAtomMatchingTrackers.size() > StatsdStats::kMaxMatcherCountPerConfig) {
251 ALOGE("This config is too big! Reject!");
252 mConfigValid = false;
253 }
254 if (mAllAnomalyTrackers.size() > StatsdStats::kMaxAlertCountPerConfig) {
255 ALOGE("This config has too many alerts! Reject!");
256 mConfigValid = false;
257 }
258 // no matter whether this config is valid, log it in the stats.
259 StatsdStats::getInstance().noteConfigReceived(
260 mConfigKey, mAllMetricProducers.size(), mAllConditionTrackers.size(),
261 mAllAtomMatchingTrackers.size(), mAllAnomalyTrackers.size(), mAnnotations,
262 mConfigValid);
263 }
264
initializeConfigActiveStatus()265 void MetricsManager::initializeConfigActiveStatus() {
266 mIsAlwaysActive = (mMetricIndexesWithActivation.size() != mAllMetricProducers.size()) ||
267 (mAllMetricProducers.size() == 0);
268 mIsActive = mIsAlwaysActive;
269 for (int metric : mMetricIndexesWithActivation) {
270 mIsActive |= mAllMetricProducers[metric]->isActive();
271 }
272 VLOG("mIsActive is initialized to %d", mIsActive);
273 }
274
initAllowedLogSources()275 void MetricsManager::initAllowedLogSources() {
276 std::lock_guard<std::mutex> lock(mAllowedLogSourcesMutex);
277 mAllowedLogSources.clear();
278 mAllowedLogSources.insert(mAllowedUid.begin(), mAllowedUid.end());
279
280 for (const auto& pkg : mAllowedPkg) {
281 auto uids = mUidMap->getAppUid(pkg);
282 mAllowedLogSources.insert(uids.begin(), uids.end());
283 }
284 if (DEBUG) {
285 for (const auto& uid : mAllowedLogSources) {
286 VLOG("Allowed uid %d", uid);
287 }
288 }
289 }
290
initPullAtomSources()291 void MetricsManager::initPullAtomSources() {
292 std::lock_guard<std::mutex> lock(mAllowedLogSourcesMutex);
293 mCombinedPullAtomUids.clear();
294 for (const auto& [atomId, uids] : mPullAtomUids) {
295 mCombinedPullAtomUids[atomId].insert(uids.begin(), uids.end());
296 }
297 for (const auto& [atomId, packages] : mPullAtomPackages) {
298 for (const string& pkg : packages) {
299 set<int32_t> uids = mUidMap->getAppUid(pkg);
300 mCombinedPullAtomUids[atomId].insert(uids.begin(), uids.end());
301 }
302 }
303 }
304
isConfigValid() const305 bool MetricsManager::isConfigValid() const {
306 return mConfigValid;
307 }
308
notifyAppUpgrade(const int64_t & eventTimeNs,const string & apk,const int uid,const int64_t version)309 void MetricsManager::notifyAppUpgrade(const int64_t& eventTimeNs, const string& apk, const int uid,
310 const int64_t version) {
311 // Inform all metric producers.
312 for (const auto& it : mAllMetricProducers) {
313 it->notifyAppUpgrade(eventTimeNs);
314 }
315 // check if we care this package
316 if (std::find(mAllowedPkg.begin(), mAllowedPkg.end(), apk) != mAllowedPkg.end()) {
317 // We will re-initialize the whole list because we don't want to keep the multi mapping of
318 // UID<->pkg inside MetricsManager to reduce the memory usage.
319 initAllowedLogSources();
320 }
321
322 for (const auto& it : mPullAtomPackages) {
323 if (it.second.find(apk) != it.second.end()) {
324 initPullAtomSources();
325 return;
326 }
327 }
328 }
329
notifyAppRemoved(const int64_t & eventTimeNs,const string & apk,const int uid)330 void MetricsManager::notifyAppRemoved(const int64_t& eventTimeNs, const string& apk,
331 const int uid) {
332 // Inform all metric producers.
333 for (const auto& it : mAllMetricProducers) {
334 it->notifyAppRemoved(eventTimeNs);
335 }
336 // check if we care this package
337 if (std::find(mAllowedPkg.begin(), mAllowedPkg.end(), apk) != mAllowedPkg.end()) {
338 // We will re-initialize the whole list because we don't want to keep the multi mapping of
339 // UID<->pkg inside MetricsManager to reduce the memory usage.
340 initAllowedLogSources();
341 }
342
343 for (const auto& it : mPullAtomPackages) {
344 if (it.second.find(apk) != it.second.end()) {
345 initPullAtomSources();
346 return;
347 }
348 }
349 }
350
onUidMapReceived(const int64_t & eventTimeNs)351 void MetricsManager::onUidMapReceived(const int64_t& eventTimeNs) {
352 // Purposefully don't inform metric producers on a new snapshot
353 // because we don't need to flush partial buckets.
354 // This occurs if a new user is added/removed or statsd crashes.
355 initPullAtomSources();
356
357 if (mAllowedPkg.size() == 0) {
358 return;
359 }
360 initAllowedLogSources();
361 }
362
onStatsdInitCompleted(const int64_t & eventTimeNs)363 void MetricsManager::onStatsdInitCompleted(const int64_t& eventTimeNs) {
364 // Inform all metric producers.
365 for (const auto& it : mAllMetricProducers) {
366 it->onStatsdInitCompleted(eventTimeNs);
367 }
368 }
369
init()370 void MetricsManager::init() {
371 for (const auto& producer : mAllMetricProducers) {
372 producer->prepareFirstBucket();
373 }
374 }
375
getPullAtomUids(int32_t atomId)376 vector<int32_t> MetricsManager::getPullAtomUids(int32_t atomId) {
377 std::lock_guard<std::mutex> lock(mAllowedLogSourcesMutex);
378 vector<int32_t> uids;
379 const auto& it = mCombinedPullAtomUids.find(atomId);
380 if (it != mCombinedPullAtomUids.end()) {
381 uids.insert(uids.end(), it->second.begin(), it->second.end());
382 }
383 uids.insert(uids.end(), mDefaultPullUids.begin(), mDefaultPullUids.end());
384 return uids;
385 }
386
dumpStates(FILE * out,bool verbose)387 void MetricsManager::dumpStates(FILE* out, bool verbose) {
388 fprintf(out, "ConfigKey %s, allowed source:", mConfigKey.ToString().c_str());
389 {
390 std::lock_guard<std::mutex> lock(mAllowedLogSourcesMutex);
391 for (const auto& source : mAllowedLogSources) {
392 fprintf(out, "%d ", source);
393 }
394 }
395 fprintf(out, "\n");
396 for (const auto& producer : mAllMetricProducers) {
397 producer->dumpStates(out, verbose);
398 }
399 }
400
dropData(const int64_t dropTimeNs)401 void MetricsManager::dropData(const int64_t dropTimeNs) {
402 for (const auto& producer : mAllMetricProducers) {
403 producer->dropData(dropTimeNs);
404 }
405 }
406
onDumpReport(const int64_t dumpTimeStampNs,const bool include_current_partial_bucket,const bool erase_data,const DumpLatency dumpLatency,std::set<string> * str_set,ProtoOutputStream * protoOutput)407 void MetricsManager::onDumpReport(const int64_t dumpTimeStampNs,
408 const bool include_current_partial_bucket,
409 const bool erase_data,
410 const DumpLatency dumpLatency,
411 std::set<string> *str_set,
412 ProtoOutputStream* protoOutput) {
413 VLOG("=========================Metric Reports Start==========================");
414 // one StatsLogReport per MetricProduer
415 for (const auto& producer : mAllMetricProducers) {
416 if (mNoReportMetricIds.find(producer->getMetricId()) == mNoReportMetricIds.end()) {
417 uint64_t token = protoOutput->start(
418 FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_METRICS);
419 if (mHashStringsInReport) {
420 producer->onDumpReport(dumpTimeStampNs, include_current_partial_bucket, erase_data,
421 dumpLatency, str_set, protoOutput);
422 } else {
423 producer->onDumpReport(dumpTimeStampNs, include_current_partial_bucket, erase_data,
424 dumpLatency, nullptr, protoOutput);
425 }
426 protoOutput->end(token);
427 } else {
428 producer->clearPastBuckets(dumpTimeStampNs);
429 }
430 }
431 for (const auto& annotation : mAnnotations) {
432 uint64_t token = protoOutput->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED |
433 FIELD_ID_ANNOTATIONS);
434 protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_ANNOTATIONS_INT64,
435 (long long)annotation.first);
436 protoOutput->write(FIELD_TYPE_INT32 | FIELD_ID_ANNOTATIONS_INT32, annotation.second);
437 protoOutput->end(token);
438 }
439
440 // Do not update the timestamps when data is not cleared to avoid timestamps from being
441 // misaligned.
442 if (erase_data) {
443 mLastReportTimeNs = dumpTimeStampNs;
444 mLastReportWallClockNs = getWallClockNs();
445 }
446 VLOG("=========================Metric Reports End==========================");
447 }
448
449
checkLogCredentials(const LogEvent & event)450 bool MetricsManager::checkLogCredentials(const LogEvent& event) {
451 if (mWhitelistedAtomIds.find(event.GetTagId()) != mWhitelistedAtomIds.end()) {
452 return true;
453 }
454 std::lock_guard<std::mutex> lock(mAllowedLogSourcesMutex);
455 if (mAllowedLogSources.find(event.GetUid()) == mAllowedLogSources.end()) {
456 VLOG("log source %d not on the whitelist", event.GetUid());
457 return false;
458 }
459 return true;
460 }
461
eventSanityCheck(const LogEvent & event)462 bool MetricsManager::eventSanityCheck(const LogEvent& event) {
463 if (event.GetTagId() == util::APP_BREADCRUMB_REPORTED) {
464 // Check that app breadcrumb reported fields are valid.
465 status_t err = NO_ERROR;
466
467 // Uid is 3rd from last field and must match the caller's uid,
468 // unless that caller is statsd itself (statsd is allowed to spoof uids).
469 long appHookUid = event.GetLong(event.size()-2, &err);
470 if (err != NO_ERROR) {
471 VLOG("APP_BREADCRUMB_REPORTED had error when parsing the uid");
472 return false;
473 }
474
475 // Because the uid within the LogEvent may have been mapped from
476 // isolated to host, map the loggerUid similarly before comparing.
477 int32_t loggerUid = mUidMap->getHostUidOrSelf(event.GetUid());
478 if (loggerUid != appHookUid && loggerUid != AID_STATSD) {
479 VLOG("APP_BREADCRUMB_REPORTED has invalid uid: claimed %ld but caller is %d",
480 appHookUid, loggerUid);
481 return false;
482 }
483
484 // The state must be from 0,3. This part of code must be manually updated.
485 long appHookState = event.GetLong(event.size(), &err);
486 if (err != NO_ERROR) {
487 VLOG("APP_BREADCRUMB_REPORTED had error when parsing the state field");
488 return false;
489 } else if (appHookState < 0 || appHookState > 3) {
490 VLOG("APP_BREADCRUMB_REPORTED does not have valid state %ld", appHookState);
491 return false;
492 }
493 } else if (event.GetTagId() == util::DAVEY_OCCURRED) {
494 // Daveys can be logged from any app since they are logged in libs/hwui/JankTracker.cpp.
495 // Check that the davey duration is reasonable. Max length check is for privacy.
496 status_t err = NO_ERROR;
497
498 // Uid is the first field provided.
499 long jankUid = event.GetLong(1, &err);
500 if (err != NO_ERROR) {
501 VLOG("Davey occurred had error when parsing the uid");
502 return false;
503 }
504 int32_t loggerUid = event.GetUid();
505 if (loggerUid != jankUid && loggerUid != AID_STATSD) {
506 VLOG("DAVEY_OCCURRED has invalid uid: claimed %ld but caller is %d", jankUid,
507 loggerUid);
508 return false;
509 }
510
511 long duration = event.GetLong(event.size(), &err);
512 if (err != NO_ERROR) {
513 VLOG("Davey occurred had error when parsing the duration");
514 return false;
515 } else if (duration > 100000) {
516 VLOG("Davey duration is unreasonably long: %ld", duration);
517 return false;
518 }
519 }
520
521 return true;
522 }
523
524 // Consume the stats log if it's interesting to this metric.
onLogEvent(const LogEvent & event)525 void MetricsManager::onLogEvent(const LogEvent& event) {
526 if (!mConfigValid) {
527 return;
528 }
529
530 if (!checkLogCredentials(event)) {
531 return;
532 }
533
534 if (!eventSanityCheck(event)) {
535 return;
536 }
537
538 int tagId = event.GetTagId();
539 int64_t eventTimeNs = event.GetElapsedTimestampNs();
540
541 bool isActive = mIsAlwaysActive;
542
543 // Set of metrics that are still active after flushing.
544 unordered_set<int> activeMetricsIndices;
545
546 // Update state of all metrics w/ activation conditions as of eventTimeNs.
547 for (int metricIndex : mMetricIndexesWithActivation) {
548 const sp<MetricProducer>& metric = mAllMetricProducers[metricIndex];
549 metric->flushIfExpire(eventTimeNs);
550 if (metric->isActive()) {
551 // If this metric w/ activation condition is still active after
552 // flushing, remember it.
553 activeMetricsIndices.insert(metricIndex);
554 }
555 }
556
557 mIsActive = isActive || !activeMetricsIndices.empty();
558
559 if (mTagIds.find(tagId) == mTagIds.end()) {
560 // Not interesting...
561 return;
562 }
563
564 vector<MatchingState> matcherCache(mAllAtomMatchingTrackers.size(),
565 MatchingState::kNotComputed);
566
567 // Evaluate all atom matchers.
568 for (auto& matcher : mAllAtomMatchingTrackers) {
569 matcher->onLogEvent(event, mAllAtomMatchingTrackers, matcherCache);
570 }
571
572 // Set of metrics that received an activation cancellation.
573 unordered_set<int> metricIndicesWithCanceledActivations;
574
575 // Determine which metric activations received a cancellation and cancel them.
576 for (const auto& it : mDeactivationAtomTrackerToMetricMap) {
577 if (matcherCache[it.first] == MatchingState::kMatched) {
578 for (int metricIndex : it.second) {
579 mAllMetricProducers[metricIndex]->cancelEventActivation(it.first);
580 metricIndicesWithCanceledActivations.insert(metricIndex);
581 }
582 }
583 }
584
585 // Determine whether any metrics are no longer active after cancelling metric activations.
586 for (const int metricIndex : metricIndicesWithCanceledActivations) {
587 const sp<MetricProducer>& metric = mAllMetricProducers[metricIndex];
588 metric->flushIfExpire(eventTimeNs);
589 if (!metric->isActive()) {
590 activeMetricsIndices.erase(metricIndex);
591 }
592 }
593
594 isActive |= !activeMetricsIndices.empty();
595
596
597 // Determine which metric activations should be turned on and turn them on
598 for (const auto& it : mActivationAtomTrackerToMetricMap) {
599 if (matcherCache[it.first] == MatchingState::kMatched) {
600 for (int metricIndex : it.second) {
601 mAllMetricProducers[metricIndex]->activate(it.first, eventTimeNs);
602 isActive |= mAllMetricProducers[metricIndex]->isActive();
603 }
604 }
605 }
606
607 mIsActive = isActive;
608
609 // A bitmap to see which ConditionTracker needs to be re-evaluated.
610 vector<bool> conditionToBeEvaluated(mAllConditionTrackers.size(), false);
611
612 for (const auto& pair : mTrackerToConditionMap) {
613 if (matcherCache[pair.first] == MatchingState::kMatched) {
614 const auto& conditionList = pair.second;
615 for (const int conditionIndex : conditionList) {
616 conditionToBeEvaluated[conditionIndex] = true;
617 }
618 }
619 }
620
621 vector<ConditionState> conditionCache(mAllConditionTrackers.size(),
622 ConditionState::kNotEvaluated);
623 // A bitmap to track if a condition has changed value.
624 vector<bool> changedCache(mAllConditionTrackers.size(), false);
625 for (size_t i = 0; i < mAllConditionTrackers.size(); i++) {
626 if (conditionToBeEvaluated[i] == false) {
627 continue;
628 }
629 sp<ConditionTracker>& condition = mAllConditionTrackers[i];
630 condition->evaluateCondition(event, matcherCache, mAllConditionTrackers, conditionCache,
631 changedCache);
632 }
633
634 for (size_t i = 0; i < mAllConditionTrackers.size(); i++) {
635 if (changedCache[i] == false) {
636 continue;
637 }
638 auto pair = mConditionToMetricMap.find(i);
639 if (pair != mConditionToMetricMap.end()) {
640 auto& metricList = pair->second;
641 for (auto metricIndex : metricList) {
642 // Metric cares about non sliced condition, and it's changed.
643 // Push the new condition to it directly.
644 if (!mAllMetricProducers[metricIndex]->isConditionSliced()) {
645 mAllMetricProducers[metricIndex]->onConditionChanged(conditionCache[i],
646 eventTimeNs);
647 // Metric cares about sliced conditions, and it may have changed. Send
648 // notification, and the metric can query the sliced conditions that are
649 // interesting to it.
650 } else {
651 mAllMetricProducers[metricIndex]->onSlicedConditionMayChange(conditionCache[i],
652 eventTimeNs);
653 }
654 }
655 }
656 }
657
658 // For matched AtomMatchers, tell relevant metrics that a matched event has come.
659 for (size_t i = 0; i < mAllAtomMatchingTrackers.size(); i++) {
660 if (matcherCache[i] == MatchingState::kMatched) {
661 StatsdStats::getInstance().noteMatcherMatched(mConfigKey,
662 mAllAtomMatchingTrackers[i]->getId());
663 auto pair = mTrackerToMetricMap.find(i);
664 if (pair != mTrackerToMetricMap.end()) {
665 auto& metricList = pair->second;
666 for (const int metricIndex : metricList) {
667 // pushed metrics are never scheduled pulls
668 mAllMetricProducers[metricIndex]->onMatchedLogEvent(i, event);
669 }
670 }
671 }
672 }
673 }
674
onAnomalyAlarmFired(const int64_t & timestampNs,unordered_set<sp<const InternalAlarm>,SpHash<InternalAlarm>> & alarmSet)675 void MetricsManager::onAnomalyAlarmFired(
676 const int64_t& timestampNs,
677 unordered_set<sp<const InternalAlarm>, SpHash<InternalAlarm>>& alarmSet) {
678 for (const auto& itr : mAllAnomalyTrackers) {
679 itr->informAlarmsFired(timestampNs, alarmSet);
680 }
681 }
682
onPeriodicAlarmFired(const int64_t & timestampNs,unordered_set<sp<const InternalAlarm>,SpHash<InternalAlarm>> & alarmSet)683 void MetricsManager::onPeriodicAlarmFired(
684 const int64_t& timestampNs,
685 unordered_set<sp<const InternalAlarm>, SpHash<InternalAlarm>>& alarmSet) {
686 for (const auto& itr : mAllPeriodicAlarmTrackers) {
687 itr->informAlarmsFired(timestampNs, alarmSet);
688 }
689 }
690
691 // Returns the total byte size of all metrics managed by a single config source.
byteSize()692 size_t MetricsManager::byteSize() {
693 size_t totalSize = 0;
694 for (const auto& metricProducer : mAllMetricProducers) {
695 totalSize += metricProducer->byteSize();
696 }
697 return totalSize;
698 }
699
loadActiveConfig(const ActiveConfig & config,int64_t currentTimeNs)700 void MetricsManager::loadActiveConfig(const ActiveConfig& config, int64_t currentTimeNs) {
701 if (config.metric_size() == 0) {
702 ALOGW("No active metric for config %s", mConfigKey.ToString().c_str());
703 return;
704 }
705
706 for (int i = 0; i < config.metric_size(); i++) {
707 const auto& activeMetric = config.metric(i);
708 for (int metricIndex : mMetricIndexesWithActivation) {
709 const auto& metric = mAllMetricProducers[metricIndex];
710 if (metric->getMetricId() == activeMetric.id()) {
711 VLOG("Setting active metric: %lld", (long long)metric->getMetricId());
712 metric->loadActiveMetric(activeMetric, currentTimeNs);
713 if (!mIsActive && metric->isActive()) {
714 StatsdStats::getInstance().noteActiveStatusChanged(mConfigKey,
715 /*activate=*/ true);
716 }
717 mIsActive |= metric->isActive();
718 }
719 }
720 }
721 }
722
writeActiveConfigToProtoOutputStream(int64_t currentTimeNs,const DumpReportReason reason,ProtoOutputStream * proto)723 void MetricsManager::writeActiveConfigToProtoOutputStream(
724 int64_t currentTimeNs, const DumpReportReason reason, ProtoOutputStream* proto) {
725 proto->write(FIELD_TYPE_INT64 | FIELD_ID_ACTIVE_CONFIG_ID, (long long)mConfigKey.GetId());
726 proto->write(FIELD_TYPE_INT32 | FIELD_ID_ACTIVE_CONFIG_UID, mConfigKey.GetUid());
727 for (int metricIndex : mMetricIndexesWithActivation) {
728 const auto& metric = mAllMetricProducers[metricIndex];
729 const uint64_t metricToken = proto->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED |
730 FIELD_ID_ACTIVE_CONFIG_METRIC);
731 metric->writeActiveMetricToProtoOutputStream(currentTimeNs, reason, proto);
732 proto->end(metricToken);
733 }
734 }
735
writeMetadataToProto(int64_t currentWallClockTimeNs,int64_t systemElapsedTimeNs,metadata::StatsMetadata * statsMetadata)736 bool MetricsManager::writeMetadataToProto(int64_t currentWallClockTimeNs,
737 int64_t systemElapsedTimeNs,
738 metadata::StatsMetadata* statsMetadata) {
739 bool metadataWritten = false;
740 metadata::ConfigKey* configKey = statsMetadata->mutable_config_key();
741 configKey->set_config_id(mConfigKey.GetId());
742 configKey->set_uid(mConfigKey.GetUid());
743 for (const auto& anomalyTracker : mAllAnomalyTrackers) {
744 metadata::AlertMetadata* alertMetadata = statsMetadata->add_alert_metadata();
745 bool alertWritten = anomalyTracker->writeAlertMetadataToProto(currentWallClockTimeNs,
746 systemElapsedTimeNs, alertMetadata);
747 if (!alertWritten) {
748 statsMetadata->mutable_alert_metadata()->RemoveLast();
749 }
750 metadataWritten |= alertWritten;
751 }
752 return metadataWritten;
753 }
754
loadMetadata(const metadata::StatsMetadata & metadata,int64_t currentWallClockTimeNs,int64_t systemElapsedTimeNs)755 void MetricsManager::loadMetadata(const metadata::StatsMetadata& metadata,
756 int64_t currentWallClockTimeNs,
757 int64_t systemElapsedTimeNs) {
758 for (const metadata::AlertMetadata& alertMetadata : metadata.alert_metadata()) {
759 int64_t alertId = alertMetadata.alert_id();
760 auto it = mAlertTrackerMap.find(alertId);
761 if (it == mAlertTrackerMap.end()) {
762 ALOGE("No anomalyTracker found for alertId %lld", (long long) alertId);
763 continue;
764 }
765 mAllAnomalyTrackers[it->second]->loadAlertMetadata(alertMetadata,
766 currentWallClockTimeNs,
767 systemElapsedTimeNs);
768 }
769 }
770
771 } // namespace statsd
772 } // namespace os
773 } // namespace android
774