ftrace_reader: Mock code that runs atrace for testing
Change-Id: I5601e87fc03ba0b9b499d7224a6ec231230ca9e4
diff --git a/Android.bp b/Android.bp
index aa0101a..a451202 100644
--- a/Android.bp
+++ b/Android.bp
@@ -33,6 +33,7 @@
"src/base/thread_checker.cc",
"src/base/unix_task_runner.cc",
"src/base/watchdog.cc",
+ "src/ftrace_reader/atrace_wrapper.cc",
"src/ftrace_reader/cpu_reader.cc",
"src/ftrace_reader/event_info.cc",
"src/ftrace_reader/event_info_constants.cc",
@@ -227,6 +228,7 @@
"src/base/thread_checker.cc",
"src/base/unix_task_runner.cc",
"src/base/watchdog.cc",
+ "src/ftrace_reader/atrace_wrapper.cc",
"src/ftrace_reader/cpu_reader.cc",
"src/ftrace_reader/end_to_end_integrationtest.cc",
"src/ftrace_reader/event_info.cc",
@@ -2958,6 +2960,7 @@
"src/base/watchdog.cc",
"src/base/watchdog_unittest.cc",
"src/base/weak_ptr_unittest.cc",
+ "src/ftrace_reader/atrace_wrapper.cc",
"src/ftrace_reader/cpu_reader.cc",
"src/ftrace_reader/cpu_reader_unittest.cc",
"src/ftrace_reader/event_info.cc",
diff --git a/src/ftrace_reader/BUILD.gn b/src/ftrace_reader/BUILD.gn
index 5fffdb5..29a24b3 100644
--- a/src/ftrace_reader/BUILD.gn
+++ b/src/ftrace_reader/BUILD.gn
@@ -112,6 +112,8 @@
"../protozero",
]
sources = [
+ "atrace_wrapper.cc",
+ "atrace_wrapper.h",
"cpu_reader.cc",
"cpu_reader.h",
"event_info.cc",
diff --git a/src/ftrace_reader/atrace_wrapper.cc b/src/ftrace_reader/atrace_wrapper.cc
new file mode 100644
index 0000000..8ca9b7a
--- /dev/null
+++ b/src/ftrace_reader/atrace_wrapper.cc
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "atrace_wrapper.h"
+
+#include <fcntl.h>
+#include <stdint.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include "perfetto/base/logging.h"
+
+namespace perfetto {
+
+namespace {
+
+RunAtraceFunction g_run_atrace_for_testing = nullptr;
+
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
+// Args should include "atrace" for argv[0].
+bool ExecvAtrace(const std::vector<std::string>& args) {
+ int status = 1;
+
+ std::vector<char*> argv;
+ // args, and then a null.
+ argv.reserve(1 + args.size());
+ for (const auto& arg : args)
+ argv.push_back(const_cast<char*>(arg.c_str()));
+ argv.push_back(nullptr);
+
+ pid_t pid = fork();
+ PERFETTO_CHECK(pid >= 0);
+ if (pid == 0) {
+ // Close stdin/out/err + any file descriptor that we might have mistakenly
+ // not marked as FD_CLOEXEC.
+ for (int i = 0; i < 128; i++)
+ close(i);
+ execv("/system/bin/atrace", &argv[0]);
+ // Reached only if execv fails.
+ _exit(1);
+ }
+ PERFETTO_EINTR(waitpid(pid, &status, 0));
+ return status == 0;
+}
+#endif
+
+} // namespace
+
+bool RunAtrace(const std::vector<std::string>& args) {
+ if (g_run_atrace_for_testing)
+ return g_run_atrace_for_testing(args);
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
+ return ExecvAtrace(args);
+#else
+ PERFETTO_LOG("Atrace only supported on Android.");
+ return false;
+#endif
+}
+
+void SetRunAtraceForTesting(RunAtraceFunction f) {
+ g_run_atrace_for_testing = f;
+}
+
+} // namespace perfetto
diff --git a/src/ftrace_reader/atrace_wrapper.h b/src/ftrace_reader/atrace_wrapper.h
new file mode 100644
index 0000000..1984525
--- /dev/null
+++ b/src/ftrace_reader/atrace_wrapper.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SRC_FTRACE_READER_ATRACE_WRAPPER_H_
+#define SRC_FTRACE_READER_ATRACE_WRAPPER_H_
+
+#include <string>
+#include <type_traits>
+#include <vector>
+
+namespace perfetto {
+
+using RunAtraceFunction =
+ std::add_pointer<bool(const std::vector<std::string>& /*args*/)>::type;
+
+bool RunAtrace(const std::vector<std::string>& args);
+void SetRunAtraceForTesting(RunAtraceFunction);
+
+} // namespace perfetto
+
+#endif // SRC_FTRACE_READER_ATRACE_WRAPPER_H_
diff --git a/src/ftrace_reader/ftrace_config_muxer.cc b/src/ftrace_reader/ftrace_config_muxer.cc
index 63c1f6f..5a1ed14 100644
--- a/src/ftrace_reader/ftrace_config_muxer.cc
+++ b/src/ftrace_reader/ftrace_config_muxer.cc
@@ -16,16 +16,14 @@
#include "ftrace_config_muxer.h"
-#include <fcntl.h>
#include <stdint.h>
#include <string.h>
-#include <sys/stat.h>
#include <sys/types.h>
-#include <sys/wait.h>
#include <unistd.h>
#include <algorithm>
+#include "atrace_wrapper.h"
#include "perfetto/base/utils.h"
#include "proto_translation_table.h"
@@ -47,32 +45,6 @@
return result;
}
-// Including "atrace" for argv[0].
-bool RunAtrace(const std::vector<std::string>& args) {
- int status = 1;
-
- std::vector<char*> argv;
- // args, and then a null.
- argv.reserve(1 + args.size());
- for (const auto& arg : args)
- argv.push_back(const_cast<char*>(arg.c_str()));
- argv.push_back(nullptr);
-
- pid_t pid = fork();
- PERFETTO_CHECK(pid >= 0);
- if (pid == 0) {
- // Close stdin/out/err + any file descriptor that we might have mistakenly
- // not marked as FD_CLOEXEC.
- for (int i = 0; i < 128; i++)
- close(i);
- execv("/system/bin/atrace", &argv[0]);
- // Reached only if execv fails.
- _exit(1);
- }
- PERFETTO_EINTR(waitpid(pid, &status, 0));
- return status == 0;
-}
-
} // namespace
std::set<std::string> GetFtraceEvents(const FtraceConfig& request) {
@@ -119,7 +91,7 @@
// If we're about to turn tracing on use this opportunity do some setup:
if (RequiresAtrace(request))
- EnableAtraceOnAndroid(request);
+ EnableAtrace(request);
SetupClock(request);
SetupBufferSize(request);
} else {
@@ -188,7 +160,7 @@
ftrace_->ClearTrace();
current_state_.tracing_on = false;
if (current_state_.atrace_on)
- DisableAtraceOnAndroid();
+ DisableAtrace();
}
return true;
@@ -221,19 +193,11 @@
current_state_.cpu_buffer_size_pages = pages;
}
-void FtraceConfigMuxer::EnableAtraceOnAndroid(const FtraceConfig& request) {
-#if PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
- EnableAtrace(request);
-#else
- PERFETTO_LOG("Atrace only supported on Android.");
-#endif
-}
-
void FtraceConfigMuxer::EnableAtrace(const FtraceConfig& request) {
PERFETTO_DCHECK(!current_state_.atrace_on);
- current_state_.atrace_on = true;
PERFETTO_DLOG("Start atrace...");
+
std::vector<std::string> args;
args.push_back("atrace"); // argv0 for exec()
args.push_back("--async_start");
@@ -245,26 +209,21 @@
args.push_back(app);
}
- PERFETTO_CHECK(RunAtrace(args));
- PERFETTO_DLOG("...done");
-}
+ if (RunAtrace(args))
+ current_state_.atrace_on = true;
-void FtraceConfigMuxer::DisableAtraceOnAndroid() {
-#if PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
- DisableAtrace();
-#else
- PERFETTO_LOG("Atrace only supported on Android.");
-#endif
+ PERFETTO_DLOG("...done");
}
void FtraceConfigMuxer::DisableAtrace() {
- PERFETTO_DCHECK(!current_state_.atrace_on);
+ PERFETTO_DCHECK(current_state_.atrace_on);
PERFETTO_DLOG("Stop atrace...");
- PERFETTO_CHECK(RunAtrace({"atrace", "--async_stop"}));
- PERFETTO_DLOG("...done");
- current_state_.atrace_on = false;
+ if (RunAtrace({"atrace", "--async_stop"}))
+ current_state_.atrace_on = false;
+
+ PERFETTO_DLOG("...done");
}
} // namespace perfetto
diff --git a/src/ftrace_reader/ftrace_config_muxer.h b/src/ftrace_reader/ftrace_config_muxer.h
index 37d031b..c24609c 100644
--- a/src/ftrace_reader/ftrace_config_muxer.h
+++ b/src/ftrace_reader/ftrace_config_muxer.h
@@ -38,7 +38,8 @@
// |RemoveConfig|.
class FtraceConfigMuxer {
public:
- // The ProtoTranslationTable table should outlive this instance.
+ // The FtraceConfigMuxer and ProtoTranslationTable
+ // should outlive this instance.
FtraceConfigMuxer(FtraceProcfs* ftrace, const ProtoTranslationTable* table);
virtual ~FtraceConfigMuxer();
@@ -79,8 +80,6 @@
void SetupClock(const FtraceConfig& request);
void SetupBufferSize(const FtraceConfig& request);
- void EnableAtraceOnAndroid(const FtraceConfig& request);
- void DisableAtraceOnAndroid();
void EnableAtrace(const FtraceConfig& request);
void DisableAtrace();
diff --git a/src/ftrace_reader/ftrace_config_muxer_unittest.cc b/src/ftrace_reader/ftrace_config_muxer_unittest.cc
index f7e3e74..b0ca96c 100644
--- a/src/ftrace_reader/ftrace_config_muxer_unittest.cc
+++ b/src/ftrace_reader/ftrace_config_muxer_unittest.cc
@@ -18,14 +18,18 @@
#include <memory>
-#include "ftrace_procfs.h"
#include "gmock/gmock.h"
#include "gtest/gtest.h"
+
+#include "atrace_wrapper.h"
+#include "ftrace_procfs.h"
#include "proto_translation_table.h"
using testing::_;
using testing::AnyNumber;
using testing::Contains;
+using testing::ElementsAreArray;
+using testing::Eq;
using testing::IsEmpty;
using testing::NiceMock;
using testing::Not;
@@ -52,6 +56,20 @@
MOCK_CONST_METHOD0(NumberOfCpus, size_t());
};
+struct MockRunAtrace {
+ MockRunAtrace() {
+ static MockRunAtrace* instance;
+ instance = this;
+ SetRunAtraceForTesting([](const std::vector<std::string>& args) {
+ return instance->RunAtrace(args);
+ });
+ }
+
+ ~MockRunAtrace() { SetRunAtraceForTesting(nullptr); }
+
+ MOCK_METHOD1(RunAtrace, bool(const std::vector<std::string>&));
+};
+
std::unique_ptr<ProtoTranslationTable> CreateFakeTable() {
std::vector<Field> common_fields;
std::vector<Event> events;
@@ -157,15 +175,10 @@
ASSERT_FALSE(id);
}
-// TODO(hjd): Mock atrace on Android.
-#if PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
-#define MAYBE_Atrace DISABLED_Atrace
-#else
-#define MAYBE_Atrace Atrace
-#endif
-TEST(FtraceConfigMuxerTest, MAYBE_Atrace) {
+TEST(FtraceConfigMuxerTest, Atrace) {
std::unique_ptr<ProtoTranslationTable> table = CreateFakeTable();
NiceMock<MockFtraceProcfs> ftrace;
+ MockRunAtrace atrace;
FtraceConfig config = CreateFtraceConfig({"sched_switch"});
*config.add_atrace_categories() = "sched";
@@ -174,6 +187,9 @@
EXPECT_CALL(ftrace, ReadOneCharFromFile("/root/tracing_on"))
.WillOnce(Return('0'));
+ EXPECT_CALL(atrace,
+ RunAtrace(ElementsAreArray({"atrace", "--async_start", "sched"})))
+ .WillOnce(Return(true));
FtraceConfigId id = model.RequestConfig(config);
ASSERT_TRUE(id);
@@ -183,6 +199,8 @@
EXPECT_THAT(actual_config->ftrace_events(), Contains("sched_switch"));
EXPECT_THAT(actual_config->ftrace_events(), Contains("print"));
+ EXPECT_CALL(atrace, RunAtrace(ElementsAreArray({"atrace", "--async_stop"})))
+ .WillOnce(Return(true));
ASSERT_TRUE(model.RemoveConfig(id));
}
diff --git a/src/ftrace_reader/ftrace_controller_unittest.cc b/src/ftrace_reader/ftrace_controller_unittest.cc
index 5eed521..964baff 100644
--- a/src/ftrace_reader/ftrace_controller_unittest.cc
+++ b/src/ftrace_reader/ftrace_controller_unittest.cc
@@ -260,8 +260,9 @@
std::unique_ptr<MockFtraceProcfs>(new MockFtraceProcfs(cpu_count));
}
- MockFtraceProcfs* raw_procfs = ftrace_procfs.get();
auto model = FakeModel(ftrace_procfs.get(), table.get());
+
+ MockFtraceProcfs* raw_procfs = ftrace_procfs.get();
return std::unique_ptr<TestFtraceController>(new TestFtraceController(
std::move(ftrace_procfs), std::move(table), std::move(model),
std::move(runner), raw_procfs));