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 a96e5b1c8343e2bd99439e858a4a043023400b9a..1e74199c2a2d6a08215ee7c97045f22fa4241169 100644 |
--- a/chrome/browser/performance_monitor/performance_monitor.cc |
+++ b/chrome/browser/performance_monitor/performance_monitor.cc |
@@ -4,16 +4,24 @@ |
#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/extensions/crx_installer.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/extensions/crx_installer.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/common/chrome_notification_types.h" |
#include "chrome/common/chrome_version_info.h" |
#include "chrome/common/extensions/extension.h" |
@@ -27,6 +35,23 @@ |
using content::BrowserThread; |
using extensions::Extension; |
+namespace { |
+ |
+std::string TimeToString(base::Time time) { |
+ int64 time_int64 = time.ToInternalValue(); |
+ return base::Int64ToString(time_int64); |
+} |
+ |
+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) { |
@@ -60,19 +85,23 @@ void PerformanceMonitor::Start() { |
} |
void PerformanceMonitor::InitOnBackgroundThread() { |
- DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::UI)); |
+ CHECK(!BrowserThread::CurrentlyOn(BrowserThread::UI)); |
database_ = Database::Create(database_path_); |
} |
void PerformanceMonitor::FinishInit() { |
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
+ CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
RegisterForNotifications(); |
+ CheckForUncleanExits(); |
BrowserThread::PostBlockingPoolSequencedTask( |
Database::kDatabaseSequenceToken, |
FROM_HERE, |
base::Bind(&PerformanceMonitor::CheckForVersionUpdateOnBackgroundThread, |
base::Unretained(this))); |
+ timer_.Start(FROM_HERE, base::TimeDelta::FromMinutes(2), |
+ this, &PerformanceMonitor::DoTimedCollections); |
+ |
// Post a task to the background thread to a function which does nothing. |
// This will force any tasks the database is performing to finish prior to |
// the reply being sent, since they use the same thread. |
@@ -104,10 +133,53 @@ void PerformanceMonitor::RegisterForNotifications() { |
content::NotificationService::AllSources()); |
registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_CLOSED, |
content::NotificationService::AllSources()); |
+ |
+ // Profiles (for unclean exit) |
+ registrar_.Add(this, chrome::NOTIFICATION_PROFILE_ADDED, |
+ content::NotificationService::AllSources()); |
+} |
+ |
+// We check if profiles exited cleanly initialization time in case they were |
+// loaded prior to PerformanceMonitor's initialization. Later profiles will be |
+// checked through the PROFILE_ADDED notification. |
+void PerformanceMonitor::CheckForUncleanExits() { |
+ 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()) { |
+ BrowserThread::PostBlockingPoolSequencedTask( |
+ Database::kDatabaseSequenceToken, |
+ FROM_HERE, |
+ base::Bind(&PerformanceMonitor::AddUncleanExitEvent, |
+ base::Unretained(this), |
+ (*iter)->GetDebugName())); |
+ } |
+ } |
+} |
+ |
+void PerformanceMonitor::AddUncleanExitEvent(const std::string& profile_name) { |
+ std::string database_key = kStateProfilePrefix + 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)); |
+ |
+ scoped_ptr<Event> event = |
+ util::CreateUncleanExitEvent(last_active_time, profile_name); |
+ |
+ database_->AddEvent(*event.get()); |
} |
void PerformanceMonitor::CheckForVersionUpdateOnBackgroundThread() { |
- DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::UI)); |
+ CHECK(!BrowserThread::CurrentlyOn(BrowserThread::UI)); |
chrome::VersionInfo version; |
DCHECK(version.is_valid()); |
@@ -149,7 +221,7 @@ void PerformanceMonitor::AddEventOnBackgroundThread(scoped_ptr<Event> event) { |
void PerformanceMonitor::GetStateValueOnBackgroundThread( |
const std::string& key, |
const StateValueCallback& callback) { |
- DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::UI)); |
+ CHECK(!BrowserThread::CurrentlyOn(BrowserThread::UI)); |
std::string state_value = database_->GetStateValue(key); |
BrowserThread::PostTask(BrowserThread::UI, |
@@ -164,6 +236,40 @@ void PerformanceMonitor::NotifyInitialized() { |
content::NotificationService::NoDetails()); |
} |
+void PerformanceMonitor::UpdateLiveProfiles() { |
+ std::string time = TimeToString(base::Time::Now()); |
+ 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()); |
+ } |
+ |
+ 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(!BrowserThread::CurrentlyOn(BrowserThread::UI)); |
+ |
+ for (std::set<std::string>::const_iterator iter = active_profiles->begin(); |
+ iter != active_profiles->end(); ++iter) { |
+ database_->AddStateValue(kStateProfilePrefix + *iter, time); |
+ } |
+} |
+ |
+void PerformanceMonitor::DoTimedCollections() { |
+ UpdateLiveProfiles(); |
+} |
+ |
void PerformanceMonitor::Observe(int type, |
const content::NotificationSource& source, |
const content::NotificationDetails& details) { |
@@ -259,6 +365,18 @@ void PerformanceMonitor::Observe(int type, |
type)); |
break; |
} |
+ case chrome::NOTIFICATION_PROFILE_ADDED: { |
+ Profile* profile = content::Source<Profile>(source).ptr(); |
+ if (!profile->DidLastSessionExitCleanly()) { |
+ BrowserThread::PostBlockingPoolSequencedTask( |
+ Database::kDatabaseSequenceToken, |
+ FROM_HERE, |
+ base::Bind(&PerformanceMonitor::AddUncleanExitEvent, |
+ base::Unretained(this), |
+ profile->GetDebugName())); |
+ } |
+ break; |
+ } |
default: { |
NOTREACHED(); |
break; |