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