1 /*
2 * Copyright 2023 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 <cstring>
18 #include <dirent.h>
19 #include <dump/pixel_dump.h>
20 #include <fstream>
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <sys/sysinfo.h>
24 #include <sys/wait.h>
25 #include <time.h>
26 #include <unistd.h>
27 #include <vector>
28
29 #include <android-base/file.h>
30 #include <android-base/strings.h>
31 #include "DumpstateUtil.h"
32
33
printTitle(const char * msg)34 void printTitle(const char *msg) {
35 printf("\n------ %s ------\n", msg);
36 }
37
getCommandOutput(const char * cmd,std::string * output)38 int getCommandOutput(const char *cmd, std::string *output) {
39 char buffer[1024];
40 FILE *pipe = popen(cmd, "r");
41 if (!pipe) {
42 return -1;
43 }
44
45 while (fgets(buffer, sizeof buffer, pipe) != NULL) {
46 *output += buffer;
47 }
48 pclose(pipe);
49
50 if (output->back() == '\n')
51 output->pop_back();
52
53 return 0;
54 }
55
isValidFile(const char * file)56 bool isValidFile(const char *file) {
57 FILE *fp = fopen(file, "r");
58 if (fp != NULL) {
59 fclose(fp);
60 return true;
61 }
62 return false;
63 }
64
isValidDir(const char * directory)65 bool isValidDir(const char *directory) {
66 DIR *dir = opendir(directory);
67 if (dir == NULL)
68 return false;
69
70 closedir(dir);
71 return true;
72 }
73
isUserBuild()74 bool isUserBuild() {
75 return ::android::os::dumpstate::PropertiesHelper::IsUserBuild();
76 }
77
getFilesInDir(const char * directory,std::vector<std::string> * files)78 int getFilesInDir(const char *directory, std::vector<std::string> *files) {
79 std::string content;
80 struct dirent *entry;
81
82 DIR *dir = opendir(directory);
83 if (dir == NULL)
84 return -1;
85
86 files->clear();
87 while ((entry = readdir(dir)) != NULL)
88 files->push_back(entry->d_name);
89 closedir(dir);
90
91 sort(files->begin(), files->end());
92 return 0;
93 }
94
dumpPowerStatsTimes()95 void dumpPowerStatsTimes() {
96 const char *title = "Power Stats Times";
97 char rBuff[128];
98 struct timespec rTs;
99 struct sysinfo info;
100 int ret;
101
102 printTitle(title);
103
104 sysinfo(&info);
105
106 const time_t boottime = time(NULL) - info.uptime;
107
108 ret = clock_gettime(CLOCK_REALTIME, &rTs);
109 if (ret)
110 return;
111
112 struct tm *nowTime = std::localtime(&rTs.tv_sec);
113
114 std::strftime(rBuff, sizeof(rBuff), "%m/%d/%Y %H:%M:%S", nowTime);
115 printf("Boot: %s", ctime(&boottime));
116 printf("Now: %s\n", rBuff);
117 }
118
readContentsOfDir(const char * title,const char * directory,const char * strMatch,bool useStrMatch=false,bool printDirectory=false)119 int readContentsOfDir(const char* title, const char* directory, const char* strMatch,
120 bool useStrMatch = false, bool printDirectory = false) {
121 std::vector<std::string> files;
122 std::string content;
123 std::string fileLocation;
124 int ret;
125
126 ret = getFilesInDir(directory, &files);
127 if (ret < 0)
128 return ret;
129
130 printTitle(title);
131 for (auto &file : files) {
132 if (useStrMatch && std::string::npos == std::string(file).find(strMatch)) {
133 continue;
134 }
135
136 fileLocation = std::string(directory) + std::string(file);
137 if (!android::base::ReadFileToString(fileLocation, &content)) {
138 continue;
139 }
140 if (printDirectory) {
141 printf("\n\n%s\n", fileLocation.c_str());
142 }
143 if (content.back() == '\n')
144 content.pop_back();
145 printf("%s\n", content.c_str());
146 }
147 return 0;
148 }
149
dumpAcpmStats()150 void dumpAcpmStats() {
151 const char* acpmDir = "/sys/devices/platform/acpm_stats/";
152 const char* statsSubStr = "_stats";
153 const char* acpmTitle = "ACPM stats";
154 readContentsOfDir(acpmTitle, acpmDir, statsSubStr, true, true);
155 }
156
dumpPowerSupplyStats()157 void dumpPowerSupplyStats() {
158 const char* dumpList[][2] = {
159 {"CPU PM stats", "/sys/devices/system/cpu/cpupm/cpupm/time_in_state"},
160 {"GENPD summary", "/d/pm_genpd/pm_genpd_summary"},
161 {"Power supply property battery", "/sys/class/power_supply/battery/uevent"},
162 {"Power supply property dc", "/sys/class/power_supply/dc/uevent"},
163 {"Power supply property gcpm", "/sys/class/power_supply/gcpm/uevent"},
164 {"Power supply property gcpm_pps", "/sys/class/power_supply/gcpm_pps/uevent"},
165 {"Power supply property main-charger", "/sys/class/power_supply/main-charger/uevent"},
166 {"Power supply property dc-mains", "/sys/class/power_supply/dc-mains/uevent"},
167 {"Power supply property tcpm", "/sys/class/power_supply/tcpm-source-psy-i2c-max77759tcpc/uevent"},
168 {"Power supply property usb", "/sys/class/power_supply/usb/uevent"},
169 {"Power supply property wireless", "/sys/class/power_supply/wireless/uevent"},
170 };
171
172 for (const auto &row : dumpList) {
173 dumpFileContent(row[0], row[1]);
174 }
175 }
176
dumpMaxFg()177 void dumpMaxFg() {
178 const char *maxfgLoc = "/sys/class/power_supply/maxfg";
179 const char *max77779fgDir = "/sys/class/power_supply/max77779fg";
180 const char *maxfgDualLoc = "/sys/class/power_supply/maxfg_base";
181 const char *maxfg [][2] = {
182 {"Power supply property maxfg", "/sys/class/power_supply/maxfg/uevent"},
183 {"maxfg registers", "/sys/class/power_supply/maxfg/registers_dump"},
184 {"m5_state", "/sys/class/power_supply/maxfg/m5_model_state"},
185 {"maxfg logbuffer", "/dev/logbuffer_maxfg"},
186 {"maxfg_monitor logbuffer", "/dev/logbuffer_maxfg_monitor"},
187 };
188
189 const char *max77779fgFiles [][2] = {
190 {"Power supply property max77779fg", "/sys/class/power_supply/max77779fg/uevent"},
191 {"max77779fg registers", "/sys/class/power_supply/max77779fg/registers_dump"},
192 {"model_state", "/sys/class/power_supply/max77779fg/model_state"},
193 {"max77779fg logbuffer", "/dev/logbuffer_max77779fg"},
194 {"max77779fg_monitor logbuffer", "/dev/logbuffer_max77779fg_monitor"},
195 };
196
197 const char *maxfgDual [][2] = {
198 {"Power supply property maxfg_base", "/sys/class/power_supply/maxfg_base/uevent"},
199 {"Power supply property maxfg_secondary", "/sys/class/power_supply/maxfg_secondary/uevent"},
200 {"maxfg_base registers", "/sys/class/power_supply/maxfg_base/registers_dump"},
201 {"maxfg_secondary registers", "/sys/class/power_supply/maxfg_secondary/registers_dump"},
202 {"model_state", "/sys/class/power_supply/maxfg_base/model_state"},
203 {"maxfg_base logbuffer", "/dev/logbuffer_maxfg_base"},
204 {"maxfg_secondary logbuffer", "/dev/logbuffer_maxfg_secondary"},
205 {"maxfg_base_monitor logbuffer", "/dev/logbuffer_maxfg_base_monitor"},
206 {"maxfg_secondary_monitor logbuffer", "/dev/logbuffer_maxfg_secondary_monitor"},
207 {"dual_batt logbuffer", "/dev/logbuffer_dual_batt"},
208 };
209
210 const char *maxfgHistoryName = "Maxim FG History";
211 const char *maxfgHistoryDir = "/dev/maxfg_history";
212
213 std::string content;
214
215
216 if (isValidDir(maxfgLoc)) {
217 for (const auto &row : maxfg) {
218 dumpFileContent(row[0], row[1]);
219 }
220 } else if (isValidDir(max77779fgDir)) {
221 for (const auto &row : max77779fgFiles) {
222 dumpFileContent(row[0], row[1]);
223 }
224 } else if (isValidDir(maxfgDualLoc)){
225 for (const auto &row : maxfgDual) {
226 dumpFileContent(row[0], row[1]);
227 }
228 if (isValidFile(maxfgHistoryDir)) {
229 dumpFileContent(maxfgHistoryName, maxfgHistoryDir);
230 }
231 }
232 }
233
dumpPowerSupplyDock()234 void dumpPowerSupplyDock() {
235 const char* powerSupplyPropertyDockTitle = "Power supply property dock";
236 const char* powerSupplyPropertyDockFile = "/sys/class/power_supply/dock/uevent";
237 if (isValidFile(powerSupplyPropertyDockFile)) {
238 dumpFileContent(powerSupplyPropertyDockTitle, powerSupplyPropertyDockFile);
239 }
240 }
241
dumpSecondCharge()242 void dumpSecondCharge() {
243 const char* powerSupplyPropertySecChgTitle = "Power supply property rt9471";
244 const char* powerSupplyPropertySecChgFile = "/sys/class/power_supply/rt9471/uevent";
245 const char *secChgTitle = "RT9470G";
246 const char *secChgFile = "/sys/devices/platform/10ca0000.hsi2c/i2c-10/10-005b/registers_dump";
247
248 if (isValidFile(powerSupplyPropertySecChgFile)) {
249 dumpFileContent(powerSupplyPropertySecChgTitle, powerSupplyPropertySecChgFile);
250 }
251
252 if (isValidFile(secChgFile)) {
253 dumpFileContent(secChgTitle, secChgFile);
254 }
255 }
256
dumpLogBufferTcpm()257 void dumpLogBufferTcpm() {
258 const char* logbufferTcpmTitle = "Logbuffer TCPM";
259 const char* logbufferTcpmFile = "/dev/logbuffer_tcpm";
260 const char* debugTcpmFile = "/sys/kernel/debug/tcpm";
261 const char* tcpmLogTitle = "TCPM logs";
262 const char* tcpmFile = "/sys/kernel/debug/tcpm";
263 const char* tcpmFileAlt = "/sys/kernel/debug/usb/tcpm";
264 int retCode;
265
266 dumpFileContent(logbufferTcpmTitle, logbufferTcpmFile);
267
268 retCode = readContentsOfDir(tcpmLogTitle, isValidFile(debugTcpmFile) ? tcpmFile : tcpmFileAlt,
269 NULL);
270 if (retCode < 0)
271 printTitle(tcpmLogTitle);
272 }
273
dumpTcpc()274 void dumpTcpc() {
275 const char* max77759TcpcHead = "TCPC Device Attributes";
276 const char* directory = "/sys/class/typec/port0/device";
277 // alphabetic order
278 const char* max77759Tcpc [] {
279 "auto_discharge",
280 "bc12_enabled",
281 "cc_toggle_enable",
282 "contaminant_detection",
283 "contaminant_detection_status",
284 "frs",
285 "irq_hpd_count",
286 "manual_disable_vbus",
287 "non_compliant_reasons",
288 "sbu_pullup",
289 "update_sdp_enum_timeout",
290 "usb_limit_accessory_current",
291 "usb_limit_accessory_enable",
292 "usb_limit_sink_current",
293 "usb_limit_sink_enable",
294 "usb_limit_source_enable",
295 };
296
297 std::string content;
298 std::string tcpcRegistersPath(std::string(directory) + "/registers");
299
300 dumpFileContent("TCPC Registers", tcpcRegistersPath.c_str());
301
302 printTitle(max77759TcpcHead);
303
304 for (auto& tcpcVal : max77759Tcpc) {
305 std::string filename = std::string(directory) + "/" + std::string(tcpcVal);
306 printf("%s: ", tcpcVal);
307 android::base::ReadFileToString(filename, &content);
308 if (!content.empty() && (content.back() == '\n' || content.back() == '\r'))
309 content.pop_back();
310 printf("%s\n", content.c_str());
311 }
312 printf("\n");
313 }
314
dumpPdEngine()315 void dumpPdEngine() {
316 const char* pdEngine [][2] {
317 {"TCPC logbuffer", "/dev/logbuffer_usbpd"},
318 {"pogo_transport logbuffer", "/dev/logbuffer_pogo_transport"},
319 {"PPS-google_cpm logbuffer", "/dev/logbuffer_cpm"},
320 {"PPS-pca9468 logbuffer", "/dev/logbuffer_pca9468"},
321 {"PPS-ln8411 logbuffer", "/dev/logbuffer_ln8411"},
322 {"PPS-dc_mains logbuffer", "/dev/logbuffer_dc_mains"}
323 };
324
325 for (const auto &row : pdEngine) {
326 dumpFileContent(row[0], row[1]);
327 }
328 }
329
dumpBatteryHealth()330 void dumpBatteryHealth() {
331 const char* batteryHealth [][2] {
332 {"Battery Health", "/sys/class/power_supply/battery/health_index_stats"},
333 {"Battery Health SoC Residency", "/sys/class/power_supply/battery/swelling_data"},
334 {"BMS logbuffer", "/dev/logbuffer_ssoc"},
335 {"TTF logbuffer", "/dev/logbuffer_ttf"},
336 {"TTF details", "/sys/class/power_supply/battery/ttf_details"},
337 {"TTF stats", "/sys/class/power_supply/battery/ttf_stats"},
338 {"aacr_state", "/sys/class/power_supply/battery/aacr_state"},
339 {"pairing_state", "/sys/class/power_supply/battery/pairing_state"},
340 {"fwupdate", "/dev/logbuffer_max77779_fwupdate"}
341 };
342
343 const char* maxqName = "maxq logbuffer";
344 const char* maxqDir = "/dev/logbuffer_maxq";
345 const char* tempDockDefendName = "TEMP/DOCK-DEFEND";
346 const char* tempDockDefendDir = "/dev/logbuffer_bd";
347
348 for (const auto &row : batteryHealth) {
349 dumpFileContent(row[0], row[1]);
350 }
351
352 if (isValidFile(maxqDir))
353 dumpFileContent(maxqName, maxqDir);
354
355 dumpFileContent(tempDockDefendName, tempDockDefendDir);
356 }
357
dumpBatteryDefend()358 void dumpBatteryDefend() {
359 const char* defendConfig [][3] {
360 {"TRICKLE-DEFEND Config",
361 "/sys/devices/platform/google,battery/power_supply/battery/", "bd_"},
362 {"DWELL-DEFEND Config", "/sys/devices/platform/google,charger/", "charge_s"},
363 {"DWELL-DEFEND Time", "/mnt/vendor/persist/battery/", "defender_"},
364 {"TEMP-DEFEND Config", "/sys/devices/platform/google,charger/", "bd_"},
365 };
366
367 std::vector<std::string> files;
368 struct dirent *entry;
369 std::string content;
370 std::string fileLocation;
371
372 for (auto &config : defendConfig) {
373 DIR *dir = opendir(config[1]);
374 if (dir == NULL)
375 continue;
376
377 printTitle(config[0]);
378 while ((entry = readdir(dir)) != NULL) {
379 if (std::string(entry->d_name).find(config[2]) != std::string::npos &&
380 strncmp(config[2], entry->d_name, strlen(config[2])) == 0) {
381 files.push_back(entry->d_name);
382 }
383 }
384 closedir(dir);
385
386 sort(files.begin(), files.end());
387
388 for (auto &file : files) {
389 fileLocation = std::string(config[1]) + std::string(file);
390 if (!android::base::ReadFileToString(fileLocation, &content) || content.empty()) {
391 content = "\n";
392 }
393
394 printf("%s: %s", file.c_str(), content.c_str());
395
396 if (content.back() != '\n')
397 printf("\n");
398 }
399
400 files.clear();
401 }
402 }
403
dumpBatteryCaretaker()404 void dumpBatteryCaretaker() {
405 const char* aacpConfig [][3] {
406 {"AACP Version",
407 "/sys/devices/platform/google,battery/power_supply/battery/", "aacp_"},
408 {"AACR Config",
409 "/sys/devices/platform/google,battery/power_supply/battery/", "aacr_"},
410 {"AAFV Config",
411 "/sys/devices/platform/google,battery/power_supply/battery/", "aafv_"},
412 {"AACT Config",
413 "/sys/devices/platform/google,battery/power_supply/battery/", "aact_"},
414 {"AACC",
415 "/sys/devices/platform/google,battery/power_supply/battery/", "aacc"},
416 };
417
418 std::vector<std::string> files;
419 struct dirent *entry;
420 std::string content;
421 std::string fileLocation;
422
423 for (auto &config : aacpConfig) {
424 DIR *dir = opendir(config[1]);
425 if (dir == NULL)
426 continue;
427
428 printTitle(config[0]);
429 while ((entry = readdir(dir)) != NULL) {
430 if (std::string(entry->d_name).find(config[2]) != std::string::npos &&
431 strncmp(config[2], entry->d_name, strlen(config[2])) == 0) {
432 files.push_back(entry->d_name);
433 }
434 }
435 closedir(dir);
436
437 sort(files.begin(), files.end());
438
439 for (auto &file : files) {
440 fileLocation = std::string(config[1]) + std::string(file);
441 if (!android::base::ReadFileToString(fileLocation, &content) || content.empty()) {
442 content = "\n";
443 }
444
445 printf("%s: %s", file.c_str(), content.c_str());
446
447 if (content.back() != '\n')
448 printf("\n");
449 }
450
451 files.clear();
452 }
453 }
454
printValuesOfDirectory(const char * directory,std::string debugfs,const char * strMatch)455 void printValuesOfDirectory(const char *directory, std::string debugfs, const char *strMatch) {
456 std::vector<std::string> files;
457 auto info = directory;
458 std::string content;
459 struct dirent *entry;
460 DIR *dir = opendir(debugfs.c_str());
461 if (dir == NULL)
462 return;
463
464 printTitle((debugfs + std::string(strMatch) + "/" + std::string(info)).c_str());
465 while ((entry = readdir(dir)) != NULL)
466 if (std::string(entry->d_name).find(strMatch) != std::string::npos)
467 files.push_back(entry->d_name);
468 closedir(dir);
469
470 sort(files.begin(), files.end());
471
472 for (auto &file : files) {
473 std::string fileDirectory = debugfs + file;
474 std::string fileLocation = fileDirectory + "/" + std::string(info);
475 if (!android::base::ReadFileToString(fileLocation, &content)) {
476 content = "\n";
477 }
478
479 printf("%s:\n%s", fileDirectory.c_str(), content.c_str());
480
481 if (content.back() != '\n')
482 printf("\n");
483 }
484 files.clear();
485 }
486
dumpChg()487 void dumpChg() {
488 const std::string pmic_bus = "/sys/devices/platform/108d0000.hsi2c/i2c-6/6-0066";
489 const char* chg_reg_dump_file = "/sys/class/power_supply/main-charger/device/registers_dump";
490 const std::string chg_name_file = "/sys/class/power_supply/main-charger/device/name";
491 const std::string pmic_name_file = pmic_bus + "/name";
492 const std::string pmic_reg_dump_file = pmic_bus + "/registers_dump";
493 const std::string reg_dump_str = " registers dump";
494 const char* chgConfig [][2] {
495 {"DC_registers dump", "/sys/class/power_supply/dc-mains/device/registers_dump"},
496 };
497 std::string chg_name;
498 std::string pmic_name;
499 std::string pmic_reg_dump;
500
501 printf("\n");
502
503 int ret = android::base::ReadFileToString(chg_name_file, &chg_name);
504 if (ret && !chg_name.empty()) {
505 chg_name.erase(chg_name.length() - 1); // remove new line
506 const std::string chg_reg_dump_title = chg_name + reg_dump_str;
507
508 /* CHG reg dump */
509 dumpFileContent(chg_reg_dump_title.c_str(), chg_reg_dump_file);
510 }
511
512 if (isValidDir(pmic_bus.c_str())) {
513 ret = android::base::ReadFileToString(pmic_name_file, &pmic_name);
514 pmic_reg_dump = pmic_reg_dump_file;
515 }
516
517 if (ret && !pmic_name.empty()) {
518 pmic_name.erase(pmic_name.length() - 1); // remove new line
519 const std::string pmic_reg_dump_title = pmic_name + reg_dump_str;
520
521 /* PMIC reg dump */
522 dumpFileContent(pmic_reg_dump_title.c_str(), pmic_reg_dump.c_str());
523 }
524
525 for (auto &config : chgConfig) {
526 dumpFileContent(config[0], config[1]);
527 }
528 }
529
dumpChgUserDebug()530 void dumpChgUserDebug() {
531 const std::string debugfs = "/d/";
532 const char *maxBaseFgDir = "/d/maxfg_base";
533 const char *maxBaseFgStrMatch = "maxfg_base";
534 const char *max77779FgDir = "/d/max77779fg";
535 const char *maxFg77779StrMatch = "max77779fg";
536 const char *chgTblName = "Charging table dump";
537 const char *chgTblDir = "/d/google_battery/chg_raw_profile";
538
539 const char *max77779FgInfo [] {
540 "fg_model",
541 "model_ok",
542 };
543
544 if (isUserBuild())
545 return;
546
547 dumpFileContent(chgTblName, chgTblDir);
548
549 if (isValidDir(max77779FgDir)) {
550 for (auto & directory : max77779FgInfo) {
551 printValuesOfDirectory(directory, debugfs, maxFg77779StrMatch);
552 }
553 } else if (isValidDir(maxBaseFgDir)) {
554 for (auto & directory : max77779FgInfo) {
555 printValuesOfDirectory(directory, debugfs, maxBaseFgStrMatch);
556 }
557 }
558 }
559
dumpScratchpad()560 void dumpScratchpad() {
561 const char *title = "max77779sp registers dump";
562 const char *file = "/sys/devices/platform/108d0000.hsi2c/i2c-6/6-0060/registers_dump";
563
564 if (isValidFile(file)) {
565 dumpFileContent(title, file);
566 }
567 }
568
dumpBatteryEeprom()569 void dumpBatteryEeprom() {
570 const char *title = "Battery EEPROM";
571 const char *files[] {
572 "/sys/devices/platform/10ca0000.hsi2c/i2c-10/10-0050/eeprom",
573 "/sys/devices/platform/10c90000.hsi2c/i2c-9/9-0050/eeprom",
574 };
575 std::string result;
576 std::string xxdCmd;
577
578 printTitle(title);
579 for (auto &file : files) {
580 if (!isValidFile(file))
581 continue;
582
583 xxdCmd = "xxd " + std::string(file);
584
585 int ret = getCommandOutput(xxdCmd.c_str(), &result);
586 if (ret < 0)
587 return;
588
589 printf("%s\n", result.c_str());
590 }
591 }
592
dumpChargerStats()593 void dumpChargerStats() {
594 const char *chgStatsTitle = "Charger Stats";
595 const char *chgStatsLocation = "/sys/class/power_supply/battery/charge_details";
596 const char *chargerStats [][3] {
597 {"Google Charger", "/sys/kernel/debug/google_charger/", "pps_"},
598 {"Google Battery", "/sys/kernel/debug/google_battery/", "ssoc_"},
599 };
600 std::vector<std::string> files;
601 std::string content;
602 struct dirent *entry;
603
604 dumpFileContent(chgStatsTitle, chgStatsLocation);
605
606 if (isUserBuild())
607 return;
608
609 for (auto &stat : chargerStats) {
610 DIR *dir = opendir(stat[1]);
611 if (dir == NULL)
612 return;
613
614 printTitle(stat[0]);
615 while ((entry = readdir(dir)) != NULL)
616 if (std::string(entry->d_name).find(stat[2]) != std::string::npos)
617 files.push_back(entry->d_name);
618 closedir(dir);
619
620 sort(files.begin(), files.end());
621
622 for (auto &file : files) {
623 std::string fileLocation = std::string(stat[1]) + file;
624 if (!android::base::ReadFileToString(fileLocation, &content)) {
625 content = "\n";
626 }
627
628 printf("%s: %s", file.c_str(), content.c_str());
629
630 if (content.back() != '\n')
631 printf("\n");
632 }
633 files.clear();
634 }
635 }
636
dumpWlcLogs()637 void dumpWlcLogs() {
638 const char *dumpWlcList [][2] {
639 {"WLC Logs", "/dev/logbuffer_wireless"},
640 {"WLC VER", "/sys/class/power_supply/wireless/device/version"},
641 {"WLC STATUS", "/sys/class/power_supply/wireless/device/status"},
642 {"WLC FW Version", "/sys/class/power_supply/wireless/device/fw_rev"},
643 {"RTX", "/dev/logbuffer_rtx"},
644 };
645
646 for (auto &row : dumpWlcList) {
647 if (!isValidFile(row[1]))
648 printTitle(row[0]);
649 dumpFileContent(row[0], row[1]);
650 }
651 }
652
dumpGvoteables()653 void dumpGvoteables() {
654 const char *directory = "/sys/kernel/debug/gvotables/";
655 const char *statusName = "/status";
656 const char *title = "gvotables";
657 std::string content;
658 std::vector<std::string> files;
659 int ret;
660
661 if (isUserBuild())
662 return;
663
664 ret = getFilesInDir(directory, &files);
665 if (ret < 0)
666 return;
667
668 printTitle(title);
669 for (auto &file : files) {
670 std::string fileLocation = std::string(directory) + file + std::string(statusName);
671 if (!android::base::ReadFileToString(fileLocation, &content)) {
672 continue;
673 }
674
675 printf("%s: %s", file.c_str(), content.c_str());
676
677 if (content.back() != '\n')
678 printf("\n");
679 }
680 files.clear();
681 }
682
dumpMitigation()683 void dumpMitigation() {
684 const char *mitigationList [][2] {
685 {"LastmealCSV" , "/data/vendor/mitigation/lastmeal.csv"},
686 {"Lastmeal" , "/data/vendor/mitigation/lastmeal.txt"},
687 {"Thismeal" , "/data/vendor/mitigation/thismeal.txt"},
688 };
689
690 /* parsing thismeal.bin */
691 int status;
692 int pid = fork();
693 if (pid < 0) {
694 printf("Fork failed for parsing thismeal.bin.\n");
695 exit(EXIT_FAILURE);
696 } else if (pid == 0) {
697 execl("/vendor/bin/hw/battery_mitigation", "battery_mitigation", "-d", nullptr);
698 exit(EXIT_SUCCESS);
699 }
700 waitpid(pid, &status, 0);
701
702 if (WIFSIGNALED(status)) {
703 printf("Failed to parse thismeal.bin.(killed by: %d)\n", WTERMSIG(status));
704 }
705
706 for (auto &row : mitigationList) {
707 if (!isValidFile(row[1]))
708 printTitle(row[0]);
709 dumpFileContent(row[0], row[1]);
710 }
711 }
712
dumpMitigationStats()713 void dumpMitigationStats() {
714 int ret;
715 const char *directory = "/sys/devices/virtual/pmic/mitigation/last_triggered_count/";
716 const char *capacityDirectory = "/sys/devices/virtual/pmic/mitigation/last_triggered_capacity/";
717 const char *timestampDirectory =
718 "/sys/devices/virtual/pmic/mitigation/last_triggered_timestamp/";
719 const char *voltageDirectory = "/sys/devices/virtual/pmic/mitigation/last_triggered_voltage/";
720 const char *capacitySuffix = "_cap";
721 const char *timeSuffix = "_time";
722 const char *voltageSuffix = "_volt";
723 const char *countSuffix = "_count";
724 const char *title = "Mitigation Stats";
725
726 std::vector<std::string> files;
727 std::string content;
728 std::string fileLocation;
729 std::string source;
730 std::string subModuleName;
731 int count;
732 int soc;
733 int time;
734 int voltage;
735
736 ret = getFilesInDir(directory, &files);
737 if (ret < 0)
738 return;
739
740 printTitle(title);
741 printf("Source\t\tCount\tSOC\tTime\tVoltage\n");
742
743 for (auto &file : files) {
744 fileLocation = std::string(directory) + std::string(file);
745 if (!android::base::ReadFileToString(fileLocation, &content)) {
746 continue;
747 }
748
749 ret = atoi(android::base::Trim(content).c_str());
750 if (ret == -1)
751 continue;
752 count = ret;
753
754 subModuleName = std::string(file);
755 subModuleName.erase(subModuleName.find(countSuffix), strlen(countSuffix));
756
757 fileLocation = std::string(capacityDirectory) + std::string(subModuleName) +
758 std::string(capacitySuffix);
759 if (!android::base::ReadFileToString(fileLocation, &content)) {
760 continue;
761 }
762 ret = atoi(android::base::Trim(content).c_str());
763 if (ret == -1)
764 continue;
765 soc = ret;
766
767 fileLocation = std::string(timestampDirectory) + std::string(subModuleName) +
768 std::string(timeSuffix);
769 if (!android::base::ReadFileToString(fileLocation, &content)) {
770 continue;
771 }
772 ret = atoi(android::base::Trim(content).c_str());
773 if (ret == -1)
774 continue;
775 time = ret;
776
777 fileLocation = std::string(voltageDirectory) + std::string(subModuleName) +
778 std::string(voltageSuffix);
779 if (!android::base::ReadFileToString(fileLocation, &content)) {
780 continue;
781 }
782 ret = atoi(android::base::Trim(content).c_str());
783 if (ret == -1)
784 continue;
785 voltage = ret;
786 printf("%s \t%i\t%i\t%i\t%i\n", subModuleName.c_str(), count, soc, time, voltage);
787 }
788 }
789
dumpMitigationDirs()790 void dumpMitigationDirs() {
791 const int paramCount = 4;
792 const char *titles[] = {
793 "Clock Divider Ratio",
794 "Clock Stats",
795 "Triggered Level",
796 "Instruction",
797 };
798 const char *directories[] = {
799 "/sys/devices/virtual/pmic/mitigation/clock_ratio/",
800 "/sys/devices/virtual/pmic/mitigation/clock_stats/",
801 "/sys/devices/virtual/pmic/mitigation/triggered_lvl/",
802 "/sys/devices/virtual/pmic/mitigation/instruction/",
803 };
804 const char *paramSuffix[] = {"_ratio", "_stats", "_lvl", ""};
805 const char *titleRowVal[] = {
806 "Source\t\tRatio",
807 "Source\t\tStats",
808 "Source\t\tLevel",
809 "",
810 };
811 const int eraseCnt[] = {6, 6, 4, 0};
812 const bool useTitleRow[] = {true, true, true, false};
813 const char *vimon_name = "vimon_buff";
814 const char delimiter = '\n';
815 const int vimon_len = strlen(vimon_name);
816 const double VIMON_VMULT = 7.8122e-5;
817 const double VIMON_IMULT = 7.8125e-4;
818
819 std::vector<std::string> files;
820 std::string content;
821 std::string fileLocation;
822 std::string source;
823 std::string subModuleName;
824 std::string readout;
825 char *endptr;
826
827 bool vimon_found = false;
828
829 for (int i = 0; i < paramCount; i++) {
830 printTitle(titles[i]);
831 if (useTitleRow[i]) {
832 printf("%s\n", titleRowVal[i]);
833 }
834
835 getFilesInDir(directories[i], &files);
836
837 for (auto &file : files) {
838 fileLocation = std::string(directories[i]) + std::string(file);
839 if (!android::base::ReadFileToString(fileLocation, &content)) {
840 continue;
841 }
842
843 readout = android::base::Trim(content);
844
845 if (strncmp(file.c_str(), vimon_name, vimon_len) == 0)
846 vimon_found = true;
847
848 subModuleName = std::string(file);
849 subModuleName.erase(subModuleName.find(paramSuffix[i]), eraseCnt[i]);
850
851 if (useTitleRow[i]) {
852 printf("%s \t%s\n", subModuleName.c_str(), readout.c_str());
853 } else if (vimon_found) {
854
855 std::vector<std::string> tokens;
856 std::istringstream tokenStream(readout);
857 std::string token;
858
859 while (std::getline(tokenStream, token, delimiter)) {
860 tokens.push_back(token);
861 }
862
863 bool oddEntry = true;
864 for (auto &hexval : tokens) {
865 int val = strtol(hexval.c_str(), &endptr, 16);
866 if (*endptr != '\0') {
867 printf("invalid vimon readout\n");
868 break;
869 }
870 if (oddEntry) {
871 int vbatt = int(1000 * (val * VIMON_VMULT));
872 printf("vimon vbatt: %d ", vbatt);
873 } else {
874 int ibatt = int(1000 * (val * VIMON_IMULT));
875 printf("ibatt: %d\n", ibatt);
876 }
877 oddEntry = !oddEntry;
878 }
879 } else {
880 printf("%s=%s\n", subModuleName.c_str(), readout.c_str());
881 }
882 }
883 }
884 }
885
dumpIrqDurationCounts()886 void dumpIrqDurationCounts() {
887 const char *title = "IRQ Duration Counts";
888 const char *colNames = "Source\t\t\t\tlt_5ms_cnt\tbt_5ms_to_10ms_cnt\tgt_10ms_cnt\tCode"
889 "\tCurrent Threshold (uA)\tCurrent Reading (uA)\n";
890 const int nonOdpmChannelCnt = 12;
891 const int odpmChCnt = 12;
892
893 enum Duration {
894 LT_5MS,
895 BT_5MS_10MS,
896 GT_10MS,
897 DUR_MAX,
898 };
899 const char *irqDurDirectories[] = {
900 "/sys/devices/virtual/pmic/mitigation/irq_dur_cnt/less_than_5ms_count",
901 "/sys/devices/virtual/pmic/mitigation/irq_dur_cnt/between_5ms_to_10ms_count",
902 "/sys/devices/virtual/pmic/mitigation/irq_dur_cnt/greater_than_10ms_count",
903 };
904
905 enum PowerWarn {
906 MAIN,
907 SUB,
908 PWRWARN_MAX,
909 };
910 const char *pwrwarnDirectories[] = {
911 "/sys/devices/virtual/pmic/mitigation/main_pwrwarn/",
912 "/sys/devices/virtual/pmic/mitigation/sub_pwrwarn/",
913 };
914
915 const char *lpfCurrentDirs[] = {
916 "/sys/devices/platform/acpm_mfd_bus@15500000/i2c-7/7-001f/s2mpg14-meter/"
917 "s2mpg14-odpm/iio:device1/lpf_current",
918 "/sys/devices/platform/acpm_mfd_bus@15510000/i2c-8/8-002f/s2mpg15-meter/"
919 "s2mpg15-odpm/iio:device0/lpf_current",
920 };
921
922 const char *lpfCurrentDirsAlt[] = {
923 "/sys/devices/platform/acpm_mfd_bus@15500000/i2c-7/7-001f/s2mpg14-meter/"
924 "s2mpg14-odpm/iio:device0/lpf_current",
925 "/sys/devices/platform/acpm_mfd_bus@15510000/i2c-8/8-002f/s2mpg15-meter/"
926 "s2mpg15-odpm/iio:device1/lpf_current",
927 };
928
929 bool titlesInitialized = false;
930
931 std::vector<std::string> channelNames;
932 std::vector<std::string> channelData[DUR_MAX];
933 std::vector<std::string> pwrwarnThreshold[PWRWARN_MAX];
934 std::vector<std::string> pwrwarnCode[PWRWARN_MAX];
935 std::vector<std::string> lpfCurrentVals[PWRWARN_MAX];
936 std::vector<std::string> files;
937
938 std::string content;
939 std::string token;
940 std::string tokenCh;
941 std::string fileLocation;
942
943 for (int i = 0; i < DUR_MAX; i++) {
944 if (!android::base::ReadFileToString(irqDurDirectories[i], &content)) {
945 return;
946 }
947
948 std::istringstream tokenStream(content);
949
950 while (std::getline(tokenStream, token, '\n')) {
951 if (!titlesInitialized) {
952 tokenCh = token;
953 tokenCh.erase(tokenCh.find(':'), tokenCh.length());
954 channelNames.push_back(tokenCh);
955 }
956
957 // there is a space after the ':' which needs to be removed
958 token.erase(0, token.find(':') + 1);
959 channelData[i].push_back(token);
960
961 }
962 if (!titlesInitialized)
963 titlesInitialized = true;
964 }
965
966 for (int i = 0; i < PWRWARN_MAX; i++) {
967 getFilesInDir(pwrwarnDirectories[i], &files);
968
969 for (auto &file : files) {
970 fileLocation = std::string(pwrwarnDirectories[i]) + std::string(file);
971 if (!android::base::ReadFileToString(fileLocation, &content)) {
972 continue;
973 }
974
975 std::string readout;
976
977 readout = android::base::Trim(content);
978
979 std::string readoutThreshold = readout;
980 readoutThreshold.erase(0, readoutThreshold.find('=') + 1);
981
982 std::string readoutCode = readout;
983 readoutCode.erase(readoutCode.find('='), readoutCode.length());
984
985 pwrwarnThreshold[i].push_back(readoutThreshold);
986 pwrwarnCode[i].push_back(readoutCode);
987 }
988 }
989
990 for (int i = 0; i < PWRWARN_MAX; i++) {
991 if (!android::base::ReadFileToString(lpfCurrentDirs[i], &content) &&
992 !android::base::ReadFileToString(lpfCurrentDirsAlt[i], &content)) {
993 printf("Cannot find %s\n", lpfCurrentDirs[i]);
994 continue;
995 }
996
997 std::istringstream tokenStream(content);
998
999 bool first = true;
1000 while (std::getline(tokenStream, token, '\n')) {
1001 token.erase(0, token.find(' '));
1002 if (first) {
1003 first = false;
1004 continue;
1005 }
1006 lpfCurrentVals[i].push_back(token);
1007 }
1008 }
1009
1010 printTitle(title);
1011 printf("%s", colNames);
1012
1013 for (uint i = 0; i < channelNames.size(); i++) {
1014 std::string code = "";
1015 std::string threshold = "";
1016 std::string current = "";
1017 std::string ltDataMsg = "";
1018 std::string btDataMsg = "";
1019 std::string gtDataMsg = "";
1020 int pmicSel = 0;
1021 int offset = 0;
1022 std::string channelNameSuffix = " \t";
1023 if (i >= nonOdpmChannelCnt) {
1024 offset = nonOdpmChannelCnt;
1025 if (i >= (odpmChCnt + nonOdpmChannelCnt)) {
1026 pmicSel = 1;
1027 offset = odpmChCnt + nonOdpmChannelCnt;
1028 }
1029 channelNameSuffix = "";
1030
1031 if (pmicSel >= PWRWARN_MAX) {
1032 printf("invalid index: pmicSel >= pwrwarnCode size\n");
1033 return;
1034 }
1035
1036 if (i - offset >= pwrwarnCode[pmicSel].size()) {
1037 printf("invalid index: i - offset >= pwrwarnCode size\n");
1038 return;
1039 }
1040 code = pwrwarnCode[pmicSel][i - offset];
1041
1042 if (i - offset >= pwrwarnThreshold[pmicSel].size()) {
1043 printf("invalid index: i - offset >= pwrwarnThreshold size\n");
1044 return;
1045 }
1046 threshold = pwrwarnThreshold[pmicSel][i - offset];
1047
1048 if (i - offset >= lpfCurrentVals[pmicSel].size()) {
1049 printf("invalid index: i - offset >= lpfCurrentVals size\n");
1050 return;
1051 }
1052 current = lpfCurrentVals[pmicSel][i - offset];
1053 }
1054
1055 if (i < channelData[0].size())
1056 ltDataMsg = channelData[0][i];
1057
1058 if (i < channelData[1].size())
1059 btDataMsg = channelData[1][i];
1060
1061 if (i < channelData[2].size())
1062 gtDataMsg = channelData[2][i];
1063
1064 std::string adjustedChannelName = channelNames[i] + channelNameSuffix;
1065 printf("%s \t%s\t\t%s\t\t\t%s\t\t%s \t%s \t\t%s\n",
1066 adjustedChannelName.c_str(),
1067 ltDataMsg.c_str(),
1068 btDataMsg.c_str(),
1069 gtDataMsg.c_str(),
1070 code.c_str(),
1071 threshold.c_str(),
1072 current.c_str());
1073 }
1074 }
1075
dumpEvtCounter()1076 void dumpEvtCounter() {
1077 const char* title = "Event Counter";
1078 const char* evtCntDir = "/sys/devices/virtual/pmic/mitigation/instruction/";
1079
1080 const char* evtCnt [][2] {
1081 {"batoilo1", "evt_cnt_batoilo1"},
1082 {"batoilo2", "evt_cnt_batoilo2"},
1083 {"uvlo1", "evt_cnt_uvlo1"},
1084 {"uvlo2", "evt_cnt_uvlo2"},
1085 };
1086
1087 printTitle(title);
1088 printf("name\tcount\n");
1089
1090 for (const auto &row : evtCnt) {
1091 std::string name = row[0];
1092 std::string fileLocation = std::string(evtCntDir) + std::string(row[1]);
1093 std::string count = "N/A\n";
1094 if (!android::base::ReadFileToString(fileLocation, &count)) {
1095 count = "invalid\n";
1096 }
1097
1098 printf("%s\t%s", name.c_str(), count.c_str());
1099 }
1100 }
1101
dumpCpuIdleHistogramStats()1102 void dumpCpuIdleHistogramStats() {
1103 const char* cpuIdleHistogramTitle = "CPU Idle Histogram";
1104 const char* cpuIdleHistogramFile = "/sys/kernel/metrics/cpuidle_histogram/"
1105 "cpuidle_histogram";
1106 const char* cpuClusterHistogramTitle = "CPU Cluster Histogram";
1107 const char* cpuClusterHistogramFile = "/sys/kernel/metrics/"
1108 "cpuidle_histogram/cpucluster_histogram";
1109 dumpFileContent(cpuIdleHistogramTitle, cpuIdleHistogramFile);
1110 dumpFileContent(cpuClusterHistogramTitle, cpuClusterHistogramFile);
1111 }
1112
main()1113 int main() {
1114 dumpPowerStatsTimes();
1115 dumpAcpmStats();
1116 dumpCpuIdleHistogramStats();
1117 dumpPowerSupplyStats();
1118 dumpSecondCharge();
1119 dumpMaxFg();
1120 dumpPowerSupplyDock();
1121 dumpLogBufferTcpm();
1122 dumpTcpc();
1123 dumpPdEngine();
1124 dumpBatteryHealth();
1125 dumpBatteryDefend();
1126 dumpBatteryCaretaker();
1127 dumpChg();
1128 dumpChgUserDebug();
1129 dumpScratchpad();
1130 dumpBatteryEeprom();
1131 dumpChargerStats();
1132 dumpWlcLogs();
1133 dumpGvoteables();
1134 dumpMitigation();
1135 dumpMitigationStats();
1136 dumpMitigationDirs();
1137 dumpIrqDurationCounts();
1138 dumpEvtCounter();
1139 }
1140
1141