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