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