-
Notifications
You must be signed in to change notification settings - Fork 36
/
Copy pathcrash_history.cc
134 lines (111 loc) · 3.15 KB
/
crash_history.cc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
#include "crash_history.h"
#include <ctime>
#include <iostream>
#include <deque>
#include <fstream>
#include <limits>
#include <sstream>
#include <string>
#include <vector>
#include "build/build_config.h"
#include "util/string/split_string.h"
namespace crashpad {
namespace backtrace {
namespace crash_history {
static auto CsvFileName(const base::FilePath& database)
{
#if BUILDFLAG(IS_WIN)
return database.value() + L"/crash_history.csv";
#else
return database.value() + "/crash_history.csv";
#endif
}
static std::vector<RunEntry>
LoadCrashData(const base::FilePath& database, int max_entries = std::numeric_limits<int>::max())
{
std::vector<RunEntry> entries;
auto csv_file = CsvFileName(database);
std::ifstream f(csv_file);
for (std::string line; std::getline(f, line);) {
if (line.size() && line.back() == '\n')
line.pop_back();
auto split = SplitString(line, ',');
if (split.size() < 3)
continue;
RunEntry entry;
if (!entry.uuid.InitializeFromString(split[0]))
continue;
entry.crashed = split[1] == "1";
try {
entry.start_time = std::stoll(split[2]);
if (split.size() > 3) {
entry.crash_time = std::stoll(split[3]);
}
} catch (const std::invalid_argument& arg) {
continue;
}
entries.push_back(std::move(entry));
}
if (entries.size() > max_entries)
entries.erase(entries.begin(), entries.end() - max_entries);
return entries;
}
static bool WriteCrashData(const base::FilePath& database,
const std::vector<RunEntry>& data)
{
std::deque<std::string> lines;
std::ofstream f(CsvFileName(database), std::ios::trunc);
if (!f)
return false;
for (const auto& entry : data) {
std::stringstream str;
str << entry.uuid.ToString() << ','
<< (entry.crashed ? "1" : "0") << ','
<< entry.start_time;
if (entry.crash_time)
str << ',' << entry.crash_time.value();
str << '\n';
auto line = str.str();
if (line.size()) {
if (&entry == &data.back())
line.pop_back();
}
f << line;
}
return true;
}
bool Append(const base::FilePath& database, UUID uuid, int max_entries)
{
auto entries = LoadCrashData(database, max_entries - 1);
time_t current_time = time(nullptr);
RunEntry entry = {uuid, false, current_time, std::nullopt};
entries.push_back(std::move(entry));
return WriteCrashData(database, entries);
}
bool SetCrashed(const base::FilePath& database, UUID uuid)
{
auto entries = LoadCrashData(database);
bool success{};
std::string uuid_str = uuid.ToString();
for (auto& entry : entries) {
if (entry.uuid == uuid) {
success = true;
entry.crashed = true;
entry.crash_time = time(nullptr);
break;
}
}
return success && WriteCrashData(database, entries);
}
int ConsecutiveCrashesCount(const base::FilePath& database)
{
auto entries = LoadCrashData(database);
auto is_crashing = [](const auto& entry) {
return !entry.crashed;
};
auto it = std::find_if(entries.rbegin(), entries.rend(), is_crashing);
return std::distance(entries.rbegin(), it);
}
} // namespace crash_history
} // namespace backtrace
} // namespace crashpad