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