1cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao/* 2cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao * Copyright 2016, The Android Open Source Project 3cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao * 4cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao * Licensed under the Apache License, Version 2.0 (the "License"); 5cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao * you may not use this file except in compliance with the License. 6cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao * You may obtain a copy of the License at 7cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao * 8cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao * http://www.apache.org/licenses/LICENSE-2.0 9cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao * 10cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao * Unless required by applicable law or agreed to in writing, software 11cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao * distributed under the License is distributed on an "AS IS" BASIS, 12cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao * See the License for the specific language governing permissions and 14cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao * limitations under the License. 15cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao */ 16cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao 17cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao#include <fcntl.h> 18cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao#include <stdio.h> 19cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao#include <stdlib.h> 20cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao#include <sys/stat.h> 21cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao#include <sys/types.h> 22cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao#include <unistd.h> 23cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao 24cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao#include <array> 25cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao#include <deque> 26cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao#include <unordered_map> 27cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao 28cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao#include <event2/event.h> 29cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao#include <event2/listener.h> 30cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao#include <event2/thread.h> 31cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao 32cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao#include <android-base/logging.h> 33cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao#include <android-base/stringprintf.h> 34cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao#include <android-base/unique_fd.h> 35cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao#include <cutils/sockets.h> 36cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao 3755f79a5953e81c6b7ae56081e3c2fd2711a47dbcJosh Gao#include "debuggerd/handler.h" 38cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao#include "debuggerd/protocol.h" 39cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao#include "debuggerd/util.h" 40cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao 41cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao#include "intercept_manager.h" 42cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao 43cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gaousing android::base::StringPrintf; 44cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gaousing android::base::unique_fd; 45cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao 46cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gaostatic InterceptManager* intercept_manager; 47cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao 48cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gaoenum CrashStatus { 49cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao kCrashStatusRunning, 50cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao kCrashStatusQueued, 51cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao}; 52cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao 53cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao// Ownership of Crash is a bit messy. 54cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao// It's either owned by an active event that must have a timeout, or owned by 55cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao// queued_requests, in the case that multiple crashes come in at the same time. 56cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gaostruct Crash { 57cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao ~Crash() { 58cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao event_free(crash_event); 59cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao } 60cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao 61cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao unique_fd crash_fd; 62cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao pid_t crash_pid; 63cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao event* crash_event = nullptr; 643272000382e0013a2e3f7ec86d4b45ec15a2c363Josh Gao std::string crash_path; 65cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao}; 66cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao 67cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gaostatic constexpr char kTombstoneDirectory[] = "/data/tombstones/"; 68cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gaostatic constexpr size_t kTombstoneCount = 10; 69cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gaostatic int tombstone_directory_fd = -1; 70cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gaostatic int next_tombstone = 0; 71cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao 72cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gaostatic constexpr size_t kMaxConcurrentDumps = 1; 73cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gaostatic size_t num_concurrent_dumps = 0; 74cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao 75cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gaostatic std::deque<Crash*> queued_requests; 76cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao 77cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao// Forward declare the callbacks so they can be placed in a sensible order. 78cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gaostatic void crash_accept_cb(evconnlistener* listener, evutil_socket_t sockfd, sockaddr*, int, void*); 79cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gaostatic void crash_request_cb(evutil_socket_t sockfd, short ev, void* arg); 80cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gaostatic void crash_completed_cb(evutil_socket_t sockfd, short ev, void* arg); 81cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao 82cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gaostatic void find_oldest_tombstone() { 83cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao size_t oldest_tombstone = 0; 84cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao time_t oldest_time = std::numeric_limits<time_t>::max(); 85cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao 86cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao for (size_t i = 0; i < kTombstoneCount; ++i) { 87cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao std::string path = android::base::StringPrintf("%stombstone_%02zu", kTombstoneDirectory, i); 88cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao struct stat st; 89cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao if (stat(path.c_str(), &st) != 0) { 908498016b81a393e48ce1e3060872b841298708a3Josh Gao if (errno == ENOENT) { 918498016b81a393e48ce1e3060872b841298708a3Josh Gao oldest_tombstone = i; 928498016b81a393e48ce1e3060872b841298708a3Josh Gao break; 938498016b81a393e48ce1e3060872b841298708a3Josh Gao } else { 948498016b81a393e48ce1e3060872b841298708a3Josh Gao PLOG(ERROR) << "failed to stat " << path; 958498016b81a393e48ce1e3060872b841298708a3Josh Gao continue; 968498016b81a393e48ce1e3060872b841298708a3Josh Gao } 97cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao } 98cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao 99cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao if (st.st_mtime < oldest_time) { 100cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao oldest_tombstone = i; 101cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao oldest_time = st.st_mtime; 102cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao } 103cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao } 104cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao 105cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao next_tombstone = oldest_tombstone; 106cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao} 107cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao 1083272000382e0013a2e3f7ec86d4b45ec15a2c363Josh Gaostatic std::pair<unique_fd, std::string> get_tombstone() { 109cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao // If kMaxConcurrentDumps is greater than 1, then theoretically the same 110cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao // filename could be handed out to multiple processes. Unlink and create the 111cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao // file, instead of using O_TRUNC, to avoid two processes interleaving their 112cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao // output. 113cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao unique_fd result; 1143272000382e0013a2e3f7ec86d4b45ec15a2c363Josh Gao std::string file_name = StringPrintf("tombstone_%02d", next_tombstone); 1153272000382e0013a2e3f7ec86d4b45ec15a2c363Josh Gao if (unlinkat(tombstone_directory_fd, file_name.c_str(), 0) != 0 && errno != ENOENT) { 1163272000382e0013a2e3f7ec86d4b45ec15a2c363Josh Gao PLOG(FATAL) << "failed to unlink tombstone at " << kTombstoneDirectory << "/" << file_name; 117cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao } 118cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao 1193272000382e0013a2e3f7ec86d4b45ec15a2c363Josh Gao result.reset(openat(tombstone_directory_fd, file_name.c_str(), 1203272000382e0013a2e3f7ec86d4b45ec15a2c363Josh Gao O_CREAT | O_EXCL | O_WRONLY | O_APPEND | O_CLOEXEC, 0640)); 121cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao if (result == -1) { 1223272000382e0013a2e3f7ec86d4b45ec15a2c363Josh Gao PLOG(FATAL) << "failed to create tombstone at " << kTombstoneDirectory << "/" << file_name; 123cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao } 124cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao 125cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao next_tombstone = (next_tombstone + 1) % kTombstoneCount; 1263272000382e0013a2e3f7ec86d4b45ec15a2c363Josh Gao return {std::move(result), std::string(kTombstoneDirectory) + "/" + file_name}; 127cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao} 128cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao 129ef042d3fc546b73c8e55408920e7cdc7d6c45e9bJosh Gaostatic void perform_request(Crash* crash) { 130cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao unique_fd output_fd; 131cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao if (!intercept_manager->GetIntercept(crash->crash_pid, &output_fd)) { 1323272000382e0013a2e3f7ec86d4b45ec15a2c363Josh Gao std::tie(output_fd, crash->crash_path) = get_tombstone(); 133cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao } 134cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao 135cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao TombstonedCrashPacket response = { 136cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao .packet_type = CrashPacketType::kPerformDump 137cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao }; 138cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao ssize_t rc = send_fd(crash->crash_fd, &response, sizeof(response), std::move(output_fd)); 139cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao if (rc == -1) { 140cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao PLOG(WARNING) << "failed to send response to CrashRequest"; 141cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao goto fail; 142cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao } else if (rc != sizeof(response)) { 143cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao PLOG(WARNING) << "crash socket write returned short"; 144cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao goto fail; 145cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao } else { 146cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao // TODO: Make this configurable by the interceptor? 147cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao struct timeval timeout = { 10, 0 }; 148cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao 149cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao event_base* base = event_get_base(crash->crash_event); 150cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao event_assign(crash->crash_event, base, crash->crash_fd, EV_TIMEOUT | EV_READ, 151cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao crash_completed_cb, crash); 152cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao event_add(crash->crash_event, &timeout); 153cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao } 154a1bd1733aeac2ed6de1a8bab3610faa65051d053Josh Gao 155a1bd1733aeac2ed6de1a8bab3610faa65051d053Josh Gao ++num_concurrent_dumps; 156cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao return; 157cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao 158cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gaofail: 159cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao delete crash; 160cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao} 161cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao 162ef042d3fc546b73c8e55408920e7cdc7d6c45e9bJosh Gaostatic void dequeue_requests() { 163ef042d3fc546b73c8e55408920e7cdc7d6c45e9bJosh Gao while (!queued_requests.empty() && num_concurrent_dumps < kMaxConcurrentDumps) { 164ef042d3fc546b73c8e55408920e7cdc7d6c45e9bJosh Gao Crash* next_crash = queued_requests.front(); 165ef042d3fc546b73c8e55408920e7cdc7d6c45e9bJosh Gao queued_requests.pop_front(); 166ef042d3fc546b73c8e55408920e7cdc7d6c45e9bJosh Gao perform_request(next_crash); 167ef042d3fc546b73c8e55408920e7cdc7d6c45e9bJosh Gao } 168ef042d3fc546b73c8e55408920e7cdc7d6c45e9bJosh Gao} 169ef042d3fc546b73c8e55408920e7cdc7d6c45e9bJosh Gao 170cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gaostatic void crash_accept_cb(evconnlistener* listener, evutil_socket_t sockfd, sockaddr*, int, 171cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao void*) { 172cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao event_base* base = evconnlistener_get_base(listener); 173cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao Crash* crash = new Crash(); 174cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao 175cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao struct timeval timeout = { 1, 0 }; 176cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao event* crash_event = event_new(base, sockfd, EV_TIMEOUT | EV_READ, crash_request_cb, crash); 177cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao crash->crash_fd.reset(sockfd); 178cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao crash->crash_event = crash_event; 179cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao event_add(crash_event, &timeout); 180cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao} 181cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao 182cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gaostatic void crash_request_cb(evutil_socket_t sockfd, short ev, void* arg) { 183cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao ssize_t rc; 184cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao Crash* crash = static_cast<Crash*>(arg); 185cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao TombstonedCrashPacket request = {}; 186cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao 187cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao if ((ev & EV_TIMEOUT) != 0) { 188cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao LOG(WARNING) << "crash request timed out"; 189cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao goto fail; 190cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao } else if ((ev & EV_READ) == 0) { 191cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao LOG(WARNING) << "tombstoned received unexpected event from crash socket"; 192cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao goto fail; 193cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao } 194cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao 195cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao rc = TEMP_FAILURE_RETRY(read(sockfd, &request, sizeof(request))); 196cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao if (rc == -1) { 197cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao PLOG(WARNING) << "failed to read from crash socket"; 198cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao goto fail; 199cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao } else if (rc != sizeof(request)) { 200cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao LOG(WARNING) << "crash socket received short read of length " << rc << " (expected " 201cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao << sizeof(request) << ")"; 202cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao goto fail; 203cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao } 204cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao 205cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao if (request.packet_type != CrashPacketType::kDumpRequest) { 206cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao LOG(WARNING) << "unexpected crash packet type, expected kDumpRequest, received " 207cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao << StringPrintf("%#2hhX", request.packet_type); 208cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao goto fail; 209cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao } 210cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao 211cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao crash->crash_pid = request.packet.dump_request.pid; 212cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao LOG(INFO) << "received crash request for pid " << crash->crash_pid; 213cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao 214cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao if (num_concurrent_dumps == kMaxConcurrentDumps) { 215cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao LOG(INFO) << "enqueueing crash request for pid " << crash->crash_pid; 216cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao queued_requests.push_back(crash); 217cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao } else { 218ef042d3fc546b73c8e55408920e7cdc7d6c45e9bJosh Gao perform_request(crash); 219cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao } 220cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao 221cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao return; 222cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao 223cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gaofail: 224cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao delete crash; 225cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao} 226cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao 227cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gaostatic void crash_completed_cb(evutil_socket_t sockfd, short ev, void* arg) { 228cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao ssize_t rc; 229cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao Crash* crash = static_cast<Crash*>(arg); 230cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao TombstonedCrashPacket request = {}; 231cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao 232cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao --num_concurrent_dumps; 233cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao 234cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao if ((ev & EV_READ) == 0) { 235cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao goto fail; 236cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao } 237cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao 238cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao rc = TEMP_FAILURE_RETRY(read(sockfd, &request, sizeof(request))); 239cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao if (rc == -1) { 240cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao PLOG(WARNING) << "failed to read from crash socket"; 241cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao goto fail; 242cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao } else if (rc != sizeof(request)) { 243cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao LOG(WARNING) << "crash socket received short read of length " << rc << " (expected " 244cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao << sizeof(request) << ")"; 245cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao goto fail; 246cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao } 247cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao 248cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao if (request.packet_type != CrashPacketType::kCompletedDump) { 249cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao LOG(WARNING) << "unexpected crash packet type, expected kCompletedDump, received " 250cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao << uint32_t(request.packet_type); 251cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao goto fail; 252cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao } 253cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao 2543272000382e0013a2e3f7ec86d4b45ec15a2c363Josh Gao if (!crash->crash_path.empty()) { 2553272000382e0013a2e3f7ec86d4b45ec15a2c363Josh Gao LOG(ERROR) << "Tombstone written to: " << crash->crash_path; 2563272000382e0013a2e3f7ec86d4b45ec15a2c363Josh Gao } 2573272000382e0013a2e3f7ec86d4b45ec15a2c363Josh Gao 258cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gaofail: 259cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao delete crash; 260cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao 261cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao // If there's something queued up, let them proceed. 262ef042d3fc546b73c8e55408920e7cdc7d6c45e9bJosh Gao dequeue_requests(); 263cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao} 264cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao 265cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gaoint main(int, char* []) { 2668830c95def6602db3e7e44755f840a9155f83d2aJosh Gao umask(0137); 2678830c95def6602db3e7e44755f840a9155f83d2aJosh Gao 26855f79a5953e81c6b7ae56081e3c2fd2711a47dbcJosh Gao // Don't try to connect to ourselves if we crash. 26955f79a5953e81c6b7ae56081e3c2fd2711a47dbcJosh Gao struct sigaction action = {}; 27055f79a5953e81c6b7ae56081e3c2fd2711a47dbcJosh Gao action.sa_handler = [](int signal) { 27155f79a5953e81c6b7ae56081e3c2fd2711a47dbcJosh Gao LOG(ERROR) << "received fatal signal " << signal; 27255f79a5953e81c6b7ae56081e3c2fd2711a47dbcJosh Gao _exit(1); 27355f79a5953e81c6b7ae56081e3c2fd2711a47dbcJosh Gao }; 27455f79a5953e81c6b7ae56081e3c2fd2711a47dbcJosh Gao debuggerd_register_handlers(&action); 27555f79a5953e81c6b7ae56081e3c2fd2711a47dbcJosh Gao 276cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao tombstone_directory_fd = open(kTombstoneDirectory, O_DIRECTORY | O_RDONLY | O_CLOEXEC); 277cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao if (tombstone_directory_fd == -1) { 278cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao PLOG(FATAL) << "failed to open tombstone directory"; 279cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao } 280cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao 281cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao find_oldest_tombstone(); 282cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao 283cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao int intercept_socket = android_get_control_socket(kTombstonedInterceptSocketName); 284cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao int crash_socket = android_get_control_socket(kTombstonedCrashSocketName); 285cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao 286cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao if (intercept_socket == -1 || crash_socket == -1) { 287cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao PLOG(FATAL) << "failed to get socket from init"; 288cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao } 289cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao 290cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao evutil_make_socket_nonblocking(intercept_socket); 291cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao evutil_make_socket_nonblocking(crash_socket); 292cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao 293cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao event_base* base = event_base_new(); 294cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao if (!base) { 295cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao LOG(FATAL) << "failed to create event_base"; 296cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao } 297cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao 298cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao intercept_manager = new InterceptManager(base, intercept_socket); 299cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao 300cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao evconnlistener* listener = 301cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao evconnlistener_new(base, crash_accept_cb, nullptr, -1, LEV_OPT_CLOSE_ON_FREE, crash_socket); 302cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao if (!listener) { 303cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao LOG(FATAL) << "failed to create evconnlistener"; 304cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao } 305cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao 306cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao LOG(INFO) << "tombstoned successfully initialized"; 307cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao event_base_dispatch(base); 308cbe70cb0a8cb0171f3802273050e851a47b090edJosh Gao} 309