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,FlushFlags)164 void JavaHprofProducer::Flush(FlushRequestID flush_id,
165 const DataSourceInstanceID*,
166 size_t,
167 FlushFlags) {
168 endpoint_->NotifyFlushComplete(flush_id);
169 }
170
OnConnect()171 void JavaHprofProducer::OnConnect() {
172 PERFETTO_DCHECK(state_ == kConnecting);
173 state_ = kConnected;
174 ResetConnectionBackoff();
175 PERFETTO_LOG("Connected to the service.");
176
177 DataSourceDescriptor desc;
178 desc.set_name(kJavaHprofDataSource);
179 endpoint_->RegisterDataSource(desc);
180 }
181
Restart()182 void JavaHprofProducer::Restart() {
183 // We lost the connection with the tracing service. At this point we need
184 // to reset all the data sources. Trying to handle that manually is going to
185 // be error prone. What we do here is simply destroy the instance and
186 // recreate it again.
187 base::TaskRunner* task_runner = task_runner_;
188 const char* socket_name = producer_sock_name_;
189
190 // Invoke destructor and then the constructor again.
191 this->~JavaHprofProducer();
192 new (this) JavaHprofProducer(task_runner);
193
194 ConnectWithRetries(socket_name);
195 }
196
ConnectWithRetries(const char * socket_name)197 void JavaHprofProducer::ConnectWithRetries(const char* socket_name) {
198 PERFETTO_DCHECK(state_ == kNotStarted);
199 state_ = kNotConnected;
200
201 ResetConnectionBackoff();
202 producer_sock_name_ = socket_name;
203 ConnectService();
204 }
205
SetProducerEndpoint(std::unique_ptr<TracingService::ProducerEndpoint> endpoint)206 void JavaHprofProducer::SetProducerEndpoint(
207 std::unique_ptr<TracingService::ProducerEndpoint> endpoint) {
208 PERFETTO_DCHECK(state_ == kNotConnected || state_ == kNotStarted);
209 state_ = kConnecting;
210 endpoint_ = std::move(endpoint);
211 }
212
ConnectService()213 void JavaHprofProducer::ConnectService() {
214 SetProducerEndpoint(ProducerIPCClient::Connect(
215 producer_sock_name_, this, "android.java_hprof", task_runner_));
216 }
217
OnDisconnect()218 void JavaHprofProducer::OnDisconnect() {
219 PERFETTO_DCHECK(state_ == kConnected || state_ == kConnecting);
220 PERFETTO_LOG("Disconnected from tracing service");
221
222 auto weak_producer = weak_factory_.GetWeakPtr();
223 if (state_ == kConnected)
224 return task_runner_->PostTask([weak_producer] {
225 if (!weak_producer)
226 return;
227 weak_producer->Restart();
228 });
229
230 state_ = kNotConnected;
231 IncreaseConnectionBackoff();
232 task_runner_->PostDelayedTask(
233 [weak_producer] {
234 if (!weak_producer)
235 return;
236 weak_producer->ConnectService();
237 },
238 connection_backoff_ms_);
239 }
240
241 } // namespace profiling
242 } // namespace perfetto
243