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