Skip to content

Commit 3ffd162

Browse files
primianoAndroid (Google) Code Review
authored andcommitted
Merge "dumpstate: attach more than 1 trace to BR" into main
2 parents 9381637 + 06d3420 commit 3ffd162

4 files changed

Lines changed: 141 additions & 23 deletions

File tree

cmds/dumpstate/Android.bp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,7 @@ cc_defaults {
117117
"libdumpsys",
118118
"libserviceutils",
119119
"android.tracing.flags_c_lib",
120+
"perfetto_flags_c_lib",
120121
],
121122
}
122123

cmds/dumpstate/dumpstate.cpp

Lines changed: 48 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@
5757
#include <log/log_read.h>
5858
#include <math.h>
5959
#include <openssl/sha.h>
60+
#include <perfetto_flags.h>
6061
#include <poll.h>
6162
#include <private/android_filesystem_config.h>
6263
#include <private/android_logger.h>
@@ -190,7 +191,7 @@ void add_mountinfo();
190191
#define SNAPSHOTCTL_LOG_DIR "/data/misc/snapshotctl_log"
191192
#define LINKERCONFIG_DIR "/linkerconfig"
192193
#define PACKAGE_DEX_USE_LIST "/data/system/package-dex-usage.list"
193-
#define SYSTEM_TRACE_SNAPSHOT "/data/misc/perfetto-traces/bugreport/systrace.pftrace"
194+
#define SYSTEM_TRACE_DIR "/data/misc/perfetto-traces/bugreport"
194195
#define CGROUPFS_DIR "/sys/fs/cgroup"
195196
#define SDK_EXT_INFO "/apex/com.android.sdkext/bin/derive_sdk"
196197
#define DROPBOX_DIR "/data/system/dropbox"
@@ -359,6 +360,31 @@ static bool CopyFileToFile(const std::string& input_file, const std::string& out
359360
return CopyFileToFd(input_file, out_fd.get());
360361
}
361362

363+
template <typename Func>
364+
size_t ForEachTrace(Func func) {
365+
std::unique_ptr<DIR, decltype(&closedir)> traces_dir(opendir(SYSTEM_TRACE_DIR), closedir);
366+
367+
if (traces_dir == nullptr) {
368+
MYLOGW("Unable to open directory %s: %s\n", SYSTEM_TRACE_DIR, strerror(errno));
369+
return 0;
370+
}
371+
372+
size_t traces_found = 0;
373+
struct dirent* entry = nullptr;
374+
while ((entry = readdir(traces_dir.get()))) {
375+
if (entry->d_type != DT_REG) {
376+
continue;
377+
}
378+
std::string trace_path = std::string(SYSTEM_TRACE_DIR) + "/" + entry->d_name;
379+
if (access(trace_path.c_str(), F_OK) != 0) {
380+
continue;
381+
}
382+
++traces_found;
383+
func(trace_path);
384+
}
385+
return traces_found;
386+
}
387+
362388
} // namespace
363389
} // namespace os
364390
} // namespace android
@@ -1101,20 +1127,16 @@ static void MaybeAddSystemTraceToZip() {
11011127
// This function copies into the .zip the system trace that was snapshotted
11021128
// by the early call to MaybeSnapshotSystemTraceAsync(), if any background
11031129
// tracing was happening.
1104-
bool system_trace_exists = access(SYSTEM_TRACE_SNAPSHOT, F_OK) == 0;
1105-
if (!system_trace_exists) {
1106-
// No background trace was happening at the time MaybeSnapshotSystemTraceAsync() was invoked
1107-
if (!PropertiesHelper::IsUserBuild()) {
1108-
MYLOGI(
1109-
"No system traces found. Check for previously uploaded traces by looking for "
1110-
"go/trace-uuid in logcat")
1111-
}
1112-
return;
1130+
size_t traces_found = android::os::ForEachTrace([&](const std::string& trace_path) {
1131+
ds.AddZipEntry(ZIP_ROOT_DIR + trace_path, trace_path);
1132+
android::os::UnlinkAndLogOnError(trace_path);
1133+
});
1134+
1135+
if (traces_found == 0 && !PropertiesHelper::IsUserBuild()) {
1136+
MYLOGI(
1137+
"No system traces found. Check for previously uploaded traces by looking for "
1138+
"go/trace-uuid in logcat")
11131139
}
1114-
ds.AddZipEntry(
1115-
ZIP_ROOT_DIR + SYSTEM_TRACE_SNAPSHOT,
1116-
SYSTEM_TRACE_SNAPSHOT);
1117-
android::os::UnlinkAndLogOnError(SYSTEM_TRACE_SNAPSHOT);
11181140
}
11191141

11201142
static void DumpVisibleWindowViews() {
@@ -3412,8 +3434,8 @@ Dumpstate::RunStatus Dumpstate::RunInternal(int32_t calling_uid,
34123434
// duration is logged into MYLOG instead.
34133435
PrintHeader();
34143436

3415-
bool system_trace_exists = access(SYSTEM_TRACE_SNAPSHOT, F_OK) == 0;
3416-
if (options_->use_predumped_ui_data && !system_trace_exists) {
3437+
size_t trace_count = android::os::ForEachTrace([](const std::string&) {});
3438+
if (options_->use_predumped_ui_data && trace_count == 0) {
34173439
MYLOGW("Ignoring 'use predumped data' flag because no predumped data is available");
34183440
options_->use_predumped_ui_data = false;
34193441
}
@@ -3560,20 +3582,24 @@ std::future<std::string> Dumpstate::MaybeSnapshotSystemTraceAsync() {
35603582
}
35613583

35623584
// If a stale file exists already, remove it.
3563-
unlink(SYSTEM_TRACE_SNAPSHOT);
3585+
android::os::ForEachTrace([&](const std::string& trace_path) { unlink(trace_path.c_str()); });
35643586

35653587
MYLOGI("Launching async '%s'", SERIALIZE_PERFETTO_TRACE_TASK.c_str())
3588+
35663589
return std::async(
35673590
std::launch::async, [this, outPath = std::move(outPath), outFd = std::move(outFd)] {
3568-
// If a background system trace is happening and is marked as "suitable for
3569-
// bugreport" (i.e. bugreport_score > 0 in the trace config), this command
3570-
// will stop it and serialize into SYSTEM_TRACE_SNAPSHOT. In the (likely)
3571-
// case that no trace is ongoing, this command is a no-op.
3591+
// If one or more background system traces are happening and are marked as
3592+
// "suitable for bugreport" (bugreport_score > 0 in the trace config), this command
3593+
// will snapshot them into SYSTEM_TRACE_DIR.
3594+
// In the (likely) case that no trace is ongoing, this command is a no-op.
35723595
// Note: this should not be enqueued as we need to freeze the trace before
35733596
// dumpstate starts. Otherwise the trace ring buffers will contain mostly
35743597
// the dumpstate's own activity which is irrelevant.
3598+
const char* cmd_arg = perfetto::flags::save_all_traces_in_bugreport()
3599+
? "--save-all-for-bugreport"
3600+
: "--save-for-bugreport";
35753601
RunCommand(
3576-
SERIALIZE_PERFETTO_TRACE_TASK, {"perfetto", "--save-for-bugreport"},
3602+
SERIALIZE_PERFETTO_TRACE_TASK, {"perfetto", cmd_arg},
35773603
CommandOptions::WithTimeout(30).DropRoot().CloseAllFileDescriptorsOnExec().Build(),
35783604
false, outFd);
35793605
// MaybeAddSystemTraceToZip() will take care of copying the trace in the zip

cmds/dumpstate/dumpstate_smoke_test.xml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,9 @@
2222
<option name="cleanup" value="true" />
2323
<option name="push" value="dumpstate_smoke_test->/data/local/tmp/dumpstate_smoke_test" />
2424
</target_preparer>
25-
25+
<target_preparer class="com.android.tradefed.targetprep.FeatureFlagTargetPreparer">
26+
<option name="flag-value" value="perfetto/perfetto.flags.save_all_traces_in_bugreport=true" />
27+
</target_preparer>
2628
<test class="com.android.tradefed.testtype.GTest" >
2729
<option name="native-test-device-path" value="/data/local/tmp" />
2830
<option name="module-name" value="dumpstate_smoke_test" />

cmds/dumpstate/tests/dumpstate_smoke_test.cpp

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,10 @@
2424
#include <gmock/gmock.h>
2525
#include <gtest/gtest.h>
2626
#include <libgen.h>
27+
#include <signal.h>
2728
#include <ziparchive/zip_archive.h>
2829

30+
#include <cstdio>
2931
#include <fstream>
3032
#include <regex>
3133

@@ -603,6 +605,93 @@ TEST_F(DumpstateBinderTest, SimultaneousBugreportsNotAllowed) {
603605
listener1->getErrorCode() == IDumpstateListener::BUGREPORT_ERROR_USER_CONSENT_TIMED_OUT);
604606
}
605607

608+
class DumpstateTracingTest : public Test {
609+
protected:
610+
void TearDown() override {
611+
for (int pid : bg_process_pids) {
612+
kill(pid, SIGKILL);
613+
}
614+
}
615+
616+
void StartTracing(const std::string& config) {
617+
// Write the perfetto config into a file.
618+
const int id = static_cast<int>(bg_process_pids.size());
619+
char cfg[64];
620+
snprintf(cfg, sizeof(cfg), "/data/misc/perfetto-configs/br-%d", id);
621+
unlink(cfg); // Remove the config file if it exists already.
622+
FILE* f = fopen(cfg, "w");
623+
ASSERT_NE(f, nullptr);
624+
fputs(config.c_str(), f);
625+
fclose(f);
626+
627+
// Invoke perfetto to start tracing.
628+
char cmd[255];
629+
snprintf(cmd, sizeof(cmd), "perfetto --background-wait --txt -o /dev/null -c %s", cfg);
630+
FILE* proc = popen(cmd, "r");
631+
ASSERT_NE(proc, nullptr);
632+
633+
// Read back the PID of the background process. We will use it to kill
634+
// all tracing sessions when the test ends or fails.
635+
char pid_str[32]{};
636+
ASSERT_NE(fgets(pid_str, sizeof(pid_str), proc), nullptr);
637+
int pid = atoi(pid_str);
638+
bg_process_pids.push_back(pid);
639+
640+
pclose(proc);
641+
unlink(cfg);
642+
}
643+
644+
std::vector<int> bg_process_pids;
645+
};
646+
647+
TEST_F(DumpstateTracingTest, ManyTracesInBugreport) {
648+
// Note the trace duration is irrelevant and is only an upper bound.
649+
// Tracing is stopped as soon as the bugreport.zip creation ends.
650+
StartTracing(R"(
651+
buffers { size_kb: 4096 }
652+
data_sources {
653+
config {
654+
name: "linux.ftrace"
655+
}
656+
}
657+
658+
duration_ms: 120000
659+
bugreport_filename: "sys.pftrace"
660+
bugreport_score: 100
661+
)");
662+
663+
StartTracing(R"(
664+
buffers { size_kb: 4096 }
665+
data_sources {
666+
config {
667+
name: "linux.ftrace"
668+
}
669+
}
670+
671+
duration_ms: 120000
672+
bugreport_score: 50
673+
bugreport_filename: "mem.pftrace"
674+
)");
675+
676+
ZippedBugreportGenerationTest::GenerateBugreport();
677+
std::string zip_path = ZippedBugreportGenerationTest::getZipFilePath();
678+
ZipArchiveHandle handle;
679+
ASSERT_EQ(OpenArchive(zip_path.c_str(), &handle), 0);
680+
681+
const char* kExpectedEntries[]{
682+
"FS/data/misc/perfetto-traces/bugreport/sys.pftrace",
683+
"FS/data/misc/perfetto-traces/bugreport/mem.pftrace",
684+
};
685+
686+
// Check that the bugreport contains both traces.
687+
for (const char* file_path : kExpectedEntries) {
688+
ZipEntry entry{};
689+
GetEntry(handle, file_path, &entry);
690+
EXPECT_GT(entry.uncompressed_length, 100);
691+
}
692+
CloseArchive(handle);
693+
}
694+
606695
} // namespace dumpstate
607696
} // namespace os
608697
} // namespace android

0 commit comments

Comments
 (0)