1 /*
2 * Copyright (C) 2019 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "src/traced/service/builtin_producer.h"
18
19 #include <sys/types.h>
20
21 #include "perfetto/base/build_config.h"
22 #include "perfetto/base/logging.h"
23 #include "perfetto/ext/base/metatrace.h"
24 #include "perfetto/ext/base/utils.h"
25 #include "perfetto/ext/base/weak_ptr.h"
26 #include "perfetto/ext/tracing/core/basic_types.h"
27 #include "perfetto/ext/tracing/core/trace_writer.h"
28 #include "perfetto/ext/tracing/core/tracing_service.h"
29 #include "perfetto/tracing/core/data_source_config.h"
30 #include "perfetto/tracing/core/data_source_descriptor.h"
31 #include "src/tracing/core/metatrace_writer.h"
32
33 #if PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
34 #include <sys/system_properties.h>
35 #endif
36
37 namespace perfetto {
38
39 namespace {
40
41 constexpr char kHeapprofdDataSourceName[] = "android.heapprofd";
42 constexpr char kJavaHprofDataSourceName[] = "android.java_hprof";
43 constexpr char kTracedPerfDataSourceName[] = "linux.perf";
44 constexpr char kLazyHeapprofdPropertyName[] = "traced.lazy.heapprofd";
45 constexpr char kLazyTracedPerfPropertyName[] = "traced.lazy.traced_perf";
46
47 } // namespace
48
BuiltinProducer(base::TaskRunner * task_runner,uint32_t lazy_stop_delay_ms)49 BuiltinProducer::BuiltinProducer(base::TaskRunner* task_runner,
50 uint32_t lazy_stop_delay_ms)
51 : task_runner_(task_runner), weak_factory_(this) {
52 lazy_heapprofd_.stop_delay_ms = lazy_stop_delay_ms;
53 lazy_traced_perf_.stop_delay_ms = lazy_stop_delay_ms;
54 }
55
~BuiltinProducer()56 BuiltinProducer::~BuiltinProducer() {
57 if (!lazy_heapprofd_.instance_ids.empty())
58 SetAndroidProperty(kLazyHeapprofdPropertyName, "");
59 if (!lazy_traced_perf_.instance_ids.empty())
60 SetAndroidProperty(kLazyTracedPerfPropertyName, "");
61 }
62
ConnectInProcess(TracingService * svc)63 void BuiltinProducer::ConnectInProcess(TracingService* svc) {
64 endpoint_ = svc->ConnectProducer(
65 this, base::GetCurrentUserId(), "traced",
66 /*shared_memory_size_hint_bytes=*/16 * 1024, /*in_process=*/true,
67 TracingService::ProducerSMBScrapingMode::kDisabled,
68 /*shared_memory_page_size_hint_bytes=*/4096);
69 }
70
OnConnect()71 void BuiltinProducer::OnConnect() {
72 DataSourceDescriptor metatrace_dsd;
73 metatrace_dsd.set_name(MetatraceWriter::kDataSourceName);
74 metatrace_dsd.set_will_notify_on_stop(true);
75 endpoint_->RegisterDataSource(metatrace_dsd);
76 {
77 DataSourceDescriptor lazy_heapprofd_dsd;
78 lazy_heapprofd_dsd.set_name(kHeapprofdDataSourceName);
79 endpoint_->RegisterDataSource(lazy_heapprofd_dsd);
80 }
81 {
82 DataSourceDescriptor lazy_java_hprof_dsd;
83 lazy_java_hprof_dsd.set_name(kJavaHprofDataSourceName);
84 endpoint_->RegisterDataSource(lazy_java_hprof_dsd);
85 }
86 {
87 DataSourceDescriptor lazy_traced_perf_dsd;
88 lazy_traced_perf_dsd.set_name(kTracedPerfDataSourceName);
89 endpoint_->RegisterDataSource(lazy_traced_perf_dsd);
90 }
91 }
92
SetupDataSource(DataSourceInstanceID ds_id,const DataSourceConfig & ds_config)93 void BuiltinProducer::SetupDataSource(DataSourceInstanceID ds_id,
94 const DataSourceConfig& ds_config) {
95 if (ds_config.name() == kHeapprofdDataSourceName ||
96 ds_config.name() == kJavaHprofDataSourceName) {
97 SetAndroidProperty(kLazyHeapprofdPropertyName, "1");
98 lazy_heapprofd_.generation++;
99 lazy_heapprofd_.instance_ids.emplace(ds_id);
100 return;
101 }
102
103 if (ds_config.name() == kTracedPerfDataSourceName) {
104 SetAndroidProperty(kLazyTracedPerfPropertyName, "1");
105 lazy_traced_perf_.generation++;
106 lazy_traced_perf_.instance_ids.emplace(ds_id);
107 return;
108 }
109 }
110
StartDataSource(DataSourceInstanceID ds_id,const DataSourceConfig & ds_config)111 void BuiltinProducer::StartDataSource(DataSourceInstanceID ds_id,
112 const DataSourceConfig& ds_config) {
113 // We slightly rely on the fact that since this producer is in-process for
114 // enabling metatrace early (relative to producers that are notified via IPC).
115 if (ds_config.name() == MetatraceWriter::kDataSourceName) {
116 auto writer = endpoint_->CreateTraceWriter(
117 static_cast<BufferID>(ds_config.target_buffer()));
118
119 auto it_and_inserted = metatrace_.writers.emplace(
120 std::piecewise_construct, std::make_tuple(ds_id), std::make_tuple());
121 PERFETTO_DCHECK(it_and_inserted.second);
122 // Note: only the first concurrent writer will actually be active.
123 metatrace_.writers[ds_id].Enable(task_runner_, std::move(writer),
124 metatrace::TAG_ANY);
125 }
126 }
127
StopDataSource(DataSourceInstanceID ds_id)128 void BuiltinProducer::StopDataSource(DataSourceInstanceID ds_id) {
129 auto meta_it = metatrace_.writers.find(ds_id);
130 if (meta_it != metatrace_.writers.end()) {
131 // Synchronously re-flush the metatrace writer to record more of the
132 // teardown interactions, then ack the stop.
133 meta_it->second.WriteAllAndFlushTraceWriter([] {});
134 metatrace_.writers.erase(meta_it);
135 endpoint_->NotifyDataSourceStopped(ds_id);
136 return;
137 }
138
139 MaybeInitiateLazyStop(ds_id, &lazy_heapprofd_, kLazyHeapprofdPropertyName);
140 MaybeInitiateLazyStop(ds_id, &lazy_traced_perf_, kLazyTracedPerfPropertyName);
141 }
142
MaybeInitiateLazyStop(DataSourceInstanceID ds_id,LazyAndroidDaemonState * lazy_state,const char * prop_name)143 void BuiltinProducer::MaybeInitiateLazyStop(DataSourceInstanceID ds_id,
144 LazyAndroidDaemonState* lazy_state,
145 const char* prop_name) {
146 auto lazy_it = lazy_state->instance_ids.find(ds_id);
147 if (lazy_it != lazy_state->instance_ids.end()) {
148 lazy_state->instance_ids.erase(lazy_it);
149
150 // if no more sessions - stop daemon after a delay
151 if (lazy_state->instance_ids.empty()) {
152 uint64_t cur_generation = lazy_state->generation;
153 auto weak_this = weak_factory_.GetWeakPtr();
154 task_runner_->PostDelayedTask(
155 [weak_this, cur_generation, lazy_state, prop_name] {
156 if (!weak_this)
157 return;
158 // |lazy_state| should be valid if the |weak_this| is still valid
159 if (lazy_state->generation == cur_generation)
160 weak_this->SetAndroidProperty(prop_name, "");
161 },
162 lazy_state->stop_delay_ms);
163 }
164 }
165 }
166
Flush(FlushRequestID flush_id,const DataSourceInstanceID * ds_ids,size_t num_ds_ids)167 void BuiltinProducer::Flush(FlushRequestID flush_id,
168 const DataSourceInstanceID* ds_ids,
169 size_t num_ds_ids) {
170 for (size_t i = 0; i < num_ds_ids; i++) {
171 auto meta_it = metatrace_.writers.find(ds_ids[i]);
172 if (meta_it != metatrace_.writers.end()) {
173 meta_it->second.WriteAllAndFlushTraceWriter([] {});
174 }
175 // nothing to be done for lazy sources
176 }
177 endpoint_->NotifyFlushComplete(flush_id);
178 }
179
SetAndroidProperty(const std::string & name,const std::string & value)180 bool BuiltinProducer::SetAndroidProperty(const std::string& name,
181 const std::string& value) {
182 #if PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
183 return __system_property_set(name.c_str(), value.c_str()) == 0;
184 #else
185 // Allow this to be mocked out for tests on other platforms.
186 base::ignore_result(name);
187 base::ignore_result(value);
188 return true;
189 #endif
190 }
191
192 } // namespace perfetto
193