• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2013 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/dump_without_crashing.h"
6 
7 #include "base/check.h"
8 #include "base/metrics/histogram_functions.h"
9 #include "base/no_destructor.h"
10 #include "base/synchronization/lock.h"
11 #include "base/trace_event/base_tracing.h"
12 
13 namespace {
14 
15 // Pointer to the function that's called by DumpWithoutCrashing* to dump the
16 // process's memory.
17 void(CDECL* dump_without_crashing_function_)() = nullptr;
18 
19 template <typename Map, typename Key>
ShouldDump(Map & map,Key & key,base::TimeDelta time_between_dumps)20 bool ShouldDump(Map& map, Key& key, base::TimeDelta time_between_dumps) {
21   static base::NoDestructor<base::Lock> lock;
22   base::AutoLock auto_lock(*lock);
23   base::TimeTicks now = base::TimeTicks::Now();
24   auto [it, inserted] = map.emplace(key, now);
25   if (inserted) {
26     return true;
27   }
28 
29   if (now - it->second >= time_between_dumps) {
30     it->second = now;
31     return true;
32   }
33   return false;
34 }
35 
36 // Map used to store the most recent time a location called
37 // ShouldDumpWithoutCrashWithLocation.
LocationToTimestampMap()38 std::map<base::Location, base::TimeTicks>& LocationToTimestampMap() {
39   static base::NoDestructor<std::map<base::Location, base::TimeTicks>>
40       location_to_timestamp;
41   return *location_to_timestamp;
42 }
43 
44 // Map used to store the most recent time a pair of location and
45 // unique_identifier called ShouldDumpWithoutCrashWithLocationAndUniqueId.
46 std::map<std::pair<base::Location, size_t>, base::TimeTicks>&
LocationAndUniqueIdentifierToTimestampMap()47 LocationAndUniqueIdentifierToTimestampMap() {
48   static base::NoDestructor<
49       std::map<std::pair<base::Location, size_t>, base::TimeTicks>>
50       location_and_unique_identifier_to_timestamp;
51   return *location_and_unique_identifier_to_timestamp;
52 }
53 
54 // This function takes `location` and `time_between_dumps` as an input
55 // and checks if DumpWithoutCrashing() meets the requirements to take the dump
56 // or not.
ShouldDumpWithoutCrashWithLocation(const base::Location & location,base::TimeDelta time_between_dumps)57 bool ShouldDumpWithoutCrashWithLocation(const base::Location& location,
58                                         base::TimeDelta time_between_dumps) {
59   return ShouldDump(LocationToTimestampMap(), location, time_between_dumps);
60 }
61 
62 // Pair of `location` and `unique_identifier` creates a unique key and checks
63 // if DumpWithoutCrashingWithUniqueId() meets the requirements to take dump or
64 // not.
ShouldDumpWithoutCrashWithLocationAndUniqueId(size_t unique_identifier,const base::Location & location,base::TimeDelta time_between_dumps)65 bool ShouldDumpWithoutCrashWithLocationAndUniqueId(
66     size_t unique_identifier,
67     const base::Location& location,
68     base::TimeDelta time_between_dumps) {
69   std::pair<base::Location, size_t> key(location, unique_identifier);
70   return ShouldDump(LocationAndUniqueIdentifierToTimestampMap(), key,
71                     time_between_dumps);
72 }
73 
74 }  // namespace
75 
76 namespace base {
77 
78 namespace debug {
79 
DumpWithoutCrashingUnthrottled()80 bool DumpWithoutCrashingUnthrottled() {
81   TRACE_EVENT0("base", "DumpWithoutCrashingUnthrottled");
82   if (dump_without_crashing_function_) {
83     (*dump_without_crashing_function_)();
84     return true;
85   }
86   return false;
87 }
88 
DumpWithoutCrashing(const base::Location & location,base::TimeDelta time_between_dumps)89 bool DumpWithoutCrashing(const base::Location& location,
90                          base::TimeDelta time_between_dumps) {
91   TRACE_EVENT0("base", "DumpWithoutCrashing");
92   if (dump_without_crashing_function_ &&
93       ShouldDumpWithoutCrashWithLocation(location, time_between_dumps)) {
94     (*dump_without_crashing_function_)();
95     base::UmaHistogramEnumeration("Stability.DumpWithoutCrashingStatus",
96                                   DumpWithoutCrashingStatus::kUploaded);
97     return true;
98   }
99   base::UmaHistogramEnumeration("Stability.DumpWithoutCrashingStatus",
100                                 DumpWithoutCrashingStatus::kThrottled);
101   return false;
102 }
103 
DumpWithoutCrashingWithUniqueId(size_t unique_identifier,const base::Location & location,base::TimeDelta time_between_dumps)104 bool DumpWithoutCrashingWithUniqueId(size_t unique_identifier,
105                                      const base::Location& location,
106                                      base::TimeDelta time_between_dumps) {
107   TRACE_EVENT0("base", "DumpWithoutCrashingWithUniqueId");
108   if (dump_without_crashing_function_ &&
109       ShouldDumpWithoutCrashWithLocationAndUniqueId(unique_identifier, location,
110                                                     time_between_dumps)) {
111     (*dump_without_crashing_function_)();
112     base::UmaHistogramEnumeration("Stability.DumpWithoutCrashingStatus",
113                                   DumpWithoutCrashingStatus::kUploaded);
114     return true;
115   }
116   base::UmaHistogramEnumeration("Stability.DumpWithoutCrashingStatus",
117                                 DumpWithoutCrashingStatus::kThrottled);
118   return false;
119 }
120 
SetDumpWithoutCrashingFunction(void (CDECL * function)())121 void SetDumpWithoutCrashingFunction(void (CDECL *function)()) {
122 #if !defined(COMPONENT_BUILD)
123   // In component builds, the same base is shared between modules
124   // so might be initialized several times. However in non-
125   // component builds this should never happen.
126   DCHECK(!dump_without_crashing_function_ || !function);
127 #endif
128   dump_without_crashing_function_ = function;
129 }
130 
ClearMapsForTesting()131 void ClearMapsForTesting() {
132   LocationToTimestampMap().clear();
133   LocationAndUniqueIdentifierToTimestampMap().clear();
134 }
135 
136 }  // namespace debug
137 }  // namespace base
138