• 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/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