1 /*
2 * Copyright (C) 2020 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "src/profiling/memory/client_api_factory.h"
18
19 #include "perfetto/base/logging.h"
20 #include "perfetto/ext/base/scoped_file.h"
21 #include "perfetto/ext/base/unix_socket.h"
22 #include "perfetto/ext/base/unix_task_runner.h"
23 #include "perfetto/ext/base/utils.h"
24 #include "perfetto/ext/base/watchdog.h"
25 #include "perfetto/heap_profile.h"
26 #include "perfetto/tracing/default_socket.h"
27 #include "src/profiling/common/proc_utils.h"
28 #include "src/profiling/memory/client.h"
29 #include "src/profiling/memory/heap_profile_internal.h"
30 #include "src/profiling/memory/heapprofd_producer.h"
31
32 #include <string>
33
34 #include <fcntl.h>
35 #include <sys/types.h>
36 #include <sys/wait.h>
37 #include <unistd.h>
38
39 // General approach:
40 // On loading this library, we fork off a process that runs heapprofd. We
41 // share a control socket pair (g_child_sock in client, srv_sock in service)
42 // which is used to:
43 // * Signal a new profiling session was started by sending a byte to
44 // g_child_sock. This signal gets received in MonitorFd.
45 // * For each profiling session, send a new socket from the client to the
46 // service. This happens in CreateClient.
47
48 namespace perfetto {
49 namespace profiling {
50 namespace {
51
52 base::UnixSocketRaw* g_client_sock;
53
MonitorFdOnce()54 bool MonitorFdOnce() {
55 char buf[1];
56 ssize_t r = g_client_sock->Receive(buf, sizeof(buf));
57 if (r == 0) {
58 PERFETTO_ELOG("Server disconneced.");
59 return false;
60 }
61 if (r < 0) {
62 PERFETTO_PLOG("Receive failed.");
63 return true;
64 }
65 AHeapProfile_initSession(malloc, free);
66 return true;
67 }
68
MonitorFd()69 void MonitorFd() {
70 g_client_sock->DcheckIsBlocking(true);
71 for (;;) {
72 bool cont = MonitorFdOnce();
73 if (!cont)
74 break;
75 }
76 }
77
78 } // namespace
79
StartHeapprofdIfStatic()80 void StartHeapprofdIfStatic() {
81 pid_t pid = getpid();
82 std::string cmdline;
83
84 if (!GetCmdlineForPID(pid, &cmdline)) {
85 PERFETTO_ELOG("Failed to get cmdline.");
86 }
87
88 g_client_sock = new base::UnixSocketRaw();
89 base::UnixSocketRaw srv_sock;
90 base::UnixSocketRaw cli_sock;
91
92 std::tie(cli_sock, srv_sock) = base::UnixSocketRaw::CreatePairPosix(
93 base::SockFamily::kUnix, base::SockType::kStream);
94
95 if (!cli_sock || !srv_sock) {
96 PERFETTO_ELOG("Failed to create socket pair.");
97 return;
98 }
99 pid_t f = fork();
100
101 if (f == -1) {
102 PERFETTO_PLOG("fork");
103 return;
104 }
105
106 if (f != 0) {
107 int wstatus;
108 if (PERFETTO_EINTR(waitpid(f, &wstatus, 0)) == -1)
109 PERFETTO_PLOG("waitpid");
110
111 *g_client_sock = std::move(cli_sock);
112
113 const char* w = getenv("PERFETTO_HEAPPROFD_BLOCKING_INIT");
114 if (w && w[0] == '1') {
115 g_client_sock->DcheckIsBlocking(true);
116 MonitorFdOnce();
117 }
118
119 std::thread th(MonitorFd);
120 th.detach();
121 return;
122 }
123
124 daemon(/* nochdir= */ 0, /* noclose= */ 1);
125
126 // On debug builds, we want to turn on crash reporting for heapprofd.
127 #if PERFETTO_BUILDFLAG(PERFETTO_STDERR_CRASH_DUMP)
128 base::EnableStacktraceOnCrashForDebug();
129 #endif
130
131 cli_sock.ReleaseFd();
132
133 // Leave stderr open for logging.
134 int null = open("/dev/null", O_RDWR); // NOLINT(android-cloexec-open)
135 dup2(null, STDIN_FILENO);
136 dup2(null, STDOUT_FILENO);
137 if (null > STDERR_FILENO)
138 close(null);
139
140 for (int i = STDERR_FILENO + 1; i < 512; ++i) {
141 if (i != srv_sock.fd())
142 close(i);
143 }
144
145 srv_sock.SetBlocking(false);
146
147 base::UnixTaskRunner task_runner;
148 base::Watchdog::GetInstance()->Start(); // crash on exceedingly long tasks
149 HeapprofdProducer producer(HeapprofdMode::kChild, &task_runner,
150 /* exit_when_done= */ false);
151 producer.SetTargetProcess(pid, cmdline);
152 producer.ConnectWithRetries(GetProducerSocket());
153 // Signal MonitorFd in the parent process to start a session.
154 producer.SetDataSourceCallback([&srv_sock] { srv_sock.Send("x", 1); });
155 task_runner.AddFileDescriptorWatch(
156 srv_sock.fd(), [&task_runner, &producer, &srv_sock] {
157 base::ScopedFile fd;
158 char buf[1];
159 ssize_t r = srv_sock.Receive(buf, sizeof(buf), &fd, 1);
160 if (r == 0) {
161 PERFETTO_LOG("Child disconnected.");
162 producer.TerminateWhenDone();
163 task_runner.RemoveFileDescriptorWatch(srv_sock.fd());
164 }
165 if (r == -1 && !base::IsAgain(errno)) {
166 PERFETTO_PLOG("Receive");
167 }
168 if (fd) {
169 producer.AdoptSocket(std::move(fd));
170 }
171 });
172 task_runner.Run();
173 // We currently do not Quit the task_runner, but if we ever do it will be
174 // very hard to debug if we don't exit here.
175 exit(0);
176 }
177
178 // This is called by AHeapProfile_initSession (client_api.cc) to construct a
179 // client.
ConstructClient(UnhookedAllocator<perfetto::profiling::Client> unhooked_allocator)180 std::shared_ptr<Client> ConstructClient(
181 UnhookedAllocator<perfetto::profiling::Client> unhooked_allocator) {
182 if (!g_client_sock)
183 return nullptr;
184
185 std::shared_ptr<perfetto::profiling::Client> client;
186 base::UnixSocketRaw srv_session_sock;
187 base::UnixSocketRaw client_session_sock;
188
189 std::tie(srv_session_sock, client_session_sock) =
190 base::UnixSocketRaw::CreatePairPosix(base::SockFamily::kUnix,
191 base::SockType::kStream);
192 if (!client_session_sock || !srv_session_sock) {
193 PERFETTO_ELOG("Failed to create socket pair.");
194 return nullptr;
195 }
196 base::ScopedFile srv_fd = srv_session_sock.ReleaseFd();
197 int fd = srv_fd.get();
198 // Send the session socket to the service.
199 g_client_sock->Send(" ", 1, &fd, 1);
200 return perfetto::profiling::Client::CreateAndHandshake(
201 std::move(client_session_sock), unhooked_allocator);
202 }
203
204 } // namespace profiling
205 } // namespace perfetto
206