OLD | NEW |
---|---|
1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chromecast/crash/linux/synchronized_minidump_manager.h" | 5 #include "chromecast/crash/linux/synchronized_minidump_manager.h" |
6 | 6 |
7 #include <dirent.h> | |
8 #include <errno.h> | 7 #include <errno.h> |
9 #include <fcntl.h> | |
10 #include <stddef.h> | 8 #include <stddef.h> |
11 #include <stdint.h> | 9 #include <stdint.h> |
12 #include <string.h> | 10 #include <string.h> |
13 #include <sys/file.h> | |
14 #include <sys/stat.h> | |
15 #include <sys/types.h> | |
16 #include <time.h> | |
17 #include <unistd.h> | |
18 | 11 |
19 #include <utility> | 12 #include <utility> |
20 | 13 |
21 #include "base/files/dir_reader_posix.h" | 14 #include "base/files/dir_reader_posix.h" |
22 #include "base/files/file_util.h" | 15 #include "base/files/file_util.h" |
23 #include "base/logging.h" | 16 #include "base/logging.h" |
24 #include "base/memory/ptr_util.h" | 17 #include "base/memory/ptr_util.h" |
18 #include "base/strings/string_number_conversions.h" | |
25 #include "base/strings/string_split.h" | 19 #include "base/strings/string_split.h" |
26 #include "base/strings/stringprintf.h" | 20 #include "base/strings/stringprintf.h" |
21 #include "chromecast/base/file_utils.h" | |
27 #include "chromecast/base/path_utils.h" | 22 #include "chromecast/base/path_utils.h" |
28 #include "chromecast/base/serializers.h" | 23 #include "chromecast/base/serializers.h" |
29 #include "chromecast/crash/linux/dump_info.h" | 24 #include "chromecast/crash/linux/dump_info.h" |
30 | 25 |
31 // if |cond| is false, returns |retval|. | 26 // if |cond| is false, returns |retval|. |
32 #define RCHECK(cond, retval) \ | 27 #define RCHECK(cond, retval) \ |
33 do { \ | 28 do { \ |
34 if (!(cond)) { \ | 29 if (!(cond)) { \ |
35 return (retval); \ | 30 return (retval); \ |
36 } \ | 31 } \ |
37 } while (0) | 32 } while (0) |
38 | 33 |
39 namespace chromecast { | 34 namespace chromecast { |
40 | 35 |
41 namespace { | 36 namespace { |
42 | 37 |
43 const mode_t kDirMode = 0770; | |
44 const mode_t kFileMode = 0660; | |
45 const char kLockfileName[] = "lockfile"; | 38 const char kLockfileName[] = "lockfile"; |
46 const char kMetadataName[] = "metadata"; | 39 const char kMetadataName[] = "metadata"; |
47 const char kMinidumpsDir[] = "minidumps"; | 40 const char kMinidumpsDir[] = "minidumps"; |
48 | 41 |
49 const char kLockfileRatelimitKey[] = "ratelimit"; | 42 const char kLockfileRatelimitKey[] = "ratelimit"; |
50 const char kLockfileRatelimitPeriodStartKey[] = "period_start"; | 43 const char kLockfileRatelimitPeriodStartKey[] = "period_start"; |
51 const char kLockfileRatelimitPeriodDumpsKey[] = "period_dumps"; | 44 const char kLockfileRatelimitPeriodDumpsKey[] = "period_dumps"; |
52 const std::size_t kLockfileNumRatelimitParams = 2; | 45 const uint64_t kLockfileNumRatelimitParams = 2; |
53 | 46 |
54 // Gets the ratelimit parameter dictionary given a deserialized |metadata|. | 47 // Gets the ratelimit parameter dictionary given a deserialized |metadata|. |
55 // Returns nullptr if invalid. | 48 // Returns nullptr if invalid. |
56 base::DictionaryValue* GetRatelimitParams(base::Value* metadata) { | 49 base::DictionaryValue* GetRatelimitParams(base::Value* metadata) { |
57 base::DictionaryValue* dict; | 50 base::DictionaryValue* dict; |
58 base::DictionaryValue* ratelimit_params; | 51 base::DictionaryValue* ratelimit_params; |
59 if (!metadata || !metadata->GetAsDictionary(&dict) || | 52 if (!metadata || !metadata->GetAsDictionary(&dict) || |
60 !dict->GetDictionary(kLockfileRatelimitKey, &ratelimit_params)) { | 53 !dict->GetDictionary(kLockfileRatelimitKey, &ratelimit_params)) { |
61 return nullptr; | 54 return nullptr; |
62 } | 55 } |
63 | 56 |
64 return ratelimit_params; | 57 return ratelimit_params; |
65 } | 58 } |
66 | 59 |
67 // Returns the time of the current ratelimit period's start in |metadata|. | 60 // Returns the time of the current ratelimit period's start in |metadata|. |
68 // Returns (time_t)-1 if an error occurs. | 61 // Returns base::Time() if an error occurs. |
69 time_t GetRatelimitPeriodStart(base::Value* metadata) { | 62 base::Time GetRatelimitPeriodStart(base::Value* metadata) { |
70 time_t result = static_cast<time_t>(-1); | |
71 base::DictionaryValue* ratelimit_params = GetRatelimitParams(metadata); | 63 base::DictionaryValue* ratelimit_params = GetRatelimitParams(metadata); |
72 RCHECK(ratelimit_params, result); | 64 RCHECK(ratelimit_params, base::Time()); |
73 | 65 |
74 std::string period_start_str; | 66 double seconds; |
slan
2016/08/08 16:37:10
nit: init
ameyak
2016/08/08 18:00:43
Done.
| |
75 RCHECK(ratelimit_params->GetString(kLockfileRatelimitPeriodStartKey, | 67 RCHECK( |
76 &period_start_str), | 68 ratelimit_params->GetDouble(kLockfileRatelimitPeriodStartKey, &seconds), |
77 result); | 69 base::Time()); |
78 | 70 |
79 errno = 0; | 71 // Return value of 0 indicates "not initialized", so we need to explicitly |
80 result = static_cast<time_t>(strtoll(period_start_str.c_str(), nullptr, 0)); | 72 // check for it and return time_t = 0 equivalent. |
81 if (errno != 0) { | 73 return seconds ? base::Time::FromDoubleT(seconds) : base::Time::UnixEpoch(); |
82 return static_cast<time_t>(-1); | |
83 } | |
84 | |
85 return result; | |
86 } | 74 } |
87 | 75 |
88 // Sets the time of the current ratelimit period's start in |metadata| to | 76 // Sets the time of the current ratelimit period's start in |metadata| to |
89 // |period_start|. Returns 0 on success, < 0 on error. | 77 // |period_start|. Returns true on success, false on error. |
90 int SetRatelimitPeriodStart(base::Value* metadata, time_t period_start) { | 78 bool SetRatelimitPeriodStart(base::Value* metadata, base::Time period_start) { |
91 DCHECK_GE(period_start, 0); | 79 DCHECK(!period_start.is_null()); |
92 | 80 |
93 base::DictionaryValue* ratelimit_params = GetRatelimitParams(metadata); | 81 base::DictionaryValue* ratelimit_params = GetRatelimitParams(metadata); |
94 RCHECK(ratelimit_params, -1); | 82 RCHECK(ratelimit_params, false); |
95 | 83 |
96 std::string period_start_str = | 84 ratelimit_params->SetDouble(kLockfileRatelimitPeriodStartKey, |
97 base::StringPrintf("%lld", static_cast<long long>(period_start)); | 85 period_start.ToDoubleT()); |
98 ratelimit_params->SetString(kLockfileRatelimitPeriodStartKey, | 86 return true; |
99 period_start_str); | |
100 return 0; | |
101 } | 87 } |
102 | 88 |
103 // Gets the number of dumps added to |metadata| in the current ratelimit | 89 // Gets the number of dumps added to |metadata| in the current ratelimit |
104 // period. Returns < 0 on error. | 90 // period. Returns < 0 on error. |
105 int GetRatelimitPeriodDumps(base::Value* metadata) { | 91 int GetRatelimitPeriodDumps(base::Value* metadata) { |
106 int period_dumps = -1; | 92 int period_dumps = -1; |
107 | 93 |
108 base::DictionaryValue* ratelimit_params = GetRatelimitParams(metadata); | 94 base::DictionaryValue* ratelimit_params = GetRatelimitParams(metadata); |
109 if (!ratelimit_params || | 95 if (!ratelimit_params || |
110 !ratelimit_params->GetInteger(kLockfileRatelimitPeriodDumpsKey, | 96 !ratelimit_params->GetInteger(kLockfileRatelimitPeriodDumpsKey, |
111 &period_dumps)) { | 97 &period_dumps)) { |
112 return -1; | 98 return -1; |
113 } | 99 } |
114 | 100 |
115 return period_dumps; | 101 return period_dumps; |
116 } | 102 } |
117 | 103 |
118 // Sets the current ratelimit period's number of dumps in |metadata| to | 104 // Sets the current ratelimit period's number of dumps in |metadata| to |
119 // |period_dumps|. Returns 0 on success, < 0 on error. | 105 // |period_dumps|. Returns true on success, false on error. |
120 int SetRatelimitPeriodDumps(base::Value* metadata, int period_dumps) { | 106 bool SetRatelimitPeriodDumps(base::Value* metadata, int period_dumps) { |
121 DCHECK_GE(period_dumps, 0); | 107 DCHECK_GE(period_dumps, 0); |
122 | 108 |
123 base::DictionaryValue* ratelimit_params = GetRatelimitParams(metadata); | 109 base::DictionaryValue* ratelimit_params = GetRatelimitParams(metadata); |
124 RCHECK(ratelimit_params, -1); | 110 RCHECK(ratelimit_params, false); |
125 | 111 |
126 ratelimit_params->SetInteger(kLockfileRatelimitPeriodDumpsKey, period_dumps); | 112 ratelimit_params->SetInteger(kLockfileRatelimitPeriodDumpsKey, period_dumps); |
127 | 113 |
128 return 0; | 114 return true; |
129 } | 115 } |
130 | 116 |
131 // Returns true if |metadata| contains valid metadata, false otherwise. | 117 // Returns true if |metadata| contains valid metadata, false otherwise. |
132 bool ValidateMetadata(base::Value* metadata) { | 118 bool ValidateMetadata(base::Value* metadata) { |
133 RCHECK(metadata, false); | 119 RCHECK(metadata, false); |
134 | 120 |
135 // Validate ratelimit params | 121 // Validate ratelimit params |
136 base::DictionaryValue* ratelimit_params = GetRatelimitParams(metadata); | 122 base::DictionaryValue* ratelimit_params = GetRatelimitParams(metadata); |
137 | 123 |
138 return ratelimit_params && | 124 return ratelimit_params && |
139 ratelimit_params->size() == kLockfileNumRatelimitParams && | 125 ratelimit_params->size() == kLockfileNumRatelimitParams && |
140 GetRatelimitPeriodStart(metadata) >= 0 && | 126 !GetRatelimitPeriodStart(metadata).is_null() && |
141 GetRatelimitPeriodDumps(metadata) >= 0; | 127 GetRatelimitPeriodDumps(metadata) >= 0; |
142 } | 128 } |
143 | 129 |
144 } // namespace | 130 } // namespace |
145 | 131 |
146 // One day | 132 // One day |
147 const int SynchronizedMinidumpManager::kRatelimitPeriodSeconds = 24 * 3600; | 133 const int SynchronizedMinidumpManager::kRatelimitPeriodSeconds = 24 * 3600; |
148 const int SynchronizedMinidumpManager::kRatelimitPeriodMaxDumps = 100; | 134 const int SynchronizedMinidumpManager::kRatelimitPeriodMaxDumps = 100; |
149 | 135 |
150 SynchronizedMinidumpManager::SynchronizedMinidumpManager() | 136 SynchronizedMinidumpManager::SynchronizedMinidumpManager() |
151 : non_blocking_(false), | 137 : dump_path_(GetHomePathASCII(kMinidumpsDir)), |
152 dump_path_(GetHomePathASCII(kMinidumpsDir)), | |
153 lockfile_path_(dump_path_.Append(kLockfileName).value()), | 138 lockfile_path_(dump_path_.Append(kLockfileName).value()), |
154 metadata_path_(dump_path_.Append(kMetadataName).value()), | 139 metadata_path_(dump_path_.Append(kMetadataName).value()), |
155 lockfile_fd_(-1) { | 140 lockfile_fd_(-1) {} |
156 } | |
157 | 141 |
158 SynchronizedMinidumpManager::~SynchronizedMinidumpManager() { | 142 SynchronizedMinidumpManager::~SynchronizedMinidumpManager() { |
159 // Release the lock if held. | 143 // Release the lock if held. |
160 ReleaseLockFile(); | 144 ReleaseLockFile(); |
161 } | 145 } |
162 | 146 |
163 // TODO(slan): Move some of this pruning logic to ReleaseLockFile? | 147 // TODO(slan): Move some of this pruning logic to ReleaseLockFile? |
164 int SynchronizedMinidumpManager::GetNumDumps(bool delete_all_dumps) { | 148 int SynchronizedMinidumpManager::GetNumDumps(bool delete_all_dumps) { |
165 DIR* dirp; | |
166 struct dirent* dptr; | |
167 int num_dumps = 0; | 149 int num_dumps = 0; |
168 | 150 |
169 // folder does not exist | 151 base::DirReaderPosix reader(dump_path_.value().c_str()); |
170 dirp = opendir(dump_path_.value().c_str()); | 152 if (!reader.IsValid()) { |
171 if (dirp == NULL) { | |
172 LOG(ERROR) << "Unable to open directory " << dump_path_.value(); | 153 LOG(ERROR) << "Unable to open directory " << dump_path_.value(); |
173 return 0; | 154 return 0; |
174 } | 155 } |
175 | 156 |
176 while ((dptr = readdir(dirp)) != NULL) { | 157 while (reader.Next()) { |
177 struct stat buf; | 158 if (strcmp(reader.name(), ".") == 0 || strcmp(reader.name(), "..") == 0) |
178 const std::string file_fullname = dump_path_.value() + "/" + dptr->d_name; | |
179 if (lstat(file_fullname.c_str(), &buf) == -1 || !S_ISREG(buf.st_mode)) { | |
180 // if we cannot lstat this file, it is probably bad, so skip | |
181 // if the file is not regular, skip | |
182 continue; | 159 continue; |
183 } | |
184 | 160 |
185 // 'lockfile' and 'metadata' is not counted | 161 const base::FilePath dump_file(dump_path_.Append(reader.name())); |
186 if (lockfile_path_ != file_fullname && metadata_path_ != file_fullname) { | 162 // If file cannot be found, skip. |
163 if (!base::PathExists(dump_file)) | |
164 continue; | |
165 | |
166 // Do not count |lockfile_path_| and |metadata_path_|. | |
167 if (lockfile_path_ != dump_file && metadata_path_ != dump_file) { | |
187 ++num_dumps; | 168 ++num_dumps; |
188 if (delete_all_dumps) { | 169 if (delete_all_dumps) { |
189 LOG(INFO) << "Removing " << dptr->d_name | 170 LOG(INFO) << "Removing " << reader.name() |
190 << "which was not in the lockfile"; | 171 << "which was not in the lockfile"; |
191 if (remove(file_fullname.c_str()) < 0) { | 172 if (!base::DeleteFile(dump_file, false)) { |
192 LOG(INFO) << "remove failed. error " << strerror(errno); | 173 LOG(INFO) << "remove failed. error " << strerror(errno); |
slan
2016/08/08 16:37:11
PLOG
ameyak
2016/08/08 18:00:43
Done.
| |
193 } | 174 } |
194 } | 175 } |
195 } | 176 } |
196 } | 177 } |
197 | 178 |
198 closedir(dirp); | |
199 return num_dumps; | 179 return num_dumps; |
200 } | 180 } |
201 | 181 |
202 int SynchronizedMinidumpManager::AcquireLockAndDoWork() { | 182 bool SynchronizedMinidumpManager::AcquireLockAndDoWork() { |
203 int success = -1; | 183 bool success = false; |
204 if (AcquireLockFile() >= 0) { | 184 if (AcquireLockFile()) { |
205 success = DoWork(); | 185 success = DoWork(); |
206 ReleaseLockFile(); | 186 ReleaseLockFile(); |
207 } | 187 } |
208 return success; | 188 return success; |
209 } | 189 } |
210 | 190 |
211 int SynchronizedMinidumpManager::AcquireLockFile() { | 191 bool SynchronizedMinidumpManager::AcquireLockFile() { |
212 DCHECK_LT(lockfile_fd_, 0); | 192 DCHECK_LT(lockfile_fd_, 0); |
213 // Make the directory for the minidumps if it does not exist. | 193 // Make the directory for the minidumps if it does not exist. |
214 if (mkdir(dump_path_.value().c_str(), kDirMode) < 0 && errno != EEXIST) { | 194 base::File::Error error; |
215 LOG(ERROR) << "mkdir for " << dump_path_.value().c_str() | 195 if (!CreateDirectoryAndGetError(dump_path_, &error)) { |
216 << " failed. error = " << strerror(errno); | 196 LOG(ERROR) << "Failed to create directory " << dump_path_.value() |
217 return -1; | 197 << ". error = " << error; |
198 return false; | |
218 } | 199 } |
219 | 200 |
220 // Open the lockfile. Create it if it does not exist. | 201 // Open the lockfile. Create it if it does not exist. |
221 lockfile_fd_ = open(lockfile_path_.c_str(), O_RDWR | O_CREAT, kFileMode); | 202 base::File lockfile(lockfile_path_, base::File::FLAG_OPEN_ALWAYS); |
222 | 203 |
223 // If opening or creating the lockfile failed, we don't want to proceed | 204 // If opening or creating the lockfile failed, we don't want to proceed |
224 // with dump writing for fear of exhausting up system resources. | 205 // with dump writing for fear of exhausting up system resources. |
225 if (lockfile_fd_ < 0) { | 206 if (!lockfile.IsValid()) { |
226 LOG(ERROR) << "open lockfile failed " << lockfile_path_; | 207 LOG(ERROR) << "open lockfile failed " << lockfile_path_.value(); |
227 return -1; | 208 return false; |
228 } | 209 } |
229 | 210 |
230 // Acquire the lock on the file. Whether or not we are in non-blocking mode, | 211 if ((lockfile_fd_ = OpenAndLockFile(lockfile_path_)) < 0) { |
slan
2016/08/08 16:37:11
This sets lockfile_fd_ if it fails. That seems lik
ameyak
2016/08/08 18:00:43
OpenAndLockFile will return -1, which will assign
slan
2016/08/08 18:32:19
LGTM
| |
231 // flock failure means that we did not acquire it and this method should fail. | |
232 int operation_mode = non_blocking_ ? (LOCK_EX | LOCK_NB) : LOCK_EX; | |
233 if (flock(lockfile_fd_, operation_mode) < 0) { | |
234 ReleaseLockFile(); | 212 ReleaseLockFile(); |
235 LOG(INFO) << "flock lockfile failed, error = " << strerror(errno); | 213 return false; |
236 return -1; | |
237 } | 214 } |
238 | 215 |
239 // The lockfile is open and locked. Parse it to provide subclasses with a | 216 // The lockfile is open and locked. Parse it to provide subclasses with a |
240 // record of all the current dumps. | 217 // record of all the current dumps. |
241 if (ParseFiles() < 0) { | 218 if (!ParseFiles()) { |
242 LOG(ERROR) << "Lockfile did not parse correctly. "; | 219 LOG(ERROR) << "Lockfile did not parse correctly. "; |
243 if (InitializeFiles() < 0 || ParseFiles() < 0) { | 220 if (!InitializeFiles() || !ParseFiles()) { |
244 LOG(ERROR) << "Failed to create a new lock file!"; | 221 LOG(ERROR) << "Failed to create a new lock file!"; |
245 return -1; | 222 return false; |
246 } | 223 } |
247 } | 224 } |
248 | 225 |
249 DCHECK(dumps_); | 226 DCHECK(dumps_); |
250 DCHECK(metadata_); | 227 DCHECK(metadata_); |
251 | 228 |
252 // We successfully have acquired the lock. | 229 // We successfully have acquired the lock. |
253 return 0; | 230 return true; |
254 } | 231 } |
255 | 232 |
256 int SynchronizedMinidumpManager::ParseFiles() { | 233 bool SynchronizedMinidumpManager::ParseFiles() { |
257 DCHECK_GE(lockfile_fd_, 0); | 234 DCHECK_GE(lockfile_fd_, 0); |
258 DCHECK(!dumps_); | 235 DCHECK(!dumps_); |
259 DCHECK(!metadata_); | 236 DCHECK(!metadata_); |
260 | 237 |
261 std::string lockfile; | 238 std::string lockfile; |
262 RCHECK(ReadFileToString(base::FilePath(lockfile_path_), &lockfile), -1); | 239 RCHECK(ReadFileToString(lockfile_path_, &lockfile), false); |
263 | 240 |
264 std::vector<std::string> lines = base::SplitString( | 241 std::vector<std::string> lines = base::SplitString( |
265 lockfile, "\n", base::KEEP_WHITESPACE, base::SPLIT_WANT_NONEMPTY); | 242 lockfile, "\n", base::KEEP_WHITESPACE, base::SPLIT_WANT_NONEMPTY); |
266 | 243 |
267 std::unique_ptr<base::ListValue> dumps = | 244 std::unique_ptr<base::ListValue> dumps = |
268 base::WrapUnique(new base::ListValue()); | 245 base::WrapUnique(new base::ListValue()); |
269 | 246 |
270 // Validate dumps | 247 // Validate dumps |
271 for (const std::string& line : lines) { | 248 for (const std::string& line : lines) { |
272 if (line.size() == 0) | 249 if (line.size() == 0) |
273 continue; | 250 continue; |
274 std::unique_ptr<base::Value> dump_info = DeserializeFromJson(line); | 251 std::unique_ptr<base::Value> dump_info = DeserializeFromJson(line); |
275 DumpInfo info(dump_info.get()); | 252 DumpInfo info(dump_info.get()); |
276 RCHECK(info.valid(), -1); | 253 RCHECK(info.valid(), false); |
277 dumps->Append(std::move(dump_info)); | 254 dumps->Append(std::move(dump_info)); |
278 } | 255 } |
279 | 256 |
280 std::unique_ptr<base::Value> metadata = | 257 std::unique_ptr<base::Value> metadata = |
281 DeserializeJsonFromFile(base::FilePath(metadata_path_)); | 258 DeserializeJsonFromFile(metadata_path_); |
282 RCHECK(ValidateMetadata(metadata.get()), -1); | 259 RCHECK(ValidateMetadata(metadata.get()), false); |
283 | 260 |
284 dumps_ = std::move(dumps); | 261 dumps_ = std::move(dumps); |
285 metadata_ = std::move(metadata); | 262 metadata_ = std::move(metadata); |
286 return 0; | 263 return true; |
287 } | 264 } |
288 | 265 |
289 int SynchronizedMinidumpManager::WriteFiles(const base::ListValue* dumps, | 266 bool SynchronizedMinidumpManager::WriteFiles(const base::ListValue* dumps, |
290 const base::Value* metadata) { | 267 const base::Value* metadata) { |
291 DCHECK(dumps); | 268 DCHECK(dumps); |
292 DCHECK(metadata); | 269 DCHECK(metadata); |
293 std::string lockfile; | 270 std::string lockfile; |
294 | 271 |
295 for (const auto& elem : *dumps) { | 272 for (const auto& elem : *dumps) { |
296 std::unique_ptr<std::string> dump_info = SerializeToJson(*elem); | 273 std::unique_ptr<std::string> dump_info = SerializeToJson(*elem); |
297 RCHECK(dump_info, -1); | 274 RCHECK(dump_info, false); |
298 lockfile += *dump_info; | 275 lockfile += *dump_info; |
299 lockfile += "\n"; // Add line seperatators | 276 lockfile += "\n"; // Add line seperatators |
300 } | 277 } |
301 | 278 |
302 if (WriteFile(base::FilePath(lockfile_path_), | 279 if (WriteFile(lockfile_path_, lockfile.c_str(), lockfile.size()) < 0) { |
303 lockfile.c_str(), | 280 return false; |
304 lockfile.size()) < 0) { | |
305 return -1; | |
306 } | 281 } |
307 | 282 |
308 return SerializeJsonToFile(base::FilePath(metadata_path_), *metadata) ? 0 | 283 return SerializeJsonToFile(metadata_path_, *metadata); |
309 : -1; | |
310 } | 284 } |
311 | 285 |
312 int SynchronizedMinidumpManager::InitializeFiles() { | 286 bool SynchronizedMinidumpManager::InitializeFiles() { |
313 std::unique_ptr<base::DictionaryValue> metadata = | 287 std::unique_ptr<base::DictionaryValue> metadata = |
314 base::WrapUnique(new base::DictionaryValue()); | 288 base::WrapUnique(new base::DictionaryValue()); |
315 | 289 |
316 base::DictionaryValue* ratelimit_fields = new base::DictionaryValue(); | 290 base::DictionaryValue* ratelimit_fields = new base::DictionaryValue(); |
317 metadata->Set(kLockfileRatelimitKey, base::WrapUnique(ratelimit_fields)); | 291 metadata->Set(kLockfileRatelimitKey, base::WrapUnique(ratelimit_fields)); |
318 ratelimit_fields->SetString(kLockfileRatelimitPeriodStartKey, "0"); | 292 ratelimit_fields->SetDouble(kLockfileRatelimitPeriodStartKey, 0.0); |
319 ratelimit_fields->SetInteger(kLockfileRatelimitPeriodDumpsKey, 0); | 293 ratelimit_fields->SetInteger(kLockfileRatelimitPeriodDumpsKey, 0); |
320 | 294 |
321 std::unique_ptr<base::ListValue> dumps = | 295 std::unique_ptr<base::ListValue> dumps = |
322 base::WrapUnique(new base::ListValue()); | 296 base::WrapUnique(new base::ListValue()); |
323 | 297 |
324 return WriteFiles(dumps.get(), metadata.get()); | 298 return WriteFiles(dumps.get(), metadata.get()); |
325 } | 299 } |
326 | 300 |
327 int SynchronizedMinidumpManager::AddEntryToLockFile(const DumpInfo& dump_info) { | 301 bool SynchronizedMinidumpManager::AddEntryToLockFile( |
328 DCHECK_LE(0, lockfile_fd_); | 302 const DumpInfo& dump_info) { |
303 DCHECK_GE(lockfile_fd_, 0); | |
329 DCHECK(dumps_); | 304 DCHECK(dumps_); |
330 | 305 |
331 // Make sure dump_info is valid. | 306 // Make sure dump_info is valid. |
332 if (!dump_info.valid()) { | 307 if (!dump_info.valid()) { |
333 LOG(ERROR) << "Entry to be added is invalid"; | 308 LOG(ERROR) << "Entry to be added is invalid"; |
334 return -1; | 309 return false; |
335 } | 310 } |
336 | 311 |
337 dumps_->Append(dump_info.GetAsValue()); | 312 dumps_->Append(dump_info.GetAsValue()); |
338 | 313 return true; |
339 return 0; | |
340 } | 314 } |
341 | 315 |
342 int SynchronizedMinidumpManager::RemoveEntryFromLockFile(int index) { | 316 bool SynchronizedMinidumpManager::RemoveEntryFromLockFile(int index) { |
343 return dumps_->Remove(static_cast<size_t>(index), nullptr) ? 0 : -1; | 317 return dumps_->Remove(static_cast<uint64_t>(index), nullptr); |
344 } | 318 } |
345 | 319 |
346 void SynchronizedMinidumpManager::ReleaseLockFile() { | 320 void SynchronizedMinidumpManager::ReleaseLockFile() { |
347 // flock is associated with the fd entry in the open fd table, so closing | 321 // flock is associated with the fd entry in the open fd table, so closing |
348 // all fd's will release the lock. To be safe, we explicitly unlock. | 322 // all fd's will release the lock. To be safe, we explicitly unlock. |
349 if (lockfile_fd_ >= 0) { | 323 if (lockfile_fd_ >= 0) { |
350 if (dumps_) | 324 if (dumps_) |
351 WriteFiles(dumps_.get(), metadata_.get()); | 325 WriteFiles(dumps_.get(), metadata_.get()); |
352 | 326 |
353 flock(lockfile_fd_, LOCK_UN); | 327 chromecast::UnlockAndCloseFile(lockfile_fd_); |
slan
2016/08/08 16:37:10
nit: ns qualifier not needed.
ameyak
2016/08/08 18:00:43
Done.
| |
354 close(lockfile_fd_); | |
355 | |
356 // We may use this object again, so we should reset this. | |
357 lockfile_fd_ = -1; | 328 lockfile_fd_ = -1; |
358 } | 329 } |
359 | 330 |
360 dumps_.reset(); | 331 dumps_.reset(); |
361 metadata_.reset(); | 332 metadata_.reset(); |
362 } | 333 } |
363 | 334 |
364 ScopedVector<DumpInfo> SynchronizedMinidumpManager::GetDumps() { | 335 ScopedVector<DumpInfo> SynchronizedMinidumpManager::GetDumps() { |
365 ScopedVector<DumpInfo> dumps; | 336 ScopedVector<DumpInfo> dumps; |
366 | 337 |
367 for (const auto& elem : *dumps_) { | 338 for (const auto& elem : *dumps_) { |
368 dumps.push_back(new DumpInfo(elem.get())); | 339 dumps.push_back(new DumpInfo(elem.get())); |
369 } | 340 } |
370 | 341 |
371 return dumps; | 342 return dumps; |
372 } | 343 } |
373 | 344 |
374 int SynchronizedMinidumpManager::SetCurrentDumps( | 345 bool SynchronizedMinidumpManager::SetCurrentDumps( |
375 const ScopedVector<DumpInfo>& dumps) { | 346 const ScopedVector<DumpInfo>& dumps) { |
376 dumps_->Clear(); | 347 dumps_->Clear(); |
377 | 348 |
378 for (DumpInfo* dump : dumps) | 349 for (DumpInfo* dump : dumps) |
379 dumps_->Append(dump->GetAsValue()); | 350 dumps_->Append(dump->GetAsValue()); |
380 | 351 |
381 return 0; | 352 return true; |
382 } | 353 } |
383 | 354 |
384 int SynchronizedMinidumpManager::IncrementNumDumpsInCurrentPeriod() { | 355 bool SynchronizedMinidumpManager::IncrementNumDumpsInCurrentPeriod() { |
385 DCHECK(metadata_); | 356 DCHECK(metadata_); |
386 int last_dumps = GetRatelimitPeriodDumps(metadata_.get()); | 357 int last_dumps = GetRatelimitPeriodDumps(metadata_.get()); |
387 RCHECK(last_dumps >= 0, -1); | 358 RCHECK(last_dumps >= 0, false); |
388 | 359 |
389 return SetRatelimitPeriodDumps(metadata_.get(), last_dumps + 1); | 360 return SetRatelimitPeriodDumps(metadata_.get(), last_dumps + 1); |
390 } | 361 } |
391 | 362 |
392 bool SynchronizedMinidumpManager::CanUploadDump() { | 363 bool SynchronizedMinidumpManager::CanUploadDump() { |
393 time_t cur_time = time(nullptr); | 364 base::Time cur_time = base::Time::Now(); |
394 time_t period_start = GetRatelimitPeriodStart(metadata_.get()); | 365 base::Time period_start = GetRatelimitPeriodStart(metadata_.get()); |
395 int period_dumps_count = GetRatelimitPeriodDumps(metadata_.get()); | 366 int period_dumps_count = GetRatelimitPeriodDumps(metadata_.get()); |
396 | 367 |
397 // If we're in invalid state, or we passed the period, reset the ratelimit. | 368 // If we're in invalid state, or we passed the period, reset the ratelimit. |
398 // When the device reboots, |cur_time| may be incorrectly reported to be a | 369 // When the device reboots, |cur_time| may be incorrectly reported to be a |
399 // very small number for a short period of time. So only consider | 370 // very small number for a short period of time. So only consider |
400 // |period_start| invalid when |cur_time| is less if |cur_time| is not very | 371 // |period_start| invalid when |cur_time| is less if |cur_time| is not very |
401 // close to 0. | 372 // close to 0. |
402 if (period_dumps_count < 0 || | 373 if (period_dumps_count < 0 || |
403 (cur_time < period_start && cur_time > kRatelimitPeriodSeconds) || | 374 (cur_time < period_start && |
404 difftime(cur_time, period_start) >= kRatelimitPeriodSeconds) { | 375 cur_time.ToDoubleT() > kRatelimitPeriodSeconds) || |
376 (cur_time - period_start).InSeconds() >= kRatelimitPeriodSeconds) { | |
405 period_start = cur_time; | 377 period_start = cur_time; |
406 period_dumps_count = 0; | 378 period_dumps_count = 0; |
407 SetRatelimitPeriodStart(metadata_.get(), period_start); | 379 SetRatelimitPeriodStart(metadata_.get(), period_start); |
408 SetRatelimitPeriodDumps(metadata_.get(), period_dumps_count); | 380 SetRatelimitPeriodDumps(metadata_.get(), period_dumps_count); |
409 } | 381 } |
410 | 382 |
411 return period_dumps_count < kRatelimitPeriodMaxDumps; | 383 return period_dumps_count < kRatelimitPeriodMaxDumps; |
412 } | 384 } |
413 | 385 |
414 bool SynchronizedMinidumpManager::HasDumps() { | 386 bool SynchronizedMinidumpManager::HasDumps() { |
415 // Check if lockfile has entries. | 387 // Check if lockfile has entries. |
416 int64_t size = 0; | 388 int64_t size = 0; |
417 if (GetFileSize(base::FilePath(lockfile_path_), &size) && size > 0) | 389 if (base::GetFileSize(lockfile_path_, &size) && size > 0) |
418 return true; | 390 return true; |
419 | 391 |
420 // Check if any files are in minidump directory | 392 // Check if any files are in minidump directory |
421 base::DirReaderPosix reader(dump_path_.value().c_str()); | 393 base::DirReaderPosix reader(dump_path_.value().c_str()); |
422 if (!reader.IsValid()) { | 394 if (!reader.IsValid()) { |
423 DLOG(FATAL) << "Could not open minidump dir: " << dump_path_.value(); | 395 DLOG(FATAL) << "Could not open minidump dir: " << dump_path_.value(); |
424 return false; | 396 return false; |
425 } | 397 } |
426 | 398 |
427 while (reader.Next()) { | 399 while (reader.Next()) { |
428 if (strcmp(reader.name(), ".") == 0 || strcmp(reader.name(), "..") == 0) | 400 if (strcmp(reader.name(), ".") == 0 || strcmp(reader.name(), "..") == 0) |
429 continue; | 401 continue; |
430 | 402 |
431 const std::string file_path = dump_path_.Append(reader.name()).value(); | 403 const base::FilePath file_path = dump_path_.Append(reader.name()); |
432 if (file_path != lockfile_path_ && file_path != metadata_path_) | 404 if (file_path != lockfile_path_ && file_path != metadata_path_) |
433 return true; | 405 return true; |
434 } | 406 } |
435 | 407 |
436 return false; | 408 return false; |
437 } | 409 } |
438 | 410 |
439 } // namespace chromecast | 411 } // namespace chromecast |
OLD | NEW |