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