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