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..7fea5a35b3dee52c07ca1289a116bba380b96792 100644 |
--- a/chrome/browser/chromeos/boot_times_loader.cc |
+++ b/chrome/browser/chromeos/boot_times_loader.cc |
@@ -10,11 +10,14 @@ |
#include "base/command_line.h" |
#include "base/file_util.h" |
#include "base/files/file_path.h" |
+#include "base/json/json_reader.h" |
+#include "base/json/json_writer.h" |
#include "base/lazy_instance.h" |
#include "base/location.h" |
#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 +32,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 +47,9 @@ using content::WebContents; |
namespace { |
+const char kUptime[] = "uptime"; |
+const char kDisk[] = "disk"; |
+ |
RenderWidgetHost* GetRenderWidgetHost(NavigationController* tab) { |
WebContents* web_contents = tab->GetWebContents(); |
if (web_contents) { |
@@ -70,6 +77,19 @@ const std::string GetTabUrl(RenderWidgetHost* rwh) { |
return std::string(); |
} |
+// Appends the given buffer into the file. Returns the number of bytes |
+// written, or -1 on error. |
+// TODO(satorux): Move this to file_util. |
+int AppendFile(const base::FilePath& file_path, const char* data, int size) { |
+ FILE* file = base::OpenFile(file_path, "a"); |
+ if (!file) { |
+ return -1; |
+ } |
stevenjb
2014/06/02 15:30:31
nit: {} unnecessary
Alexander Alekseev
2014/06/02 18:46:03
Done.
|
+ const int num_bytes_written = fwrite(data, 1, size, file); |
+ base::CloseFile(file); |
+ return num_bytes_written; |
+} |
+ |
} // namespace |
namespace chromeos { |
@@ -112,40 +132,88 @@ static const char kLogoutTimes[] = "logout-times"; |
static base::LazyInstance<BootTimesLoader> g_boot_times_loader = |
LAZY_INSTANCE_INITIALIZER; |
-BootTimesLoader::BootTimesLoader() |
- : backend_(new Backend()), |
- have_registered_(false), |
- login_done_(false), |
- restart_requested_(false) { |
- login_time_markers_.reserve(30); |
- logout_time_markers_.reserve(30); |
+// static |
+BootTimesLoader::Stats BootTimesLoader::Stats::GetCurrentStats() { |
+ const base::FilePath kProcUptime(FPL("/proc/uptime")); |
+ const base::FilePath kDiskStat(FPL("/sys/block/sda/stat")); |
+ Stats stats; |
+ base::ThreadRestrictions::ScopedAllowIO allow_io; |
stevenjb
2014/06/02 15:30:31
We should avoid using ScopedAllowIO if at all poss
Alexander Alekseev
2014/06/02 18:46:03
Done.
|
+ base::ReadFileToString(kProcUptime, &stats.uptime_); |
+ base::ReadFileToString(kDiskStat, &stats.disk_); |
+ return stats; |
} |
-BootTimesLoader::~BootTimesLoader() {} |
+std::string BootTimesLoader::Stats::SerializeToString() const { |
+ if (uptime_.empty() || disk_.empty()) |
+ return std::string(); |
+ base::DictionaryValue dictionary; |
+ dictionary.SetString(kUptime, uptime_); |
+ dictionary.SetString(kDisk, disk_); |
-// static |
-BootTimesLoader* BootTimesLoader::Get() { |
- return g_boot_times_loader.Pointer(); |
+ std::string result; |
+ if (!base::JSONWriter::Write(&dictionary, &result)) |
+ return std::string(); |
stevenjb
2014/06/02 15:30:31
nit: Should probably log an error here. 'result' w
Alexander Alekseev
2014/06/02 18:46:03
On 2014/06/02 15:30:31, stevenjb wrote:
> nit: Sho
|
+ |
+ return result; |
} |
-// Appends the given buffer into the file. Returns the number of bytes |
-// written, or -1 on error. |
-// TODO(satorux): Move this to file_util. |
-static int AppendFile(const base::FilePath& file_path, |
- const char* data, |
- int size) { |
- FILE* file = base::OpenFile(file_path, "a"); |
- if (!file) { |
- return -1; |
+// static |
+BootTimesLoader::Stats BootTimesLoader::Stats::DeserializeFromString( |
+ const std::string& source) { |
+ if (source.empty()) |
+ return Stats(); |
+ |
+ scoped_ptr<base::Value> value(base::JSONReader::Read(source)); |
+ base::DictionaryValue* dictionary; |
+ if (!value || !value->GetAsDictionary(&dictionary)) |
stevenjb
2014/06/02 15:30:31
LOG(ERROR)
Alexander Alekseev
2014/06/02 18:46:03
Done.
|
+ return Stats(); |
+ |
+ Stats result; |
+ if (!dictionary->GetString(kUptime, &result.uptime_) || |
+ !dictionary->GetString(kDisk, &result.disk_)) { |
stevenjb
2014/06/02 15:30:31
LOG(ERROR)
Alexander Alekseev
2014/06/02 18:46:03
Done.
|
+ return Stats(); |
} |
- const int num_bytes_written = fwrite(data, 1, size, file); |
- base::CloseFile(file); |
- return num_bytes_written; |
+ |
+ return result; |
+} |
+ |
+bool BootTimesLoader::Stats::uptimeD(double* result) const { |
+ std::string uptime = uptime_; |
+ const size_t space_at = uptime.find_first_of(' '); |
+ if (space_at == std::string::npos) |
+ return false; |
+ |
+ uptime.resize(space_at); |
+ |
+ if (base::StringToDouble(uptime, result)) |
+ return true; |
+ |
+ return false; |
+} |
+ |
+void BootTimesLoader::Stats::RecordStats(const std::string& name) const { |
+ BrowserThread::PostBlockingPoolTask( |
+ FROM_HERE, |
+ base::Bind(&BootTimesLoader::Stats::RecordStatsImpl, |
+ base::Owned(new Stats(*this)), |
+ name)); |
} |
-static void RecordStatsDelayed(const base::FilePath::StringType& name, |
- const std::string& uptime, |
- const std::string& disk) { |
+void BootTimesLoader::Stats::RecordStatsWithCallback( |
+ const std::string& name, |
+ const base::Closure& callback) const { |
+ BrowserThread::PostBlockingPoolTaskAndReply( |
+ FROM_HERE, |
+ base::Bind(&BootTimesLoader::Stats::RecordStatsImpl, |
+ base::Owned(new Stats(*this)), |
+ name), |
+ callback); |
+} |
+ |
+void BootTimesLoader::Stats::RecordStatsImpl( |
+ const base::FilePath::StringType& name) const { |
+ DCHECK(content::BrowserThread::GetBlockingPool()->RunsTasksOnCurrentThread()); |
+ |
const base::FilePath log_path(kLogPath); |
const base::FilePath uptime_output = |
log_path.Append(base::FilePath(kUptimePrefix + name)); |
@@ -153,8 +221,25 @@ static void RecordStatsDelayed(const base::FilePath::StringType& name, |
log_path.Append(base::FilePath(kDiskPrefix + name)); |
// Append numbers to the files. |
- AppendFile(uptime_output, uptime.data(), uptime.size()); |
- AppendFile(disk_output, disk.data(), disk.size()); |
+ AppendFile(uptime_output, uptime_.data(), uptime_.size()); |
+ AppendFile(disk_output, disk_.data(), disk_.size()); |
+} |
+ |
+BootTimesLoader::BootTimesLoader() |
+ : backend_(new Backend()), |
+ have_registered_(false), |
+ login_done_(false), |
+ restart_requested_(false) { |
+ login_time_markers_.reserve(30); |
+ logout_time_markers_.reserve(30); |
+} |
+ |
+BootTimesLoader::~BootTimesLoader() { |
+} |
+ |
+// static |
+BootTimesLoader* BootTimesLoader::Get() { |
+ return g_boot_times_loader.Pointer(); |
} |
// static |
@@ -265,32 +350,63 @@ void BootTimesLoader::WriteLogoutTimes() { |
logout_time_markers_); |
} |
-void BootTimesLoader::RecordStats(const std::string& name, const Stats& stats) { |
- BrowserThread::PostTask( |
- BrowserThread::FILE, FROM_HERE, |
- base::Bind(&RecordStatsDelayed, name, stats.uptime, stats.disk)); |
+// static |
+void BootTimesLoader::ClearLogoutStartedLastPreference() { |
+ PrefService* local_state = g_browser_process->local_state(); |
+ local_state->ClearPref(prefs::kLogoutStartedLast); |
} |
-BootTimesLoader::Stats BootTimesLoader::GetCurrentStats() { |
- const base::FilePath kProcUptime(FPL("/proc/uptime")); |
- const base::FilePath kDiskStat(FPL("/sys/block/sda/stat")); |
- Stats stats; |
- base::ThreadRestrictions::ScopedAllowIO allow_io; |
- base::ReadFileToString(kProcUptime, &stats.uptime); |
- base::ReadFileToString(kDiskStat, &stats.disk); |
- return stats; |
+void BootTimesLoader::OnChromeProcessStart() { |
+ 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; |
+ |
+ double logout_started_last; |
+ double uptime; |
+ if (!logout_started_last_stats.uptimeD(&logout_started_last) || |
+ !Stats::GetCurrentStats().uptimeD(&uptime)) { |
+ return; |
+ } |
+ |
+ if (logout_started_last >= uptime) { |
+ // Reboot happened. |
+ ClearLogoutStartedLastPreference(); |
+ return; |
+ } |
+ |
+ // Write /tmp/uptime-logout-started as well. |
+ const char kLogoutStarted[] = "logout-started"; |
+ logout_started_last_stats.RecordStatsWithCallback( |
+ kLogoutStarted, |
+ base::Bind(&BootTimesLoader::ClearLogoutStartedLastPreference)); |
+} |
+ |
+void BootTimesLoader::OnLogoutStarted(PrefService* state) { |
+ const std::string uptime = Stats::GetCurrentStats().SerializeToString(); |
+ if (!uptime.empty()) |
+ state->SetString(prefs::kLogoutStartedLast, uptime); |
} |
void BootTimesLoader::RecordCurrentStats(const std::string& name) { |
- RecordStats(name, GetCurrentStats()); |
+ Stats::GetCurrentStats().RecordStats(name); |
} |
void BootTimesLoader::SaveChromeMainStats() { |
- chrome_main_stats_ = GetCurrentStats(); |
+ chrome_main_stats_ = Stats::GetCurrentStats(); |
} |
void BootTimesLoader::RecordChromeMainStats() { |
- RecordStats(kChromeMain, chrome_main_stats_); |
+ chrome_main_stats_.RecordStats(kChromeMain); |
} |
void BootTimesLoader::RecordLoginAttempted() { |