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/base/proc_utils.h"
24 #include "perfetto/ext/base/metatrace.h"
25 #include "perfetto/ext/base/utils.h"
26 #include "perfetto/ext/base/weak_ptr.h"
27 #include "perfetto/ext/tracing/core/basic_types.h"
28 #include "perfetto/ext/tracing/core/trace_writer.h"
29 #include "perfetto/ext/tracing/core/tracing_service.h"
30 #include "perfetto/tracing/core/data_source_config.h"
31 #include "perfetto/tracing/core/data_source_descriptor.h"
32 #include "src/tracing/core/metatrace_writer.h"
33
34 // This translation unit is only ever used in Android in-tree builds.
35 // These producers are here to dynamically start heapprofd and other services
36 // via sysprops when a trace that requests them is active. That can only happen
37 // in in-tree builds of Android.
38
39 #if PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
40 #include <sys/system_properties.h>
41 #endif
42
43 namespace perfetto {
44
45 namespace {
46
47 constexpr char kHeapprofdDataSourceName[] = "android.heapprofd";
48 constexpr char kJavaHprofDataSourceName[] = "android.java_hprof";
49 constexpr char kJavaHprofOomDataSourceName[] = "android.java_hprof.oom";
50 constexpr char kTracedPerfDataSourceName[] = "linux.perf";
51 constexpr char kLazyHeapprofdPropertyName[] = "traced.lazy.heapprofd";
52 constexpr char kLazyTracedPerfPropertyName[] = "traced.lazy.traced_perf";
53 constexpr char kJavaHprofOomActivePropertyName[] = "traced.oome_heap_session.count";
54
55 } // namespace
56
BuiltinProducer(base::TaskRunner * task_runner,uint32_t lazy_stop_delay_ms)57 BuiltinProducer::BuiltinProducer(base::TaskRunner* task_runner,
58 uint32_t lazy_stop_delay_ms)
59 : task_runner_(task_runner), weak_factory_(this) {
60 lazy_heapprofd_.stop_delay_ms = lazy_stop_delay_ms;
61 lazy_traced_perf_.stop_delay_ms = lazy_stop_delay_ms;
62 }
63
~BuiltinProducer()64 BuiltinProducer::~BuiltinProducer() {
65 if (!lazy_heapprofd_.instance_ids.empty())
66 SetAndroidProperty(kLazyHeapprofdPropertyName, "");
67 if (!lazy_traced_perf_.instance_ids.empty())
68 SetAndroidProperty(kLazyTracedPerfPropertyName, "");
69 if (!java_hprof_oome_instances_.empty())
70 SetAndroidProperty(kJavaHprofOomActivePropertyName, "");
71 }
72
ConnectInProcess(TracingService * svc)73 void BuiltinProducer::ConnectInProcess(TracingService* svc) {
74 #if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
75 // TODO(primiano): ConnectProducer should take a base::PlatformProcessId not
76 // pid_t, as they are different on Windows. But that is a larger refactoring
77 // and not worth given this is the only use case where it clashes.
78 const pid_t cur_proc_id = 0;
79 #else
80 const pid_t cur_proc_id = base::GetProcessId();
81 #endif
82 endpoint_ = svc->ConnectProducer(
83 this, base::GetCurrentUserId(), cur_proc_id, "traced",
84 /*shared_memory_size_hint_bytes=*/16 * 1024, /*in_process=*/true,
85 TracingService::ProducerSMBScrapingMode::kDisabled,
86 /*shared_memory_page_size_hint_bytes=*/4096);
87 }
88
OnConnect()89 void BuiltinProducer::OnConnect() {
90 DataSourceDescriptor metatrace_dsd;
91 metatrace_dsd.set_name(MetatraceWriter::kDataSourceName);
92 metatrace_dsd.set_will_notify_on_stop(true);
93 endpoint_->RegisterDataSource(metatrace_dsd);
94 {
95 DataSourceDescriptor lazy_heapprofd_dsd;
96 lazy_heapprofd_dsd.set_name(kHeapprofdDataSourceName);
97 endpoint_->RegisterDataSource(lazy_heapprofd_dsd);
98 }
99 {
100 DataSourceDescriptor lazy_java_hprof_dsd;
101 lazy_java_hprof_dsd.set_name(kJavaHprofDataSourceName);
102 endpoint_->RegisterDataSource(lazy_java_hprof_dsd);
103 }
104 {
105 DataSourceDescriptor lazy_traced_perf_dsd;
106 lazy_traced_perf_dsd.set_name(kTracedPerfDataSourceName);
107 endpoint_->RegisterDataSource(lazy_traced_perf_dsd);
108 }
109 {
110 DataSourceDescriptor java_hprof_oome_dsd;
111 java_hprof_oome_dsd.set_name(kJavaHprofOomDataSourceName);
112 endpoint_->RegisterDataSource(java_hprof_oome_dsd);
113 }
114 }
115
SetupDataSource(DataSourceInstanceID ds_id,const DataSourceConfig & ds_config)116 void BuiltinProducer::SetupDataSource(DataSourceInstanceID ds_id,
117 const DataSourceConfig& ds_config) {
118 if (ds_config.name() == kHeapprofdDataSourceName ||
119 ds_config.name() == kJavaHprofDataSourceName) {
120 SetAndroidProperty(kLazyHeapprofdPropertyName, "1");
121 lazy_heapprofd_.generation++;
122 lazy_heapprofd_.instance_ids.emplace(ds_id);
123 return;
124 }
125
126 if (ds_config.name() == kTracedPerfDataSourceName) {
127 SetAndroidProperty(kLazyTracedPerfPropertyName, "1");
128 lazy_traced_perf_.generation++;
129 lazy_traced_perf_.instance_ids.emplace(ds_id);
130 return;
131 }
132
133 if (ds_config.name() == kJavaHprofOomDataSourceName) {
134 java_hprof_oome_instances_.emplace(ds_id);
135 SetAndroidProperty(kJavaHprofOomActivePropertyName,
136 std::to_string(java_hprof_oome_instances_.size()));
137 return;
138 }
139 }
140
StartDataSource(DataSourceInstanceID ds_id,const DataSourceConfig & ds_config)141 void BuiltinProducer::StartDataSource(DataSourceInstanceID ds_id,
142 const DataSourceConfig& ds_config) {
143 // We slightly rely on the fact that since this producer is in-process for
144 // enabling metatrace early (relative to producers that are notified via IPC).
145 if (ds_config.name() == MetatraceWriter::kDataSourceName) {
146 auto writer = endpoint_->CreateTraceWriter(
147 static_cast<BufferID>(ds_config.target_buffer()));
148
149 auto it_and_inserted = metatrace_.writers.emplace(
150 std::piecewise_construct, std::make_tuple(ds_id), std::make_tuple());
151 PERFETTO_DCHECK(it_and_inserted.second);
152 // Note: only the first concurrent writer will actually be active.
153 metatrace_.writers[ds_id].Enable(task_runner_, std::move(writer),
154 metatrace::TAG_ANY);
155 }
156 }
157
StopDataSource(DataSourceInstanceID ds_id)158 void BuiltinProducer::StopDataSource(DataSourceInstanceID ds_id) {
159 auto meta_it = metatrace_.writers.find(ds_id);
160 if (meta_it != metatrace_.writers.end()) {
161 // Synchronously re-flush the metatrace writer to record more of the
162 // teardown interactions, then ack the stop.
163 meta_it->second.WriteAllAndFlushTraceWriter([] {});
164 metatrace_.writers.erase(meta_it);
165 endpoint_->NotifyDataSourceStopped(ds_id);
166 return;
167 }
168
169 MaybeInitiateLazyStop(ds_id, &lazy_heapprofd_, kLazyHeapprofdPropertyName);
170 MaybeInitiateLazyStop(ds_id, &lazy_traced_perf_, kLazyTracedPerfPropertyName);
171
172 auto oome_it = java_hprof_oome_instances_.find(ds_id);
173 if (oome_it != java_hprof_oome_instances_.end()) {
174 java_hprof_oome_instances_.erase(oome_it);
175 SetAndroidProperty(kJavaHprofOomActivePropertyName,
176 std::to_string(java_hprof_oome_instances_.size()));
177 }
178 }
179
MaybeInitiateLazyStop(DataSourceInstanceID ds_id,LazyAndroidDaemonState * lazy_state,const char * prop_name)180 void BuiltinProducer::MaybeInitiateLazyStop(DataSourceInstanceID ds_id,
181 LazyAndroidDaemonState* lazy_state,
182 const char* prop_name) {
183 auto lazy_it = lazy_state->instance_ids.find(ds_id);
184 if (lazy_it != lazy_state->instance_ids.end()) {
185 lazy_state->instance_ids.erase(lazy_it);
186
187 // if no more sessions - stop daemon after a delay
188 if (lazy_state->instance_ids.empty()) {
189 uint64_t cur_generation = lazy_state->generation;
190 auto weak_this = weak_factory_.GetWeakPtr();
191 task_runner_->PostDelayedTask(
192 [weak_this, cur_generation, lazy_state, prop_name] {
193 if (!weak_this)
194 return;
195 // |lazy_state| should be valid if the |weak_this| is still valid
196 if (lazy_state->generation == cur_generation)
197 weak_this->SetAndroidProperty(prop_name, "");
198 },
199 lazy_state->stop_delay_ms);
200 }
201 }
202 }
203
Flush(FlushRequestID flush_id,const DataSourceInstanceID * ds_ids,size_t num_ds_ids)204 void BuiltinProducer::Flush(FlushRequestID flush_id,
205 const DataSourceInstanceID* ds_ids,
206 size_t num_ds_ids) {
207 for (size_t i = 0; i < num_ds_ids; i++) {
208 auto meta_it = metatrace_.writers.find(ds_ids[i]);
209 if (meta_it != metatrace_.writers.end()) {
210 meta_it->second.WriteAllAndFlushTraceWriter([] {});
211 }
212 // nothing to be done for lazy sources
213 }
214 endpoint_->NotifyFlushComplete(flush_id);
215 }
216
SetAndroidProperty(const std::string & name,const std::string & value)217 bool BuiltinProducer::SetAndroidProperty(const std::string& name,
218 const std::string& value) {
219 #if PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
220 return __system_property_set(name.c_str(), value.c_str()) == 0;
221 #else
222 // Allow this to be mocked out for tests on other platforms.
223 base::ignore_result(name);
224 base::ignore_result(value);
225 return true;
226 #endif
227 }
228
229 } // namespace perfetto
230