• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2016, 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 <debuggerd/client.h>
18 
19 #include <fcntl.h>
20 #include <signal.h>
21 #include <stdlib.h>
22 #include <sys/poll.h>
23 #include <sys/stat.h>
24 #include <sys/types.h>
25 #include <unistd.h>
26 
27 #include <chrono>
28 
29 #include <android-base/file.h>
30 #include <android-base/logging.h>
31 #include <android-base/parseint.h>
32 #include <android-base/stringprintf.h>
33 #include <android-base/strings.h>
34 #include <android-base/unique_fd.h>
35 #include <cutils/sockets.h>
36 
37 #include "debuggerd/handler.h"
38 #include "protocol.h"
39 #include "util.h"
40 
41 using namespace std::chrono_literals;
42 
43 using android::base::unique_fd;
44 
send_signal(pid_t pid,const DebuggerdDumpType dump_type)45 static bool send_signal(pid_t pid, const DebuggerdDumpType dump_type) {
46   const int signal = (dump_type == kDebuggerdJavaBacktrace) ? SIGQUIT : DEBUGGER_SIGNAL;
47   sigval val;
48   val.sival_int = (dump_type == kDebuggerdNativeBacktrace) ? 1 : 0;
49 
50   if (sigqueue(pid, signal, val) != 0) {
51     PLOG(ERROR) << "libdebuggerd_client: failed to send signal to pid " << pid;
52     return false;
53   }
54   return true;
55 }
56 
57 template <typename Duration>
populate_timeval(struct timeval * tv,const Duration & duration)58 static void populate_timeval(struct timeval* tv, const Duration& duration) {
59   auto seconds = std::chrono::duration_cast<std::chrono::seconds>(duration);
60   auto microseconds = std::chrono::duration_cast<std::chrono::microseconds>(duration - seconds);
61   tv->tv_sec = static_cast<long>(seconds.count());
62   tv->tv_usec = static_cast<long>(microseconds.count());
63 }
64 
debuggerd_trigger_dump(pid_t pid,DebuggerdDumpType dump_type,unsigned int timeout_ms,unique_fd output_fd)65 bool debuggerd_trigger_dump(pid_t pid, DebuggerdDumpType dump_type, unsigned int timeout_ms,
66                             unique_fd output_fd) {
67   LOG(INFO) << "libdebuggerd_client: started dumping process " << pid;
68   unique_fd sockfd;
69   const auto end = std::chrono::steady_clock::now() + std::chrono::milliseconds(timeout_ms);
70   auto time_left = [&end]() { return end - std::chrono::steady_clock::now(); };
71   auto set_timeout = [timeout_ms, &time_left](int sockfd) {
72     if (timeout_ms <= 0) {
73       return sockfd;
74     }
75 
76     auto remaining = time_left();
77     if (remaining < decltype(remaining)::zero()) {
78       LOG(ERROR) << "libdebuggerd_client: timeout expired";
79       return -1;
80     }
81 
82     struct timeval timeout;
83     populate_timeval(&timeout, remaining);
84 
85     if (setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout)) != 0) {
86       PLOG(ERROR) << "libdebuggerd_client: failed to set receive timeout";
87       return -1;
88     }
89     if (setsockopt(sockfd, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(timeout)) != 0) {
90       PLOG(ERROR) << "libdebuggerd_client: failed to set send timeout";
91       return -1;
92     }
93 
94     return sockfd;
95   };
96 
97   sockfd.reset(socket(AF_LOCAL, SOCK_SEQPACKET, 0));
98   if (sockfd == -1) {
99     PLOG(ERROR) << "libdebugger_client: failed to create socket";
100     return false;
101   }
102 
103   if (socket_local_client_connect(set_timeout(sockfd.get()), kTombstonedInterceptSocketName,
104                                   ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_SEQPACKET) == -1) {
105     PLOG(ERROR) << "libdebuggerd_client: failed to connect to tombstoned";
106     return false;
107   }
108 
109   InterceptRequest req = {.pid = pid, .dump_type = dump_type};
110   if (!set_timeout(sockfd)) {
111     PLOG(ERROR) << "libdebugger_client: failed to set timeout";
112     return false;
113   }
114 
115   // Create an intermediate pipe to pass to the other end.
116   unique_fd pipe_read, pipe_write;
117   if (!Pipe(&pipe_read, &pipe_write)) {
118     PLOG(ERROR) << "libdebuggerd_client: failed to create pipe";
119     return false;
120   }
121 
122   std::string pipe_size_str;
123   int pipe_buffer_size = 1024 * 1024;
124   if (android::base::ReadFileToString("/proc/sys/fs/pipe-max-size", &pipe_size_str)) {
125     pipe_size_str = android::base::Trim(pipe_size_str);
126 
127     if (!android::base::ParseInt(pipe_size_str.c_str(), &pipe_buffer_size, 0)) {
128       LOG(FATAL) << "failed to parse pipe max size '" << pipe_size_str << "'";
129     }
130   }
131 
132   if (fcntl(pipe_read.get(), F_SETPIPE_SZ, pipe_buffer_size) != pipe_buffer_size) {
133     PLOG(ERROR) << "failed to set pipe buffer size";
134   }
135 
136   if (send_fd(set_timeout(sockfd), &req, sizeof(req), std::move(pipe_write)) != sizeof(req)) {
137     PLOG(ERROR) << "libdebuggerd_client: failed to send output fd to tombstoned";
138     return false;
139   }
140 
141   // Check to make sure we've successfully registered.
142   InterceptResponse response;
143   ssize_t rc =
144       TEMP_FAILURE_RETRY(recv(set_timeout(sockfd.get()), &response, sizeof(response), MSG_TRUNC));
145   if (rc == 0) {
146     LOG(ERROR) << "libdebuggerd_client: failed to read response from tombstoned: timeout reached?";
147     return false;
148   } else if (rc != sizeof(response)) {
149     LOG(ERROR)
150         << "libdebuggerd_client: received packet of unexpected length from tombstoned: expected "
151         << sizeof(response) << ", received " << rc;
152     return false;
153   }
154 
155   if (response.status != InterceptStatus::kRegistered) {
156     LOG(ERROR) << "libdebuggerd_client: unexpected registration response: "
157                << static_cast<int>(response.status);
158     return false;
159   }
160 
161   if (!send_signal(pid, dump_type)) {
162     return false;
163   }
164 
165   rc = TEMP_FAILURE_RETRY(recv(set_timeout(sockfd.get()), &response, sizeof(response), MSG_TRUNC));
166   if (rc == 0) {
167     LOG(ERROR) << "libdebuggerd_client: failed to read response from tombstoned: timeout reached?";
168     return false;
169   } else if (rc != sizeof(response)) {
170     LOG(ERROR)
171       << "libdebuggerd_client: received packet of unexpected length from tombstoned: expected "
172       << sizeof(response) << ", received " << rc;
173     return false;
174   }
175 
176   if (response.status != InterceptStatus::kStarted) {
177     response.error_message[sizeof(response.error_message) - 1] = '\0';
178     LOG(ERROR) << "libdebuggerd_client: tombstoned reported failure: " << response.error_message;
179     return false;
180   }
181 
182   // Forward output from the pipe to the output fd.
183   while (true) {
184     auto remaining_ms = std::chrono::duration_cast<std::chrono::milliseconds>(time_left()).count();
185     if (timeout_ms <= 0) {
186       remaining_ms = -1;
187     } else if (remaining_ms < 0) {
188       LOG(ERROR) << "libdebuggerd_client: timeout expired";
189       return false;
190     }
191 
192     struct pollfd pfd = {
193         .fd = pipe_read.get(), .events = POLLIN, .revents = 0,
194     };
195 
196     rc = poll(&pfd, 1, remaining_ms);
197     if (rc == -1) {
198       if (errno == EINTR) {
199         continue;
200       } else {
201         PLOG(ERROR) << "libdebuggerd_client: error while polling";
202         return false;
203       }
204     } else if (rc == 0) {
205       LOG(ERROR) << "libdebuggerd_client: timeout expired";
206       return false;
207     }
208 
209     char buf[1024];
210     rc = TEMP_FAILURE_RETRY(read(pipe_read.get(), buf, sizeof(buf)));
211     if (rc == 0) {
212       // Done.
213       break;
214     } else if (rc == -1) {
215       PLOG(ERROR) << "libdebuggerd_client: error while reading";
216       return false;
217     }
218 
219     if (!android::base::WriteFully(output_fd.get(), buf, rc)) {
220       PLOG(ERROR) << "libdebuggerd_client: error while writing";
221       return false;
222     }
223   }
224 
225   LOG(INFO) << "libdebuggerd_client: done dumping process " << pid;
226 
227   return true;
228 }
229 
dump_backtrace_to_file(pid_t tid,DebuggerdDumpType dump_type,int fd)230 int dump_backtrace_to_file(pid_t tid, DebuggerdDumpType dump_type, int fd) {
231   return dump_backtrace_to_file_timeout(tid, dump_type, 0, fd);
232 }
233 
dump_backtrace_to_file_timeout(pid_t tid,DebuggerdDumpType dump_type,int timeout_secs,int fd)234 int dump_backtrace_to_file_timeout(pid_t tid, DebuggerdDumpType dump_type, int timeout_secs,
235                                    int fd) {
236   android::base::unique_fd copy(dup(fd));
237   if (copy == -1) {
238     return -1;
239   }
240   int timeout_ms = timeout_secs > 0 ? timeout_secs * 1000 : 0;
241   return debuggerd_trigger_dump(tid, dump_type, timeout_ms, std::move(copy)) ? 0 : -1;
242 }
243