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 
181     const char *maxfg [][2] = {
182             {"Power supply property maxfg", "/sys/class/power_supply/maxfg/uevent"},
183             {"m5_state", "/sys/class/power_supply/maxfg/m5_model_state"},
184             {"maxfg logbuffer", "/dev/logbuffer_maxfg"},
185             {"maxfg_monitor logbuffer", "/dev/logbuffer_maxfg_monitor"},
186     };
187 
188     const char *max77779fgFiles [][2] = {
189             {"Power supply property max77779fg", "/sys/class/power_supply/max77779fg/uevent"},
190             {"model_state", "/sys/class/power_supply/max77779fg/model_state"},
191             {"max77779fg logbuffer", "/dev/logbuffer_max77779fg"},
192             {"max77779fg_monitor logbuffer", "/dev/logbuffer_max77779fg_monitor"},
193     };
194 
195     const char *maxfgSecondary [][2] = {
196             {"Power supply property maxfg_base", "/sys/class/power_supply/maxfg_base/uevent"},
197             {"Power supply property maxfg_secondary", "/sys/class/power_supply/maxfg_secondary/uevent"},
198             {"model_state", "/sys/class/power_supply/maxfg_base/model_state"},
199             {"maxfg_base", "/dev/logbuffer_maxfg_base"},
200             {"maxfg_secondary", "/dev/logbuffer_maxfg_secondary"},
201             {"maxfg_base_monitor logbuffer", "/dev/logbuffer_maxfg_base_monitor"},
202             {"maxfg_secondary_monitor logbuffer", "/dev/logbuffer_maxfg_secondary_monitor"},
203     };
204 
205     const char *maxfgHistoryName = "Maxim FG History";
206     const char *maxfgHistoryDir = "/dev/maxfg_history";
207 
208     std::string content;
209 
210 
211     if (isValidDir(maxfgLoc)) {
212         for (const auto &row : maxfg) {
213             dumpFileContent(row[0], row[1]);
214         }
215     } else if (isValidDir(max77779fgDir)) {
216         for (const auto &row : max77779fgFiles) {
217             dumpFileContent(row[0], row[1]);
218         }
219     } else {
220         for (const auto &row : maxfgSecondary) {
221             dumpFileContent(row[0], row[1]);
222         }
223     }
224 
225     if (isValidFile(maxfgHistoryDir)) {
226         dumpFileContent(maxfgHistoryName, maxfgHistoryDir);
227     }
228 }
229 
dumpPowerSupplyDock()230 void dumpPowerSupplyDock() {
231     const char* powerSupplyPropertyDockTitle = "Power supply property dock";
232     const char* powerSupplyPropertyDockFile = "/sys/class/power_supply/dock/uevent";
233     if (isValidFile(powerSupplyPropertyDockFile)) {
234         dumpFileContent(powerSupplyPropertyDockTitle, powerSupplyPropertyDockFile);
235     }
236 }
237 
dumpLogBufferTcpm()238 void dumpLogBufferTcpm() {
239     const char* logbufferTcpmTitle = "Logbuffer TCPM";
240     const char* logbufferTcpmFile = "/dev/logbuffer_tcpm";
241     const char* debugTcpmFile = "/sys/kernel/debug/tcpm";
242     const char* tcpmLogTitle = "TCPM logs";
243     const char* tcpmFile = "/sys/kernel/debug/tcpm";
244     const char* tcpmFileAlt = "/sys/kernel/debug/usb/tcpm";
245     int retCode;
246 
247     dumpFileContent(logbufferTcpmTitle, logbufferTcpmFile);
248 
249     retCode = readContentsOfDir(tcpmLogTitle, isValidFile(debugTcpmFile) ? tcpmFile : tcpmFileAlt,
250             NULL);
251     if (retCode < 0)
252         printTitle(tcpmLogTitle);
253 }
254 
dumpTcpc()255 void dumpTcpc() {
256     int ret;
257     const char* max77759TcpcHead = "TCPC";
258     const char* i2cSubDirMatch = "i2c-";
259     const char* directory = "/sys/devices/platform/10d60000.hsi2c/";
260     const char* max77759Tcpc [][2] {
261             {"registers:", "/i2c-max77759tcpc/registers"},
262             {"frs:", "/i2c-max77759tcpc/frs"},
263             {"auto_discharge:", "/i2c-max77759tcpc/auto_discharge"},
264             {"bcl2_enabled:", "/i2c-max77759tcpc/bcl2_enabled"},
265             {"cc_toggle_enable:", "/i2c-max77759tcpc/cc_toggle_enable"},
266             {"containment_detection:", "/i2c-max77759tcpc/containment_detection"},
267             {"containment_detection_status:", "/i2c-max77759tcpc/containment_detection_status"},
268     };
269 
270     std::vector<std::string> files;
271     std::string content;
272 
273     printTitle(max77759TcpcHead);
274 
275     ret = getFilesInDir(directory, &files);
276     if (ret < 0) {
277         for (auto &tcpcVal : max77759Tcpc)
278             printf("%s\n", tcpcVal[0]);
279         return;
280     }
281 
282     for (auto &file : files) {
283         for (auto &tcpcVal : max77759Tcpc) {
284             printf("%s ", tcpcVal[0]);
285             if (std::string::npos == std::string(file).find(i2cSubDirMatch)) {
286                 continue;
287             }
288 
289             std::string fileName = directory + file + "/" + std::string(tcpcVal[1]);
290 
291             if (!android::base::ReadFileToString(fileName, &content)) {
292                 continue;
293             }
294 
295             printf("%s\n", content.c_str());
296         }
297     }
298 }
299 
dumpPdEngine()300 void dumpPdEngine() {
301     const char* pdEngine [][2] {
302             {"TCPC logbuffer", "/dev/logbuffer_usbpd"},
303             {"pogo_transport logbuffer", "/dev/logbuffer_pogo_transport"},
304             {"PPS-google_cpm logbuffer", "/dev/logbuffer_cpm"},
305     };
306     const char* ppsDcMsg = "PPS-dc logbuffer";
307     const char* pca9468dir = "/dev/logbuffer_pca9468";
308     const char* ln8411dir = "/dev/logbuffer_ln8411";
309 
310     for (const auto &row : pdEngine) {
311         dumpFileContent(row[0], row[1]);
312     }
313     if (isValidFile(pca9468dir)) {
314         dumpFileContent(ppsDcMsg, pca9468dir);
315     } else {
316         dumpFileContent(ppsDcMsg, ln8411dir);
317     }
318 }
319 
dumpBatteryHealth()320 void dumpBatteryHealth() {
321     const char* batteryHealth [][2] {
322             {"Battery Health", "/sys/class/power_supply/battery/health_index_stats"},
323             {"Battery Health SoC Residency", "/sys/class/power_supply/battery/swelling_data"},
324             {"BMS logbuffer", "/dev/logbuffer_ssoc"},
325             {"TTF logbuffer", "/dev/logbuffer_ttf"},
326             {"TTF details", "/sys/class/power_supply/battery/ttf_details"},
327             {"TTF stats", "/sys/class/power_supply/battery/ttf_stats"},
328             {"aacr_state", "/sys/class/power_supply/battery/aacr_state"},
329             {"pairing_state", "/sys/class/power_supply/battery/pairing_state"},
330             {"fwupdate", "/dev/logbuffer_max77779_fwupdate"}
331     };
332 
333     const char* maxqName = "maxq logbuffer";
334     const char* maxqDir = "/dev/logbuffer_maxq";
335     const char* tempDockDefendName = "TEMP/DOCK-DEFEND";
336     const char* tempDockDefendDir = "/dev/logbuffer_bd";
337 
338     for (const auto &row : batteryHealth) {
339         dumpFileContent(row[0], row[1]);
340     }
341 
342     if (isValidFile(maxqDir))
343         dumpFileContent(maxqName, maxqDir);
344 
345     dumpFileContent(tempDockDefendName, tempDockDefendDir);
346 }
347 
dumpBatteryDefend()348 void dumpBatteryDefend() {
349     const char* defendConfig [][4] {
350             {"TRICKLE-DEFEND Config",
351                     "/sys/devices/platform/google,battery/power_supply/battery/", "bd_"},
352             {"DWELL-DEFEND Config", "/sys/devices/platform/google,charger/", "charge_s"},
353             {"DWELL-DEFEND Time", "/mnt/vendor/persist/battery/", "defender_"},
354             {"TEMP-DEFEND Config", "/sys/devices/platform/google,charger/", "bd_"},
355     };
356 
357     std::vector<std::string> files;
358     struct dirent *entry;
359     std::string content;
360     std::string fileLocation;
361 
362     for (auto &config : defendConfig) {
363         DIR *dir = opendir(config[1]);
364         if (dir == NULL)
365             continue;
366 
367         printTitle(config[0]);
368         while ((entry = readdir(dir)) != NULL) {
369             if (std::string(entry->d_name).find(config[2]) != std::string::npos &&
370                     strncmp(config[2], entry->d_name, strlen(config[2])) == 0) {
371                 files.push_back(entry->d_name);
372             }
373         }
374         closedir(dir);
375 
376         sort(files.begin(), files.end());
377 
378         for (auto &file : files) {
379             fileLocation = std::string(config[1]) + std::string(file);
380             if (!android::base::ReadFileToString(fileLocation, &content) || content.empty()) {
381                 content = "\n";
382             }
383 
384             printf("%s: %s", file.c_str(), content.c_str());
385 
386             if (content.back() != '\n')
387                 printf("\n");
388         }
389 
390         files.clear();
391     }
392 }
393 
printValuesOfDirectory(const char * directory,std::string debugfs,const char * strMatch)394 void printValuesOfDirectory(const char *directory, std::string debugfs, const char *strMatch) {
395     std::vector<std::string> files;
396     auto info = directory;
397     std::string content;
398     struct dirent *entry;
399     DIR *dir = opendir(debugfs.c_str());
400     if (dir == NULL)
401         return;
402 
403     printTitle((debugfs + std::string(strMatch) + "/" + std::string(info)).c_str());
404     while ((entry = readdir(dir)) != NULL)
405         if (std::string(entry->d_name).find(strMatch) != std::string::npos)
406             files.push_back(entry->d_name);
407     closedir(dir);
408 
409     sort(files.begin(), files.end());
410 
411     for (auto &file : files) {
412         std::string fileDirectory = debugfs + file;
413         std::string fileLocation = fileDirectory + "/" + std::string(info);
414         if (!android::base::ReadFileToString(fileLocation, &content)) {
415             content = "\n";
416         }
417 
418         printf("%s:\n%s", fileDirectory.c_str(), content.c_str());
419 
420         if (content.back() != '\n')
421             printf("\n");
422     }
423     files.clear();
424 }
425 
dumpChg()426 void dumpChg() {
427     const std::string pmic_bus = "/sys/devices/platform/108d0000.hsi2c/i2c-6/6-0066";
428     const std::string pmic_bus_dev = "/sys/devices/platform/10cb0000.hsi2c/i2c-11/11-0066";
429     const char* chg_reg_dump_file = "/sys/class/power_supply/main-charger/device/registers_dump";
430     const std::string chg_name_file = "/sys/class/power_supply/main-charger/device/name";
431     const std::string pmic_name_file_dev = pmic_bus_dev + "/name";
432     const std::string pmic_reg_dump_dev_file = pmic_bus_dev + "/registers_dump";
433     const std::string pmic_name_file = pmic_bus + "/name";
434     const std::string pmic_reg_dump_file = pmic_bus + "/registers_dump";
435     const std::string reg_dump_str = " registers dump";
436     const char* chgConfig [][2] {
437         {"DC_registers dump", "/sys/class/power_supply/dc-mains/device/registers_dump"},
438     };
439     std::string chg_name;
440     std::string pmic_name;
441     std::string pmic_reg_dump;
442 
443     printf("\n");
444 
445     int ret = android::base::ReadFileToString(chg_name_file, &chg_name);
446     if (ret && !chg_name.empty()) {
447         chg_name.erase(chg_name.length() - 1); // remove new line
448         const std::string chg_reg_dump_title = chg_name + reg_dump_str;
449 
450         /* CHG reg dump */
451         dumpFileContent(chg_reg_dump_title.c_str(), chg_reg_dump_file);
452     }
453 
454     if (isValidDir(pmic_bus.c_str())) {
455         ret = android::base::ReadFileToString(pmic_name_file, &pmic_name);
456         pmic_reg_dump = pmic_reg_dump_file;
457     } else {
458         /* DEV device */
459         ret = android::base::ReadFileToString(pmic_name_file_dev, &pmic_name);
460         pmic_reg_dump = pmic_reg_dump_dev_file;
461     }
462 
463     if (ret && !pmic_name.empty()) {
464         pmic_name.erase(pmic_name.length() - 1); // remove new line
465         const std::string pmic_reg_dump_title = pmic_name + reg_dump_str;
466 
467         /* PMIC reg dump */
468         dumpFileContent(pmic_reg_dump_title.c_str(), pmic_reg_dump.c_str());
469     }
470 
471     for (auto &config : chgConfig) {
472         dumpFileContent(config[0], config[1]);
473     }
474 }
475 
dumpChgUserDebug()476 void dumpChgUserDebug() {
477     const std::string debugfs = "/d/";
478     const char *maxFgDir = "/d/maxfg";
479     const char *maxFgStrMatch = "maxfg";
480     const char *maxBaseFgDir = "/d/maxfg_base";
481     const char *maxBaseFgStrMatch = "maxfg_base";
482     const char *maxSecFgDir = "/d/maxfg_secondary";
483     const char *maxSecFgStrMatch = "maxfg_secondary";
484     const char *max77779FgDir = "/d/max77779fg";
485     const char *maxFg77779StrMatch = "max77779fg";
486     const char *chgTblName = "Charging table dump";
487     const char *chgTblDir = "/d/google_battery/chg_raw_profile";
488 
489     const char *maxFgInfo [] {
490             "fg_model",
491             "algo_ver",
492             "model_ok",
493             "registers",
494             "nv_registers",
495     };
496 
497     const char *max77779FgInfo [] {
498             "fg_model",
499             "algo_ver",
500             "model_ok",
501             "registers",
502             "debug_registers",
503     };
504 
505     const char *max1720xFgInfo [] {
506             "registers",
507             "nv_registers",
508     };
509 
510     if (isUserBuild())
511         return;
512 
513     dumpFileContent(chgTblName, chgTblDir);
514 
515     if (isValidDir(maxFgDir)) {
516         for (auto & directory : maxFgInfo) {
517             printValuesOfDirectory(directory, debugfs, maxFgStrMatch);
518         }
519     } else if (isValidDir(max77779FgDir)) {
520         for (auto & directory : max77779FgInfo) {
521             printValuesOfDirectory(directory, debugfs, maxFg77779StrMatch);
522         }
523     } else if (isValidDir(maxBaseFgDir)) {
524         for (auto & directory : max77779FgInfo) {
525             printValuesOfDirectory(directory, debugfs, maxBaseFgStrMatch);
526         }
527         if (isValidDir(maxSecFgDir)) {
528             for (auto & directory : max1720xFgInfo) {
529                 printValuesOfDirectory(directory, debugfs, maxSecFgStrMatch);
530             }
531         }
532     }
533 }
534 
dumpBatteryEeprom()535 void dumpBatteryEeprom() {
536     const char *title = "Battery EEPROM";
537     const char *files[] {
538             "/sys/devices/platform/10ca0000.hsi2c/i2c-10/10-0050/eeprom",
539             "/sys/devices/platform/10c90000.hsi2c/i2c-9/9-0050/eeprom",
540     };
541     std::string result;
542     std::string xxdCmd;
543 
544     printTitle(title);
545     for (auto &file : files) {
546         if (!isValidFile(file))
547             continue;
548 
549         xxdCmd = "xxd " + std::string(file);
550 
551         int ret = getCommandOutput(xxdCmd.c_str(), &result);
552         if (ret < 0)
553             return;
554 
555         printf("%s\n", result.c_str());
556     }
557 }
558 
dumpChargerStats()559 void dumpChargerStats() {
560     const char *chgStatsTitle = "Charger Stats";
561     const char *chgStatsLocation = "/sys/class/power_supply/battery/charge_details";
562     const char *chargerStats [][3] {
563             {"Google Charger", "/sys/kernel/debug/google_charger/", "pps_"},
564             {"Google Battery", "/sys/kernel/debug/google_battery/", "ssoc_"},
565     };
566     std::vector<std::string> files;
567     std::string content;
568     struct dirent *entry;
569 
570     dumpFileContent(chgStatsTitle, chgStatsLocation);
571 
572     if (isUserBuild())
573         return;
574 
575     for (auto &stat : chargerStats) {
576         DIR *dir = opendir(stat[1]);
577         if (dir == NULL)
578             return;
579 
580         printTitle(stat[0]);
581         while ((entry = readdir(dir)) != NULL)
582             if (std::string(entry->d_name).find(stat[2]) != std::string::npos)
583                 files.push_back(entry->d_name);
584         closedir(dir);
585 
586         sort(files.begin(), files.end());
587 
588         for (auto &file : files) {
589             std::string fileLocation = std::string(stat[1]) + file;
590             if (!android::base::ReadFileToString(fileLocation, &content)) {
591                 content = "\n";
592             }
593 
594             printf("%s: %s", file.c_str(), content.c_str());
595 
596             if (content.back() != '\n')
597                 printf("\n");
598         }
599         files.clear();
600     }
601 }
602 
dumpWlcLogs()603 void dumpWlcLogs() {
604     const char *dumpWlcList [][2] {
605             {"WLC Logs", "/dev/logbuffer_wireless"},
606             {"WLC VER", "/sys/class/power_supply/wireless/device/version"},
607             {"WLC STATUS", "/sys/class/power_supply/wireless/device/status"},
608             {"WLC FW Version", "/sys/class/power_supply/wireless/device/fw_rev"},
609             {"RTX", "/dev/logbuffer_rtx"},
610     };
611 
612     for (auto &row : dumpWlcList) {
613         if (!isValidFile(row[1]))
614             printTitle(row[0]);
615         dumpFileContent(row[0], row[1]);
616     }
617 }
618 
dumpGvoteables()619 void dumpGvoteables() {
620     const char *directory = "/sys/kernel/debug/gvotables/";
621     const char *statusName = "/status";
622     const char *title = "gvotables";
623     std::string content;
624     std::vector<std::string> files;
625     int ret;
626 
627     if (isUserBuild())
628         return;
629 
630     ret = getFilesInDir(directory, &files);
631     if (ret < 0)
632         return;
633 
634     printTitle(title);
635     for (auto &file : files) {
636         std::string fileLocation = std::string(directory) + file + std::string(statusName);
637         if (!android::base::ReadFileToString(fileLocation, &content)) {
638             continue;
639         }
640 
641         printf("%s: %s", file.c_str(), content.c_str());
642 
643         if (content.back() != '\n')
644             printf("\n");
645     }
646     files.clear();
647 }
648 
dumpMitigation()649 void dumpMitigation() {
650     const char *mitigationList [][2] {
651             {"LastmealCSV" , "/data/vendor/mitigation/lastmeal.csv"},
652             {"Lastmeal" , "/data/vendor/mitigation/lastmeal.txt"},
653             {"Thismeal" , "/data/vendor/mitigation/thismeal.txt"},
654     };
655 
656     /* parsing thismeal.bin */
657     int status;
658     int pid = fork();
659     if (pid < 0) {
660         printf("Fork failed for parsing thismeal.bin.\n");
661         exit(EXIT_FAILURE);
662     } else if (pid == 0) {
663         execl("/vendor/bin/hw/battery_mitigation", "battery_mitigation", "-d", nullptr);
664         exit(EXIT_SUCCESS);
665     }
666     waitpid(pid, &status, 0);
667 
668     if (WIFSIGNALED(status)) {
669         printf("Failed to parse thismeal.bin.(killed by: %d)\n", WTERMSIG(status));
670     }
671 
672     for (auto &row : mitigationList) {
673         if (!isValidFile(row[1]))
674             printTitle(row[0]);
675         dumpFileContent(row[0], row[1]);
676     }
677 }
678 
dumpMitigationStats()679 void dumpMitigationStats() {
680     int ret;
681     const char *directory = "/sys/devices/virtual/pmic/mitigation/last_triggered_count/";
682     const char *capacityDirectory = "/sys/devices/virtual/pmic/mitigation/last_triggered_capacity/";
683     const char *timestampDirectory =
684             "/sys/devices/virtual/pmic/mitigation/last_triggered_timestamp/";
685     const char *voltageDirectory = "/sys/devices/virtual/pmic/mitigation/last_triggered_voltage/";
686     const char *capacitySuffix = "_cap";
687     const char *timeSuffix = "_time";
688     const char *voltageSuffix = "_volt";
689     const char *countSuffix = "_count";
690     const char *title = "Mitigation Stats";
691 
692     std::vector<std::string> files;
693     std::string content;
694     std::string fileLocation;
695     std::string source;
696     std::string subModuleName;
697     int count;
698     int soc;
699     int time;
700     int voltage;
701 
702     ret = getFilesInDir(directory, &files);
703     if (ret < 0)
704         return;
705 
706     printTitle(title);
707     printf("Source\t\tCount\tSOC\tTime\tVoltage\n");
708 
709     for (auto &file : files) {
710         fileLocation = std::string(directory) + std::string(file);
711         if (!android::base::ReadFileToString(fileLocation, &content)) {
712             continue;
713         }
714 
715         ret = atoi(android::base::Trim(content).c_str());
716         if (ret == -1)
717             continue;
718         count = ret;
719 
720         subModuleName = std::string(file);
721         subModuleName.erase(subModuleName.find(countSuffix), strlen(countSuffix));
722 
723         fileLocation = std::string(capacityDirectory) + std::string(subModuleName) +
724                 std::string(capacitySuffix);
725         if (!android::base::ReadFileToString(fileLocation, &content)) {
726             continue;
727         }
728         ret = atoi(android::base::Trim(content).c_str());
729         if (ret == -1)
730             continue;
731         soc = ret;
732 
733         fileLocation = std::string(timestampDirectory) + std::string(subModuleName) +
734                 std::string(timeSuffix);
735         if (!android::base::ReadFileToString(fileLocation, &content)) {
736             continue;
737         }
738         ret = atoi(android::base::Trim(content).c_str());
739         if (ret == -1)
740             continue;
741         time = ret;
742 
743         fileLocation = std::string(voltageDirectory) + std::string(subModuleName) +
744                 std::string(voltageSuffix);
745         if (!android::base::ReadFileToString(fileLocation, &content)) {
746             continue;
747         }
748         ret = atoi(android::base::Trim(content).c_str());
749         if (ret == -1)
750             continue;
751         voltage = ret;
752         printf("%s \t%i\t%i\t%i\t%i\n", subModuleName.c_str(), count, soc, time, voltage);
753     }
754 }
755 
dumpMitigationDirs()756 void dumpMitigationDirs() {
757     const int paramCount = 4;
758     const char *titles[] = {
759             "Clock Divider Ratio",
760             "Clock Stats",
761             "Triggered Level",
762             "Instruction",
763     };
764     const char *directories[] = {
765             "/sys/devices/virtual/pmic/mitigation/clock_ratio/",
766             "/sys/devices/virtual/pmic/mitigation/clock_stats/",
767             "/sys/devices/virtual/pmic/mitigation/triggered_lvl/",
768             "/sys/devices/virtual/pmic/mitigation/instruction/",
769     };
770     const char *paramSuffix[] = {"_ratio", "_stats", "_lvl", ""};
771     const char *titleRowVal[] = {
772             "Source\t\tRatio",
773             "Source\t\tStats",
774             "Source\t\tLevel",
775             "",
776     };
777     const int eraseCnt[] = {6, 6, 4, 0};
778     const bool useTitleRow[] = {true, true, true, false};
779     const char *vimon_name = "vimon_buff";
780     const char delimiter = '\n';
781     const int vimon_len = strlen(vimon_name);
782     const double VIMON_VMULT = 7.8122e-5;
783     const double VIMON_IMULT = 7.8125e-4;
784 
785     std::vector<std::string> files;
786     std::string content;
787     std::string fileLocation;
788     std::string source;
789     std::string subModuleName;
790     std::string readout;
791     char *endptr;
792 
793     bool vimon_found = false;
794 
795     for (int i = 0; i < paramCount; i++) {
796         printTitle(titles[i]);
797         if (useTitleRow[i]) {
798             printf("%s\n", titleRowVal[i]);
799         }
800 
801         getFilesInDir(directories[i], &files);
802 
803         for (auto &file : files) {
804             fileLocation = std::string(directories[i]) + std::string(file);
805             if (!android::base::ReadFileToString(fileLocation, &content)) {
806                 continue;
807             }
808 
809             readout = android::base::Trim(content);
810 
811             if (strncmp(file.c_str(), vimon_name, vimon_len) == 0)
812                 vimon_found = true;
813 
814             subModuleName = std::string(file);
815             subModuleName.erase(subModuleName.find(paramSuffix[i]), eraseCnt[i]);
816 
817             if (useTitleRow[i]) {
818                 printf("%s \t%s\n", subModuleName.c_str(), readout.c_str());
819             } else if (vimon_found) {
820 
821                 std::vector<std::string> tokens;
822                 std::istringstream tokenStream(readout);
823                 std::string token;
824 
825                 while (std::getline(tokenStream, token, delimiter)) {
826                     tokens.push_back(token);
827                 }
828 
829                 bool oddEntry = true;
830                 for (auto &hexval : tokens) {
831                     int val = strtol(hexval.c_str(), &endptr, 16);
832                     if (*endptr != '\0') {
833                         printf("invalid vimon readout\n");
834                         break;
835                     }
836                     if (oddEntry) {
837                         int vbatt = int(1000 * (val * VIMON_VMULT));
838                         printf("vimon vbatt: %d ", vbatt);
839                     } else {
840                         int ibatt = int(1000 * (val * VIMON_IMULT));
841                         printf("ibatt: %d\n", ibatt);
842                     }
843                     oddEntry = !oddEntry;
844                 }
845             } else {
846                 printf("%s=%s\n", subModuleName.c_str(), readout.c_str());
847             }
848         }
849     }
850 }
851 
dumpIrqDurationCounts()852 void dumpIrqDurationCounts() {
853     const char *title = "IRQ Duration Counts";
854     const char *colNames = "Source\t\t\t\tlt_5ms_cnt\tbt_5ms_to_10ms_cnt\tgt_10ms_cnt\tCode"
855             "\tCurrent Threshold (uA)\tCurrent Reading (uA)\n";
856     const int nonOdpmChannelCnt = 12;
857     const int odpmChCnt = 12;
858 
859     enum Duration {
860         LT_5MS,
861         BT_5MS_10MS,
862         GT_10MS,
863         DUR_MAX,
864     };
865     const char *irqDurDirectories[] = {
866             "/sys/devices/virtual/pmic/mitigation/irq_dur_cnt/less_than_5ms_count",
867             "/sys/devices/virtual/pmic/mitigation/irq_dur_cnt/between_5ms_to_10ms_count",
868             "/sys/devices/virtual/pmic/mitigation/irq_dur_cnt/greater_than_10ms_count",
869     };
870 
871     enum PowerWarn {
872         MAIN,
873         SUB,
874         PWRWARN_MAX,
875     };
876     const char *pwrwarnDirectories[] = {
877             "/sys/devices/virtual/pmic/mitigation/main_pwrwarn/",
878             "/sys/devices/virtual/pmic/mitigation/sub_pwrwarn/",
879     };
880 
881     const char *lpfCurrentDirs[] = {
882             "/sys/devices/platform/acpm_mfd_bus@15500000/i2c-7/7-001f/s2mpg14-meter/"
883                     "s2mpg14-odpm/iio:device1/lpf_current",
884             "/sys/devices/platform/acpm_mfd_bus@15510000/i2c-8/8-002f/s2mpg15-meter/"
885                     "s2mpg15-odpm/iio:device0/lpf_current",
886     };
887 
888     const char *lpfCurrentDirsAlt[] = {
889             "/sys/devices/platform/acpm_mfd_bus@15500000/i2c-7/7-001f/s2mpg14-meter/"
890                     "s2mpg14-odpm/iio:device0/lpf_current",
891             "/sys/devices/platform/acpm_mfd_bus@15510000/i2c-8/8-002f/s2mpg15-meter/"
892                     "s2mpg15-odpm/iio:device1/lpf_current",
893     };
894 
895     bool titlesInitialized = false;
896 
897     std::vector<std::string> channelNames;
898     std::vector<std::string> channelData[DUR_MAX];
899     std::vector<std::string> pwrwarnThreshold[PWRWARN_MAX];
900     std::vector<std::string> pwrwarnCode[PWRWARN_MAX];
901     std::vector<std::string> lpfCurrentVals[PWRWARN_MAX];
902     std::vector<std::string> files;
903 
904     std::string content;
905     std::string token;
906     std::string tokenCh;
907     std::string fileLocation;
908 
909     for (int i = 0; i < DUR_MAX; i++) {
910         if (!android::base::ReadFileToString(irqDurDirectories[i], &content)) {
911             return;
912         }
913 
914         std::istringstream tokenStream(content);
915 
916         while (std::getline(tokenStream, token, '\n')) {
917             if (!titlesInitialized) {
918                 tokenCh = token;
919                 tokenCh.erase(tokenCh.find(':'), tokenCh.length());
920                 channelNames.push_back(tokenCh);
921             }
922 
923             // there is a space after the ':' which needs to be removed
924             token.erase(0, token.find(':') + 1);
925             channelData[i].push_back(token);
926 
927         }
928         if (!titlesInitialized)
929             titlesInitialized = true;
930     }
931 
932     for (int i = 0; i < PWRWARN_MAX; i++) {
933         getFilesInDir(pwrwarnDirectories[i], &files);
934 
935         for (auto &file : files) {
936             fileLocation = std::string(pwrwarnDirectories[i]) + std::string(file);
937             if (!android::base::ReadFileToString(fileLocation, &content)) {
938                 continue;
939             }
940 
941             std::string readout;
942 
943             readout = android::base::Trim(content);
944 
945             std::string readoutThreshold = readout;
946             readoutThreshold.erase(0, readoutThreshold.find('=') + 1);
947 
948             std::string readoutCode = readout;
949             readoutCode.erase(readoutCode.find('='), readoutCode.length());
950 
951             pwrwarnThreshold[i].push_back(readoutThreshold);
952             pwrwarnCode[i].push_back(readoutCode);
953         }
954     }
955 
956     for (int i = 0; i < PWRWARN_MAX; i++) {
957         if (!android::base::ReadFileToString(lpfCurrentDirs[i], &content) &&
958             !android::base::ReadFileToString(lpfCurrentDirsAlt[i], &content)) {
959             printf("Cannot find %s\n", lpfCurrentDirs[i]);
960             continue;
961         }
962 
963         std::istringstream tokenStream(content);
964 
965         bool first = true;
966         while (std::getline(tokenStream, token, '\n')) {
967             token.erase(0, token.find(' '));
968             if (first) {
969                 first = false;
970                 continue;
971             }
972             lpfCurrentVals[i].push_back(token);
973         }
974     }
975 
976     printTitle(title);
977     printf("%s", colNames);
978 
979     for (uint i = 0; i < channelNames.size(); i++) {
980         std::string code = "";
981         std::string threshold = "";
982         std::string current = "";
983         std::string ltDataMsg = "";
984         std::string btDataMsg = "";
985         std::string gtDataMsg = "";
986         int pmicSel = 0;
987         int offset = 0;
988         std::string channelNameSuffix = "      \t";
989         if (i >= nonOdpmChannelCnt) {
990             offset = nonOdpmChannelCnt;
991             if (i >= (odpmChCnt + nonOdpmChannelCnt)) {
992                 pmicSel = 1;
993                 offset = odpmChCnt + nonOdpmChannelCnt;
994             }
995             channelNameSuffix = "";
996 
997             if (pmicSel >= PWRWARN_MAX) {
998                 printf("invalid index: pmicSel >= pwrwarnCode size\n");
999                 return;
1000             }
1001 
1002             if (i - offset >= pwrwarnCode[pmicSel].size()) {
1003                 printf("invalid index: i - offset >= pwrwarnCode size\n");
1004                 return;
1005             }
1006             code = pwrwarnCode[pmicSel][i - offset];
1007 
1008             if (i - offset >= pwrwarnThreshold[pmicSel].size()) {
1009                 printf("invalid index: i - offset >= pwrwarnThreshold size\n");
1010                 return;
1011             }
1012             threshold = pwrwarnThreshold[pmicSel][i - offset];
1013 
1014             if (i - offset >= lpfCurrentVals[pmicSel].size()) {
1015                 printf("invalid index: i - offset >= lpfCurrentVals size\n");
1016                 return;
1017             }
1018             current = lpfCurrentVals[pmicSel][i - offset];
1019         }
1020 
1021         if (i < channelData[0].size())
1022             ltDataMsg = channelData[0][i];
1023 
1024         if (i < channelData[1].size())
1025             btDataMsg = channelData[1][i];
1026 
1027         if (i < channelData[2].size())
1028             gtDataMsg = channelData[2][i];
1029 
1030         std::string adjustedChannelName = channelNames[i] + channelNameSuffix;
1031         printf("%s     \t%s\t\t%s\t\t\t%s\t\t%s    \t%s       \t\t%s\n",
1032                 adjustedChannelName.c_str(),
1033                 ltDataMsg.c_str(),
1034                 btDataMsg.c_str(),
1035                 gtDataMsg.c_str(),
1036                 code.c_str(),
1037                 threshold.c_str(),
1038                 current.c_str());
1039     }
1040 }
1041 
dumpEvtCounter()1042 void dumpEvtCounter() {
1043     const char* title = "Event Counter";
1044     const char* evtCntDir = "/sys/devices/virtual/pmic/mitigation/instruction/";
1045 
1046     const char* evtCnt [][2] {
1047             {"batoilo1", "evt_cnt_batoilo1"},
1048             {"batoilo2", "evt_cnt_batoilo2"},
1049             {"uvlo1", "evt_cnt_uvlo1"},
1050             {"uvlo2", "evt_cnt_uvlo2"},
1051     };
1052 
1053     printTitle(title);
1054     printf("name\tcount\n");
1055 
1056     for (const auto &row : evtCnt) {
1057         std::string name = row[0];
1058         std::string fileLocation = std::string(evtCntDir) + std::string(row[1]);
1059         std::string count = "N/A\n";
1060         if (!android::base::ReadFileToString(fileLocation, &count)) {
1061             count = "invalid\n";
1062         }
1063 
1064         printf("%s\t%s", name.c_str(), count.c_str());
1065     }
1066 }
1067 
main()1068 int main() {
1069     dumpPowerStatsTimes();
1070     dumpAcpmStats();
1071     dumpPowerSupplyStats();
1072     dumpMaxFg();
1073     dumpPowerSupplyDock();
1074     dumpLogBufferTcpm();
1075     dumpTcpc();
1076     dumpPdEngine();
1077     dumpBatteryHealth();
1078     dumpBatteryDefend();
1079     dumpChg();
1080     dumpChgUserDebug();
1081     dumpBatteryEeprom();
1082     dumpChargerStats();
1083     dumpWlcLogs();
1084     dumpGvoteables();
1085     dumpMitigation();
1086     dumpMitigationStats();
1087     dumpMitigationDirs();
1088     dumpIrqDurationCounts();
1089     dumpEvtCounter();
1090 }
1091 
1092