Chromium Code Reviews| Index: chrome/browser/performance_monitor/performance_monitor.cc |
| diff --git a/chrome/browser/performance_monitor/performance_monitor.cc b/chrome/browser/performance_monitor/performance_monitor.cc |
| index 833fcd4f475f263fb3141a759cb579d690b411c3..85a91e51110739b5d9a31b626095f2a69541571e 100644 |
| --- a/chrome/browser/performance_monitor/performance_monitor.cc |
| +++ b/chrome/browser/performance_monitor/performance_monitor.cc |
| @@ -4,15 +4,23 @@ |
| #include "chrome/browser/performance_monitor/performance_monitor.h" |
| +#include <set> |
| + |
| #include "base/bind.h" |
| #include "base/logging.h" |
| #include "base/process_util.h" |
| +#include "base/string_number_conversions.h" |
| #include "base/threading/worker_pool.h" |
| #include "base/time.h" |
| +#include "chrome/browser/browser_process.h" |
| #include "chrome/browser/browser_shutdown.h" |
| #include "chrome/browser/performance_monitor/constants.h" |
| #include "chrome/browser/performance_monitor/database.h" |
| #include "chrome/browser/performance_monitor/performance_monitor_util.h" |
| +#include "chrome/browser/profiles/profile.h" |
| +#include "chrome/browser/profiles/profile_manager.h" |
| +#include "chrome/browser/ui/browser.h" |
| +#include "chrome/browser/ui/browser_list.h" |
| #include "chrome/browser/extensions/crx_installer.h" |
| #include "chrome/common/chrome_notification_types.h" |
| #include "chrome/common/chrome_version_info.h" |
| @@ -25,6 +33,24 @@ |
| using extensions::Extension; |
| +namespace { |
| + |
| +bool TimeToString(base::Time time, std::string* output) { |
|
Yoyo Zhou
2012/07/10 02:35:06
It doesn't make sense that conversion in this dire
Devlin
2012/07/10 17:18:32
Done.
|
| + int64 time_int64 = time.ToInternalValue(); |
| + *output = base::Int64ToString(time_int64); |
| + return !output->empty(); |
| +} |
| + |
| +bool StringToTime(std::string time, base::Time* output) { |
| + int64 time_int64 = 0; |
| + if (!base::StringToInt64(time, &time_int64)) |
| + return false; |
| + *output = base::Time::FromInternalValue(time_int64); |
| + return true; |
| +} |
| + |
| +} // namespace |
| + |
| namespace performance_monitor { |
| PerformanceMonitor::PerformanceMonitor() : database_(NULL) { |
| @@ -34,6 +60,8 @@ PerformanceMonitor::~PerformanceMonitor() { |
| } |
| void PerformanceMonitor::Start() { |
| + std::string time; |
| + CHECK(TimeToString(base::Time::Now(), &time)); |
| content::BrowserThread::PostBlockingPoolTaskAndReply( |
| FROM_HERE, |
| base::Bind(&PerformanceMonitor::InitOnBackgroundThread, |
| @@ -60,7 +88,11 @@ bool PerformanceMonitor::SetDatabasePath(const FilePath& path) { |
| void PerformanceMonitor::FinishInit() { |
| CHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); |
| RegisterForNotifications(); |
| + CheckForUncleanExit(); |
| CheckForVersionUpdate(); |
| + |
| + timer_.Start(FROM_HERE, base::TimeDelta::FromMinutes(2), |
| + this, &PerformanceMonitor::DoTimedCollections); |
| } |
| void PerformanceMonitor::RegisterForNotifications() { |
| @@ -79,6 +111,10 @@ void PerformanceMonitor::RegisterForNotifications() { |
| content::NotificationService::AllSources()); |
| registrar_.Add(this, content::NOTIFICATION_WEB_CONTENTS_DISCONNECTED, |
| content::NotificationService::AllSources()); |
| + |
| + // Profiles (for unclean exit) |
| + registrar_.Add(this, chrome::NOTIFICATION_PROFILE_ADDED, |
| + content::NotificationService::AllSources()); |
| } |
| // Static |
| @@ -153,6 +189,86 @@ void PerformanceMonitor::CheckForVersionUpdateHelper( |
| } |
| } |
| +// The reason we need this as well as a notification check is because the first |
| +// profiles can be loaded prior to the initialization of PerformanceMonitor. In |
| +// this case, we find if they exited uncleanly here. |
|
Yoyo Zhou
2012/07/10 02:35:06
This comment is written backwards. I'd say
"At ini
Devlin
2012/07/10 17:18:32
Done.
|
| +void PerformanceMonitor::CheckForUncleanExit() { |
|
Yoyo Zhou
2012/07/10 02:35:06
CheckForUncleanExits
Devlin
2012/07/10 17:18:32
Done.
|
| + std::vector<Profile*> profiles = |
| + g_browser_process->profile_manager()->GetLoadedProfiles(); |
| + |
| + for (std::vector<Profile*>::const_iterator iter = profiles.begin(); |
| + iter != profiles.end(); ++iter) { |
| + if (!(*iter)->DidLastSessionExitCleanly()) { |
| + content::BrowserThread::PostBlockingPoolSequencedTask( |
| + Database::kDatabaseSequenceToken, |
| + FROM_HERE, |
| + base::Bind(&PerformanceMonitor::AddUncleanExitEvent, |
| + base::Unretained(this), |
| + (*iter)->GetDebugName())); |
| + } |
| + } |
| +} |
| + |
| +void PerformanceMonitor::AddUncleanExitEvent(std::string profile_name) { |
| + std::string database_key = kStateProfile + profile_name; |
| + std::string last_active_string = database_->GetStateValue(database_key); |
| + |
| + // Check if there was no previous time; this should only happen if the profile |
| + // was last used prior to PerformanceMonitor's integration. Do nothing in this |
| + // case, since the event was prior to the beginning of our recording. |
| + if (last_active_string.empty()) |
| + return; |
| + |
| + base::Time last_active_time; |
| + CHECK(StringToTime(last_active_string, &last_active_time)); |
| + |
| + // We should never find a case where the last active time for the profile is |
| + // after the current time. DCHECK (instead of CHECK) because of the chance |
| + // that someone has backdated the system time, so that Chrome won't crash in |
|
Yoyo Zhou
2012/07/10 02:35:06
This seems like a case that could actually happen,
Devlin
2012/07/10 17:18:32
Yeah, I wasn't sure about this one...it won't brea
|
| + // a release build. |
| + DCHECK(last_active_time < base::Time::Now()); |
| + |
| + scoped_ptr<Event> event = |
| + util::CreateUncleanExitEvent(last_active_time, profile_name); |
| + |
| + database_->AddEvent(*event.get()); |
| +} |
| + |
| +void PerformanceMonitor::UpdateLiveProfiles() { |
| + std::string time; |
| + CHECK(TimeToString(base::Time::Now(), &time)); |
| + scoped_ptr<std::set<std::string> > active_profiles( |
| + new std::set<std::string>()); |
| + |
| + for (BrowserList::const_iterator iter = BrowserList::begin(); |
| + iter != BrowserList::end(); ++iter) { |
| + active_profiles->insert((*iter)->profile()->GetDebugName()); |
| + } |
| + |
| + content::BrowserThread::PostBlockingPoolSequencedTask( |
| + Database::kDatabaseSequenceToken, |
| + FROM_HERE, |
| + base::Bind(&PerformanceMonitor::UpdateLiveProfilesHelper, |
| + base::Unretained(this), |
| + base::Passed(active_profiles.Pass()), |
| + time)); |
| +} |
| + |
| +void PerformanceMonitor::UpdateLiveProfilesHelper( |
| + scoped_ptr<std::set<std::string> > active_profiles, |
| + std::string time) { |
| + CHECK(!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); |
| + |
| + for (std::set<std::string>::const_iterator iter = active_profiles->begin(); |
| + iter != active_profiles->end(); ++iter) { |
| + database_->AddStateValue(kStateProfile + *iter, time); |
| + } |
| +} |
| + |
| +void PerformanceMonitor::DoTimedCollections() { |
| + UpdateLiveProfiles(); |
| +} |
| + |
| void PerformanceMonitor::Observe(int type, |
| const content::NotificationSource& source, |
| const content::NotificationDetails& details) { |
| @@ -239,6 +355,18 @@ void PerformanceMonitor::Observe(int type, |
| contents->GetURL().spec())); |
| break; |
| } |
| + case chrome::NOTIFICATION_PROFILE_ADDED: { |
| + Profile* profile = content::Source<Profile>(source).ptr(); |
| + if (!profile->DidLastSessionExitCleanly()) { |
| + content::BrowserThread::PostBlockingPoolSequencedTask( |
| + Database::kDatabaseSequenceToken, |
| + FROM_HERE, |
| + base::Bind(&PerformanceMonitor::AddUncleanExitEvent, |
| + base::Unretained(this), |
| + profile->GetDebugName())); |
| + } |
| + break; |
| + } |
| default: { |
| NOTREACHED(); |
| break; |