1*6dbdd20aSAndroid Build Coastguard Worker /*
2*6dbdd20aSAndroid Build Coastguard Worker * Copyright (C) 2018 The Android Open Source Project
3*6dbdd20aSAndroid Build Coastguard Worker *
4*6dbdd20aSAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License");
5*6dbdd20aSAndroid Build Coastguard Worker * you may not use this file except in compliance with the License.
6*6dbdd20aSAndroid Build Coastguard Worker * You may obtain a copy of the License at
7*6dbdd20aSAndroid Build Coastguard Worker *
8*6dbdd20aSAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0
9*6dbdd20aSAndroid Build Coastguard Worker *
10*6dbdd20aSAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software
11*6dbdd20aSAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS,
12*6dbdd20aSAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*6dbdd20aSAndroid Build Coastguard Worker * See the License for the specific language governing permissions and
14*6dbdd20aSAndroid Build Coastguard Worker * limitations under the License.
15*6dbdd20aSAndroid Build Coastguard Worker */
16*6dbdd20aSAndroid Build Coastguard Worker
17*6dbdd20aSAndroid Build Coastguard Worker #include "src/profiling/memory/client.h"
18*6dbdd20aSAndroid Build Coastguard Worker
19*6dbdd20aSAndroid Build Coastguard Worker #include <signal.h>
20*6dbdd20aSAndroid Build Coastguard Worker #include <sys/prctl.h>
21*6dbdd20aSAndroid Build Coastguard Worker #include <sys/syscall.h>
22*6dbdd20aSAndroid Build Coastguard Worker #include <sys/types.h>
23*6dbdd20aSAndroid Build Coastguard Worker #include <unistd.h>
24*6dbdd20aSAndroid Build Coastguard Worker
25*6dbdd20aSAndroid Build Coastguard Worker #include <algorithm>
26*6dbdd20aSAndroid Build Coastguard Worker #include <atomic>
27*6dbdd20aSAndroid Build Coastguard Worker #include <cinttypes>
28*6dbdd20aSAndroid Build Coastguard Worker #include <new>
29*6dbdd20aSAndroid Build Coastguard Worker
30*6dbdd20aSAndroid Build Coastguard Worker #include <unwindstack/Regs.h>
31*6dbdd20aSAndroid Build Coastguard Worker #include <unwindstack/RegsGetLocal.h>
32*6dbdd20aSAndroid Build Coastguard Worker
33*6dbdd20aSAndroid Build Coastguard Worker #include "perfetto/base/build_config.h"
34*6dbdd20aSAndroid Build Coastguard Worker #include "perfetto/base/compiler.h"
35*6dbdd20aSAndroid Build Coastguard Worker #include "perfetto/base/logging.h"
36*6dbdd20aSAndroid Build Coastguard Worker #include "perfetto/base/thread_utils.h"
37*6dbdd20aSAndroid Build Coastguard Worker #include "perfetto/base/time.h"
38*6dbdd20aSAndroid Build Coastguard Worker #include "perfetto/ext/base/file_utils.h"
39*6dbdd20aSAndroid Build Coastguard Worker #include "perfetto/ext/base/scoped_file.h"
40*6dbdd20aSAndroid Build Coastguard Worker #include "perfetto/ext/base/string_utils.h"
41*6dbdd20aSAndroid Build Coastguard Worker #include "perfetto/ext/base/unix_socket.h"
42*6dbdd20aSAndroid Build Coastguard Worker #include "perfetto/ext/base/utils.h"
43*6dbdd20aSAndroid Build Coastguard Worker #include "src/profiling/memory/sampler.h"
44*6dbdd20aSAndroid Build Coastguard Worker #include "src/profiling/memory/scoped_spinlock.h"
45*6dbdd20aSAndroid Build Coastguard Worker #include "src/profiling/memory/shared_ring_buffer.h"
46*6dbdd20aSAndroid Build Coastguard Worker #include "src/profiling/memory/wire_protocol.h"
47*6dbdd20aSAndroid Build Coastguard Worker
48*6dbdd20aSAndroid Build Coastguard Worker namespace perfetto {
49*6dbdd20aSAndroid Build Coastguard Worker namespace profiling {
50*6dbdd20aSAndroid Build Coastguard Worker namespace {
51*6dbdd20aSAndroid Build Coastguard Worker
52*6dbdd20aSAndroid Build Coastguard Worker const char kSingleByte[1] = {'x'};
53*6dbdd20aSAndroid Build Coastguard Worker constexpr auto kResendBackoffUs = 100;
54*6dbdd20aSAndroid Build Coastguard Worker
IsMainThread()55*6dbdd20aSAndroid Build Coastguard Worker inline bool IsMainThread() {
56*6dbdd20aSAndroid Build Coastguard Worker return getpid() == base::GetThreadId();
57*6dbdd20aSAndroid Build Coastguard Worker }
58*6dbdd20aSAndroid Build Coastguard Worker
UnsetDumpable(int)59*6dbdd20aSAndroid Build Coastguard Worker int UnsetDumpable(int) {
60*6dbdd20aSAndroid Build Coastguard Worker prctl(PR_SET_DUMPABLE, 0);
61*6dbdd20aSAndroid Build Coastguard Worker return 0;
62*6dbdd20aSAndroid Build Coastguard Worker }
63*6dbdd20aSAndroid Build Coastguard Worker
Contained(const StackRange & base,const char * ptr)64*6dbdd20aSAndroid Build Coastguard Worker bool Contained(const StackRange& base, const char* ptr) {
65*6dbdd20aSAndroid Build Coastguard Worker return (ptr >= base.begin && ptr < base.end);
66*6dbdd20aSAndroid Build Coastguard Worker }
67*6dbdd20aSAndroid Build Coastguard Worker
68*6dbdd20aSAndroid Build Coastguard Worker } // namespace
69*6dbdd20aSAndroid Build Coastguard Worker
GetMaxTries(const ClientConfiguration & client_config)70*6dbdd20aSAndroid Build Coastguard Worker uint64_t GetMaxTries(const ClientConfiguration& client_config) {
71*6dbdd20aSAndroid Build Coastguard Worker if (!client_config.block_client)
72*6dbdd20aSAndroid Build Coastguard Worker return 1u;
73*6dbdd20aSAndroid Build Coastguard Worker if (client_config.block_client_timeout_us == 0)
74*6dbdd20aSAndroid Build Coastguard Worker return kInfiniteTries;
75*6dbdd20aSAndroid Build Coastguard Worker return std::max<uint64_t>(
76*6dbdd20aSAndroid Build Coastguard Worker 1ul, client_config.block_client_timeout_us / kResendBackoffUs);
77*6dbdd20aSAndroid Build Coastguard Worker }
78*6dbdd20aSAndroid Build Coastguard Worker
GetThreadStackRange()79*6dbdd20aSAndroid Build Coastguard Worker StackRange GetThreadStackRange() {
80*6dbdd20aSAndroid Build Coastguard Worker // In glibc pthread_getattr_np can call realloc, even for a non-main-thread.
81*6dbdd20aSAndroid Build Coastguard Worker // This is fine, because the heapprofd wrapper for glibc prevents re-entering
82*6dbdd20aSAndroid Build Coastguard Worker // malloc.
83*6dbdd20aSAndroid Build Coastguard Worker pthread_attr_t attr;
84*6dbdd20aSAndroid Build Coastguard Worker if (pthread_getattr_np(pthread_self(), &attr) != 0)
85*6dbdd20aSAndroid Build Coastguard Worker return {nullptr, nullptr};
86*6dbdd20aSAndroid Build Coastguard Worker base::ScopedResource<pthread_attr_t*, pthread_attr_destroy, nullptr> cleanup(
87*6dbdd20aSAndroid Build Coastguard Worker &attr);
88*6dbdd20aSAndroid Build Coastguard Worker
89*6dbdd20aSAndroid Build Coastguard Worker char* stackaddr;
90*6dbdd20aSAndroid Build Coastguard Worker size_t stacksize;
91*6dbdd20aSAndroid Build Coastguard Worker if (pthread_attr_getstack(&attr, reinterpret_cast<void**>(&stackaddr),
92*6dbdd20aSAndroid Build Coastguard Worker &stacksize) != 0)
93*6dbdd20aSAndroid Build Coastguard Worker return {nullptr, nullptr};
94*6dbdd20aSAndroid Build Coastguard Worker return {stackaddr, stackaddr + stacksize};
95*6dbdd20aSAndroid Build Coastguard Worker }
96*6dbdd20aSAndroid Build Coastguard Worker
GetSigAltStackRange()97*6dbdd20aSAndroid Build Coastguard Worker StackRange GetSigAltStackRange() {
98*6dbdd20aSAndroid Build Coastguard Worker stack_t altstack;
99*6dbdd20aSAndroid Build Coastguard Worker
100*6dbdd20aSAndroid Build Coastguard Worker if (sigaltstack(nullptr, &altstack) == -1) {
101*6dbdd20aSAndroid Build Coastguard Worker PERFETTO_PLOG("sigaltstack");
102*6dbdd20aSAndroid Build Coastguard Worker return {nullptr, nullptr};
103*6dbdd20aSAndroid Build Coastguard Worker }
104*6dbdd20aSAndroid Build Coastguard Worker
105*6dbdd20aSAndroid Build Coastguard Worker if ((altstack.ss_flags & SS_ONSTACK) == 0) {
106*6dbdd20aSAndroid Build Coastguard Worker return {nullptr, nullptr};
107*6dbdd20aSAndroid Build Coastguard Worker }
108*6dbdd20aSAndroid Build Coastguard Worker
109*6dbdd20aSAndroid Build Coastguard Worker return {static_cast<char*>(altstack.ss_sp),
110*6dbdd20aSAndroid Build Coastguard Worker static_cast<char*>(altstack.ss_sp) + altstack.ss_size};
111*6dbdd20aSAndroid Build Coastguard Worker }
112*6dbdd20aSAndroid Build Coastguard Worker
113*6dbdd20aSAndroid Build Coastguard Worker // The implementation of pthread_getattr_np for the main thread on bionic uses
114*6dbdd20aSAndroid Build Coastguard Worker // malloc, so we cannot use it in GetStackEnd, which we use inside of
115*6dbdd20aSAndroid Build Coastguard Worker // RecordMalloc (which is called from malloc). We would re-enter malloc if we
116*6dbdd20aSAndroid Build Coastguard Worker // used it.
117*6dbdd20aSAndroid Build Coastguard Worker //
118*6dbdd20aSAndroid Build Coastguard Worker // This is why we find the stack base for the main-thread when constructing
119*6dbdd20aSAndroid Build Coastguard Worker // the client and remember it.
GetMainThreadStackRange()120*6dbdd20aSAndroid Build Coastguard Worker StackRange GetMainThreadStackRange() {
121*6dbdd20aSAndroid Build Coastguard Worker base::ScopedFstream maps(fopen("/proc/self/maps", "re"));
122*6dbdd20aSAndroid Build Coastguard Worker if (!maps) {
123*6dbdd20aSAndroid Build Coastguard Worker return {nullptr, nullptr};
124*6dbdd20aSAndroid Build Coastguard Worker }
125*6dbdd20aSAndroid Build Coastguard Worker while (!feof(*maps)) {
126*6dbdd20aSAndroid Build Coastguard Worker char line[1024];
127*6dbdd20aSAndroid Build Coastguard Worker char* data = fgets(line, sizeof(line), *maps);
128*6dbdd20aSAndroid Build Coastguard Worker if (data != nullptr && strstr(data, "[stack]")) {
129*6dbdd20aSAndroid Build Coastguard Worker char* sep = strstr(data, "-");
130*6dbdd20aSAndroid Build Coastguard Worker if (sep == nullptr)
131*6dbdd20aSAndroid Build Coastguard Worker continue;
132*6dbdd20aSAndroid Build Coastguard Worker
133*6dbdd20aSAndroid Build Coastguard Worker char* min = reinterpret_cast<char*>(strtoll(data, nullptr, 16));
134*6dbdd20aSAndroid Build Coastguard Worker char* max = reinterpret_cast<char*>(strtoll(sep + 1, nullptr, 16));
135*6dbdd20aSAndroid Build Coastguard Worker return {min, max};
136*6dbdd20aSAndroid Build Coastguard Worker }
137*6dbdd20aSAndroid Build Coastguard Worker }
138*6dbdd20aSAndroid Build Coastguard Worker return {nullptr, nullptr};
139*6dbdd20aSAndroid Build Coastguard Worker }
140*6dbdd20aSAndroid Build Coastguard Worker
141*6dbdd20aSAndroid Build Coastguard Worker // static
ConnectToHeapprofd(const std::string & sock_name)142*6dbdd20aSAndroid Build Coastguard Worker std::optional<base::UnixSocketRaw> Client::ConnectToHeapprofd(
143*6dbdd20aSAndroid Build Coastguard Worker const std::string& sock_name) {
144*6dbdd20aSAndroid Build Coastguard Worker auto sock = base::UnixSocketRaw::CreateMayFail(base::SockFamily::kUnix,
145*6dbdd20aSAndroid Build Coastguard Worker base::SockType::kStream);
146*6dbdd20aSAndroid Build Coastguard Worker if (!sock || !sock.Connect(sock_name)) {
147*6dbdd20aSAndroid Build Coastguard Worker PERFETTO_PLOG("Failed to connect to %s", sock_name.c_str());
148*6dbdd20aSAndroid Build Coastguard Worker return std::nullopt;
149*6dbdd20aSAndroid Build Coastguard Worker }
150*6dbdd20aSAndroid Build Coastguard Worker if (!sock.SetTxTimeout(kClientSockTimeoutMs)) {
151*6dbdd20aSAndroid Build Coastguard Worker PERFETTO_PLOG("Failed to set send timeout for %s", sock_name.c_str());
152*6dbdd20aSAndroid Build Coastguard Worker return std::nullopt;
153*6dbdd20aSAndroid Build Coastguard Worker }
154*6dbdd20aSAndroid Build Coastguard Worker if (!sock.SetRxTimeout(kClientSockTimeoutMs)) {
155*6dbdd20aSAndroid Build Coastguard Worker PERFETTO_PLOG("Failed to set receive timeout for %s", sock_name.c_str());
156*6dbdd20aSAndroid Build Coastguard Worker return std::nullopt;
157*6dbdd20aSAndroid Build Coastguard Worker }
158*6dbdd20aSAndroid Build Coastguard Worker return std::move(sock);
159*6dbdd20aSAndroid Build Coastguard Worker }
160*6dbdd20aSAndroid Build Coastguard Worker
161*6dbdd20aSAndroid Build Coastguard Worker // static
CreateAndHandshake(base::UnixSocketRaw sock,UnhookedAllocator<Client> unhooked_allocator)162*6dbdd20aSAndroid Build Coastguard Worker std::shared_ptr<Client> Client::CreateAndHandshake(
163*6dbdd20aSAndroid Build Coastguard Worker base::UnixSocketRaw sock,
164*6dbdd20aSAndroid Build Coastguard Worker UnhookedAllocator<Client> unhooked_allocator) {
165*6dbdd20aSAndroid Build Coastguard Worker if (!sock) {
166*6dbdd20aSAndroid Build Coastguard Worker PERFETTO_DFATAL_OR_ELOG("Socket not connected.");
167*6dbdd20aSAndroid Build Coastguard Worker return nullptr;
168*6dbdd20aSAndroid Build Coastguard Worker }
169*6dbdd20aSAndroid Build Coastguard Worker
170*6dbdd20aSAndroid Build Coastguard Worker sock.DcheckIsBlocking(true);
171*6dbdd20aSAndroid Build Coastguard Worker
172*6dbdd20aSAndroid Build Coastguard Worker // We might be running in a process that is not dumpable (such as app
173*6dbdd20aSAndroid Build Coastguard Worker // processes on user builds), in which case the /proc/self/mem will be chown'd
174*6dbdd20aSAndroid Build Coastguard Worker // to root:root, and will not be accessible even to the process itself (see
175*6dbdd20aSAndroid Build Coastguard Worker // man 5 proc). In such situations, temporarily mark the process dumpable to
176*6dbdd20aSAndroid Build Coastguard Worker // be able to open the files, unsetting dumpability immediately afterwards.
177*6dbdd20aSAndroid Build Coastguard Worker int orig_dumpable = prctl(PR_GET_DUMPABLE);
178*6dbdd20aSAndroid Build Coastguard Worker
179*6dbdd20aSAndroid Build Coastguard Worker enum { kNop, kDoUnset };
180*6dbdd20aSAndroid Build Coastguard Worker base::ScopedResource<int, UnsetDumpable, kNop, false> unset_dumpable(kNop);
181*6dbdd20aSAndroid Build Coastguard Worker if (orig_dumpable == 0) {
182*6dbdd20aSAndroid Build Coastguard Worker unset_dumpable.reset(kDoUnset);
183*6dbdd20aSAndroid Build Coastguard Worker prctl(PR_SET_DUMPABLE, 1);
184*6dbdd20aSAndroid Build Coastguard Worker }
185*6dbdd20aSAndroid Build Coastguard Worker
186*6dbdd20aSAndroid Build Coastguard Worker base::ScopedFile maps(base::OpenFile("/proc/self/maps", O_RDONLY));
187*6dbdd20aSAndroid Build Coastguard Worker if (!maps) {
188*6dbdd20aSAndroid Build Coastguard Worker PERFETTO_DFATAL_OR_ELOG("Failed to open /proc/self/maps");
189*6dbdd20aSAndroid Build Coastguard Worker return nullptr;
190*6dbdd20aSAndroid Build Coastguard Worker }
191*6dbdd20aSAndroid Build Coastguard Worker base::ScopedFile mem(base::OpenFile("/proc/self/mem", O_RDONLY));
192*6dbdd20aSAndroid Build Coastguard Worker if (!mem) {
193*6dbdd20aSAndroid Build Coastguard Worker PERFETTO_DFATAL_OR_ELOG("Failed to open /proc/self/mem");
194*6dbdd20aSAndroid Build Coastguard Worker return nullptr;
195*6dbdd20aSAndroid Build Coastguard Worker }
196*6dbdd20aSAndroid Build Coastguard Worker
197*6dbdd20aSAndroid Build Coastguard Worker // Restore original dumpability value if we overrode it.
198*6dbdd20aSAndroid Build Coastguard Worker unset_dumpable.reset();
199*6dbdd20aSAndroid Build Coastguard Worker
200*6dbdd20aSAndroid Build Coastguard Worker int fds[kHandshakeSize];
201*6dbdd20aSAndroid Build Coastguard Worker fds[kHandshakeMaps] = *maps;
202*6dbdd20aSAndroid Build Coastguard Worker fds[kHandshakeMem] = *mem;
203*6dbdd20aSAndroid Build Coastguard Worker
204*6dbdd20aSAndroid Build Coastguard Worker // Send an empty record to transfer fds for /proc/self/maps and
205*6dbdd20aSAndroid Build Coastguard Worker // /proc/self/mem.
206*6dbdd20aSAndroid Build Coastguard Worker if (sock.Send(kSingleByte, sizeof(kSingleByte), fds, kHandshakeSize) !=
207*6dbdd20aSAndroid Build Coastguard Worker sizeof(kSingleByte)) {
208*6dbdd20aSAndroid Build Coastguard Worker PERFETTO_DFATAL_OR_ELOG("Failed to send file descriptors.");
209*6dbdd20aSAndroid Build Coastguard Worker return nullptr;
210*6dbdd20aSAndroid Build Coastguard Worker }
211*6dbdd20aSAndroid Build Coastguard Worker
212*6dbdd20aSAndroid Build Coastguard Worker ClientConfiguration client_config;
213*6dbdd20aSAndroid Build Coastguard Worker base::ScopedFile shmem_fd;
214*6dbdd20aSAndroid Build Coastguard Worker size_t recv = 0;
215*6dbdd20aSAndroid Build Coastguard Worker while (recv < sizeof(client_config)) {
216*6dbdd20aSAndroid Build Coastguard Worker size_t num_fds = 0;
217*6dbdd20aSAndroid Build Coastguard Worker base::ScopedFile* fd = nullptr;
218*6dbdd20aSAndroid Build Coastguard Worker if (!shmem_fd) {
219*6dbdd20aSAndroid Build Coastguard Worker num_fds = 1;
220*6dbdd20aSAndroid Build Coastguard Worker fd = &shmem_fd;
221*6dbdd20aSAndroid Build Coastguard Worker }
222*6dbdd20aSAndroid Build Coastguard Worker ssize_t rd = sock.Receive(reinterpret_cast<char*>(&client_config) + recv,
223*6dbdd20aSAndroid Build Coastguard Worker sizeof(client_config) - recv, fd, num_fds);
224*6dbdd20aSAndroid Build Coastguard Worker if (rd == -1) {
225*6dbdd20aSAndroid Build Coastguard Worker PERFETTO_PLOG("Failed to receive ClientConfiguration.");
226*6dbdd20aSAndroid Build Coastguard Worker return nullptr;
227*6dbdd20aSAndroid Build Coastguard Worker }
228*6dbdd20aSAndroid Build Coastguard Worker if (rd == 0) {
229*6dbdd20aSAndroid Build Coastguard Worker PERFETTO_LOG("Server disconnected while sending ClientConfiguration.");
230*6dbdd20aSAndroid Build Coastguard Worker return nullptr;
231*6dbdd20aSAndroid Build Coastguard Worker }
232*6dbdd20aSAndroid Build Coastguard Worker recv += static_cast<size_t>(rd);
233*6dbdd20aSAndroid Build Coastguard Worker }
234*6dbdd20aSAndroid Build Coastguard Worker
235*6dbdd20aSAndroid Build Coastguard Worker if (!shmem_fd) {
236*6dbdd20aSAndroid Build Coastguard Worker PERFETTO_DFATAL_OR_ELOG("Did not receive shmem fd.");
237*6dbdd20aSAndroid Build Coastguard Worker return nullptr;
238*6dbdd20aSAndroid Build Coastguard Worker }
239*6dbdd20aSAndroid Build Coastguard Worker
240*6dbdd20aSAndroid Build Coastguard Worker auto shmem = SharedRingBuffer::Attach(std::move(shmem_fd));
241*6dbdd20aSAndroid Build Coastguard Worker if (!shmem || !shmem->is_valid()) {
242*6dbdd20aSAndroid Build Coastguard Worker PERFETTO_DFATAL_OR_ELOG("Failed to attach to shmem.");
243*6dbdd20aSAndroid Build Coastguard Worker return nullptr;
244*6dbdd20aSAndroid Build Coastguard Worker }
245*6dbdd20aSAndroid Build Coastguard Worker
246*6dbdd20aSAndroid Build Coastguard Worker sock.SetBlocking(false);
247*6dbdd20aSAndroid Build Coastguard Worker // note: the shared_ptr will retain a copy of the unhooked_allocator
248*6dbdd20aSAndroid Build Coastguard Worker return std::allocate_shared<Client>(unhooked_allocator, std::move(sock),
249*6dbdd20aSAndroid Build Coastguard Worker client_config, std::move(shmem.value()),
250*6dbdd20aSAndroid Build Coastguard Worker getpid(), GetMainThreadStackRange());
251*6dbdd20aSAndroid Build Coastguard Worker }
252*6dbdd20aSAndroid Build Coastguard Worker
Client(base::UnixSocketRaw sock,ClientConfiguration client_config,SharedRingBuffer shmem,pid_t pid_at_creation,StackRange main_thread_stack_range)253*6dbdd20aSAndroid Build Coastguard Worker Client::Client(base::UnixSocketRaw sock,
254*6dbdd20aSAndroid Build Coastguard Worker ClientConfiguration client_config,
255*6dbdd20aSAndroid Build Coastguard Worker SharedRingBuffer shmem,
256*6dbdd20aSAndroid Build Coastguard Worker pid_t pid_at_creation,
257*6dbdd20aSAndroid Build Coastguard Worker StackRange main_thread_stack_range)
258*6dbdd20aSAndroid Build Coastguard Worker : client_config_(client_config),
259*6dbdd20aSAndroid Build Coastguard Worker max_shmem_tries_(GetMaxTries(client_config_)),
260*6dbdd20aSAndroid Build Coastguard Worker sock_(std::move(sock)),
261*6dbdd20aSAndroid Build Coastguard Worker main_thread_stack_range_(main_thread_stack_range),
262*6dbdd20aSAndroid Build Coastguard Worker shmem_(std::move(shmem)),
263*6dbdd20aSAndroid Build Coastguard Worker pid_at_creation_(pid_at_creation) {}
264*6dbdd20aSAndroid Build Coastguard Worker
~Client()265*6dbdd20aSAndroid Build Coastguard Worker Client::~Client() {
266*6dbdd20aSAndroid Build Coastguard Worker // This is work-around for code like the following:
267*6dbdd20aSAndroid Build Coastguard Worker // https://android.googlesource.com/platform/libcore/+/4ecb71f94378716f88703b9f7548b5d24839262f/ojluni/src/main/native/UNIXProcess_md.c#427
268*6dbdd20aSAndroid Build Coastguard Worker // They fork, close all fds by iterating over /proc/self/fd using opendir.
269*6dbdd20aSAndroid Build Coastguard Worker // Unfortunately closedir calls free, which detects the fork, and then tries
270*6dbdd20aSAndroid Build Coastguard Worker // to destruct this Client.
271*6dbdd20aSAndroid Build Coastguard Worker //
272*6dbdd20aSAndroid Build Coastguard Worker // ScopedResource crashes on failure to close, so we explicitly ignore
273*6dbdd20aSAndroid Build Coastguard Worker // failures here.
274*6dbdd20aSAndroid Build Coastguard Worker int fd = sock_.ReleaseFd().release();
275*6dbdd20aSAndroid Build Coastguard Worker if (fd != -1)
276*6dbdd20aSAndroid Build Coastguard Worker close(fd);
277*6dbdd20aSAndroid Build Coastguard Worker }
278*6dbdd20aSAndroid Build Coastguard Worker
GetStackEnd(const char * stackptr)279*6dbdd20aSAndroid Build Coastguard Worker const char* Client::GetStackEnd(const char* stackptr) {
280*6dbdd20aSAndroid Build Coastguard Worker StackRange thread_stack_range;
281*6dbdd20aSAndroid Build Coastguard Worker bool is_main_thread = IsMainThread();
282*6dbdd20aSAndroid Build Coastguard Worker if (is_main_thread) {
283*6dbdd20aSAndroid Build Coastguard Worker thread_stack_range = main_thread_stack_range_;
284*6dbdd20aSAndroid Build Coastguard Worker } else {
285*6dbdd20aSAndroid Build Coastguard Worker thread_stack_range = GetThreadStackRange();
286*6dbdd20aSAndroid Build Coastguard Worker }
287*6dbdd20aSAndroid Build Coastguard Worker if (Contained(thread_stack_range, stackptr)) {
288*6dbdd20aSAndroid Build Coastguard Worker return thread_stack_range.end;
289*6dbdd20aSAndroid Build Coastguard Worker }
290*6dbdd20aSAndroid Build Coastguard Worker StackRange sigalt_stack_range = GetSigAltStackRange();
291*6dbdd20aSAndroid Build Coastguard Worker if (Contained(sigalt_stack_range, stackptr)) {
292*6dbdd20aSAndroid Build Coastguard Worker return sigalt_stack_range.end;
293*6dbdd20aSAndroid Build Coastguard Worker }
294*6dbdd20aSAndroid Build Coastguard Worker // The main thread might have expanded since we read its bounds. We now know
295*6dbdd20aSAndroid Build Coastguard Worker // it is not the sigaltstack, so it has to be the main stack.
296*6dbdd20aSAndroid Build Coastguard Worker // TODO(fmayer): We should reparse maps here, because now we will keep
297*6dbdd20aSAndroid Build Coastguard Worker // hitting the slow-path that calls the sigaltstack syscall.
298*6dbdd20aSAndroid Build Coastguard Worker if (is_main_thread && stackptr < thread_stack_range.end) {
299*6dbdd20aSAndroid Build Coastguard Worker return thread_stack_range.end;
300*6dbdd20aSAndroid Build Coastguard Worker }
301*6dbdd20aSAndroid Build Coastguard Worker return nullptr;
302*6dbdd20aSAndroid Build Coastguard Worker }
303*6dbdd20aSAndroid Build Coastguard Worker
304*6dbdd20aSAndroid Build Coastguard Worker // Best-effort detection of whether we're continuing work in a forked child of
305*6dbdd20aSAndroid Build Coastguard Worker // the profiled process, in which case we want to stop. Note that due to
306*6dbdd20aSAndroid Build Coastguard Worker // malloc_hooks.cc's atfork handler, the proper fork calls should leak the child
307*6dbdd20aSAndroid Build Coastguard Worker // before reaching this point. Therefore this logic exists primarily to handle
308*6dbdd20aSAndroid Build Coastguard Worker // clone and vfork.
309*6dbdd20aSAndroid Build Coastguard Worker // TODO(rsavitski): rename/delete |disable_fork_teardown| config option if this
310*6dbdd20aSAndroid Build Coastguard Worker // logic sticks, as the option becomes more clone-specific, and quite narrow.
IsPostFork()311*6dbdd20aSAndroid Build Coastguard Worker bool Client::IsPostFork() {
312*6dbdd20aSAndroid Build Coastguard Worker if (PERFETTO_UNLIKELY(getpid() != pid_at_creation_)) {
313*6dbdd20aSAndroid Build Coastguard Worker // Only print the message once, even if we do not shut down the client.
314*6dbdd20aSAndroid Build Coastguard Worker if (!detected_fork_) {
315*6dbdd20aSAndroid Build Coastguard Worker detected_fork_ = true;
316*6dbdd20aSAndroid Build Coastguard Worker const char* vfork_detected = "";
317*6dbdd20aSAndroid Build Coastguard Worker
318*6dbdd20aSAndroid Build Coastguard Worker // We use the fact that vfork does not update Bionic's TID cache, so
319*6dbdd20aSAndroid Build Coastguard Worker // we will have a mismatch between the actual TID (from the syscall)
320*6dbdd20aSAndroid Build Coastguard Worker // and the cached one.
321*6dbdd20aSAndroid Build Coastguard Worker //
322*6dbdd20aSAndroid Build Coastguard Worker // What we really want to check is if we are sharing virtual memory space
323*6dbdd20aSAndroid Build Coastguard Worker // with the original process. This would be
324*6dbdd20aSAndroid Build Coastguard Worker // syscall(__NR_kcmp, syscall(__NR_getpid), pid_at_creation_,
325*6dbdd20aSAndroid Build Coastguard Worker // KCMP_VM, 0, 0),
326*6dbdd20aSAndroid Build Coastguard Worker // but that is not compiled into our kernels and disallowed by seccomp.
327*6dbdd20aSAndroid Build Coastguard Worker if (!client_config_.disable_vfork_detection &&
328*6dbdd20aSAndroid Build Coastguard Worker syscall(__NR_gettid) != base::GetThreadId()) {
329*6dbdd20aSAndroid Build Coastguard Worker postfork_return_value_ = true;
330*6dbdd20aSAndroid Build Coastguard Worker vfork_detected = " (vfork detected)";
331*6dbdd20aSAndroid Build Coastguard Worker } else {
332*6dbdd20aSAndroid Build Coastguard Worker postfork_return_value_ = client_config_.disable_fork_teardown;
333*6dbdd20aSAndroid Build Coastguard Worker }
334*6dbdd20aSAndroid Build Coastguard Worker const char* action =
335*6dbdd20aSAndroid Build Coastguard Worker postfork_return_value_ ? "Not shutting down" : "Shutting down";
336*6dbdd20aSAndroid Build Coastguard Worker const char* force =
337*6dbdd20aSAndroid Build Coastguard Worker postfork_return_value_ ? " (fork teardown disabled)" : "";
338*6dbdd20aSAndroid Build Coastguard Worker PERFETTO_LOG(
339*6dbdd20aSAndroid Build Coastguard Worker "Detected post-fork child situation. Not profiling the child. "
340*6dbdd20aSAndroid Build Coastguard Worker "%s client%s%s",
341*6dbdd20aSAndroid Build Coastguard Worker action, force, vfork_detected);
342*6dbdd20aSAndroid Build Coastguard Worker }
343*6dbdd20aSAndroid Build Coastguard Worker return true;
344*6dbdd20aSAndroid Build Coastguard Worker }
345*6dbdd20aSAndroid Build Coastguard Worker return false;
346*6dbdd20aSAndroid Build Coastguard Worker }
347*6dbdd20aSAndroid Build Coastguard Worker
348*6dbdd20aSAndroid Build Coastguard Worker #if PERFETTO_BUILDFLAG(PERFETTO_ARCH_CPU_RISCV) && \
349*6dbdd20aSAndroid Build Coastguard Worker !PERFETTO_HAS_BUILTIN_STACK_ADDRESS()
GetStackRegister(unwindstack::ArchEnum arch)350*6dbdd20aSAndroid Build Coastguard Worker ssize_t Client::GetStackRegister(unwindstack::ArchEnum arch) {
351*6dbdd20aSAndroid Build Coastguard Worker ssize_t reg_sp, reg_size;
352*6dbdd20aSAndroid Build Coastguard Worker switch (arch) {
353*6dbdd20aSAndroid Build Coastguard Worker case unwindstack::ARCH_X86:
354*6dbdd20aSAndroid Build Coastguard Worker reg_sp = unwindstack::X86_REG_SP;
355*6dbdd20aSAndroid Build Coastguard Worker reg_size = sizeof(uint32_t);
356*6dbdd20aSAndroid Build Coastguard Worker break;
357*6dbdd20aSAndroid Build Coastguard Worker case unwindstack::ARCH_X86_64:
358*6dbdd20aSAndroid Build Coastguard Worker reg_sp = unwindstack::X86_64_REG_SP;
359*6dbdd20aSAndroid Build Coastguard Worker reg_size = sizeof(uint64_t);
360*6dbdd20aSAndroid Build Coastguard Worker break;
361*6dbdd20aSAndroid Build Coastguard Worker case unwindstack::ARCH_ARM:
362*6dbdd20aSAndroid Build Coastguard Worker reg_sp = unwindstack::ARM_REG_SP;
363*6dbdd20aSAndroid Build Coastguard Worker reg_size = sizeof(uint32_t);
364*6dbdd20aSAndroid Build Coastguard Worker break;
365*6dbdd20aSAndroid Build Coastguard Worker case unwindstack::ARCH_ARM64:
366*6dbdd20aSAndroid Build Coastguard Worker reg_sp = unwindstack::ARM64_REG_SP;
367*6dbdd20aSAndroid Build Coastguard Worker reg_size = sizeof(uint64_t);
368*6dbdd20aSAndroid Build Coastguard Worker break;
369*6dbdd20aSAndroid Build Coastguard Worker case unwindstack::ARCH_RISCV64:
370*6dbdd20aSAndroid Build Coastguard Worker reg_sp = unwindstack::RISCV64_REG_SP;
371*6dbdd20aSAndroid Build Coastguard Worker reg_size = sizeof(uint64_t);
372*6dbdd20aSAndroid Build Coastguard Worker break;
373*6dbdd20aSAndroid Build Coastguard Worker case unwindstack::ARCH_UNKNOWN:
374*6dbdd20aSAndroid Build Coastguard Worker return -1;
375*6dbdd20aSAndroid Build Coastguard Worker }
376*6dbdd20aSAndroid Build Coastguard Worker return reg_sp * reg_size;
377*6dbdd20aSAndroid Build Coastguard Worker }
378*6dbdd20aSAndroid Build Coastguard Worker
GetStackAddress(char * reg_data,unwindstack::ArchEnum arch)379*6dbdd20aSAndroid Build Coastguard Worker uintptr_t Client::GetStackAddress(char* reg_data, unwindstack::ArchEnum arch) {
380*6dbdd20aSAndroid Build Coastguard Worker ssize_t reg = GetStackRegister(arch);
381*6dbdd20aSAndroid Build Coastguard Worker if (reg < 0)
382*6dbdd20aSAndroid Build Coastguard Worker return reinterpret_cast<uintptr_t>(nullptr);
383*6dbdd20aSAndroid Build Coastguard Worker return *reinterpret_cast<uintptr_t*>(®_data[reg]);
384*6dbdd20aSAndroid Build Coastguard Worker }
385*6dbdd20aSAndroid Build Coastguard Worker #endif /* PERFETTO_ARCH_CPU_RISCV && !PERFETTO_HAS_BUILTIN_STACK_ADDRESS() */
386*6dbdd20aSAndroid Build Coastguard Worker
387*6dbdd20aSAndroid Build Coastguard Worker // The stack grows towards numerically smaller addresses, so the stack layout
388*6dbdd20aSAndroid Build Coastguard Worker // of main calling malloc is as follows.
389*6dbdd20aSAndroid Build Coastguard Worker //
390*6dbdd20aSAndroid Build Coastguard Worker // +------------+
391*6dbdd20aSAndroid Build Coastguard Worker // |SendWireMsg |
392*6dbdd20aSAndroid Build Coastguard Worker // stackptr +--> +------------+ 0x1000
393*6dbdd20aSAndroid Build Coastguard Worker // |RecordMalloc| +
394*6dbdd20aSAndroid Build Coastguard Worker // +------------+ |
395*6dbdd20aSAndroid Build Coastguard Worker // | malloc | |
396*6dbdd20aSAndroid Build Coastguard Worker // +------------+ |
397*6dbdd20aSAndroid Build Coastguard Worker // | main | v
398*6dbdd20aSAndroid Build Coastguard Worker // stackend +-> +------------+ 0xffff
RecordMalloc(uint32_t heap_id,uint64_t sample_size,uint64_t alloc_size,uint64_t alloc_address)399*6dbdd20aSAndroid Build Coastguard Worker bool Client::RecordMalloc(uint32_t heap_id,
400*6dbdd20aSAndroid Build Coastguard Worker uint64_t sample_size,
401*6dbdd20aSAndroid Build Coastguard Worker uint64_t alloc_size,
402*6dbdd20aSAndroid Build Coastguard Worker uint64_t alloc_address) {
403*6dbdd20aSAndroid Build Coastguard Worker if (PERFETTO_UNLIKELY(IsPostFork())) {
404*6dbdd20aSAndroid Build Coastguard Worker return postfork_return_value_;
405*6dbdd20aSAndroid Build Coastguard Worker }
406*6dbdd20aSAndroid Build Coastguard Worker
407*6dbdd20aSAndroid Build Coastguard Worker AllocMetadata metadata;
408*6dbdd20aSAndroid Build Coastguard Worker // By the difference between calling conventions, the frame pointer might
409*6dbdd20aSAndroid Build Coastguard Worker // include the current frame or not. So, using __builtin_frame_address()
410*6dbdd20aSAndroid Build Coastguard Worker // on specific architectures such as riscv can make stack unwinding failed.
411*6dbdd20aSAndroid Build Coastguard Worker // Thus, using __builtin_stack_address() or reading the stack pointer in
412*6dbdd20aSAndroid Build Coastguard Worker // register data directly instead of using __builtin_frame_address() on riscv.
413*6dbdd20aSAndroid Build Coastguard Worker #if PERFETTO_BUILDFLAG(PERFETTO_ARCH_CPU_RISCV)
414*6dbdd20aSAndroid Build Coastguard Worker #if PERFETTO_HAS_BUILTIN_STACK_ADDRESS()
415*6dbdd20aSAndroid Build Coastguard Worker const char* stackptr = reinterpret_cast<char*>(__builtin_stack_address());
416*6dbdd20aSAndroid Build Coastguard Worker unwindstack::AsmGetRegs(metadata.register_data);
417*6dbdd20aSAndroid Build Coastguard Worker #else
418*6dbdd20aSAndroid Build Coastguard Worker char* register_data = metadata.register_data;
419*6dbdd20aSAndroid Build Coastguard Worker unwindstack::AsmGetRegs(register_data);
420*6dbdd20aSAndroid Build Coastguard Worker const char* stackptr = reinterpret_cast<char*>(
421*6dbdd20aSAndroid Build Coastguard Worker GetStackAddress(register_data, unwindstack::Regs::CurrentArch()));
422*6dbdd20aSAndroid Build Coastguard Worker if (!stackptr) {
423*6dbdd20aSAndroid Build Coastguard Worker PERFETTO_ELOG("Failed to get stack address.");
424*6dbdd20aSAndroid Build Coastguard Worker shmem_.SetErrorState(SharedRingBuffer::kInvalidStackBounds);
425*6dbdd20aSAndroid Build Coastguard Worker return false;
426*6dbdd20aSAndroid Build Coastguard Worker }
427*6dbdd20aSAndroid Build Coastguard Worker #endif /* PERFETTO_HAS_BUILTIN_STACK_ADDRESS() */
428*6dbdd20aSAndroid Build Coastguard Worker #else
429*6dbdd20aSAndroid Build Coastguard Worker const char* stackptr = reinterpret_cast<char*>(__builtin_frame_address(0));
430*6dbdd20aSAndroid Build Coastguard Worker unwindstack::AsmGetRegs(metadata.register_data);
431*6dbdd20aSAndroid Build Coastguard Worker #endif /* PERFETTO_BUILDFLAG(PERFETTO_ARCH_CPU_RISCV) */
432*6dbdd20aSAndroid Build Coastguard Worker const char* stackend = GetStackEnd(stackptr);
433*6dbdd20aSAndroid Build Coastguard Worker if (!stackend) {
434*6dbdd20aSAndroid Build Coastguard Worker PERFETTO_ELOG("Failed to find stackend.");
435*6dbdd20aSAndroid Build Coastguard Worker shmem_.SetErrorState(SharedRingBuffer::kInvalidStackBounds);
436*6dbdd20aSAndroid Build Coastguard Worker return false;
437*6dbdd20aSAndroid Build Coastguard Worker }
438*6dbdd20aSAndroid Build Coastguard Worker uint64_t stack_size = static_cast<uint64_t>(stackend - stackptr);
439*6dbdd20aSAndroid Build Coastguard Worker metadata.sample_size = sample_size;
440*6dbdd20aSAndroid Build Coastguard Worker metadata.alloc_size = alloc_size;
441*6dbdd20aSAndroid Build Coastguard Worker metadata.alloc_address = alloc_address;
442*6dbdd20aSAndroid Build Coastguard Worker metadata.stack_pointer = reinterpret_cast<uint64_t>(stackptr);
443*6dbdd20aSAndroid Build Coastguard Worker metadata.arch = unwindstack::Regs::CurrentArch();
444*6dbdd20aSAndroid Build Coastguard Worker metadata.sequence_number =
445*6dbdd20aSAndroid Build Coastguard Worker 1 + sequence_number_[heap_id].fetch_add(1, std::memory_order_acq_rel);
446*6dbdd20aSAndroid Build Coastguard Worker metadata.heap_id = heap_id;
447*6dbdd20aSAndroid Build Coastguard Worker
448*6dbdd20aSAndroid Build Coastguard Worker struct timespec ts;
449*6dbdd20aSAndroid Build Coastguard Worker if (clock_gettime(CLOCK_MONOTONIC_COARSE, &ts) == 0) {
450*6dbdd20aSAndroid Build Coastguard Worker metadata.clock_monotonic_coarse_timestamp =
451*6dbdd20aSAndroid Build Coastguard Worker static_cast<uint64_t>(base::FromPosixTimespec(ts).count());
452*6dbdd20aSAndroid Build Coastguard Worker } else {
453*6dbdd20aSAndroid Build Coastguard Worker metadata.clock_monotonic_coarse_timestamp = 0;
454*6dbdd20aSAndroid Build Coastguard Worker }
455*6dbdd20aSAndroid Build Coastguard Worker
456*6dbdd20aSAndroid Build Coastguard Worker WireMessage msg{};
457*6dbdd20aSAndroid Build Coastguard Worker msg.record_type = RecordType::Malloc;
458*6dbdd20aSAndroid Build Coastguard Worker msg.alloc_header = &metadata;
459*6dbdd20aSAndroid Build Coastguard Worker msg.payload = const_cast<char*>(stackptr);
460*6dbdd20aSAndroid Build Coastguard Worker msg.payload_size = static_cast<size_t>(stack_size);
461*6dbdd20aSAndroid Build Coastguard Worker
462*6dbdd20aSAndroid Build Coastguard Worker if (SendWireMessageWithRetriesIfBlocking(msg) == -1)
463*6dbdd20aSAndroid Build Coastguard Worker return false;
464*6dbdd20aSAndroid Build Coastguard Worker
465*6dbdd20aSAndroid Build Coastguard Worker if (!shmem_.GetAndResetReaderPaused())
466*6dbdd20aSAndroid Build Coastguard Worker return true;
467*6dbdd20aSAndroid Build Coastguard Worker return SendControlSocketByte();
468*6dbdd20aSAndroid Build Coastguard Worker }
469*6dbdd20aSAndroid Build Coastguard Worker
SendWireMessageWithRetriesIfBlocking(const WireMessage & msg)470*6dbdd20aSAndroid Build Coastguard Worker int64_t Client::SendWireMessageWithRetriesIfBlocking(const WireMessage& msg) {
471*6dbdd20aSAndroid Build Coastguard Worker for (uint64_t i = 0;
472*6dbdd20aSAndroid Build Coastguard Worker max_shmem_tries_ == kInfiniteTries || i < max_shmem_tries_; ++i) {
473*6dbdd20aSAndroid Build Coastguard Worker if (shmem_.shutting_down())
474*6dbdd20aSAndroid Build Coastguard Worker return -1;
475*6dbdd20aSAndroid Build Coastguard Worker int64_t res = SendWireMessage(&shmem_, msg);
476*6dbdd20aSAndroid Build Coastguard Worker if (PERFETTO_LIKELY(res >= 0))
477*6dbdd20aSAndroid Build Coastguard Worker return res;
478*6dbdd20aSAndroid Build Coastguard Worker // retry if in blocking mode and still connected
479*6dbdd20aSAndroid Build Coastguard Worker if (client_config_.block_client && base::IsAgain(errno) && IsConnected()) {
480*6dbdd20aSAndroid Build Coastguard Worker usleep(kResendBackoffUs);
481*6dbdd20aSAndroid Build Coastguard Worker } else {
482*6dbdd20aSAndroid Build Coastguard Worker break;
483*6dbdd20aSAndroid Build Coastguard Worker }
484*6dbdd20aSAndroid Build Coastguard Worker }
485*6dbdd20aSAndroid Build Coastguard Worker if (IsConnected())
486*6dbdd20aSAndroid Build Coastguard Worker shmem_.SetErrorState(SharedRingBuffer::kHitTimeout);
487*6dbdd20aSAndroid Build Coastguard Worker PERFETTO_PLOG("Failed to write to shared ring buffer. Disconnecting.");
488*6dbdd20aSAndroid Build Coastguard Worker return -1;
489*6dbdd20aSAndroid Build Coastguard Worker }
490*6dbdd20aSAndroid Build Coastguard Worker
RecordFree(uint32_t heap_id,const uint64_t alloc_address)491*6dbdd20aSAndroid Build Coastguard Worker bool Client::RecordFree(uint32_t heap_id, const uint64_t alloc_address) {
492*6dbdd20aSAndroid Build Coastguard Worker if (PERFETTO_UNLIKELY(IsPostFork())) {
493*6dbdd20aSAndroid Build Coastguard Worker return postfork_return_value_;
494*6dbdd20aSAndroid Build Coastguard Worker }
495*6dbdd20aSAndroid Build Coastguard Worker
496*6dbdd20aSAndroid Build Coastguard Worker FreeEntry current_entry;
497*6dbdd20aSAndroid Build Coastguard Worker current_entry.sequence_number =
498*6dbdd20aSAndroid Build Coastguard Worker 1 + sequence_number_[heap_id].fetch_add(1, std::memory_order_acq_rel);
499*6dbdd20aSAndroid Build Coastguard Worker current_entry.addr = alloc_address;
500*6dbdd20aSAndroid Build Coastguard Worker current_entry.heap_id = heap_id;
501*6dbdd20aSAndroid Build Coastguard Worker WireMessage msg = {};
502*6dbdd20aSAndroid Build Coastguard Worker msg.record_type = RecordType::Free;
503*6dbdd20aSAndroid Build Coastguard Worker msg.free_header = ¤t_entry;
504*6dbdd20aSAndroid Build Coastguard Worker // Do not send control socket byte, as frees are very cheap to handle, so we
505*6dbdd20aSAndroid Build Coastguard Worker // just delay to the next alloc. Sending the control socket byte is ~10x the
506*6dbdd20aSAndroid Build Coastguard Worker // rest of the client overhead.
507*6dbdd20aSAndroid Build Coastguard Worker int64_t bytes_free = SendWireMessageWithRetriesIfBlocking(msg);
508*6dbdd20aSAndroid Build Coastguard Worker if (bytes_free == -1)
509*6dbdd20aSAndroid Build Coastguard Worker return false;
510*6dbdd20aSAndroid Build Coastguard Worker // Seems like we are filling up the shmem with frees. Flush.
511*6dbdd20aSAndroid Build Coastguard Worker if (static_cast<uint64_t>(bytes_free) < shmem_.size() / 2 &&
512*6dbdd20aSAndroid Build Coastguard Worker shmem_.GetAndResetReaderPaused()) {
513*6dbdd20aSAndroid Build Coastguard Worker return SendControlSocketByte();
514*6dbdd20aSAndroid Build Coastguard Worker }
515*6dbdd20aSAndroid Build Coastguard Worker return true;
516*6dbdd20aSAndroid Build Coastguard Worker }
517*6dbdd20aSAndroid Build Coastguard Worker
RecordHeapInfo(uint32_t heap_id,const char * heap_name,uint64_t interval)518*6dbdd20aSAndroid Build Coastguard Worker bool Client::RecordHeapInfo(uint32_t heap_id,
519*6dbdd20aSAndroid Build Coastguard Worker const char* heap_name,
520*6dbdd20aSAndroid Build Coastguard Worker uint64_t interval) {
521*6dbdd20aSAndroid Build Coastguard Worker if (PERFETTO_UNLIKELY(IsPostFork())) {
522*6dbdd20aSAndroid Build Coastguard Worker return postfork_return_value_;
523*6dbdd20aSAndroid Build Coastguard Worker }
524*6dbdd20aSAndroid Build Coastguard Worker
525*6dbdd20aSAndroid Build Coastguard Worker HeapName hnr;
526*6dbdd20aSAndroid Build Coastguard Worker hnr.heap_id = heap_id;
527*6dbdd20aSAndroid Build Coastguard Worker base::StringCopy(&hnr.heap_name[0], heap_name, sizeof(hnr.heap_name));
528*6dbdd20aSAndroid Build Coastguard Worker hnr.sample_interval = interval;
529*6dbdd20aSAndroid Build Coastguard Worker
530*6dbdd20aSAndroid Build Coastguard Worker WireMessage msg = {};
531*6dbdd20aSAndroid Build Coastguard Worker msg.record_type = RecordType::HeapName;
532*6dbdd20aSAndroid Build Coastguard Worker msg.heap_name_header = &hnr;
533*6dbdd20aSAndroid Build Coastguard Worker return SendWireMessageWithRetriesIfBlocking(msg);
534*6dbdd20aSAndroid Build Coastguard Worker }
535*6dbdd20aSAndroid Build Coastguard Worker
IsConnected()536*6dbdd20aSAndroid Build Coastguard Worker bool Client::IsConnected() {
537*6dbdd20aSAndroid Build Coastguard Worker sock_.DcheckIsBlocking(false);
538*6dbdd20aSAndroid Build Coastguard Worker char buf[1];
539*6dbdd20aSAndroid Build Coastguard Worker ssize_t recv_bytes = sock_.Receive(buf, sizeof(buf), nullptr, 0);
540*6dbdd20aSAndroid Build Coastguard Worker if (recv_bytes == 0)
541*6dbdd20aSAndroid Build Coastguard Worker return false;
542*6dbdd20aSAndroid Build Coastguard Worker // This is not supposed to happen because currently heapprofd does not send
543*6dbdd20aSAndroid Build Coastguard Worker // data to the client. Here for generality's sake.
544*6dbdd20aSAndroid Build Coastguard Worker if (recv_bytes > 0)
545*6dbdd20aSAndroid Build Coastguard Worker return true;
546*6dbdd20aSAndroid Build Coastguard Worker return base::IsAgain(errno);
547*6dbdd20aSAndroid Build Coastguard Worker }
548*6dbdd20aSAndroid Build Coastguard Worker
SendControlSocketByte()549*6dbdd20aSAndroid Build Coastguard Worker bool Client::SendControlSocketByte() {
550*6dbdd20aSAndroid Build Coastguard Worker // If base::IsAgain(errno), the socket buffer is full, so the service will
551*6dbdd20aSAndroid Build Coastguard Worker // pick up the notification even without adding another byte.
552*6dbdd20aSAndroid Build Coastguard Worker // In other error cases (usually EPIPE) we want to disconnect, because that
553*6dbdd20aSAndroid Build Coastguard Worker // is how the service signals the tracing session was torn down.
554*6dbdd20aSAndroid Build Coastguard Worker if (sock_.Send(kSingleByte, sizeof(kSingleByte)) == -1 &&
555*6dbdd20aSAndroid Build Coastguard Worker !base::IsAgain(errno)) {
556*6dbdd20aSAndroid Build Coastguard Worker if (shmem_.shutting_down()) {
557*6dbdd20aSAndroid Build Coastguard Worker PERFETTO_LOG("Profiling session ended.");
558*6dbdd20aSAndroid Build Coastguard Worker } else {
559*6dbdd20aSAndroid Build Coastguard Worker PERFETTO_PLOG("Failed to send control socket byte.");
560*6dbdd20aSAndroid Build Coastguard Worker }
561*6dbdd20aSAndroid Build Coastguard Worker return false;
562*6dbdd20aSAndroid Build Coastguard Worker }
563*6dbdd20aSAndroid Build Coastguard Worker return true;
564*6dbdd20aSAndroid Build Coastguard Worker }
565*6dbdd20aSAndroid Build Coastguard Worker
566*6dbdd20aSAndroid Build Coastguard Worker } // namespace profiling
567*6dbdd20aSAndroid Build Coastguard Worker } // namespace perfetto
568