1 
2 /*
3  * Copyright 2023 The Android Open Source Project
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  *      http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
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 <time.h>
25 #include <vector>
26 #include <android-base/file.h>
27 #include <android-base/strings.h>
28 #include "DumpstateUtil.h"
printTitle(const char * msg)29 void printTitle(const char *msg) {
30     printf("\n------ %s ------\n", msg);
31 }
getCommandOutput(const char * cmd,std::string * output)32 int getCommandOutput(const char *cmd, std::string *output) {
33     char buffer[1024];
34     FILE *pipe = popen(cmd, "r");
35     if (!pipe) {
36         return -1;
37     }
38     while (fgets(buffer, sizeof buffer, pipe) != NULL) {
39         *output += buffer;
40     }
41     pclose(pipe);
42     if (output->back() == '\n')
43         output->pop_back();
44     return 0;
45 }
isValidFile(const char * file)46 bool isValidFile(const char *file) {
47     FILE *fp = fopen(file, "r");
48     if (fp != NULL) {
49         fclose(fp);
50         return true;
51     }
52     return false;
53 }
isValidDir(const char * directory)54 bool isValidDir(const char *directory) {
55     DIR *dir = opendir(directory);
56     if (dir == NULL)
57         return false;
58 
59     closedir(dir);
60     return true;
61 }
isUserBuild()62 bool isUserBuild() {
63     return ::android::os::dumpstate::PropertiesHelper::IsUserBuild();
64 }
getFilesInDir(const char * directory,std::vector<std::string> * files)65 int getFilesInDir(const char *directory, std::vector<std::string> *files) {
66     std::string content;
67     struct dirent *entry;
68     DIR *dir = opendir(directory);
69     if (dir == NULL)
70         return -1;
71     files->clear();
72     while ((entry = readdir(dir)) != NULL)
73         files->push_back(entry->d_name);
74     closedir(dir);
75     sort(files->begin(), files->end());
76     return 0;
77 }
dumpPowerStatsTimes()78 void dumpPowerStatsTimes() {
79     const char *title = "Power Stats Times";
80     char rBuff[128];
81     struct timespec rTs;
82     struct sysinfo info;
83     int ret;
84     printTitle(title);
85     sysinfo(&info);
86     const time_t boottime = time(NULL) - info.uptime;
87     ret = clock_gettime(CLOCK_REALTIME, &rTs);
88     if (ret)
89         return;
90     struct tm *nowTime = std::localtime(&rTs.tv_sec);
91     std::strftime(rBuff, sizeof(rBuff), "%m/%d/%Y %H:%M:%S", nowTime);
92     printf("Boot: %s", ctime(&boottime));
93     printf("Now: %s\n", rBuff);
94 }
readContentsOfDir(const char * title,const char * directory,const char * strMatch,bool useStrMatch=false,bool printDirectory=false)95 int readContentsOfDir(const char* title, const char* directory, const char* strMatch,
96         bool useStrMatch = false, bool printDirectory = false) {
97     std::vector<std::string> files;
98     std::string content;
99     std::string fileLocation;
100     int ret;
101     ret = getFilesInDir(directory, &files);
102     if (ret < 0)
103         return ret;
104     printTitle(title);
105     for (auto &file : files) {
106         if (useStrMatch && std::string::npos == std::string(file).find(strMatch)) {
107             continue;
108         }
109         fileLocation = std::string(directory) + std::string(file);
110         if (!android::base::ReadFileToString(fileLocation, &content)) {
111             continue;
112         }
113         if (printDirectory) {
114             printf("\n\n%s\n", fileLocation.c_str());
115         }
116         if (content.back() == '\n')
117             content.pop_back();
118         printf("%s\n", content.c_str());
119     }
120     return 0;
121 }
dumpAcpmStats()122 void dumpAcpmStats() {
123     const char* acpmDir = "/sys/devices/platform/acpm_stats/";
124     const char* statsSubStr = "_stats";
125     const char* acpmTitle = "ACPM stats";
126     readContentsOfDir(acpmTitle, acpmDir, statsSubStr, true, true);
127 }
dumpPowerSupplyStats()128 void dumpPowerSupplyStats() {
129     const char* dumpList[][2] = {
130             {"CPU PM stats", "/sys/devices/system/cpu/cpupm/cpupm/time_in_state"},
131             {"Power supply property battery", "/sys/class/power_supply/battery/uevent"},
132             {"Power supply property dc", "/sys/class/power_supply/dc/uevent"},
133             {"Power supply property gcpm", "/sys/class/power_supply/gcpm/uevent"},
134             {"Power supply property gcpm_pps", "/sys/class/power_supply/gcpm_pps/uevent"},
135             {"Power supply property main-charger", "/sys/class/power_supply/main-charger/uevent"},
136             {"Power supply property pca9468-mains", "/sys/class/power_supply/pca9468-mains/uevent"},
137             {"Power supply property tcpm", "/sys/class/power_supply/tcpm-source-psy-i2c-max77759tcpc/uevent"},
138             {"Power supply property usb", "/sys/class/power_supply/usb/uevent"},
139             {"Power supply property wireless", "/sys/class/power_supply/wireless/uevent"},
140     };
141     for (const auto &row : dumpList) {
142         dumpFileContent(row[0], row[1]);
143     }
144 }
dumpMaxFg()145 void dumpMaxFg() {
146     const char *maxfgLoc = "/sys/class/power_supply/maxfg";
147     const char *maxfg [][2] = {
148             {"Power supply property maxfg", "/sys/class/power_supply/maxfg/uevent"},
149             {"m5_state", "/sys/class/power_supply/maxfg/m5_model_state"},
150             {"maxfg registers", "/sys/class/power_supply/maxfg/registers_dump"},
151             {"maxfg logbuffer", "/dev/logbuffer_maxfg"},
152             {"maxfg_monitor logbuffer", "/dev/logbuffer_maxfg_monitor"},
153     };
154     std::string content;
155     if (isValidDir(maxfgLoc)) {
156         for (const auto &row : maxfg) {
157             dumpFileContent(row[0], row[1]);
158         }
159     }
160 }
dumpPowerSupplyDock()161 void dumpPowerSupplyDock() {
162     const char* powerSupplyPropertyDockTitle = "Power supply property dock";
163     const char* powerSupplyPropertyDockFile = "/sys/class/power_supply/dock/uevent";
164     dumpFileContent(powerSupplyPropertyDockTitle, powerSupplyPropertyDockFile);
165 }
dumpLogBufferTcpm()166 void dumpLogBufferTcpm() {
167     const char* logbufferTcpmTitle = "Logbuffer TCPM";
168     const char* logbufferTcpmFile = "/dev/logbuffer_tcpm";
169     const char* debugTcpmFile = "/sys/kernel/debug/tcpm";
170     const char* tcpmLogTitle = "TCPM logs";
171     const char* tcpmFile = "/sys/kernel/debug/tcpm";
172     const char* tcpmFileAlt = "/sys/kernel/debug/usb/tcpm";
173     int retCode;
174     dumpFileContent(logbufferTcpmTitle, logbufferTcpmFile);
175     retCode = readContentsOfDir(tcpmLogTitle, isValidFile(debugTcpmFile) ? tcpmFile : tcpmFileAlt,
176             NULL);
177     if (retCode < 0)
178         printTitle(tcpmLogTitle);
179 }
dumpTcpc()180 void dumpTcpc() {
181     int ret;
182     const char* max77759TcpcHead = "TCPC";
183     const char* i2cSubDirMatch = "i2c-";
184     const char* directory = "/sys/devices/platform/10d60000.hsi2c/";
185     const char* max77759Tcpc [][2] {
186             {"registers:", "/i2c-max77759tcpc/registers"},
187             {"frs:", "/i2c-max77759tcpc/frs"},
188             {"auto_discharge:", "/i2c-max77759tcpc/auto_discharge"},
189             {"bcl2_enabled:", "/i2c-max77759tcpc/bcl2_enabled"},
190             {"cc_toggle_enable:", "/i2c-max77759tcpc/cc_toggle_enable"},
191             {"containment_detection:", "/i2c-max77759tcpc/containment_detection"},
192             {"containment_detection_status:", "/i2c-max77759tcpc/containment_detection_status"},
193     };
194     std::vector<std::string> files;
195     std::string content;
196     printTitle(max77759TcpcHead);
197     ret = getFilesInDir(directory, &files);
198     if (ret < 0) {
199         for (auto &tcpcVal : max77759Tcpc)
200             printf("%s\n", tcpcVal[0]);
201         return;
202     }
203     for (auto &file : files) {
204         for (auto &tcpcVal : max77759Tcpc) {
205             printf("%s ", tcpcVal[0]);
206             if (std::string::npos == std::string(file).find(i2cSubDirMatch)) {
207                 continue;
208             }
209             std::string fileName = directory + file + "/" + std::string(tcpcVal[1]);
210             if (!android::base::ReadFileToString(fileName, &content)) {
211                 continue;
212             }
213             printf("%s\n", content.c_str());
214         }
215     }
216 }
dumpPdEngine()217 void dumpPdEngine() {
218     const char* pdEngine [][2] {
219             {"PD Engine", "/dev/logbuffer_usbpd"},
220             {"PPS-google_cpm logbuffer", "/dev/logbuffer_cpm"},
221             {"PPS-pca9468 logbuffer", "/dev/logbuffer_pca9468"},
222     };
223     for (const auto &row : pdEngine) {
224         dumpFileContent(row[0], row[1]);
225     }
226 }
dumpBatteryHealth()227 void dumpBatteryHealth() {
228     const char* batteryHealth [][2] {
229             {"Battery Health", "/sys/class/power_supply/battery/health_index_stats"},
230             {"Battery Health SoC Residency", "/sys/class/power_supply/battery/swelling_data"},
231             {"BMS", "/dev/logbuffer_ssoc"},
232             {"TTF", "/dev/logbuffer_ttf"},
233             {"TTF details", "/sys/class/power_supply/battery/ttf_details"},
234             {"TTF stats", "/sys/class/power_supply/battery/ttf_stats"},
235             {"aacr_state", "/sys/class/power_supply/battery/aacr_state"},
236             {"maxq", "/dev/logbuffer_maxq"},
237             {"TEMP/DOCK-DEFEND", "/dev/logbuffer_bd"},
238     };
239     for (const auto &row : batteryHealth) {
240         dumpFileContent(row[0], row[1]);
241     }
242 }
dumpBatteryDefend()243 void dumpBatteryDefend() {
244     const char* defendConfig [][3] {
245             {"TRICKLE-DEFEND Config",
246                     "/sys/devices/platform/google,battery/power_supply/battery/", "bd_"},
247             {"DWELL-DEFEND Config", "/sys/devices/platform/google,charger/", "charge_s"},
248             {"TEMP-DEFEND Config", "/sys/devices/platform/google,charger/", "bd_"},
249     };
250     std::vector<std::string> files;
251     struct dirent *entry;
252     std::string content;
253     std::string fileLocation;
254     for (auto &config : defendConfig) {
255         DIR *dir = opendir(config[1]);
256         if (dir == NULL)
257             continue;
258         printTitle(config[0]);
259         while ((entry = readdir(dir)) != NULL) {
260             if (std::string(entry->d_name).find(config[2]) != std::string::npos &&
261                     strncmp(config[2], entry->d_name, strlen(config[2])) == 0) {
262                 files.push_back(entry->d_name);
263             }
264         }
265         closedir(dir);
266         sort(files.begin(), files.end());
267         for (auto &file : files) {
268             fileLocation = std::string(config[1]) + std::string(file);
269             if (!android::base::ReadFileToString(fileLocation, &content) || content.empty()) {
270                 content = "\n";
271             }
272             printf("%s: %s", file.c_str(), content.c_str());
273             if (content.back() != '\n')
274                 printf("\n");
275         }
276         files.clear();
277     }
278 }
dumpBatteryCaretaker()279 void dumpBatteryCaretaker() {
280     const char* aacpConfig [][3] {
281             {"AACP Version",
282                     "/sys/devices/platform/google,battery/power_supply/battery/", "aacp_"},
283             {"AACR Config",
284                     "/sys/devices/platform/google,battery/power_supply/battery/", "aacr_"},
285             {"AAFV Config",
286                     "/sys/devices/platform/google,battery/power_supply/battery/", "aafv_"},
287             {"AACT Config",
288                     "/sys/devices/platform/google,battery/power_supply/battery/", "aact_"},
289             {"AACC",
290                     "/sys/devices/platform/google,battery/power_supply/battery/", "aacc"},
291     };
292     std::vector<std::string> files;
293     struct dirent *entry;
294     std::string content;
295     std::string fileLocation;
296     for (auto &config : aacpConfig) {
297         DIR *dir = opendir(config[1]);
298         if (dir == NULL)
299             continue;
300         printTitle(config[0]);
301         while ((entry = readdir(dir)) != NULL) {
302             if (std::string(entry->d_name).find(config[2]) != std::string::npos &&
303                     strncmp(config[2], entry->d_name, strlen(config[2])) == 0) {
304                 files.push_back(entry->d_name);
305             }
306         }
307         closedir(dir);
308         sort(files.begin(), files.end());
309         for (auto &file : files) {
310             fileLocation = std::string(config[1]) + std::string(file);
311             if (!android::base::ReadFileToString(fileLocation, &content) || content.empty()) {
312                 content = "\n";
313             }
314             printf("%s: %s", file.c_str(), content.c_str());
315             if (content.back() != '\n')
316                 printf("\n");
317         }
318         files.clear();
319     }
320 }
printValuesOfDirectory(const char * directory,std::string debugfs,const char * strMatch)321 void printValuesOfDirectory(const char *directory, std::string debugfs, const char *strMatch) {
322     std::vector<std::string> files;
323     auto info = directory;
324     std::string content;
325     struct dirent *entry;
326     DIR *dir = opendir(debugfs.c_str());
327     if (dir == NULL)
328         return;
329 
330     printTitle((debugfs + std::string(strMatch) + "/" + std::string(info)).c_str());
331     while ((entry = readdir(dir)) != NULL)
332         if (std::string(entry->d_name).find(strMatch) != std::string::npos)
333             files.push_back(entry->d_name);
334     closedir(dir);
335 
336     sort(files.begin(), files.end());
337 
338     for (auto &file : files) {
339         std::string fileDirectory = debugfs + file;
340         std::string fileLocation = fileDirectory + "/" + std::string(info);
341         if (!android::base::ReadFileToString(fileLocation, &content)) {
342             content = "\n";
343         }
344 
345         printf("%s:\n%s", fileDirectory.c_str(), content.c_str());
346 
347         if (content.back() != '\n')
348             printf("\n");
349     }
350     files.clear();
351 }
dumpChg()352 void dumpChg() {
353     const std::string pmic_bus = "/sys/devices/platform/10d50000.hsi2c/i2c-12/12-0066";
354     const char* chg_reg_dump_file = "/sys/class/power_supply/main-charger/device/registers_dump";
355     const std::string chg_name_cmd = "/sys/class/power_supply/main-charger/device/name";
356     const std::string pmic_name_cmd = pmic_bus + "/name";
357     const std::string pmic_reg_dump_file = pmic_bus + "/registers_dump";
358     const std::string reg_dump_str = " registers dump";
359     const char* chgConfig [][2] {
360         {"DC_registers dump", "/sys/class/power_supply/pca9468-mains/device/registers_dump"},
361     };
362     std::string chg_name;
363     std::string pmic_name;
364 
365     printf("\n");
366 
367     int ret = android::base::ReadFileToString(chg_name_cmd, &chg_name);
368     if (ret && !chg_name.empty()) {
369         chg_name.erase(chg_name.length() - 1); // remove new line
370         const std::string chg_reg_dump_title = chg_name + reg_dump_str;
371 
372         /* CHG reg dump */
373         dumpFileContent(chg_reg_dump_title.c_str(), chg_reg_dump_file);
374     }
375 
376     ret = android::base::ReadFileToString(pmic_name_cmd, &pmic_name);
377     if (ret && !pmic_name.empty()) {
378         pmic_name.erase(pmic_name.length() - 1); // remove new line
379         const std::string pmic_reg_dump_title = pmic_name + reg_dump_str;
380 
381         /* PMIC reg dump */
382         dumpFileContent(pmic_reg_dump_title.c_str(), pmic_reg_dump_file.c_str());
383     }
384 
385     for (auto &config : chgConfig) {
386         dumpFileContent(config[0], config[1]);
387     }
388 }
dumpChgUserDebug()389 void dumpChgUserDebug() {
390     const std::string debugfs = "/d/";
391     const char *maxFgDir = "/d/maxfg";
392     const char *maxFgStrMatch = "maxfg";
393     const char *chgTblName = "Charging table dump";
394     const char *chgTblDir = "/d/google_battery/chg_raw_profile";
395 
396     const char *maxFgInfo [] {
397             "fg_model",
398             "algo_ver",
399             "model_ok",
400     };
401 
402     if (isUserBuild())
403         return;
404 
405     dumpFileContent(chgTblName, chgTblDir);
406 
407     if (isValidDir(maxFgDir)) {
408         for (auto & directory : maxFgInfo) {
409             printValuesOfDirectory(directory, debugfs, maxFgStrMatch);
410         }
411     }
412 }
dumpBatteryEeprom()413 void dumpBatteryEeprom() {
414     const char *title = "Battery EEPROM";
415     const char *files[] {
416             "/sys/devices/platform/10970000.hsi2c/i2c-8/8-0050/eeprom",
417     };
418     std::string result;
419     std::string xxdCmd;
420     printTitle(title);
421     for (auto &file : files) {
422         if (!isValidFile(file))
423             continue;
424         xxdCmd = "xxd " + std::string(file);
425         int ret = getCommandOutput(xxdCmd.c_str(), &result);
426         if (ret < 0)
427             return;
428         printf("%s\n", result.c_str());
429     }
430 }
dumpChargerStats()431 void dumpChargerStats() {
432     const char *chgStatsTitle = "Charger Stats";
433     const char *chgStatsLocation = "/sys/class/power_supply/battery/charge_details";
434     const char *chargerStats [][3] {
435             {"Google Charger", "/sys/kernel/debug/google_charger/", "pps_"},
436             {"Google Battery", "/sys/kernel/debug/google_battery/", "ssoc_"},
437     };
438     std::vector<std::string> files;
439     std::string content;
440     struct dirent *entry;
441     dumpFileContent(chgStatsTitle, chgStatsLocation);
442     if (isUserBuild())
443         return;
444     for (auto &stat : chargerStats) {
445         DIR *dir = opendir(stat[1]);
446         if (dir == NULL)
447             return;
448         printTitle(stat[0]);
449         while ((entry = readdir(dir)) != NULL)
450             if (std::string(entry->d_name).find(stat[2]) != std::string::npos)
451                 files.push_back(entry->d_name);
452         closedir(dir);
453         sort(files.begin(), files.end());
454         for (auto &file : files) {
455             std::string fileLocation = std::string(stat[1]) + file;
456             if (!android::base::ReadFileToString(fileLocation, &content)) {
457                 content = "\n";
458             }
459             printf("%s: %s", file.c_str(), content.c_str());
460             if (content.back() != '\n')
461                 printf("\n");
462         }
463         files.clear();
464     }
465 }
dumpWlcLogs()466 void dumpWlcLogs() {
467     const char *dumpWlcList [][2] {
468             {"WLC Logs", "/dev/logbuffer_wireless"},
469             {"WLC VER", "/sys/class/power_supply/wireless/device/version"},
470             {"WLC STATUS", "/sys/class/power_supply/wireless/device/status"},
471             {"WLC FW Version", "/sys/class/power_supply/wireless/device/fw_rev"},
472             {"RTX", "/dev/logbuffer_rtx"},
473     };
474     for (auto &row : dumpWlcList) {
475         if (!isValidFile(row[1]))
476             printTitle(row[0]);
477         dumpFileContent(row[0], row[1]);
478     }
479 }
dumpGvoteables()480 void dumpGvoteables() {
481     const char *directory = "/sys/kernel/debug/gvotables/";
482     const char *statusName = "/status";
483     const char *title = "gvotables";
484     std::string content;
485     std::vector<std::string> files;
486     int ret;
487     if (isUserBuild())
488         return;
489     ret = getFilesInDir(directory, &files);
490     if (ret < 0)
491         return;
492     printTitle(title);
493     for (auto &file : files) {
494         std::string fileLocation = std::string(directory) + file + std::string(statusName);
495         if (!android::base::ReadFileToString(fileLocation, &content)) {
496             continue;
497         }
498         printf("%s: %s", file.c_str(), content.c_str());
499         if (content.back() != '\n')
500             printf("\n");
501     }
502     files.clear();
503 }
dumpMitigation()504 void dumpMitigation() {
505     const char *mitigationList [][2] {
506             {"Lastmeal" , "/data/vendor/mitigation/lastmeal.txt"},
507             {"Thismeal" , "/data/vendor/mitigation/thismeal.txt"},
508     };
509     for (auto &row : mitigationList) {
510         if (!isValidFile(row[1]))
511             printTitle(row[0]);
512         dumpFileContent(row[0], row[1]);
513     }
514 }
dumpMitigationStats()515 void dumpMitigationStats() {
516     int ret;
517     const char *directory = "/sys/devices/virtual/pmic/mitigation/last_triggered_count/";
518     const char *capacityDirectory = "/sys/devices/virtual/pmic/mitigation/last_triggered_capacity/";
519     const char *timestampDirectory =
520             "/sys/devices/virtual/pmic/mitigation/last_triggered_timestamp/";
521     const char *voltageDirectory = "/sys/devices/virtual/pmic/mitigation/last_triggered_voltage/";
522     const char *capacitySuffix = "_cap";
523     const char *timeSuffix = "_time";
524     const char *voltageSuffix = "_volt";
525     const char *countSuffix = "_count";
526     const char *title = "Mitigation Stats";
527     std::vector<std::string> files;
528     std::string content;
529     std::string fileLocation;
530     std::string source;
531     std::string subModuleName;
532     int count;
533     int soc;
534     int time;
535     int voltage;
536     ret = getFilesInDir(directory, &files);
537     if (ret < 0)
538         return;
539     printTitle(title);
540     printf("Source\t\tCount\tSOC\tTime\tVoltage\n");
541     for (auto &file : files) {
542         fileLocation = std::string(directory) + std::string(file);
543         if (!android::base::ReadFileToString(fileLocation, &content)) {
544             continue;
545         }
546         ret = atoi(android::base::Trim(content).c_str());
547         if (ret == -1)
548             continue;
549         count = ret;
550         subModuleName = std::string(file);
551         subModuleName.erase(subModuleName.find(countSuffix), strlen(countSuffix));
552         fileLocation = std::string(capacityDirectory) + std::string(subModuleName) +
553                 std::string(capacitySuffix);
554         if (!android::base::ReadFileToString(fileLocation, &content)) {
555             continue;
556         }
557         ret = atoi(android::base::Trim(content).c_str());
558         if (ret == -1)
559             continue;
560         soc = ret;
561         fileLocation = std::string(timestampDirectory) + std::string(subModuleName) +
562                 std::string(timeSuffix);
563         if (!android::base::ReadFileToString(fileLocation, &content)) {
564             continue;
565         }
566         ret = atoi(android::base::Trim(content).c_str());
567         if (ret == -1)
568             continue;
569         time = ret;
570         fileLocation = std::string(voltageDirectory) + std::string(subModuleName) +
571                 std::string(voltageSuffix);
572         if (!android::base::ReadFileToString(fileLocation, &content)) {
573             continue;
574         }
575         ret = atoi(android::base::Trim(content).c_str());
576         if (ret == -1)
577             continue;
578         voltage = ret;
579         printf("%s \t%i\t%i\t%i\t%i\n", subModuleName.c_str(), count, soc, time, voltage);
580     }
581 }
dumpMitigationDirs()582 void dumpMitigationDirs() {
583     const int paramCount = 4;
584     const char *titles[] = {
585             "Clock Divider Ratio",
586             "Clock Stats",
587             "Triggered Level",
588             "Instruction",
589     };
590     const char *directories[] = {
591             "/sys/devices/virtual/pmic/mitigation/clock_ratio/",
592             "/sys/devices/virtual/pmic/mitigation/clock_stats/",
593             "/sys/devices/virtual/pmic/mitigation/triggered_lvl/",
594             "/sys/devices/virtual/pmic/mitigation/instruction/",
595     };
596     const char *paramSuffix[] = {"_ratio", "_stats", "_lvl", ""};
597     const char *titleRowVal[] = {
598             "Source\t\tRatio",
599             "Source\t\tStats",
600             "Source\t\tLevel",
601             "",
602     };
603     const int eraseCnt[] = {6, 6, 4, 0};
604     const bool useTitleRow[] = {true, true, true, false};
605     std::vector<std::string> files;
606     std::string content;
607     std::string fileLocation;
608     std::string source;
609     std::string subModuleName;
610     std::string readout;
611     for (int i = 0; i < paramCount; i++) {
612         printTitle(titles[i]);
613         if (useTitleRow[i]) {
614             printf("%s\n", titleRowVal[i]);
615         }
616         getFilesInDir(directories[i], &files);
617         for (auto &file : files) {
618             fileLocation = std::string(directories[i]) + std::string(file);
619             if (!android::base::ReadFileToString(fileLocation, &content)) {
620                 continue;
621             }
622             readout = android::base::Trim(content);
623             subModuleName = std::string(file);
624             subModuleName.erase(subModuleName.find(paramSuffix[i]), eraseCnt[i]);
625             if (useTitleRow[i]) {
626                 printf("%s \t%s\n", subModuleName.c_str(), readout.c_str());
627             } else {
628                 printf("%s=%s\n", subModuleName.c_str(), readout.c_str());
629             }
630         }
631     }
632 }
dumpIrqDurationCounts()633 void dumpIrqDurationCounts() {
634     const char *title = "IRQ Duration Counts";
635     const char *colNames = "Source\t\t\t\tlt_5ms_cnt\tbt_5ms_to_10ms_cnt\tgt_10ms_cnt\tCode"
636             "\tCurrent Threshold (uA)\tCurrent Reading (uA)\n";
637     const int nonOdpmChannelCnt = 9;
638     const int odpmChCnt = 12;
639     enum Duration {
640         LT_5MS,
641         BT_5MS_10MS,
642         GT_10MS,
643         DUR_MAX,
644     };
645     const char *irqDurDirectories[] = {
646             "/sys/devices/virtual/pmic/mitigation/irq_dur_cnt/less_than_5ms_count",
647             "/sys/devices/virtual/pmic/mitigation/irq_dur_cnt/between_5ms_to_10ms_count",
648             "/sys/devices/virtual/pmic/mitigation/irq_dur_cnt/greater_than_10ms_count",
649     };
650     enum PowerWarn {
651         MAIN,
652         SUB,
653         PWRWARN_MAX,
654     };
655     const char *pwrwarnDirectories[] = {
656             "/sys/devices/virtual/pmic/mitigation/main_pwrwarn/",
657             "/sys/devices/virtual/pmic/mitigation/sub_pwrwarn/",
658     };
659     const char *lpfCurrentDirs[] = {
660             "/sys/devices/platform/acpm_mfd_bus@15500000/i2c-1/1-001f/s2mpg14-meter/"
661                     "s2mpg14-odpm/iio:device1/lpf_current",
662             "/sys/devices/platform/acpm_mfd_bus@15510000/i2c-0/0-002f/s2mpg15-meter/"
663                     "s2mpg15-odpm/iio:device0/lpf_current",
664     };
665     bool titlesInitialized = false;
666     std::vector<std::string> channelNames;
667     std::vector<std::string> channelData[DUR_MAX];
668     std::vector<std::string> pwrwarnThreshold[PWRWARN_MAX];
669     std::vector<std::string> pwrwarnCode[PWRWARN_MAX];
670     std::vector<std::string> lpfCurrentVals[PWRWARN_MAX];
671     std::vector<std::string> files;
672     std::string content;
673     std::string token;
674     std::string tokenCh;
675     std::string fileLocation;
676     for (int i = 0; i < DUR_MAX; i++) {
677         if (!android::base::ReadFileToString(irqDurDirectories[i], &content)) {
678             return;
679         }
680         std::istringstream tokenStream(content);
681         while (std::getline(tokenStream, token, '\n')) {
682             if (!titlesInitialized) {
683                 tokenCh = token;
684                 tokenCh.erase(tokenCh.find(':'), tokenCh.length());
685                 channelNames.push_back(tokenCh);
686             }
687             // there is a space after the ':' which needs to be removed
688             token.erase(0, token.find(':') + 1);
689             channelData[i].push_back(token);
690         }
691         if (!titlesInitialized)
692             titlesInitialized = true;
693     }
694     for (int i = 0; i < PWRWARN_MAX; i++) {
695         getFilesInDir(pwrwarnDirectories[i], &files);
696         for (auto &file : files) {
697             fileLocation = std::string(pwrwarnDirectories[i]) + std::string(file);
698             if (!android::base::ReadFileToString(fileLocation, &content)) {
699                 continue;
700             }
701             std::string readout;
702             readout = android::base::Trim(content);
703             std::string readoutThreshold = readout;
704             readoutThreshold.erase(0, readoutThreshold.find('=') + 1);
705             std::string readoutCode = readout;
706             readoutCode.erase(readoutCode.find('='), readoutCode.length());
707             pwrwarnThreshold[i].push_back(readoutThreshold);
708             pwrwarnCode[i].push_back(readoutCode);
709         }
710     }
711     for (int i = 0; i < PWRWARN_MAX; i++) {
712         if (!android::base::ReadFileToString(lpfCurrentDirs[i], &content)) {
713             continue;
714         }
715         std::istringstream tokenStream(content);
716         bool first = true;
717         while (std::getline(tokenStream, token, '\n')) {
718             token.erase(0, token.find(' '));
719             if (first) {
720                 first = false;
721                 continue;
722             }
723             lpfCurrentVals[i].push_back(token);
724         }
725     }
726     printTitle(title);
727     printf("%s", colNames);
728     for (uint i = 0; i < channelNames.size(); i++) {
729         std::string code = "";
730         std::string threshold = "";
731         std::string current = "";
732         std::string ltDataMsg = "";
733         std::string btDataMsg = "";
734         std::string gtDataMsg = "";
735         int pmicSel = 0;
736         int offset = 0;
737         std::string channelNameSuffix = "      \t";
738         if (i >= nonOdpmChannelCnt) {
739             offset = nonOdpmChannelCnt;
740             if (i >= (odpmChCnt + nonOdpmChannelCnt)) {
741                 pmicSel = 1;
742                 offset = odpmChCnt + nonOdpmChannelCnt;
743             }
744             channelNameSuffix = "";
745             code = pwrwarnCode[pmicSel][i - offset];
746             threshold = pwrwarnThreshold[pmicSel][i - offset];
747             current = lpfCurrentVals[pmicSel][i - offset];
748         }
749         if (i < channelData[0].size())
750             ltDataMsg = channelData[0][i];
751         if (i < channelData[1].size())
752             btDataMsg = channelData[1][i];
753         if (i < channelData[2].size())
754             gtDataMsg = channelData[2][i];
755         std::string adjustedChannelName = channelNames[i] + channelNameSuffix;
756         printf("%s     \t%s\t\t%s\t\t\t%s\t\t%s    \t%s       \t\t%s\n",
757                 adjustedChannelName.c_str(),
758                 ltDataMsg.c_str(),
759                 btDataMsg.c_str(),
760                 gtDataMsg.c_str(),
761                 code.c_str(),
762                 threshold.c_str(),
763                 current.c_str());
764     }
765 }
main()766 int main() {
767     dumpPowerStatsTimes();
768     dumpAcpmStats();
769     dumpPowerSupplyStats();
770     dumpMaxFg();
771     dumpPowerSupplyDock();
772     dumpLogBufferTcpm();
773     dumpTcpc();
774     dumpPdEngine();
775     dumpBatteryHealth();
776     dumpBatteryDefend();
777     dumpBatteryCaretaker();
778     dumpChg();
779     dumpChgUserDebug();
780     dumpBatteryEeprom();
781     dumpChargerStats();
782     dumpWlcLogs();
783     dumpGvoteables();
784     dumpMitigation();
785     dumpMitigationStats();
786     dumpMitigationDirs();
787     dumpIrqDurationCounts();
788 }
789