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