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/profiling/memory/java_hprof_producer.h"
18
19 #include <signal.h>
20 #include <limits>
21 #include <optional>
22
23 #include "perfetto/ext/tracing/core/trace_writer.h"
24 #include "src/profiling/common/proc_cmdline.h"
25 #include "src/profiling/common/proc_utils.h"
26 #include "src/profiling/common/producer_support.h"
27
28 namespace perfetto {
29 namespace profiling {
30 namespace {
31
32 constexpr int kJavaHeapprofdSignal = __SIGRTMIN + 6;
33 constexpr uint32_t kInitialConnectionBackoffMs = 100;
34 constexpr uint32_t kMaxConnectionBackoffMs = 30 * 1000;
35 constexpr const char* kJavaHprofDataSource = "android.java_hprof";
36
37 } // namespace
38
DoContinuousDump(DataSourceInstanceID id,uint32_t dump_interval)39 void JavaHprofProducer::DoContinuousDump(DataSourceInstanceID id,
40 uint32_t dump_interval) {
41 auto it = data_sources_.find(id);
42 if (it == data_sources_.end())
43 return;
44 DataSource& ds = it->second;
45 if (!ds.config().continuous_dump_config().scan_pids_only_on_start()) {
46 ds.CollectPids();
47 }
48 ds.SendSignal();
49 auto weak_producer = weak_factory_.GetWeakPtr();
50 task_runner_->PostDelayedTask(
51 [weak_producer, id, dump_interval] {
52 if (!weak_producer)
53 return;
54 weak_producer->DoContinuousDump(id, dump_interval);
55 },
56 dump_interval);
57 }
58
DataSource(DataSourceConfig ds_config,JavaHprofConfig config,std::vector<std::string> target_cmdlines)59 JavaHprofProducer::DataSource::DataSource(
60 DataSourceConfig ds_config,
61 JavaHprofConfig config,
62 std::vector<std::string> target_cmdlines)
63 : ds_config_(std::move(ds_config)),
64 config_(std::move(config)),
65 target_cmdlines_(std::move(target_cmdlines)) {}
66
SendSignal() const67 void JavaHprofProducer::DataSource::SendSignal() const {
68 for (pid_t pid : pids_) {
69 auto opt_status = ReadStatus(pid);
70 if (!opt_status) {
71 PERFETTO_PLOG("Failed to read /proc/%d/status. Not signalling.", pid);
72 continue;
73 }
74 auto uids = GetUids(*opt_status);
75 if (!uids) {
76 PERFETTO_ELOG(
77 "Failed to read Uid from /proc/%d/status. "
78 "Not signalling.",
79 pid);
80 continue;
81 }
82 if (!CanProfile(ds_config_, uids->effective,
83 config_.target_installed_by())) {
84 PERFETTO_ELOG("%d (UID %" PRIu64 ") not profileable.", pid,
85 uids->effective);
86 continue;
87 }
88 PERFETTO_DLOG("Sending %d to %d", kJavaHeapprofdSignal, pid);
89 union sigval signal_value;
90 signal_value.sival_int = static_cast<int32_t>(
91 ds_config_.tracing_session_id() % std::numeric_limits<int32_t>::max());
92 if (sigqueue(pid, kJavaHeapprofdSignal, signal_value) != 0) {
93 PERFETTO_DPLOG("sigqueue");
94 }
95 }
96 }
97
CollectPids()98 void JavaHprofProducer::DataSource::CollectPids() {
99 pids_.clear();
100 for (uint64_t pid : config_.pid()) {
101 pids_.insert(static_cast<pid_t>(pid));
102 }
103 glob_aware::FindPidsForCmdlinePatterns(target_cmdlines_, &pids_);
104 if (config_.min_anonymous_memory_kb() > 0)
105 RemoveUnderAnonThreshold(config_.min_anonymous_memory_kb(), &pids_);
106 }
107
IncreaseConnectionBackoff()108 void JavaHprofProducer::IncreaseConnectionBackoff() {
109 connection_backoff_ms_ *= 2;
110 if (connection_backoff_ms_ > kMaxConnectionBackoffMs)
111 connection_backoff_ms_ = kMaxConnectionBackoffMs;
112 }
113
ResetConnectionBackoff()114 void JavaHprofProducer::ResetConnectionBackoff() {
115 connection_backoff_ms_ = kInitialConnectionBackoffMs;
116 }
117
SetupDataSource(DataSourceInstanceID id,const DataSourceConfig & ds_config)118 void JavaHprofProducer::SetupDataSource(DataSourceInstanceID id,
119 const DataSourceConfig& ds_config) {
120 if (data_sources_.find(id) != data_sources_.end()) {
121 PERFETTO_DFATAL_OR_ELOG("Duplicate data source: %" PRIu64, id);
122 return;
123 }
124 JavaHprofConfig config;
125 config.ParseFromString(ds_config.java_hprof_config_raw());
126 std::vector<std::string> cmdline_patterns = config.process_cmdline();
127 DataSource ds(ds_config, std::move(config), std::move(cmdline_patterns));
128 ds.CollectPids();
129 data_sources_.emplace(id, ds);
130 }
131
StartDataSource(DataSourceInstanceID id,const DataSourceConfig &)132 void JavaHprofProducer::StartDataSource(DataSourceInstanceID id,
133 const DataSourceConfig&) {
134 auto it = data_sources_.find(id);
135 if (it == data_sources_.end()) {
136 PERFETTO_DFATAL_OR_ELOG("Starting invalid data source: %" PRIu64, id);
137 return;
138 }
139 const DataSource& ds = it->second;
140 const auto& continuous_dump_config = ds.config().continuous_dump_config();
141 uint32_t dump_interval = continuous_dump_config.dump_interval_ms();
142 if (dump_interval) {
143 auto weak_producer = weak_factory_.GetWeakPtr();
144 task_runner_->PostDelayedTask(
145 [weak_producer, id, dump_interval] {
146 if (!weak_producer)
147 return;
148 weak_producer->DoContinuousDump(id, dump_interval);
149 },
150 continuous_dump_config.dump_phase_ms());
151 }
152 ds.SendSignal();
153 }
154
StopDataSource(DataSourceInstanceID id)155 void JavaHprofProducer::StopDataSource(DataSourceInstanceID id) {
156 auto it = data_sources_.find(id);
157 if (it == data_sources_.end()) {
158 PERFETTO_DFATAL_OR_ELOG("Stopping invalid data source: %" PRIu64, id);
159 return;
160 }
161 data_sources_.erase(it);
162 }
163
Flush(FlushRequestID flush_id,const DataSourceInstanceID *,size_t)164 void JavaHprofProducer::Flush(FlushRequestID flush_id,
165 const DataSourceInstanceID*,
166 size_t) {
167 endpoint_->NotifyFlushComplete(flush_id);
168 }
169
OnConnect()170 void JavaHprofProducer::OnConnect() {
171 PERFETTO_DCHECK(state_ == kConnecting);
172 state_ = kConnected;
173 ResetConnectionBackoff();
174 PERFETTO_LOG("Connected to the service.");
175
176 DataSourceDescriptor desc;
177 desc.set_name(kJavaHprofDataSource);
178 endpoint_->RegisterDataSource(desc);
179 }
180
Restart()181 void JavaHprofProducer::Restart() {
182 // We lost the connection with the tracing service. At this point we need
183 // to reset all the data sources. Trying to handle that manually is going to
184 // be error prone. What we do here is simply destroy the instance and
185 // recreate it again.
186 base::TaskRunner* task_runner = task_runner_;
187 const char* socket_name = producer_sock_name_;
188
189 // Invoke destructor and then the constructor again.
190 this->~JavaHprofProducer();
191 new (this) JavaHprofProducer(task_runner);
192
193 ConnectWithRetries(socket_name);
194 }
195
ConnectWithRetries(const char * socket_name)196 void JavaHprofProducer::ConnectWithRetries(const char* socket_name) {
197 PERFETTO_DCHECK(state_ == kNotStarted);
198 state_ = kNotConnected;
199
200 ResetConnectionBackoff();
201 producer_sock_name_ = socket_name;
202 ConnectService();
203 }
204
SetProducerEndpoint(std::unique_ptr<TracingService::ProducerEndpoint> endpoint)205 void JavaHprofProducer::SetProducerEndpoint(
206 std::unique_ptr<TracingService::ProducerEndpoint> endpoint) {
207 PERFETTO_DCHECK(state_ == kNotConnected || state_ == kNotStarted);
208 state_ = kConnecting;
209 endpoint_ = std::move(endpoint);
210 }
211
ConnectService()212 void JavaHprofProducer::ConnectService() {
213 SetProducerEndpoint(ProducerIPCClient::Connect(
214 producer_sock_name_, this, "android.java_hprof", task_runner_));
215 }
216
OnDisconnect()217 void JavaHprofProducer::OnDisconnect() {
218 PERFETTO_DCHECK(state_ == kConnected || state_ == kConnecting);
219 PERFETTO_LOG("Disconnected from tracing service");
220
221 auto weak_producer = weak_factory_.GetWeakPtr();
222 if (state_ == kConnected)
223 return task_runner_->PostTask([weak_producer] {
224 if (!weak_producer)
225 return;
226 weak_producer->Restart();
227 });
228
229 state_ = kNotConnected;
230 IncreaseConnectionBackoff();
231 task_runner_->PostDelayedTask(
232 [weak_producer] {
233 if (!weak_producer)
234 return;
235 weak_producer->ConnectService();
236 },
237 connection_backoff_ms_);
238 }
239
240 } // namespace profiling
241 } // namespace perfetto
242