Add lazy startup producer class to traced.
This is sufficiently different to the heapprofd system properties to warrant
a parallel implementation.
heapprofd requires a global property that signals whether to profile at all or
whether to profile all processes.
Change-Id: I5ff5e317b9cd99310b145b5501bff3f4afccb56d
Bug: 126724929
diff --git a/Android.bp b/Android.bp
index d450d6f..aa87928 100644
--- a/Android.bp
+++ b/Android.bp
@@ -276,6 +276,7 @@
"src/traced/probes/probes_producer.cc",
"src/traced/probes/ps/process_stats_data_source.cc",
"src/traced/probes/sys_stats/sys_stats_data_source.cc",
+ "src/traced/service/lazy_producer.cc",
"src/traced/service/service.cc",
"src/tracing/api_impl/consumer_api.cc",
"src/tracing/core/android_log_config.cc",
@@ -2940,6 +2941,9 @@
"src/traced/probes/ps/process_stats_data_source_unittest.cc",
"src/traced/probes/sys_stats/sys_stats_data_source.cc",
"src/traced/probes/sys_stats/sys_stats_data_source_unittest.cc",
+ "src/traced/service/lazy_producer.cc",
+ "src/traced/service/lazy_producer_unittest.cc",
+ "src/traced/service/service.cc",
"src/tracing/core/android_log_config.cc",
"src/tracing/core/android_power_config.cc",
"src/tracing/core/chrome_config.cc",
diff --git a/BUILD.gn b/BUILD.gn
index 971d25d..d941328 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -113,6 +113,7 @@
"gn:gtest_main",
"src/base:unittests",
"src/protozero:unittests",
+ "src/traced/service:unittests",
"src/tracing:unittests",
]
diff --git a/heapprofd.rc b/heapprofd.rc
index f1869bf..8868751 100644
--- a/heapprofd.rc
+++ b/heapprofd.rc
@@ -24,5 +24,8 @@
on property:persist.heapprofd.enable=1
start heapprofd
-on property:persist.heapprofd.enable=0
+on property:traced.lazy.heapprofd=1
+ start heapprofd
+
+on property:persist.heapprofd.enable=0 && property:traced.lazy.heapprofd=0
stop heapprofd
diff --git a/include/perfetto/tracing/ipc/service_ipc_host.h b/include/perfetto/tracing/ipc/service_ipc_host.h
index ccdc89b..eeec568 100644
--- a/include/perfetto/tracing/ipc/service_ipc_host.h
+++ b/include/perfetto/tracing/ipc/service_ipc_host.h
@@ -50,6 +50,8 @@
virtual bool Start(base::ScopedFile producer_socket_fd,
base::ScopedFile consumer_socket_fd) = 0;
+ virtual TracingService* service() const = 0;
+
protected:
ServiceIPCHost();
diff --git a/src/traced/service/BUILD.gn b/src/traced/service/BUILD.gn
index 6b027c6..f351f0e 100644
--- a/src/traced/service/BUILD.gn
+++ b/src/traced/service/BUILD.gn
@@ -23,6 +23,23 @@
"../../tracing:ipc",
]
sources = [
+ "lazy_producer.cc",
+ "lazy_producer.h",
"service.cc",
]
}
+
+source_set("unittests") {
+ testonly = true
+ deps = [
+ ":service",
+ "../../../gn:default_deps",
+ "../../../gn:gtest_deps",
+ "../../base",
+ "../../base:test_support",
+ "../../tracing",
+ ]
+ sources = [
+ "lazy_producer_unittest.cc",
+ ]
+}
diff --git a/src/traced/service/lazy_producer.cc b/src/traced/service/lazy_producer.cc
new file mode 100644
index 0000000..0787f26
--- /dev/null
+++ b/src/traced/service/lazy_producer.cc
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2019 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 "src/traced/service/lazy_producer.h"
+
+#include "perfetto/base/build_config.h"
+
+#include "perfetto/tracing/core/data_source_config.h"
+#include "perfetto/tracing/core/data_source_descriptor.h"
+
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
+#include <sys/system_properties.h>
+#endif
+
+namespace perfetto {
+
+LazyProducer::LazyProducer(base::TaskRunner* task_runner,
+ uint32_t delay_ms,
+ std::string data_source_name,
+ std::string property_name)
+ : task_runner_(task_runner),
+ delay_ms_(delay_ms),
+ data_source_name_(data_source_name),
+ property_name_(property_name),
+ weak_factory_(this) {}
+
+void LazyProducer::ConnectInProcess(TracingService* svc) {
+ endpoint_ = svc->ConnectProducer(this, geteuid(), "lazy_producer",
+ /*shm_hint_kb*/ 16);
+}
+
+void LazyProducer::OnConnect() {
+ DataSourceDescriptor dsd;
+ dsd.set_name(data_source_name_);
+ endpoint_->RegisterDataSource(dsd);
+}
+
+void LazyProducer::SetupDataSource(DataSourceInstanceID,
+ const DataSourceConfig&) {
+ SetAndroidProperty(property_name_, "1");
+ active_sessions_++;
+ generation_++;
+}
+
+void LazyProducer::StopDataSource(DataSourceInstanceID) {
+ if (--active_sessions_)
+ return;
+
+ uint64_t cur_generation = generation_;
+ auto weak_this = weak_factory_.GetWeakPtr();
+ task_runner_->PostDelayedTask(
+ [weak_this, cur_generation] {
+ if (!weak_this)
+ return;
+ if (weak_this->generation_ == cur_generation)
+ weak_this->SetAndroidProperty(weak_this->property_name_, "0");
+ },
+ delay_ms_);
+}
+
+bool LazyProducer::SetAndroidProperty(const std::string& name,
+ const std::string& value) {
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
+ return __system_property_set(name.c_str(), value.c_str()) == 0;
+#else
+ // Allow this to be mocked out for tests on other platforms.
+ base::ignore_result(name);
+ base::ignore_result(value);
+ return true;
+#endif
+}
+
+LazyProducer::~LazyProducer() {
+ if (active_sessions_)
+ SetAndroidProperty(property_name_, "0");
+}
+
+} // namespace perfetto
diff --git a/src/traced/service/lazy_producer.h b/src/traced/service/lazy_producer.h
new file mode 100644
index 0000000..dc6f3aa
--- /dev/null
+++ b/src/traced/service/lazy_producer.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2019 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_TRACED_SERVICE_LAZY_PRODUCER_H_
+#define SRC_TRACED_SERVICE_LAZY_PRODUCER_H_
+
+#include <set>
+#include <string>
+
+#include "perfetto/base/task_runner.h"
+#include "perfetto/base/weak_ptr.h"
+
+#include "perfetto/tracing/core/basic_types.h"
+#include "perfetto/tracing/core/producer.h"
+#include "perfetto/tracing/core/tracing_service.h"
+
+namespace perfetto {
+
+class LazyProducer : public Producer {
+ public:
+ LazyProducer(base::TaskRunner* task_runner,
+ uint32_t delay_ms,
+ std::string data_source_name,
+ std::string property_name);
+
+ ~LazyProducer() override;
+ // No-ops to satisfy the Producer implementation.
+ void OnDisconnect() override {}
+ void OnTracingSetup() override {}
+ void StartDataSource(DataSourceInstanceID, const DataSourceConfig&) override {
+ }
+ void Flush(FlushRequestID, const DataSourceInstanceID*, size_t) override {}
+
+ void OnConnect() override;
+ void SetupDataSource(DataSourceInstanceID, const DataSourceConfig&) override;
+ void StopDataSource(DataSourceInstanceID) override;
+
+ void ConnectInProcess(TracingService* svc);
+ virtual bool SetAndroidProperty(const std::string& name,
+ const std::string& value);
+
+ private:
+ base::TaskRunner* task_runner_;
+ uint32_t delay_ms_;
+
+ std::string data_source_name_;
+ std::string property_name_;
+
+ std::unique_ptr<TracingService::ProducerEndpoint> endpoint_;
+ uint64_t active_sessions_ = 0;
+ uint64_t generation_ = 0;
+
+ base::WeakPtrFactory<LazyProducer> weak_factory_; // Keep last.
+};
+
+} // namespace perfetto
+
+#endif // SRC_TRACED_SERVICE_LAZY_PRODUCER_H_
diff --git a/src/traced/service/lazy_producer_unittest.cc b/src/traced/service/lazy_producer_unittest.cc
new file mode 100644
index 0000000..5565481
--- /dev/null
+++ b/src/traced/service/lazy_producer_unittest.cc
@@ -0,0 +1,93 @@
+/*
+ * 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 "src/traced/service/lazy_producer.h"
+
+#include "src/base/test/test_task_runner.h"
+
+#include "perfetto/tracing/core/data_source_config.h"
+
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+
+namespace perfetto {
+namespace {
+
+constexpr const char* kDataSourceName = "android.heapprofd";
+constexpr const char* kPropertyName = "persist.heapprofd.enable";
+
+using ::testing::_;
+using ::testing::InSequence;
+using ::testing::Return;
+
+class MockLazyProducer : public LazyProducer {
+ public:
+ MockLazyProducer(base::TaskRunner* task_runner)
+ : LazyProducer(task_runner, 0, kDataSourceName, kPropertyName) {}
+
+ MOCK_METHOD2(SetAndroidProperty,
+ bool(const std::string&, const std::string&));
+};
+
+TEST(LazyProducersTest, Simple) {
+ DataSourceConfig cfg;
+ cfg.set_name(kDataSourceName);
+ base::TestTaskRunner task_runner;
+ MockLazyProducer p(&task_runner);
+ InSequence s;
+ EXPECT_CALL(p, SetAndroidProperty(kPropertyName, "1")).WillOnce(Return(true));
+ EXPECT_CALL(p, SetAndroidProperty(kPropertyName, "0")).WillOnce(Return(true));
+ p.SetupDataSource(1, cfg);
+ p.StopDataSource(1);
+ task_runner.RunUntilIdle();
+}
+
+TEST(LazyProducersTest, RefCount) {
+ DataSourceConfig cfg;
+ cfg.set_name(kDataSourceName);
+ base::TestTaskRunner task_runner;
+ MockLazyProducer p(&task_runner);
+ InSequence s;
+ EXPECT_CALL(p, SetAndroidProperty(kPropertyName, "1"))
+ .WillRepeatedly(Return(true));
+ p.SetupDataSource(1, cfg);
+ p.SetupDataSource(2, cfg);
+ p.StopDataSource(2);
+ task_runner.RunUntilIdle();
+ EXPECT_CALL(p, SetAndroidProperty(kPropertyName, "0")).WillOnce(Return(true));
+ p.StopDataSource(1);
+ task_runner.RunUntilIdle();
+}
+
+TEST(LazyProducersTest, NoFlap) {
+ DataSourceConfig cfg;
+ cfg.set_name(kDataSourceName);
+ base::TestTaskRunner task_runner;
+ MockLazyProducer p(&task_runner);
+ InSequence s;
+ EXPECT_CALL(p, SetAndroidProperty(kPropertyName, "1"))
+ .WillRepeatedly(Return(true));
+ p.SetupDataSource(1, cfg);
+ p.StopDataSource(1);
+ p.SetupDataSource(2, cfg);
+ task_runner.RunUntilIdle();
+ p.StopDataSource(2);
+ EXPECT_CALL(p, SetAndroidProperty(kPropertyName, "0")).WillOnce(Return(true));
+ task_runner.RunUntilIdle();
+}
+
+} // namespace
+} // namespace perfetto
diff --git a/src/traced/service/service.cc b/src/traced/service/service.cc
index ae8d82d..c52b246 100644
--- a/src/traced/service/service.cc
+++ b/src/traced/service/service.cc
@@ -18,6 +18,7 @@
#include "perfetto/base/watchdog.h"
#include "perfetto/traced/traced.h"
#include "perfetto/tracing/ipc/service_ipc_host.h"
+#include "src/traced/service/lazy_producer.h"
#include "src/tracing/ipc/default_socket.h"
namespace perfetto {
@@ -49,6 +50,10 @@
return 1;
}
+ LazyProducer lazy_heapprofd(&task_runner, /*delay_ms=*/30000,
+ "android.heapprofd", "traced.lazy.heapprofd");
+ lazy_heapprofd.ConnectInProcess(svc->service());
+
// Set the CPU limit and start the watchdog running. The memory limit will
// be set inside the service code as it relies on the size of buffers.
// The CPU limit is 75% over a 30 second interval.
diff --git a/src/tracing/ipc/service/service_ipc_host_impl.cc b/src/tracing/ipc/service/service_ipc_host_impl.cc
index 4338a3b..9c185ac 100644
--- a/src/tracing/ipc/service/service_ipc_host_impl.cc
+++ b/src/tracing/ipc/service/service_ipc_host_impl.cc
@@ -88,7 +88,7 @@
return true;
}
-TracingService* ServiceIPCHostImpl::service_for_testing() const {
+TracingService* ServiceIPCHostImpl::service() const {
return svc_.get();
}
diff --git a/src/tracing/ipc/service/service_ipc_host_impl.h b/src/tracing/ipc/service/service_ipc_host_impl.h
index 8e10322..e7f5cdd 100644
--- a/src/tracing/ipc/service/service_ipc_host_impl.h
+++ b/src/tracing/ipc/service/service_ipc_host_impl.h
@@ -42,7 +42,7 @@
bool Start(base::ScopedFile producer_socket_fd,
base::ScopedFile consumer_socket_fd) override;
- TracingService* service_for_testing() const;
+ TracingService* service() const override;
private:
bool DoStart();