Streaming bugreport content to stdout 2/2
- Stream compressed content via the socket from dumpstate
- Remove do_zip_file, do_add_data vars in dumpstate
- getopt '-d' and '-z' options are now no-op
- Rename use_control_socket -> progress_updates_to_socket
- Rename use_socket -> stream_to_socket
do_zip_file and do_add_data are now default behaviors.
Also adding a function interface to hook dumpstate `open_socket`
function that would make it easy to do integration tests of streaming
zipped bugreport via socket. Stub the function and capture data from
target file to verify content.
Bug: 162910469
Test: adb bugreport --stream > test.zip; 7z t test.zip
Test: adb shell bugreportz -s > test.zip; 7z t test.zip
Test: atest dumpstate_test
Test: atest dumpstate_test:ZippedBugReportStreamTest
Test: atest dumpstate_smoke_test
Test: manually test combo keys voldown+volup+power to trigger bugreport
verify logcat kernel buffer shows "Starting service 'bugreport'
from keychord 114 115 116" and device viberated as expected
Change-Id: Icf79bbc42a5616e85625bd604e543fbf973911da
diff --git a/cmds/dumpstate/tests/dumpstate_test.cpp b/cmds/dumpstate/tests/dumpstate_test.cpp
index 6b93692..306069f 100644
--- a/cmds/dumpstate/tests/dumpstate_test.cpp
+++ b/cmds/dumpstate/tests/dumpstate_test.cpp
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#define LOG_TAG "dumpstate"
-#include <cutils/log.h>
+#define LOG_TAG "dumpstate_test"
#include "DumpstateInternal.h"
#include "DumpstateService.h"
@@ -24,6 +23,7 @@
#include "DumpPool.h"
#include <gmock/gmock.h>
+#include <gmock/gmock-matchers.h>
#include <gtest/gtest.h>
#include <fcntl.h>
@@ -39,7 +39,9 @@
#include <android-base/strings.h>
#include <android-base/unique_fd.h>
#include <android/hardware/dumpstate/1.1/types.h>
+#include <cutils/log.h>
#include <cutils/properties.h>
+#include <ziparchive/zip_archive.h>
namespace android {
namespace os {
@@ -176,11 +178,9 @@
EXPECT_EQ(status, Dumpstate::RunStatus::OK);
- EXPECT_FALSE(options_.do_add_date);
- EXPECT_FALSE(options_.do_zip_file);
EXPECT_EQ("", options_.out_dir);
- EXPECT_FALSE(options_.use_socket);
- EXPECT_FALSE(options_.use_control_socket);
+ EXPECT_FALSE(options_.stream_to_socket);
+ EXPECT_FALSE(options_.progress_updates_to_socket);
EXPECT_FALSE(options_.show_header_only);
EXPECT_TRUE(options_.do_vibrate);
EXPECT_FALSE(options_.do_screenshot);
@@ -195,17 +195,13 @@
char* argv[] = {
const_cast<char*>("dumpstatez"),
const_cast<char*>("-S"),
- const_cast<char*>("-d"),
- const_cast<char*>("-z"),
};
// clang-format on
Dumpstate::RunStatus status = options_.Initialize(ARRAY_SIZE(argv), argv);
EXPECT_EQ(status, Dumpstate::RunStatus::OK);
- EXPECT_TRUE(options_.do_add_date);
- EXPECT_TRUE(options_.do_zip_file);
- EXPECT_TRUE(options_.use_control_socket);
+ EXPECT_TRUE(options_.progress_updates_to_socket);
// Other options retain default values
EXPECT_TRUE(options_.do_vibrate);
@@ -213,7 +209,7 @@
EXPECT_FALSE(options_.do_screenshot);
EXPECT_FALSE(options_.do_progress_updates);
EXPECT_FALSE(options_.is_remote_mode);
- EXPECT_FALSE(options_.use_socket);
+ EXPECT_FALSE(options_.stream_to_socket);
EXPECT_FALSE(options_.limited_only);
EXPECT_EQ(options_.dumpstate_hal_mode, DumpstateMode::DEFAULT);
}
@@ -229,13 +225,11 @@
Dumpstate::RunStatus status = options_.Initialize(ARRAY_SIZE(argv), argv);
EXPECT_EQ(status, Dumpstate::RunStatus::OK);
- EXPECT_TRUE(options_.use_socket);
+ EXPECT_TRUE(options_.stream_to_socket);
// Other options retain default values
EXPECT_TRUE(options_.do_vibrate);
- EXPECT_FALSE(options_.do_add_date);
- EXPECT_FALSE(options_.do_zip_file);
- EXPECT_FALSE(options_.use_control_socket);
+ EXPECT_FALSE(options_.progress_updates_to_socket);
EXPECT_FALSE(options_.show_header_only);
EXPECT_FALSE(options_.do_screenshot);
EXPECT_FALSE(options_.do_progress_updates);
@@ -246,105 +240,93 @@
TEST_F(DumpOptionsTest, InitializeFullBugReport) {
options_.Initialize(Dumpstate::BugreportMode::BUGREPORT_FULL, fd, fd, true);
- EXPECT_TRUE(options_.do_add_date);
EXPECT_TRUE(options_.do_screenshot);
- EXPECT_TRUE(options_.do_zip_file);
EXPECT_EQ(options_.dumpstate_hal_mode, DumpstateMode::FULL);
// Other options retain default values
EXPECT_TRUE(options_.do_vibrate);
- EXPECT_FALSE(options_.use_control_socket);
+ EXPECT_FALSE(options_.progress_updates_to_socket);
EXPECT_FALSE(options_.show_header_only);
EXPECT_FALSE(options_.do_progress_updates);
EXPECT_FALSE(options_.is_remote_mode);
- EXPECT_FALSE(options_.use_socket);
+ EXPECT_FALSE(options_.stream_to_socket);
EXPECT_FALSE(options_.limited_only);
}
TEST_F(DumpOptionsTest, InitializeInteractiveBugReport) {
options_.Initialize(Dumpstate::BugreportMode::BUGREPORT_INTERACTIVE, fd, fd, true);
- EXPECT_TRUE(options_.do_add_date);
- EXPECT_TRUE(options_.do_zip_file);
EXPECT_TRUE(options_.do_progress_updates);
EXPECT_TRUE(options_.do_screenshot);
EXPECT_EQ(options_.dumpstate_hal_mode, DumpstateMode::INTERACTIVE);
// Other options retain default values
EXPECT_TRUE(options_.do_vibrate);
- EXPECT_FALSE(options_.use_control_socket);
+ EXPECT_FALSE(options_.progress_updates_to_socket);
EXPECT_FALSE(options_.show_header_only);
EXPECT_FALSE(options_.is_remote_mode);
- EXPECT_FALSE(options_.use_socket);
+ EXPECT_FALSE(options_.stream_to_socket);
EXPECT_FALSE(options_.limited_only);
}
TEST_F(DumpOptionsTest, InitializeRemoteBugReport) {
options_.Initialize(Dumpstate::BugreportMode::BUGREPORT_REMOTE, fd, fd, false);
- EXPECT_TRUE(options_.do_add_date);
- EXPECT_TRUE(options_.do_zip_file);
EXPECT_TRUE(options_.is_remote_mode);
EXPECT_FALSE(options_.do_vibrate);
EXPECT_FALSE(options_.do_screenshot);
EXPECT_EQ(options_.dumpstate_hal_mode, DumpstateMode::REMOTE);
// Other options retain default values
- EXPECT_FALSE(options_.use_control_socket);
+ EXPECT_FALSE(options_.progress_updates_to_socket);
EXPECT_FALSE(options_.show_header_only);
EXPECT_FALSE(options_.do_progress_updates);
- EXPECT_FALSE(options_.use_socket);
+ EXPECT_FALSE(options_.stream_to_socket);
EXPECT_FALSE(options_.limited_only);
}
TEST_F(DumpOptionsTest, InitializeWearBugReport) {
options_.Initialize(Dumpstate::BugreportMode::BUGREPORT_WEAR, fd, fd, true);
- EXPECT_TRUE(options_.do_add_date);
EXPECT_TRUE(options_.do_screenshot);
- EXPECT_TRUE(options_.do_zip_file);
EXPECT_TRUE(options_.do_progress_updates);
EXPECT_EQ(options_.dumpstate_hal_mode, DumpstateMode::WEAR);
// Other options retain default values
EXPECT_TRUE(options_.do_vibrate);
- EXPECT_FALSE(options_.use_control_socket);
+ EXPECT_FALSE(options_.progress_updates_to_socket);
EXPECT_FALSE(options_.show_header_only);
EXPECT_FALSE(options_.is_remote_mode);
- EXPECT_FALSE(options_.use_socket);
+ EXPECT_FALSE(options_.stream_to_socket);
EXPECT_FALSE(options_.limited_only);
}
TEST_F(DumpOptionsTest, InitializeTelephonyBugReport) {
options_.Initialize(Dumpstate::BugreportMode::BUGREPORT_TELEPHONY, fd, fd, false);
- EXPECT_TRUE(options_.do_add_date);
EXPECT_FALSE(options_.do_screenshot);
- EXPECT_TRUE(options_.do_zip_file);
EXPECT_TRUE(options_.telephony_only);
EXPECT_TRUE(options_.do_progress_updates);
EXPECT_EQ(options_.dumpstate_hal_mode, DumpstateMode::CONNECTIVITY);
// Other options retain default values
EXPECT_TRUE(options_.do_vibrate);
- EXPECT_FALSE(options_.use_control_socket);
+ EXPECT_FALSE(options_.progress_updates_to_socket);
EXPECT_FALSE(options_.show_header_only);
EXPECT_FALSE(options_.is_remote_mode);
- EXPECT_FALSE(options_.use_socket);
+ EXPECT_FALSE(options_.stream_to_socket);
EXPECT_FALSE(options_.limited_only);
}
TEST_F(DumpOptionsTest, InitializeWifiBugReport) {
options_.Initialize(Dumpstate::BugreportMode::BUGREPORT_WIFI, fd, fd, false);
- EXPECT_TRUE(options_.do_add_date);
EXPECT_FALSE(options_.do_screenshot);
- EXPECT_TRUE(options_.do_zip_file);
EXPECT_TRUE(options_.wifi_only);
EXPECT_EQ(options_.dumpstate_hal_mode, DumpstateMode::WIFI);
// Other options retain default values
EXPECT_TRUE(options_.do_vibrate);
- EXPECT_FALSE(options_.use_control_socket);
+ EXPECT_FALSE(options_.progress_updates_to_socket);
EXPECT_FALSE(options_.show_header_only);
EXPECT_FALSE(options_.do_progress_updates);
EXPECT_FALSE(options_.is_remote_mode);
- EXPECT_FALSE(options_.use_socket);
+ EXPECT_FALSE(options_.stream_to_socket);
EXPECT_FALSE(options_.limited_only);
}
@@ -353,8 +335,6 @@
char* argv[] = {
const_cast<char*>("dumpstatez"),
const_cast<char*>("-S"),
- const_cast<char*>("-d"),
- const_cast<char*>("-z"),
const_cast<char*>("-q"),
const_cast<char*>("-L"),
const_cast<char*>("-o abc")
@@ -364,9 +344,7 @@
Dumpstate::RunStatus status = options_.Initialize(ARRAY_SIZE(argv), argv);
EXPECT_EQ(status, Dumpstate::RunStatus::OK);
- EXPECT_TRUE(options_.do_add_date);
- EXPECT_TRUE(options_.do_zip_file);
- EXPECT_TRUE(options_.use_control_socket);
+ EXPECT_TRUE(options_.progress_updates_to_socket);
EXPECT_FALSE(options_.do_vibrate);
EXPECT_TRUE(options_.limited_only);
EXPECT_EQ(" abc", std::string(options_.out_dir));
@@ -376,7 +354,7 @@
EXPECT_FALSE(options_.do_screenshot);
EXPECT_FALSE(options_.do_progress_updates);
EXPECT_FALSE(options_.is_remote_mode);
- EXPECT_FALSE(options_.use_socket);
+ EXPECT_FALSE(options_.stream_to_socket);
EXPECT_EQ(options_.dumpstate_hal_mode, DumpstateMode::DEFAULT);
}
@@ -393,18 +371,16 @@
Dumpstate::RunStatus status = options_.Initialize(ARRAY_SIZE(argv), argv);
EXPECT_EQ(status, Dumpstate::RunStatus::OK);
- EXPECT_TRUE(options_.do_add_date);
EXPECT_TRUE(options_.do_screenshot);
- EXPECT_TRUE(options_.do_zip_file);
EXPECT_EQ(options_.dumpstate_hal_mode, DumpstateMode::DEFAULT);
// Other options retain default values
EXPECT_TRUE(options_.do_vibrate);
- EXPECT_FALSE(options_.use_control_socket);
+ EXPECT_FALSE(options_.progress_updates_to_socket);
EXPECT_FALSE(options_.show_header_only);
EXPECT_FALSE(options_.do_progress_updates);
EXPECT_FALSE(options_.is_remote_mode);
- EXPECT_FALSE(options_.use_socket);
+ EXPECT_FALSE(options_.stream_to_socket);
EXPECT_FALSE(options_.wifi_only);
EXPECT_FALSE(options_.limited_only);
}
@@ -413,8 +389,6 @@
// clang-format off
char* argv[] = {
const_cast<char*>("dumpstate"),
- const_cast<char*>("-d"),
- const_cast<char*>("-z"),
const_cast<char*>("-s"),
const_cast<char*>("-S"),
@@ -424,11 +398,9 @@
Dumpstate::RunStatus status = options_.Initialize(ARRAY_SIZE(argv), argv);
EXPECT_EQ(status, Dumpstate::RunStatus::OK);
- EXPECT_TRUE(options_.do_add_date);
- EXPECT_TRUE(options_.do_zip_file);
// TODO: Maybe we should trim the filename
- EXPECT_TRUE(options_.use_socket);
- EXPECT_TRUE(options_.use_control_socket);
+ EXPECT_TRUE(options_.stream_to_socket);
+ EXPECT_TRUE(options_.progress_updates_to_socket);
// Other options retain default values
EXPECT_FALSE(options_.show_header_only);
@@ -462,10 +434,8 @@
EXPECT_TRUE(options_.is_remote_mode);
// Other options retain default values
- EXPECT_FALSE(options_.do_add_date);
- EXPECT_FALSE(options_.do_zip_file);
- EXPECT_FALSE(options_.use_socket);
- EXPECT_FALSE(options_.use_control_socket);
+ EXPECT_FALSE(options_.stream_to_socket);
+ EXPECT_FALSE(options_.progress_updates_to_socket);
EXPECT_FALSE(options_.limited_only);
EXPECT_EQ(options_.dumpstate_hal_mode, DumpstateMode::DEFAULT);
}
@@ -498,40 +468,31 @@
EXPECT_EQ(status, Dumpstate::RunStatus::INVALID_INPUT);
}
-TEST_F(DumpOptionsTest, ValidateOptionsNeedOutfile1) {
- options_.do_zip_file = true;
- // Writing to socket = !writing to file.
- options_.use_socket = true;
+TEST_F(DumpOptionsTest, ValidateOptionsSocketUsage1) {
+ options_.progress_updates_to_socket = true;
+ options_.stream_to_socket = true;
EXPECT_FALSE(options_.ValidateOptions());
- options_.use_socket = false;
+ options_.stream_to_socket = false;
EXPECT_TRUE(options_.ValidateOptions());
}
-TEST_F(DumpOptionsTest, ValidateOptionsNeedOutfile2) {
+TEST_F(DumpOptionsTest, ValidateOptionsSocketUsage2) {
options_.do_progress_updates = true;
// Writing to socket = !writing to file.
- options_.use_socket = true;
+ options_.stream_to_socket = true;
EXPECT_FALSE(options_.ValidateOptions());
- options_.use_socket = false;
- EXPECT_TRUE(options_.ValidateOptions());
-}
-
-TEST_F(DumpOptionsTest, ValidateOptionsNeedZipfile) {
- options_.use_control_socket = true;
- EXPECT_FALSE(options_.ValidateOptions());
-
- options_.do_zip_file = true;
+ options_.stream_to_socket = false;
EXPECT_TRUE(options_.ValidateOptions());
}
TEST_F(DumpOptionsTest, ValidateOptionsRemoteMode) {
+ options_.do_progress_updates = true;
options_.is_remote_mode = true;
EXPECT_FALSE(options_.ValidateOptions());
- options_.do_zip_file = true;
- options_.do_add_date = true;
+ options_.do_progress_updates = false;
EXPECT_TRUE(options_.ValidateOptions());
}
@@ -1018,23 +979,13 @@
ds.listener_.clear();
}
-TEST_F(DumpstateTest, DumpPool_withOutputToFileAndParallelRunEnabled_notNull) {
- ds.options_->use_socket = false;
+TEST_F(DumpstateTest, DumpPool_withParallelRunEnabled_notNull) {
SetParallelRun(true);
EnableParallelRunIfNeeded();
- EXPECT_TRUE(ds.options_->OutputToFile());
EXPECT_TRUE(ds.zip_entry_tasks_);
EXPECT_TRUE(ds.dump_pool_);
}
-TEST_F(DumpstateTest, DumpPool_withNotOutputToFile_isNull) {
- ds.options_->use_socket = true;
- EnableParallelRunIfNeeded();
- EXPECT_FALSE(ds.options_->OutputToFile());
- EXPECT_FALSE(ds.zip_entry_tasks_);
- EXPECT_FALSE(ds.dump_pool_);
-}
-
TEST_F(DumpstateTest, DumpPool_withParallelRunDisabled_isNull) {
SetParallelRun(false);
EnableParallelRunIfNeeded();
@@ -1042,6 +993,69 @@
EXPECT_FALSE(ds.dump_pool_);
}
+class ZippedBugReportStreamTest : public DumpstateBaseTest {
+ public:
+ void SetUp() {
+ DumpstateBaseTest::SetUp();
+ ds_.options_.reset(new Dumpstate::DumpOptions());
+ }
+ void TearDown() {
+ CloseArchive(handle_);
+ }
+
+ // Set bugreport mode and options before here.
+ void GenerateBugreport() {
+ ds_.Initialize();
+ EXPECT_EQ(Dumpstate::RunStatus::OK, ds_.Run(/*calling_uid=*/-1, /*calling_package=*/""));
+ }
+
+ // Most bugreports droproot, ensure the file can be opened by shell to verify file content.
+ void CreateFd(const std::string& path, android::base::unique_fd* out_fd) {
+ out_fd->reset(TEMP_FAILURE_RETRY(open(path.c_str(),
+ O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_NOFOLLOW,
+ S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)));
+ ASSERT_GE(out_fd->get(), 0) << "could not create FD for path " << path;
+ }
+
+ void VerifyEntry(const ZipArchiveHandle archive, const std::string_view entry_name,
+ ZipEntry* data) {
+ int32_t e = FindEntry(archive, entry_name, data);
+ EXPECT_EQ(0, e) << ErrorCodeString(e) << " entry name: " << entry_name;
+ }
+
+ // While testing dumpstate in process, using STDOUT may get confused about
+ // the internal fd redirection. Redirect to a dedicate fd to save content.
+ void RedirectOutputToFd(android::base::unique_fd& ufd) {
+ ds_.open_socket_fn_ = [&](const char*) -> int { return ufd.release(); };
+ };
+
+ Dumpstate& ds_ = Dumpstate::GetInstance();
+ ZipArchiveHandle handle_;
+};
+
+// Generate a quick wifi report redirected to a file, open it and verify entry exist.
+TEST_F(ZippedBugReportStreamTest, StreamWifiReport) {
+ std::string out_path = kTestDataPath + "out.zip";
+ android::base::unique_fd out_fd;
+ CreateFd(out_path, &out_fd);
+ ds_.options_->wifi_only = true;
+ ds_.options_->stream_to_socket = true;
+ RedirectOutputToFd(out_fd);
+
+ GenerateBugreport();
+ OpenArchive(out_path.c_str(), &handle_);
+
+ ZipEntry entry;
+ VerifyEntry(handle_, "main_entry.txt", &entry);
+ std::string bugreport_txt_name;
+ bugreport_txt_name.resize(entry.uncompressed_length);
+ ExtractToMemory(handle_, &entry, reinterpret_cast<uint8_t*>(bugreport_txt_name.data()),
+ entry.uncompressed_length);
+ EXPECT_THAT(bugreport_txt_name,
+ testing::ContainsRegex("(bugreport-.+-wifi(-[[:digit:]]+){6}\\.txt)"));
+ VerifyEntry(handle_, bugreport_txt_name, &entry);
+}
+
class DumpstateServiceTest : public DumpstateBaseTest {
public:
DumpstateService dss;