• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2016 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 #define LOG_TAG "dumpstate_device"
18 #define ATRACE_TAG ATRACE_TAG_ALWAYS
19 
20 #include <inttypes.h>
21 
22 #include <android-base/file.h>
23 #include <android-base/stringprintf.h>
24 #include <android-base/properties.h>
25 #include <android-base/unique_fd.h>
26 #include <cutils/trace.h>
27 #include <log/log.h>
28 #include <sys/stat.h>
29 #include <dump/pixel_dump.h>
30 #include "Dumpstate.h"
31 
32 #include "DumpstateUtil.h"
33 
34 #define HW_REVISION "ro.boot.hardware.revision"
35 
36 using android::os::dumpstate::CommandOptions;
37 using android::os::dumpstate::DumpFileToFd;
38 using android::os::dumpstate::PropertiesHelper;
39 using android::os::dumpstate::RunCommandToFd;
40 
41 namespace aidl {
42 namespace android {
43 namespace hardware {
44 namespace dumpstate {
45 
46 typedef std::chrono::time_point<std::chrono::steady_clock> timepoint_t;
47 
48 const char kVerboseLoggingProperty[] = "persist.vendor.verbose_logging_enabled";
49 
startSection(int fd,const std::string & sectionName)50 timepoint_t startSection(int fd, const std::string &sectionName) {
51     ATRACE_BEGIN(sectionName.c_str());
52     ::android::base::WriteStringToFd(
53             "\n"
54             "------ Section start: " + sectionName + " ------\n"
55             "\n", fd);
56     return std::chrono::steady_clock::now();
57 }
58 
endSection(int fd,const std::string & sectionName,timepoint_t startTime)59 void endSection(int fd, const std::string &sectionName, timepoint_t startTime) {
60     ATRACE_END();
61     auto endTime = std::chrono::steady_clock::now();
62     auto elapsedMsec = std::chrono::duration_cast<std::chrono::milliseconds>
63             (endTime - startTime).count();
64 
65     ::android::base::WriteStringToFd(
66             "\n"
67             "------ Section end: " + sectionName + " ------\n"
68             "Elapsed msec: " + std::to_string(elapsedMsec) + "\n"
69             "\n", fd);
70 }
71 
72 // Dump data requested by an argument to the "dump" interface, or help info
73 // if the specified section is not supported.
dumpTextSection(int fd,const std::string & sectionName)74 void Dumpstate::dumpTextSection(int fd, const std::string &sectionName) {
75     bool dumpAll = (sectionName == kAllSections);
76     std::string dumpFiles;
77 
78     // Execute all or designated programs under vendor/bin/dump/
79     std::unique_ptr<DIR, decltype(&closedir)> dir(opendir("/vendor/bin/dump"), closedir);
80     if (!dir) {
81         ALOGE("Fail To Open Dir vendor/bin/dump/");
82         ::android::base::WriteStringToFd("Fail To Open Dir vendor/bin/dump/\n", fd);
83         return;
84     }
85     dirent *entry;
86     while ((entry = readdir(dir.get())) != nullptr) {
87         // Skip '.', '..'
88         if (entry->d_name[0] == '.') {
89             continue;
90         }
91         std::string bin(entry->d_name);
92         dumpFiles = dumpFiles + " " + bin;
93         if (dumpAll || sectionName == bin) {
94             auto startTime = startSection(fd, bin);
95             RunCommandToFd(fd, "/vendor/bin/dump/"+bin, {"/vendor/bin/dump/"+bin}, CommandOptions::WithTimeout(15).Build());
96             endSection(fd, bin, startTime);
97             if (!dumpAll) {
98                 return;
99             }
100         }
101     }
102 
103     if (dumpAll) {
104         RunCommandToFd(fd, "VENDOR PROPERTIES", {"/vendor/bin/getprop"});
105         return;
106     }
107 
108     // An unsupported section was requested on the command line
109     ::android::base::WriteStringToFd("Unrecognized text section: " + sectionName + "\n", fd);
110     ::android::base::WriteStringToFd("Try \"" + kAllSections + "\" or one of the following:", fd);
111     ::android::base::WriteStringToFd(dumpFiles, fd);
112     ::android::base::WriteStringToFd("\nNote: sections with attachments (e.g. dump_soc) are"
113                                    "not available from the command line.\n", fd);
114 }
115 
dumpLogSection(int fd,int fd_bin)116 void Dumpstate::dumpLogSection(int fd, int fd_bin)
117 {
118     std::string logDir = MODEM_LOG_DIRECTORY;
119     const std::string logCombined = logDir + "/combined_logs.tar";
120     const std::string logAllDir = logDir + "/all_logs";
121 
122     RunCommandToFd(fd, "MKDIR LOG", {"/vendor/bin/mkdir", "-p", logAllDir.c_str()}, CommandOptions::WithTimeout(2).Build());
123 
124     dumpTextSection(fd, kAllSections);
125 
126     RunCommandToFd(fd, "TAR LOG", {"/vendor/bin/tar", "cvf", logCombined.c_str(), "-C", logAllDir.c_str(), "."}, CommandOptions::WithTimeout(20).Build());
127     RunCommandToFd(fd, "CHG PERM", {"/vendor/bin/chmod", "a+w", logCombined.c_str()}, CommandOptions::WithTimeout(2).Build());
128 
129     std::vector<uint8_t> buffer(65536);
130     ::android::base::unique_fd fdLog(TEMP_FAILURE_RETRY(open(logCombined.c_str(), O_RDONLY | O_CLOEXEC | O_NONBLOCK)));
131 
132     if (fdLog >= 0) {
133         while (1) {
134             ssize_t bytes_read = TEMP_FAILURE_RETRY(read(fdLog, buffer.data(), buffer.size()));
135 
136             if (bytes_read == 0) {
137                 break;
138             } else if (bytes_read < 0) {
139                 ALOGD("read(%s): %s\n", logCombined.c_str(), strerror(errno));
140                 break;
141             }
142 
143             ssize_t result = TEMP_FAILURE_RETRY(write(fd_bin, buffer.data(), bytes_read));
144 
145             if (result != bytes_read) {
146                 ALOGD("Failed to write %zd bytes, actually written: %zd", bytes_read, result);
147                 break;
148             }
149         }
150     }
151 
152     RunCommandToFd(fd, "RM LOG DIR", { "/vendor/bin/rm", "-r", logAllDir.c_str()}, CommandOptions::WithTimeout(2).Build());
153     RunCommandToFd(fd, "RM LOG", { "/vendor/bin/rm", logCombined.c_str()}, CommandOptions::WithTimeout(2).Build());
154 }
155 
dumpstateBoard(const std::vector<::ndk::ScopedFileDescriptor> & in_fds,IDumpstateDevice::DumpstateMode in_mode,int64_t in_timeoutMillis)156 ndk::ScopedAStatus Dumpstate::dumpstateBoard(const std::vector<::ndk::ScopedFileDescriptor>& in_fds,
157                                              IDumpstateDevice::DumpstateMode in_mode,
158                                              int64_t in_timeoutMillis) {
159     ATRACE_BEGIN("dumpstateBoard");
160     // Unused arguments.
161     (void) in_timeoutMillis;
162 
163     if (in_mode < IDumpstateDevice::DumpstateMode::FULL || in_mode > IDumpstateDevice::DumpstateMode::PROTO) {
164         ALOGE("Invalid mode: %d\n", in_mode);
165         return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT, "Invalid mode");
166     }
167 
168     if (in_fds.size() < 1) {
169         ALOGE("no FDs\n");
170         return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
171                                                                 "No file descriptor");
172     }
173 
174     int fd = in_fds[0].get();
175     if (fd < 0) {
176         ALOGE("invalid FD: %d\n", fd);
177         return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
178                                                                 "Invalid file descriptor");
179     }
180 
181     if (in_fds.size() < 2) {
182           ALOGE("no FD for dumpstate_board binary\n");
183           dumpTextSection(fd, "");
184     } else {
185           int fd_bin = in_fds[1].get();
186           dumpLogSection(fd, fd_bin);
187     }
188 
189     ATRACE_END();
190     return ndk::ScopedAStatus::ok();
191 }
192 
setVerboseLoggingEnabled(bool in_enable)193 ndk::ScopedAStatus Dumpstate::setVerboseLoggingEnabled(bool in_enable) {
194     ::android::base::SetProperty(kVerboseLoggingProperty, in_enable ? "true" : "false");
195     return ndk::ScopedAStatus::ok();
196 }
197 
getVerboseLoggingEnabled(bool * _aidl_return)198 ndk::ScopedAStatus Dumpstate::getVerboseLoggingEnabled(bool* _aidl_return) {
199     *_aidl_return = ::android::base::GetBoolProperty(kVerboseLoggingProperty, false);
200     return ndk::ScopedAStatus::ok();
201 }
202 
203 // Since AIDLs that support the dump() interface are automatically invoked during
204 // bugreport generation and we don't want to generate a second copy of the same
205 // data that will go into dumpstate_board.txt, this function will only do
206 // something if it is called with an option, e.g.
207 //   dumpsys android.hardware.dumpstate.IDumpstateDevice/default all
208 //
209 // Also, note that sections which generate attachments and/or binary data when
210 // included in a bugreport are not available through the dump() interface.
dump(int fd,const char ** args,uint32_t numArgs)211 binder_status_t Dumpstate::dump(int fd, const char** args, uint32_t numArgs) {
212 
213     if (numArgs != 1) {
214         return STATUS_OK;
215     }
216 
217     dumpTextSection(fd, static_cast<std::string>(args[0]));
218 
219     fsync(fd);
220     return STATUS_OK;
221 }
222 
223 }  // namespace dumpstate
224 }  // namespace hardware
225 }  // namespace android
226 }  // namespace aidl
227