Home | History | Annotate | Download | only in src
      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 
     17 #define DEBUG false // STOPSHIP if true
     18 #include "Log.h"
     19 #include "statslog.h"
     20 
     21 #include <android-base/file.h>
     22 #include <dirent.h>
     23 #include "StatsLogProcessor.h"
     24 #include "stats_log_util.h"
     25 #include "android-base/stringprintf.h"
     26 #include "guardrail/StatsdStats.h"
     27 #include "metrics/CountMetricProducer.h"
     28 #include "external/StatsPullerManager.h"
     29 #include "stats_util.h"
     30 #include "storage/StorageManager.h"
     31 
     32 #include <log/log_event_list.h>
     33 #include <utils/Errors.h>
     34 #include <utils/SystemClock.h>
     35 
     36 using namespace android;
     37 using android::base::StringPrintf;
     38 using android::util::FIELD_COUNT_REPEATED;
     39 using android::util::FIELD_TYPE_BOOL;
     40 using android::util::FIELD_TYPE_FLOAT;
     41 using android::util::FIELD_TYPE_INT32;
     42 using android::util::FIELD_TYPE_INT64;
     43 using android::util::FIELD_TYPE_MESSAGE;
     44 using android::util::FIELD_TYPE_STRING;
     45 using android::util::ProtoOutputStream;
     46 using std::make_unique;
     47 using std::unique_ptr;
     48 using std::vector;
     49 
     50 namespace android {
     51 namespace os {
     52 namespace statsd {
     53 
     54 // for ConfigMetricsReportList
     55 const int FIELD_ID_CONFIG_KEY = 1;
     56 const int FIELD_ID_REPORTS = 2;
     57 // for ConfigKey
     58 const int FIELD_ID_UID = 1;
     59 const int FIELD_ID_ID = 2;
     60 // for ConfigMetricsReport
     61 // const int FIELD_ID_METRICS = 1; // written in MetricsManager.cpp
     62 const int FIELD_ID_UID_MAP = 2;
     63 const int FIELD_ID_LAST_REPORT_ELAPSED_NANOS = 3;
     64 const int FIELD_ID_CURRENT_REPORT_ELAPSED_NANOS = 4;
     65 const int FIELD_ID_LAST_REPORT_WALL_CLOCK_NANOS = 5;
     66 const int FIELD_ID_CURRENT_REPORT_WALL_CLOCK_NANOS = 6;
     67 const int FIELD_ID_DUMP_REPORT_REASON = 8;
     68 const int FIELD_ID_STRINGS = 9;
     69 
     70 #define NS_PER_HOUR 3600 * NS_PER_SEC
     71 
     72 #define STATS_DATA_DIR "/data/misc/stats-data"
     73 
     74 StatsLogProcessor::StatsLogProcessor(const sp<UidMap>& uidMap,
     75                                      const sp<AlarmMonitor>& anomalyAlarmMonitor,
     76                                      const sp<AlarmMonitor>& periodicAlarmMonitor,
     77                                      const int64_t timeBaseNs,
     78                                      const std::function<bool(const ConfigKey&)>& sendBroadcast)
     79     : mUidMap(uidMap),
     80       mAnomalyAlarmMonitor(anomalyAlarmMonitor),
     81       mPeriodicAlarmMonitor(periodicAlarmMonitor),
     82       mSendBroadcast(sendBroadcast),
     83       mTimeBaseNs(timeBaseNs),
     84       mLargestTimestampSeen(0),
     85       mLastTimestampSeen(0) {
     86     mStatsPullerManager.ForceClearPullerCache();
     87 }
     88 
     89 StatsLogProcessor::~StatsLogProcessor() {
     90 }
     91 
     92 void StatsLogProcessor::onAnomalyAlarmFired(
     93         const int64_t& timestampNs,
     94         unordered_set<sp<const InternalAlarm>, SpHash<InternalAlarm>> alarmSet) {
     95     std::lock_guard<std::mutex> lock(mMetricsMutex);
     96     for (const auto& itr : mMetricsManagers) {
     97         itr.second->onAnomalyAlarmFired(timestampNs, alarmSet);
     98     }
     99 }
    100 void StatsLogProcessor::onPeriodicAlarmFired(
    101         const int64_t& timestampNs,
    102         unordered_set<sp<const InternalAlarm>, SpHash<InternalAlarm>> alarmSet) {
    103 
    104     std::lock_guard<std::mutex> lock(mMetricsMutex);
    105     for (const auto& itr : mMetricsManagers) {
    106         itr.second->onPeriodicAlarmFired(timestampNs, alarmSet);
    107     }
    108 }
    109 
    110 void updateUid(Value* value, int hostUid) {
    111     int uid = value->int_value;
    112     if (uid != hostUid) {
    113         value->setInt(hostUid);
    114     }
    115 }
    116 
    117 void StatsLogProcessor::mapIsolatedUidToHostUidIfNecessaryLocked(LogEvent* event) const {
    118     if (android::util::AtomsInfo::kAtomsWithAttributionChain.find(event->GetTagId()) !=
    119         android::util::AtomsInfo::kAtomsWithAttributionChain.end()) {
    120         for (auto& value : *(event->getMutableValues())) {
    121             if (value.mField.getPosAtDepth(0) > kAttributionField) {
    122                 break;
    123             }
    124             if (isAttributionUidField(value)) {
    125                 const int hostUid = mUidMap->getHostUidOrSelf(value.mValue.int_value);
    126                 updateUid(&value.mValue, hostUid);
    127             }
    128         }
    129     } else {
    130         auto it = android::util::AtomsInfo::kAtomsWithUidField.find(event->GetTagId());
    131         if (it != android::util::AtomsInfo::kAtomsWithUidField.end()) {
    132             int uidField = it->second;  // uidField is the field number in proto,
    133                                         // starting from 1
    134             if (uidField > 0 && (int)event->getValues().size() >= uidField &&
    135                 (event->getValues())[uidField - 1].mValue.getType() == INT) {
    136                 Value& value = (*event->getMutableValues())[uidField - 1].mValue;
    137                 const int hostUid = mUidMap->getHostUidOrSelf(value.int_value);
    138                 updateUid(&value, hostUid);
    139             } else {
    140                 ALOGE("Malformed log, uid not found. %s", event->ToString().c_str());
    141             }
    142         }
    143     }
    144 }
    145 
    146 void StatsLogProcessor::onIsolatedUidChangedEventLocked(const LogEvent& event) {
    147     status_t err = NO_ERROR, err2 = NO_ERROR, err3 = NO_ERROR;
    148     bool is_create = event.GetBool(3, &err);
    149     auto parent_uid = int(event.GetLong(1, &err2));
    150     auto isolated_uid = int(event.GetLong(2, &err3));
    151     if (err == NO_ERROR && err2 == NO_ERROR && err3 == NO_ERROR) {
    152         if (is_create) {
    153             mUidMap->assignIsolatedUid(isolated_uid, parent_uid);
    154         } else {
    155             mUidMap->removeIsolatedUid(isolated_uid, parent_uid);
    156         }
    157     } else {
    158         ALOGE("Failed to parse uid in the isolated uid change event.");
    159     }
    160 }
    161 
    162 void StatsLogProcessor::OnLogEvent(LogEvent* event) {
    163     OnLogEvent(event, false);
    164 }
    165 
    166 void StatsLogProcessor::resetConfigs() {
    167     std::lock_guard<std::mutex> lock(mMetricsMutex);
    168     resetConfigsLocked(getElapsedRealtimeNs());
    169 }
    170 
    171 void StatsLogProcessor::resetConfigsLocked(const int64_t timestampNs) {
    172     std::vector<ConfigKey> configKeys;
    173     for (auto it = mMetricsManagers.begin(); it != mMetricsManagers.end(); it++) {
    174         configKeys.push_back(it->first);
    175     }
    176     resetConfigsLocked(timestampNs, configKeys);
    177 }
    178 
    179 void StatsLogProcessor::OnLogEvent(LogEvent* event, bool reconnected) {
    180     std::lock_guard<std::mutex> lock(mMetricsMutex);
    181 
    182 #ifdef VERY_VERBOSE_PRINTING
    183     if (mPrintAllLogs) {
    184         ALOGI("%s", event->ToString().c_str());
    185     }
    186 #endif
    187     const int64_t currentTimestampNs = event->GetElapsedTimestampNs();
    188 
    189     if (reconnected && mLastTimestampSeen != 0) {
    190         // LogReader tells us the connection has just been reset. Now we need
    191         // to enter reconnection state to find the last CP.
    192         mInReconnection = true;
    193     }
    194 
    195     if (mInReconnection) {
    196         // We see the checkpoint
    197         if (currentTimestampNs == mLastTimestampSeen) {
    198             mInReconnection = false;
    199             // Found the CP. ignore this event, and we will start to read from next event.
    200             return;
    201         }
    202         if (currentTimestampNs > mLargestTimestampSeen) {
    203             // We see a new log but CP has not been found yet. Give up now.
    204             mLogLossCount++;
    205             mInReconnection = false;
    206             StatsdStats::getInstance().noteLogLost(currentTimestampNs);
    207             // Persist the data before we reset. Do we want this?
    208             WriteDataToDiskLocked(CONFIG_RESET);
    209             // We see fresher event before we see the checkpoint. We might have lost data.
    210             // The best we can do is to reset.
    211             resetConfigsLocked(currentTimestampNs);
    212         } else {
    213             // Still in search of the CP. Keep going.
    214             return;
    215         }
    216     }
    217 
    218     mLogCount++;
    219     mLastTimestampSeen = currentTimestampNs;
    220     if (mLargestTimestampSeen < currentTimestampNs) {
    221         mLargestTimestampSeen = currentTimestampNs;
    222     }
    223 
    224     resetIfConfigTtlExpiredLocked(currentTimestampNs);
    225 
    226     StatsdStats::getInstance().noteAtomLogged(
    227         event->GetTagId(), event->GetElapsedTimestampNs() / NS_PER_SEC);
    228 
    229     // Hard-coded logic to update the isolated uid's in the uid-map.
    230     // The field numbers need to be currently updated by hand with atoms.proto
    231     if (event->GetTagId() == android::util::ISOLATED_UID_CHANGED) {
    232         onIsolatedUidChangedEventLocked(*event);
    233     }
    234 
    235     if (mMetricsManagers.empty()) {
    236         return;
    237     }
    238 
    239     int64_t curTimeSec = getElapsedRealtimeSec();
    240     if (curTimeSec - mLastPullerCacheClearTimeSec > StatsdStats::kPullerCacheClearIntervalSec) {
    241         mStatsPullerManager.ClearPullerCacheIfNecessary(curTimeSec * NS_PER_SEC);
    242         mLastPullerCacheClearTimeSec = curTimeSec;
    243     }
    244 
    245 
    246     if (event->GetTagId() != android::util::ISOLATED_UID_CHANGED) {
    247         // Map the isolated uid to host uid if necessary.
    248         mapIsolatedUidToHostUidIfNecessaryLocked(event);
    249     }
    250 
    251     // pass the event to metrics managers.
    252     for (auto& pair : mMetricsManagers) {
    253         pair.second->onLogEvent(*event);
    254         flushIfNecessaryLocked(event->GetElapsedTimestampNs(), pair.first, *(pair.second));
    255     }
    256 }
    257 
    258 void StatsLogProcessor::OnConfigUpdated(const int64_t timestampNs, const ConfigKey& key,
    259                                         const StatsdConfig& config) {
    260     std::lock_guard<std::mutex> lock(mMetricsMutex);
    261     WriteDataToDiskLocked(key, timestampNs, CONFIG_UPDATED);
    262     OnConfigUpdatedLocked(timestampNs, key, config);
    263 }
    264 
    265 void StatsLogProcessor::OnConfigUpdatedLocked(
    266         const int64_t timestampNs, const ConfigKey& key, const StatsdConfig& config) {
    267     VLOG("Updated configuration for key %s", key.ToString().c_str());
    268     sp<MetricsManager> newMetricsManager =
    269         new MetricsManager(key, config, mTimeBaseNs, timestampNs, mUidMap,
    270                            mAnomalyAlarmMonitor, mPeriodicAlarmMonitor);
    271     if (newMetricsManager->isConfigValid()) {
    272         mUidMap->OnConfigUpdated(key);
    273         if (newMetricsManager->shouldAddUidMapListener()) {
    274             // We have to add listener after the MetricsManager is constructed because it's
    275             // not safe to create wp or sp from this pointer inside its constructor.
    276             mUidMap->addListener(newMetricsManager.get());
    277         }
    278         newMetricsManager->refreshTtl(timestampNs);
    279         mMetricsManagers[key] = newMetricsManager;
    280         VLOG("StatsdConfig valid");
    281     } else {
    282         // If there is any error in the config, don't use it.
    283         ALOGE("StatsdConfig NOT valid");
    284     }
    285 }
    286 
    287 size_t StatsLogProcessor::GetMetricsSize(const ConfigKey& key) const {
    288     std::lock_guard<std::mutex> lock(mMetricsMutex);
    289     auto it = mMetricsManagers.find(key);
    290     if (it == mMetricsManagers.end()) {
    291         ALOGW("Config source %s does not exist", key.ToString().c_str());
    292         return 0;
    293     }
    294     return it->second->byteSize();
    295 }
    296 
    297 void StatsLogProcessor::dumpStates(FILE* out, bool verbose) {
    298     std::lock_guard<std::mutex> lock(mMetricsMutex);
    299     fprintf(out, "MetricsManager count: %lu\n", (unsigned long)mMetricsManagers.size());
    300     for (auto metricsManager : mMetricsManagers) {
    301         metricsManager.second->dumpStates(out, verbose);
    302     }
    303 }
    304 
    305 /*
    306  * onDumpReport dumps serialized ConfigMetricsReportList into outData.
    307  */
    308 void StatsLogProcessor::onDumpReport(const ConfigKey& key, const int64_t dumpTimeStampNs,
    309                                      const bool include_current_partial_bucket,
    310                                      const DumpReportReason dumpReportReason,
    311                                      vector<uint8_t>* outData) {
    312     std::lock_guard<std::mutex> lock(mMetricsMutex);
    313 
    314     ProtoOutputStream proto;
    315 
    316     // Start of ConfigKey.
    317     uint64_t configKeyToken = proto.start(FIELD_TYPE_MESSAGE | FIELD_ID_CONFIG_KEY);
    318     proto.write(FIELD_TYPE_INT32 | FIELD_ID_UID, key.GetUid());
    319     proto.write(FIELD_TYPE_INT64 | FIELD_ID_ID, (long long)key.GetId());
    320     proto.end(configKeyToken);
    321     // End of ConfigKey.
    322 
    323     // Then, check stats-data directory to see there's any file containing
    324     // ConfigMetricsReport from previous shutdowns to concatenate to reports.
    325     StorageManager::appendConfigMetricsReport(key, &proto);
    326 
    327     auto it = mMetricsManagers.find(key);
    328     if (it != mMetricsManagers.end()) {
    329         // This allows another broadcast to be sent within the rate-limit period if we get close to
    330         // filling the buffer again soon.
    331         mLastBroadcastTimes.erase(key);
    332 
    333         // Start of ConfigMetricsReport (reports).
    334         uint64_t reportsToken =
    335                 proto.start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_REPORTS);
    336         onConfigMetricsReportLocked(key, dumpTimeStampNs, include_current_partial_bucket,
    337                                     dumpReportReason, &proto);
    338         proto.end(reportsToken);
    339         // End of ConfigMetricsReport (reports).
    340     } else {
    341         ALOGW("Config source %s does not exist", key.ToString().c_str());
    342     }
    343 
    344     if (outData != nullptr) {
    345         outData->clear();
    346         outData->resize(proto.size());
    347         size_t pos = 0;
    348         auto iter = proto.data();
    349         while (iter.readBuffer() != NULL) {
    350             size_t toRead = iter.currentToRead();
    351             std::memcpy(&((*outData)[pos]), iter.readBuffer(), toRead);
    352             pos += toRead;
    353             iter.rp()->move(toRead);
    354         }
    355     }
    356 
    357     StatsdStats::getInstance().noteMetricsReportSent(key, proto.size());
    358 }
    359 
    360 /*
    361  * onConfigMetricsReportLocked dumps serialized ConfigMetricsReport into outData.
    362  */
    363 void StatsLogProcessor::onConfigMetricsReportLocked(const ConfigKey& key,
    364                                                     const int64_t dumpTimeStampNs,
    365                                                     const bool include_current_partial_bucket,
    366                                                     const DumpReportReason dumpReportReason,
    367                                                     ProtoOutputStream* proto) {
    368     // We already checked whether key exists in mMetricsManagers in
    369     // WriteDataToDisk.
    370     auto it = mMetricsManagers.find(key);
    371     if (it == mMetricsManagers.end()) {
    372         return;
    373     }
    374     int64_t lastReportTimeNs = it->second->getLastReportTimeNs();
    375     int64_t lastReportWallClockNs = it->second->getLastReportWallClockNs();
    376 
    377     std::set<string> str_set;
    378 
    379     // First, fill in ConfigMetricsReport using current data on memory, which
    380     // starts from filling in StatsLogReport's.
    381     it->second->onDumpReport(dumpTimeStampNs, include_current_partial_bucket,
    382                              &str_set, proto);
    383 
    384     // Fill in UidMap if there is at least one metric to report.
    385     // This skips the uid map if it's an empty config.
    386     if (it->second->getNumMetrics() > 0) {
    387         uint64_t uidMapToken = proto->start(FIELD_TYPE_MESSAGE | FIELD_ID_UID_MAP);
    388         if (it->second->hashStringInReport()) {
    389             mUidMap->appendUidMap(dumpTimeStampNs, key, &str_set, proto);
    390         } else {
    391             mUidMap->appendUidMap(dumpTimeStampNs, key, nullptr, proto);
    392         }
    393         proto->end(uidMapToken);
    394     }
    395 
    396     // Fill in the timestamps.
    397     proto->write(FIELD_TYPE_INT64 | FIELD_ID_LAST_REPORT_ELAPSED_NANOS,
    398                 (long long)lastReportTimeNs);
    399     proto->write(FIELD_TYPE_INT64 | FIELD_ID_CURRENT_REPORT_ELAPSED_NANOS,
    400                 (long long)dumpTimeStampNs);
    401     proto->write(FIELD_TYPE_INT64 | FIELD_ID_LAST_REPORT_WALL_CLOCK_NANOS,
    402                 (long long)lastReportWallClockNs);
    403     proto->write(FIELD_TYPE_INT64 | FIELD_ID_CURRENT_REPORT_WALL_CLOCK_NANOS,
    404                 (long long)getWallClockNs());
    405     // Dump report reason
    406     proto->write(FIELD_TYPE_INT32 | FIELD_ID_DUMP_REPORT_REASON, dumpReportReason);
    407 
    408     for (const auto& str : str_set) {
    409         proto->write(FIELD_TYPE_STRING | FIELD_COUNT_REPEATED | FIELD_ID_STRINGS, str);
    410     }
    411 }
    412 
    413 void StatsLogProcessor::resetConfigsLocked(const int64_t timestampNs,
    414                                            const std::vector<ConfigKey>& configs) {
    415     for (const auto& key : configs) {
    416         StatsdConfig config;
    417         if (StorageManager::readConfigFromDisk(key, &config)) {
    418             OnConfigUpdatedLocked(timestampNs, key, config);
    419             StatsdStats::getInstance().noteConfigReset(key);
    420         } else {
    421             ALOGE("Failed to read backup config from disk for : %s", key.ToString().c_str());
    422             auto it = mMetricsManagers.find(key);
    423             if (it != mMetricsManagers.end()) {
    424                 it->second->refreshTtl(timestampNs);
    425             }
    426         }
    427     }
    428 }
    429 
    430 void StatsLogProcessor::resetIfConfigTtlExpiredLocked(const int64_t timestampNs) {
    431     std::vector<ConfigKey> configKeysTtlExpired;
    432     for (auto it = mMetricsManagers.begin(); it != mMetricsManagers.end(); it++) {
    433         if (it->second != nullptr && !it->second->isInTtl(timestampNs)) {
    434             configKeysTtlExpired.push_back(it->first);
    435         }
    436     }
    437     if (configKeysTtlExpired.size() > 0) {
    438         WriteDataToDiskLocked(CONFIG_RESET);
    439         resetConfigsLocked(timestampNs, configKeysTtlExpired);
    440     }
    441 }
    442 
    443 void StatsLogProcessor::OnConfigRemoved(const ConfigKey& key) {
    444     std::lock_guard<std::mutex> lock(mMetricsMutex);
    445     auto it = mMetricsManagers.find(key);
    446     if (it != mMetricsManagers.end()) {
    447         WriteDataToDiskLocked(key, getElapsedRealtimeNs(), CONFIG_REMOVED);
    448         mMetricsManagers.erase(it);
    449         mUidMap->OnConfigRemoved(key);
    450     }
    451     StatsdStats::getInstance().noteConfigRemoved(key);
    452 
    453     mLastBroadcastTimes.erase(key);
    454 
    455     if (mMetricsManagers.empty()) {
    456         mStatsPullerManager.ForceClearPullerCache();
    457     }
    458 }
    459 
    460 void StatsLogProcessor::flushIfNecessaryLocked(
    461     int64_t timestampNs, const ConfigKey& key, MetricsManager& metricsManager) {
    462     auto lastCheckTime = mLastByteSizeTimes.find(key);
    463     if (lastCheckTime != mLastByteSizeTimes.end()) {
    464         if (timestampNs - lastCheckTime->second < StatsdStats::kMinByteSizeCheckPeriodNs) {
    465             return;
    466         }
    467     }
    468 
    469     // We suspect that the byteSize() computation is expensive, so we set a rate limit.
    470     size_t totalBytes = metricsManager.byteSize();
    471     mLastByteSizeTimes[key] = timestampNs;
    472     bool requestDump = false;
    473     if (totalBytes >
    474         StatsdStats::kMaxMetricsBytesPerConfig) {  // Too late. We need to start clearing data.
    475         metricsManager.dropData(timestampNs);
    476         StatsdStats::getInstance().noteDataDropped(key);
    477         VLOG("StatsD had to toss out metrics for %s", key.ToString().c_str());
    478     } else if ((totalBytes > StatsdStats::kBytesPerConfigTriggerGetData) ||
    479                (mOnDiskDataConfigs.find(key) != mOnDiskDataConfigs.end())) {
    480         // Request to send a broadcast if:
    481         // 1. in memory data > threshold   OR
    482         // 2. config has old data report on disk.
    483         requestDump = true;
    484     }
    485 
    486     if (requestDump) {
    487         // Send broadcast so that receivers can pull data.
    488         auto lastBroadcastTime = mLastBroadcastTimes.find(key);
    489         if (lastBroadcastTime != mLastBroadcastTimes.end()) {
    490             if (timestampNs - lastBroadcastTime->second < StatsdStats::kMinBroadcastPeriodNs) {
    491                 VLOG("StatsD would've sent a broadcast but the rate limit stopped us.");
    492                 return;
    493             }
    494         }
    495         if (mSendBroadcast(key)) {
    496             mOnDiskDataConfigs.erase(key);
    497             VLOG("StatsD triggered data fetch for %s", key.ToString().c_str());
    498             mLastBroadcastTimes[key] = timestampNs;
    499             StatsdStats::getInstance().noteBroadcastSent(key);
    500         }
    501     }
    502 }
    503 
    504 void StatsLogProcessor::WriteDataToDiskLocked(const ConfigKey& key,
    505                                               const int64_t timestampNs,
    506                                               const DumpReportReason dumpReportReason) {
    507     if (mMetricsManagers.find(key) == mMetricsManagers.end() ||
    508         !mMetricsManagers.find(key)->second->shouldWriteToDisk()) {
    509         return;
    510     }
    511     ProtoOutputStream proto;
    512     onConfigMetricsReportLocked(key, timestampNs, true /* include_current_partial_bucket*/,
    513                                 dumpReportReason, &proto);
    514     string file_name = StringPrintf("%s/%ld_%d_%lld", STATS_DATA_DIR,
    515          (long)getWallClockSec(), key.GetUid(), (long long)key.GetId());
    516     android::base::unique_fd fd(open(file_name.c_str(),
    517                                 O_WRONLY | O_CREAT | O_CLOEXEC, S_IRUSR | S_IWUSR));
    518     if (fd == -1) {
    519         ALOGE("Attempt to write %s but failed", file_name.c_str());
    520         return;
    521     }
    522     proto.flush(fd.get());
    523     // We were able to write the ConfigMetricsReport to disk, so we should trigger collection ASAP.
    524     mOnDiskDataConfigs.insert(key);
    525 }
    526 
    527 void StatsLogProcessor::WriteDataToDiskLocked(const DumpReportReason dumpReportReason) {
    528     const int64_t timeNs = getElapsedRealtimeNs();
    529     for (auto& pair : mMetricsManagers) {
    530         WriteDataToDiskLocked(pair.first, timeNs, dumpReportReason);
    531     }
    532 }
    533 
    534 void StatsLogProcessor::WriteDataToDisk(const DumpReportReason dumpReportReason) {
    535     std::lock_guard<std::mutex> lock(mMetricsMutex);
    536     WriteDataToDiskLocked(dumpReportReason);
    537 }
    538 
    539 void StatsLogProcessor::informPullAlarmFired(const int64_t timestampNs) {
    540     std::lock_guard<std::mutex> lock(mMetricsMutex);
    541     mStatsPullerManager.OnAlarmFired(timestampNs);
    542 }
    543 
    544 int64_t StatsLogProcessor::getLastReportTimeNs(const ConfigKey& key) {
    545     auto it = mMetricsManagers.find(key);
    546     if (it == mMetricsManagers.end()) {
    547         return 0;
    548     } else {
    549         return it->second->getLastReportTimeNs();
    550     }
    551 }
    552 
    553 void StatsLogProcessor::noteOnDiskData(const ConfigKey& key) {
    554     std::lock_guard<std::mutex> lock(mMetricsMutex);
    555     mOnDiskDataConfigs.insert(key);
    556 }
    557 
    558 }  // namespace statsd
    559 }  // namespace os
    560 }  // namespace android
    561