OLD | NEW |
---|---|
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/performance_monitor/performance_monitor.h" | 5 #include "chrome/browser/performance_monitor/performance_monitor.h" |
6 | 6 |
7 #include <set> | |
8 | |
7 #include "base/bind.h" | 9 #include "base/bind.h" |
8 #include "base/logging.h" | 10 #include "base/logging.h" |
9 #include "base/process_util.h" | 11 #include "base/process_util.h" |
12 #include "base/string_number_conversions.h" | |
10 #include "base/threading/worker_pool.h" | 13 #include "base/threading/worker_pool.h" |
11 #include "base/time.h" | 14 #include "base/time.h" |
15 #include "chrome/browser/browser_process.h" | |
12 #include "chrome/browser/browser_shutdown.h" | 16 #include "chrome/browser/browser_shutdown.h" |
13 #include "chrome/browser/performance_monitor/constants.h" | 17 #include "chrome/browser/performance_monitor/constants.h" |
14 #include "chrome/browser/performance_monitor/database.h" | 18 #include "chrome/browser/performance_monitor/database.h" |
15 #include "chrome/browser/performance_monitor/performance_monitor_util.h" | 19 #include "chrome/browser/performance_monitor/performance_monitor_util.h" |
20 #include "chrome/browser/profiles/profile.h" | |
21 #include "chrome/browser/profiles/profile_manager.h" | |
22 #include "chrome/browser/ui/browser.h" | |
23 #include "chrome/browser/ui/browser_list.h" | |
16 #include "chrome/browser/extensions/crx_installer.h" | 24 #include "chrome/browser/extensions/crx_installer.h" |
17 #include "chrome/common/chrome_notification_types.h" | 25 #include "chrome/common/chrome_notification_types.h" |
18 #include "chrome/common/chrome_version_info.h" | 26 #include "chrome/common/chrome_version_info.h" |
19 #include "chrome/common/extensions/extension.h" | 27 #include "chrome/common/extensions/extension.h" |
20 #include "chrome/common/extensions/extension_constants.h" | 28 #include "chrome/common/extensions/extension_constants.h" |
21 #include "content/public/browser/browser_thread.h" | 29 #include "content/public/browser/browser_thread.h" |
22 #include "content/public/browser/notification_service.h" | 30 #include "content/public/browser/notification_service.h" |
23 #include "content/public/browser/notification_types.h" | 31 #include "content/public/browser/notification_types.h" |
24 #include "content/public/browser/web_contents.h" | 32 #include "content/public/browser/web_contents.h" |
25 | 33 |
26 using extensions::Extension; | 34 using extensions::Extension; |
27 | 35 |
36 namespace { | |
37 | |
38 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.
| |
39 int64 time_int64 = time.ToInternalValue(); | |
40 *output = base::Int64ToString(time_int64); | |
41 return !output->empty(); | |
42 } | |
43 | |
44 bool StringToTime(std::string time, base::Time* output) { | |
45 int64 time_int64 = 0; | |
46 if (!base::StringToInt64(time, &time_int64)) | |
47 return false; | |
48 *output = base::Time::FromInternalValue(time_int64); | |
49 return true; | |
50 } | |
51 | |
52 } // namespace | |
53 | |
28 namespace performance_monitor { | 54 namespace performance_monitor { |
29 | 55 |
30 PerformanceMonitor::PerformanceMonitor() : database_(NULL) { | 56 PerformanceMonitor::PerformanceMonitor() : database_(NULL) { |
31 } | 57 } |
32 | 58 |
33 PerformanceMonitor::~PerformanceMonitor() { | 59 PerformanceMonitor::~PerformanceMonitor() { |
34 } | 60 } |
35 | 61 |
36 void PerformanceMonitor::Start() { | 62 void PerformanceMonitor::Start() { |
63 std::string time; | |
64 CHECK(TimeToString(base::Time::Now(), &time)); | |
37 content::BrowserThread::PostBlockingPoolTaskAndReply( | 65 content::BrowserThread::PostBlockingPoolTaskAndReply( |
38 FROM_HERE, | 66 FROM_HERE, |
39 base::Bind(&PerformanceMonitor::InitOnBackgroundThread, | 67 base::Bind(&PerformanceMonitor::InitOnBackgroundThread, |
40 base::Unretained(this)), | 68 base::Unretained(this)), |
41 base::Bind(&PerformanceMonitor::FinishInit, | 69 base::Bind(&PerformanceMonitor::FinishInit, |
42 base::Unretained(this))); | 70 base::Unretained(this))); |
43 } | 71 } |
44 | 72 |
45 void PerformanceMonitor::InitOnBackgroundThread() { | 73 void PerformanceMonitor::InitOnBackgroundThread() { |
46 CHECK(!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); | 74 CHECK(!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); |
47 database_ = Database::Create(database_path_); | 75 database_ = Database::Create(database_path_); |
48 } | 76 } |
49 | 77 |
50 bool PerformanceMonitor::SetDatabasePath(const FilePath& path) { | 78 bool PerformanceMonitor::SetDatabasePath(const FilePath& path) { |
51 if (!database_.get()) { | 79 if (!database_.get()) { |
52 database_path_ = path; | 80 database_path_ = path; |
53 return true; | 81 return true; |
54 } | 82 } |
55 | 83 |
56 // PerformanceMonitor already initialized with another path. | 84 // PerformanceMonitor already initialized with another path. |
57 return false; | 85 return false; |
58 } | 86 } |
59 | 87 |
60 void PerformanceMonitor::FinishInit() { | 88 void PerformanceMonitor::FinishInit() { |
61 CHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); | 89 CHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); |
62 RegisterForNotifications(); | 90 RegisterForNotifications(); |
91 CheckForUncleanExit(); | |
63 CheckForVersionUpdate(); | 92 CheckForVersionUpdate(); |
93 | |
94 timer_.Start(FROM_HERE, base::TimeDelta::FromMinutes(2), | |
95 this, &PerformanceMonitor::DoTimedCollections); | |
64 } | 96 } |
65 | 97 |
66 void PerformanceMonitor::RegisterForNotifications() { | 98 void PerformanceMonitor::RegisterForNotifications() { |
67 // Extensions | 99 // Extensions |
68 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_INSTALLED, | 100 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_INSTALLED, |
69 content::NotificationService::AllSources()); | 101 content::NotificationService::AllSources()); |
70 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_ENABLED, | 102 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_ENABLED, |
71 content::NotificationService::AllSources()); | 103 content::NotificationService::AllSources()); |
72 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_UNLOADED, | 104 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_UNLOADED, |
73 content::NotificationService::AllSources()); | 105 content::NotificationService::AllSources()); |
74 registrar_.Add(this, chrome::NOTIFICATION_CRX_INSTALLER_DONE, | 106 registrar_.Add(this, chrome::NOTIFICATION_CRX_INSTALLER_DONE, |
75 content::NotificationService::AllSources()); | 107 content::NotificationService::AllSources()); |
76 | 108 |
77 // Crashes | 109 // Crashes |
78 registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_HANG, | 110 registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_HANG, |
79 content::NotificationService::AllSources()); | 111 content::NotificationService::AllSources()); |
80 registrar_.Add(this, content::NOTIFICATION_WEB_CONTENTS_DISCONNECTED, | 112 registrar_.Add(this, content::NOTIFICATION_WEB_CONTENTS_DISCONNECTED, |
81 content::NotificationService::AllSources()); | 113 content::NotificationService::AllSources()); |
114 | |
115 // Profiles (for unclean exit) | |
116 registrar_.Add(this, chrome::NOTIFICATION_PROFILE_ADDED, | |
117 content::NotificationService::AllSources()); | |
82 } | 118 } |
83 | 119 |
84 // Static | 120 // Static |
85 PerformanceMonitor* PerformanceMonitor::GetInstance() { | 121 PerformanceMonitor* PerformanceMonitor::GetInstance() { |
86 return Singleton<PerformanceMonitor>::get(); | 122 return Singleton<PerformanceMonitor>::get(); |
87 } | 123 } |
88 | 124 |
89 void PerformanceMonitor::AddEvent(scoped_ptr<Event> event) { | 125 void PerformanceMonitor::AddEvent(scoped_ptr<Event> event) { |
90 content::BrowserThread::PostBlockingPoolSequencedTask( | 126 content::BrowserThread::PostBlockingPoolSequencedTask( |
91 Database::kDatabaseSequenceToken, | 127 Database::kDatabaseSequenceToken, |
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
146 current_version)); | 182 current_version)); |
147 if (!previous_version.empty()) { | 183 if (!previous_version.empty()) { |
148 AddEvent(util::CreateChromeUpdateEvent( | 184 AddEvent(util::CreateChromeUpdateEvent( |
149 base::Time::Now(), | 185 base::Time::Now(), |
150 previous_version, | 186 previous_version, |
151 current_version)); | 187 current_version)); |
152 } | 188 } |
153 } | 189 } |
154 } | 190 } |
155 | 191 |
192 // The reason we need this as well as a notification check is because the first | |
193 // profiles can be loaded prior to the initialization of PerformanceMonitor. In | |
194 // 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.
| |
195 void PerformanceMonitor::CheckForUncleanExit() { | |
Yoyo Zhou
2012/07/10 02:35:06
CheckForUncleanExits
Devlin
2012/07/10 17:18:32
Done.
| |
196 std::vector<Profile*> profiles = | |
197 g_browser_process->profile_manager()->GetLoadedProfiles(); | |
198 | |
199 for (std::vector<Profile*>::const_iterator iter = profiles.begin(); | |
200 iter != profiles.end(); ++iter) { | |
201 if (!(*iter)->DidLastSessionExitCleanly()) { | |
202 content::BrowserThread::PostBlockingPoolSequencedTask( | |
203 Database::kDatabaseSequenceToken, | |
204 FROM_HERE, | |
205 base::Bind(&PerformanceMonitor::AddUncleanExitEvent, | |
206 base::Unretained(this), | |
207 (*iter)->GetDebugName())); | |
208 } | |
209 } | |
210 } | |
211 | |
212 void PerformanceMonitor::AddUncleanExitEvent(std::string profile_name) { | |
213 std::string database_key = kStateProfile + profile_name; | |
214 std::string last_active_string = database_->GetStateValue(database_key); | |
215 | |
216 // Check if there was no previous time; this should only happen if the profile | |
217 // was last used prior to PerformanceMonitor's integration. Do nothing in this | |
218 // case, since the event was prior to the beginning of our recording. | |
219 if (last_active_string.empty()) | |
220 return; | |
221 | |
222 base::Time last_active_time; | |
223 CHECK(StringToTime(last_active_string, &last_active_time)); | |
224 | |
225 // We should never find a case where the last active time for the profile is | |
226 // after the current time. DCHECK (instead of CHECK) because of the chance | |
227 // 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
| |
228 // a release build. | |
229 DCHECK(last_active_time < base::Time::Now()); | |
230 | |
231 scoped_ptr<Event> event = | |
232 util::CreateUncleanExitEvent(last_active_time, profile_name); | |
233 | |
234 database_->AddEvent(*event.get()); | |
235 } | |
236 | |
237 void PerformanceMonitor::UpdateLiveProfiles() { | |
238 std::string time; | |
239 CHECK(TimeToString(base::Time::Now(), &time)); | |
240 scoped_ptr<std::set<std::string> > active_profiles( | |
241 new std::set<std::string>()); | |
242 | |
243 for (BrowserList::const_iterator iter = BrowserList::begin(); | |
244 iter != BrowserList::end(); ++iter) { | |
245 active_profiles->insert((*iter)->profile()->GetDebugName()); | |
246 } | |
247 | |
248 content::BrowserThread::PostBlockingPoolSequencedTask( | |
249 Database::kDatabaseSequenceToken, | |
250 FROM_HERE, | |
251 base::Bind(&PerformanceMonitor::UpdateLiveProfilesHelper, | |
252 base::Unretained(this), | |
253 base::Passed(active_profiles.Pass()), | |
254 time)); | |
255 } | |
256 | |
257 void PerformanceMonitor::UpdateLiveProfilesHelper( | |
258 scoped_ptr<std::set<std::string> > active_profiles, | |
259 std::string time) { | |
260 CHECK(!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); | |
261 | |
262 for (std::set<std::string>::const_iterator iter = active_profiles->begin(); | |
263 iter != active_profiles->end(); ++iter) { | |
264 database_->AddStateValue(kStateProfile + *iter, time); | |
265 } | |
266 } | |
267 | |
268 void PerformanceMonitor::DoTimedCollections() { | |
269 UpdateLiveProfiles(); | |
270 } | |
271 | |
156 void PerformanceMonitor::Observe(int type, | 272 void PerformanceMonitor::Observe(int type, |
157 const content::NotificationSource& source, | 273 const content::NotificationSource& source, |
158 const content::NotificationDetails& details) { | 274 const content::NotificationDetails& details) { |
159 switch (type) { | 275 switch (type) { |
160 case chrome::NOTIFICATION_EXTENSION_INSTALLED: { | 276 case chrome::NOTIFICATION_EXTENSION_INSTALLED: { |
161 const Extension* extension = content::Details<Extension>(details).ptr(); | 277 const Extension* extension = content::Details<Extension>(details).ptr(); |
162 AddEvent(util::CreateExtensionInstallEvent(base::Time::Now(), | 278 AddEvent(util::CreateExtensionInstallEvent(base::Time::Now(), |
163 extension->id(), | 279 extension->id(), |
164 extension->name(), | 280 extension->name(), |
165 extension->url().spec(), | 281 extension->url().spec(), |
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
232 // Determine the type of crash. | 348 // Determine the type of crash. |
233 EventType type = | 349 EventType type = |
234 status == base::TERMINATION_STATUS_PROCESS_WAS_KILLED ? | 350 status == base::TERMINATION_STATUS_PROCESS_WAS_KILLED ? |
235 EVENT_KILLED_BY_OS_CRASH : EVENT_RENDERER_CRASH; | 351 EVENT_KILLED_BY_OS_CRASH : EVENT_RENDERER_CRASH; |
236 | 352 |
237 AddEvent(util::CreateCrashEvent(base::Time::Now(), | 353 AddEvent(util::CreateCrashEvent(base::Time::Now(), |
238 type, | 354 type, |
239 contents->GetURL().spec())); | 355 contents->GetURL().spec())); |
240 break; | 356 break; |
241 } | 357 } |
358 case chrome::NOTIFICATION_PROFILE_ADDED: { | |
359 Profile* profile = content::Source<Profile>(source).ptr(); | |
360 if (!profile->DidLastSessionExitCleanly()) { | |
361 content::BrowserThread::PostBlockingPoolSequencedTask( | |
362 Database::kDatabaseSequenceToken, | |
363 FROM_HERE, | |
364 base::Bind(&PerformanceMonitor::AddUncleanExitEvent, | |
365 base::Unretained(this), | |
366 profile->GetDebugName())); | |
367 } | |
368 break; | |
369 } | |
242 default: { | 370 default: { |
243 NOTREACHED(); | 371 NOTREACHED(); |
244 break; | 372 break; |
245 } | 373 } |
246 } | 374 } |
247 } | 375 } |
248 | 376 |
249 } // namespace performance_monitor | 377 } // namespace performance_monitor |
OLD | NEW |