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