1*795d594fSAndroid Build Coastguard Worker /*
2*795d594fSAndroid Build Coastguard Worker * Copyright (C) 2019 The Android Open Source Project
3*795d594fSAndroid Build Coastguard Worker *
4*795d594fSAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License");
5*795d594fSAndroid Build Coastguard Worker * you may not use this file except in compliance with the License.
6*795d594fSAndroid Build Coastguard Worker * You may obtain a copy of the License at
7*795d594fSAndroid Build Coastguard Worker *
8*795d594fSAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0
9*795d594fSAndroid Build Coastguard Worker *
10*795d594fSAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software
11*795d594fSAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS,
12*795d594fSAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*795d594fSAndroid Build Coastguard Worker * See the License for the specific language governing permissions and
14*795d594fSAndroid Build Coastguard Worker * limitations under the License.
15*795d594fSAndroid Build Coastguard Worker */
16*795d594fSAndroid Build Coastguard Worker
17*795d594fSAndroid Build Coastguard Worker #define LOG_TAG "perfetto_hprof"
18*795d594fSAndroid Build Coastguard Worker
19*795d594fSAndroid Build Coastguard Worker #include "perfetto_hprof.h"
20*795d594fSAndroid Build Coastguard Worker
21*795d594fSAndroid Build Coastguard Worker #include <fcntl.h>
22*795d594fSAndroid Build Coastguard Worker #include <fnmatch.h>
23*795d594fSAndroid Build Coastguard Worker #include <inttypes.h>
24*795d594fSAndroid Build Coastguard Worker #include <sched.h>
25*795d594fSAndroid Build Coastguard Worker #include <signal.h>
26*795d594fSAndroid Build Coastguard Worker #include <sys/socket.h>
27*795d594fSAndroid Build Coastguard Worker #include <sys/stat.h>
28*795d594fSAndroid Build Coastguard Worker #include <sys/types.h>
29*795d594fSAndroid Build Coastguard Worker #include <sys/un.h>
30*795d594fSAndroid Build Coastguard Worker #include <sys/wait.h>
31*795d594fSAndroid Build Coastguard Worker #include <thread>
32*795d594fSAndroid Build Coastguard Worker #include <time.h>
33*795d594fSAndroid Build Coastguard Worker
34*795d594fSAndroid Build Coastguard Worker #include <limits>
35*795d594fSAndroid Build Coastguard Worker #include <optional>
36*795d594fSAndroid Build Coastguard Worker #include <type_traits>
37*795d594fSAndroid Build Coastguard Worker
38*795d594fSAndroid Build Coastguard Worker #include "android-base/file.h"
39*795d594fSAndroid Build Coastguard Worker #include "android-base/logging.h"
40*795d594fSAndroid Build Coastguard Worker #include "android-base/properties.h"
41*795d594fSAndroid Build Coastguard Worker #include "base/fast_exit.h"
42*795d594fSAndroid Build Coastguard Worker #include "base/systrace.h"
43*795d594fSAndroid Build Coastguard Worker #include "gc/heap-visit-objects-inl.h"
44*795d594fSAndroid Build Coastguard Worker #include "gc/heap.h"
45*795d594fSAndroid Build Coastguard Worker #include "gc/scoped_gc_critical_section.h"
46*795d594fSAndroid Build Coastguard Worker #include "mirror/object-refvisitor-inl.h"
47*795d594fSAndroid Build Coastguard Worker #include "nativehelper/scoped_local_ref.h"
48*795d594fSAndroid Build Coastguard Worker #include "perfetto/profiling/parse_smaps.h"
49*795d594fSAndroid Build Coastguard Worker #include "perfetto/trace/interned_data/interned_data.pbzero.h"
50*795d594fSAndroid Build Coastguard Worker #include "perfetto/trace/profiling/heap_graph.pbzero.h"
51*795d594fSAndroid Build Coastguard Worker #include "perfetto/trace/profiling/profile_common.pbzero.h"
52*795d594fSAndroid Build Coastguard Worker #include "perfetto/trace/profiling/smaps.pbzero.h"
53*795d594fSAndroid Build Coastguard Worker #include "perfetto/config/profiling/java_hprof_config.pbzero.h"
54*795d594fSAndroid Build Coastguard Worker #include "perfetto/protozero/packed_repeated_fields.h"
55*795d594fSAndroid Build Coastguard Worker #include "perfetto/tracing.h"
56*795d594fSAndroid Build Coastguard Worker #include "runtime-inl.h"
57*795d594fSAndroid Build Coastguard Worker #include "runtime_callbacks.h"
58*795d594fSAndroid Build Coastguard Worker #include "scoped_thread_state_change-inl.h"
59*795d594fSAndroid Build Coastguard Worker #include "thread_list.h"
60*795d594fSAndroid Build Coastguard Worker #include "well_known_classes.h"
61*795d594fSAndroid Build Coastguard Worker #include "dex/descriptors_names.h"
62*795d594fSAndroid Build Coastguard Worker
63*795d594fSAndroid Build Coastguard Worker // There are three threads involved in this:
64*795d594fSAndroid Build Coastguard Worker // * listener thread: this is idle in the background when this plugin gets loaded, and waits
65*795d594fSAndroid Build Coastguard Worker // for data on on g_signal_pipe_fds.
66*795d594fSAndroid Build Coastguard Worker // * signal thread: an arbitrary thread that handles the signal and writes data to
67*795d594fSAndroid Build Coastguard Worker // g_signal_pipe_fds.
68*795d594fSAndroid Build Coastguard Worker // * perfetto producer thread: once the signal is received, the app forks. In the newly forked
69*795d594fSAndroid Build Coastguard Worker // child, the Perfetto Client API spawns a thread to communicate with traced.
70*795d594fSAndroid Build Coastguard Worker
71*795d594fSAndroid Build Coastguard Worker namespace perfetto_hprof {
72*795d594fSAndroid Build Coastguard Worker
73*795d594fSAndroid Build Coastguard Worker constexpr int kJavaHeapprofdSignal = __SIGRTMIN + 6;
74*795d594fSAndroid Build Coastguard Worker constexpr time_t kWatchdogTimeoutSec = 120;
75*795d594fSAndroid Build Coastguard Worker // This needs to be lower than the maximum acceptable chunk size, because this
76*795d594fSAndroid Build Coastguard Worker // is checked *before* writing another submessage. We conservatively assume
77*795d594fSAndroid Build Coastguard Worker // submessages can be up to 100k here for a 500k chunk size.
78*795d594fSAndroid Build Coastguard Worker // DropBox has a 500k chunk limit, and each chunk needs to parse as a proto.
79*795d594fSAndroid Build Coastguard Worker constexpr uint32_t kPacketSizeThreshold = 400000;
80*795d594fSAndroid Build Coastguard Worker constexpr char kByte[1] = {'x'};
GetStateMutex()81*795d594fSAndroid Build Coastguard Worker static art::Mutex& GetStateMutex() {
82*795d594fSAndroid Build Coastguard Worker static art::Mutex state_mutex("perfetto_hprof_state_mutex", art::LockLevel::kGenericBottomLock);
83*795d594fSAndroid Build Coastguard Worker return state_mutex;
84*795d594fSAndroid Build Coastguard Worker }
85*795d594fSAndroid Build Coastguard Worker
GetStateCV()86*795d594fSAndroid Build Coastguard Worker static art::ConditionVariable& GetStateCV() {
87*795d594fSAndroid Build Coastguard Worker static art::ConditionVariable state_cv("perfetto_hprof_state_cv", GetStateMutex());
88*795d594fSAndroid Build Coastguard Worker return state_cv;
89*795d594fSAndroid Build Coastguard Worker }
90*795d594fSAndroid Build Coastguard Worker
91*795d594fSAndroid Build Coastguard Worker static int requested_tracing_session_id = 0;
92*795d594fSAndroid Build Coastguard Worker static State g_state = State::kUninitialized;
93*795d594fSAndroid Build Coastguard Worker static bool g_oome_triggered = false;
94*795d594fSAndroid Build Coastguard Worker static uint32_t g_oome_sessions_pending = 0;
95*795d594fSAndroid Build Coastguard Worker
96*795d594fSAndroid Build Coastguard Worker // Pipe to signal from the signal handler into a worker thread that handles the
97*795d594fSAndroid Build Coastguard Worker // dump requests.
98*795d594fSAndroid Build Coastguard Worker int g_signal_pipe_fds[2];
99*795d594fSAndroid Build Coastguard Worker static struct sigaction g_orig_act = {};
100*795d594fSAndroid Build Coastguard Worker
101*795d594fSAndroid Build Coastguard Worker template <typename T>
FindOrAppend(std::map<T,uint64_t> * m,const T & s)102*795d594fSAndroid Build Coastguard Worker uint64_t FindOrAppend(std::map<T, uint64_t>* m, const T& s) {
103*795d594fSAndroid Build Coastguard Worker auto it = m->find(s);
104*795d594fSAndroid Build Coastguard Worker if (it == m->end()) {
105*795d594fSAndroid Build Coastguard Worker std::tie(it, std::ignore) = m->emplace(s, m->size());
106*795d594fSAndroid Build Coastguard Worker }
107*795d594fSAndroid Build Coastguard Worker return it->second;
108*795d594fSAndroid Build Coastguard Worker }
109*795d594fSAndroid Build Coastguard Worker
ArmWatchdogOrDie()110*795d594fSAndroid Build Coastguard Worker void ArmWatchdogOrDie() {
111*795d594fSAndroid Build Coastguard Worker timer_t timerid{};
112*795d594fSAndroid Build Coastguard Worker struct sigevent sev {};
113*795d594fSAndroid Build Coastguard Worker sev.sigev_notify = SIGEV_SIGNAL;
114*795d594fSAndroid Build Coastguard Worker sev.sigev_signo = SIGKILL;
115*795d594fSAndroid Build Coastguard Worker
116*795d594fSAndroid Build Coastguard Worker if (timer_create(CLOCK_MONOTONIC, &sev, &timerid) == -1) {
117*795d594fSAndroid Build Coastguard Worker // This only gets called in the child, so we can fatal without impacting
118*795d594fSAndroid Build Coastguard Worker // the app.
119*795d594fSAndroid Build Coastguard Worker PLOG(FATAL) << "failed to create watchdog timer";
120*795d594fSAndroid Build Coastguard Worker }
121*795d594fSAndroid Build Coastguard Worker
122*795d594fSAndroid Build Coastguard Worker struct itimerspec its {};
123*795d594fSAndroid Build Coastguard Worker its.it_value.tv_sec = kWatchdogTimeoutSec;
124*795d594fSAndroid Build Coastguard Worker
125*795d594fSAndroid Build Coastguard Worker if (timer_settime(timerid, 0, &its, nullptr) == -1) {
126*795d594fSAndroid Build Coastguard Worker // This only gets called in the child, so we can fatal without impacting
127*795d594fSAndroid Build Coastguard Worker // the app.
128*795d594fSAndroid Build Coastguard Worker PLOG(FATAL) << "failed to arm watchdog timer";
129*795d594fSAndroid Build Coastguard Worker }
130*795d594fSAndroid Build Coastguard Worker }
131*795d594fSAndroid Build Coastguard Worker
132*795d594fSAndroid Build Coastguard Worker // Sample entries that match one of the following
133*795d594fSAndroid Build Coastguard Worker // start with /system/
134*795d594fSAndroid Build Coastguard Worker // start with /vendor/
135*795d594fSAndroid Build Coastguard Worker // start with /data/app/
136*795d594fSAndroid Build Coastguard Worker // contains "extracted in memory from Y", where Y matches any of the above
ShouldSampleSmapsEntry(const perfetto::profiling::SmapsEntry & e)137*795d594fSAndroid Build Coastguard Worker bool ShouldSampleSmapsEntry(const perfetto::profiling::SmapsEntry& e) {
138*795d594fSAndroid Build Coastguard Worker if (e.pathname.starts_with("/system/") ||
139*795d594fSAndroid Build Coastguard Worker e.pathname.starts_with("/vendor/") ||
140*795d594fSAndroid Build Coastguard Worker e.pathname.starts_with("/data/app/")) {
141*795d594fSAndroid Build Coastguard Worker return true;
142*795d594fSAndroid Build Coastguard Worker }
143*795d594fSAndroid Build Coastguard Worker if (e.pathname.starts_with("[anon:")) {
144*795d594fSAndroid Build Coastguard Worker if (e.pathname.find("extracted in memory from /system/") != std::string::npos) {
145*795d594fSAndroid Build Coastguard Worker return true;
146*795d594fSAndroid Build Coastguard Worker }
147*795d594fSAndroid Build Coastguard Worker if (e.pathname.find("extracted in memory from /vendor/") != std::string::npos) {
148*795d594fSAndroid Build Coastguard Worker return true;
149*795d594fSAndroid Build Coastguard Worker }
150*795d594fSAndroid Build Coastguard Worker if (e.pathname.find("extracted in memory from /data/app/") != std::string::npos) {
151*795d594fSAndroid Build Coastguard Worker return true;
152*795d594fSAndroid Build Coastguard Worker }
153*795d594fSAndroid Build Coastguard Worker }
154*795d594fSAndroid Build Coastguard Worker return false;
155*795d594fSAndroid Build Coastguard Worker }
156*795d594fSAndroid Build Coastguard Worker
GetCurrentBootClockNs()157*795d594fSAndroid Build Coastguard Worker uint64_t GetCurrentBootClockNs() {
158*795d594fSAndroid Build Coastguard Worker struct timespec ts = {};
159*795d594fSAndroid Build Coastguard Worker if (clock_gettime(CLOCK_BOOTTIME, &ts) != 0) {
160*795d594fSAndroid Build Coastguard Worker LOG(FATAL) << "Failed to get boottime.";
161*795d594fSAndroid Build Coastguard Worker }
162*795d594fSAndroid Build Coastguard Worker return ts.tv_sec * 1000000000LL + ts.tv_nsec;
163*795d594fSAndroid Build Coastguard Worker }
164*795d594fSAndroid Build Coastguard Worker
IsDebugBuild()165*795d594fSAndroid Build Coastguard Worker bool IsDebugBuild() {
166*795d594fSAndroid Build Coastguard Worker std::string build_type = android::base::GetProperty("ro.build.type", "");
167*795d594fSAndroid Build Coastguard Worker return !build_type.empty() && build_type != "user";
168*795d594fSAndroid Build Coastguard Worker }
169*795d594fSAndroid Build Coastguard Worker
170*795d594fSAndroid Build Coastguard Worker // Verifies the manifest restrictions are respected.
171*795d594fSAndroid Build Coastguard Worker // For regular heap dumps this is already handled by heapprofd.
IsOomeHeapDumpAllowed(const perfetto::DataSourceConfig & ds_config)172*795d594fSAndroid Build Coastguard Worker bool IsOomeHeapDumpAllowed(const perfetto::DataSourceConfig& ds_config) {
173*795d594fSAndroid Build Coastguard Worker if (art::Runtime::Current()->IsJavaDebuggable() || IsDebugBuild()) {
174*795d594fSAndroid Build Coastguard Worker return true;
175*795d594fSAndroid Build Coastguard Worker }
176*795d594fSAndroid Build Coastguard Worker
177*795d594fSAndroid Build Coastguard Worker if (ds_config.session_initiator() ==
178*795d594fSAndroid Build Coastguard Worker perfetto::DataSourceConfig::SESSION_INITIATOR_TRUSTED_SYSTEM) {
179*795d594fSAndroid Build Coastguard Worker return art::Runtime::Current()->IsProfileable() || art::Runtime::Current()->IsSystemServer();
180*795d594fSAndroid Build Coastguard Worker } else {
181*795d594fSAndroid Build Coastguard Worker return art::Runtime::Current()->IsProfileableFromShell();
182*795d594fSAndroid Build Coastguard Worker }
183*795d594fSAndroid Build Coastguard Worker }
184*795d594fSAndroid Build Coastguard Worker
185*795d594fSAndroid Build Coastguard Worker class JavaHprofDataSource : public perfetto::DataSource<JavaHprofDataSource> {
186*795d594fSAndroid Build Coastguard Worker public:
187*795d594fSAndroid Build Coastguard Worker constexpr static perfetto::BufferExhaustedPolicy kBufferExhaustedPolicy =
188*795d594fSAndroid Build Coastguard Worker perfetto::BufferExhaustedPolicy::kStall;
189*795d594fSAndroid Build Coastguard Worker
JavaHprofDataSource(bool is_oome_heap)190*795d594fSAndroid Build Coastguard Worker explicit JavaHprofDataSource(bool is_oome_heap) : is_oome_heap_(is_oome_heap) {}
191*795d594fSAndroid Build Coastguard Worker
OnSetup(const SetupArgs & args)192*795d594fSAndroid Build Coastguard Worker void OnSetup(const SetupArgs& args) override {
193*795d594fSAndroid Build Coastguard Worker if (!is_oome_heap_) {
194*795d594fSAndroid Build Coastguard Worker uint64_t normalized_tracing_session_id =
195*795d594fSAndroid Build Coastguard Worker args.config->tracing_session_id() % std::numeric_limits<int32_t>::max();
196*795d594fSAndroid Build Coastguard Worker if (requested_tracing_session_id < 0) {
197*795d594fSAndroid Build Coastguard Worker LOG(ERROR) << "invalid requested tracing session id " << requested_tracing_session_id;
198*795d594fSAndroid Build Coastguard Worker return;
199*795d594fSAndroid Build Coastguard Worker }
200*795d594fSAndroid Build Coastguard Worker if (static_cast<uint64_t>(requested_tracing_session_id) != normalized_tracing_session_id) {
201*795d594fSAndroid Build Coastguard Worker return;
202*795d594fSAndroid Build Coastguard Worker }
203*795d594fSAndroid Build Coastguard Worker }
204*795d594fSAndroid Build Coastguard Worker
205*795d594fSAndroid Build Coastguard Worker // This is on the heap as it triggers -Wframe-larger-than.
206*795d594fSAndroid Build Coastguard Worker std::unique_ptr<perfetto::protos::pbzero::JavaHprofConfig::Decoder> cfg(
207*795d594fSAndroid Build Coastguard Worker new perfetto::protos::pbzero::JavaHprofConfig::Decoder(
208*795d594fSAndroid Build Coastguard Worker args.config->java_hprof_config_raw()));
209*795d594fSAndroid Build Coastguard Worker
210*795d594fSAndroid Build Coastguard Worker dump_smaps_ = cfg->dump_smaps();
211*795d594fSAndroid Build Coastguard Worker for (auto it = cfg->ignored_types(); it; ++it) {
212*795d594fSAndroid Build Coastguard Worker std::string name = (*it).ToStdString();
213*795d594fSAndroid Build Coastguard Worker ignored_types_.emplace_back(art::InversePrettyDescriptor(name));
214*795d594fSAndroid Build Coastguard Worker }
215*795d594fSAndroid Build Coastguard Worker // This tracing session ID matches the requesting tracing session ID, so we know heapprofd
216*795d594fSAndroid Build Coastguard Worker // has verified it targets this process.
217*795d594fSAndroid Build Coastguard Worker enabled_ =
218*795d594fSAndroid Build Coastguard Worker !is_oome_heap_ || (IsOomeHeapDumpAllowed(*args.config) && IsOomeDumpEnabled(*cfg.get()));
219*795d594fSAndroid Build Coastguard Worker }
220*795d594fSAndroid Build Coastguard Worker
dump_smaps()221*795d594fSAndroid Build Coastguard Worker bool dump_smaps() { return dump_smaps_; }
222*795d594fSAndroid Build Coastguard Worker
223*795d594fSAndroid Build Coastguard Worker // Per-DataSource enable bit. Invoked by the ::Trace method.
enabled()224*795d594fSAndroid Build Coastguard Worker bool enabled() { return enabled_; }
225*795d594fSAndroid Build Coastguard Worker
OnStart(const StartArgs &)226*795d594fSAndroid Build Coastguard Worker void OnStart(const StartArgs&) override {
227*795d594fSAndroid Build Coastguard Worker art::MutexLock lk(art_thread(), GetStateMutex());
228*795d594fSAndroid Build Coastguard Worker // In case there are multiple tracing sessions waiting for an OOME error,
229*795d594fSAndroid Build Coastguard Worker // there will be a data source instance for each of them. Before the
230*795d594fSAndroid Build Coastguard Worker // transition to kStart and signaling the dumping thread, we need to make
231*795d594fSAndroid Build Coastguard Worker // sure all the data sources are ready.
232*795d594fSAndroid Build Coastguard Worker if (is_oome_heap_ && g_oome_sessions_pending > 0) {
233*795d594fSAndroid Build Coastguard Worker --g_oome_sessions_pending;
234*795d594fSAndroid Build Coastguard Worker }
235*795d594fSAndroid Build Coastguard Worker if (g_state == State::kWaitForStart) {
236*795d594fSAndroid Build Coastguard Worker // WriteHeapPackets is responsible for checking whether the DataSource is\
237*795d594fSAndroid Build Coastguard Worker // actually enabled.
238*795d594fSAndroid Build Coastguard Worker if (!is_oome_heap_ || g_oome_sessions_pending == 0) {
239*795d594fSAndroid Build Coastguard Worker g_state = State::kStart;
240*795d594fSAndroid Build Coastguard Worker GetStateCV().Broadcast(art_thread());
241*795d594fSAndroid Build Coastguard Worker }
242*795d594fSAndroid Build Coastguard Worker }
243*795d594fSAndroid Build Coastguard Worker }
244*795d594fSAndroid Build Coastguard Worker
245*795d594fSAndroid Build Coastguard Worker // This datasource can be used with a trace config with a short duration_ms
246*795d594fSAndroid Build Coastguard Worker // but a long datasource_stop_timeout_ms. In that case, OnStop is called (in
247*795d594fSAndroid Build Coastguard Worker // general) before the dump is done. In that case, we handle the stop
248*795d594fSAndroid Build Coastguard Worker // asynchronously, and notify the tracing service once we are done.
249*795d594fSAndroid Build Coastguard Worker // In case OnStop is called after the dump is done (but before the process)
250*795d594fSAndroid Build Coastguard Worker // has exited, we just acknowledge the request.
OnStop(const StopArgs & a)251*795d594fSAndroid Build Coastguard Worker void OnStop(const StopArgs& a) override {
252*795d594fSAndroid Build Coastguard Worker art::MutexLock lk(art_thread(), finish_mutex_);
253*795d594fSAndroid Build Coastguard Worker if (is_finished_) {
254*795d594fSAndroid Build Coastguard Worker return;
255*795d594fSAndroid Build Coastguard Worker }
256*795d594fSAndroid Build Coastguard Worker is_stopped_ = true;
257*795d594fSAndroid Build Coastguard Worker async_stop_ = a.HandleStopAsynchronously();
258*795d594fSAndroid Build Coastguard Worker }
259*795d594fSAndroid Build Coastguard Worker
art_thread()260*795d594fSAndroid Build Coastguard Worker static art::Thread* art_thread() {
261*795d594fSAndroid Build Coastguard Worker // TODO(fmayer): Attach the Perfetto producer thread to ART and give it a name. This is
262*795d594fSAndroid Build Coastguard Worker // not trivial, we cannot just attach the first time this method is called, because
263*795d594fSAndroid Build Coastguard Worker // AttachCurrentThread deadlocks with the ConditionVariable::Wait in WaitForDataSource.
264*795d594fSAndroid Build Coastguard Worker //
265*795d594fSAndroid Build Coastguard Worker // We should attach the thread as soon as the Client API spawns it, but that needs more
266*795d594fSAndroid Build Coastguard Worker // complicated plumbing.
267*795d594fSAndroid Build Coastguard Worker return nullptr;
268*795d594fSAndroid Build Coastguard Worker }
269*795d594fSAndroid Build Coastguard Worker
ignored_types()270*795d594fSAndroid Build Coastguard Worker std::vector<std::string> ignored_types() { return ignored_types_; }
271*795d594fSAndroid Build Coastguard Worker
Finish()272*795d594fSAndroid Build Coastguard Worker void Finish() {
273*795d594fSAndroid Build Coastguard Worker art::MutexLock lk(art_thread(), finish_mutex_);
274*795d594fSAndroid Build Coastguard Worker if (is_stopped_) {
275*795d594fSAndroid Build Coastguard Worker async_stop_();
276*795d594fSAndroid Build Coastguard Worker } else {
277*795d594fSAndroid Build Coastguard Worker is_finished_ = true;
278*795d594fSAndroid Build Coastguard Worker }
279*795d594fSAndroid Build Coastguard Worker }
280*795d594fSAndroid Build Coastguard Worker
281*795d594fSAndroid Build Coastguard Worker private:
IsOomeDumpEnabled(const perfetto::protos::pbzero::JavaHprofConfig::Decoder & cfg)282*795d594fSAndroid Build Coastguard Worker static bool IsOomeDumpEnabled(const perfetto::protos::pbzero::JavaHprofConfig::Decoder& cfg) {
283*795d594fSAndroid Build Coastguard Worker std::string cmdline;
284*795d594fSAndroid Build Coastguard Worker if (!android::base::ReadFileToString("/proc/self/cmdline", &cmdline)) {
285*795d594fSAndroid Build Coastguard Worker return false;
286*795d594fSAndroid Build Coastguard Worker }
287*795d594fSAndroid Build Coastguard Worker const char* argv0 = cmdline.c_str();
288*795d594fSAndroid Build Coastguard Worker
289*795d594fSAndroid Build Coastguard Worker for (auto it = cfg.process_cmdline(); it; ++it) {
290*795d594fSAndroid Build Coastguard Worker std::string pattern = (*it).ToStdString();
291*795d594fSAndroid Build Coastguard Worker if (fnmatch(pattern.c_str(), argv0, FNM_NOESCAPE) == 0) {
292*795d594fSAndroid Build Coastguard Worker return true;
293*795d594fSAndroid Build Coastguard Worker }
294*795d594fSAndroid Build Coastguard Worker }
295*795d594fSAndroid Build Coastguard Worker return false;
296*795d594fSAndroid Build Coastguard Worker }
297*795d594fSAndroid Build Coastguard Worker
298*795d594fSAndroid Build Coastguard Worker bool is_oome_heap_ = false;
299*795d594fSAndroid Build Coastguard Worker bool enabled_ = false;
300*795d594fSAndroid Build Coastguard Worker bool dump_smaps_ = false;
301*795d594fSAndroid Build Coastguard Worker std::vector<std::string> ignored_types_;
302*795d594fSAndroid Build Coastguard Worker
303*795d594fSAndroid Build Coastguard Worker art::Mutex finish_mutex_{"perfetto_hprof_ds_mutex", art::LockLevel::kGenericBottomLock};
304*795d594fSAndroid Build Coastguard Worker bool is_finished_ = false;
305*795d594fSAndroid Build Coastguard Worker bool is_stopped_ = false;
306*795d594fSAndroid Build Coastguard Worker std::function<void()> async_stop_;
307*795d594fSAndroid Build Coastguard Worker };
308*795d594fSAndroid Build Coastguard Worker
SetupDataSource(const std::string & ds_name,bool is_oome_heap)309*795d594fSAndroid Build Coastguard Worker void SetupDataSource(const std::string& ds_name, bool is_oome_heap) {
310*795d594fSAndroid Build Coastguard Worker perfetto::TracingInitArgs args;
311*795d594fSAndroid Build Coastguard Worker args.backends = perfetto::BackendType::kSystemBackend;
312*795d594fSAndroid Build Coastguard Worker perfetto::Tracing::Initialize(args);
313*795d594fSAndroid Build Coastguard Worker
314*795d594fSAndroid Build Coastguard Worker perfetto::DataSourceDescriptor dsd;
315*795d594fSAndroid Build Coastguard Worker dsd.set_name(ds_name);
316*795d594fSAndroid Build Coastguard Worker dsd.set_will_notify_on_stop(true);
317*795d594fSAndroid Build Coastguard Worker JavaHprofDataSource::Register(dsd, is_oome_heap);
318*795d594fSAndroid Build Coastguard Worker }
319*795d594fSAndroid Build Coastguard Worker
320*795d594fSAndroid Build Coastguard Worker // Waits for the data source OnStart
WaitForDataSource(art::Thread * self)321*795d594fSAndroid Build Coastguard Worker void WaitForDataSource(art::Thread* self) {
322*795d594fSAndroid Build Coastguard Worker art::MutexLock lk(self, GetStateMutex());
323*795d594fSAndroid Build Coastguard Worker while (g_state != State::kStart) {
324*795d594fSAndroid Build Coastguard Worker GetStateCV().Wait(self);
325*795d594fSAndroid Build Coastguard Worker }
326*795d594fSAndroid Build Coastguard Worker }
327*795d594fSAndroid Build Coastguard Worker
328*795d594fSAndroid Build Coastguard Worker // Waits for the data source OnStart with a timeout. Returns false on timeout.
TimedWaitForDataSource(art::Thread * self,int64_t timeout_ms)329*795d594fSAndroid Build Coastguard Worker bool TimedWaitForDataSource(art::Thread* self, int64_t timeout_ms) {
330*795d594fSAndroid Build Coastguard Worker const uint64_t cutoff_ns = GetCurrentBootClockNs() + timeout_ms * 1000000;
331*795d594fSAndroid Build Coastguard Worker art::MutexLock lk(self, GetStateMutex());
332*795d594fSAndroid Build Coastguard Worker while (g_state != State::kStart) {
333*795d594fSAndroid Build Coastguard Worker const uint64_t current_ns = GetCurrentBootClockNs();
334*795d594fSAndroid Build Coastguard Worker if (current_ns >= cutoff_ns) {
335*795d594fSAndroid Build Coastguard Worker return false;
336*795d594fSAndroid Build Coastguard Worker }
337*795d594fSAndroid Build Coastguard Worker GetStateCV().TimedWait(self, (cutoff_ns - current_ns) / 1000000, 0);
338*795d594fSAndroid Build Coastguard Worker }
339*795d594fSAndroid Build Coastguard Worker return true;
340*795d594fSAndroid Build Coastguard Worker }
341*795d594fSAndroid Build Coastguard Worker
342*795d594fSAndroid Build Coastguard Worker // Helper class to write Java heap dumps to `ctx`. The whole heap dump can be
343*795d594fSAndroid Build Coastguard Worker // split into more perfetto.protos.HeapGraph messages, to avoid making each
344*795d594fSAndroid Build Coastguard Worker // message too big.
345*795d594fSAndroid Build Coastguard Worker class Writer {
346*795d594fSAndroid Build Coastguard Worker public:
Writer(pid_t pid,JavaHprofDataSource::TraceContext * ctx,uint64_t timestamp)347*795d594fSAndroid Build Coastguard Worker Writer(pid_t pid, JavaHprofDataSource::TraceContext* ctx, uint64_t timestamp)
348*795d594fSAndroid Build Coastguard Worker : pid_(pid), ctx_(ctx), timestamp_(timestamp),
349*795d594fSAndroid Build Coastguard Worker last_written_(ctx_->written()) {}
350*795d594fSAndroid Build Coastguard Worker
351*795d594fSAndroid Build Coastguard Worker // Return whether the next call to GetHeapGraph will create a new TracePacket.
will_create_new_packet() const352*795d594fSAndroid Build Coastguard Worker bool will_create_new_packet() const {
353*795d594fSAndroid Build Coastguard Worker return !heap_graph_ || ctx_->written() - last_written_ > kPacketSizeThreshold;
354*795d594fSAndroid Build Coastguard Worker }
355*795d594fSAndroid Build Coastguard Worker
GetHeapGraph()356*795d594fSAndroid Build Coastguard Worker perfetto::protos::pbzero::HeapGraph* GetHeapGraph() {
357*795d594fSAndroid Build Coastguard Worker if (will_create_new_packet()) {
358*795d594fSAndroid Build Coastguard Worker CreateNewHeapGraph();
359*795d594fSAndroid Build Coastguard Worker }
360*795d594fSAndroid Build Coastguard Worker return heap_graph_;
361*795d594fSAndroid Build Coastguard Worker }
362*795d594fSAndroid Build Coastguard Worker
Finalize()363*795d594fSAndroid Build Coastguard Worker void Finalize() {
364*795d594fSAndroid Build Coastguard Worker if (trace_packet_) {
365*795d594fSAndroid Build Coastguard Worker trace_packet_->Finalize();
366*795d594fSAndroid Build Coastguard Worker }
367*795d594fSAndroid Build Coastguard Worker heap_graph_ = nullptr;
368*795d594fSAndroid Build Coastguard Worker }
369*795d594fSAndroid Build Coastguard Worker
~Writer()370*795d594fSAndroid Build Coastguard Worker ~Writer() { Finalize(); }
371*795d594fSAndroid Build Coastguard Worker
372*795d594fSAndroid Build Coastguard Worker private:
373*795d594fSAndroid Build Coastguard Worker Writer(const Writer&) = delete;
374*795d594fSAndroid Build Coastguard Worker Writer& operator=(const Writer&) = delete;
375*795d594fSAndroid Build Coastguard Worker Writer(Writer&&) = delete;
376*795d594fSAndroid Build Coastguard Worker Writer& operator=(Writer&&) = delete;
377*795d594fSAndroid Build Coastguard Worker
CreateNewHeapGraph()378*795d594fSAndroid Build Coastguard Worker void CreateNewHeapGraph() {
379*795d594fSAndroid Build Coastguard Worker if (heap_graph_) {
380*795d594fSAndroid Build Coastguard Worker heap_graph_->set_continued(true);
381*795d594fSAndroid Build Coastguard Worker }
382*795d594fSAndroid Build Coastguard Worker Finalize();
383*795d594fSAndroid Build Coastguard Worker
384*795d594fSAndroid Build Coastguard Worker uint64_t written = ctx_->written();
385*795d594fSAndroid Build Coastguard Worker
386*795d594fSAndroid Build Coastguard Worker trace_packet_ = ctx_->NewTracePacket();
387*795d594fSAndroid Build Coastguard Worker trace_packet_->set_timestamp(timestamp_);
388*795d594fSAndroid Build Coastguard Worker heap_graph_ = trace_packet_->set_heap_graph();
389*795d594fSAndroid Build Coastguard Worker heap_graph_->set_pid(pid_);
390*795d594fSAndroid Build Coastguard Worker heap_graph_->set_index(index_++);
391*795d594fSAndroid Build Coastguard Worker
392*795d594fSAndroid Build Coastguard Worker last_written_ = written;
393*795d594fSAndroid Build Coastguard Worker }
394*795d594fSAndroid Build Coastguard Worker
395*795d594fSAndroid Build Coastguard Worker const pid_t pid_;
396*795d594fSAndroid Build Coastguard Worker JavaHprofDataSource::TraceContext* const ctx_;
397*795d594fSAndroid Build Coastguard Worker const uint64_t timestamp_;
398*795d594fSAndroid Build Coastguard Worker
399*795d594fSAndroid Build Coastguard Worker uint64_t last_written_ = 0;
400*795d594fSAndroid Build Coastguard Worker
401*795d594fSAndroid Build Coastguard Worker perfetto::DataSource<JavaHprofDataSource>::TraceContext::TracePacketHandle
402*795d594fSAndroid Build Coastguard Worker trace_packet_;
403*795d594fSAndroid Build Coastguard Worker perfetto::protos::pbzero::HeapGraph* heap_graph_ = nullptr;
404*795d594fSAndroid Build Coastguard Worker
405*795d594fSAndroid Build Coastguard Worker uint64_t index_ = 0;
406*795d594fSAndroid Build Coastguard Worker };
407*795d594fSAndroid Build Coastguard Worker
408*795d594fSAndroid Build Coastguard Worker class ReferredObjectsFinder {
409*795d594fSAndroid Build Coastguard Worker public:
ReferredObjectsFinder(std::vector<std::pair<std::string,art::mirror::Object * >> * referred_objects,bool emit_field_ids)410*795d594fSAndroid Build Coastguard Worker explicit ReferredObjectsFinder(
411*795d594fSAndroid Build Coastguard Worker std::vector<std::pair<std::string, art::mirror::Object*>>* referred_objects,
412*795d594fSAndroid Build Coastguard Worker bool emit_field_ids)
413*795d594fSAndroid Build Coastguard Worker : referred_objects_(referred_objects), emit_field_ids_(emit_field_ids) {}
414*795d594fSAndroid Build Coastguard Worker
415*795d594fSAndroid Build Coastguard Worker // For art::mirror::Object::VisitReferences.
operator ()(art::ObjPtr<art::mirror::Object> obj,art::MemberOffset offset,bool is_static) const416*795d594fSAndroid Build Coastguard Worker void operator()(art::ObjPtr<art::mirror::Object> obj, art::MemberOffset offset,
417*795d594fSAndroid Build Coastguard Worker bool is_static) const
418*795d594fSAndroid Build Coastguard Worker REQUIRES_SHARED(art::Locks::mutator_lock_) {
419*795d594fSAndroid Build Coastguard Worker if (offset.Uint32Value() == art::mirror::Object::ClassOffset().Uint32Value()) {
420*795d594fSAndroid Build Coastguard Worker // Skip shadow$klass pointer.
421*795d594fSAndroid Build Coastguard Worker return;
422*795d594fSAndroid Build Coastguard Worker }
423*795d594fSAndroid Build Coastguard Worker art::mirror::Object* ref = obj->GetFieldObject<art::mirror::Object>(offset);
424*795d594fSAndroid Build Coastguard Worker art::ArtField* field;
425*795d594fSAndroid Build Coastguard Worker if (is_static) {
426*795d594fSAndroid Build Coastguard Worker field = art::ArtField::FindStaticFieldWithOffset(obj->AsClass(), offset.Uint32Value());
427*795d594fSAndroid Build Coastguard Worker } else {
428*795d594fSAndroid Build Coastguard Worker field = art::ArtField::FindInstanceFieldWithOffset(obj->GetClass(), offset.Uint32Value());
429*795d594fSAndroid Build Coastguard Worker }
430*795d594fSAndroid Build Coastguard Worker std::string field_name = "";
431*795d594fSAndroid Build Coastguard Worker if (field != nullptr && emit_field_ids_) {
432*795d594fSAndroid Build Coastguard Worker field_name = field->PrettyField(/*with_type=*/true);
433*795d594fSAndroid Build Coastguard Worker }
434*795d594fSAndroid Build Coastguard Worker referred_objects_->emplace_back(std::move(field_name), ref);
435*795d594fSAndroid Build Coastguard Worker }
436*795d594fSAndroid Build Coastguard Worker
VisitRootIfNonNull(art::mirror::CompressedReference<art::mirror::Object> * root) const437*795d594fSAndroid Build Coastguard Worker void VisitRootIfNonNull(
438*795d594fSAndroid Build Coastguard Worker [[maybe_unused]] art::mirror::CompressedReference<art::mirror::Object>* root) const {}
VisitRoot(art::mirror::CompressedReference<art::mirror::Object> * root) const439*795d594fSAndroid Build Coastguard Worker void VisitRoot(
440*795d594fSAndroid Build Coastguard Worker [[maybe_unused]] art::mirror::CompressedReference<art::mirror::Object>* root) const {}
441*795d594fSAndroid Build Coastguard Worker
442*795d594fSAndroid Build Coastguard Worker private:
443*795d594fSAndroid Build Coastguard Worker // We can use a raw Object* pointer here, because there are no concurrent GC threads after the
444*795d594fSAndroid Build Coastguard Worker // fork.
445*795d594fSAndroid Build Coastguard Worker std::vector<std::pair<std::string, art::mirror::Object*>>* referred_objects_;
446*795d594fSAndroid Build Coastguard Worker // Prettifying field names is expensive; avoid if field name will not be used.
447*795d594fSAndroid Build Coastguard Worker bool emit_field_ids_;
448*795d594fSAndroid Build Coastguard Worker };
449*795d594fSAndroid Build Coastguard Worker
450*795d594fSAndroid Build Coastguard Worker class RootFinder : public art::SingleRootVisitor {
451*795d594fSAndroid Build Coastguard Worker public:
RootFinder(std::map<art::RootType,std::vector<art::mirror::Object * >> * root_objects)452*795d594fSAndroid Build Coastguard Worker explicit RootFinder(
453*795d594fSAndroid Build Coastguard Worker std::map<art::RootType, std::vector<art::mirror::Object*>>* root_objects)
454*795d594fSAndroid Build Coastguard Worker : root_objects_(root_objects) {}
455*795d594fSAndroid Build Coastguard Worker
VisitRoot(art::mirror::Object * root,const art::RootInfo & info)456*795d594fSAndroid Build Coastguard Worker void VisitRoot(art::mirror::Object* root, const art::RootInfo& info) override {
457*795d594fSAndroid Build Coastguard Worker (*root_objects_)[info.GetType()].emplace_back(root);
458*795d594fSAndroid Build Coastguard Worker }
459*795d594fSAndroid Build Coastguard Worker
460*795d594fSAndroid Build Coastguard Worker private:
461*795d594fSAndroid Build Coastguard Worker // We can use a raw Object* pointer here, because there are no concurrent GC threads after the
462*795d594fSAndroid Build Coastguard Worker // fork.
463*795d594fSAndroid Build Coastguard Worker std::map<art::RootType, std::vector<art::mirror::Object*>>* root_objects_;
464*795d594fSAndroid Build Coastguard Worker };
465*795d594fSAndroid Build Coastguard Worker
ToProtoType(art::RootType art_type)466*795d594fSAndroid Build Coastguard Worker perfetto::protos::pbzero::HeapGraphRoot::Type ToProtoType(art::RootType art_type) {
467*795d594fSAndroid Build Coastguard Worker using perfetto::protos::pbzero::HeapGraphRoot;
468*795d594fSAndroid Build Coastguard Worker switch (art_type) {
469*795d594fSAndroid Build Coastguard Worker case art::kRootUnknown:
470*795d594fSAndroid Build Coastguard Worker return HeapGraphRoot::ROOT_UNKNOWN;
471*795d594fSAndroid Build Coastguard Worker case art::kRootJNIGlobal:
472*795d594fSAndroid Build Coastguard Worker return HeapGraphRoot::ROOT_JNI_GLOBAL;
473*795d594fSAndroid Build Coastguard Worker case art::kRootJNILocal:
474*795d594fSAndroid Build Coastguard Worker return HeapGraphRoot::ROOT_JNI_LOCAL;
475*795d594fSAndroid Build Coastguard Worker case art::kRootJavaFrame:
476*795d594fSAndroid Build Coastguard Worker return HeapGraphRoot::ROOT_JAVA_FRAME;
477*795d594fSAndroid Build Coastguard Worker case art::kRootNativeStack:
478*795d594fSAndroid Build Coastguard Worker return HeapGraphRoot::ROOT_NATIVE_STACK;
479*795d594fSAndroid Build Coastguard Worker case art::kRootStickyClass:
480*795d594fSAndroid Build Coastguard Worker return HeapGraphRoot::ROOT_STICKY_CLASS;
481*795d594fSAndroid Build Coastguard Worker case art::kRootThreadBlock:
482*795d594fSAndroid Build Coastguard Worker return HeapGraphRoot::ROOT_THREAD_BLOCK;
483*795d594fSAndroid Build Coastguard Worker case art::kRootMonitorUsed:
484*795d594fSAndroid Build Coastguard Worker return HeapGraphRoot::ROOT_MONITOR_USED;
485*795d594fSAndroid Build Coastguard Worker case art::kRootThreadObject:
486*795d594fSAndroid Build Coastguard Worker return HeapGraphRoot::ROOT_THREAD_OBJECT;
487*795d594fSAndroid Build Coastguard Worker case art::kRootInternedString:
488*795d594fSAndroid Build Coastguard Worker return HeapGraphRoot::ROOT_INTERNED_STRING;
489*795d594fSAndroid Build Coastguard Worker case art::kRootFinalizing:
490*795d594fSAndroid Build Coastguard Worker return HeapGraphRoot::ROOT_FINALIZING;
491*795d594fSAndroid Build Coastguard Worker case art::kRootDebugger:
492*795d594fSAndroid Build Coastguard Worker return HeapGraphRoot::ROOT_DEBUGGER;
493*795d594fSAndroid Build Coastguard Worker case art::kRootReferenceCleanup:
494*795d594fSAndroid Build Coastguard Worker return HeapGraphRoot::ROOT_REFERENCE_CLEANUP;
495*795d594fSAndroid Build Coastguard Worker case art::kRootVMInternal:
496*795d594fSAndroid Build Coastguard Worker return HeapGraphRoot::ROOT_VM_INTERNAL;
497*795d594fSAndroid Build Coastguard Worker case art::kRootJNIMonitor:
498*795d594fSAndroid Build Coastguard Worker return HeapGraphRoot::ROOT_JNI_MONITOR;
499*795d594fSAndroid Build Coastguard Worker }
500*795d594fSAndroid Build Coastguard Worker }
501*795d594fSAndroid Build Coastguard Worker
ProtoClassKind(uint32_t class_flags)502*795d594fSAndroid Build Coastguard Worker perfetto::protos::pbzero::HeapGraphType::Kind ProtoClassKind(uint32_t class_flags) {
503*795d594fSAndroid Build Coastguard Worker using perfetto::protos::pbzero::HeapGraphType;
504*795d594fSAndroid Build Coastguard Worker switch (class_flags) {
505*795d594fSAndroid Build Coastguard Worker case art::mirror::kClassFlagNormal:
506*795d594fSAndroid Build Coastguard Worker case art::mirror::kClassFlagRecord:
507*795d594fSAndroid Build Coastguard Worker return HeapGraphType::KIND_NORMAL;
508*795d594fSAndroid Build Coastguard Worker case art::mirror::kClassFlagNoReferenceFields:
509*795d594fSAndroid Build Coastguard Worker case art::mirror::kClassFlagNoReferenceFields | art::mirror::kClassFlagRecord:
510*795d594fSAndroid Build Coastguard Worker return HeapGraphType::KIND_NOREFERENCES;
511*795d594fSAndroid Build Coastguard Worker case art::mirror::kClassFlagString | art::mirror::kClassFlagNoReferenceFields:
512*795d594fSAndroid Build Coastguard Worker return HeapGraphType::KIND_STRING;
513*795d594fSAndroid Build Coastguard Worker case art::mirror::kClassFlagObjectArray:
514*795d594fSAndroid Build Coastguard Worker return HeapGraphType::KIND_ARRAY;
515*795d594fSAndroid Build Coastguard Worker case art::mirror::kClassFlagClass:
516*795d594fSAndroid Build Coastguard Worker return HeapGraphType::KIND_CLASS;
517*795d594fSAndroid Build Coastguard Worker case art::mirror::kClassFlagClassLoader:
518*795d594fSAndroid Build Coastguard Worker return HeapGraphType::KIND_CLASSLOADER;
519*795d594fSAndroid Build Coastguard Worker case art::mirror::kClassFlagDexCache:
520*795d594fSAndroid Build Coastguard Worker return HeapGraphType::KIND_DEXCACHE;
521*795d594fSAndroid Build Coastguard Worker case art::mirror::kClassFlagSoftReference:
522*795d594fSAndroid Build Coastguard Worker return HeapGraphType::KIND_SOFT_REFERENCE;
523*795d594fSAndroid Build Coastguard Worker case art::mirror::kClassFlagWeakReference:
524*795d594fSAndroid Build Coastguard Worker return HeapGraphType::KIND_WEAK_REFERENCE;
525*795d594fSAndroid Build Coastguard Worker case art::mirror::kClassFlagFinalizerReference:
526*795d594fSAndroid Build Coastguard Worker return HeapGraphType::KIND_FINALIZER_REFERENCE;
527*795d594fSAndroid Build Coastguard Worker case art::mirror::kClassFlagPhantomReference:
528*795d594fSAndroid Build Coastguard Worker return HeapGraphType::KIND_PHANTOM_REFERENCE;
529*795d594fSAndroid Build Coastguard Worker default:
530*795d594fSAndroid Build Coastguard Worker return HeapGraphType::KIND_UNKNOWN;
531*795d594fSAndroid Build Coastguard Worker }
532*795d594fSAndroid Build Coastguard Worker }
533*795d594fSAndroid Build Coastguard Worker
PrettyType(art::mirror::Class * klass)534*795d594fSAndroid Build Coastguard Worker std::string PrettyType(art::mirror::Class* klass) NO_THREAD_SAFETY_ANALYSIS {
535*795d594fSAndroid Build Coastguard Worker if (klass == nullptr) {
536*795d594fSAndroid Build Coastguard Worker return "(raw)";
537*795d594fSAndroid Build Coastguard Worker }
538*795d594fSAndroid Build Coastguard Worker std::string temp;
539*795d594fSAndroid Build Coastguard Worker std::string result(art::PrettyDescriptor(klass->GetDescriptor(&temp)));
540*795d594fSAndroid Build Coastguard Worker return result;
541*795d594fSAndroid Build Coastguard Worker }
542*795d594fSAndroid Build Coastguard Worker
DumpSmaps(JavaHprofDataSource::TraceContext * ctx)543*795d594fSAndroid Build Coastguard Worker void DumpSmaps(JavaHprofDataSource::TraceContext* ctx) {
544*795d594fSAndroid Build Coastguard Worker FILE* smaps = fopen("/proc/self/smaps", "re");
545*795d594fSAndroid Build Coastguard Worker if (smaps != nullptr) {
546*795d594fSAndroid Build Coastguard Worker auto trace_packet = ctx->NewTracePacket();
547*795d594fSAndroid Build Coastguard Worker auto* smaps_packet = trace_packet->set_smaps_packet();
548*795d594fSAndroid Build Coastguard Worker smaps_packet->set_pid(getpid());
549*795d594fSAndroid Build Coastguard Worker perfetto::profiling::ParseSmaps(smaps,
550*795d594fSAndroid Build Coastguard Worker [&smaps_packet](const perfetto::profiling::SmapsEntry& e) {
551*795d594fSAndroid Build Coastguard Worker if (ShouldSampleSmapsEntry(e)) {
552*795d594fSAndroid Build Coastguard Worker auto* smaps_entry = smaps_packet->add_entries();
553*795d594fSAndroid Build Coastguard Worker smaps_entry->set_path(e.pathname);
554*795d594fSAndroid Build Coastguard Worker smaps_entry->set_size_kb(e.size_kb);
555*795d594fSAndroid Build Coastguard Worker smaps_entry->set_private_dirty_kb(e.private_dirty_kb);
556*795d594fSAndroid Build Coastguard Worker smaps_entry->set_swap_kb(e.swap_kb);
557*795d594fSAndroid Build Coastguard Worker }
558*795d594fSAndroid Build Coastguard Worker });
559*795d594fSAndroid Build Coastguard Worker fclose(smaps);
560*795d594fSAndroid Build Coastguard Worker } else {
561*795d594fSAndroid Build Coastguard Worker PLOG(ERROR) << "failed to open smaps";
562*795d594fSAndroid Build Coastguard Worker }
563*795d594fSAndroid Build Coastguard Worker }
564*795d594fSAndroid Build Coastguard Worker
GetObjectId(const art::mirror::Object * obj)565*795d594fSAndroid Build Coastguard Worker uint64_t GetObjectId(const art::mirror::Object* obj) {
566*795d594fSAndroid Build Coastguard Worker return reinterpret_cast<uint64_t>(obj) / std::alignment_of<art::mirror::Object>::value;
567*795d594fSAndroid Build Coastguard Worker }
568*795d594fSAndroid Build Coastguard Worker
569*795d594fSAndroid Build Coastguard Worker template <typename F>
ForInstanceReferenceField(art::mirror::Class * klass,F fn)570*795d594fSAndroid Build Coastguard Worker void ForInstanceReferenceField(art::mirror::Class* klass, F fn) NO_THREAD_SAFETY_ANALYSIS {
571*795d594fSAndroid Build Coastguard Worker for (art::ArtField& af : klass->GetIFields()) {
572*795d594fSAndroid Build Coastguard Worker if (af.IsPrimitiveType() ||
573*795d594fSAndroid Build Coastguard Worker af.GetOffset().Uint32Value() == art::mirror::Object::ClassOffset().Uint32Value()) {
574*795d594fSAndroid Build Coastguard Worker continue;
575*795d594fSAndroid Build Coastguard Worker }
576*795d594fSAndroid Build Coastguard Worker fn(af.GetOffset());
577*795d594fSAndroid Build Coastguard Worker }
578*795d594fSAndroid Build Coastguard Worker }
579*795d594fSAndroid Build Coastguard Worker
EncodedSize(uint64_t n)580*795d594fSAndroid Build Coastguard Worker size_t EncodedSize(uint64_t n) {
581*795d594fSAndroid Build Coastguard Worker if (n == 0) return 1;
582*795d594fSAndroid Build Coastguard Worker return 1 + static_cast<size_t>(art::MostSignificantBit(n)) / 7;
583*795d594fSAndroid Build Coastguard Worker }
584*795d594fSAndroid Build Coastguard Worker
585*795d594fSAndroid Build Coastguard Worker // Returns all the references that `*obj` (an object of type `*klass`) is holding.
GetReferences(art::mirror::Object * obj,art::mirror::Class * klass,bool emit_field_ids)586*795d594fSAndroid Build Coastguard Worker std::vector<std::pair<std::string, art::mirror::Object*>> GetReferences(art::mirror::Object* obj,
587*795d594fSAndroid Build Coastguard Worker art::mirror::Class* klass,
588*795d594fSAndroid Build Coastguard Worker bool emit_field_ids)
589*795d594fSAndroid Build Coastguard Worker REQUIRES_SHARED(art::Locks::mutator_lock_) {
590*795d594fSAndroid Build Coastguard Worker std::vector<std::pair<std::string, art::mirror::Object*>> referred_objects;
591*795d594fSAndroid Build Coastguard Worker ReferredObjectsFinder objf(&referred_objects, emit_field_ids);
592*795d594fSAndroid Build Coastguard Worker
593*795d594fSAndroid Build Coastguard Worker uint32_t klass_flags = klass->GetClassFlags();
594*795d594fSAndroid Build Coastguard Worker if (klass_flags != art::mirror::kClassFlagNormal &&
595*795d594fSAndroid Build Coastguard Worker klass_flags != art::mirror::kClassFlagSoftReference &&
596*795d594fSAndroid Build Coastguard Worker klass_flags != art::mirror::kClassFlagWeakReference &&
597*795d594fSAndroid Build Coastguard Worker klass_flags != art::mirror::kClassFlagFinalizerReference &&
598*795d594fSAndroid Build Coastguard Worker klass_flags != art::mirror::kClassFlagPhantomReference) {
599*795d594fSAndroid Build Coastguard Worker obj->VisitReferences(objf, art::VoidFunctor());
600*795d594fSAndroid Build Coastguard Worker } else {
601*795d594fSAndroid Build Coastguard Worker for (art::mirror::Class* cls = klass; cls != nullptr; cls = cls->GetSuperClass().Ptr()) {
602*795d594fSAndroid Build Coastguard Worker ForInstanceReferenceField(cls,
603*795d594fSAndroid Build Coastguard Worker [obj, objf](art::MemberOffset offset) NO_THREAD_SAFETY_ANALYSIS {
604*795d594fSAndroid Build Coastguard Worker objf(art::ObjPtr<art::mirror::Object>(obj),
605*795d594fSAndroid Build Coastguard Worker offset,
606*795d594fSAndroid Build Coastguard Worker /*is_static=*/false);
607*795d594fSAndroid Build Coastguard Worker });
608*795d594fSAndroid Build Coastguard Worker }
609*795d594fSAndroid Build Coastguard Worker }
610*795d594fSAndroid Build Coastguard Worker return referred_objects;
611*795d594fSAndroid Build Coastguard Worker }
612*795d594fSAndroid Build Coastguard Worker
613*795d594fSAndroid Build Coastguard Worker // Returns the base for delta encoding all the `referred_objects`. If delta
614*795d594fSAndroid Build Coastguard Worker // encoding would waste space, returns 0.
EncodeBaseObjId(const std::vector<std::pair<std::string,art::mirror::Object * >> & referred_objects,const art::mirror::Object * min_nonnull_ptr)615*795d594fSAndroid Build Coastguard Worker uint64_t EncodeBaseObjId(
616*795d594fSAndroid Build Coastguard Worker const std::vector<std::pair<std::string, art::mirror::Object*>>& referred_objects,
617*795d594fSAndroid Build Coastguard Worker const art::mirror::Object* min_nonnull_ptr) REQUIRES_SHARED(art::Locks::mutator_lock_) {
618*795d594fSAndroid Build Coastguard Worker uint64_t base_obj_id = GetObjectId(min_nonnull_ptr);
619*795d594fSAndroid Build Coastguard Worker if (base_obj_id <= 1) {
620*795d594fSAndroid Build Coastguard Worker return 0;
621*795d594fSAndroid Build Coastguard Worker }
622*795d594fSAndroid Build Coastguard Worker
623*795d594fSAndroid Build Coastguard Worker // We need to decrement the base for object ids so that we can tell apart
624*795d594fSAndroid Build Coastguard Worker // null references.
625*795d594fSAndroid Build Coastguard Worker base_obj_id--;
626*795d594fSAndroid Build Coastguard Worker uint64_t bytes_saved = 0;
627*795d594fSAndroid Build Coastguard Worker for (const auto& p : referred_objects) {
628*795d594fSAndroid Build Coastguard Worker art::mirror::Object* referred_obj = p.second;
629*795d594fSAndroid Build Coastguard Worker if (!referred_obj) {
630*795d594fSAndroid Build Coastguard Worker continue;
631*795d594fSAndroid Build Coastguard Worker }
632*795d594fSAndroid Build Coastguard Worker uint64_t referred_obj_id = GetObjectId(referred_obj);
633*795d594fSAndroid Build Coastguard Worker bytes_saved += EncodedSize(referred_obj_id) - EncodedSize(referred_obj_id - base_obj_id);
634*795d594fSAndroid Build Coastguard Worker }
635*795d594fSAndroid Build Coastguard Worker
636*795d594fSAndroid Build Coastguard Worker // +1 for storing the field id.
637*795d594fSAndroid Build Coastguard Worker if (bytes_saved <= EncodedSize(base_obj_id) + 1) {
638*795d594fSAndroid Build Coastguard Worker // Subtracting the base ptr gains fewer bytes than it takes to store it.
639*795d594fSAndroid Build Coastguard Worker return 0;
640*795d594fSAndroid Build Coastguard Worker }
641*795d594fSAndroid Build Coastguard Worker return base_obj_id;
642*795d594fSAndroid Build Coastguard Worker }
643*795d594fSAndroid Build Coastguard Worker
644*795d594fSAndroid Build Coastguard Worker // Helper to keep intermediate state while dumping objects and classes from ART into
645*795d594fSAndroid Build Coastguard Worker // perfetto.protos.HeapGraph.
646*795d594fSAndroid Build Coastguard Worker class HeapGraphDumper {
647*795d594fSAndroid Build Coastguard Worker public:
648*795d594fSAndroid Build Coastguard Worker // Instances of classes whose name is in `ignored_types` will be ignored.
HeapGraphDumper(const std::vector<std::string> & ignored_types)649*795d594fSAndroid Build Coastguard Worker explicit HeapGraphDumper(const std::vector<std::string>& ignored_types)
650*795d594fSAndroid Build Coastguard Worker : ignored_types_(ignored_types),
651*795d594fSAndroid Build Coastguard Worker reference_field_ids_(std::make_unique<protozero::PackedVarInt>()),
652*795d594fSAndroid Build Coastguard Worker reference_object_ids_(std::make_unique<protozero::PackedVarInt>()) {}
653*795d594fSAndroid Build Coastguard Worker
654*795d594fSAndroid Build Coastguard Worker // Dumps a heap graph from `*runtime` and writes it to `writer`.
Dump(art::Runtime * runtime,Writer & writer)655*795d594fSAndroid Build Coastguard Worker void Dump(art::Runtime* runtime, Writer& writer) REQUIRES(art::Locks::mutator_lock_) {
656*795d594fSAndroid Build Coastguard Worker DumpRootObjects(runtime, writer);
657*795d594fSAndroid Build Coastguard Worker
658*795d594fSAndroid Build Coastguard Worker DumpObjects(runtime, writer);
659*795d594fSAndroid Build Coastguard Worker
660*795d594fSAndroid Build Coastguard Worker WriteInternedData(writer);
661*795d594fSAndroid Build Coastguard Worker }
662*795d594fSAndroid Build Coastguard Worker
663*795d594fSAndroid Build Coastguard Worker private:
664*795d594fSAndroid Build Coastguard Worker // Dumps the root objects from `*runtime` to `writer`.
DumpRootObjects(art::Runtime * runtime,Writer & writer)665*795d594fSAndroid Build Coastguard Worker void DumpRootObjects(art::Runtime* runtime, Writer& writer)
666*795d594fSAndroid Build Coastguard Worker REQUIRES_SHARED(art::Locks::mutator_lock_) {
667*795d594fSAndroid Build Coastguard Worker std::map<art::RootType, std::vector<art::mirror::Object*>> root_objects;
668*795d594fSAndroid Build Coastguard Worker RootFinder rcf(&root_objects);
669*795d594fSAndroid Build Coastguard Worker runtime->VisitRoots(&rcf);
670*795d594fSAndroid Build Coastguard Worker std::unique_ptr<protozero::PackedVarInt> object_ids(new protozero::PackedVarInt);
671*795d594fSAndroid Build Coastguard Worker for (const auto& p : root_objects) {
672*795d594fSAndroid Build Coastguard Worker const art::RootType root_type = p.first;
673*795d594fSAndroid Build Coastguard Worker const std::vector<art::mirror::Object*>& children = p.second;
674*795d594fSAndroid Build Coastguard Worker perfetto::protos::pbzero::HeapGraphRoot* root_proto = writer.GetHeapGraph()->add_roots();
675*795d594fSAndroid Build Coastguard Worker root_proto->set_root_type(ToProtoType(root_type));
676*795d594fSAndroid Build Coastguard Worker for (art::mirror::Object* obj : children) {
677*795d594fSAndroid Build Coastguard Worker if (writer.will_create_new_packet()) {
678*795d594fSAndroid Build Coastguard Worker root_proto->set_object_ids(*object_ids);
679*795d594fSAndroid Build Coastguard Worker object_ids->Reset();
680*795d594fSAndroid Build Coastguard Worker root_proto = writer.GetHeapGraph()->add_roots();
681*795d594fSAndroid Build Coastguard Worker root_proto->set_root_type(ToProtoType(root_type));
682*795d594fSAndroid Build Coastguard Worker }
683*795d594fSAndroid Build Coastguard Worker object_ids->Append(GetObjectId(obj));
684*795d594fSAndroid Build Coastguard Worker }
685*795d594fSAndroid Build Coastguard Worker root_proto->set_object_ids(*object_ids);
686*795d594fSAndroid Build Coastguard Worker object_ids->Reset();
687*795d594fSAndroid Build Coastguard Worker }
688*795d594fSAndroid Build Coastguard Worker }
689*795d594fSAndroid Build Coastguard Worker
690*795d594fSAndroid Build Coastguard Worker // Dumps all the objects from `*runtime` to `writer`.
DumpObjects(art::Runtime * runtime,Writer & writer)691*795d594fSAndroid Build Coastguard Worker void DumpObjects(art::Runtime* runtime, Writer& writer) REQUIRES(art::Locks::mutator_lock_) {
692*795d594fSAndroid Build Coastguard Worker runtime->GetHeap()->VisitObjectsPaused(
693*795d594fSAndroid Build Coastguard Worker [this, &writer](art::mirror::Object* obj)
694*795d594fSAndroid Build Coastguard Worker REQUIRES_SHARED(art::Locks::mutator_lock_) { WriteOneObject(obj, writer); });
695*795d594fSAndroid Build Coastguard Worker }
696*795d594fSAndroid Build Coastguard Worker
697*795d594fSAndroid Build Coastguard Worker // Writes all the previously accumulated (while dumping objects and roots) interned data to
698*795d594fSAndroid Build Coastguard Worker // `writer`.
WriteInternedData(Writer & writer)699*795d594fSAndroid Build Coastguard Worker void WriteInternedData(Writer& writer) {
700*795d594fSAndroid Build Coastguard Worker for (const auto& p : interned_locations_) {
701*795d594fSAndroid Build Coastguard Worker const std::string& str = p.first;
702*795d594fSAndroid Build Coastguard Worker uint64_t id = p.second;
703*795d594fSAndroid Build Coastguard Worker
704*795d594fSAndroid Build Coastguard Worker perfetto::protos::pbzero::InternedString* location_proto =
705*795d594fSAndroid Build Coastguard Worker writer.GetHeapGraph()->add_location_names();
706*795d594fSAndroid Build Coastguard Worker location_proto->set_iid(id);
707*795d594fSAndroid Build Coastguard Worker location_proto->set_str(reinterpret_cast<const uint8_t*>(str.c_str()), str.size());
708*795d594fSAndroid Build Coastguard Worker }
709*795d594fSAndroid Build Coastguard Worker for (const auto& p : interned_fields_) {
710*795d594fSAndroid Build Coastguard Worker const std::string& str = p.first;
711*795d594fSAndroid Build Coastguard Worker uint64_t id = p.second;
712*795d594fSAndroid Build Coastguard Worker
713*795d594fSAndroid Build Coastguard Worker perfetto::protos::pbzero::InternedString* field_proto =
714*795d594fSAndroid Build Coastguard Worker writer.GetHeapGraph()->add_field_names();
715*795d594fSAndroid Build Coastguard Worker field_proto->set_iid(id);
716*795d594fSAndroid Build Coastguard Worker field_proto->set_str(reinterpret_cast<const uint8_t*>(str.c_str()), str.size());
717*795d594fSAndroid Build Coastguard Worker }
718*795d594fSAndroid Build Coastguard Worker }
719*795d594fSAndroid Build Coastguard Worker
720*795d594fSAndroid Build Coastguard Worker // Writes `*obj` into `writer`.
WriteOneObject(art::mirror::Object * obj,Writer & writer)721*795d594fSAndroid Build Coastguard Worker void WriteOneObject(art::mirror::Object* obj, Writer& writer)
722*795d594fSAndroid Build Coastguard Worker REQUIRES_SHARED(art::Locks::mutator_lock_) {
723*795d594fSAndroid Build Coastguard Worker if (obj->IsClass()) {
724*795d594fSAndroid Build Coastguard Worker WriteClass(obj->AsClass().Ptr(), writer);
725*795d594fSAndroid Build Coastguard Worker }
726*795d594fSAndroid Build Coastguard Worker
727*795d594fSAndroid Build Coastguard Worker art::mirror::Class* klass = obj->GetClass();
728*795d594fSAndroid Build Coastguard Worker uintptr_t class_ptr = reinterpret_cast<uintptr_t>(klass);
729*795d594fSAndroid Build Coastguard Worker // We need to synethesize a new type for Class<Foo>, which does not exist
730*795d594fSAndroid Build Coastguard Worker // in the runtime. Otherwise, all the static members of all classes would be
731*795d594fSAndroid Build Coastguard Worker // attributed to java.lang.Class.
732*795d594fSAndroid Build Coastguard Worker if (klass->IsClassClass()) {
733*795d594fSAndroid Build Coastguard Worker class_ptr = WriteSyntheticClassFromObj(obj, writer);
734*795d594fSAndroid Build Coastguard Worker }
735*795d594fSAndroid Build Coastguard Worker
736*795d594fSAndroid Build Coastguard Worker if (IsIgnored(obj)) {
737*795d594fSAndroid Build Coastguard Worker return;
738*795d594fSAndroid Build Coastguard Worker }
739*795d594fSAndroid Build Coastguard Worker
740*795d594fSAndroid Build Coastguard Worker auto class_id = FindOrAppend(&interned_classes_, class_ptr);
741*795d594fSAndroid Build Coastguard Worker
742*795d594fSAndroid Build Coastguard Worker uint64_t object_id = GetObjectId(obj);
743*795d594fSAndroid Build Coastguard Worker perfetto::protos::pbzero::HeapGraphObject* object_proto = writer.GetHeapGraph()->add_objects();
744*795d594fSAndroid Build Coastguard Worker if (prev_object_id_ && prev_object_id_ < object_id) {
745*795d594fSAndroid Build Coastguard Worker object_proto->set_id_delta(object_id - prev_object_id_);
746*795d594fSAndroid Build Coastguard Worker } else {
747*795d594fSAndroid Build Coastguard Worker object_proto->set_id(object_id);
748*795d594fSAndroid Build Coastguard Worker }
749*795d594fSAndroid Build Coastguard Worker prev_object_id_ = object_id;
750*795d594fSAndroid Build Coastguard Worker object_proto->set_type_id(class_id);
751*795d594fSAndroid Build Coastguard Worker
752*795d594fSAndroid Build Coastguard Worker // Arrays / strings are magic and have an instance dependent size.
753*795d594fSAndroid Build Coastguard Worker if (obj->SizeOf() != klass->GetObjectSize()) {
754*795d594fSAndroid Build Coastguard Worker object_proto->set_self_size(obj->SizeOf());
755*795d594fSAndroid Build Coastguard Worker }
756*795d594fSAndroid Build Coastguard Worker
757*795d594fSAndroid Build Coastguard Worker const art::gc::Heap* heap = art::Runtime::Current()->GetHeap();
758*795d594fSAndroid Build Coastguard Worker const auto* space = heap->FindContinuousSpaceFromObject(obj, /*fail_ok=*/true);
759*795d594fSAndroid Build Coastguard Worker auto heap_type = perfetto::protos::pbzero::HeapGraphObject::HEAP_TYPE_APP;
760*795d594fSAndroid Build Coastguard Worker if (space != nullptr) {
761*795d594fSAndroid Build Coastguard Worker if (space->IsZygoteSpace()) {
762*795d594fSAndroid Build Coastguard Worker heap_type = perfetto::protos::pbzero::HeapGraphObject::HEAP_TYPE_ZYGOTE;
763*795d594fSAndroid Build Coastguard Worker } else if (space->IsImageSpace() && heap->ObjectIsInBootImageSpace(obj)) {
764*795d594fSAndroid Build Coastguard Worker heap_type = perfetto::protos::pbzero::HeapGraphObject::HEAP_TYPE_BOOT_IMAGE;
765*795d594fSAndroid Build Coastguard Worker }
766*795d594fSAndroid Build Coastguard Worker } else {
767*795d594fSAndroid Build Coastguard Worker const auto* los = heap->GetLargeObjectsSpace();
768*795d594fSAndroid Build Coastguard Worker if (los->Contains(obj) && los->IsZygoteLargeObject(art::Thread::Current(), obj)) {
769*795d594fSAndroid Build Coastguard Worker heap_type = perfetto::protos::pbzero::HeapGraphObject::HEAP_TYPE_ZYGOTE;
770*795d594fSAndroid Build Coastguard Worker }
771*795d594fSAndroid Build Coastguard Worker }
772*795d594fSAndroid Build Coastguard Worker if (heap_type != prev_heap_type_) {
773*795d594fSAndroid Build Coastguard Worker object_proto->set_heap_type_delta(heap_type);
774*795d594fSAndroid Build Coastguard Worker prev_heap_type_ = heap_type;
775*795d594fSAndroid Build Coastguard Worker }
776*795d594fSAndroid Build Coastguard Worker
777*795d594fSAndroid Build Coastguard Worker FillReferences(obj, klass, object_proto);
778*795d594fSAndroid Build Coastguard Worker
779*795d594fSAndroid Build Coastguard Worker FillFieldValues(obj, klass, object_proto);
780*795d594fSAndroid Build Coastguard Worker }
781*795d594fSAndroid Build Coastguard Worker
782*795d594fSAndroid Build Coastguard Worker // Writes `*klass` into `writer`.
WriteClass(art::mirror::Class * klass,Writer & writer)783*795d594fSAndroid Build Coastguard Worker void WriteClass(art::mirror::Class* klass, Writer& writer)
784*795d594fSAndroid Build Coastguard Worker REQUIRES_SHARED(art::Locks::mutator_lock_) {
785*795d594fSAndroid Build Coastguard Worker perfetto::protos::pbzero::HeapGraphType* type_proto = writer.GetHeapGraph()->add_types();
786*795d594fSAndroid Build Coastguard Worker type_proto->set_id(FindOrAppend(&interned_classes_, reinterpret_cast<uintptr_t>(klass)));
787*795d594fSAndroid Build Coastguard Worker type_proto->set_class_name(PrettyType(klass));
788*795d594fSAndroid Build Coastguard Worker type_proto->set_location_id(FindOrAppend(&interned_locations_, klass->GetLocation()));
789*795d594fSAndroid Build Coastguard Worker type_proto->set_object_size(klass->GetObjectSize());
790*795d594fSAndroid Build Coastguard Worker type_proto->set_kind(ProtoClassKind(klass->GetClassFlags()));
791*795d594fSAndroid Build Coastguard Worker type_proto->set_classloader_id(GetObjectId(klass->GetClassLoader().Ptr()));
792*795d594fSAndroid Build Coastguard Worker if (klass->GetSuperClass().Ptr()) {
793*795d594fSAndroid Build Coastguard Worker type_proto->set_superclass_id(FindOrAppend(
794*795d594fSAndroid Build Coastguard Worker &interned_classes_, reinterpret_cast<uintptr_t>(klass->GetSuperClass().Ptr())));
795*795d594fSAndroid Build Coastguard Worker }
796*795d594fSAndroid Build Coastguard Worker ForInstanceReferenceField(
797*795d594fSAndroid Build Coastguard Worker klass, [klass, this](art::MemberOffset offset) NO_THREAD_SAFETY_ANALYSIS {
798*795d594fSAndroid Build Coastguard Worker auto art_field = art::ArtField::FindInstanceFieldWithOffset(klass, offset.Uint32Value());
799*795d594fSAndroid Build Coastguard Worker reference_field_ids_->Append(
800*795d594fSAndroid Build Coastguard Worker FindOrAppend(&interned_fields_, art_field->PrettyField(true)));
801*795d594fSAndroid Build Coastguard Worker });
802*795d594fSAndroid Build Coastguard Worker type_proto->set_reference_field_id(*reference_field_ids_);
803*795d594fSAndroid Build Coastguard Worker reference_field_ids_->Reset();
804*795d594fSAndroid Build Coastguard Worker }
805*795d594fSAndroid Build Coastguard Worker
806*795d594fSAndroid Build Coastguard Worker // Creates a fake class that represents a type only used by `*obj` into `writer`.
WriteSyntheticClassFromObj(art::mirror::Object * obj,Writer & writer)807*795d594fSAndroid Build Coastguard Worker uintptr_t WriteSyntheticClassFromObj(art::mirror::Object* obj, Writer& writer)
808*795d594fSAndroid Build Coastguard Worker REQUIRES_SHARED(art::Locks::mutator_lock_) {
809*795d594fSAndroid Build Coastguard Worker CHECK(obj->IsClass());
810*795d594fSAndroid Build Coastguard Worker perfetto::protos::pbzero::HeapGraphType* type_proto = writer.GetHeapGraph()->add_types();
811*795d594fSAndroid Build Coastguard Worker // All pointers are at least multiples of two, so this way we can make sure
812*795d594fSAndroid Build Coastguard Worker // we are not colliding with a real class.
813*795d594fSAndroid Build Coastguard Worker uintptr_t class_ptr = reinterpret_cast<uintptr_t>(obj) | 1;
814*795d594fSAndroid Build Coastguard Worker auto class_id = FindOrAppend(&interned_classes_, class_ptr);
815*795d594fSAndroid Build Coastguard Worker type_proto->set_id(class_id);
816*795d594fSAndroid Build Coastguard Worker type_proto->set_class_name(obj->PrettyTypeOf());
817*795d594fSAndroid Build Coastguard Worker type_proto->set_location_id(FindOrAppend(&interned_locations_, obj->AsClass()->GetLocation()));
818*795d594fSAndroid Build Coastguard Worker return class_ptr;
819*795d594fSAndroid Build Coastguard Worker }
820*795d594fSAndroid Build Coastguard Worker
821*795d594fSAndroid Build Coastguard Worker // Fills `*object_proto` with all the references held by `*obj` (an object of type `*klass`).
FillReferences(art::mirror::Object * obj,art::mirror::Class * klass,perfetto::protos::pbzero::HeapGraphObject * object_proto)822*795d594fSAndroid Build Coastguard Worker void FillReferences(art::mirror::Object* obj,
823*795d594fSAndroid Build Coastguard Worker art::mirror::Class* klass,
824*795d594fSAndroid Build Coastguard Worker perfetto::protos::pbzero::HeapGraphObject* object_proto)
825*795d594fSAndroid Build Coastguard Worker REQUIRES_SHARED(art::Locks::mutator_lock_) {
826*795d594fSAndroid Build Coastguard Worker const uint32_t klass_flags = klass->GetClassFlags();
827*795d594fSAndroid Build Coastguard Worker const bool emit_field_ids = klass_flags != art::mirror::kClassFlagObjectArray &&
828*795d594fSAndroid Build Coastguard Worker klass_flags != art::mirror::kClassFlagNormal &&
829*795d594fSAndroid Build Coastguard Worker klass_flags != art::mirror::kClassFlagSoftReference &&
830*795d594fSAndroid Build Coastguard Worker klass_flags != art::mirror::kClassFlagWeakReference &&
831*795d594fSAndroid Build Coastguard Worker klass_flags != art::mirror::kClassFlagFinalizerReference &&
832*795d594fSAndroid Build Coastguard Worker klass_flags != art::mirror::kClassFlagPhantomReference;
833*795d594fSAndroid Build Coastguard Worker std::vector<std::pair<std::string, art::mirror::Object*>> referred_objects =
834*795d594fSAndroid Build Coastguard Worker GetReferences(obj, klass, emit_field_ids);
835*795d594fSAndroid Build Coastguard Worker
836*795d594fSAndroid Build Coastguard Worker art::mirror::Object* min_nonnull_ptr = FilterIgnoredReferencesAndFindMin(referred_objects);
837*795d594fSAndroid Build Coastguard Worker
838*795d594fSAndroid Build Coastguard Worker uint64_t base_obj_id = EncodeBaseObjId(referred_objects, min_nonnull_ptr);
839*795d594fSAndroid Build Coastguard Worker
840*795d594fSAndroid Build Coastguard Worker for (const auto& p : referred_objects) {
841*795d594fSAndroid Build Coastguard Worker const std::string& field_name = p.first;
842*795d594fSAndroid Build Coastguard Worker art::mirror::Object* referred_obj = p.second;
843*795d594fSAndroid Build Coastguard Worker if (emit_field_ids) {
844*795d594fSAndroid Build Coastguard Worker reference_field_ids_->Append(FindOrAppend(&interned_fields_, field_name));
845*795d594fSAndroid Build Coastguard Worker }
846*795d594fSAndroid Build Coastguard Worker uint64_t referred_obj_id = GetObjectId(referred_obj);
847*795d594fSAndroid Build Coastguard Worker if (referred_obj_id) {
848*795d594fSAndroid Build Coastguard Worker referred_obj_id -= base_obj_id;
849*795d594fSAndroid Build Coastguard Worker }
850*795d594fSAndroid Build Coastguard Worker reference_object_ids_->Append(referred_obj_id);
851*795d594fSAndroid Build Coastguard Worker }
852*795d594fSAndroid Build Coastguard Worker if (emit_field_ids) {
853*795d594fSAndroid Build Coastguard Worker object_proto->set_reference_field_id(*reference_field_ids_);
854*795d594fSAndroid Build Coastguard Worker reference_field_ids_->Reset();
855*795d594fSAndroid Build Coastguard Worker }
856*795d594fSAndroid Build Coastguard Worker if (base_obj_id) {
857*795d594fSAndroid Build Coastguard Worker // The field is called `reference_field_id_base`, but it has always been used as a base for
858*795d594fSAndroid Build Coastguard Worker // `reference_object_id`. It should be called `reference_object_id_base`.
859*795d594fSAndroid Build Coastguard Worker object_proto->set_reference_field_id_base(base_obj_id);
860*795d594fSAndroid Build Coastguard Worker }
861*795d594fSAndroid Build Coastguard Worker object_proto->set_reference_object_id(*reference_object_ids_);
862*795d594fSAndroid Build Coastguard Worker reference_object_ids_->Reset();
863*795d594fSAndroid Build Coastguard Worker }
864*795d594fSAndroid Build Coastguard Worker
865*795d594fSAndroid Build Coastguard Worker // Iterates all the `referred_objects` and sets all the objects that are supposed to be ignored
866*795d594fSAndroid Build Coastguard Worker // to nullptr. Returns the object with the smallest address (ignoring nullptr).
FilterIgnoredReferencesAndFindMin(std::vector<std::pair<std::string,art::mirror::Object * >> & referred_objects) const867*795d594fSAndroid Build Coastguard Worker art::mirror::Object* FilterIgnoredReferencesAndFindMin(
868*795d594fSAndroid Build Coastguard Worker std::vector<std::pair<std::string, art::mirror::Object*>>& referred_objects) const
869*795d594fSAndroid Build Coastguard Worker REQUIRES_SHARED(art::Locks::mutator_lock_) {
870*795d594fSAndroid Build Coastguard Worker art::mirror::Object* min_nonnull_ptr = nullptr;
871*795d594fSAndroid Build Coastguard Worker for (auto& p : referred_objects) {
872*795d594fSAndroid Build Coastguard Worker art::mirror::Object*& referred_obj = p.second;
873*795d594fSAndroid Build Coastguard Worker if (referred_obj == nullptr)
874*795d594fSAndroid Build Coastguard Worker continue;
875*795d594fSAndroid Build Coastguard Worker if (IsIgnored(referred_obj)) {
876*795d594fSAndroid Build Coastguard Worker referred_obj = nullptr;
877*795d594fSAndroid Build Coastguard Worker continue;
878*795d594fSAndroid Build Coastguard Worker }
879*795d594fSAndroid Build Coastguard Worker if (min_nonnull_ptr == nullptr || min_nonnull_ptr > referred_obj) {
880*795d594fSAndroid Build Coastguard Worker min_nonnull_ptr = referred_obj;
881*795d594fSAndroid Build Coastguard Worker }
882*795d594fSAndroid Build Coastguard Worker }
883*795d594fSAndroid Build Coastguard Worker return min_nonnull_ptr;
884*795d594fSAndroid Build Coastguard Worker }
885*795d594fSAndroid Build Coastguard Worker
886*795d594fSAndroid Build Coastguard Worker // Fills `*object_proto` with the value of a subset of potentially interesting fields of `*obj`
887*795d594fSAndroid Build Coastguard Worker // (an object of type `*klass`).
FillFieldValues(art::mirror::Object * obj,art::mirror::Class * klass,perfetto::protos::pbzero::HeapGraphObject * object_proto) const888*795d594fSAndroid Build Coastguard Worker void FillFieldValues(art::mirror::Object* obj,
889*795d594fSAndroid Build Coastguard Worker art::mirror::Class* klass,
890*795d594fSAndroid Build Coastguard Worker perfetto::protos::pbzero::HeapGraphObject* object_proto) const
891*795d594fSAndroid Build Coastguard Worker REQUIRES_SHARED(art::Locks::mutator_lock_) {
892*795d594fSAndroid Build Coastguard Worker if (obj->IsClass() || klass->IsClassClass()) {
893*795d594fSAndroid Build Coastguard Worker return;
894*795d594fSAndroid Build Coastguard Worker }
895*795d594fSAndroid Build Coastguard Worker
896*795d594fSAndroid Build Coastguard Worker for (art::mirror::Class* cls = klass; cls != nullptr; cls = cls->GetSuperClass().Ptr()) {
897*795d594fSAndroid Build Coastguard Worker if (cls->IsArrayClass()) {
898*795d594fSAndroid Build Coastguard Worker continue;
899*795d594fSAndroid Build Coastguard Worker }
900*795d594fSAndroid Build Coastguard Worker
901*795d594fSAndroid Build Coastguard Worker if (cls->DescriptorEquals("Llibcore/util/NativeAllocationRegistry;")) {
902*795d594fSAndroid Build Coastguard Worker art::ArtField* af = cls->FindDeclaredInstanceField(
903*795d594fSAndroid Build Coastguard Worker "size", art::Primitive::Descriptor(art::Primitive::kPrimLong));
904*795d594fSAndroid Build Coastguard Worker if (af) {
905*795d594fSAndroid Build Coastguard Worker object_proto->set_native_allocation_registry_size_field(af->GetLong(obj));
906*795d594fSAndroid Build Coastguard Worker }
907*795d594fSAndroid Build Coastguard Worker }
908*795d594fSAndroid Build Coastguard Worker }
909*795d594fSAndroid Build Coastguard Worker }
910*795d594fSAndroid Build Coastguard Worker
911*795d594fSAndroid Build Coastguard Worker // Returns true if `*obj` has a type that's supposed to be ignored.
IsIgnored(art::mirror::Object * obj) const912*795d594fSAndroid Build Coastguard Worker bool IsIgnored(art::mirror::Object* obj) const REQUIRES_SHARED(art::Locks::mutator_lock_) {
913*795d594fSAndroid Build Coastguard Worker if (obj->IsClass()) {
914*795d594fSAndroid Build Coastguard Worker return false;
915*795d594fSAndroid Build Coastguard Worker }
916*795d594fSAndroid Build Coastguard Worker art::mirror::Class* klass = obj->GetClass();
917*795d594fSAndroid Build Coastguard Worker std::string temp;
918*795d594fSAndroid Build Coastguard Worker std::string_view name(klass->GetDescriptor(&temp));
919*795d594fSAndroid Build Coastguard Worker return std::find(ignored_types_.begin(), ignored_types_.end(), name) != ignored_types_.end();
920*795d594fSAndroid Build Coastguard Worker }
921*795d594fSAndroid Build Coastguard Worker
922*795d594fSAndroid Build Coastguard Worker // Name of classes whose instances should be ignored.
923*795d594fSAndroid Build Coastguard Worker const std::vector<std::string> ignored_types_;
924*795d594fSAndroid Build Coastguard Worker
925*795d594fSAndroid Build Coastguard Worker // Make sure that intern ID 0 (default proto value for a uint64_t) always maps to ""
926*795d594fSAndroid Build Coastguard Worker // (default proto value for a string) or to 0 (default proto value for a uint64).
927*795d594fSAndroid Build Coastguard Worker
928*795d594fSAndroid Build Coastguard Worker // Map from string (the field name) to its index in perfetto.protos.HeapGraph.field_names
929*795d594fSAndroid Build Coastguard Worker std::map<std::string, uint64_t> interned_fields_{{"", 0}};
930*795d594fSAndroid Build Coastguard Worker // Map from string (the location name) to its index in perfetto.protos.HeapGraph.location_names
931*795d594fSAndroid Build Coastguard Worker std::map<std::string, uint64_t> interned_locations_{{"", 0}};
932*795d594fSAndroid Build Coastguard Worker // Map from addr (the class pointer) to its id in perfetto.protos.HeapGraph.types
933*795d594fSAndroid Build Coastguard Worker std::map<uintptr_t, uint64_t> interned_classes_{{0, 0}};
934*795d594fSAndroid Build Coastguard Worker
935*795d594fSAndroid Build Coastguard Worker // Temporary buffers: used locally in some methods and then cleared.
936*795d594fSAndroid Build Coastguard Worker std::unique_ptr<protozero::PackedVarInt> reference_field_ids_;
937*795d594fSAndroid Build Coastguard Worker std::unique_ptr<protozero::PackedVarInt> reference_object_ids_;
938*795d594fSAndroid Build Coastguard Worker
939*795d594fSAndroid Build Coastguard Worker // Id of the previous object that was dumped. Used for delta encoding.
940*795d594fSAndroid Build Coastguard Worker uint64_t prev_object_id_ = 0;
941*795d594fSAndroid Build Coastguard Worker // Heap type of the previous object that was dumped. Used for delta encoding.
942*795d594fSAndroid Build Coastguard Worker perfetto::protos::pbzero::HeapGraphObject::HeapType prev_heap_type_ =
943*795d594fSAndroid Build Coastguard Worker perfetto::protos::pbzero::HeapGraphObject::HEAP_TYPE_UNKNOWN;
944*795d594fSAndroid Build Coastguard Worker };
945*795d594fSAndroid Build Coastguard Worker
946*795d594fSAndroid Build Coastguard Worker // waitpid with a timeout implemented by ~busy-waiting
947*795d594fSAndroid Build Coastguard Worker // See b/181031512 for rationale.
BusyWaitpid(pid_t pid,uint32_t timeout_ms)948*795d594fSAndroid Build Coastguard Worker void BusyWaitpid(pid_t pid, uint32_t timeout_ms) {
949*795d594fSAndroid Build Coastguard Worker for (size_t i = 0;; ++i) {
950*795d594fSAndroid Build Coastguard Worker if (i == timeout_ms) {
951*795d594fSAndroid Build Coastguard Worker // The child hasn't exited.
952*795d594fSAndroid Build Coastguard Worker // Give up and SIGKILL it. The next waitpid should succeed.
953*795d594fSAndroid Build Coastguard Worker LOG(ERROR) << "perfetto_hprof child timed out. Sending SIGKILL.";
954*795d594fSAndroid Build Coastguard Worker kill(pid, SIGKILL);
955*795d594fSAndroid Build Coastguard Worker }
956*795d594fSAndroid Build Coastguard Worker int stat_loc;
957*795d594fSAndroid Build Coastguard Worker pid_t wait_result = waitpid(pid, &stat_loc, WNOHANG);
958*795d594fSAndroid Build Coastguard Worker if (wait_result == -1 && errno != EINTR) {
959*795d594fSAndroid Build Coastguard Worker if (errno != ECHILD) {
960*795d594fSAndroid Build Coastguard Worker // This hopefully never happens (should only be EINVAL).
961*795d594fSAndroid Build Coastguard Worker PLOG(FATAL_WITHOUT_ABORT) << "waitpid";
962*795d594fSAndroid Build Coastguard Worker }
963*795d594fSAndroid Build Coastguard Worker // If we get ECHILD, the parent process was handling SIGCHLD, or did a wildcard wait.
964*795d594fSAndroid Build Coastguard Worker // The child is no longer here either way, so that's good enough for us.
965*795d594fSAndroid Build Coastguard Worker break;
966*795d594fSAndroid Build Coastguard Worker } else if (wait_result > 0) {
967*795d594fSAndroid Build Coastguard Worker break;
968*795d594fSAndroid Build Coastguard Worker } else { // wait_result == 0 || errno == EINTR.
969*795d594fSAndroid Build Coastguard Worker usleep(1000);
970*795d594fSAndroid Build Coastguard Worker }
971*795d594fSAndroid Build Coastguard Worker }
972*795d594fSAndroid Build Coastguard Worker }
973*795d594fSAndroid Build Coastguard Worker
974*795d594fSAndroid Build Coastguard Worker enum class ResumeParentPolicy {
975*795d594fSAndroid Build Coastguard Worker IMMEDIATELY,
976*795d594fSAndroid Build Coastguard Worker DEFERRED
977*795d594fSAndroid Build Coastguard Worker };
978*795d594fSAndroid Build Coastguard Worker
ForkUnderThreadListLock(art::Thread * self)979*795d594fSAndroid Build Coastguard Worker pid_t ForkUnderThreadListLock(art::Thread* self) {
980*795d594fSAndroid Build Coastguard Worker art::MutexLock lk(self, *art::Locks::thread_list_lock_);
981*795d594fSAndroid Build Coastguard Worker return fork();
982*795d594fSAndroid Build Coastguard Worker }
983*795d594fSAndroid Build Coastguard Worker
ForkAndRun(art::Thread * self,ResumeParentPolicy resume_parent_policy,const std::function<void (pid_t child)> & parent_runnable,const std::function<void (pid_t parent,uint64_t timestamp)> & child_runnable)984*795d594fSAndroid Build Coastguard Worker void ForkAndRun(art::Thread* self,
985*795d594fSAndroid Build Coastguard Worker ResumeParentPolicy resume_parent_policy,
986*795d594fSAndroid Build Coastguard Worker const std::function<void(pid_t child)>& parent_runnable,
987*795d594fSAndroid Build Coastguard Worker const std::function<void(pid_t parent, uint64_t timestamp)>& child_runnable) {
988*795d594fSAndroid Build Coastguard Worker pid_t parent_pid = getpid();
989*795d594fSAndroid Build Coastguard Worker LOG(INFO) << "forking for " << parent_pid;
990*795d594fSAndroid Build Coastguard Worker // Need to take a heap dump while GC isn't running. See the comment in
991*795d594fSAndroid Build Coastguard Worker // Heap::VisitObjects(). Also we need the critical section to avoid visiting
992*795d594fSAndroid Build Coastguard Worker // the same object twice. See b/34967844.
993*795d594fSAndroid Build Coastguard Worker //
994*795d594fSAndroid Build Coastguard Worker // We need to do this before the fork, because otherwise it can deadlock
995*795d594fSAndroid Build Coastguard Worker // waiting for the GC, as all other threads get terminated by the clone, but
996*795d594fSAndroid Build Coastguard Worker // their locks are not released.
997*795d594fSAndroid Build Coastguard Worker // We must also avoid any logd logging actions on the forked process; art LogdLoggerLocked
998*795d594fSAndroid Build Coastguard Worker // serializes logging from different threads via a mutex.
999*795d594fSAndroid Build Coastguard Worker // This does not perfectly solve all fork-related issues, as there could still be threads that
1000*795d594fSAndroid Build Coastguard Worker // are unaffected by ScopedSuspendAll and in a non-fork-friendly situation
1001*795d594fSAndroid Build Coastguard Worker // (e.g. inside a malloc holding a lock). This situation is quite rare, and in that case we will
1002*795d594fSAndroid Build Coastguard Worker // hit the watchdog in the grand-child process if it gets stuck.
1003*795d594fSAndroid Build Coastguard Worker std::optional<art::gc::ScopedGCCriticalSection> gcs(std::in_place, self, art::gc::kGcCauseHprof,
1004*795d594fSAndroid Build Coastguard Worker art::gc::kCollectorTypeHprof);
1005*795d594fSAndroid Build Coastguard Worker
1006*795d594fSAndroid Build Coastguard Worker std::optional<art::ScopedSuspendAll> ssa(std::in_place, __FUNCTION__, /* long_suspend=*/ true);
1007*795d594fSAndroid Build Coastguard Worker
1008*795d594fSAndroid Build Coastguard Worker // Optimistically get the thread_list_lock_ to avoid the child process deadlocking
1009*795d594fSAndroid Build Coastguard Worker pid_t pid = ForkUnderThreadListLock(self);
1010*795d594fSAndroid Build Coastguard Worker if (pid == -1) {
1011*795d594fSAndroid Build Coastguard Worker // Fork error.
1012*795d594fSAndroid Build Coastguard Worker PLOG(ERROR) << "fork";
1013*795d594fSAndroid Build Coastguard Worker return;
1014*795d594fSAndroid Build Coastguard Worker }
1015*795d594fSAndroid Build Coastguard Worker if (pid != 0) {
1016*795d594fSAndroid Build Coastguard Worker // Parent
1017*795d594fSAndroid Build Coastguard Worker if (resume_parent_policy == ResumeParentPolicy::IMMEDIATELY) {
1018*795d594fSAndroid Build Coastguard Worker // Stop the thread suspension as soon as possible to allow the rest of the application to
1019*795d594fSAndroid Build Coastguard Worker // continue while we waitpid here.
1020*795d594fSAndroid Build Coastguard Worker ssa.reset();
1021*795d594fSAndroid Build Coastguard Worker gcs.reset();
1022*795d594fSAndroid Build Coastguard Worker }
1023*795d594fSAndroid Build Coastguard Worker parent_runnable(pid);
1024*795d594fSAndroid Build Coastguard Worker if (resume_parent_policy != ResumeParentPolicy::IMMEDIATELY) {
1025*795d594fSAndroid Build Coastguard Worker ssa.reset();
1026*795d594fSAndroid Build Coastguard Worker gcs.reset();
1027*795d594fSAndroid Build Coastguard Worker }
1028*795d594fSAndroid Build Coastguard Worker return;
1029*795d594fSAndroid Build Coastguard Worker }
1030*795d594fSAndroid Build Coastguard Worker // The following code is only executed by the child of the original process.
1031*795d594fSAndroid Build Coastguard Worker // Uninstall signal handler, so we don't trigger a profile on it.
1032*795d594fSAndroid Build Coastguard Worker if (sigaction(kJavaHeapprofdSignal, &g_orig_act, nullptr) != 0) {
1033*795d594fSAndroid Build Coastguard Worker close(g_signal_pipe_fds[0]);
1034*795d594fSAndroid Build Coastguard Worker close(g_signal_pipe_fds[1]);
1035*795d594fSAndroid Build Coastguard Worker PLOG(FATAL) << "Failed to sigaction";
1036*795d594fSAndroid Build Coastguard Worker return;
1037*795d594fSAndroid Build Coastguard Worker }
1038*795d594fSAndroid Build Coastguard Worker
1039*795d594fSAndroid Build Coastguard Worker uint64_t ts = GetCurrentBootClockNs();
1040*795d594fSAndroid Build Coastguard Worker child_runnable(parent_pid, ts);
1041*795d594fSAndroid Build Coastguard Worker // Prevent the `atexit` handlers from running. We do not want to call cleanup
1042*795d594fSAndroid Build Coastguard Worker // functions the parent process has registered.
1043*795d594fSAndroid Build Coastguard Worker art::FastExit(0);
1044*795d594fSAndroid Build Coastguard Worker }
1045*795d594fSAndroid Build Coastguard Worker
WriteHeapPackets(pid_t parent_pid,uint64_t timestamp)1046*795d594fSAndroid Build Coastguard Worker void WriteHeapPackets(pid_t parent_pid, uint64_t timestamp) {
1047*795d594fSAndroid Build Coastguard Worker JavaHprofDataSource::Trace(
1048*795d594fSAndroid Build Coastguard Worker [parent_pid, timestamp](JavaHprofDataSource::TraceContext ctx)
1049*795d594fSAndroid Build Coastguard Worker NO_THREAD_SAFETY_ANALYSIS {
1050*795d594fSAndroid Build Coastguard Worker bool dump_smaps;
1051*795d594fSAndroid Build Coastguard Worker std::vector<std::string> ignored_types;
1052*795d594fSAndroid Build Coastguard Worker {
1053*795d594fSAndroid Build Coastguard Worker auto ds = ctx.GetDataSourceLocked();
1054*795d594fSAndroid Build Coastguard Worker if (!ds || !ds->enabled()) {
1055*795d594fSAndroid Build Coastguard Worker if (ds) ds->Finish();
1056*795d594fSAndroid Build Coastguard Worker LOG(INFO) << "skipping irrelevant data source.";
1057*795d594fSAndroid Build Coastguard Worker return;
1058*795d594fSAndroid Build Coastguard Worker }
1059*795d594fSAndroid Build Coastguard Worker dump_smaps = ds->dump_smaps();
1060*795d594fSAndroid Build Coastguard Worker ignored_types = ds->ignored_types();
1061*795d594fSAndroid Build Coastguard Worker }
1062*795d594fSAndroid Build Coastguard Worker art::ScopedTrace trace("ART heap dump for " + std::to_string(parent_pid));
1063*795d594fSAndroid Build Coastguard Worker if (dump_smaps) {
1064*795d594fSAndroid Build Coastguard Worker DumpSmaps(&ctx);
1065*795d594fSAndroid Build Coastguard Worker }
1066*795d594fSAndroid Build Coastguard Worker Writer writer(parent_pid, &ctx, timestamp);
1067*795d594fSAndroid Build Coastguard Worker HeapGraphDumper dumper(ignored_types);
1068*795d594fSAndroid Build Coastguard Worker
1069*795d594fSAndroid Build Coastguard Worker dumper.Dump(art::Runtime::Current(), writer);
1070*795d594fSAndroid Build Coastguard Worker
1071*795d594fSAndroid Build Coastguard Worker writer.Finalize();
1072*795d594fSAndroid Build Coastguard Worker ctx.Flush([] {
1073*795d594fSAndroid Build Coastguard Worker art::MutexLock lk(JavaHprofDataSource::art_thread(), GetStateMutex());
1074*795d594fSAndroid Build Coastguard Worker g_state = State::kEnd;
1075*795d594fSAndroid Build Coastguard Worker GetStateCV().Broadcast(JavaHprofDataSource::art_thread());
1076*795d594fSAndroid Build Coastguard Worker });
1077*795d594fSAndroid Build Coastguard Worker // Wait for the Flush that will happen on the Perfetto thread.
1078*795d594fSAndroid Build Coastguard Worker {
1079*795d594fSAndroid Build Coastguard Worker art::MutexLock lk(JavaHprofDataSource::art_thread(), GetStateMutex());
1080*795d594fSAndroid Build Coastguard Worker while (g_state != State::kEnd) {
1081*795d594fSAndroid Build Coastguard Worker GetStateCV().Wait(JavaHprofDataSource::art_thread());
1082*795d594fSAndroid Build Coastguard Worker }
1083*795d594fSAndroid Build Coastguard Worker }
1084*795d594fSAndroid Build Coastguard Worker {
1085*795d594fSAndroid Build Coastguard Worker auto ds = ctx.GetDataSourceLocked();
1086*795d594fSAndroid Build Coastguard Worker if (ds) {
1087*795d594fSAndroid Build Coastguard Worker ds->Finish();
1088*795d594fSAndroid Build Coastguard Worker } else {
1089*795d594fSAndroid Build Coastguard Worker LOG(ERROR) << "datasource timed out (duration_ms + datasource_stop_timeout_ms) "
1090*795d594fSAndroid Build Coastguard Worker "before dump finished";
1091*795d594fSAndroid Build Coastguard Worker }
1092*795d594fSAndroid Build Coastguard Worker }
1093*795d594fSAndroid Build Coastguard Worker });
1094*795d594fSAndroid Build Coastguard Worker }
1095*795d594fSAndroid Build Coastguard Worker
DumpPerfetto(art::Thread * self)1096*795d594fSAndroid Build Coastguard Worker void DumpPerfetto(art::Thread* self) {
1097*795d594fSAndroid Build Coastguard Worker ForkAndRun(
1098*795d594fSAndroid Build Coastguard Worker self,
1099*795d594fSAndroid Build Coastguard Worker ResumeParentPolicy::IMMEDIATELY,
1100*795d594fSAndroid Build Coastguard Worker // parent thread
1101*795d594fSAndroid Build Coastguard Worker [](pid_t child) {
1102*795d594fSAndroid Build Coastguard Worker // Busy waiting here will introduce some extra latency, but that is okay because we have
1103*795d594fSAndroid Build Coastguard Worker // already unsuspended all other threads. This runs on the perfetto_hprof_listener, which
1104*795d594fSAndroid Build Coastguard Worker // is not needed for progress of the app itself.
1105*795d594fSAndroid Build Coastguard Worker // We daemonize the child process, so effectively we only need to wait
1106*795d594fSAndroid Build Coastguard Worker // for it to fork and exit.
1107*795d594fSAndroid Build Coastguard Worker BusyWaitpid(child, 1000);
1108*795d594fSAndroid Build Coastguard Worker },
1109*795d594fSAndroid Build Coastguard Worker // child thread
1110*795d594fSAndroid Build Coastguard Worker [self](pid_t dumped_pid, uint64_t timestamp) {
1111*795d594fSAndroid Build Coastguard Worker // Daemon creates a new process that is the grand-child of the original process, and exits.
1112*795d594fSAndroid Build Coastguard Worker if (daemon(0, 0) == -1) {
1113*795d594fSAndroid Build Coastguard Worker PLOG(FATAL) << "daemon";
1114*795d594fSAndroid Build Coastguard Worker }
1115*795d594fSAndroid Build Coastguard Worker // The following code is only executed by the grand-child of the original process.
1116*795d594fSAndroid Build Coastguard Worker
1117*795d594fSAndroid Build Coastguard Worker // Make sure that this is the first thing we do after forking, so if anything
1118*795d594fSAndroid Build Coastguard Worker // below hangs, the fork will go away from the watchdog.
1119*795d594fSAndroid Build Coastguard Worker ArmWatchdogOrDie();
1120*795d594fSAndroid Build Coastguard Worker SetupDataSource("android.java_hprof", false);
1121*795d594fSAndroid Build Coastguard Worker WaitForDataSource(self);
1122*795d594fSAndroid Build Coastguard Worker WriteHeapPackets(dumped_pid, timestamp);
1123*795d594fSAndroid Build Coastguard Worker LOG(INFO) << "finished dumping heap for " << dumped_pid;
1124*795d594fSAndroid Build Coastguard Worker });
1125*795d594fSAndroid Build Coastguard Worker }
1126*795d594fSAndroid Build Coastguard Worker
DumpPerfettoOutOfMemory()1127*795d594fSAndroid Build Coastguard Worker void DumpPerfettoOutOfMemory() REQUIRES_SHARED(art::Locks::mutator_lock_) {
1128*795d594fSAndroid Build Coastguard Worker art::Thread* self = art::Thread::Current();
1129*795d594fSAndroid Build Coastguard Worker if (!self) {
1130*795d594fSAndroid Build Coastguard Worker LOG(FATAL_WITHOUT_ABORT) << "no thread in DumpPerfettoOutOfMemory";
1131*795d594fSAndroid Build Coastguard Worker return;
1132*795d594fSAndroid Build Coastguard Worker }
1133*795d594fSAndroid Build Coastguard Worker
1134*795d594fSAndroid Build Coastguard Worker // Ensure that there is an active, armed tracing session
1135*795d594fSAndroid Build Coastguard Worker uint32_t session_cnt =
1136*795d594fSAndroid Build Coastguard Worker android::base::GetUintProperty<uint32_t>("traced.oome_heap_session.count", 0);
1137*795d594fSAndroid Build Coastguard Worker if (session_cnt == 0) {
1138*795d594fSAndroid Build Coastguard Worker return;
1139*795d594fSAndroid Build Coastguard Worker }
1140*795d594fSAndroid Build Coastguard Worker {
1141*795d594fSAndroid Build Coastguard Worker // OutOfMemoryErrors are reentrant, make sure we do not fork and process
1142*795d594fSAndroid Build Coastguard Worker // more than once.
1143*795d594fSAndroid Build Coastguard Worker art::MutexLock lk(self, GetStateMutex());
1144*795d594fSAndroid Build Coastguard Worker if (g_oome_triggered) {
1145*795d594fSAndroid Build Coastguard Worker return;
1146*795d594fSAndroid Build Coastguard Worker }
1147*795d594fSAndroid Build Coastguard Worker g_oome_triggered = true;
1148*795d594fSAndroid Build Coastguard Worker g_oome_sessions_pending = session_cnt;
1149*795d594fSAndroid Build Coastguard Worker }
1150*795d594fSAndroid Build Coastguard Worker
1151*795d594fSAndroid Build Coastguard Worker art::ScopedThreadSuspension sts(self, art::ThreadState::kSuspended);
1152*795d594fSAndroid Build Coastguard Worker // If we fork & resume the original process execution it will most likely exit
1153*795d594fSAndroid Build Coastguard Worker // ~immediately due to the OOME error thrown. When the system detects that
1154*795d594fSAndroid Build Coastguard Worker // that, it will cleanup by killing all processes in the cgroup (including
1155*795d594fSAndroid Build Coastguard Worker // the process we just forked).
1156*795d594fSAndroid Build Coastguard Worker // We need to avoid the race between the heap dump and the process group
1157*795d594fSAndroid Build Coastguard Worker // cleanup, and the only way to do this is to avoid resuming the original
1158*795d594fSAndroid Build Coastguard Worker // process until the heap dump is complete.
1159*795d594fSAndroid Build Coastguard Worker // Given we are already about to crash anyway, the diagnostic data we get
1160*795d594fSAndroid Build Coastguard Worker // outweighs the cost of introducing some latency.
1161*795d594fSAndroid Build Coastguard Worker ForkAndRun(
1162*795d594fSAndroid Build Coastguard Worker self,
1163*795d594fSAndroid Build Coastguard Worker ResumeParentPolicy::DEFERRED,
1164*795d594fSAndroid Build Coastguard Worker // parent process
1165*795d594fSAndroid Build Coastguard Worker [](pid_t child) {
1166*795d594fSAndroid Build Coastguard Worker // waitpid to reap the zombie
1167*795d594fSAndroid Build Coastguard Worker // we are explicitly waiting for the child to exit
1168*795d594fSAndroid Build Coastguard Worker // The reason for the timeout on top of the watchdog is that it is
1169*795d594fSAndroid Build Coastguard Worker // possible (albeit unlikely) that even the watchdog will fail to be
1170*795d594fSAndroid Build Coastguard Worker // activated in the case of an atfork handler.
1171*795d594fSAndroid Build Coastguard Worker BusyWaitpid(child, kWatchdogTimeoutSec * 1000);
1172*795d594fSAndroid Build Coastguard Worker },
1173*795d594fSAndroid Build Coastguard Worker // child process
1174*795d594fSAndroid Build Coastguard Worker [self](pid_t dumped_pid, uint64_t timestamp) {
1175*795d594fSAndroid Build Coastguard Worker ArmWatchdogOrDie();
1176*795d594fSAndroid Build Coastguard Worker art::SetThreadName("perfetto_oome_hprof");
1177*795d594fSAndroid Build Coastguard Worker art::ScopedTrace trace("perfetto_hprof oome");
1178*795d594fSAndroid Build Coastguard Worker SetupDataSource("android.java_hprof.oom", true);
1179*795d594fSAndroid Build Coastguard Worker perfetto::Tracing::ActivateTriggers({"com.android.telemetry.art-outofmemory"}, 500);
1180*795d594fSAndroid Build Coastguard Worker
1181*795d594fSAndroid Build Coastguard Worker // A pre-armed tracing session might not exist, so we should wait for a
1182*795d594fSAndroid Build Coastguard Worker // limited amount of time before we decide to let the execution continue.
1183*795d594fSAndroid Build Coastguard Worker if (!TimedWaitForDataSource(self, 1000)) {
1184*795d594fSAndroid Build Coastguard Worker LOG(INFO) << "OOME hprof timeout (state " << g_state << ")";
1185*795d594fSAndroid Build Coastguard Worker return;
1186*795d594fSAndroid Build Coastguard Worker }
1187*795d594fSAndroid Build Coastguard Worker WriteHeapPackets(dumped_pid, timestamp);
1188*795d594fSAndroid Build Coastguard Worker LOG(INFO) << "OOME hprof complete for " << dumped_pid;
1189*795d594fSAndroid Build Coastguard Worker });
1190*795d594fSAndroid Build Coastguard Worker }
1191*795d594fSAndroid Build Coastguard Worker
1192*795d594fSAndroid Build Coastguard Worker // The plugin initialization function.
ArtPlugin_Initialize()1193*795d594fSAndroid Build Coastguard Worker extern "C" bool ArtPlugin_Initialize() {
1194*795d594fSAndroid Build Coastguard Worker if (art::Runtime::Current() == nullptr) {
1195*795d594fSAndroid Build Coastguard Worker return false;
1196*795d594fSAndroid Build Coastguard Worker }
1197*795d594fSAndroid Build Coastguard Worker art::Thread* self = art::Thread::Current();
1198*795d594fSAndroid Build Coastguard Worker {
1199*795d594fSAndroid Build Coastguard Worker art::MutexLock lk(self, GetStateMutex());
1200*795d594fSAndroid Build Coastguard Worker if (g_state != State::kUninitialized) {
1201*795d594fSAndroid Build Coastguard Worker LOG(ERROR) << "perfetto_hprof already initialized. state: " << g_state;
1202*795d594fSAndroid Build Coastguard Worker return false;
1203*795d594fSAndroid Build Coastguard Worker }
1204*795d594fSAndroid Build Coastguard Worker g_state = State::kWaitForListener;
1205*795d594fSAndroid Build Coastguard Worker }
1206*795d594fSAndroid Build Coastguard Worker
1207*795d594fSAndroid Build Coastguard Worker if (pipe2(g_signal_pipe_fds, O_CLOEXEC) == -1) {
1208*795d594fSAndroid Build Coastguard Worker PLOG(ERROR) << "Failed to pipe";
1209*795d594fSAndroid Build Coastguard Worker return false;
1210*795d594fSAndroid Build Coastguard Worker }
1211*795d594fSAndroid Build Coastguard Worker
1212*795d594fSAndroid Build Coastguard Worker struct sigaction act = {};
1213*795d594fSAndroid Build Coastguard Worker act.sa_flags = SA_SIGINFO | SA_RESTART;
1214*795d594fSAndroid Build Coastguard Worker act.sa_sigaction = [](int, siginfo_t* si, void*) {
1215*795d594fSAndroid Build Coastguard Worker requested_tracing_session_id = si->si_value.sival_int;
1216*795d594fSAndroid Build Coastguard Worker if (write(g_signal_pipe_fds[1], kByte, sizeof(kByte)) == -1) {
1217*795d594fSAndroid Build Coastguard Worker PLOG(ERROR) << "Failed to trigger heap dump";
1218*795d594fSAndroid Build Coastguard Worker }
1219*795d594fSAndroid Build Coastguard Worker };
1220*795d594fSAndroid Build Coastguard Worker
1221*795d594fSAndroid Build Coastguard Worker // TODO(fmayer): We can probably use the SignalCatcher thread here to not
1222*795d594fSAndroid Build Coastguard Worker // have an idle thread.
1223*795d594fSAndroid Build Coastguard Worker if (sigaction(kJavaHeapprofdSignal, &act, &g_orig_act) != 0) {
1224*795d594fSAndroid Build Coastguard Worker close(g_signal_pipe_fds[0]);
1225*795d594fSAndroid Build Coastguard Worker close(g_signal_pipe_fds[1]);
1226*795d594fSAndroid Build Coastguard Worker PLOG(ERROR) << "Failed to sigaction";
1227*795d594fSAndroid Build Coastguard Worker return false;
1228*795d594fSAndroid Build Coastguard Worker }
1229*795d594fSAndroid Build Coastguard Worker
1230*795d594fSAndroid Build Coastguard Worker std::thread th([] {
1231*795d594fSAndroid Build Coastguard Worker art::Runtime* runtime = art::Runtime::Current();
1232*795d594fSAndroid Build Coastguard Worker if (!runtime) {
1233*795d594fSAndroid Build Coastguard Worker LOG(FATAL_WITHOUT_ABORT) << "no runtime in perfetto_hprof_listener";
1234*795d594fSAndroid Build Coastguard Worker return;
1235*795d594fSAndroid Build Coastguard Worker }
1236*795d594fSAndroid Build Coastguard Worker if (!runtime->AttachCurrentThread("perfetto_hprof_listener", /*as_daemon=*/ true,
1237*795d594fSAndroid Build Coastguard Worker runtime->GetSystemThreadGroup(), /*create_peer=*/ false)) {
1238*795d594fSAndroid Build Coastguard Worker LOG(ERROR) << "failed to attach thread.";
1239*795d594fSAndroid Build Coastguard Worker {
1240*795d594fSAndroid Build Coastguard Worker art::MutexLock lk(nullptr, GetStateMutex());
1241*795d594fSAndroid Build Coastguard Worker g_state = State::kUninitialized;
1242*795d594fSAndroid Build Coastguard Worker GetStateCV().Broadcast(nullptr);
1243*795d594fSAndroid Build Coastguard Worker }
1244*795d594fSAndroid Build Coastguard Worker
1245*795d594fSAndroid Build Coastguard Worker return;
1246*795d594fSAndroid Build Coastguard Worker }
1247*795d594fSAndroid Build Coastguard Worker art::Thread* self = art::Thread::Current();
1248*795d594fSAndroid Build Coastguard Worker if (!self) {
1249*795d594fSAndroid Build Coastguard Worker LOG(FATAL_WITHOUT_ABORT) << "no thread in perfetto_hprof_listener";
1250*795d594fSAndroid Build Coastguard Worker return;
1251*795d594fSAndroid Build Coastguard Worker }
1252*795d594fSAndroid Build Coastguard Worker {
1253*795d594fSAndroid Build Coastguard Worker art::MutexLock lk(self, GetStateMutex());
1254*795d594fSAndroid Build Coastguard Worker if (g_state == State::kWaitForListener) {
1255*795d594fSAndroid Build Coastguard Worker g_state = State::kWaitForStart;
1256*795d594fSAndroid Build Coastguard Worker GetStateCV().Broadcast(self);
1257*795d594fSAndroid Build Coastguard Worker }
1258*795d594fSAndroid Build Coastguard Worker }
1259*795d594fSAndroid Build Coastguard Worker char buf[1];
1260*795d594fSAndroid Build Coastguard Worker for (;;) {
1261*795d594fSAndroid Build Coastguard Worker int res;
1262*795d594fSAndroid Build Coastguard Worker do {
1263*795d594fSAndroid Build Coastguard Worker res = read(g_signal_pipe_fds[0], buf, sizeof(buf));
1264*795d594fSAndroid Build Coastguard Worker } while (res == -1 && errno == EINTR);
1265*795d594fSAndroid Build Coastguard Worker
1266*795d594fSAndroid Build Coastguard Worker if (res <= 0) {
1267*795d594fSAndroid Build Coastguard Worker if (res == -1) {
1268*795d594fSAndroid Build Coastguard Worker PLOG(ERROR) << "failed to read";
1269*795d594fSAndroid Build Coastguard Worker }
1270*795d594fSAndroid Build Coastguard Worker close(g_signal_pipe_fds[0]);
1271*795d594fSAndroid Build Coastguard Worker return;
1272*795d594fSAndroid Build Coastguard Worker }
1273*795d594fSAndroid Build Coastguard Worker
1274*795d594fSAndroid Build Coastguard Worker perfetto_hprof::DumpPerfetto(self);
1275*795d594fSAndroid Build Coastguard Worker }
1276*795d594fSAndroid Build Coastguard Worker });
1277*795d594fSAndroid Build Coastguard Worker th.detach();
1278*795d594fSAndroid Build Coastguard Worker
1279*795d594fSAndroid Build Coastguard Worker // Register the OOM error handler.
1280*795d594fSAndroid Build Coastguard Worker art::Runtime::Current()->SetOutOfMemoryErrorHook(perfetto_hprof::DumpPerfettoOutOfMemory);
1281*795d594fSAndroid Build Coastguard Worker
1282*795d594fSAndroid Build Coastguard Worker return true;
1283*795d594fSAndroid Build Coastguard Worker }
1284*795d594fSAndroid Build Coastguard Worker
ArtPlugin_Deinitialize()1285*795d594fSAndroid Build Coastguard Worker extern "C" bool ArtPlugin_Deinitialize() {
1286*795d594fSAndroid Build Coastguard Worker art::Runtime::Current()->SetOutOfMemoryErrorHook(nullptr);
1287*795d594fSAndroid Build Coastguard Worker
1288*795d594fSAndroid Build Coastguard Worker if (sigaction(kJavaHeapprofdSignal, &g_orig_act, nullptr) != 0) {
1289*795d594fSAndroid Build Coastguard Worker PLOG(ERROR) << "failed to reset signal handler";
1290*795d594fSAndroid Build Coastguard Worker // We cannot close the pipe if the signal handler wasn't unregistered,
1291*795d594fSAndroid Build Coastguard Worker // to avoid receiving SIGPIPE.
1292*795d594fSAndroid Build Coastguard Worker return false;
1293*795d594fSAndroid Build Coastguard Worker }
1294*795d594fSAndroid Build Coastguard Worker close(g_signal_pipe_fds[1]);
1295*795d594fSAndroid Build Coastguard Worker
1296*795d594fSAndroid Build Coastguard Worker art::Thread* self = art::Thread::Current();
1297*795d594fSAndroid Build Coastguard Worker art::MutexLock lk(self, GetStateMutex());
1298*795d594fSAndroid Build Coastguard Worker // Wait until after the thread was registered to the runtime. This is so
1299*795d594fSAndroid Build Coastguard Worker // we do not attempt to register it with the runtime after it had been torn
1300*795d594fSAndroid Build Coastguard Worker // down (ArtPlugin_Deinitialize gets called in the Runtime dtor).
1301*795d594fSAndroid Build Coastguard Worker while (g_state == State::kWaitForListener) {
1302*795d594fSAndroid Build Coastguard Worker GetStateCV().Wait(art::Thread::Current());
1303*795d594fSAndroid Build Coastguard Worker }
1304*795d594fSAndroid Build Coastguard Worker g_state = State::kUninitialized;
1305*795d594fSAndroid Build Coastguard Worker GetStateCV().Broadcast(self);
1306*795d594fSAndroid Build Coastguard Worker return true;
1307*795d594fSAndroid Build Coastguard Worker }
1308*795d594fSAndroid Build Coastguard Worker
1309*795d594fSAndroid Build Coastguard Worker } // namespace perfetto_hprof
1310*795d594fSAndroid Build Coastguard Worker
1311*795d594fSAndroid Build Coastguard Worker namespace perfetto {
1312*795d594fSAndroid Build Coastguard Worker
1313*795d594fSAndroid Build Coastguard Worker PERFETTO_DEFINE_DATA_SOURCE_STATIC_MEMBERS(perfetto_hprof::JavaHprofDataSource);
1314*795d594fSAndroid Build Coastguard Worker
1315*795d594fSAndroid Build Coastguard Worker }
1316