xref: /aosp_15_r20/system/dmesgd/dmesgd.cpp (revision 325a5df984070639bfcfcc2d7b58a6181e21cf50)
1*325a5df9SAndroid Build Coastguard Worker /*
2*325a5df9SAndroid Build Coastguard Worker  * Copyright 2022, The Android Open Source Project
3*325a5df9SAndroid Build Coastguard Worker  *
4*325a5df9SAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*325a5df9SAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*325a5df9SAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*325a5df9SAndroid Build Coastguard Worker  *
8*325a5df9SAndroid Build Coastguard Worker  *     http://www.apache.org/licenses/LICENSE-2.0
9*325a5df9SAndroid Build Coastguard Worker  *
10*325a5df9SAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*325a5df9SAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*325a5df9SAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*325a5df9SAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*325a5df9SAndroid Build Coastguard Worker  * limitations under the License.
15*325a5df9SAndroid Build Coastguard Worker  */
16*325a5df9SAndroid Build Coastguard Worker 
17*325a5df9SAndroid Build Coastguard Worker #include <sys/epoll.h>
18*325a5df9SAndroid Build Coastguard Worker #include <sys/types.h>
19*325a5df9SAndroid Build Coastguard Worker #include <unistd.h>
20*325a5df9SAndroid Build Coastguard Worker 
21*325a5df9SAndroid Build Coastguard Worker #include <array>
22*325a5df9SAndroid Build Coastguard Worker #include <set>
23*325a5df9SAndroid Build Coastguard Worker #include <string>
24*325a5df9SAndroid Build Coastguard Worker 
25*325a5df9SAndroid Build Coastguard Worker #include <android/os/DropBoxManager.h>
26*325a5df9SAndroid Build Coastguard Worker 
27*325a5df9SAndroid Build Coastguard Worker #include <android-base/file.h>
28*325a5df9SAndroid Build Coastguard Worker #include <android-base/logging.h>
29*325a5df9SAndroid Build Coastguard Worker #include <android-base/properties.h>
30*325a5df9SAndroid Build Coastguard Worker #include <android-base/strings.h>
31*325a5df9SAndroid Build Coastguard Worker 
32*325a5df9SAndroid Build Coastguard Worker #include "dmesg_parser.h"
33*325a5df9SAndroid Build Coastguard Worker 
34*325a5df9SAndroid Build Coastguard Worker // If there are too many reports, the device is horribly broken.
35*325a5df9SAndroid Build Coastguard Worker const unsigned int kMaxReports = 10;
36*325a5df9SAndroid Build Coastguard Worker 
37*325a5df9SAndroid Build Coastguard Worker const char kSentPath[] = "/data/misc/dmesgd/sent_reports.txt";
38*325a5df9SAndroid Build Coastguard Worker 
ReadSentReports()39*325a5df9SAndroid Build Coastguard Worker static std::set<std::string> ReadSentReports() {
40*325a5df9SAndroid Build Coastguard Worker     std::set<std::string> ret;
41*325a5df9SAndroid Build Coastguard Worker     std::string content;
42*325a5df9SAndroid Build Coastguard Worker     if (!android::base::ReadFileToString(kSentPath, &content)) {
43*325a5df9SAndroid Build Coastguard Worker         PLOG(ERROR) << kSentPath << " is empty";
44*325a5df9SAndroid Build Coastguard Worker         return ret;
45*325a5df9SAndroid Build Coastguard Worker     }
46*325a5df9SAndroid Build Coastguard Worker     auto lines = android::base::Split(content, "\n");
47*325a5df9SAndroid Build Coastguard Worker     for (auto line : lines) {
48*325a5df9SAndroid Build Coastguard Worker         ret.insert(line);
49*325a5df9SAndroid Build Coastguard Worker     }
50*325a5df9SAndroid Build Coastguard Worker     LOG(ERROR) << "Read " << ret.size() << " records from " << kSentPath;
51*325a5df9SAndroid Build Coastguard Worker     return ret;
52*325a5df9SAndroid Build Coastguard Worker }
53*325a5df9SAndroid Build Coastguard Worker 
WriteSentReports(std::set<std::string> reports)54*325a5df9SAndroid Build Coastguard Worker static void WriteSentReports(std::set<std::string> reports) {
55*325a5df9SAndroid Build Coastguard Worker     if (!android::base::WriteStringToFile(android::base::Join(reports, ""), kSentPath)) {
56*325a5df9SAndroid Build Coastguard Worker         PLOG(ERROR) << "Failed to write to " << kSentPath;
57*325a5df9SAndroid Build Coastguard Worker     }
58*325a5df9SAndroid Build Coastguard Worker }
59*325a5df9SAndroid Build Coastguard Worker 
60*325a5df9SAndroid Build Coastguard Worker const char kUnknown[] = "UNKNOWN";
61*325a5df9SAndroid Build Coastguard Worker 
GetOneBootHeader(const std::string & pretty,const std::string & pname)62*325a5df9SAndroid Build Coastguard Worker static std::string GetOneBootHeader(const std::string& pretty, const std::string& pname) {
63*325a5df9SAndroid Build Coastguard Worker     return pretty + ": " + android::base::GetProperty(pname, kUnknown) + "\n";
64*325a5df9SAndroid Build Coastguard Worker };
65*325a5df9SAndroid Build Coastguard Worker 
GetBootHeaders()66*325a5df9SAndroid Build Coastguard Worker static std::string GetBootHeaders() {
67*325a5df9SAndroid Build Coastguard Worker     std::string ret = GetOneBootHeader("Build", "ro.build.fingerprint");
68*325a5df9SAndroid Build Coastguard Worker     ret += GetOneBootHeader("Hardware", "ro.product.board");
69*325a5df9SAndroid Build Coastguard Worker     ret += GetOneBootHeader("Revision", "ro.revision");
70*325a5df9SAndroid Build Coastguard Worker     ret += GetOneBootHeader("Bootloader", "ro.bootloader");
71*325a5df9SAndroid Build Coastguard Worker     ret += GetOneBootHeader("Radio", "gsm.version.baseband");
72*325a5df9SAndroid Build Coastguard Worker 
73*325a5df9SAndroid Build Coastguard Worker     std::string version;
74*325a5df9SAndroid Build Coastguard Worker     if (!android::base::ReadFileToString("/proc/version", &version)) version = kUnknown;
75*325a5df9SAndroid Build Coastguard Worker     ret += "Kernel: " + version + "\n\n";
76*325a5df9SAndroid Build Coastguard Worker     return ret;
77*325a5df9SAndroid Build Coastguard Worker }
78*325a5df9SAndroid Build Coastguard Worker 
StoreReport(const std::string & tag,const std::string & report)79*325a5df9SAndroid Build Coastguard Worker static bool StoreReport(const std::string& tag, const std::string& report) {
80*325a5df9SAndroid Build Coastguard Worker     std::string boot_headers = GetBootHeaders();
81*325a5df9SAndroid Build Coastguard Worker     android::sp<android::os::DropBoxManager> dropbox(new android::os::DropBoxManager());
82*325a5df9SAndroid Build Coastguard Worker     auto status = dropbox->addText(android::String16(tag.c_str()), boot_headers + report);
83*325a5df9SAndroid Build Coastguard Worker     if (!status.isOk()) {
84*325a5df9SAndroid Build Coastguard Worker         LOG(ERROR) << "Dropbox failed";
85*325a5df9SAndroid Build Coastguard Worker         return false;
86*325a5df9SAndroid Build Coastguard Worker     }
87*325a5df9SAndroid Build Coastguard Worker     return true;
88*325a5df9SAndroid Build Coastguard Worker }
89*325a5df9SAndroid Build Coastguard Worker 
ProcessDmesg(std::set<std::string> & sent_reports)90*325a5df9SAndroid Build Coastguard Worker static int ProcessDmesg(std::set<std::string> &sent_reports) {
91*325a5df9SAndroid Build Coastguard Worker     std::unique_ptr<FILE, decltype(&pclose)> pipe(popen("dmesg", "r"), pclose);
92*325a5df9SAndroid Build Coastguard Worker     if (!pipe) {
93*325a5df9SAndroid Build Coastguard Worker         PLOG(ERROR) << "popen() failed!";
94*325a5df9SAndroid Build Coastguard Worker         return 1;
95*325a5df9SAndroid Build Coastguard Worker     }
96*325a5df9SAndroid Build Coastguard Worker     dmesg_parser::DmesgParser dmesg_parser;
97*325a5df9SAndroid Build Coastguard Worker 
98*325a5df9SAndroid Build Coastguard Worker     char* buffer = NULL;
99*325a5df9SAndroid Build Coastguard Worker     size_t buffer_size = 0;
100*325a5df9SAndroid Build Coastguard Worker     while (getline(&buffer, &buffer_size, pipe.get()) != -1) {
101*325a5df9SAndroid Build Coastguard Worker         std::string line(buffer);
102*325a5df9SAndroid Build Coastguard Worker         if (line.back() != '\n') line += "\n";
103*325a5df9SAndroid Build Coastguard Worker         dmesg_parser.ProcessLine(line);
104*325a5df9SAndroid Build Coastguard Worker         if (dmesg_parser.ReportReady()) {
105*325a5df9SAndroid Build Coastguard Worker             std::string tag = "SYSTEM_" + dmesg_parser.ReportType() + "_ERROR_REPORT";
106*325a5df9SAndroid Build Coastguard Worker             std::string title = dmesg_parser.ReportTitle();
107*325a5df9SAndroid Build Coastguard Worker             if ((sent_reports.find(title) == sent_reports.end()) &&
108*325a5df9SAndroid Build Coastguard Worker                 (sent_reports.size() < kMaxReports)) {
109*325a5df9SAndroid Build Coastguard Worker                 if (StoreReport(tag, dmesg_parser.FlushReport())) sent_reports.insert(title);
110*325a5df9SAndroid Build Coastguard Worker             }
111*325a5df9SAndroid Build Coastguard Worker         }
112*325a5df9SAndroid Build Coastguard Worker     }
113*325a5df9SAndroid Build Coastguard Worker     free(buffer);
114*325a5df9SAndroid Build Coastguard Worker     return 0;
115*325a5df9SAndroid Build Coastguard Worker }
116*325a5df9SAndroid Build Coastguard Worker 
main(int,char * [])117*325a5df9SAndroid Build Coastguard Worker int main(int, char*[]) {
118*325a5df9SAndroid Build Coastguard Worker     auto sent_reports = ReadSentReports();
119*325a5df9SAndroid Build Coastguard Worker     int result = ProcessDmesg(sent_reports);
120*325a5df9SAndroid Build Coastguard Worker     WriteSentReports(sent_reports);
121*325a5df9SAndroid Build Coastguard Worker     return result;
122*325a5df9SAndroid Build Coastguard Worker }
123