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 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> 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 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 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 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