xref: /aosp_15_r20/bionic/libfdtrack/fdtrack.cpp (revision 8d67ca893c1523eb926b9080dbe4e2ffd2a27ba1)
1*8d67ca89SAndroid Build Coastguard Worker /*
2*8d67ca89SAndroid Build Coastguard Worker  * Copyright (C) 2019 The Android Open Source Project
3*8d67ca89SAndroid Build Coastguard Worker  * All rights reserved.
4*8d67ca89SAndroid Build Coastguard Worker  *
5*8d67ca89SAndroid Build Coastguard Worker  * Redistribution and use in source and binary forms, with or without
6*8d67ca89SAndroid Build Coastguard Worker  * modification, are permitted provided that the following conditions
7*8d67ca89SAndroid Build Coastguard Worker  * are met:
8*8d67ca89SAndroid Build Coastguard Worker  *  * Redistributions of source code must retain the above copyright
9*8d67ca89SAndroid Build Coastguard Worker  *    notice, this list of conditions and the following disclaimer.
10*8d67ca89SAndroid Build Coastguard Worker  *  * Redistributions in binary form must reproduce the above copyright
11*8d67ca89SAndroid Build Coastguard Worker  *    notice, this list of conditions and the following disclaimer in
12*8d67ca89SAndroid Build Coastguard Worker  *    the documentation and/or other materials provided with the
13*8d67ca89SAndroid Build Coastguard Worker  *    distribution.
14*8d67ca89SAndroid Build Coastguard Worker  *
15*8d67ca89SAndroid Build Coastguard Worker  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16*8d67ca89SAndroid Build Coastguard Worker  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17*8d67ca89SAndroid Build Coastguard Worker  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
18*8d67ca89SAndroid Build Coastguard Worker  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
19*8d67ca89SAndroid Build Coastguard Worker  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
20*8d67ca89SAndroid Build Coastguard Worker  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
21*8d67ca89SAndroid Build Coastguard Worker  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
22*8d67ca89SAndroid Build Coastguard Worker  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
23*8d67ca89SAndroid Build Coastguard Worker  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24*8d67ca89SAndroid Build Coastguard Worker  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
25*8d67ca89SAndroid Build Coastguard Worker  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26*8d67ca89SAndroid Build Coastguard Worker  * SUCH DAMAGE.
27*8d67ca89SAndroid Build Coastguard Worker  */
28*8d67ca89SAndroid Build Coastguard Worker 
29*8d67ca89SAndroid Build Coastguard Worker #include <inttypes.h>
30*8d67ca89SAndroid Build Coastguard Worker #include <stdint.h>
31*8d67ca89SAndroid Build Coastguard Worker 
32*8d67ca89SAndroid Build Coastguard Worker #include <array>
33*8d67ca89SAndroid Build Coastguard Worker #include <mutex>
34*8d67ca89SAndroid Build Coastguard Worker #include <string>
35*8d67ca89SAndroid Build Coastguard Worker #include <string_view>
36*8d67ca89SAndroid Build Coastguard Worker #include <thread>
37*8d67ca89SAndroid Build Coastguard Worker #include <utility>
38*8d67ca89SAndroid Build Coastguard Worker #include <vector>
39*8d67ca89SAndroid Build Coastguard Worker 
40*8d67ca89SAndroid Build Coastguard Worker #include <android/fdsan.h>
41*8d67ca89SAndroid Build Coastguard Worker #include <android/set_abort_message.h>
42*8d67ca89SAndroid Build Coastguard Worker #include <bionic/fdtrack.h>
43*8d67ca89SAndroid Build Coastguard Worker 
44*8d67ca89SAndroid Build Coastguard Worker #include <android-base/no_destructor.h>
45*8d67ca89SAndroid Build Coastguard Worker #include <android-base/thread_annotations.h>
46*8d67ca89SAndroid Build Coastguard Worker #include <async_safe/log.h>
47*8d67ca89SAndroid Build Coastguard Worker #include <bionic/reserved_signals.h>
48*8d67ca89SAndroid Build Coastguard Worker 
49*8d67ca89SAndroid Build Coastguard Worker #include <unwindstack/AndroidUnwinder.h>
50*8d67ca89SAndroid Build Coastguard Worker 
51*8d67ca89SAndroid Build Coastguard Worker struct FdEntry {
52*8d67ca89SAndroid Build Coastguard Worker   std::mutex mutex;
53*8d67ca89SAndroid Build Coastguard Worker   std::vector<unwindstack::FrameData> backtrace GUARDED_BY(mutex);
54*8d67ca89SAndroid Build Coastguard Worker };
55*8d67ca89SAndroid Build Coastguard Worker 
56*8d67ca89SAndroid Build Coastguard Worker extern "C" void fdtrack_dump();
57*8d67ca89SAndroid Build Coastguard Worker extern "C" void fdtrack_dump_fatal();
58*8d67ca89SAndroid Build Coastguard Worker 
59*8d67ca89SAndroid Build Coastguard Worker using fdtrack_callback_t = bool (*)(int fd, const char* const* function_names,
60*8d67ca89SAndroid Build Coastguard Worker                                     const uint64_t* function_offsets, size_t count, void* arg);
61*8d67ca89SAndroid Build Coastguard Worker extern "C" void fdtrack_iterate(fdtrack_callback_t callback, void* arg);
62*8d67ca89SAndroid Build Coastguard Worker 
63*8d67ca89SAndroid Build Coastguard Worker static void fd_hook(android_fdtrack_event* event);
64*8d67ca89SAndroid Build Coastguard Worker 
65*8d67ca89SAndroid Build Coastguard Worker // Backtraces for the first 4k file descriptors ought to be enough to diagnose an fd leak.
66*8d67ca89SAndroid Build Coastguard Worker static constexpr size_t kFdTableSize = 4096;
67*8d67ca89SAndroid Build Coastguard Worker 
68*8d67ca89SAndroid Build Coastguard Worker // Only unwind up to 32 frames outside of libfdtrack.so.
69*8d67ca89SAndroid Build Coastguard Worker static constexpr size_t kStackDepth = 32;
70*8d67ca89SAndroid Build Coastguard Worker 
71*8d67ca89SAndroid Build Coastguard Worker static bool installed = false;
72*8d67ca89SAndroid Build Coastguard Worker static std::array<FdEntry, kFdTableSize> stack_traces [[clang::no_destroy]];
Unwinder()73*8d67ca89SAndroid Build Coastguard Worker static unwindstack::AndroidLocalUnwinder& Unwinder() {
74*8d67ca89SAndroid Build Coastguard Worker   // Skip any initial frames from libfdtrack.so.
75*8d67ca89SAndroid Build Coastguard Worker   // Also ignore frames from ART (http://b/236197847) because we'd rather spend
76*8d67ca89SAndroid Build Coastguard Worker   // our precious few frames on the actual Java calling code rather than the
77*8d67ca89SAndroid Build Coastguard Worker   // implementation of JNI!
78*8d67ca89SAndroid Build Coastguard Worker   static android::base::NoDestructor<unwindstack::AndroidLocalUnwinder> unwinder(
79*8d67ca89SAndroid Build Coastguard Worker       std::vector<std::string>{"libfdtrack.so", "libart.so"});
80*8d67ca89SAndroid Build Coastguard Worker   return *unwinder.get();
81*8d67ca89SAndroid Build Coastguard Worker }
82*8d67ca89SAndroid Build Coastguard Worker 
ctor()83*8d67ca89SAndroid Build Coastguard Worker __attribute__((constructor)) static void ctor() {
84*8d67ca89SAndroid Build Coastguard Worker   for (auto& entry : stack_traces) {
85*8d67ca89SAndroid Build Coastguard Worker     entry.backtrace.reserve(kStackDepth);
86*8d67ca89SAndroid Build Coastguard Worker   }
87*8d67ca89SAndroid Build Coastguard Worker 
88*8d67ca89SAndroid Build Coastguard Worker   struct sigaction sa = {};
89*8d67ca89SAndroid Build Coastguard Worker   sa.sa_sigaction = [](int, siginfo_t* siginfo, void*) {
90*8d67ca89SAndroid Build Coastguard Worker     if (siginfo->si_code == SI_QUEUE && siginfo->si_int == 1) {
91*8d67ca89SAndroid Build Coastguard Worker       fdtrack_dump_fatal();
92*8d67ca89SAndroid Build Coastguard Worker     } else {
93*8d67ca89SAndroid Build Coastguard Worker       fdtrack_dump();
94*8d67ca89SAndroid Build Coastguard Worker     }
95*8d67ca89SAndroid Build Coastguard Worker   };
96*8d67ca89SAndroid Build Coastguard Worker   sa.sa_flags = SA_SIGINFO | SA_ONSTACK;
97*8d67ca89SAndroid Build Coastguard Worker   sigaction(BIONIC_SIGNAL_FDTRACK, &sa, nullptr);
98*8d67ca89SAndroid Build Coastguard Worker 
99*8d67ca89SAndroid Build Coastguard Worker   unwindstack::ErrorData error;
100*8d67ca89SAndroid Build Coastguard Worker   if (Unwinder().Initialize(error)) {
101*8d67ca89SAndroid Build Coastguard Worker     android_fdtrack_hook_t expected = nullptr;
102*8d67ca89SAndroid Build Coastguard Worker     installed = android_fdtrack_compare_exchange_hook(&expected, &fd_hook);
103*8d67ca89SAndroid Build Coastguard Worker   }
104*8d67ca89SAndroid Build Coastguard Worker 
105*8d67ca89SAndroid Build Coastguard Worker   android_fdtrack_set_globally_enabled(true);
106*8d67ca89SAndroid Build Coastguard Worker }
107*8d67ca89SAndroid Build Coastguard Worker 
dtor()108*8d67ca89SAndroid Build Coastguard Worker __attribute__((destructor)) static void dtor() {
109*8d67ca89SAndroid Build Coastguard Worker   if (installed) {
110*8d67ca89SAndroid Build Coastguard Worker     android_fdtrack_hook_t expected = &fd_hook;
111*8d67ca89SAndroid Build Coastguard Worker     android_fdtrack_compare_exchange_hook(&expected, nullptr);
112*8d67ca89SAndroid Build Coastguard Worker   }
113*8d67ca89SAndroid Build Coastguard Worker }
114*8d67ca89SAndroid Build Coastguard Worker 
GetFdEntry(int fd)115*8d67ca89SAndroid Build Coastguard Worker FdEntry* GetFdEntry(int fd) {
116*8d67ca89SAndroid Build Coastguard Worker   if (fd >= 0 && fd < static_cast<int>(kFdTableSize)) {
117*8d67ca89SAndroid Build Coastguard Worker     return &stack_traces[fd];
118*8d67ca89SAndroid Build Coastguard Worker   }
119*8d67ca89SAndroid Build Coastguard Worker   return nullptr;
120*8d67ca89SAndroid Build Coastguard Worker }
121*8d67ca89SAndroid Build Coastguard Worker 
fd_hook(android_fdtrack_event * event)122*8d67ca89SAndroid Build Coastguard Worker static void fd_hook(android_fdtrack_event* event) {
123*8d67ca89SAndroid Build Coastguard Worker   if (event->type == ANDROID_FDTRACK_EVENT_TYPE_CREATE) {
124*8d67ca89SAndroid Build Coastguard Worker     if (FdEntry* entry = GetFdEntry(event->fd); entry) {
125*8d67ca89SAndroid Build Coastguard Worker       std::lock_guard<std::mutex> lock(entry->mutex);
126*8d67ca89SAndroid Build Coastguard Worker       entry->backtrace.clear();
127*8d67ca89SAndroid Build Coastguard Worker 
128*8d67ca89SAndroid Build Coastguard Worker       unwindstack::AndroidUnwinderData data(kStackDepth);
129*8d67ca89SAndroid Build Coastguard Worker       if (Unwinder().Unwind(data)) {
130*8d67ca89SAndroid Build Coastguard Worker         entry->backtrace = std::move(data.frames);
131*8d67ca89SAndroid Build Coastguard Worker       }
132*8d67ca89SAndroid Build Coastguard Worker     }
133*8d67ca89SAndroid Build Coastguard Worker   } else if (event->type == ANDROID_FDTRACK_EVENT_TYPE_CLOSE) {
134*8d67ca89SAndroid Build Coastguard Worker     if (FdEntry* entry = GetFdEntry(event->fd); entry) {
135*8d67ca89SAndroid Build Coastguard Worker       std::lock_guard<std::mutex> lock(entry->mutex);
136*8d67ca89SAndroid Build Coastguard Worker       entry->backtrace.clear();
137*8d67ca89SAndroid Build Coastguard Worker     }
138*8d67ca89SAndroid Build Coastguard Worker   }
139*8d67ca89SAndroid Build Coastguard Worker }
140*8d67ca89SAndroid Build Coastguard Worker 
fdtrack_iterate(fdtrack_callback_t callback,void * arg)141*8d67ca89SAndroid Build Coastguard Worker void fdtrack_iterate(fdtrack_callback_t callback, void* arg) {
142*8d67ca89SAndroid Build Coastguard Worker   bool prev = android_fdtrack_set_enabled(false);
143*8d67ca89SAndroid Build Coastguard Worker 
144*8d67ca89SAndroid Build Coastguard Worker   for (int fd = 0; fd < static_cast<int>(stack_traces.size()); ++fd) {
145*8d67ca89SAndroid Build Coastguard Worker     const char* function_names[kStackDepth];
146*8d67ca89SAndroid Build Coastguard Worker     uint64_t function_offsets[kStackDepth];
147*8d67ca89SAndroid Build Coastguard Worker     FdEntry* entry = GetFdEntry(fd);
148*8d67ca89SAndroid Build Coastguard Worker     if (!entry) {
149*8d67ca89SAndroid Build Coastguard Worker       continue;
150*8d67ca89SAndroid Build Coastguard Worker     }
151*8d67ca89SAndroid Build Coastguard Worker 
152*8d67ca89SAndroid Build Coastguard Worker     if (!entry->mutex.try_lock()) {
153*8d67ca89SAndroid Build Coastguard Worker       async_safe_format_log(ANDROID_LOG_WARN, "fdtrack", "fd %d locked, skipping", fd);
154*8d67ca89SAndroid Build Coastguard Worker       continue;
155*8d67ca89SAndroid Build Coastguard Worker     }
156*8d67ca89SAndroid Build Coastguard Worker 
157*8d67ca89SAndroid Build Coastguard Worker     if (entry->backtrace.empty()) {
158*8d67ca89SAndroid Build Coastguard Worker       entry->mutex.unlock();
159*8d67ca89SAndroid Build Coastguard Worker       continue;
160*8d67ca89SAndroid Build Coastguard Worker     } else if (entry->backtrace.size() < 2) {
161*8d67ca89SAndroid Build Coastguard Worker       async_safe_format_log(ANDROID_LOG_WARN, "fdtrack", "fd %d missing frames: size = %zu", fd,
162*8d67ca89SAndroid Build Coastguard Worker                             entry->backtrace.size());
163*8d67ca89SAndroid Build Coastguard Worker 
164*8d67ca89SAndroid Build Coastguard Worker       entry->mutex.unlock();
165*8d67ca89SAndroid Build Coastguard Worker       continue;
166*8d67ca89SAndroid Build Coastguard Worker     }
167*8d67ca89SAndroid Build Coastguard Worker 
168*8d67ca89SAndroid Build Coastguard Worker     for (size_t i = 0; i < entry->backtrace.size(); ++i) {
169*8d67ca89SAndroid Build Coastguard Worker       function_names[i] = entry->backtrace[i].function_name.c_str();
170*8d67ca89SAndroid Build Coastguard Worker       function_offsets[i] = entry->backtrace[i].function_offset;
171*8d67ca89SAndroid Build Coastguard Worker     }
172*8d67ca89SAndroid Build Coastguard Worker 
173*8d67ca89SAndroid Build Coastguard Worker     bool should_continue =
174*8d67ca89SAndroid Build Coastguard Worker         callback(fd, function_names, function_offsets, entry->backtrace.size(), arg);
175*8d67ca89SAndroid Build Coastguard Worker 
176*8d67ca89SAndroid Build Coastguard Worker     entry->mutex.unlock();
177*8d67ca89SAndroid Build Coastguard Worker 
178*8d67ca89SAndroid Build Coastguard Worker     if (!should_continue) {
179*8d67ca89SAndroid Build Coastguard Worker       break;
180*8d67ca89SAndroid Build Coastguard Worker     }
181*8d67ca89SAndroid Build Coastguard Worker   }
182*8d67ca89SAndroid Build Coastguard Worker 
183*8d67ca89SAndroid Build Coastguard Worker   android_fdtrack_set_enabled(prev);
184*8d67ca89SAndroid Build Coastguard Worker }
185*8d67ca89SAndroid Build Coastguard Worker 
hash_stack(const char * const * function_names,const uint64_t * function_offsets,size_t stack_depth)186*8d67ca89SAndroid Build Coastguard Worker static size_t hash_stack(const char* const* function_names, const uint64_t* function_offsets,
187*8d67ca89SAndroid Build Coastguard Worker                          size_t stack_depth) {
188*8d67ca89SAndroid Build Coastguard Worker   size_t hash = 0;
189*8d67ca89SAndroid Build Coastguard Worker   for (size_t i = 0; i < stack_depth; ++i) {
190*8d67ca89SAndroid Build Coastguard Worker     // To future maintainers: if a libc++ update ever makes this invalid, replace this with +.
191*8d67ca89SAndroid Build Coastguard Worker     hash = std::__hash_combine(hash, std::hash<std::string_view>()(function_names[i]));
192*8d67ca89SAndroid Build Coastguard Worker     hash = std::__hash_combine(hash, std::hash<uint64_t>()(function_offsets[i]));
193*8d67ca89SAndroid Build Coastguard Worker   }
194*8d67ca89SAndroid Build Coastguard Worker   return hash;
195*8d67ca89SAndroid Build Coastguard Worker }
196*8d67ca89SAndroid Build Coastguard Worker 
fdtrack_dump_impl(bool fatal)197*8d67ca89SAndroid Build Coastguard Worker static void fdtrack_dump_impl(bool fatal) {
198*8d67ca89SAndroid Build Coastguard Worker   if (!installed) {
199*8d67ca89SAndroid Build Coastguard Worker     async_safe_format_log(ANDROID_LOG_INFO, "fdtrack", "fdtrack not installed");
200*8d67ca89SAndroid Build Coastguard Worker   } else {
201*8d67ca89SAndroid Build Coastguard Worker     async_safe_format_log(ANDROID_LOG_INFO, "fdtrack", "fdtrack dumping...");
202*8d67ca89SAndroid Build Coastguard Worker   }
203*8d67ca89SAndroid Build Coastguard Worker 
204*8d67ca89SAndroid Build Coastguard Worker   // If we're aborting, identify the most common stack in the hopes that it's the culprit,
205*8d67ca89SAndroid Build Coastguard Worker   // and emit that in the abort message so crash reporting can separate different fd leaks out.
206*8d67ca89SAndroid Build Coastguard Worker   // This is horrible and quadratic, but we need to avoid allocation since this can happen in
207*8d67ca89SAndroid Build Coastguard Worker   // response to a signal generated asynchronously. We're only going to dump 1k fds by default,
208*8d67ca89SAndroid Build Coastguard Worker   // and we're about to blow up the entire system, so this isn't too expensive.
209*8d67ca89SAndroid Build Coastguard Worker   struct StackInfo {
210*8d67ca89SAndroid Build Coastguard Worker     size_t hash = 0;
211*8d67ca89SAndroid Build Coastguard Worker     size_t count = 0;
212*8d67ca89SAndroid Build Coastguard Worker 
213*8d67ca89SAndroid Build Coastguard Worker     size_t stack_depth = 0;
214*8d67ca89SAndroid Build Coastguard Worker     const char* function_names[kStackDepth];
215*8d67ca89SAndroid Build Coastguard Worker     uint64_t function_offsets[kStackDepth];
216*8d67ca89SAndroid Build Coastguard Worker   };
217*8d67ca89SAndroid Build Coastguard Worker   struct StackList {
218*8d67ca89SAndroid Build Coastguard Worker     size_t count = 0;
219*8d67ca89SAndroid Build Coastguard Worker     std::array<StackInfo, 128> data;
220*8d67ca89SAndroid Build Coastguard Worker   };
221*8d67ca89SAndroid Build Coastguard Worker   static StackList stacks;
222*8d67ca89SAndroid Build Coastguard Worker 
223*8d67ca89SAndroid Build Coastguard Worker   fdtrack_iterate(
224*8d67ca89SAndroid Build Coastguard Worker       [](int fd, const char* const* function_names, const uint64_t* function_offsets,
225*8d67ca89SAndroid Build Coastguard Worker          size_t stack_depth, void* stacks_ptr) {
226*8d67ca89SAndroid Build Coastguard Worker         auto stacks = static_cast<StackList*>(stacks_ptr);
227*8d67ca89SAndroid Build Coastguard Worker         uint64_t fdsan_owner = android_fdsan_get_owner_tag(fd);
228*8d67ca89SAndroid Build Coastguard Worker         if (fdsan_owner != 0) {
229*8d67ca89SAndroid Build Coastguard Worker           async_safe_format_log(ANDROID_LOG_INFO, "fdtrack", "fd %d: (owner = 0x%" PRIx64 ")", fd,
230*8d67ca89SAndroid Build Coastguard Worker                                 fdsan_owner);
231*8d67ca89SAndroid Build Coastguard Worker         } else {
232*8d67ca89SAndroid Build Coastguard Worker           async_safe_format_log(ANDROID_LOG_INFO, "fdtrack", "fd %d: (unowned)", fd);
233*8d67ca89SAndroid Build Coastguard Worker         }
234*8d67ca89SAndroid Build Coastguard Worker 
235*8d67ca89SAndroid Build Coastguard Worker         for (size_t i = 0; i < stack_depth; ++i) {
236*8d67ca89SAndroid Build Coastguard Worker           async_safe_format_log(ANDROID_LOG_INFO, "fdtrack", "  %zu: %s+%" PRIu64, i,
237*8d67ca89SAndroid Build Coastguard Worker                                 function_names[i], function_offsets[i]);
238*8d67ca89SAndroid Build Coastguard Worker         }
239*8d67ca89SAndroid Build Coastguard Worker 
240*8d67ca89SAndroid Build Coastguard Worker         if (stacks) {
241*8d67ca89SAndroid Build Coastguard Worker           size_t hash = hash_stack(function_names, function_offsets, stack_depth);
242*8d67ca89SAndroid Build Coastguard Worker           bool found_stack = false;
243*8d67ca89SAndroid Build Coastguard Worker           for (size_t i = 0; i < stacks->count; ++i) {
244*8d67ca89SAndroid Build Coastguard Worker             if (stacks->data[i].hash == hash) {
245*8d67ca89SAndroid Build Coastguard Worker               ++stacks->data[i].count;
246*8d67ca89SAndroid Build Coastguard Worker               found_stack = true;
247*8d67ca89SAndroid Build Coastguard Worker               break;
248*8d67ca89SAndroid Build Coastguard Worker             }
249*8d67ca89SAndroid Build Coastguard Worker           }
250*8d67ca89SAndroid Build Coastguard Worker 
251*8d67ca89SAndroid Build Coastguard Worker           if (!found_stack) {
252*8d67ca89SAndroid Build Coastguard Worker             if (stacks->count < stacks->data.size()) {
253*8d67ca89SAndroid Build Coastguard Worker               auto& stack = stacks->data[stacks->count++];
254*8d67ca89SAndroid Build Coastguard Worker               stack.hash = hash;
255*8d67ca89SAndroid Build Coastguard Worker               stack.count = 1;
256*8d67ca89SAndroid Build Coastguard Worker               stack.stack_depth = stack_depth;
257*8d67ca89SAndroid Build Coastguard Worker               for (size_t i = 0; i < stack_depth; ++i) {
258*8d67ca89SAndroid Build Coastguard Worker                 stack.function_names[i] = function_names[i];
259*8d67ca89SAndroid Build Coastguard Worker                 stack.function_offsets[i] = function_offsets[i];
260*8d67ca89SAndroid Build Coastguard Worker               }
261*8d67ca89SAndroid Build Coastguard Worker             }
262*8d67ca89SAndroid Build Coastguard Worker           }
263*8d67ca89SAndroid Build Coastguard Worker         }
264*8d67ca89SAndroid Build Coastguard Worker 
265*8d67ca89SAndroid Build Coastguard Worker         return true;
266*8d67ca89SAndroid Build Coastguard Worker       },
267*8d67ca89SAndroid Build Coastguard Worker       fatal ? &stacks : nullptr);
268*8d67ca89SAndroid Build Coastguard Worker 
269*8d67ca89SAndroid Build Coastguard Worker   if (fatal) {
270*8d67ca89SAndroid Build Coastguard Worker     // Find the most common stack.
271*8d67ca89SAndroid Build Coastguard Worker     size_t max = 0;
272*8d67ca89SAndroid Build Coastguard Worker     size_t total = 0;
273*8d67ca89SAndroid Build Coastguard Worker     StackInfo* stack = nullptr;
274*8d67ca89SAndroid Build Coastguard Worker     for (size_t i = 0; i < stacks.count; ++i) {
275*8d67ca89SAndroid Build Coastguard Worker       total += stacks.data[i].count;
276*8d67ca89SAndroid Build Coastguard Worker       if (stacks.data[i].count > max) {
277*8d67ca89SAndroid Build Coastguard Worker         stack = &stacks.data[i];
278*8d67ca89SAndroid Build Coastguard Worker         max = stack->count;
279*8d67ca89SAndroid Build Coastguard Worker       }
280*8d67ca89SAndroid Build Coastguard Worker     }
281*8d67ca89SAndroid Build Coastguard Worker 
282*8d67ca89SAndroid Build Coastguard Worker     static char buf[1024];
283*8d67ca89SAndroid Build Coastguard Worker 
284*8d67ca89SAndroid Build Coastguard Worker     if (!stack) {
285*8d67ca89SAndroid Build Coastguard Worker       async_safe_format_buffer(buf, sizeof(buf),
286*8d67ca89SAndroid Build Coastguard Worker                                "aborting due to fd leak: see \"open files\" in the tombstone; "
287*8d67ca89SAndroid Build Coastguard Worker                                "no stacks?!");
288*8d67ca89SAndroid Build Coastguard Worker     } else {
289*8d67ca89SAndroid Build Coastguard Worker       char* p = buf;
290*8d67ca89SAndroid Build Coastguard Worker       p += async_safe_format_buffer(buf, sizeof(buf),
291*8d67ca89SAndroid Build Coastguard Worker                                     "aborting due to fd leak: see \"open files\" in the tombstone; "
292*8d67ca89SAndroid Build Coastguard Worker                                     "most common stack (%zu/%zu) is\n", max, total);
293*8d67ca89SAndroid Build Coastguard Worker 
294*8d67ca89SAndroid Build Coastguard Worker       for (size_t i = 0; i < stack->stack_depth; ++i) {
295*8d67ca89SAndroid Build Coastguard Worker         ssize_t bytes_left = buf + sizeof(buf) - p;
296*8d67ca89SAndroid Build Coastguard Worker         if (bytes_left > 0) {
297*8d67ca89SAndroid Build Coastguard Worker           p += async_safe_format_buffer(p, buf + sizeof(buf) - p, "  %zu: %s+%" PRIu64 "\n", i,
298*8d67ca89SAndroid Build Coastguard Worker                                         stack->function_names[i], stack->function_offsets[i]);
299*8d67ca89SAndroid Build Coastguard Worker         }
300*8d67ca89SAndroid Build Coastguard Worker       }
301*8d67ca89SAndroid Build Coastguard Worker     }
302*8d67ca89SAndroid Build Coastguard Worker 
303*8d67ca89SAndroid Build Coastguard Worker     android_set_abort_message(buf);
304*8d67ca89SAndroid Build Coastguard Worker 
305*8d67ca89SAndroid Build Coastguard Worker     // Abort on a different thread to avoid ART dumping runtime stacks.
306*8d67ca89SAndroid Build Coastguard Worker     std::thread([]() { abort(); }).join();
307*8d67ca89SAndroid Build Coastguard Worker   }
308*8d67ca89SAndroid Build Coastguard Worker }
309*8d67ca89SAndroid Build Coastguard Worker 
fdtrack_dump()310*8d67ca89SAndroid Build Coastguard Worker void fdtrack_dump() {
311*8d67ca89SAndroid Build Coastguard Worker   fdtrack_dump_impl(false);
312*8d67ca89SAndroid Build Coastguard Worker }
313*8d67ca89SAndroid Build Coastguard Worker 
fdtrack_dump_fatal()314*8d67ca89SAndroid Build Coastguard Worker void fdtrack_dump_fatal() {
315*8d67ca89SAndroid Build Coastguard Worker   fdtrack_dump_impl(true);
316*8d67ca89SAndroid Build Coastguard Worker }
317