forked from chromium/chromium
-
Notifications
You must be signed in to change notification settings - Fork 0
/
stability_paths.cc
159 lines (129 loc) · 5.6 KB
/
stability_paths.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
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/browser_watcher/stability_paths.h"
#if defined(OS_WIN)
#include <windows.h>
#endif // defined(OS_WIN)
#include <memory>
#include <string>
#include <utility>
#include "base/debug/activity_tracker.h"
#include "base/feature_list.h"
#include "base/files/file.h"
#include "base/files/file_enumerator.h"
#include "base/files/memory_mapped_file.h"
#include "base/metrics/persistent_memory_allocator.h"
#include "base/strings/stringprintf.h"
#include "base/time/time.h"
#include "components/browser_watcher/features.h"
#include "components/browser_watcher/stability_metrics.h"
#if defined(OS_WIN)
#include "third_party/crashpad/crashpad/util/misc/time.h"
namespace browser_watcher {
using base::FilePath;
using base::FilePersistentMemoryAllocator;
using base::MemoryMappedFile;
using base::PersistentMemoryAllocator;
namespace {
bool GetCreationTime(const base::Process& process, FILETIME* creation_time) {
FILETIME ignore;
return ::GetProcessTimes(process.Handle(), creation_time, &ignore, &ignore,
&ignore) != 0;
}
bool SetPmaFileDeleted(const base::FilePath& file_path) {
// Map the file read-write so it can guarantee consistency between
// the analyzer and any trackers that may still be active.
std::unique_ptr<MemoryMappedFile> mmfile(new MemoryMappedFile());
if (!mmfile->Initialize(file_path, MemoryMappedFile::READ_WRITE))
return false;
if (!FilePersistentMemoryAllocator::IsFileAcceptable(*mmfile, true))
return false;
FilePersistentMemoryAllocator allocator(std::move(mmfile), 0, 0,
base::StringPiece(), true);
allocator.SetMemoryState(PersistentMemoryAllocator::MEMORY_DELETED);
return true;
}
} // namespace
FilePath GetStabilityDir(const FilePath& user_data_dir) {
return user_data_dir.AppendASCII("Stability");
}
FilePath GetStabilityFileForProcess(base::ProcessId pid,
timeval creation_time,
const FilePath& user_data_dir) {
FilePath stability_dir = GetStabilityDir(user_data_dir);
constexpr uint64_t kMicrosecondsPerSecond = static_cast<uint64_t>(1E6);
int64_t creation_time_us =
creation_time.tv_sec * kMicrosecondsPerSecond + creation_time.tv_usec;
std::string file_name =
base::StringPrintf("%" CrPRIdPid "-%lld", pid, creation_time_us);
return stability_dir.AppendASCII(file_name).AddExtension(
base::PersistentMemoryAllocator::kFileExtension);
}
bool GetStabilityFileForProcess(const base::Process& process,
const FilePath& user_data_dir,
FilePath* file_path) {
DCHECK(file_path);
FILETIME creation_time;
if (!GetCreationTime(process, &creation_time))
return false;
// We rely on Crashpad's conversion to ensure the resulting filename is the
// same as on crash, when the creation time is obtained via Crashpad.
*file_path = GetStabilityFileForProcess(
process.Pid(), crashpad::FiletimeToTimevalEpoch(creation_time),
user_data_dir);
return true;
}
FilePath::StringType GetStabilityFilePattern() {
return FilePath::StringType(FILE_PATH_LITERAL("*-*")) +
base::PersistentMemoryAllocator::kFileExtension;
}
std::vector<FilePath> GetStabilityFiles(
const FilePath& stability_dir,
const FilePath::StringType& stability_file_pattern,
const std::set<FilePath>& excluded_stability_files) {
DCHECK_NE(true, stability_dir.empty());
DCHECK_NE(true, stability_file_pattern.empty());
std::vector<FilePath> paths;
base::FileEnumerator enumerator(stability_dir, false /* recursive */,
base::FileEnumerator::FILES,
stability_file_pattern);
FilePath path;
for (path = enumerator.Next(); !path.empty(); path = enumerator.Next()) {
if (excluded_stability_files.find(path) == excluded_stability_files.end())
paths.push_back(path);
}
return paths;
}
void MarkOwnStabilityFileDeleted(const base::FilePath& user_data_dir) {
base::debug::GlobalActivityTracker* global_tracker =
base::debug::GlobalActivityTracker::Get();
if (!global_tracker)
return; // No stability instrumentation.
global_tracker->MarkDeleted();
LogStabilityRecordEvent(StabilityRecordEvent::kMarkDeleted);
// Open (with delete) and then immediately close the file by going out of
// scope. This should cause the stability debugging file to be deleted prior
// to the next execution.
base::FilePath stability_file;
if (!GetStabilityFileForProcess(base::Process::Current(), user_data_dir,
&stability_file)) {
return;
}
LogStabilityRecordEvent(StabilityRecordEvent::kMarkDeletedGotFile);
base::File deleter(stability_file, base::File::FLAG_OPEN |
base::File::FLAG_READ |
base::File::FLAG_DELETE_ON_CLOSE);
if (!deleter.IsValid())
LogStabilityRecordEvent(StabilityRecordEvent::kOpenForDeleteFailed);
}
void MarkStabilityFileDeletedOnCrash(const base::FilePath& file_path) {
if (!SetPmaFileDeleted(file_path))
LogCollectOnCrashEvent(CollectOnCrashEvent::kPmaSetDeletedFailed);
base::File deleter(file_path, base::File::FLAG_OPEN | base::File::FLAG_READ |
base::File::FLAG_DELETE_ON_CLOSE);
if (!deleter.IsValid())
LogCollectOnCrashEvent(CollectOnCrashEvent::kOpenForDeleteFailed);
}
} // namespace browser_watcher
#endif // defined(OS_WIN)