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