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 c9885bea0b99ce6773d75d8c0c49b60e58a47b52..d51c6aea7aa45ff2c35f96648a2543b5dce414b3 100644 |
--- a/chrome/browser/chromeos/boot_times_loader.cc |
+++ b/chrome/browser/chromeos/boot_times_loader.cc |
@@ -293,12 +293,17 @@ void BootTimesLoader::WriteTimes( |
const std::string base_name, |
const std::string uma_name, |
const std::string uma_prefix, |
- const std::vector<TimeMarker> login_times) { |
+ std::vector<TimeMarker> login_times) { |
const int kMinTimeMillis = 1; |
const int kMaxTimeMillis = 30000; |
const int kNumBuckets = 100; |
const FilePath log_path(kLoginLogPath); |
+ // Need to sort by time since the entries may have been pushed onto the |
+ // vector (on the UI thread) in a different order from which they were |
+ // created (potentially on other threads). |
+ std::sort(login_times.begin(), login_times.end()); |
+ |
base::Time first = login_times.front().time(); |
base::Time last = login_times.back().time(); |
base::TimeDelta total = last - first; |
@@ -345,6 +350,7 @@ void BootTimesLoader::WriteTimes( |
} |
void BootTimesLoader::LoginDone() { |
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
AddLoginTimeMarker("LoginDone", true); |
RecordCurrentStats(kChromeFirstRender); |
registrar_.Remove(this, content::NOTIFICATION_LOAD_START, |
@@ -364,6 +370,12 @@ void BootTimesLoader::LoginDone() { |
} |
void BootTimesLoader::WriteLogoutTimes() { |
+ // Either we're on the browser thread, or (more likely) Chrome is in the |
+ // process of shutting down and we're on the main thread but the message loop |
+ // has already been terminated. |
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI) || |
+ !BrowserThread::IsMessageLoopValid(BrowserThread::UI)); |
+ |
WriteTimes(kLogoutTimes, |
kUmaLogout, |
kUmaLogoutPrefix, |
@@ -399,6 +411,7 @@ void BootTimesLoader::RecordChromeMainStats() { |
} |
void BootTimesLoader::RecordLoginAttempted() { |
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
login_time_markers_.clear(); |
AddLoginTimeMarker("LoginStarted", false); |
if (!have_registered_) { |
@@ -418,12 +431,34 @@ void BootTimesLoader::RecordLoginAttempted() { |
void BootTimesLoader::AddLoginTimeMarker( |
const std::string& marker_name, bool send_to_uma) { |
- login_time_markers_.push_back(TimeMarker(marker_name, send_to_uma)); |
+ AddMarker(&login_time_markers_, TimeMarker(marker_name, send_to_uma)); |
} |
void BootTimesLoader::AddLogoutTimeMarker( |
const std::string& marker_name, bool send_to_uma) { |
- logout_time_markers_.push_back(TimeMarker(marker_name, send_to_uma)); |
+ AddMarker(&logout_time_markers_, TimeMarker(marker_name, send_to_uma)); |
+} |
+ |
+// static |
+void BootTimesLoader::AddMarker(std::vector<TimeMarker>* vector, |
+ TimeMarker marker) |
+{ |
+ // The marker vectors can only be safely manipulated on the main thread. |
+ // If we're late in the process of shutting down (eg. as can be the case at |
+ // logout), then we have to assume we're on the main thread already. |
+ if (BrowserThread::CurrentlyOn(BrowserThread::UI) || |
+ !BrowserThread::IsMessageLoopValid(BrowserThread::UI)) { |
+ vector->push_back(marker); |
+ } else { |
+ // Add the marker on the UI thread. |
+ // Note that it's safe to use an unretained pointer to the vector because |
+ // BootTimesLoader's lifetime exceeds that of the UI thread message loop. |
+ BrowserThread::PostTask( |
+ BrowserThread::UI, FROM_HERE, |
+ base::Bind(&BootTimesLoader::AddMarker, |
+ base::Unretained(vector), |
+ marker)); |
+ } |
} |
void BootTimesLoader::Observe( |