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