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 STATSD_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 mPackageCertificateHashSizeBytes(
70 static_cast<uint8_t>(config.package_certificate_hash_size_bytes())),
71 mTtlNs(config.has_ttl_in_seconds() ? config.ttl_in_seconds() * NS_PER_SEC : -1),
72 mTtlEndNs(-1),
73 mLastReportTimeNs(currentTimeNs),
74 mLastReportWallClockNs(getWallClockNs()),
75 mPullerManager(pullerManager),
76 mWhitelistedAtomIds(config.whitelisted_atom_ids().begin(),
77 config.whitelisted_atom_ids().end()),
78 mShouldPersistHistory(config.persist_locally()) {
79 // Init the ttl end timestamp.
80 refreshTtl(timeBaseNs);
81
82 mConfigValid = initStatsdConfig(
83 key, config, uidMap, pullerManager, anomalyAlarmMonitor, periodicAlarmMonitor,
84 timeBaseNs, currentTimeNs, mTagIds, mAllAtomMatchingTrackers, mAtomMatchingTrackerMap,
85 mAllConditionTrackers, mConditionTrackerMap, mAllMetricProducers, mMetricProducerMap,
86 mAllAnomalyTrackers, mAllPeriodicAlarmTrackers, mConditionToMetricMap,
87 mTrackerToMetricMap, mTrackerToConditionMap, mActivationAtomTrackerToMetricMap,
88 mDeactivationAtomTrackerToMetricMap, mAlertTrackerMap, mMetricIndexesWithActivation,
89 mStateProtoHashes, mNoReportMetricIds);
90
91 mHashStringsInReport = config.hash_strings_in_metric_report();
92 mVersionStringsInReport = config.version_strings_in_metric_report();
93 mInstallerInReport = config.installer_in_metric_report();
94
95 createAllLogSourcesFromConfig(config);
96 mPullerManager->RegisterPullUidProvider(mConfigKey, this);
97
98 // Store the sub-configs used.
99 for (const auto& annotation : config.annotation()) {
100 mAnnotations.emplace_back(annotation.field_int64(), annotation.field_int32());
101 }
102 verifyGuardrailsAndUpdateStatsdStats();
103 initializeConfigActiveStatus();
104 }
105
~MetricsManager()106 MetricsManager::~MetricsManager() {
107 for (auto it : mAllMetricProducers) {
108 for (int atomId : it->getSlicedStateAtoms()) {
109 StateManager::getInstance().unregisterListener(atomId, it);
110 }
111 }
112 mPullerManager->UnregisterPullUidProvider(mConfigKey, this);
113
114 VLOG("~MetricsManager()");
115 }
116
updateConfig(const StatsdConfig & config,const int64_t timeBaseNs,const int64_t currentTimeNs,const sp<AlarmMonitor> & anomalyAlarmMonitor,const sp<AlarmMonitor> & periodicAlarmMonitor)117 bool MetricsManager::updateConfig(const StatsdConfig& config, const int64_t timeBaseNs,
118 const int64_t currentTimeNs,
119 const sp<AlarmMonitor>& anomalyAlarmMonitor,
120 const sp<AlarmMonitor>& periodicAlarmMonitor) {
121 vector<sp<AtomMatchingTracker>> newAtomMatchingTrackers;
122 unordered_map<int64_t, int> newAtomMatchingTrackerMap;
123 vector<sp<ConditionTracker>> newConditionTrackers;
124 unordered_map<int64_t, int> newConditionTrackerMap;
125 map<int64_t, uint64_t> newStateProtoHashes;
126 vector<sp<MetricProducer>> newMetricProducers;
127 unordered_map<int64_t, int> newMetricProducerMap;
128 vector<sp<AnomalyTracker>> newAnomalyTrackers;
129 unordered_map<int64_t, int> newAlertTrackerMap;
130 vector<sp<AlarmTracker>> newPeriodicAlarmTrackers;
131 mTagIds.clear();
132 mConditionToMetricMap.clear();
133 mTrackerToMetricMap.clear();
134 mTrackerToConditionMap.clear();
135 mActivationAtomTrackerToMetricMap.clear();
136 mDeactivationAtomTrackerToMetricMap.clear();
137 mMetricIndexesWithActivation.clear();
138 mNoReportMetricIds.clear();
139 mConfigValid = updateStatsdConfig(
140 mConfigKey, config, mUidMap, mPullerManager, anomalyAlarmMonitor, periodicAlarmMonitor,
141 timeBaseNs, currentTimeNs, mAllAtomMatchingTrackers, mAtomMatchingTrackerMap,
142 mAllConditionTrackers, mConditionTrackerMap, mAllMetricProducers, mMetricProducerMap,
143 mAllAnomalyTrackers, mAlertTrackerMap, mStateProtoHashes, mTagIds,
144 newAtomMatchingTrackers, newAtomMatchingTrackerMap, newConditionTrackers,
145 newConditionTrackerMap, newMetricProducers, newMetricProducerMap, newAnomalyTrackers,
146 newAlertTrackerMap, newPeriodicAlarmTrackers, mConditionToMetricMap,
147 mTrackerToMetricMap, mTrackerToConditionMap, mActivationAtomTrackerToMetricMap,
148 mDeactivationAtomTrackerToMetricMap, mMetricIndexesWithActivation, newStateProtoHashes,
149 mNoReportMetricIds);
150 mAllAtomMatchingTrackers = newAtomMatchingTrackers;
151 mAtomMatchingTrackerMap = newAtomMatchingTrackerMap;
152 mAllConditionTrackers = newConditionTrackers;
153 mConditionTrackerMap = newConditionTrackerMap;
154 mAllMetricProducers = newMetricProducers;
155 mMetricProducerMap = newMetricProducerMap;
156 mStateProtoHashes = newStateProtoHashes;
157 mAllAnomalyTrackers = newAnomalyTrackers;
158 mAlertTrackerMap = newAlertTrackerMap;
159 mAllPeriodicAlarmTrackers = newPeriodicAlarmTrackers;
160
161 mTtlNs = config.has_ttl_in_seconds() ? config.ttl_in_seconds() * NS_PER_SEC : -1;
162 refreshTtl(currentTimeNs);
163
164 mHashStringsInReport = config.hash_strings_in_metric_report();
165 mVersionStringsInReport = config.version_strings_in_metric_report();
166 mInstallerInReport = config.installer_in_metric_report();
167 mWhitelistedAtomIds.clear();
168 mWhitelistedAtomIds.insert(config.whitelisted_atom_ids().begin(),
169 config.whitelisted_atom_ids().end());
170 mShouldPersistHistory = config.persist_locally();
171 mPackageCertificateHashSizeBytes = config.package_certificate_hash_size_bytes();
172
173 // Store the sub-configs used.
174 mAnnotations.clear();
175 for (const auto& annotation : config.annotation()) {
176 mAnnotations.emplace_back(annotation.field_int64(), annotation.field_int32());
177 }
178
179 mAllowedUid.clear();
180 mAllowedPkg.clear();
181 mDefaultPullUids.clear();
182 mPullAtomUids.clear();
183 mPullAtomPackages.clear();
184 createAllLogSourcesFromConfig(config);
185
186 verifyGuardrailsAndUpdateStatsdStats();
187 initializeConfigActiveStatus();
188 return mConfigValid;
189 }
190
createAllLogSourcesFromConfig(const StatsdConfig & config)191 void MetricsManager::createAllLogSourcesFromConfig(const StatsdConfig& config) {
192 // Init allowed pushed atom uids.
193 if (config.allowed_log_source_size() == 0) {
194 mConfigValid = false;
195 ALOGE("Log source allowlist is empty! This config won't get any data. Suggest adding at "
196 "least AID_SYSTEM and AID_STATSD to the allowed_log_source field.");
197 } else {
198 for (const auto& source : config.allowed_log_source()) {
199 auto it = UidMap::sAidToUidMapping.find(source);
200 if (it != UidMap::sAidToUidMapping.end()) {
201 mAllowedUid.push_back(it->second);
202 } else {
203 mAllowedPkg.push_back(source);
204 }
205 }
206
207 if (mAllowedUid.size() + mAllowedPkg.size() > StatsdStats::kMaxLogSourceCount) {
208 ALOGE("Too many log sources. This is likely to be an error in the config.");
209 mConfigValid = false;
210 } else {
211 initAllowedLogSources();
212 }
213 }
214
215 // Init default allowed pull atom uids.
216 int numPullPackages = 0;
217 for (const string& pullSource : config.default_pull_packages()) {
218 auto it = UidMap::sAidToUidMapping.find(pullSource);
219 if (it != UidMap::sAidToUidMapping.end()) {
220 numPullPackages++;
221 mDefaultPullUids.insert(it->second);
222 } else {
223 ALOGE("Default pull atom packages must be in sAidToUidMapping");
224 mConfigValid = false;
225 }
226 }
227 // Init per-atom pull atom packages.
228 for (const PullAtomPackages& pullAtomPackages : config.pull_atom_packages()) {
229 int32_t atomId = pullAtomPackages.atom_id();
230 for (const string& pullPackage : pullAtomPackages.packages()) {
231 numPullPackages++;
232 auto it = UidMap::sAidToUidMapping.find(pullPackage);
233 if (it != UidMap::sAidToUidMapping.end()) {
234 mPullAtomUids[atomId].insert(it->second);
235 } else {
236 mPullAtomPackages[atomId].insert(pullPackage);
237 }
238 }
239 }
240 if (numPullPackages > StatsdStats::kMaxPullAtomPackages) {
241 ALOGE("Too many sources in default_pull_packages and pull_atom_packages. This is likely to "
242 "be an error in the config");
243 mConfigValid = false;
244 } else {
245 initPullAtomSources();
246 }
247 }
248
verifyGuardrailsAndUpdateStatsdStats()249 void MetricsManager::verifyGuardrailsAndUpdateStatsdStats() {
250 // Guardrail. Reject the config if it's too big.
251 if (mAllMetricProducers.size() > StatsdStats::kMaxMetricCountPerConfig ||
252 mAllConditionTrackers.size() > StatsdStats::kMaxConditionCountPerConfig ||
253 mAllAtomMatchingTrackers.size() > StatsdStats::kMaxMatcherCountPerConfig) {
254 ALOGE("This config is too big! Reject!");
255 mConfigValid = false;
256 }
257 if (mAllAnomalyTrackers.size() > StatsdStats::kMaxAlertCountPerConfig) {
258 ALOGE("This config has too many alerts! Reject!");
259 mConfigValid = false;
260 }
261 // no matter whether this config is valid, log it in the stats.
262 StatsdStats::getInstance().noteConfigReceived(
263 mConfigKey, mAllMetricProducers.size(), mAllConditionTrackers.size(),
264 mAllAtomMatchingTrackers.size(), mAllAnomalyTrackers.size(), mAnnotations,
265 mConfigValid);
266 }
267
initializeConfigActiveStatus()268 void MetricsManager::initializeConfigActiveStatus() {
269 mIsAlwaysActive = (mMetricIndexesWithActivation.size() != mAllMetricProducers.size()) ||
270 (mAllMetricProducers.size() == 0);
271 mIsActive = mIsAlwaysActive;
272 for (int metric : mMetricIndexesWithActivation) {
273 mIsActive |= mAllMetricProducers[metric]->isActive();
274 }
275 VLOG("mIsActive is initialized to %d", mIsActive);
276 }
277
initAllowedLogSources()278 void MetricsManager::initAllowedLogSources() {
279 std::lock_guard<std::mutex> lock(mAllowedLogSourcesMutex);
280 mAllowedLogSources.clear();
281 mAllowedLogSources.insert(mAllowedUid.begin(), mAllowedUid.end());
282
283 for (const auto& pkg : mAllowedPkg) {
284 auto uids = mUidMap->getAppUid(pkg);
285 mAllowedLogSources.insert(uids.begin(), uids.end());
286 }
287 if (STATSD_DEBUG) {
288 for (const auto& uid : mAllowedLogSources) {
289 VLOG("Allowed uid %d", uid);
290 }
291 }
292 }
293
initPullAtomSources()294 void MetricsManager::initPullAtomSources() {
295 std::lock_guard<std::mutex> lock(mAllowedLogSourcesMutex);
296 mCombinedPullAtomUids.clear();
297 for (const auto& [atomId, uids] : mPullAtomUids) {
298 mCombinedPullAtomUids[atomId].insert(uids.begin(), uids.end());
299 }
300 for (const auto& [atomId, packages] : mPullAtomPackages) {
301 for (const string& pkg : packages) {
302 set<int32_t> uids = mUidMap->getAppUid(pkg);
303 mCombinedPullAtomUids[atomId].insert(uids.begin(), uids.end());
304 }
305 }
306 }
307
isConfigValid() const308 bool MetricsManager::isConfigValid() const {
309 return mConfigValid;
310 }
311
notifyAppUpgrade(const int64_t & eventTimeNs,const string & apk,const int uid,const int64_t version)312 void MetricsManager::notifyAppUpgrade(const int64_t& eventTimeNs, const string& apk, const int uid,
313 const int64_t version) {
314 // Inform all metric producers.
315 for (const auto& it : mAllMetricProducers) {
316 it->notifyAppUpgrade(eventTimeNs);
317 }
318 // check if we care this package
319 if (std::find(mAllowedPkg.begin(), mAllowedPkg.end(), apk) != mAllowedPkg.end()) {
320 // We will re-initialize the whole list because we don't want to keep the multi mapping of
321 // UID<->pkg inside MetricsManager to reduce the memory usage.
322 initAllowedLogSources();
323 }
324
325 for (const auto& it : mPullAtomPackages) {
326 if (it.second.find(apk) != it.second.end()) {
327 initPullAtomSources();
328 return;
329 }
330 }
331 }
332
notifyAppRemoved(const int64_t & eventTimeNs,const string & apk,const int uid)333 void MetricsManager::notifyAppRemoved(const int64_t& eventTimeNs, const string& apk,
334 const int uid) {
335 // Inform all metric producers.
336 for (const auto& it : mAllMetricProducers) {
337 it->notifyAppRemoved(eventTimeNs);
338 }
339 // check if we care this package
340 if (std::find(mAllowedPkg.begin(), mAllowedPkg.end(), apk) != mAllowedPkg.end()) {
341 // We will re-initialize the whole list because we don't want to keep the multi mapping of
342 // UID<->pkg inside MetricsManager to reduce the memory usage.
343 initAllowedLogSources();
344 }
345
346 for (const auto& it : mPullAtomPackages) {
347 if (it.second.find(apk) != it.second.end()) {
348 initPullAtomSources();
349 return;
350 }
351 }
352 }
353
onUidMapReceived(const int64_t & eventTimeNs)354 void MetricsManager::onUidMapReceived(const int64_t& eventTimeNs) {
355 // Purposefully don't inform metric producers on a new snapshot
356 // because we don't need to flush partial buckets.
357 // This occurs if a new user is added/removed or statsd crashes.
358 initPullAtomSources();
359
360 if (mAllowedPkg.size() == 0) {
361 return;
362 }
363 initAllowedLogSources();
364 }
365
onStatsdInitCompleted(const int64_t & eventTimeNs)366 void MetricsManager::onStatsdInitCompleted(const int64_t& eventTimeNs) {
367 // Inform all metric producers.
368 for (const auto& it : mAllMetricProducers) {
369 it->onStatsdInitCompleted(eventTimeNs);
370 }
371 }
372
init()373 void MetricsManager::init() {
374 for (const auto& producer : mAllMetricProducers) {
375 producer->prepareFirstBucket();
376 }
377 }
378
getPullAtomUids(int32_t atomId)379 vector<int32_t> MetricsManager::getPullAtomUids(int32_t atomId) {
380 std::lock_guard<std::mutex> lock(mAllowedLogSourcesMutex);
381 vector<int32_t> uids;
382 const auto& it = mCombinedPullAtomUids.find(atomId);
383 if (it != mCombinedPullAtomUids.end()) {
384 uids.insert(uids.end(), it->second.begin(), it->second.end());
385 }
386 uids.insert(uids.end(), mDefaultPullUids.begin(), mDefaultPullUids.end());
387 return uids;
388 }
389
dumpStates(FILE * out,bool verbose)390 void MetricsManager::dumpStates(FILE* out, bool verbose) {
391 fprintf(out, "ConfigKey %s, allowed source:", mConfigKey.ToString().c_str());
392 {
393 std::lock_guard<std::mutex> lock(mAllowedLogSourcesMutex);
394 for (const auto& source : mAllowedLogSources) {
395 fprintf(out, "%d ", source);
396 }
397 }
398 fprintf(out, "\n");
399 for (const auto& producer : mAllMetricProducers) {
400 producer->dumpStates(out, verbose);
401 }
402 }
403
dropData(const int64_t dropTimeNs)404 void MetricsManager::dropData(const int64_t dropTimeNs) {
405 for (const auto& producer : mAllMetricProducers) {
406 producer->dropData(dropTimeNs);
407 }
408 }
409
onDumpReport(const int64_t dumpTimeStampNs,const int64_t wallClockNs,const bool include_current_partial_bucket,const bool erase_data,const DumpLatency dumpLatency,std::set<string> * str_set,ProtoOutputStream * protoOutput)410 void MetricsManager::onDumpReport(const int64_t dumpTimeStampNs, const int64_t wallClockNs,
411 const bool include_current_partial_bucket, const bool erase_data,
412 const DumpLatency dumpLatency, std::set<string>* str_set,
413 ProtoOutputStream* protoOutput) {
414 VLOG("=========================Metric Reports Start==========================");
415 // one StatsLogReport per MetricProduer
416 for (const auto& producer : mAllMetricProducers) {
417 if (mNoReportMetricIds.find(producer->getMetricId()) == mNoReportMetricIds.end()) {
418 uint64_t token = protoOutput->start(
419 FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_METRICS);
420 if (mHashStringsInReport) {
421 producer->onDumpReport(dumpTimeStampNs, include_current_partial_bucket, erase_data,
422 dumpLatency, str_set, protoOutput);
423 } else {
424 producer->onDumpReport(dumpTimeStampNs, include_current_partial_bucket, erase_data,
425 dumpLatency, nullptr, protoOutput);
426 }
427 protoOutput->end(token);
428 } else {
429 producer->clearPastBuckets(dumpTimeStampNs);
430 }
431 }
432 for (const auto& annotation : mAnnotations) {
433 uint64_t token = protoOutput->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED |
434 FIELD_ID_ANNOTATIONS);
435 protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_ANNOTATIONS_INT64,
436 (long long)annotation.first);
437 protoOutput->write(FIELD_TYPE_INT32 | FIELD_ID_ANNOTATIONS_INT32, annotation.second);
438 protoOutput->end(token);
439 }
440
441 // Do not update the timestamps when data is not cleared to avoid timestamps from being
442 // misaligned.
443 if (erase_data) {
444 mLastReportTimeNs = dumpTimeStampNs;
445 mLastReportWallClockNs = wallClockNs;
446 }
447 VLOG("=========================Metric Reports End==========================");
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