arc: Reintroduce the output file option

-o argument was previously removed in favor of new api and consent
dialog but now it is being reintroduced to go along with limited mode
dumpstate logs that do not require user consent.

This argument is effective only during limited mode but we do not throw
an error if supplied with other arguemnts for backwards compatibility
reasons.

Bug: 142684959
Bug: 136273873
Bug: 139379357
Bug: 138805202
Bug: 142685922
Test: adb bugreport
Test: adb bugreport xyz.zip
Test: adb shell bugreport
Test: atest dumpstate_test
Test: flash android to dut, android-sh, setenforce 1, arc-bugreport
Change-Id: Ib2cadf13c101dd2e957033a7657a647d043f2b72
This commit is contained in:
mhasank 2020-06-11 15:05:25 -07:00
parent d451a47124
commit 2d75c44e61
3 changed files with 52 additions and 6 deletions

View file

@ -209,6 +209,10 @@ static int Open(std::string path, int flags, mode_t mode = 0) {
return fd;
}
static int OpenForWrite(std::string path) {
return Open(path, O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_NOFOLLOW,
S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
}
static int OpenForRead(std::string path) {
return Open(path, O_RDONLY | O_CLOEXEC | O_NOFOLLOW);
@ -274,6 +278,27 @@ int64_t GetModuleMetadataVersion() {
return version_code;
}
static bool PathExists(const std::string& path) {
struct stat sb;
return stat(path.c_str(), &sb) == 0;
}
static bool CopyFileToFile(const std::string& input_file, const std::string& output_file) {
if (input_file == output_file) {
MYLOGD("Skipping copying bugreport file since the destination is the same (%s)\n",
output_file.c_str());
return false;
}
else if (PathExists(output_file)) {
MYLOGD("Cannot overwrite an existing file (%s)\n", output_file.c_str());
return false;
}
MYLOGD("Going to copy bugreport file (%s) to %s\n", input_file.c_str(), output_file.c_str());
android::base::unique_fd out_fd(OpenForWrite(output_file));
return CopyFileToFd(input_file, out_fd.get());
}
} // namespace
} // namespace os
} // namespace android
@ -2092,11 +2117,12 @@ void Dumpstate::DumpstateBoard() {
static void ShowUsage() {
fprintf(stderr,
"usage: dumpstate [-h] [-b soundfile] [-e soundfile] [-d] [-p] "
"usage: dumpstate [-h] [-b soundfile] [-e soundfile] [-o directory] [-d] [-p] "
"[-z] [-s] [-S] [-q] [-P] [-R] [-L] [-V version]\n"
" -h: display this help message\n"
" -b: play sound file instead of vibrate, at beginning of job\n"
" -e: play sound file instead of vibrate, at end of job\n"
" -o: write to custom directory (only in limited mode)\n"
" -d: append date to filename\n"
" -p: capture screenshot to filename.png\n"
" -z: generate zipped file\n"
@ -2267,6 +2293,14 @@ static void FinalizeFile() {
do_text_file = false;
}
}
std::string final_path = ds.path_;
if (ds.options_->OutputToCustomFile()) {
std::string bugreport_dir = dirname(ds.options_->use_outfile.c_str());
final_path = ds.GetPath(bugreport_dir, ".zip");
android::os::CopyFileToFile(ds.path_, final_path);
}
if (ds.options_->use_control_socket) {
if (do_text_file) {
dprintf(ds.control_socket_fd_,
@ -2274,7 +2308,7 @@ static void FinalizeFile() {
"for more details\n",
ds.log_path_.c_str());
} else {
dprintf(ds.control_socket_fd_, "OK:%s\n", ds.path_.c_str());
dprintf(ds.control_socket_fd_, "OK:%s\n", final_path.c_str());
}
}
}
@ -2384,6 +2418,7 @@ Dumpstate::RunStatus Dumpstate::DumpOptions::Initialize(int argc, char* argv[])
// clang-format off
case 'd': do_add_date = true; break;
case 'z': do_zip_file = true; break;
case 'o': use_outfile = optarg; break;
case 's': use_socket = true; break;
case 'S': use_control_socket = true; break;
case 'v': show_header_only = true; break;
@ -2505,8 +2540,8 @@ void Dumpstate::Cancel() {
* If zipping, a bunch of other files and dumps also get added to the zip archive. The log file also
* gets added to the archive.
*
* Bugreports are first generated in a local directory and later copied to the caller's fd if
* supplied.
* Bugreports are first generated in a local directory and later copied to the caller's fd
* or directory if supplied.
*/
Dumpstate::RunStatus Dumpstate::RunInternal(int32_t calling_uid,
const std::string& calling_package) {

View file

@ -386,10 +386,12 @@ class Dumpstate {
// The HAL is actually an API surface that can be validated, while the AIDL is not (@hide).
::android::hardware::dumpstate::V1_1::DumpstateMode dumpstate_hal_mode =
::android::hardware::dumpstate::V1_1::DumpstateMode::DEFAULT;
// File descriptor to output zip file.
// File descriptor to output zip file. Takes precedence over use_outfile..
android::base::unique_fd bugreport_fd;
// File descriptor to screenshot file.
android::base::unique_fd screenshot_fd;
// Partial path to output file.
std::string use_outfile;
// Bugreport mode of the bugreport.
std::string bugreport_mode;
// Command-line arguments as string
@ -415,6 +417,12 @@ class Dumpstate {
// specified, it is preferred. If not bugreport is written to /bugreports.
return !use_socket;
}
/* Returns if options specified require writing to custom file location */
bool OutputToCustomFile() {
// Custom location is only honored in limited mode.
return limited_only && !use_outfile.empty() && bugreport_fd.get() == -1;
}
};
// TODO: initialize fields on constructor

View file

@ -172,6 +172,7 @@ TEST_F(DumpOptionsTest, InitializeNone) {
EXPECT_FALSE(options_.do_add_date);
EXPECT_FALSE(options_.do_zip_file);
EXPECT_EQ("", options_.use_outfile);
EXPECT_FALSE(options_.use_socket);
EXPECT_FALSE(options_.use_control_socket);
EXPECT_FALSE(options_.show_header_only);
@ -352,7 +353,8 @@ TEST_F(DumpOptionsTest, InitializeLimitedOnlyBugreport) {
const_cast<char*>("-d"),
const_cast<char*>("-z"),
const_cast<char*>("-q"),
const_cast<char*>("-L")
const_cast<char*>("-L"),
const_cast<char*>("-o abc")
};
// clang-format on
@ -364,6 +366,7 @@ TEST_F(DumpOptionsTest, InitializeLimitedOnlyBugreport) {
EXPECT_TRUE(options_.use_control_socket);
EXPECT_FALSE(options_.do_vibrate);
EXPECT_TRUE(options_.limited_only);
EXPECT_EQ(" abc", std::string(options_.use_outfile));
// Other options retain default values
EXPECT_FALSE(options_.show_header_only);