xref: /aosp_15_r20/external/perfetto/src/profiling/memory/client.cc (revision 6dbdd20afdafa5e3ca9b8809fa73465d530080dc)
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*>(&reg_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 = &current_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