• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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