• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2019 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "base/debug/task_trace.h"
6 
7 #include "base/ranges/algorithm.h"
8 #include "build/build_config.h"
9 
10 #if BUILDFLAG(IS_ANDROID)
11 #include <android/log.h>
12 #endif  // BUILDFLAG(IS_ANDROID)
13 
14 #include <iostream>
15 #include <sstream>
16 
17 #if BUILDFLAG(IS_ANDROID)
18 #include "base/no_destructor.h"
19 #endif
20 
21 #include "base/pending_task.h"
22 #include "base/task/common/task_annotator.h"
23 
24 namespace base {
25 namespace debug {
26 namespace {
27 #if BUILDFLAG(IS_ANDROID)
28 // Android sends stdout and stderr to /dev/null; logging should be done through
29 // the __android_log_write() function. Here we create an override of
30 // std::stringbuf that writes to the Android log.
31 class AndroidErrBuffer : public std::stringbuf {
32  protected:
sync()33   int sync() override {
34     __android_log_write(ANDROID_LOG_ERROR, "chromium", str().c_str());
35     return 0;
36   }
37 };
38 
DefaultOutputStream()39 std::ostream& DefaultOutputStream() {
40   static NoDestructor<AndroidErrBuffer> buf;
41   static NoDestructor<std::ostream> out(buf.get());
42   return *out;
43 }
44 #else
45 // Use stderr by default.
46 std::ostream& DefaultOutputStream() {
47   return std::cerr;
48 }
49 #endif  // BUILDFLAG(IS_ANDROID)
50 }  // namespace
51 
TaskTrace()52 TaskTrace::TaskTrace() {
53   const PendingTask* current_task = TaskAnnotator::CurrentTaskForThread();
54   if (!current_task)
55     return;
56   std::array<const void*, PendingTask::kTaskBacktraceLength + 1> task_trace;
57   task_trace[0] = current_task->posted_from.program_counter();
58   ranges::copy(current_task->task_backtrace, task_trace.begin() + 1);
59   size_t length = 0;
60   while (length < task_trace.size() && task_trace[length])
61     ++length;
62   if (length == 0)
63     return;
64   stack_trace_.emplace(task_trace.data(), length);
65   trace_overflow_ = current_task->task_backtrace_overflow;
66 }
67 
empty() const68 bool TaskTrace::empty() const {
69   return !stack_trace_.has_value();
70 }
71 
Print() const72 void TaskTrace::Print() const {
73   OutputToStream(&DefaultOutputStream());
74 }
75 
OutputToStream(std::ostream * os) const76 void TaskTrace::OutputToStream(std::ostream* os) const {
77   *os << "Task trace:" << std::endl;
78   if (!stack_trace_) {
79     *os << "No active task.";
80     return;
81   }
82   *os << *stack_trace_;
83   if (trace_overflow_) {
84     *os << "Task trace buffer limit hit, update "
85            "PendingTask::kTaskBacktraceLength to increase."
86         << std::endl;
87   }
88 }
89 
ToString() const90 std::string TaskTrace::ToString() const {
91   std::stringstream stream;
92   OutputToStream(&stream);
93   return stream.str();
94 }
95 
GetAddresses(span<const void * > addresses) const96 size_t TaskTrace::GetAddresses(span<const void*> addresses) const {
97   size_t count = 0;
98   if (empty()) {
99     return count;
100   }
101   const void* const* current_addresses = stack_trace_->Addresses(&count);
102   for (size_t i = 0; i < count && i < addresses.size(); ++i) {
103     addresses[i] = current_addresses[i];
104   }
105   return count;
106 }
107 
operator <<(std::ostream & os,const TaskTrace & task_trace)108 std::ostream& operator<<(std::ostream& os, const TaskTrace& task_trace) {
109   task_trace.OutputToStream(&os);
110   return os;
111 }
112 
113 }  // namespace debug
114 }  // namespace base
115