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/client_identity.h"
29 #include "perfetto/ext/tracing/core/trace_writer.h"
30 #include "perfetto/ext/tracing/core/tracing_service.h"
31 #include "perfetto/tracing/core/data_source_config.h"
32 #include "perfetto/tracing/core/data_source_descriptor.h"
33 #include "src/tracing/service/metatrace_writer.h"
34
35 #include "protos/perfetto/config/android/android_sdk_sysprop_guard_config.pbzero.h"
36
37 // This translation unit is only ever used in Android in-tree builds.
38 // These producers are here to dynamically start heapprofd and other services
39 // via sysprops when a trace that requests them is active. That can only happen
40 // in in-tree builds of Android.
41
42 #if PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
43 #include <sys/system_properties.h>
44 #endif
45
46 namespace perfetto {
47
48 namespace {
49
50 constexpr char kHeapprofdDataSourceName[] = "android.heapprofd";
51 constexpr char kJavaHprofDataSourceName[] = "android.java_hprof";
52 constexpr char kJavaHprofOomDataSourceName[] = "android.java_hprof.oom";
53 constexpr char kTracedPerfDataSourceName[] = "linux.perf";
54 constexpr char kLazyHeapprofdPropertyName[] = "traced.lazy.heapprofd";
55 constexpr char kLazyTracedPerfPropertyName[] = "traced.lazy.traced_perf";
56 constexpr char kJavaHprofOomActivePropertyName[] =
57 "traced.oome_heap_session.count";
58
59 constexpr char kAndroidSdkSyspropGuardDataSourceName[] =
60 "android.sdk_sysprop_guard";
61 constexpr char kPerfettoSdkSyspropGuardGenerationPropertyName[] =
62 "debug.tracing.ctl.perfetto.sdk_sysprop_guard_generation";
63 constexpr char kHwuiSkiaBroadTracingPropertyName[] =
64 "debug.tracing.ctl.hwui.skia_tracing_enabled";
65 constexpr char kHwuiSkiaUsePerfettoPropertyName[] =
66 "debug.tracing.ctl.hwui.skia_use_perfetto_track_events";
67 constexpr char kHwuiSkiaPropertyPackageSeparator[] = ".";
68 constexpr char kSurfaceFlingerSkiaBroadTracingPropertyName[] =
69 "debug.tracing.ctl.renderengine.skia_tracing_enabled";
70 constexpr char kSurfaceFlingerSkiaUsePerfettoPropertyName[] =
71 "debug.tracing.ctl.renderengine.skia_use_perfetto_track_events";
72
73 } // namespace
74
BuiltinProducer(base::TaskRunner * task_runner,uint32_t lazy_stop_delay_ms)75 BuiltinProducer::BuiltinProducer(base::TaskRunner* task_runner,
76 uint32_t lazy_stop_delay_ms)
77 : task_runner_(task_runner), weak_factory_(this) {
78 lazy_heapprofd_.stop_delay_ms = lazy_stop_delay_ms;
79 lazy_traced_perf_.stop_delay_ms = lazy_stop_delay_ms;
80 }
81
~BuiltinProducer()82 BuiltinProducer::~BuiltinProducer() {
83 if (!lazy_heapprofd_.instance_ids.empty())
84 SetAndroidProperty(kLazyHeapprofdPropertyName, "");
85 if (!lazy_traced_perf_.instance_ids.empty())
86 SetAndroidProperty(kLazyTracedPerfPropertyName, "");
87 if (!java_hprof_oome_instances_.empty())
88 SetAndroidProperty(kJavaHprofOomActivePropertyName, "");
89 }
90
ConnectInProcess(TracingService * svc)91 void BuiltinProducer::ConnectInProcess(TracingService* svc) {
92 #if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
93 // TODO(primiano): ConnectProducer should take a base::PlatformProcessId not
94 // pid_t, as they are different on Windows. But that is a larger refactoring
95 // and not worth given this is the only use case where it clashes.
96 const pid_t cur_proc_id = 0;
97 #else
98 const pid_t cur_proc_id = base::GetProcessId();
99 #endif
100 endpoint_ = svc->ConnectProducer(
101 this, ClientIdentity(base::GetCurrentUserId(), cur_proc_id), "traced",
102 /*shared_memory_size_hint_bytes=*/16 * 1024, /*in_process=*/true,
103 TracingService::ProducerSMBScrapingMode::kDisabled,
104 /*shared_memory_page_size_hint_bytes=*/4096);
105 }
106
OnConnect()107 void BuiltinProducer::OnConnect() {
108 DataSourceDescriptor metatrace_dsd;
109 metatrace_dsd.set_name(MetatraceWriter::kDataSourceName);
110 metatrace_dsd.set_will_notify_on_stop(true);
111 endpoint_->RegisterDataSource(metatrace_dsd);
112 {
113 DataSourceDescriptor lazy_heapprofd_dsd;
114 lazy_heapprofd_dsd.set_name(kHeapprofdDataSourceName);
115 endpoint_->RegisterDataSource(lazy_heapprofd_dsd);
116 }
117 {
118 DataSourceDescriptor lazy_java_hprof_dsd;
119 lazy_java_hprof_dsd.set_name(kJavaHprofDataSourceName);
120 endpoint_->RegisterDataSource(lazy_java_hprof_dsd);
121 }
122 {
123 DataSourceDescriptor lazy_traced_perf_dsd;
124 lazy_traced_perf_dsd.set_name(kTracedPerfDataSourceName);
125 endpoint_->RegisterDataSource(lazy_traced_perf_dsd);
126 }
127 {
128 DataSourceDescriptor java_hprof_oome_dsd;
129 java_hprof_oome_dsd.set_name(kJavaHprofOomDataSourceName);
130 endpoint_->RegisterDataSource(java_hprof_oome_dsd);
131 }
132 {
133 DataSourceDescriptor track_event_dsd;
134 track_event_dsd.set_name(kAndroidSdkSyspropGuardDataSourceName);
135 endpoint_->RegisterDataSource(track_event_dsd);
136 }
137 }
138
SetupDataSource(DataSourceInstanceID ds_id,const DataSourceConfig & ds_config)139 void BuiltinProducer::SetupDataSource(DataSourceInstanceID ds_id,
140 const DataSourceConfig& ds_config) {
141 if (ds_config.name() == kHeapprofdDataSourceName ||
142 ds_config.name() == kJavaHprofDataSourceName) {
143 SetAndroidProperty(kLazyHeapprofdPropertyName, "1");
144 lazy_heapprofd_.generation++;
145 lazy_heapprofd_.instance_ids.emplace(ds_id);
146 return;
147 }
148
149 if (ds_config.name() == kTracedPerfDataSourceName) {
150 SetAndroidProperty(kLazyTracedPerfPropertyName, "1");
151 lazy_traced_perf_.generation++;
152 lazy_traced_perf_.instance_ids.emplace(ds_id);
153 return;
154 }
155
156 if (ds_config.name() == kJavaHprofOomDataSourceName) {
157 java_hprof_oome_instances_.emplace(ds_id);
158 SetAndroidProperty(kJavaHprofOomActivePropertyName,
159 std::to_string(java_hprof_oome_instances_.size()));
160 return;
161 }
162
163 // TODO(b/281329340): delete this when no longer needed.
164 if (ds_config.name() == kAndroidSdkSyspropGuardDataSourceName) {
165 protos::pbzero::AndroidSdkSyspropGuardConfig::Decoder sysprop_guard_config(
166 ds_config.android_sdk_sysprop_guard_config_raw());
167 std::vector<std::string> hwui_package_name_filter;
168 for (auto package = sysprop_guard_config.hwui_package_name_filter();
169 package; ++package) {
170 hwui_package_name_filter.emplace_back((*package).ToStdString());
171 }
172
173 bool increase_generation = false;
174
175 // SurfaceFlinger / RenderEngine
176 if (sysprop_guard_config.surfaceflinger_skia_track_events() &&
177 !android_sdk_sysprop_guard_state_.surfaceflinger_initialized) {
178 SetAndroidProperty(kSurfaceFlingerSkiaBroadTracingPropertyName, "true");
179 SetAndroidProperty(kSurfaceFlingerSkiaUsePerfettoPropertyName, "true");
180 android_sdk_sysprop_guard_state_.surfaceflinger_initialized = true;
181 increase_generation = true;
182 }
183
184 // HWUI apps
185 if (sysprop_guard_config.hwui_skia_track_events()) {
186 if (hwui_package_name_filter.size() > 0) {
187 // Set per-app flags
188 for (std::string package : hwui_package_name_filter) {
189 if (android_sdk_sysprop_guard_state_.hwui_packages_initialized.count(
190 package) == 0) {
191 SetAndroidProperty(
192 kHwuiSkiaBroadTracingPropertyName +
193 (kHwuiSkiaPropertyPackageSeparator + package),
194 "true");
195 SetAndroidProperty(
196 kHwuiSkiaUsePerfettoPropertyName +
197 (kHwuiSkiaPropertyPackageSeparator + package),
198 "true");
199 android_sdk_sysprop_guard_state_.hwui_packages_initialized.insert(
200 package);
201 increase_generation = true;
202 }
203 }
204 } else if (!android_sdk_sysprop_guard_state_.hwui_globally_initialized) {
205 // Set global flag
206 SetAndroidProperty(kHwuiSkiaBroadTracingPropertyName, "true");
207 SetAndroidProperty(kHwuiSkiaUsePerfettoPropertyName, "true");
208 android_sdk_sysprop_guard_state_.hwui_globally_initialized = true;
209 increase_generation = true;
210 }
211 }
212
213 if (increase_generation) {
214 android_sdk_sysprop_guard_state_.generation++;
215 SetAndroidProperty(
216 kPerfettoSdkSyspropGuardGenerationPropertyName,
217 std::to_string(android_sdk_sysprop_guard_state_.generation));
218 }
219
220 return;
221 }
222 }
223
StartDataSource(DataSourceInstanceID ds_id,const DataSourceConfig & ds_config)224 void BuiltinProducer::StartDataSource(DataSourceInstanceID ds_id,
225 const DataSourceConfig& ds_config) {
226 // We slightly rely on the fact that since this producer is in-process for
227 // enabling metatrace early (relative to producers that are notified via IPC).
228 if (ds_config.name() == MetatraceWriter::kDataSourceName) {
229 auto writer = endpoint_->CreateTraceWriter(
230 static_cast<BufferID>(ds_config.target_buffer()));
231
232 auto it_and_inserted = metatrace_.writers.emplace(
233 std::piecewise_construct, std::make_tuple(ds_id), std::make_tuple());
234 PERFETTO_DCHECK(it_and_inserted.second);
235 // Note: only the first concurrent writer will actually be active.
236 metatrace_.writers[ds_id].Enable(task_runner_, std::move(writer),
237 metatrace::TAG_ANY);
238 }
239 }
240
StopDataSource(DataSourceInstanceID ds_id)241 void BuiltinProducer::StopDataSource(DataSourceInstanceID ds_id) {
242 auto meta_it = metatrace_.writers.find(ds_id);
243 if (meta_it != metatrace_.writers.end()) {
244 // Synchronously re-flush the metatrace writer to record more of the
245 // teardown interactions, then ack the stop.
246 meta_it->second.WriteAllAndFlushTraceWriter([] {});
247 metatrace_.writers.erase(meta_it);
248 endpoint_->NotifyDataSourceStopped(ds_id);
249 return;
250 }
251
252 MaybeInitiateLazyStop(ds_id, &lazy_heapprofd_, kLazyHeapprofdPropertyName);
253 MaybeInitiateLazyStop(ds_id, &lazy_traced_perf_, kLazyTracedPerfPropertyName);
254
255 auto oome_it = java_hprof_oome_instances_.find(ds_id);
256 if (oome_it != java_hprof_oome_instances_.end()) {
257 java_hprof_oome_instances_.erase(oome_it);
258 SetAndroidProperty(kJavaHprofOomActivePropertyName,
259 std::to_string(java_hprof_oome_instances_.size()));
260 }
261 }
262
MaybeInitiateLazyStop(DataSourceInstanceID ds_id,LazyAndroidDaemonState * lazy_state,const char * prop_name)263 void BuiltinProducer::MaybeInitiateLazyStop(DataSourceInstanceID ds_id,
264 LazyAndroidDaemonState* lazy_state,
265 const char* prop_name) {
266 auto lazy_it = lazy_state->instance_ids.find(ds_id);
267 if (lazy_it != lazy_state->instance_ids.end()) {
268 lazy_state->instance_ids.erase(lazy_it);
269
270 // if no more sessions - stop daemon after a delay
271 if (lazy_state->instance_ids.empty()) {
272 uint64_t cur_generation = lazy_state->generation;
273 auto weak_this = weak_factory_.GetWeakPtr();
274 task_runner_->PostDelayedTask(
275 [weak_this, cur_generation, lazy_state, prop_name] {
276 if (!weak_this)
277 return;
278 // |lazy_state| should be valid if the |weak_this| is still valid
279 if (lazy_state->generation == cur_generation)
280 weak_this->SetAndroidProperty(prop_name, "");
281 },
282 lazy_state->stop_delay_ms);
283 }
284 }
285 }
286
Flush(FlushRequestID flush_id,const DataSourceInstanceID * ds_ids,size_t num_ds_ids,FlushFlags)287 void BuiltinProducer::Flush(FlushRequestID flush_id,
288 const DataSourceInstanceID* ds_ids,
289 size_t num_ds_ids,
290 FlushFlags) {
291 for (size_t i = 0; i < num_ds_ids; i++) {
292 auto meta_it = metatrace_.writers.find(ds_ids[i]);
293 if (meta_it != metatrace_.writers.end()) {
294 meta_it->second.WriteAllAndFlushTraceWriter([] {});
295 }
296 // nothing to be done for lazy sources
297 }
298 endpoint_->NotifyFlushComplete(flush_id);
299 }
300
SetAndroidProperty(const std::string & name,const std::string & value)301 bool BuiltinProducer::SetAndroidProperty(const std::string& name,
302 const std::string& value) {
303 #if PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
304 return __system_property_set(name.c_str(), value.c_str()) == 0;
305 #else
306 // Allow this to be mocked out for tests on other platforms.
307 base::ignore_result(name);
308 base::ignore_result(value);
309 return true;
310 #endif
311 }
312
313 } // namespace perfetto
314