1 /*
2  * Copyright (C) 2018 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 #include <pixelstats/StatsHelper.h>
18 #include <pixelstats/SysfsCollector.h>
19 
20 #define LOG_TAG "pixelstats-vendor"
21 
22 #include <android-base/file.h>
23 #include <android-base/parseint.h>
24 #include <android-base/properties.h>
25 #include <android-base/strings.h>
26 #include <android/binder_manager.h>
27 #include <utils/Log.h>
28 #include <utils/Timers.h>
29 
30 #include <mntent.h>
31 #include <sys/timerfd.h>
32 #include <sys/vfs.h>
33 #include <cinttypes>
34 #include <string>
35 
36 #ifndef ARRAY_SIZE
37 #define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
38 #endif
39 
40 namespace android {
41 namespace hardware {
42 namespace google {
43 namespace pixel {
44 
45 using aidl::android::frameworks::stats::VendorAtom;
46 using aidl::android::frameworks::stats::VendorAtomValue;
47 using android::base::ReadFileToString;
48 using android::base::StartsWith;
49 using android::base::WriteStringToFile;
50 using android::hardware::google::pixel::PixelAtoms::BatteryCapacity;
51 using android::hardware::google::pixel::PixelAtoms::BlockStatsReported;
52 using android::hardware::google::pixel::PixelAtoms::BootStatsInfo;
53 using android::hardware::google::pixel::PixelAtoms::DisplayPanelErrorStats;
54 using android::hardware::google::pixel::PixelAtoms::F2fsAtomicWriteInfo;
55 using android::hardware::google::pixel::PixelAtoms::F2fsCompressionInfo;
56 using android::hardware::google::pixel::PixelAtoms::F2fsGcSegmentInfo;
57 using android::hardware::google::pixel::PixelAtoms::F2fsSmartIdleMaintEnabledStateChanged;
58 using android::hardware::google::pixel::PixelAtoms::F2fsStatsInfo;
59 using android::hardware::google::pixel::PixelAtoms::PartitionsUsedSpaceReported;
60 using android::hardware::google::pixel::PixelAtoms::PcieLinkStatsReported;
61 using android::hardware::google::pixel::PixelAtoms::StorageUfsHealth;
62 using android::hardware::google::pixel::PixelAtoms::StorageUfsResetCount;
63 using android::hardware::google::pixel::PixelAtoms::ThermalDfsStats;
64 using android::hardware::google::pixel::PixelAtoms::VendorAudioAdaptedInfoStatsReported;
65 using android::hardware::google::pixel::PixelAtoms::VendorAudioHardwareStatsReported;
66 using android::hardware::google::pixel::PixelAtoms::VendorAudioPcmStatsReported;
67 using android::hardware::google::pixel::PixelAtoms::VendorAudioPdmStatsReported;
68 using android::hardware::google::pixel::PixelAtoms::VendorAudioThirdPartyEffectStatsReported;
69 using android::hardware::google::pixel::PixelAtoms::VendorChargeCycles;
70 using android::hardware::google::pixel::PixelAtoms::VendorHardwareFailed;
71 using android::hardware::google::pixel::PixelAtoms::VendorLongIRQStatsReported;
72 using android::hardware::google::pixel::PixelAtoms::VendorResumeLatencyStats;
73 using android::hardware::google::pixel::PixelAtoms::VendorSlowIo;
74 using android::hardware::google::pixel::PixelAtoms::VendorSpeakerImpedance;
75 using android::hardware::google::pixel::PixelAtoms::VendorSpeakerStatsReported;
76 using android::hardware::google::pixel::PixelAtoms::VendorSpeechDspStat;
77 using android::hardware::google::pixel::PixelAtoms::VendorTempResidencyStats;
78 using android::hardware::google::pixel::PixelAtoms::ZramBdStat;
79 using android::hardware::google::pixel::PixelAtoms::ZramMmStat;
80 
SysfsCollector(const struct SysfsPaths & sysfs_paths)81 SysfsCollector::SysfsCollector(const struct SysfsPaths &sysfs_paths)
82     : kSlowioReadCntPath(sysfs_paths.SlowioReadCntPath),
83       kSlowioWriteCntPath(sysfs_paths.SlowioWriteCntPath),
84       kSlowioUnmapCntPath(sysfs_paths.SlowioUnmapCntPath),
85       kSlowioSyncCntPath(sysfs_paths.SlowioSyncCntPath),
86       kCycleCountBinsPath(sysfs_paths.CycleCountBinsPath),
87       kImpedancePath(sysfs_paths.ImpedancePath),
88       kCodecPath(sysfs_paths.CodecPath),
89       kCodec1Path(sysfs_paths.Codec1Path),
90       kSpeechDspPath(sysfs_paths.SpeechDspPath),
91       kBatteryCapacityCC(sysfs_paths.BatteryCapacityCC),
92       kBatteryCapacityVFSOC(sysfs_paths.BatteryCapacityVFSOC),
93       kUFSLifetimeA(sysfs_paths.UFSLifetimeA),
94       kUFSLifetimeB(sysfs_paths.UFSLifetimeB),
95       kUFSLifetimeC(sysfs_paths.UFSLifetimeC),
96       kF2fsStatsPath(sysfs_paths.F2fsStatsPath),
97       kZramMmStatPath("/sys/block/zram0/mm_stat"),
98       kZramBdStatPath("/sys/block/zram0/bd_stat"),
99       kEEPROMPath(sysfs_paths.EEPROMPath),
100       kBrownoutLogPath(sysfs_paths.BrownoutLogPath),
101       kBrownoutReasonProp(sysfs_paths.BrownoutReasonProp),
102       kPowerMitigationStatsPath(sysfs_paths.MitigationPath),
103       kPowerMitigationDurationPath(sysfs_paths.MitigationDurationPath),
104       kSpeakerTemperaturePath(sysfs_paths.SpeakerTemperaturePath),
105       kSpeakerExcursionPath(sysfs_paths.SpeakerExcursionPath),
106       kSpeakerHeartbeatPath(sysfs_paths.SpeakerHeartBeatPath),
107       kUFSErrStatsPath(sysfs_paths.UFSErrStatsPath),
108       kBlockStatsLength(sysfs_paths.BlockStatsLength),
109       kAmsRatePath(sysfs_paths.AmsRatePath),
110       kThermalStatsPaths(sysfs_paths.ThermalStatsPaths),
111       kCCARatePath(sysfs_paths.CCARatePath),
112       kTempResidencyAndResetPaths(sysfs_paths.TempResidencyAndResetPaths),
113       kLongIRQMetricsPath(sysfs_paths.LongIRQMetricsPath),
114       kStormIRQMetricsPath(sysfs_paths.StormIRQMetricsPath),
115       kIRQStatsResetPath(sysfs_paths.IRQStatsResetPath),
116       kResumeLatencyMetricsPath(sysfs_paths.ResumeLatencyMetricsPath),
117       kModemPcieLinkStatsPath(sysfs_paths.ModemPcieLinkStatsPath),
118       kWifiPcieLinkStatsPath(sysfs_paths.WifiPcieLinkStatsPath),
119       kDisplayStatsPaths(sysfs_paths.DisplayStatsPaths),
120       kPDMStatePath(sysfs_paths.PDMStatePath),
121       kWavesPath(sysfs_paths.WavesPath),
122       kAdaptedInfoCountPath(sysfs_paths.AdaptedInfoCountPath),
123       kAdaptedInfoDurationPath(sysfs_paths.AdaptedInfoDurationPath),
124       kPcmLatencyPath(sysfs_paths.PcmLatencyPath),
125       kPcmCountPath(sysfs_paths.PcmCountPath),
126       kTotalCallCountPath(sysfs_paths.TotalCallCountPath) {}
127 
ReadFileToInt(const std::string & path,int * val)128 bool SysfsCollector::ReadFileToInt(const std::string &path, int *val) {
129     return ReadFileToInt(path.c_str(), val);
130 }
131 
ReadFileToInt(const char * const path,int * val)132 bool SysfsCollector::ReadFileToInt(const char *const path, int *val) {
133     std::string file_contents;
134 
135     if (!ReadFileToString(path, &file_contents)) {
136         ALOGE("Unable to read %s - %s", path, strerror(errno));
137         return false;
138     } else if (StartsWith(file_contents, "0x")) {
139         if (sscanf(file_contents.c_str(), "0x%x", val) != 1) {
140             ALOGE("Unable to convert %s to hex - %s", path, strerror(errno));
141             return false;
142         }
143     } else if (sscanf(file_contents.c_str(), "%d", val) != 1) {
144         ALOGE("Unable to convert %s to int - %s", path, strerror(errno));
145         return false;
146     }
147     return true;
148 }
149 
150 /**
151  * Read the contents of kCycleCountBinsPath and report them via IStats HAL.
152  * The contents are expected to be N buckets total, the nth of which indicates the
153  * number of times battery %-full has been increased with the n/N% full bucket.
154  */
logBatteryChargeCycles(const std::shared_ptr<IStats> & stats_client)155 void SysfsCollector::logBatteryChargeCycles(const std::shared_ptr<IStats> &stats_client) {
156     std::string file_contents;
157     int val;
158     if (kCycleCountBinsPath == nullptr || strlen(kCycleCountBinsPath) == 0) {
159         ALOGV("Battery charge cycle path not specified");
160         return;
161     }
162     if (!ReadFileToString(kCycleCountBinsPath, &file_contents)) {
163         ALOGE("Unable to read battery charge cycles %s - %s", kCycleCountBinsPath, strerror(errno));
164         return;
165     }
166 
167     const int32_t kChargeCyclesBucketsCount =
168             VendorChargeCycles::kCycleBucket10FieldNumber - kVendorAtomOffset + 1;
169     std::vector<int32_t> charge_cycles;
170     std::stringstream stream(file_contents);
171     while (stream >> val) {
172         charge_cycles.push_back(val);
173     }
174     if (charge_cycles.size() > kChargeCyclesBucketsCount) {
175         ALOGW("Got excessive battery charge cycles count %" PRIu64,
176               static_cast<uint64_t>(charge_cycles.size()));
177     } else {
178         // Push 0 for buckets that do not exist.
179         for (int bucketIdx = charge_cycles.size(); bucketIdx < kChargeCyclesBucketsCount;
180              ++bucketIdx) {
181             charge_cycles.push_back(0);
182         }
183     }
184 
185     std::replace(file_contents.begin(), file_contents.end(), ' ', ',');
186     reportChargeCycles(stats_client, charge_cycles);
187 }
188 
189 /**
190  * Read the contents of kEEPROMPath and report them.
191  */
logBatteryEEPROM(const std::shared_ptr<IStats> & stats_client)192 void SysfsCollector::logBatteryEEPROM(const std::shared_ptr<IStats> &stats_client) {
193     if (kEEPROMPath == nullptr || strlen(kEEPROMPath) == 0) {
194         ALOGV("Battery EEPROM path not specified");
195         return;
196     }
197 
198     battery_EEPROM_reporter_.checkAndReport(stats_client, kEEPROMPath);
199 }
200 
201 /**
202  * Log battery health stats
203  */
logBatteryHealth(const std::shared_ptr<IStats> & stats_client)204 void SysfsCollector::logBatteryHealth(const std::shared_ptr<IStats> &stats_client) {
205     battery_health_reporter_.checkAndReportStatus(stats_client);
206 }
207 
208 /**
209  * Check the codec for failures over the past 24hr.
210  */
logCodecFailed(const std::shared_ptr<IStats> & stats_client)211 void SysfsCollector::logCodecFailed(const std::shared_ptr<IStats> &stats_client) {
212     std::string file_contents;
213     if (kCodecPath == nullptr || strlen(kCodecPath) == 0) {
214         ALOGV("Audio codec path not specified");
215         return;
216     }
217     if (!ReadFileToString(kCodecPath, &file_contents)) {
218         ALOGE("Unable to read codec state %s - %s", kCodecPath, strerror(errno));
219         return;
220     }
221     if (file_contents == "0") {
222         return;
223     } else {
224         VendorHardwareFailed failure;
225         failure.set_hardware_type(VendorHardwareFailed::HARDWARE_FAILED_CODEC);
226         failure.set_hardware_location(0);
227         failure.set_failure_code(VendorHardwareFailed::COMPLETE);
228         reportHardwareFailed(stats_client, failure);
229     }
230 }
231 
232 /**
233  * Check the codec1 for failures over the past 24hr.
234  */
logCodec1Failed(const std::shared_ptr<IStats> & stats_client)235 void SysfsCollector::logCodec1Failed(const std::shared_ptr<IStats> &stats_client) {
236     std::string file_contents;
237     if (kCodec1Path == nullptr || strlen(kCodec1Path) == 0) {
238         ALOGV("Audio codec1 path not specified");
239         return;
240     }
241     if (!ReadFileToString(kCodec1Path, &file_contents)) {
242         ALOGE("Unable to read codec1 state %s - %s", kCodec1Path, strerror(errno));
243         return;
244     }
245     if (file_contents == "0") {
246         return;
247     } else {
248         ALOGE("%s report hardware fail", kCodec1Path);
249         VendorHardwareFailed failure;
250         failure.set_hardware_type(VendorHardwareFailed::HARDWARE_FAILED_CODEC);
251         failure.set_hardware_location(1);
252         failure.set_failure_code(VendorHardwareFailed::COMPLETE);
253         reportHardwareFailed(stats_client, failure);
254     }
255 }
256 
reportSlowIoFromFile(const std::shared_ptr<IStats> & stats_client,const char * path,const VendorSlowIo::IoOperation & operation_s)257 void SysfsCollector::reportSlowIoFromFile(const std::shared_ptr<IStats> &stats_client,
258                                           const char *path,
259                                           const VendorSlowIo::IoOperation &operation_s) {
260     std::string file_contents;
261     if (path == nullptr || strlen(path) == 0) {
262         ALOGV("slow_io path not specified");
263         return;
264     }
265     if (!ReadFileToString(path, &file_contents)) {
266         ALOGE("Unable to read slowio %s - %s", path, strerror(errno));
267         return;
268     } else {
269         int32_t slow_io_count = 0;
270         if (sscanf(file_contents.c_str(), "%d", &slow_io_count) != 1) {
271             ALOGE("Unable to parse %s from file %s to int.", file_contents.c_str(), path);
272         } else if (slow_io_count > 0) {
273             VendorSlowIo slow_io;
274             slow_io.set_operation(operation_s);
275             slow_io.set_count(slow_io_count);
276             reportSlowIo(stats_client, slow_io);
277         }
278         // Clear the stats
279         if (!android::base::WriteStringToFile("0", path, true)) {
280             ALOGE("Unable to clear SlowIO entry %s - %s", path, strerror(errno));
281         }
282     }
283 }
284 
285 /**
286  * Check for slow IO operations.
287  */
logSlowIO(const std::shared_ptr<IStats> & stats_client)288 void SysfsCollector::logSlowIO(const std::shared_ptr<IStats> &stats_client) {
289     reportSlowIoFromFile(stats_client, kSlowioReadCntPath, VendorSlowIo::READ);
290     reportSlowIoFromFile(stats_client, kSlowioWriteCntPath, VendorSlowIo::WRITE);
291     reportSlowIoFromFile(stats_client, kSlowioUnmapCntPath, VendorSlowIo::UNMAP);
292     reportSlowIoFromFile(stats_client, kSlowioSyncCntPath, VendorSlowIo::SYNC);
293 }
294 
295 /**
296  * Report the last-detected impedance of left & right speakers.
297  */
logSpeakerImpedance(const std::shared_ptr<IStats> & stats_client)298 void SysfsCollector::logSpeakerImpedance(const std::shared_ptr<IStats> &stats_client) {
299     std::string file_contents;
300     if (kImpedancePath == nullptr || strlen(kImpedancePath) == 0) {
301         ALOGV("Audio impedance path not specified");
302         return;
303     }
304     if (!ReadFileToString(kImpedancePath, &file_contents)) {
305         ALOGE("Unable to read impedance path %s", kImpedancePath);
306         return;
307     }
308 
309     float left, right;
310     if (sscanf(file_contents.c_str(), "%g,%g", &left, &right) != 2) {
311         ALOGE("Unable to parse speaker impedance %s", file_contents.c_str());
312         return;
313     }
314     VendorSpeakerImpedance left_obj;
315     left_obj.set_speaker_location(0);
316     left_obj.set_impedance(static_cast<int32_t>(left * 1000));
317 
318     VendorSpeakerImpedance right_obj;
319     right_obj.set_speaker_location(1);
320     right_obj.set_impedance(static_cast<int32_t>(right * 1000));
321 
322     reportSpeakerImpedance(stats_client, left_obj);
323     reportSpeakerImpedance(stats_client, right_obj);
324 }
325 
326 /**
327  * Report the last-detected impedance, temperature and heartbeats of left & right speakers.
328  */
logSpeakerHealthStats(const std::shared_ptr<IStats> & stats_client)329 void SysfsCollector::logSpeakerHealthStats(const std::shared_ptr<IStats> &stats_client) {
330     std::string file_contents_impedance;
331     std::string file_contents_temperature;
332     std::string file_contents_excursion;
333     std::string file_contents_heartbeat;
334     int count, i;
335     float impedance_ohm[4];
336     float temperature_C[4];
337     float excursion_mm[4];
338     float heartbeat[4];
339 
340     if (kImpedancePath == nullptr || strlen(kImpedancePath) == 0) {
341         ALOGD("Audio impedance path not specified");
342         return;
343     } else if (!ReadFileToString(kImpedancePath, &file_contents_impedance)) {
344         ALOGD("Unable to read speaker impedance path %s", kImpedancePath);
345         return;
346     }
347 
348     if (kSpeakerTemperaturePath == nullptr || strlen(kSpeakerTemperaturePath) == 0) {
349         ALOGD("Audio speaker temperature path not specified");
350         return;
351     } else if (!ReadFileToString(kSpeakerTemperaturePath, &file_contents_temperature)) {
352         ALOGD("Unable to read speaker temperature path %s", kSpeakerTemperaturePath);
353         return;
354     }
355 
356     if (kSpeakerExcursionPath == nullptr || strlen(kSpeakerExcursionPath) == 0) {
357         ALOGD("Audio speaker excursion path not specified");
358         return;
359     } else if (!ReadFileToString(kSpeakerExcursionPath, &file_contents_excursion)) {
360         ALOGD("Unable to read speaker excursion path %s", kSpeakerExcursionPath);
361         return;
362     }
363 
364     if (kSpeakerHeartbeatPath == nullptr || strlen(kSpeakerHeartbeatPath) == 0) {
365         ALOGD("Audio speaker heartbeat path not specified");
366         return;
367     } else if (!ReadFileToString(kSpeakerHeartbeatPath, &file_contents_heartbeat)) {
368         ALOGD("Unable to read speaker heartbeat path %s", kSpeakerHeartbeatPath);
369         return;
370     }
371 
372     count = sscanf(file_contents_impedance.c_str(), "%g,%g,%g,%g", &impedance_ohm[0],
373                    &impedance_ohm[1], &impedance_ohm[2], &impedance_ohm[3]);
374     if (count <= 0)
375         return;
376 
377     count = sscanf(file_contents_temperature.c_str(), "%g,%g,%g,%g", &temperature_C[0],
378                    &temperature_C[1], &temperature_C[2], &temperature_C[3]);
379     if (count <= 0)
380         return;
381 
382     count = sscanf(file_contents_excursion.c_str(), "%g,%g,%g,%g", &excursion_mm[0],
383                    &excursion_mm[1], &excursion_mm[2], &excursion_mm[3]);
384     if (count <= 0)
385         return;
386 
387     count = sscanf(file_contents_heartbeat.c_str(), "%g,%g,%g,%g", &heartbeat[0], &heartbeat[1],
388                    &heartbeat[2], &heartbeat[3]);
389     if (count <= 0)
390         return;
391 
392     VendorSpeakerStatsReported obj[4];
393     for (i = 0; i < count && i < 4; i++) {
394         obj[i].set_speaker_location(i);
395         obj[i].set_impedance(static_cast<int32_t>(impedance_ohm[i] * 1000));
396         obj[i].set_max_temperature(static_cast<int32_t>(temperature_C[i] * 1000));
397         obj[i].set_excursion(static_cast<int32_t>(excursion_mm[i] * 1000));
398         obj[i].set_heartbeat(static_cast<int32_t>(heartbeat[i]));
399 
400         reportSpeakerHealthStat(stats_client, obj[i]);
401     }
402 }
403 
logDisplayStats(const std::shared_ptr<IStats> & stats_client)404 void SysfsCollector::logDisplayStats(const std::shared_ptr<IStats> &stats_client) {
405     display_stats_reporter_.logDisplayStats(stats_client, kDisplayStatsPaths);
406 }
407 
logThermalStats(const std::shared_ptr<IStats> & stats_client)408 void SysfsCollector::logThermalStats(const std::shared_ptr<IStats> &stats_client) {
409     thermal_stats_reporter_.logThermalStats(stats_client, kThermalStatsPaths);
410 }
411 
412 /**
413  * Report the Speech DSP state.
414  */
logSpeechDspStat(const std::shared_ptr<IStats> & stats_client)415 void SysfsCollector::logSpeechDspStat(const std::shared_ptr<IStats> &stats_client) {
416     std::string file_contents;
417     if (kSpeechDspPath == nullptr || strlen(kSpeechDspPath) == 0) {
418         ALOGV("Speech DSP path not specified");
419         return;
420     }
421     if (!ReadFileToString(kSpeechDspPath, &file_contents)) {
422         ALOGE("Unable to read speech dsp path %s", kSpeechDspPath);
423         return;
424     }
425 
426     int32_t up_time = 0, down_time = 0, crash_count = 0, recover_count = 0;
427     if (sscanf(file_contents.c_str(), "%d,%d,%d,%d", &up_time, &down_time, &crash_count,
428                &recover_count) != 4) {
429         ALOGE("Unable to parse speech dsp stat %s", file_contents.c_str());
430         return;
431     }
432 
433     ALOGD("SpeechDSP uptime %d downtime %d crashcount %d recovercount %d", up_time, down_time,
434           crash_count, recover_count);
435     VendorSpeechDspStat dsp_stat;
436     dsp_stat.set_total_uptime_millis(up_time);
437     dsp_stat.set_total_downtime_millis(down_time);
438     dsp_stat.set_total_crash_count(crash_count);
439     dsp_stat.set_total_recover_count(recover_count);
440 
441     reportSpeechDspStat(stats_client, dsp_stat);
442 }
443 
logBatteryCapacity(const std::shared_ptr<IStats> & stats_client)444 void SysfsCollector::logBatteryCapacity(const std::shared_ptr<IStats> &stats_client) {
445     std::string file_contents;
446     if (kBatteryCapacityCC == nullptr || strlen(kBatteryCapacityCC) == 0) {
447         ALOGV("Battery Capacity CC path not specified");
448         return;
449     }
450     if (kBatteryCapacityVFSOC == nullptr || strlen(kBatteryCapacityVFSOC) == 0) {
451         ALOGV("Battery Capacity VFSOC path not specified");
452         return;
453     }
454     int delta_cc_sum, delta_vfsoc_sum;
455     if (!ReadFileToInt(kBatteryCapacityCC, &delta_cc_sum) ||
456             !ReadFileToInt(kBatteryCapacityVFSOC, &delta_vfsoc_sum))
457         return;
458 
459     // Load values array
460     std::vector<VendorAtomValue> values(2);
461     VendorAtomValue tmp;
462     tmp.set<VendorAtomValue::intValue>(delta_cc_sum);
463     values[BatteryCapacity::kDeltaCcSumFieldNumber - kVendorAtomOffset] = tmp;
464     tmp.set<VendorAtomValue::intValue>(delta_vfsoc_sum);
465     values[BatteryCapacity::kDeltaVfsocSumFieldNumber - kVendorAtomOffset] = tmp;
466 
467     // Send vendor atom to IStats HAL
468     VendorAtom event = {.reverseDomainName = "",
469                         .atomId = PixelAtoms::Atom::kBatteryCapacity,
470                         .values = std::move(values)};
471     const ndk::ScopedAStatus ret = stats_client->reportVendorAtom(event);
472     if (!ret.isOk())
473         ALOGE("Unable to report ChargeStats to Stats service");
474 }
475 
logUFSLifetime(const std::shared_ptr<IStats> & stats_client)476 void SysfsCollector::logUFSLifetime(const std::shared_ptr<IStats> &stats_client) {
477     std::string file_contents;
478     if (kUFSLifetimeA == nullptr || strlen(kUFSLifetimeA) == 0) {
479         ALOGV("UFS lifetimeA path not specified");
480         return;
481     }
482     if (kUFSLifetimeB == nullptr || strlen(kUFSLifetimeB) == 0) {
483         ALOGV("UFS lifetimeB path not specified");
484         return;
485     }
486     if (kUFSLifetimeC == nullptr || strlen(kUFSLifetimeC) == 0) {
487         ALOGV("UFS lifetimeC path not specified");
488         return;
489     }
490 
491     int lifetimeA = 0, lifetimeB = 0, lifetimeC = 0;
492     if (!ReadFileToInt(kUFSLifetimeA, &lifetimeA) ||
493         !ReadFileToInt(kUFSLifetimeB, &lifetimeB) ||
494         !ReadFileToInt(kUFSLifetimeC, &lifetimeC)) {
495         ALOGE("Unable to read UFS lifetime : %s", strerror(errno));
496         return;
497     }
498 
499     // Load values array
500     std::vector<VendorAtomValue> values(3);
501     VendorAtomValue tmp;
502     tmp.set<VendorAtomValue::intValue>(lifetimeA);
503     values[StorageUfsHealth::kLifetimeAFieldNumber - kVendorAtomOffset] = tmp;
504     tmp.set<VendorAtomValue::intValue>(lifetimeB);
505     values[StorageUfsHealth::kLifetimeBFieldNumber - kVendorAtomOffset] = tmp;
506     tmp.set<VendorAtomValue::intValue>(lifetimeC);
507     values[StorageUfsHealth::kLifetimeCFieldNumber - kVendorAtomOffset] = tmp;
508 
509     // Send vendor atom to IStats HAL
510     VendorAtom event = {.reverseDomainName = "",
511                         .atomId = PixelAtoms::Atom::kStorageUfsHealth,
512                         .values = std::move(values)};
513     const ndk::ScopedAStatus ret = stats_client->reportVendorAtom(event);
514     if (!ret.isOk()) {
515         ALOGE("Unable to report UfsHealthStat to Stats service");
516     }
517 }
518 
logUFSErrorStats(const std::shared_ptr<IStats> & stats_client)519 void SysfsCollector::logUFSErrorStats(const std::shared_ptr<IStats> &stats_client) {
520     int value, host_reset_count = 0;
521 
522     if (kUFSErrStatsPath.empty() || strlen(kUFSErrStatsPath.front().c_str()) == 0) {
523         ALOGV("UFS host reset count path not specified");
524         return;
525     }
526 
527     for (int i = 0; i < kUFSErrStatsPath.size(); i++) {
528         if (!ReadFileToInt(kUFSErrStatsPath[i], &value)) {
529             ALOGE("Unable to read host reset count");
530             return;
531         }
532         host_reset_count += value;
533     }
534 
535     // Load values array
536     std::vector<VendorAtomValue> values(1);
537     VendorAtomValue tmp;
538     tmp.set<VendorAtomValue::intValue>(host_reset_count);
539     values[StorageUfsResetCount::kHostResetCountFieldNumber - kVendorAtomOffset] = tmp;
540 
541     // Send vendor atom to IStats HAL
542     VendorAtom event = {.reverseDomainName = "",
543                         .atomId = PixelAtoms::Atom::kUfsResetCount,
544                         .values = std::move(values)};
545     const ndk::ScopedAStatus ret = stats_client->reportVendorAtom(event);
546     if (!ret.isOk()) {
547         ALOGE("Unable to report UFS host reset count to Stats service");
548     }
549 }
550 
getUserDataBlock()551 static std::string getUserDataBlock() {
552     std::unique_ptr<std::FILE, int (*)(std::FILE*)> fp(setmntent("/proc/mounts", "re"), endmntent);
553     if (fp == nullptr) {
554         ALOGE("Error opening /proc/mounts");
555         return "";
556     }
557 
558     mntent* mentry;
559     while ((mentry = getmntent(fp.get())) != nullptr) {
560         if (strcmp(mentry->mnt_dir, "/data") == 0) {
561             return std::string(basename(mentry->mnt_fsname));
562         }
563     }
564     return "";
565 }
566 
logF2fsStats(const std::shared_ptr<IStats> & stats_client)567 void SysfsCollector::logF2fsStats(const std::shared_ptr<IStats> &stats_client) {
568     int dirty, free, cp_calls_fg, gc_calls_fg, moved_block_fg, vblocks;
569     int cp_calls_bg, gc_calls_bg, moved_block_bg;
570 
571     if (kF2fsStatsPath == nullptr) {
572         ALOGE("F2fs stats path not specified");
573         return;
574     }
575 
576     const std::string userdataBlock = getUserDataBlock();
577     const std::string kF2fsStatsDir = kF2fsStatsPath + userdataBlock;
578 
579     if (!ReadFileToInt(kF2fsStatsDir + "/dirty_segments", &dirty)) {
580         ALOGV("Unable to read dirty segments");
581     }
582 
583     if (!ReadFileToInt(kF2fsStatsDir + "/free_segments", &free)) {
584         ALOGV("Unable to read free segments");
585     }
586 
587     if (!ReadFileToInt(kF2fsStatsDir + "/cp_foreground_calls", &cp_calls_fg)) {
588         ALOGV("Unable to read cp_foreground_calls");
589     }
590 
591     if (!ReadFileToInt(kF2fsStatsDir + "/cp_background_calls", &cp_calls_bg)) {
592         ALOGV("Unable to read cp_background_calls");
593     }
594 
595     if (!ReadFileToInt(kF2fsStatsDir + "/gc_foreground_calls", &gc_calls_fg)) {
596         ALOGV("Unable to read gc_foreground_calls");
597     }
598 
599     if (!ReadFileToInt(kF2fsStatsDir + "/gc_background_calls", &gc_calls_bg)) {
600         ALOGV("Unable to read gc_background_calls");
601     }
602 
603     if (!ReadFileToInt(kF2fsStatsDir + "/moved_blocks_foreground", &moved_block_fg)) {
604         ALOGV("Unable to read moved_blocks_foreground");
605     }
606 
607     if (!ReadFileToInt(kF2fsStatsDir + "/moved_blocks_background", &moved_block_bg)) {
608         ALOGV("Unable to read moved_blocks_background");
609     }
610 
611     if (!ReadFileToInt(kF2fsStatsDir + "/avg_vblocks", &vblocks)) {
612         ALOGV("Unable to read avg_vblocks");
613     }
614 
615     // Load values array
616     std::vector<VendorAtomValue> values(9);
617     VendorAtomValue tmp;
618     tmp.set<VendorAtomValue::intValue>(dirty);
619     values[F2fsStatsInfo::kDirtySegmentsFieldNumber - kVendorAtomOffset] = tmp;
620     tmp.set<VendorAtomValue::intValue>(free);
621     values[F2fsStatsInfo::kFreeSegmentsFieldNumber - kVendorAtomOffset] = tmp;
622     tmp.set<VendorAtomValue::intValue>(cp_calls_fg);
623     values[F2fsStatsInfo::kCpCallsFgFieldNumber - kVendorAtomOffset] = tmp;
624     tmp.set<VendorAtomValue::intValue>(cp_calls_bg);
625     values[F2fsStatsInfo::kCpCallsBgFieldNumber - kVendorAtomOffset] = tmp;
626     tmp.set<VendorAtomValue::intValue>(gc_calls_fg);
627     values[F2fsStatsInfo::kGcCallsFgFieldNumber - kVendorAtomOffset] = tmp;
628     tmp.set<VendorAtomValue::intValue>(gc_calls_bg);
629     values[F2fsStatsInfo::kGcCallsBgFieldNumber - kVendorAtomOffset] = tmp;
630     tmp.set<VendorAtomValue::intValue>(moved_block_fg);
631     values[F2fsStatsInfo::kMovedBlocksFgFieldNumber - kVendorAtomOffset] = tmp;
632     tmp.set<VendorAtomValue::intValue>(moved_block_bg);
633     values[F2fsStatsInfo::kMovedBlocksBgFieldNumber - kVendorAtomOffset] = tmp;
634     tmp.set<VendorAtomValue::intValue>(vblocks);
635     values[F2fsStatsInfo::kValidBlocksFieldNumber - kVendorAtomOffset] = tmp;
636 
637     // Send vendor atom to IStats HAL
638     VendorAtom event = {.reverseDomainName = "",
639                         .atomId = PixelAtoms::Atom::kF2FsStats,
640                         .values = std::move(values)};
641     const ndk::ScopedAStatus ret = stats_client->reportVendorAtom(event);
642     if (!ret.isOk()) {
643         ALOGE("Unable to report F2fs stats to Stats service");
644     }
645 }
646 
logF2fsAtomicWriteInfo(const std::shared_ptr<IStats> & stats_client)647 void SysfsCollector::logF2fsAtomicWriteInfo(const std::shared_ptr<IStats> &stats_client) {
648     int peak_atomic_write, committed_atomic_block, revoked_atomic_block;
649 
650     if (kF2fsStatsPath == nullptr) {
651         ALOGV("F2fs stats path not specified");
652         return;
653     }
654 
655     std::string userdataBlock = getUserDataBlock();
656 
657     std::string path = kF2fsStatsPath + (userdataBlock + "/peak_atomic_write");
658     if (!ReadFileToInt(path, &peak_atomic_write)) {
659         ALOGE("Unable to read peak_atomic_write");
660         return;
661     } else {
662         if (!WriteStringToFile(std::to_string(0), path)) {
663             ALOGE("Failed to write to file %s", path.c_str());
664             return;
665         }
666     }
667 
668     path = kF2fsStatsPath + (userdataBlock + "/committed_atomic_block");
669     if (!ReadFileToInt(path, &committed_atomic_block)) {
670         ALOGE("Unable to read committed_atomic_block");
671         return;
672     } else {
673         if (!WriteStringToFile(std::to_string(0), path)) {
674             ALOGE("Failed to write to file %s", path.c_str());
675             return;
676         }
677     }
678 
679     path = kF2fsStatsPath + (userdataBlock + "/revoked_atomic_block");
680     if (!ReadFileToInt(path, &revoked_atomic_block)) {
681         ALOGE("Unable to read revoked_atomic_block");
682         return;
683     } else {
684         if (!WriteStringToFile(std::to_string(0), path)) {
685             ALOGE("Failed to write to file %s", path.c_str());
686             return;
687         }
688     }
689 
690     // Load values array
691     std::vector<VendorAtomValue> values(3);
692     values[F2fsAtomicWriteInfo::kPeakAtomicWriteFieldNumber - kVendorAtomOffset] =
693                     VendorAtomValue::make<VendorAtomValue::intValue>(peak_atomic_write);
694     values[F2fsAtomicWriteInfo::kCommittedAtomicBlockFieldNumber - kVendorAtomOffset] =
695                     VendorAtomValue::make<VendorAtomValue::intValue>(committed_atomic_block);
696     values[F2fsAtomicWriteInfo::kRevokedAtomicBlockFieldNumber - kVendorAtomOffset] =
697                     VendorAtomValue::make<VendorAtomValue::intValue>(revoked_atomic_block);
698 
699     // Send vendor atom to IStats HAL
700     VendorAtom event = {.reverseDomainName = "",
701                         .atomId = PixelAtoms::Atom::kF2FsAtomicWriteInfo,
702                         .values = values};
703     const ndk::ScopedAStatus ret = stats_client->reportVendorAtom(event);
704     if (!ret.isOk()) {
705         ALOGE("Unable to report F2fs Atomic Write info to Stats service");
706     }
707 }
708 
logF2fsCompressionInfo(const std::shared_ptr<IStats> & stats_client)709 void SysfsCollector::logF2fsCompressionInfo(const std::shared_ptr<IStats> &stats_client) {
710     int compr_written_blocks, compr_saved_blocks, compr_new_inodes;
711 
712     if (kF2fsStatsPath == nullptr) {
713         ALOGV("F2fs stats path not specified");
714         return;
715     }
716 
717     std::string userdataBlock = getUserDataBlock();
718 
719     std::string path = kF2fsStatsPath + (userdataBlock + "/compr_written_block");
720     if (!ReadFileToInt(path, &compr_written_blocks)) {
721         ALOGE("Unable to read compression written blocks");
722         return;
723     }
724 
725     path = kF2fsStatsPath + (userdataBlock + "/compr_saved_block");
726     if (!ReadFileToInt(path, &compr_saved_blocks)) {
727         ALOGE("Unable to read compression saved blocks");
728         return;
729     } else {
730         if (!WriteStringToFile(std::to_string(0), path)) {
731             ALOGE("Failed to write to file %s", path.c_str());
732             return;
733         }
734     }
735 
736     path = kF2fsStatsPath + (userdataBlock + "/compr_new_inode");
737     if (!ReadFileToInt(path, &compr_new_inodes)) {
738         ALOGE("Unable to read compression new inodes");
739         return;
740     } else {
741         if (!WriteStringToFile(std::to_string(0), path)) {
742             ALOGE("Failed to write to file %s", path.c_str());
743             return;
744         }
745     }
746 
747     // Load values array
748     std::vector<VendorAtomValue> values(3);
749     VendorAtomValue tmp;
750     tmp.set<VendorAtomValue::intValue>(compr_written_blocks);
751     values[F2fsCompressionInfo::kComprWrittenBlocksFieldNumber - kVendorAtomOffset] = tmp;
752     tmp.set<VendorAtomValue::intValue>(compr_saved_blocks);
753     values[F2fsCompressionInfo::kComprSavedBlocksFieldNumber - kVendorAtomOffset] = tmp;
754     tmp.set<VendorAtomValue::intValue>(compr_new_inodes);
755     values[F2fsCompressionInfo::kComprNewInodesFieldNumber - kVendorAtomOffset] = tmp;
756 
757     // Send vendor atom to IStats HAL
758     VendorAtom event = {.reverseDomainName = "",
759                         .atomId = PixelAtoms::Atom::kF2FsCompressionInfo,
760                         .values = values};
761     const ndk::ScopedAStatus ret = stats_client->reportVendorAtom(event);
762     if (!ret.isOk()) {
763         ALOGE("Unable to report F2fs compression info to Stats service");
764     }
765 }
766 
getReclaimedSegments(const std::string & mode)767 int SysfsCollector::getReclaimedSegments(const std::string &mode) {
768     std::string userDataStatsPath = kF2fsStatsPath + getUserDataBlock();
769     std::string gcSegmentModePath = userDataStatsPath + "/gc_segment_mode";
770     std::string gcReclaimedSegmentsPath = userDataStatsPath + "/gc_reclaimed_segments";
771     int reclaimed_segments;
772 
773     if (!WriteStringToFile(mode, gcSegmentModePath)) {
774         ALOGE("Failed to change gc_segment_mode to %s", mode.c_str());
775         return -1;
776     }
777 
778     if (!ReadFileToInt(gcReclaimedSegmentsPath, &reclaimed_segments)) {
779         ALOGE("GC mode(%s): Unable to read gc_reclaimed_segments", mode.c_str());
780         return -1;
781     }
782 
783     if (!WriteStringToFile(std::to_string(0), gcReclaimedSegmentsPath)) {
784         ALOGE("GC mode(%s): Failed to reset gc_reclaimed_segments", mode.c_str());
785         return -1;
786     }
787 
788     return reclaimed_segments;
789 }
790 
logF2fsGcSegmentInfo(const std::shared_ptr<IStats> & stats_client)791 void SysfsCollector::logF2fsGcSegmentInfo(const std::shared_ptr<IStats> &stats_client) {
792     int reclaimed_segments_normal, reclaimed_segments_urgent_high;
793     int reclaimed_segments_urgent_mid, reclaimed_segments_urgent_low;
794     std::string gc_normal_mode = std::to_string(0);         // GC normal mode
795     std::string gc_urgent_high_mode = std::to_string(4);    // GC urgent high mode
796     std::string gc_urgent_low_mode = std::to_string(5);     // GC urgent low mode
797     std::string gc_urgent_mid_mode = std::to_string(6);     // GC urgent mid mode
798 
799     if (kF2fsStatsPath == nullptr) {
800         ALOGV("F2fs stats path not specified");
801         return;
802     }
803 
804     reclaimed_segments_normal = getReclaimedSegments(gc_normal_mode);
805     if (reclaimed_segments_normal == -1) return;
806     reclaimed_segments_urgent_high = getReclaimedSegments(gc_urgent_high_mode);
807     if (reclaimed_segments_urgent_high == -1) return;
808     reclaimed_segments_urgent_low = getReclaimedSegments(gc_urgent_low_mode);
809     if (reclaimed_segments_urgent_low == -1) return;
810     reclaimed_segments_urgent_mid = getReclaimedSegments(gc_urgent_mid_mode);
811     if (reclaimed_segments_urgent_mid == -1) return;
812 
813     // Load values array
814     std::vector<VendorAtomValue> values(4);
815     VendorAtomValue tmp;
816     tmp.set<VendorAtomValue::intValue>(reclaimed_segments_normal);
817     values[F2fsGcSegmentInfo::kReclaimedSegmentsNormalFieldNumber - kVendorAtomOffset] = tmp;
818     tmp.set<VendorAtomValue::intValue>(reclaimed_segments_urgent_high);
819     values[F2fsGcSegmentInfo::kReclaimedSegmentsUrgentHighFieldNumber - kVendorAtomOffset] = tmp;
820     tmp.set<VendorAtomValue::intValue>(reclaimed_segments_urgent_low);
821     values[F2fsGcSegmentInfo::kReclaimedSegmentsUrgentLowFieldNumber - kVendorAtomOffset] = tmp;
822     tmp.set<VendorAtomValue::intValue>(reclaimed_segments_urgent_mid);
823     values[F2fsGcSegmentInfo::kReclaimedSegmentsUrgentMidFieldNumber - kVendorAtomOffset] = tmp;
824 
825     // Send vendor atom to IStats HAL
826     VendorAtom event = {.reverseDomainName = "",
827                         .atomId = PixelAtoms::Atom::kF2FsGcSegmentInfo,
828                         .values = values};
829     const ndk::ScopedAStatus ret = stats_client->reportVendorAtom(event);
830     if (!ret.isOk()) {
831         ALOGE("Unable to report F2fs GC Segment info to Stats service");
832     }
833 }
834 
logF2fsSmartIdleMaintEnabled(const std::shared_ptr<IStats> & stats_client)835 void SysfsCollector::logF2fsSmartIdleMaintEnabled(const std::shared_ptr<IStats> &stats_client) {
836     bool smart_idle_enabled = android::base::GetBoolProperty(
837         "persist.device_config.storage_native_boot.smart_idle_maint_enabled", false);
838 
839     // Load values array
840     VendorAtomValue tmp;
841     std::vector<VendorAtomValue> values(1);
842     tmp.set<VendorAtomValue::intValue>(smart_idle_enabled);
843     values[F2fsSmartIdleMaintEnabledStateChanged::kEnabledFieldNumber - kVendorAtomOffset] = tmp;
844 
845     // Send vendor atom to IStats HAL
846     VendorAtom event = {.reverseDomainName = PixelAtoms::ReverseDomainNames().pixel(),
847                         .atomId = PixelAtoms::Atom::kF2FsSmartIdleMaintEnabledStateChanged,
848                         .values = std::move(values)};
849     const ndk::ScopedAStatus ret = stats_client->reportVendorAtom(event);
850     if (!ret.isOk()) {
851         ALOGE("Unable to report F2fsSmartIdleMaintEnabled to Stats service");
852     }
853 }
854 
logBlockStatsReported(const std::shared_ptr<IStats> & stats_client)855 void SysfsCollector::logBlockStatsReported(const std::shared_ptr<IStats> &stats_client) {
856     std::string sdaPath = "/sys/block/sda/stat";
857     std::string file_contents;
858     std::string stat;
859     std::vector<std::string> stats;
860     std::stringstream ss;
861 
862     // These index comes from kernel Document
863     // Documentation/ABI/stable/sysfs-block
864     const int READ_IO_IDX = 0, READ_SEC_IDX = 2, READ_TICK_IDX = 3;
865     const int WRITE_IO_IDX = 4, WRITE_SEC_IDX = 6, WRITE_TICK_IDX = 7;
866     uint64_t read_io, read_sectors, read_ticks;
867     uint64_t write_io, write_sectors, write_ticks;
868 
869     if (!ReadFileToString(sdaPath.c_str(), &file_contents)) {
870         ALOGE("Failed to read block layer stat %s", sdaPath.c_str());
871         return;
872     }
873 
874     ss.str(file_contents);
875     while (ss >> stat) {
876         stats.push_back(stat);
877     }
878 
879     if (stats.size() < kBlockStatsLength) {
880         ALOGE("block layer stat format is incorrect %s, length %zu/%d", file_contents.c_str(),
881               stats.size(), kBlockStatsLength);
882         return;
883     }
884 
885     read_io = std::stoul(stats[READ_IO_IDX]);
886     read_sectors = std::stoul(stats[READ_SEC_IDX]);
887     read_ticks = std::stoul(stats[READ_TICK_IDX]);
888     write_io = std::stoul(stats[WRITE_IO_IDX]);
889     write_sectors = std::stoul(stats[WRITE_SEC_IDX]);
890     write_ticks = std::stoul(stats[WRITE_TICK_IDX]);
891 
892     // Load values array
893     std::vector<VendorAtomValue> values(6);
894     values[BlockStatsReported::kReadIoFieldNumber - kVendorAtomOffset] =
895                         VendorAtomValue::make<VendorAtomValue::longValue>(read_io);
896     values[BlockStatsReported::kReadSectorsFieldNumber - kVendorAtomOffset] =
897                         VendorAtomValue::make<VendorAtomValue::longValue>(read_sectors);
898     values[BlockStatsReported::kReadTicksFieldNumber - kVendorAtomOffset] =
899                         VendorAtomValue::make<VendorAtomValue::longValue>(read_ticks);
900     values[BlockStatsReported::kWriteIoFieldNumber - kVendorAtomOffset] =
901                         VendorAtomValue::make<VendorAtomValue::longValue>(write_io);
902     values[BlockStatsReported::kWriteSectorsFieldNumber - kVendorAtomOffset] =
903                         VendorAtomValue::make<VendorAtomValue::longValue>(write_sectors);
904     values[BlockStatsReported::kWriteTicksFieldNumber - kVendorAtomOffset] =
905                         VendorAtomValue::make<VendorAtomValue::longValue>(write_ticks);
906 
907     // Send vendor atom to IStats HAL
908     VendorAtom event = {.reverseDomainName = PixelAtoms::ReverseDomainNames().pixel(),
909                         .atomId = PixelAtoms::Atom::kBlockStatsReported,
910                         .values = std::move(values)};
911     const ndk::ScopedAStatus ret = stats_client->reportVendorAtom(event);
912     if (!ret.isOk()) {
913         ALOGE("Unable to report block layer stats to Stats service");
914     }
915 }
916 
logTempResidencyStats(const std::shared_ptr<IStats> & stats_client)917 void SysfsCollector::logTempResidencyStats(const std::shared_ptr<IStats> &stats_client) {
918     for (const auto &temp_residency_and_reset_path : kTempResidencyAndResetPaths) {
919         temp_residency_reporter_.logTempResidencyStats(stats_client,
920                                                        temp_residency_and_reset_path.first,
921                                                        temp_residency_and_reset_path.second);
922     }
923 }
924 
reportZramMmStat(const std::shared_ptr<IStats> & stats_client)925 void SysfsCollector::reportZramMmStat(const std::shared_ptr<IStats> &stats_client) {
926     std::string file_contents;
927     if (!kZramMmStatPath) {
928         ALOGV("ZramMmStat path not specified");
929         return;
930     }
931 
932     if (!ReadFileToString(kZramMmStatPath, &file_contents)) {
933         ALOGE("Unable to ZramMmStat %s - %s", kZramMmStatPath, strerror(errno));
934         return;
935     } else {
936         int64_t orig_data_size = 0;
937         int64_t compr_data_size = 0;
938         int64_t mem_used_total = 0;
939         int64_t mem_limit = 0;
940         int64_t max_used_total = 0;
941         int64_t same_pages = 0;
942         int64_t pages_compacted = 0;
943         int64_t huge_pages = 0;
944         int64_t huge_pages_since_boot = 0;
945 
946         // huge_pages_since_boot may not exist according to kernel version.
947         // only check if the number of collected data is equal or larger then 8
948         if (sscanf(file_contents.c_str(),
949                    "%" SCNd64 " %" SCNd64 " %" SCNd64 " %" SCNd64 " %" SCNd64 " %" SCNd64
950                    " %" SCNd64 " %" SCNd64 " %" SCNd64,
951                    &orig_data_size, &compr_data_size, &mem_used_total, &mem_limit, &max_used_total,
952                    &same_pages, &pages_compacted, &huge_pages, &huge_pages_since_boot) < 8) {
953             ALOGE("Unable to parse ZramMmStat %s from file %s to int.",
954                     file_contents.c_str(), kZramMmStatPath);
955         }
956 
957         // Load values array.
958         // The size should be the same as the number of fields in ZramMmStat
959         std::vector<VendorAtomValue> values(6);
960         VendorAtomValue tmp;
961         tmp.set<VendorAtomValue::intValue>(orig_data_size);
962         values[ZramMmStat::kOrigDataSizeFieldNumber - kVendorAtomOffset] = tmp;
963         tmp.set<VendorAtomValue::intValue>(compr_data_size);
964         values[ZramMmStat::kComprDataSizeFieldNumber - kVendorAtomOffset] = tmp;
965         tmp.set<VendorAtomValue::intValue>(mem_used_total);
966         values[ZramMmStat::kMemUsedTotalFieldNumber - kVendorAtomOffset] = tmp;
967         tmp.set<VendorAtomValue::intValue>(same_pages);
968         values[ZramMmStat::kSamePagesFieldNumber - kVendorAtomOffset] = tmp;
969         tmp.set<VendorAtomValue::intValue>(huge_pages);
970         values[ZramMmStat::kHugePagesFieldNumber - kVendorAtomOffset] = tmp;
971 
972         // Skip the first data to avoid a big spike in this accumulated value.
973         if (prev_huge_pages_since_boot_ == -1)
974             tmp.set<VendorAtomValue::intValue>(0);
975         else
976             tmp.set<VendorAtomValue::intValue>(huge_pages_since_boot - prev_huge_pages_since_boot_);
977 
978         values[ZramMmStat::kHugePagesSinceBootFieldNumber - kVendorAtomOffset] = tmp;
979         prev_huge_pages_since_boot_ = huge_pages_since_boot;
980 
981         // Send vendor atom to IStats HAL
982         VendorAtom event = {.reverseDomainName = "",
983                             .atomId = PixelAtoms::Atom::kZramMmStat,
984                             .values = std::move(values)};
985         const ndk::ScopedAStatus ret = stats_client->reportVendorAtom(event);
986         if (!ret.isOk())
987             ALOGE("Zram Unable to report ZramMmStat to Stats service");
988     }
989 }
990 
reportZramBdStat(const std::shared_ptr<IStats> & stats_client)991 void SysfsCollector::reportZramBdStat(const std::shared_ptr<IStats> &stats_client) {
992     std::string file_contents;
993     if (!kZramBdStatPath) {
994         ALOGV("ZramBdStat path not specified");
995         return;
996     }
997 
998     if (!ReadFileToString(kZramBdStatPath, &file_contents)) {
999         ALOGE("Unable to ZramBdStat %s - %s", kZramBdStatPath, strerror(errno));
1000         return;
1001     } else {
1002         int64_t bd_count = 0;
1003         int64_t bd_reads = 0;
1004         int64_t bd_writes = 0;
1005 
1006         if (sscanf(file_contents.c_str(), "%" SCNd64 " %" SCNd64 " %" SCNd64,
1007                                 &bd_count, &bd_reads, &bd_writes) != 3) {
1008             ALOGE("Unable to parse ZramBdStat %s from file %s to int.",
1009                     file_contents.c_str(), kZramBdStatPath);
1010         }
1011 
1012         // Load values array
1013         std::vector<VendorAtomValue> values(3);
1014         VendorAtomValue tmp;
1015         tmp.set<VendorAtomValue::intValue>(bd_count);
1016         values[ZramBdStat::kBdCountFieldNumber - kVendorAtomOffset] = tmp;
1017         tmp.set<VendorAtomValue::intValue>(bd_reads);
1018         values[ZramBdStat::kBdReadsFieldNumber - kVendorAtomOffset] = tmp;
1019         tmp.set<VendorAtomValue::intValue>(bd_writes);
1020         values[ZramBdStat::kBdWritesFieldNumber - kVendorAtomOffset] = tmp;
1021 
1022         // Send vendor atom to IStats HAL
1023         VendorAtom event = {.reverseDomainName = "",
1024                             .atomId = PixelAtoms::Atom::kZramBdStat,
1025                             .values = std::move(values)};
1026         const ndk::ScopedAStatus ret = stats_client->reportVendorAtom(event);
1027         if (!ret.isOk())
1028             ALOGE("Zram Unable to report ZramBdStat to Stats service");
1029     }
1030 }
1031 
logZramStats(const std::shared_ptr<IStats> & stats_client)1032 void SysfsCollector::logZramStats(const std::shared_ptr<IStats> &stats_client) {
1033     reportZramMmStat(stats_client);
1034     reportZramBdStat(stats_client);
1035 }
1036 
logBootStats(const std::shared_ptr<IStats> & stats_client)1037 void SysfsCollector::logBootStats(const std::shared_ptr<IStats> &stats_client) {
1038     int mounted_time_sec = 0;
1039 
1040     if (kF2fsStatsPath == nullptr) {
1041         ALOGE("F2fs stats path not specified");
1042         return;
1043     }
1044 
1045     std::string userdataBlock = getUserDataBlock();
1046 
1047     if (!ReadFileToInt(kF2fsStatsPath + (userdataBlock + "/mounted_time_sec"), &mounted_time_sec)) {
1048         ALOGV("Unable to read mounted_time_sec");
1049         return;
1050     }
1051 
1052     int fsck_time_ms = android::base::GetIntProperty("ro.boottime.init.fsck.data", 0);
1053     int checkpoint_time_ms = android::base::GetIntProperty("ro.boottime.init.mount.data", 0);
1054 
1055     if (fsck_time_ms == 0 && checkpoint_time_ms == 0) {
1056         ALOGV("Not yet initialized");
1057         return;
1058     }
1059 
1060     // Load values array
1061     std::vector<VendorAtomValue> values(3);
1062     VendorAtomValue tmp;
1063     tmp.set<VendorAtomValue::intValue>(mounted_time_sec);
1064     values[BootStatsInfo::kMountedTimeSecFieldNumber - kVendorAtomOffset] = tmp;
1065     tmp.set<VendorAtomValue::intValue>(fsck_time_ms / 1000);
1066     values[BootStatsInfo::kFsckTimeSecFieldNumber - kVendorAtomOffset] = tmp;
1067     tmp.set<VendorAtomValue::intValue>(checkpoint_time_ms / 1000);
1068     values[BootStatsInfo::kCheckpointTimeSecFieldNumber - kVendorAtomOffset] = tmp;
1069 
1070     // Send vendor atom to IStats HAL
1071     VendorAtom event = {.reverseDomainName = "",
1072                         .atomId = PixelAtoms::Atom::kBootStats,
1073                         .values = std::move(values)};
1074     const ndk::ScopedAStatus ret = stats_client->reportVendorAtom(event);
1075     if (!ret.isOk()) {
1076         ALOGE("Unable to report Boot stats to Stats service");
1077     } else {
1078         log_once_reported = true;
1079     }
1080 }
1081 
1082 /**
1083  * Report the AMS & CCA rate.
1084  */
logVendorAudioHardwareStats(const std::shared_ptr<IStats> & stats_client)1085 void SysfsCollector::logVendorAudioHardwareStats(const std::shared_ptr<IStats> &stats_client) {
1086     std::string file_contents;
1087     uint32_t milli_ams_rate, c1, c2, c3, c4;
1088     uint32_t total_call_voice = 0, total_call_voip = 0;
1089     bool isAmsReady = false, isCCAReady = false;
1090 
1091     if (kAmsRatePath == nullptr) {
1092         ALOGD("Audio AMS Rate path not specified");
1093     } else {
1094         if (!ReadFileToString(kAmsRatePath, &file_contents)) {
1095             ALOGD("Unable to read ams_rate path %s", kAmsRatePath);
1096         } else {
1097             if (sscanf(file_contents.c_str(), "%u", &milli_ams_rate) != 1) {
1098                 ALOGD("Unable to parse ams_rate %s", file_contents.c_str());
1099             } else {
1100                 isAmsReady = true;
1101                 ALOGD("milli_ams_rate = %u", milli_ams_rate);
1102             }
1103         }
1104     }
1105 
1106     if (kCCARatePath == nullptr) {
1107         ALOGD("Audio CCA Rate path not specified");
1108     } else {
1109         if (!ReadFileToString(kCCARatePath, &file_contents)) {
1110             ALOGD("Unable to read cca_rate path %s", kCCARatePath);
1111         } else {
1112             if (sscanf(file_contents.c_str(), "%u %u %u %u", &c1, &c2, &c3, &c4) != 4) {
1113                 ALOGD("Unable to parse cca rates %s", file_contents.c_str());
1114             } else {
1115                 isCCAReady = true;
1116             }
1117         }
1118     }
1119 
1120     if (kTotalCallCountPath == nullptr) {
1121         ALOGD("Total call count path not specified");
1122     } else {
1123         if (!ReadFileToString(kTotalCallCountPath, &file_contents)) {
1124             ALOGD("Unable to read total call path %s", kTotalCallCountPath);
1125         } else {
1126             if (sscanf(file_contents.c_str(), "%u %u", &total_call_voice, &total_call_voip) != 2) {
1127                 ALOGD("Unable to parse total call %s", file_contents.c_str());
1128             }
1129         }
1130     }
1131 
1132     if (!(isAmsReady || isCCAReady)) {
1133         ALOGD("no ams or cca data to report");
1134         return;
1135     }
1136 
1137     // Sending ams_rate, total_call, c1 and c2
1138     {
1139         std::vector<VendorAtomValue> values(7);
1140         VendorAtomValue tmp;
1141 
1142         if (isAmsReady) {
1143             tmp.set<VendorAtomValue::intValue>(milli_ams_rate);
1144             values[VendorAudioHardwareStatsReported::kMilliRateOfAmsPerDayFieldNumber -
1145                    kVendorAtomOffset] = tmp;
1146         }
1147 
1148         tmp.set<VendorAtomValue::intValue>(1);
1149         values[VendorAudioHardwareStatsReported::kSourceFieldNumber - kVendorAtomOffset] = tmp;
1150 
1151         if (isCCAReady) {
1152             tmp.set<VendorAtomValue::intValue>(c1);
1153             values[VendorAudioHardwareStatsReported::kCcaActiveCountPerDayFieldNumber -
1154                    kVendorAtomOffset] = tmp;
1155 
1156             tmp.set<VendorAtomValue::intValue>(c2);
1157             values[VendorAudioHardwareStatsReported::kCcaEnableCountPerDayFieldNumber -
1158                    kVendorAtomOffset] = tmp;
1159         }
1160 
1161         tmp.set<VendorAtomValue::intValue>(total_call_voice);
1162         values[VendorAudioHardwareStatsReported::kTotalCallCountPerDayFieldNumber -
1163                kVendorAtomOffset] = tmp;
1164 
1165         // Send vendor atom to IStats HAL
1166         VendorAtom event = {.reverseDomainName = "",
1167                             .atomId = PixelAtoms::Atom::kVendorAudioHardwareStatsReported,
1168                             .values = std::move(values)};
1169         const ndk::ScopedAStatus ret = stats_client->reportVendorAtom(event);
1170         if (!ret.isOk())
1171             ALOGE("Unable to report VendorAudioHardwareStatsReported to Stats service");
1172     }
1173 
1174     // Sending total_call, c3 and c4
1175     {
1176         std::vector<VendorAtomValue> values(7);
1177         VendorAtomValue tmp;
1178 
1179         tmp.set<VendorAtomValue::intValue>(0);
1180         values[VendorAudioHardwareStatsReported::kSourceFieldNumber - kVendorAtomOffset] = tmp;
1181 
1182         if (isCCAReady) {
1183             tmp.set<VendorAtomValue::intValue>(c3);
1184             values[VendorAudioHardwareStatsReported::kCcaActiveCountPerDayFieldNumber -
1185                    kVendorAtomOffset] = tmp;
1186 
1187             tmp.set<VendorAtomValue::intValue>(c4);
1188             values[VendorAudioHardwareStatsReported::kCcaEnableCountPerDayFieldNumber -
1189                    kVendorAtomOffset] = tmp;
1190         }
1191 
1192         tmp.set<VendorAtomValue::intValue>(total_call_voip);
1193         values[VendorAudioHardwareStatsReported::kTotalCallCountPerDayFieldNumber -
1194                kVendorAtomOffset] = tmp;
1195 
1196         // Send vendor atom to IStats HAL
1197         VendorAtom event = {.reverseDomainName = "",
1198                             .atomId = PixelAtoms::Atom::kVendorAudioHardwareStatsReported,
1199                             .values = std::move(values)};
1200         const ndk::ScopedAStatus ret = stats_client->reportVendorAtom(event);
1201         if (!ret.isOk())
1202             ALOGE("Unable to report VendorAudioHardwareStatsReported to Stats service");
1203     }
1204 }
1205 
1206 /**
1207  * Report PDM States which indicates microphone background noise level.
1208  * This function will report at most 4 atoms showing different background noise type.
1209  */
logVendorAudioPdmStatsReported(const std::shared_ptr<IStats> & stats_client)1210 void SysfsCollector::logVendorAudioPdmStatsReported(const std::shared_ptr<IStats> &stats_client) {
1211     std::string file_contents;
1212     std::vector<int> pdm_states;
1213 
1214     if (kPDMStatePath == nullptr) {
1215         ALOGD("Audio PDM State path not specified");
1216     } else {
1217         if (!ReadFileToString(kPDMStatePath, &file_contents)) {
1218             ALOGD("Unable to read PDM State path %s", kPDMStatePath);
1219         } else {
1220             std::stringstream file_content_stream(file_contents);
1221             while (file_content_stream.good()) {
1222                 std::string substr;
1223                 int state;
1224                 getline(file_content_stream, substr, ',');
1225                 if (sscanf(substr.c_str(), "%d", &state) != 1) {
1226                     ALOGD("Unable to parse PDM State %s", file_contents.c_str());
1227                 } else {
1228                     pdm_states.push_back(state);
1229                     ALOGD("Parsed PDM State: %d", state);
1230                 }
1231             }
1232         }
1233     }
1234     if (pdm_states.empty()) {
1235         ALOGD("Empty PDM State parsed.");
1236         return;
1237     }
1238 
1239     if (pdm_states.size() > 4) {
1240         ALOGD("Too many values parsed.");
1241         return;
1242     }
1243 
1244     for (int index = 0; index < pdm_states.size(); index++) {
1245         std::vector<VendorAtomValue> values(2);
1246         VendorAtomValue tmp;
1247 
1248         if (pdm_states[index] == 0) {
1249             continue;
1250         }
1251 
1252         tmp.set<VendorAtomValue::intValue>(index);
1253         values[VendorAudioPdmStatsReported::kPdmIndexFieldNumber - kVendorAtomOffset] = tmp;
1254 
1255         tmp.set<VendorAtomValue::intValue>(pdm_states[index]);
1256         values[VendorAudioPdmStatsReported::kStateFieldNumber - kVendorAtomOffset] = tmp;
1257 
1258         // Send vendor atom to IStats HAL
1259         VendorAtom event = {.reverseDomainName = "",
1260                             .atomId = PixelAtoms::Atom::kVendorAudioPdmStatsReported,
1261                             .values = std::move(values)};
1262 
1263         const ndk::ScopedAStatus ret = stats_client->reportVendorAtom(event);
1264         if (!ret.isOk())
1265             ALOGE("Unable to report VendorAudioPdmStatsReported at index %d", index);
1266     }
1267 }
1268 
1269 /**
1270  * Report Third party audio effects stats.
1271  * This function will report at most 5 atoms showing different instance stats.
1272  */
logWavesStats(const std::shared_ptr<IStats> & stats_client)1273 void SysfsCollector::logWavesStats(const std::shared_ptr<IStats> &stats_client) {
1274     std::string file_contents;
1275     std::vector<std::vector<int>> volume_duration_per_instance;
1276 
1277     constexpr int num_instances = 5;
1278     constexpr int num_volume = 10;
1279 
1280     if (kWavesPath == nullptr) {
1281         ALOGD("Audio Waves stats path not specified");
1282         return;
1283     }
1284 
1285     if (!ReadFileToString(kWavesPath, &file_contents)) {
1286         ALOGD("Unable to read Wave stats path %s", kWavesPath);
1287     } else {
1288         std::stringstream file_content_stream(file_contents);
1289         int duration;
1290         std::vector<int> volume_duration;
1291         while (file_content_stream.good() && file_content_stream >> duration) {
1292             volume_duration.push_back(duration);
1293             if (volume_duration.size() >= num_volume) {
1294                 volume_duration_per_instance.push_back(volume_duration);
1295                 volume_duration.clear();
1296             }
1297         }
1298     }
1299 
1300     if (volume_duration_per_instance.size() != num_instances) {
1301         ALOGE("Number of instances %zu doesn't match the correct number %d",
1302               volume_duration_per_instance.size(), num_instances);
1303         return;
1304     }
1305     for (int i = 0; i < volume_duration_per_instance.size(); i++) {
1306         if (volume_duration_per_instance[i].size() != num_volume) {
1307             ALOGE("Number of volume %zu doesn't match the correct number %d",
1308                   volume_duration_per_instance[i].size(), num_volume);
1309             return;
1310         }
1311     }
1312 
1313     std::vector<int> volume_range_field_numbers = {
1314             VendorAudioThirdPartyEffectStatsReported::kVolumeRange0ActiveMsPerDayFieldNumber,
1315             VendorAudioThirdPartyEffectStatsReported::kVolumeRange1ActiveMsPerDayFieldNumber,
1316             VendorAudioThirdPartyEffectStatsReported::kVolumeRange2ActiveMsPerDayFieldNumber,
1317             VendorAudioThirdPartyEffectStatsReported::kVolumeRange3ActiveMsPerDayFieldNumber,
1318             VendorAudioThirdPartyEffectStatsReported::kVolumeRange4ActiveMsPerDayFieldNumber,
1319             VendorAudioThirdPartyEffectStatsReported::kVolumeRange5ActiveMsPerDayFieldNumber,
1320             VendorAudioThirdPartyEffectStatsReported::kVolumeRange6ActiveMsPerDayFieldNumber,
1321             VendorAudioThirdPartyEffectStatsReported::kVolumeRange7ActiveMsPerDayFieldNumber,
1322             VendorAudioThirdPartyEffectStatsReported::kVolumeRange8ActiveMsPerDayFieldNumber,
1323             VendorAudioThirdPartyEffectStatsReported::kVolumeRange9ActiveMsPerDayFieldNumber};
1324 
1325     for (int index = 0; index < volume_duration_per_instance.size(); index++) {
1326         std::vector<VendorAtomValue> values(11);
1327         VendorAtomValue tmp;
1328 
1329         bool has_value = false;
1330         for (int volume_index = 0; volume_index < num_volume; volume_index++) {
1331             if (volume_duration_per_instance[index][volume_index] > 0) {
1332                 has_value = true;
1333             }
1334         }
1335         if (!has_value) {
1336             continue;
1337         }
1338 
1339         tmp.set<VendorAtomValue::intValue>(index);
1340         values[VendorAudioThirdPartyEffectStatsReported::kInstanceFieldNumber - kVendorAtomOffset] =
1341                 tmp;
1342 
1343         for (int volume_index = 0; volume_index < num_volume; volume_index++) {
1344             tmp.set<VendorAtomValue::intValue>(volume_duration_per_instance[index][volume_index]);
1345             values[volume_range_field_numbers[volume_index] - kVendorAtomOffset] = tmp;
1346         }
1347         // Send vendor atom to IStats HAL
1348         VendorAtom event = {.reverseDomainName = "",
1349                             .atomId = PixelAtoms::Atom::kVendorAudioThirdPartyEffectStatsReported,
1350                             .values = std::move(values)};
1351 
1352         const ndk::ScopedAStatus ret = stats_client->reportVendorAtom(event);
1353         if (!ret.isOk())
1354             ALOGE("Unable to report VendorAudioThirdPartyEffectStatsReported at index %d", index);
1355     }
1356 }
1357 
1358 /**
1359  * Report Audio Adapted Information stats such as thermal throttling.
1360  * This function will report at most 6 atoms showing different instance stats.
1361  */
logAdaptedInfoStats(const std::shared_ptr<IStats> & stats_client)1362 void SysfsCollector::logAdaptedInfoStats(const std::shared_ptr<IStats> &stats_client) {
1363     std::string file_contents;
1364     std::vector<int> count_per_feature;
1365     std::vector<int> duration_per_feature;
1366 
1367     constexpr int num_features = 6;
1368 
1369     if (kAdaptedInfoCountPath == nullptr) {
1370         ALOGD("Audio Adapted Info Count stats path not specified");
1371         return;
1372     }
1373 
1374     if (kAdaptedInfoDurationPath == nullptr) {
1375         ALOGD("Audio Adapted Info Duration stats path not specified");
1376         return;
1377     }
1378 
1379     if (!ReadFileToString(kAdaptedInfoCountPath, &file_contents)) {
1380         ALOGD("Unable to read Adapted Info Count stats path %s", kAdaptedInfoCountPath);
1381     } else {
1382         std::stringstream file_content_stream(file_contents);
1383         int count;
1384         while (file_content_stream.good() && file_content_stream >> count) {
1385             count_per_feature.push_back(count);
1386         }
1387     }
1388 
1389     if (count_per_feature.size() != num_features) {
1390         ALOGD("Audio Adapted Info Count doesn't match the number of features. %zu / %d",
1391               count_per_feature.size(), num_features);
1392         return;
1393     }
1394 
1395     if (!ReadFileToString(kAdaptedInfoDurationPath, &file_contents)) {
1396         ALOGD("Unable to read Adapted Info Duration stats path %s", kAdaptedInfoDurationPath);
1397     } else {
1398         std::stringstream file_content_stream(file_contents);
1399         int duration;
1400         while (file_content_stream.good() && file_content_stream >> duration) {
1401             duration_per_feature.push_back(duration);
1402         }
1403     }
1404 
1405     if (duration_per_feature.size() != num_features) {
1406         ALOGD("Audio Adapted Info Duration doesn't match the number of features. %zu / %d",
1407               duration_per_feature.size(), num_features);
1408         return;
1409     }
1410 
1411     for (int index = 0; index < num_features; index++) {
1412         std::vector<VendorAtomValue> values(3);
1413         VendorAtomValue tmp;
1414 
1415         if (count_per_feature[index] == 0 && duration_per_feature[index] == 0) {
1416             continue;
1417         }
1418 
1419         tmp.set<VendorAtomValue::intValue>(index);
1420         values[VendorAudioAdaptedInfoStatsReported::kFeatureIdFieldNumber - kVendorAtomOffset] =
1421                 tmp;
1422 
1423         tmp.set<VendorAtomValue::intValue>(count_per_feature[index]);
1424         values[VendorAudioAdaptedInfoStatsReported::kActiveCountsPerDayFieldNumber -
1425                kVendorAtomOffset] = tmp;
1426 
1427         tmp.set<VendorAtomValue::intValue>(duration_per_feature[index]);
1428         values[VendorAudioAdaptedInfoStatsReported::kActiveDurationMsPerDayFieldNumber -
1429                kVendorAtomOffset] = tmp;
1430 
1431         // Send vendor atom to IStats HAL
1432         VendorAtom event = {.reverseDomainName = "",
1433                             .atomId = PixelAtoms::Atom::kVendorAudioAdaptedInfoStatsReported,
1434                             .values = std::move(values)};
1435 
1436         const ndk::ScopedAStatus ret = stats_client->reportVendorAtom(event);
1437         if (!ret.isOk())
1438             ALOGE("Unable to report VendorAudioAdaptedInfoStatsReported at index %d", index);
1439     }
1440 }
1441 
1442 /**
1443  * Report audio PCM usage stats such as latency and active count.
1444  * This function will report at most 19 atoms showing different PCM type.
1445  */
logPcmUsageStats(const std::shared_ptr<IStats> & stats_client)1446 void SysfsCollector::logPcmUsageStats(const std::shared_ptr<IStats> &stats_client) {
1447     std::string file_contents;
1448     std::vector<int> count_per_type;
1449     std::vector<int> latency_per_type;
1450 
1451     constexpr int num_type = 19;
1452 
1453     if (kPcmLatencyPath == nullptr) {
1454         ALOGD("PCM Latency path not specified");
1455         return;
1456     }
1457 
1458     if (kPcmCountPath == nullptr) {
1459         ALOGD("PCM Count path not specified");
1460         return;
1461     }
1462 
1463     if (!ReadFileToString(kPcmCountPath, &file_contents)) {
1464         ALOGD("Unable to read PCM Count path %s", kPcmCountPath);
1465     } else {
1466         std::stringstream file_content_stream(file_contents);
1467         int count;
1468         while (file_content_stream.good() && file_content_stream >> count) {
1469             count_per_type.push_back(count);
1470         }
1471     }
1472 
1473     if (count_per_type.size() != num_type) {
1474         ALOGD("Audio PCM Count path doesn't match the number of features. %zu / %d",
1475               count_per_type.size(), num_type);
1476         return;
1477     }
1478 
1479     if (!ReadFileToString(kPcmLatencyPath, &file_contents)) {
1480         ALOGD("Unable to read PCM Latency path %s", kPcmLatencyPath);
1481     } else {
1482         std::stringstream file_content_stream(file_contents);
1483         int duration;
1484         while (file_content_stream.good() && file_content_stream >> duration) {
1485             latency_per_type.push_back(duration);
1486         }
1487     }
1488 
1489     if (latency_per_type.size() != num_type) {
1490         ALOGD("Audio PCM Latency path doesn't match the number of features. %zu / %d",
1491               latency_per_type.size(), num_type);
1492         return;
1493     }
1494 
1495     for (int index = 0; index < num_type; index++) {
1496         std::vector<VendorAtomValue> values(3);
1497         VendorAtomValue tmp;
1498 
1499         if (latency_per_type[index] == 0 && count_per_type[index] == 0) {
1500             continue;
1501         }
1502 
1503         tmp.set<VendorAtomValue::intValue>(index);
1504         values[VendorAudioPcmStatsReported::kTypeFieldNumber - kVendorAtomOffset] = tmp;
1505 
1506         tmp.set<VendorAtomValue::intValue>(latency_per_type[index]);
1507         values[VendorAudioPcmStatsReported::kPcmOpenLatencyAvgMsPerDayFieldNumber -
1508                kVendorAtomOffset] = tmp;
1509 
1510         tmp.set<VendorAtomValue::intValue>(count_per_type[index]);
1511         values[VendorAudioPcmStatsReported::kPcmActiveCountsPerDayFieldNumber - kVendorAtomOffset] =
1512                 tmp;
1513 
1514         // Send vendor atom to IStats HAL
1515         VendorAtom event = {.reverseDomainName = "",
1516                             .atomId = PixelAtoms::Atom::kVendorAudioPcmStatsReported,
1517                             .values = std::move(values)};
1518 
1519         const ndk::ScopedAStatus ret = stats_client->reportVendorAtom(event);
1520         if (!ret.isOk())
1521             ALOGE("Unable to report VendorAudioPcmStatsReported at index %d", index);
1522     }
1523 }
1524 
1525 /**
1526  * Logs the Resume Latency stats.
1527  */
logVendorResumeLatencyStats(const std::shared_ptr<IStats> & stats_client)1528 void SysfsCollector::logVendorResumeLatencyStats(const std::shared_ptr<IStats> &stats_client) {
1529     std::string uart_enabled = android::base::GetProperty("init.svc.console", "");
1530     if (uart_enabled == "running") {
1531         return;
1532     }
1533     std::string file_contents;
1534     if (!kResumeLatencyMetricsPath) {
1535         ALOGE("ResumeLatencyMetrics path not specified");
1536         return;
1537     }
1538     if (!ReadFileToString(kResumeLatencyMetricsPath, &file_contents)) {
1539         ALOGE("Unable to ResumeLatencyMetric %s - %s", kResumeLatencyMetricsPath, strerror(errno));
1540         return;
1541     }
1542 
1543     int offset = 0;
1544     int bytes_read;
1545     const char *data = file_contents.c_str();
1546     int data_len = file_contents.length();
1547 
1548     int curr_bucket_cnt;
1549     if (!sscanf(data + offset, "Resume Latency Bucket Count: %d\n%n", &curr_bucket_cnt,
1550                 &bytes_read))
1551         return;
1552     offset += bytes_read;
1553     if (offset >= data_len)
1554         return;
1555 
1556     int64_t max_latency;
1557     if (!sscanf(data + offset, "Max Resume Latency: %" PRId64 "\n%n", &max_latency, &bytes_read))
1558         return;
1559     offset += bytes_read;
1560     if (offset >= data_len)
1561         return;
1562 
1563     uint64_t sum_latency;
1564     if (!sscanf(data + offset, "Sum Resume Latency: %" PRIu64 "\n%n", &sum_latency, &bytes_read))
1565         return;
1566     offset += bytes_read;
1567     if (offset >= data_len)
1568         return;
1569 
1570     if (curr_bucket_cnt > kMaxResumeLatencyBuckets)
1571         return;
1572     if (curr_bucket_cnt != prev_data.bucket_cnt) {
1573         prev_data.resume_latency_buckets.clear();
1574     }
1575 
1576     int64_t total_latency_cnt = 0;
1577     int64_t count;
1578     int index = 2;
1579     std::vector<VendorAtomValue> values(curr_bucket_cnt + 2);
1580     VendorAtomValue tmp;
1581     // Iterate over resume latency buckets to get latency count within some latency thresholds
1582     while (sscanf(data + offset, "%*ld - %*ldms ====> %" PRId64 "\n%n", &count, &bytes_read) == 1 ||
1583            sscanf(data + offset, "%*ld - infms ====> %" PRId64 "\n%n", &count, &bytes_read) == 1) {
1584         offset += bytes_read;
1585         if (offset >= data_len && (index + 1 < curr_bucket_cnt + 2))
1586             return;
1587         if (curr_bucket_cnt == prev_data.bucket_cnt) {
1588             tmp.set<VendorAtomValue::longValue>(count -
1589                                                 prev_data.resume_latency_buckets[index - 2]);
1590             prev_data.resume_latency_buckets[index - 2] = count;
1591         } else {
1592             tmp.set<VendorAtomValue::longValue>(count);
1593             prev_data.resume_latency_buckets.push_back(count);
1594         }
1595         if (index >= curr_bucket_cnt + 2)
1596             return;
1597         values[index] = tmp;
1598         index += 1;
1599         total_latency_cnt += count;
1600     }
1601     tmp.set<VendorAtomValue::longValue>(max_latency);
1602     values[0] = tmp;
1603     if ((sum_latency - prev_data.resume_latency_sum_ms < 0) ||
1604         (total_latency_cnt - prev_data.resume_count <= 0)) {
1605         tmp.set<VendorAtomValue::longValue>(-1);
1606         ALOGI("average resume latency get overflow");
1607     } else {
1608         tmp.set<VendorAtomValue::longValue>(
1609                 (int64_t)(sum_latency - prev_data.resume_latency_sum_ms) /
1610                 (total_latency_cnt - prev_data.resume_count));
1611     }
1612     values[1] = tmp;
1613 
1614     prev_data.resume_latency_sum_ms = sum_latency;
1615     prev_data.resume_count = total_latency_cnt;
1616     prev_data.bucket_cnt = curr_bucket_cnt;
1617     // Send vendor atom to IStats HAL
1618     VendorAtom event = {.reverseDomainName = "",
1619                         .atomId = PixelAtoms::Atom::kVendorResumeLatencyStats,
1620                         .values = std::move(values)};
1621     const ndk::ScopedAStatus ret = stats_client->reportVendorAtom(event);
1622     if (!ret.isOk())
1623         ALOGE("Unable to report VendorResumeLatencyStats to Stats service");
1624 }
1625 
1626 /**
1627  * Read and store top 5 irq stats.
1628  */
process_irqatom_values(std::string file_contents,int * offset,std::vector<VendorAtomValue> * values)1629 void process_irqatom_values(std::string file_contents, int *offset,
1630                             std::vector<VendorAtomValue> *values) {
1631     const char *data = file_contents.c_str();
1632     int bytes_read;
1633     int64_t irq_data;
1634     int irq_num;
1635 
1636     std::vector<std::pair<int, int64_t>> irq_pair;
1637 
1638     while (sscanf(data + *offset, "%d %" PRId64 "\n%n", &irq_num, &irq_data, &bytes_read) == 2) {
1639         irq_pair.push_back(std::make_pair(irq_num, irq_data));
1640         *offset += bytes_read;
1641     }
1642     VendorAtomValue tmp;
1643     int irq_stats_size = irq_pair.size();
1644     for (int i = 0; i < 5; i++) {
1645         if (irq_stats_size < 5 && i >= irq_stats_size) {
1646             tmp.set<VendorAtomValue::longValue>(-1);
1647             values->push_back(tmp);
1648             tmp.set<VendorAtomValue::longValue>(0);
1649             values->push_back(tmp);
1650         } else {
1651             tmp.set<VendorAtomValue::longValue>(irq_pair[i].first);
1652             values->push_back(tmp);
1653             tmp.set<VendorAtomValue::longValue>(irq_pair[i].second);
1654             values->push_back(tmp);
1655         }
1656     }
1657 }
1658 
1659 /**
1660  * Logs the Long irq stats.
1661  */
logVendorLongIRQStatsReported(const std::shared_ptr<IStats> & stats_client)1662 void SysfsCollector::logVendorLongIRQStatsReported(const std::shared_ptr<IStats> &stats_client) {
1663     std::string uart_enabled = android::base::GetProperty("init.svc.console", "");
1664     if (uart_enabled == "running") {
1665         return;
1666     }
1667     std::string irq_file_contents, storm_file_contents;
1668     if (kLongIRQMetricsPath == nullptr || strlen(kLongIRQMetricsPath) == 0) {
1669         ALOGV("LongIRQ path not specified");
1670         return;
1671     }
1672     if (!ReadFileToString(kLongIRQMetricsPath, &irq_file_contents)) {
1673         ALOGE("Unable to read LongIRQ %s - %s", kLongIRQMetricsPath, strerror(errno));
1674         return;
1675     }
1676     if (kStormIRQMetricsPath == nullptr || strlen(kStormIRQMetricsPath) == 0) {
1677         ALOGV("StormIRQ path not specified");
1678         return;
1679     }
1680     if (!ReadFileToString(kStormIRQMetricsPath, &storm_file_contents)) {
1681         ALOGE("Unable to read StormIRQ %s - %s", kStormIRQMetricsPath, strerror(errno));
1682         return;
1683     }
1684     if (kIRQStatsResetPath == nullptr || strlen(kIRQStatsResetPath) == 0) {
1685         ALOGV("IRQStatsReset path not specified");
1686         return;
1687     }
1688     int offset = 0;
1689     int bytes_read;
1690     const char *data = irq_file_contents.c_str();
1691 
1692     // Get, process softirq stats
1693     int64_t irq_count;
1694     if (sscanf(data + offset, "long SOFTIRQ count: %" PRId64 "\n%n", &irq_count, &bytes_read) != 1)
1695         return;
1696     offset += bytes_read;
1697     std::vector<VendorAtomValue> values;
1698     VendorAtomValue tmp;
1699     tmp.set<VendorAtomValue::longValue>(irq_count);
1700     values.push_back(tmp);
1701 
1702     if (sscanf(data + offset, "long SOFTIRQ detail (num, latency):\n%n", &bytes_read) != 0)
1703         return;
1704     offset += bytes_read;
1705     process_irqatom_values(data, &offset, &values);
1706 
1707     // Get, process irq stats
1708     if (sscanf(data + offset, "long IRQ count: %" PRId64 "\n%n", &irq_count, &bytes_read) != 1)
1709         return;
1710     offset += bytes_read;
1711     tmp.set<VendorAtomValue::longValue>(irq_count);
1712     values.push_back(tmp);
1713 
1714     if (sscanf(data + offset, "long IRQ detail (num, latency):\n%n", &bytes_read) != 0)
1715         return;
1716     offset += bytes_read;
1717     process_irqatom_values(data, &offset, &values);
1718 
1719     // Get, process storm irq stats
1720     offset = 0;
1721     data = storm_file_contents.c_str();
1722     if (sscanf(data + offset, "storm IRQ detail (num, storm_count):\n%n", &bytes_read) != 0)
1723         return;
1724     offset += bytes_read;
1725     process_irqatom_values(data, &offset, &values);
1726 
1727     // Send vendor atom to IStats HAL
1728     VendorAtom event = {.reverseDomainName = "",
1729                         .atomId = PixelAtoms::Atom::kVendorLongIrqStatsReported,
1730                         .values = std::move(values)};
1731     const ndk::ScopedAStatus ret = stats_client->reportVendorAtom(event);
1732     if (!ret.isOk())
1733         ALOGE("Unable to report kVendorLongIRQStatsReported to Stats service");
1734 
1735     // Reset irq stats
1736     if (!WriteStringToFile(std::to_string(1), kIRQStatsResetPath)) {
1737         ALOGE("Failed to write to stats_reset");
1738         return;
1739     }
1740 }
1741 
logPartitionUsedSpace(const std::shared_ptr<IStats> & stats_client)1742 void SysfsCollector::logPartitionUsedSpace(const std::shared_ptr<IStats> &stats_client) {
1743     struct statfs fs_info;
1744     char path[] = "/mnt/vendor/persist";
1745 
1746     if (statfs(path, &fs_info) == -1) {
1747         ALOGE("statfs: %s", strerror(errno));
1748         return;
1749     }
1750 
1751     // Load values array
1752     std::vector<VendorAtomValue> values(3);
1753     values[PartitionsUsedSpaceReported::kDirectoryFieldNumber - kVendorAtomOffset] =
1754                     VendorAtomValue::make<VendorAtomValue::intValue>
1755                         (PixelAtoms::PartitionsUsedSpaceReported::PERSIST);
1756     values[PartitionsUsedSpaceReported::kFreeBytesFieldNumber - kVendorAtomOffset] =
1757             VendorAtomValue::make<VendorAtomValue::longValue>(fs_info.f_bsize * fs_info.f_bfree);
1758     values[PartitionsUsedSpaceReported::kTotalBytesFieldNumber - kVendorAtomOffset] =
1759             VendorAtomValue::make<VendorAtomValue::longValue>(fs_info.f_bsize * fs_info.f_blocks);
1760     // Send vendor atom to IStats HAL
1761     VendorAtom event = {.reverseDomainName = "",
1762                         .atomId = PixelAtoms::Atom::kPartitionUsedSpaceReported,
1763                         .values = std::move(values)};
1764 
1765     const ndk::ScopedAStatus ret = stats_client->reportVendorAtom(event);
1766     if (!ret.isOk()) {
1767         ALOGE("Unable to report Partitions Used Space Reported to stats service");
1768     }
1769 }
1770 
logPcieLinkStats(const std::shared_ptr<IStats> & stats_client)1771 void SysfsCollector::logPcieLinkStats(const std::shared_ptr<IStats> &stats_client) {
1772     struct sysfs_map {
1773         const char *sysfs_path;
1774         bool is_counter;
1775         int modem_val;
1776         int wifi_val;
1777         int modem_msg_field_number;
1778         int wifi_msg_field_number;
1779     };
1780 
1781     int i;
1782     bool reportPcieLinkStats = false;
1783 
1784     /* Map sysfs data to PcieLinkStatsReported message elements */
1785     struct sysfs_map datamap[] = {
1786         {"link_down_irqs", true, 0, 0,
1787          PcieLinkStatsReported::kModemPcieLinkdownsFieldNumber,
1788          PcieLinkStatsReported::kWifiPcieLinkdownsFieldNumber},
1789 
1790         {"complete_timeout_irqs", true, 0, 0,
1791          PcieLinkStatsReported::kModemPcieCompletionTimeoutsFieldNumber,
1792          PcieLinkStatsReported::kWifiPcieCompletionTimeoutsFieldNumber},
1793 
1794         {"link_up_failures", true, 0, 0,
1795          PcieLinkStatsReported::kModemPcieLinkupFailuresFieldNumber,
1796          PcieLinkStatsReported::kWifiPcieLinkupFailuresFieldNumber},
1797 
1798         {"link_recovery_failures", true, 0, 0,
1799          PcieLinkStatsReported::kModemPcieLinkRecoveryFailuresFieldNumber,
1800          PcieLinkStatsReported::kWifiPcieLinkRecoveryFailuresFieldNumber},
1801 
1802         {"pll_lock_average", false, 0, 0,
1803          PcieLinkStatsReported::kModemPciePllLockAvgFieldNumber,
1804          PcieLinkStatsReported::kWifiPciePllLockAvgFieldNumber},
1805 
1806         {"link_up_average", false, 0, 0,
1807          PcieLinkStatsReported::kModemPcieLinkUpAvgFieldNumber,
1808          PcieLinkStatsReported::kWifiPcieLinkUpAvgFieldNumber },
1809     };
1810 
1811 
1812     if (kModemPcieLinkStatsPath == nullptr) {
1813         ALOGD("Modem PCIe stats path not specified");
1814     } else {
1815         for (i=0; i < ARRAY_SIZE(datamap); i++) {
1816             std::string modempath =
1817                     std::string(kModemPcieLinkStatsPath) + "/" + datamap[i].sysfs_path;
1818 
1819             if (ReadFileToInt(modempath, &(datamap[i].modem_val))) {
1820                 reportPcieLinkStats = true;
1821                 ALOGD("Modem %s = %d", datamap[i].sysfs_path,
1822                       datamap[i].modem_val);
1823                 if (datamap[i].is_counter) {
1824                     std::string value = std::to_string(datamap[i].modem_val);
1825                     /* Writing the value back clears the counter */
1826                     if (!WriteStringToFile(value, modempath)) {
1827                         ALOGE("Unable to clear modem PCIe statistics file: %s - %s",
1828                               modempath.c_str(), strerror(errno));
1829                     }
1830                 }
1831             }
1832         }
1833     }
1834 
1835     if (kWifiPcieLinkStatsPath == nullptr) {
1836         ALOGD("Wifi PCIe stats path not specified");
1837     } else {
1838         for (i=0; i < ARRAY_SIZE(datamap); i++) {
1839             std::string wifipath =
1840                     std::string(kWifiPcieLinkStatsPath) + "/" + datamap[i].sysfs_path;
1841 
1842             if (ReadFileToInt(wifipath, &(datamap[i].wifi_val))) {
1843                 reportPcieLinkStats = true;
1844                 ALOGD("Wifi %s = %d", datamap[i].sysfs_path,
1845                       datamap[i].wifi_val);
1846                 if (datamap[i].is_counter) {
1847                     std::string value = std::to_string(datamap[i].wifi_val);
1848                     /* Writing the value back clears the counter */
1849                     if (!WriteStringToFile(value, wifipath)) {
1850                         ALOGE("Unable to clear wifi PCIe statistics file: %s - %s",
1851                               wifipath.c_str(), strerror(errno));
1852                     }
1853                 }
1854             }
1855         }
1856     }
1857 
1858     if (!reportPcieLinkStats) {
1859         ALOGD("No PCIe link stats to report");
1860         return;
1861     }
1862 
1863     // Load values array
1864     std::vector<VendorAtomValue> values(2 * ARRAY_SIZE(datamap));
1865     VendorAtomValue tmp;
1866     for (i=0; i < ARRAY_SIZE(datamap); i++) {
1867         if (datamap[i].modem_val > 0) {
1868             tmp.set<VendorAtomValue::intValue>(datamap[i].modem_val);
1869             values[datamap[i].modem_msg_field_number - kVendorAtomOffset] = tmp;
1870         }
1871         if (datamap[i].wifi_val > 0) {
1872             tmp.set<VendorAtomValue::intValue>(datamap[i].wifi_val);
1873             values[datamap[i].wifi_msg_field_number - kVendorAtomOffset] = tmp;
1874         }
1875     }
1876 
1877     // Send vendor atom to IStats HAL
1878     VendorAtom event = {.reverseDomainName = "",
1879                         .atomId = PixelAtoms::Atom::kPcieLinkStats,
1880                         .values = std::move(values)};
1881 
1882     const ndk::ScopedAStatus ret = stats_client->reportVendorAtom(event);
1883     if (!ret.isOk()) {
1884         ALOGE("Unable to report PCIe link statistics to stats service");
1885     }
1886 }
1887 
1888 /**
1889  * Read the contents of kPowerMitigationDurationPath and report them.
1890  */
logMitigationDurationCounts(const std::shared_ptr<IStats> & stats_client)1891 void SysfsCollector::logMitigationDurationCounts(const std::shared_ptr<IStats> &stats_client) {
1892     if (kPowerMitigationDurationPath == nullptr || strlen(kPowerMitigationDurationPath) == 0) {
1893         ALOGE("Mitigation Duration path is invalid!");
1894         return;
1895     }
1896     mitigation_duration_reporter_.logMitigationDuration(stats_client, kPowerMitigationDurationPath);
1897 }
1898 
logPerDay()1899 void SysfsCollector::logPerDay() {
1900     const std::shared_ptr<IStats> stats_client = getStatsService();
1901     if (!stats_client) {
1902         ALOGE("Unable to get AIDL Stats service");
1903         return;
1904     }
1905     // Collect once per service init; can be multiple due to service reinit
1906     if (!log_once_reported) {
1907         logBootStats(stats_client);
1908     }
1909     logBatteryCapacity(stats_client);
1910     logBatteryChargeCycles(stats_client);
1911     logBatteryEEPROM(stats_client);
1912     logBatteryHealth(stats_client);
1913     logBlockStatsReported(stats_client);
1914     logCodec1Failed(stats_client);
1915     logCodecFailed(stats_client);
1916     logDisplayStats(stats_client);
1917     logF2fsStats(stats_client);
1918     logF2fsAtomicWriteInfo(stats_client);
1919     logF2fsCompressionInfo(stats_client);
1920     logF2fsGcSegmentInfo(stats_client);
1921     logF2fsSmartIdleMaintEnabled(stats_client);
1922     logSlowIO(stats_client);
1923     logSpeakerImpedance(stats_client);
1924     logSpeechDspStat(stats_client);
1925     logUFSLifetime(stats_client);
1926     logUFSErrorStats(stats_client);
1927     logSpeakerHealthStats(stats_client);
1928     mm_metrics_reporter_.logCmaStatus(stats_client);
1929     mm_metrics_reporter_.logPixelMmMetricsPerDay(stats_client);
1930     logVendorAudioHardwareStats(stats_client);
1931     logThermalStats(stats_client);
1932     logTempResidencyStats(stats_client);
1933     logVendorLongIRQStatsReported(stats_client);
1934     logVendorResumeLatencyStats(stats_client);
1935     logPartitionUsedSpace(stats_client);
1936     logPcieLinkStats(stats_client);
1937     logMitigationDurationCounts(stats_client);
1938     logVendorAudioPdmStatsReported(stats_client);
1939     logWavesStats(stats_client);
1940     logAdaptedInfoStats(stats_client);
1941     logPcmUsageStats(stats_client);
1942 }
1943 
aggregatePer5Min()1944 void SysfsCollector::aggregatePer5Min() {
1945     mm_metrics_reporter_.aggregatePixelMmMetricsPer5Min();
1946 }
1947 
logBrownout()1948 void SysfsCollector::logBrownout() {
1949     const std::shared_ptr<IStats> stats_client = getStatsService();
1950     if (!stats_client) {
1951         ALOGE("Unable to get AIDL Stats service");
1952         return;
1953     }
1954     if (kBrownoutLogPath != nullptr && strlen(kBrownoutLogPath) > 0)
1955         brownout_detected_reporter_.logBrownout(stats_client, kBrownoutLogPath,
1956                                                 kBrownoutReasonProp);
1957 }
1958 
logOnce()1959 void SysfsCollector::logOnce() {
1960     logBrownout();
1961 }
1962 
logPerHour()1963 void SysfsCollector::logPerHour() {
1964     const std::shared_ptr<IStats> stats_client = getStatsService();
1965     if (!stats_client) {
1966         ALOGE("Unable to get AIDL Stats service");
1967         return;
1968     }
1969     mm_metrics_reporter_.logPixelMmMetricsPerHour(stats_client);
1970     logZramStats(stats_client);
1971     if (kPowerMitigationStatsPath != nullptr && strlen(kPowerMitigationStatsPath) > 0)
1972         mitigation_stats_reporter_.logMitigationStatsPerHour(stats_client,
1973                                                              kPowerMitigationStatsPath);
1974 }
1975 
1976 /**
1977  * Loop forever collecting stats from sysfs nodes and reporting them via
1978  * IStats.
1979  */
collect(void)1980 void SysfsCollector::collect(void) {
1981     int timerfd = timerfd_create(CLOCK_BOOTTIME, 0);
1982     if (timerfd < 0) {
1983         ALOGE("Unable to create timerfd - %s", strerror(errno));
1984         return;
1985     }
1986 
1987     // Sleep for 30 seconds on launch to allow codec driver to load.
1988     sleep(30);
1989 
1990     // sample & aggregate for the first time.
1991     aggregatePer5Min();
1992 
1993     // Collect first set of stats on boot.
1994     logOnce();
1995     logPerHour();
1996     logPerDay();
1997 
1998     struct itimerspec period;
1999 
2000     // gcd (greatest common divisor) of all the following timings
2001     constexpr int kSecondsPerWake = 5 * 60;
2002 
2003     constexpr int kWakesPer5Min = 5 * 60 / kSecondsPerWake;
2004     constexpr int kWakesPerHour = 60 * 60 / kSecondsPerWake;
2005     constexpr int kWakesPerDay = 24 * 60 * 60 / kSecondsPerWake;
2006 
2007     int wake_5min = 0;
2008     int wake_hours = 0;
2009     int wake_days = 0;
2010 
2011     period.it_interval.tv_sec = kSecondsPerWake;
2012     period.it_interval.tv_nsec = 0;
2013     period.it_value.tv_sec = kSecondsPerWake;
2014     period.it_value.tv_nsec = 0;
2015 
2016     if (timerfd_settime(timerfd, 0, &period, NULL)) {
2017         ALOGE("Unable to set one hour timer - %s", strerror(errno));
2018         return;
2019     }
2020 
2021     while (1) {
2022         int readval;
2023         union {
2024             char buf[8];
2025             uint64_t count;
2026         } expire;
2027 
2028         do {
2029             errno = 0;
2030             readval = read(timerfd, expire.buf, sizeof(expire.buf));
2031         } while (readval < 0 && errno == EINTR);
2032         if (readval < 0) {
2033             ALOGE("Timerfd error - %s\n", strerror(errno));
2034             return;
2035         }
2036 
2037         wake_5min += expire.count;
2038         wake_hours += expire.count;
2039         wake_days += expire.count;
2040 
2041         if (wake_5min >= kWakesPer5Min) {
2042             wake_5min %= kWakesPer5Min;
2043             aggregatePer5Min();
2044         }
2045 
2046         if (wake_hours >= kWakesPerHour) {
2047             if (wake_hours >= 2 * kWakesPerHour)
2048                 ALOGW("Hourly wake: sleep too much: expire.count=%" PRId64, expire.count);
2049             wake_hours %= kWakesPerHour;
2050             logPerHour();
2051         }
2052 
2053         if (wake_days >= kWakesPerDay) {
2054             if (wake_hours >= 2 * kWakesPerDay)
2055                 ALOGW("Daily wake: sleep too much: expire.count=%" PRId64, expire.count);
2056             wake_days %= kWakesPerDay;
2057             logPerDay();
2058         }
2059     }
2060 }
2061 
2062 }  // namespace pixel
2063 }  // namespace google
2064 }  // namespace hardware
2065 }  // namespace android
2066