Chromium Code Reviews| Index: chrome/browser/chromeos/boot_times_loader.cc |
| diff --git a/chrome/browser/chromeos/boot_times_loader.cc b/chrome/browser/chromeos/boot_times_loader.cc |
| index 94a675de5433dbcf712824ddd5fa02b548b1c978..79743b4c813b573a07a79c16b3ce0007d487e56c 100644 |
| --- a/chrome/browser/chromeos/boot_times_loader.cc |
| +++ b/chrome/browser/chromeos/boot_times_loader.cc |
| @@ -15,6 +15,7 @@ |
| #include "base/message_loop/message_loop.h" |
| #include "base/message_loop/message_loop_proxy.h" |
| #include "base/metrics/histogram.h" |
| +#include "base/prefs/pref_service.h" |
| #include "base/strings/string_number_conversions.h" |
| #include "base/strings/string_util.h" |
| #include "base/strings/stringprintf.h" |
| @@ -29,6 +30,7 @@ |
| #include "chrome/browser/ui/browser_iterator.h" |
| #include "chrome/browser/ui/tabs/tab_strip_model.h" |
| #include "chrome/common/chrome_switches.h" |
| +#include "chrome/common/pref_names.h" |
| #include "content/public/browser/browser_thread.h" |
| #include "content/public/browser/navigation_controller.h" |
| #include "content/public/browser/notification_service.h" |
| @@ -43,6 +45,8 @@ using content::WebContents; |
| namespace { |
| +const char kStatsDividerCharacter = '^'; |
| + |
| RenderWidgetHost* GetRenderWidgetHost(NavigationController* tab) { |
| WebContents* web_contents = tab->GetWebContents(); |
| if (web_contents) { |
| @@ -265,12 +269,97 @@ void BootTimesLoader::WriteLogoutTimes() { |
| logout_time_markers_); |
| } |
| +// static |
| +void BootTimesLoader::ClearLogoutStartedLastPreference() { |
| + PrefService* local_state = g_browser_process->local_state(); |
| + local_state->ClearPref(prefs::kLogoutStartedLast); |
| +} |
| + |
| +void BootTimesLoader::OnBoot() { |
| + PrefService* local_state = g_browser_process->local_state(); |
| + const std::string logout_started_last_str = |
| + local_state->GetString(prefs::kLogoutStartedLast); |
| + if (logout_started_last_str.empty()) |
| + return; |
| + |
| + // Note that kLogoutStartedLast is not cleared on format error to stay in |
| + // logs in case of other fatal system errors. |
| + |
| + const Stats logout_started_last_stats = |
| + Stats::DeserializeFromString(logout_started_last_str); |
| + if (logout_started_last_stats.uptime.empty()) |
| + return; |
| + |
| + // Extract double uptime seconds. |
| + const std::string logout_started_last_uptime_str = |
| + GetUptimeSeconds(logout_started_last_stats); |
| + if (logout_started_last_uptime_str.empty()) |
| + return; |
| + |
| + const std::string uptime_str = GetUptimeSeconds(GetCurrentStats()); |
| + |
| + double logout_started_last; |
| + double uptime; |
| + if (!base::StringToDouble(logout_started_last_uptime_str, |
| + &logout_started_last) || |
| + !base::StringToDouble(uptime_str, &uptime)) { |
| + return; |
| + } |
| + |
| + if (logout_started_last >= uptime) { |
| + // Reboot happened. |
| + ClearLogoutStartedLastPreference(); |
| + return; |
| + } |
| + // Write /tmp/uptime-logout-started as well. |
| + const char kLogoutStarted[] = "logout-started"; |
| + RecordStatsWithCallback( |
| + kLogoutStarted, |
| + logout_started_last_stats, |
| + base::Bind(&BootTimesLoader::ClearLogoutStartedLastPreference)); |
| +} |
| + |
| +void BootTimesLoader::OnLogoutStarted(PrefService* state) { |
| + const std::string uptime = GetCurrentStats().SerializeToString(); |
| + if (!uptime.empty()) |
| + state->SetString(prefs::kLogoutStartedLast, uptime); |
| +} |
| + |
| void BootTimesLoader::RecordStats(const std::string& name, const Stats& stats) { |
| BrowserThread::PostTask( |
| BrowserThread::FILE, FROM_HERE, |
| base::Bind(&RecordStatsDelayed, name, stats.uptime, stats.disk)); |
| } |
| +void BootTimesLoader::RecordStatsWithCallback(const std::string& name, |
| + const Stats& stats, |
| + const base::Closure& callback) { |
| + BrowserThread::PostBlockingPoolTaskAndReply( |
| + FROM_HERE, |
| + base::Bind(&RecordStatsDelayed, name, stats.uptime, stats.disk), |
| + callback); |
| +} |
| + |
| +std::string BootTimesLoader::Stats::SerializeToString() const { |
| + if (uptime.empty() || disk.empty()) |
| + return std::string(); |
| + |
| + return uptime + kStatsDividerCharacter + disk; |
| +} |
| + |
| +// static |
| +BootTimesLoader::Stats BootTimesLoader::Stats::DeserializeFromString( |
| + const std::string& value) { |
| + Stats result; |
| + |
| + const size_t divider_at = value.find_first_of(kStatsDividerCharacter); |
| + if (divider_at != std::string::npos) { |
| + result.uptime = value.substr(0, divider_at); |
| + result.disk = value.substr(divider_at + 1); |
| + } |
|
stevenjb
2014/05/30 16:20:23
While on the one hand this is fairly trivial, if w
Alexander Alekseev
2014/05/30 21:12:45
Done.
|
| + return result; |
| +} |
| + |
| BootTimesLoader::Stats BootTimesLoader::GetCurrentStats() { |
| const base::FilePath kProcUptime(FPL("/proc/uptime")); |
| const base::FilePath kDiskStat(FPL("/sys/block/sda/stat")); |
| @@ -281,6 +370,17 @@ BootTimesLoader::Stats BootTimesLoader::GetCurrentStats() { |
| return stats; |
| } |
| +std::string BootTimesLoader::GetUptimeSeconds( |
| + const BootTimesLoader::Stats& stats) { |
| + std::string uptime = stats.uptime; |
| + const size_t space_at = uptime.find_first_of(' '); |
|
stevenjb
2014/05/30 16:20:23
Where is this ' ' coming from?
Alexander Alekseev
2014/05/30 21:12:45
/proc/uptime has two fields: uptime in seconds and
|
| + if (space_at == std::string::npos) |
| + return std::string(); |
| + |
| + uptime.resize(space_at); |
| + return uptime; |
| +} |
|
stevenjb
2014/05/30 16:20:23
This seems like either it should be a member of St
Alexander Alekseev
2014/05/30 21:12:45
There is a member of type Stats, so I decided to l
|
| + |
| void BootTimesLoader::RecordCurrentStats(const std::string& name) { |
| RecordStats(name, GetCurrentStats()); |
| } |