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