• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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