Disable accessible touch exploration by default.
[chromium-blink-merge.git] / chrome / browser / performance_monitor / performance_monitor.cc
blobdd76da90000dd70e37217c7c1e9b87674e1b4603
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
3 // found in the LICENSE file.
5 #include "chrome/browser/performance_monitor/performance_monitor.h"
7 #include <set>
8 #include <vector>
10 #include "base/bind.h"
11 #include "base/command_line.h"
12 #include "base/logging.h"
13 #include "base/memory/singleton.h"
14 #include "base/process/process_iterator.h"
15 #include "base/stl_util.h"
16 #include "base/strings/string_number_conversions.h"
17 #include "base/threading/worker_pool.h"
18 #include "base/time/time.h"
19 #include "chrome/browser/browser_process.h"
20 #include "chrome/browser/browser_shutdown.h"
21 #include "chrome/browser/chrome_notification_types.h"
22 #include "chrome/browser/extensions/crx_installer.h"
23 #include "chrome/browser/performance_monitor/constants.h"
24 #include "chrome/browser/performance_monitor/performance_monitor_util.h"
25 #include "chrome/browser/profiles/profile.h"
26 #include "chrome/browser/profiles/profile_manager.h"
27 #include "chrome/browser/ui/browser.h"
28 #include "chrome/browser/ui/browser_iterator.h"
29 #include "chrome/common/chrome_switches.h"
30 #include "chrome/common/chrome_version_info.h"
31 #include "chrome/common/extensions/extension_constants.h"
32 #include "content/public/browser/browser_child_process_host.h"
33 #include "content/public/browser/browser_child_process_host_iterator.h"
34 #include "content/public/browser/browser_thread.h"
35 #include "content/public/browser/child_process_data.h"
36 #include "content/public/browser/load_notification_details.h"
37 #include "content/public/browser/notification_service.h"
38 #include "content/public/browser/notification_types.h"
39 #include "content/public/browser/render_view_host.h"
40 #include "content/public/browser/render_widget_host.h"
41 #include "content/public/browser/render_widget_host_iterator.h"
42 #include "content/public/browser/web_contents.h"
43 #include "extensions/common/extension.h"
44 #include "net/url_request/url_request.h"
46 using content::BrowserThread;
47 using extensions::Extension;
48 using extensions::UnloadedExtensionInfo;
50 namespace performance_monitor {
52 namespace {
54 #if !defined(OS_ANDROID)
55 std::string TimeToString(base::Time time) {
56 int64 time_int64 = time.ToInternalValue();
57 return base::Int64ToString(time_int64);
59 #endif // !defined(OS_ANDROID)
61 bool StringToTime(std::string time, base::Time* output) {
62 int64 time_int64 = 0;
63 if (!base::StringToInt64(time, &time_int64))
64 return false;
65 *output = base::Time::FromInternalValue(time_int64);
66 return true;
69 // Try to get the URL for the RenderViewHost if the host does not correspond to
70 // an incognito profile (we don't store URLs from incognito sessions). Returns
71 // true if url has been populated, and false otherwise.
72 bool MaybeGetURLFromRenderView(const content::RenderViewHost* view,
73 std::string* url) {
74 content::WebContents* web_contents =
75 content::WebContents::FromRenderViewHost(view);
77 if (Profile::FromBrowserContext(
78 web_contents->GetBrowserContext())->IsOffTheRecord()) {
79 return false;
82 *url = web_contents->GetURL().spec();
83 return true;
86 // Takes ownership of and deletes |database| on the background thread, to
87 // avoid destruction in the middle of an operation.
88 void DeleteDatabaseOnBackgroundThread(Database* database) {
89 delete database;
92 } // namespace
94 bool PerformanceMonitor::initialized_ = false;
96 PerformanceMonitor::PerformanceDataForIOThread::PerformanceDataForIOThread()
97 : network_bytes_read(0) {
100 PerformanceMonitor::PerformanceMonitor()
101 : gather_interval_in_seconds_(kDefaultGatherIntervalInSeconds),
102 database_logging_enabled_(false),
103 timer_(FROM_HERE,
104 base::TimeDelta::FromSeconds(kSampleIntervalInSeconds),
105 this,
106 &PerformanceMonitor::DoTimedCollections),
107 disable_timer_autostart_for_testing_(false) {
110 PerformanceMonitor::~PerformanceMonitor() {
111 BrowserThread::PostBlockingPoolSequencedTask(
112 Database::kDatabaseSequenceToken,
113 FROM_HERE,
114 base::Bind(&DeleteDatabaseOnBackgroundThread, database_.release()));
117 bool PerformanceMonitor::SetDatabasePath(const base::FilePath& path) {
118 if (!database_.get()) {
119 database_path_ = path;
120 return true;
123 // PerformanceMonitor already initialized with another path.
124 return false;
127 // static
128 PerformanceMonitor* PerformanceMonitor::GetInstance() {
129 return Singleton<PerformanceMonitor>::get();
132 void PerformanceMonitor::Initialize() {
133 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
135 if (CommandLine::ForCurrentProcess()->HasSwitch(
136 switches::kPerformanceMonitorGathering)) {
137 database_logging_enabled_ = true;
139 std::string switch_value = CommandLine::ForCurrentProcess()->
140 GetSwitchValueASCII(switches::kPerformanceMonitorGathering);
142 if (!switch_value.empty()) {
143 int specified_interval = 0;
144 if (!base::StringToInt(switch_value, &specified_interval) ||
145 specified_interval <= 0) {
146 LOG(ERROR) << "Invalid value for switch: '"
147 << switches::kPerformanceMonitorGathering
148 << "'; please use an integer greater than 0.";
149 } else {
150 gather_interval_in_seconds_ = std::max(specified_interval,
151 kSampleIntervalInSeconds);
156 DCHECK(gather_interval_in_seconds_ >= kSampleIntervalInSeconds);
158 next_collection_time_ = base::Time::Now() +
159 base::TimeDelta::FromSeconds(gather_interval_in_seconds_);
161 util::PostTaskToDatabaseThreadAndReply(
162 FROM_HERE,
163 base::Bind(&PerformanceMonitor::InitOnBackgroundThread,
164 base::Unretained(this)),
165 base::Bind(&PerformanceMonitor::FinishInit,
166 base::Unretained(this)));
169 void PerformanceMonitor::InitOnBackgroundThread() {
170 CHECK(!BrowserThread::CurrentlyOn(BrowserThread::UI));
172 if (database_logging_enabled_) {
173 if (!database_)
174 database_ = Database::Create(database_path_);
176 if (!database_) {
177 LOG(ERROR) << "Could not initialize database; aborting initialization.";
178 database_logging_enabled_ = false;
179 return;
182 // Initialize the io thread's performance data to the value in the database;
183 // if there isn't a recording in the database, the value stays at 0.
184 Metric metric;
185 if (database_->GetRecentStatsForActivityAndMetric(METRIC_NETWORK_BYTES_READ,
186 &metric)) {
187 performance_data_for_io_thread_.network_bytes_read = metric.value;
192 void PerformanceMonitor::FinishInit() {
193 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
195 // Events and notifications are only useful if we're logging to the database.
196 if (database_logging_enabled_) {
197 RegisterForNotifications();
198 CheckForUncleanExits();
199 BrowserThread::PostBlockingPoolSequencedTask(
200 Database::kDatabaseSequenceToken,
201 FROM_HERE,
202 base::Bind(&PerformanceMonitor::CheckForVersionUpdateOnBackgroundThread,
203 base::Unretained(this)));
206 // Post a task to the background thread to a function which does nothing.
207 // This will force any tasks the database is performing to finish prior to
208 // the reply being sent, since they use the same thread.
210 // Important! Make sure that methods in FinishInit() only rely on posting
211 // to the background thread, and do not rely upon a reply from the background
212 // thread; this is necessary for this notification to be valid.
213 util::PostTaskToDatabaseThreadAndReply(
214 FROM_HERE,
215 base::Bind(&base::DoNothing),
216 base::Bind(&PerformanceMonitor::NotifyInitialized,
217 base::Unretained(this)));
220 void PerformanceMonitor::StartGatherCycle() {
221 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
223 // Start our periodic gathering of metrics.
224 if (!disable_timer_autostart_for_testing_)
225 timer_.Reset();
228 void PerformanceMonitor::RegisterForNotifications() {
229 DCHECK(database_logging_enabled_);
231 // Extensions
232 registrar_.Add(this,
233 chrome::NOTIFICATION_EXTENSION_WILL_BE_INSTALLED_DEPRECATED,
234 content::NotificationService::AllSources());
235 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_ENABLED,
236 content::NotificationService::AllSources());
237 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_UNLOADED_DEPRECATED,
238 content::NotificationService::AllSources());
239 registrar_.Add(this, chrome::NOTIFICATION_CRX_INSTALLER_DONE,
240 content::NotificationService::AllSources());
241 registrar_.Add(this,
242 chrome::NOTIFICATION_EXTENSION_UNINSTALLED_DEPRECATED,
243 content::NotificationService::AllSources());
245 // Crashes
246 registrar_.Add(this, content::NOTIFICATION_RENDER_WIDGET_HOST_HANG,
247 content::NotificationService::AllSources());
248 registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_CLOSED,
249 content::NotificationService::AllSources());
251 // Profiles (for unclean exit)
252 registrar_.Add(this, chrome::NOTIFICATION_PROFILE_ADDED,
253 content::NotificationService::AllSources());
255 // Page load times
256 registrar_.Add(this, content::NOTIFICATION_LOAD_STOP,
257 content::NotificationService::AllSources());
260 // We check if profiles exited cleanly initialization time in case they were
261 // loaded prior to PerformanceMonitor's initialization. Later profiles will be
262 // checked through the PROFILE_ADDED notification.
263 void PerformanceMonitor::CheckForUncleanExits() {
264 DCHECK(database_logging_enabled_);
266 std::vector<Profile*> profiles =
267 g_browser_process->profile_manager()->GetLoadedProfiles();
269 for (std::vector<Profile*>::const_iterator iter = profiles.begin();
270 iter != profiles.end(); ++iter) {
271 if ((*iter)->GetLastSessionExitType() == Profile::EXIT_CRASHED) {
272 BrowserThread::PostBlockingPoolSequencedTask(
273 Database::kDatabaseSequenceToken,
274 FROM_HERE,
275 base::Bind(&PerformanceMonitor::AddUncleanExitEventOnBackgroundThread,
276 base::Unretained(this),
277 (*iter)->GetDebugName()));
282 void PerformanceMonitor::AddUncleanExitEventOnBackgroundThread(
283 const std::string& profile_name) {
284 DCHECK(database_logging_enabled_);
285 std::string database_key = kStateProfilePrefix + profile_name;
286 std::string last_active_string = database_->GetStateValue(database_key);
288 // Check if there was no previous time; this should only happen if the profile
289 // was last used prior to PerformanceMonitor's integration. Do nothing in this
290 // case, since the event was prior to the beginning of our recording.
291 if (last_active_string.empty())
292 return;
294 base::Time last_active_time;
295 CHECK(StringToTime(last_active_string, &last_active_time));
297 scoped_ptr<Event> event =
298 util::CreateUncleanExitEvent(last_active_time, profile_name);
300 database_->AddEvent(*event.get());
303 void PerformanceMonitor::CheckForVersionUpdateOnBackgroundThread() {
304 CHECK(!BrowserThread::CurrentlyOn(BrowserThread::UI));
305 DCHECK(database_logging_enabled_);
307 chrome::VersionInfo version;
308 DCHECK(version.is_valid());
309 std::string current_version = version.Version();
311 std::string previous_version = database_->GetStateValue(kStateChromeVersion);
313 // We should never have a current_version which is older than the
314 // previous_version.
315 DCHECK(current_version >= previous_version);
317 // If this is the first run, there will not be a stored value for Chrome
318 // version; we insert the current version and will insert an event for the
319 // next update of Chrome. If the previous version is older than the current
320 // version, update the state in the database and insert an event.
321 if (current_version > previous_version) {
322 database_->AddStateValue(kStateChromeVersion, current_version);
323 if (!previous_version.empty()) {
324 scoped_ptr<Event> event = util::CreateChromeUpdateEvent(
325 base::Time::Now(), previous_version, current_version);
326 database_->AddEvent(*event.get());
331 void PerformanceMonitor::AddEvent(scoped_ptr<Event> event) {
332 DCHECK(database_logging_enabled_);
334 BrowserThread::PostBlockingPoolSequencedTask(
335 Database::kDatabaseSequenceToken,
336 FROM_HERE,
337 base::Bind(&PerformanceMonitor::AddEventOnBackgroundThread,
338 base::Unretained(this),
339 base::Passed(&event)));
342 void PerformanceMonitor::AddEventOnBackgroundThread(scoped_ptr<Event> event) {
343 database_->AddEvent(*event.get());
346 void PerformanceMonitor::AddMetricOnBackgroundThread(const Metric& metric) {
347 DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::UI));
348 DCHECK(database_logging_enabled_);
350 database_->AddMetric(metric);
353 void PerformanceMonitor::NotifyInitialized() {
354 content::NotificationService::current()->Notify(
355 chrome::NOTIFICATION_PERFORMANCE_MONITOR_INITIALIZED,
356 content::Source<PerformanceMonitor>(this),
357 content::NotificationService::NoDetails());
359 initialized_ = true;
362 void PerformanceMonitor::DoTimedCollections() {
363 #if !defined(OS_ANDROID)
364 // The profile list is only useful for the logged events.
365 if (database_logging_enabled_)
366 UpdateLiveProfiles();
367 #endif
369 GatherMetricsMapOnUIThread();
372 void PerformanceMonitor::GatherMetricsMapOnUIThread() {
373 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
374 static int current_update_sequence = 0;
375 // Even in the "somewhat" unlikely event this wraps around,
376 // it doesn't matter. We just check it for inequality.
377 current_update_sequence++;
379 // Find all render child processes; has to be done on the UI thread.
380 for (content::RenderProcessHost::iterator rph_iter =
381 content::RenderProcessHost::AllHostsIterator();
382 !rph_iter.IsAtEnd(); rph_iter.Advance()) {
383 base::ProcessHandle handle = rph_iter.GetCurrentValue()->GetHandle();
384 MarkProcessAsAlive(handle, content::PROCESS_TYPE_RENDERER,
385 current_update_sequence);
388 BrowserThread::PostTask(
389 BrowserThread::IO,
390 FROM_HERE,
391 base::Bind(&PerformanceMonitor::GatherMetricsMapOnIOThread,
392 base::Unretained(this),
393 current_update_sequence));
396 void PerformanceMonitor::MarkProcessAsAlive(const base::ProcessHandle& handle,
397 int process_type,
398 int current_update_sequence) {
400 if (handle == 0) {
401 // Process may not be valid yet.
402 return;
405 MetricsMap::iterator process_metrics_iter = metrics_map_.find(handle);
406 if (process_metrics_iter == metrics_map_.end()) {
407 // If we're not already watching the process, let's initialize it.
408 metrics_map_[handle]
409 .Initialize(handle, process_type, current_update_sequence);
410 } else {
411 // If we are watching the process, touch it to keep it alive.
412 ProcessMetricsHistory& process_metrics = process_metrics_iter->second;
413 process_metrics.set_last_update_sequence(current_update_sequence);
417 #if !defined(OS_ANDROID)
418 void PerformanceMonitor::UpdateLiveProfiles() {
419 std::string time = TimeToString(base::Time::Now());
420 scoped_ptr<std::set<std::string> > active_profiles(
421 new std::set<std::string>());
423 for (chrome::BrowserIterator it; !it.done(); it.Next())
424 active_profiles->insert(it->profile()->GetDebugName());
426 BrowserThread::PostBlockingPoolSequencedTask(
427 Database::kDatabaseSequenceToken,
428 FROM_HERE,
429 base::Bind(&PerformanceMonitor::UpdateLiveProfilesHelper,
430 base::Unretained(this),
431 base::Passed(&active_profiles),
432 time));
435 void PerformanceMonitor::UpdateLiveProfilesHelper(
436 scoped_ptr<std::set<std::string> > active_profiles,
437 std::string time) {
438 CHECK(!BrowserThread::CurrentlyOn(BrowserThread::UI));
439 DCHECK(database_logging_enabled_);
441 for (std::set<std::string>::const_iterator iter = active_profiles->begin();
442 iter != active_profiles->end(); ++iter) {
443 database_->AddStateValue(kStateProfilePrefix + *iter, time);
446 #endif
448 void PerformanceMonitor::GatherMetricsMapOnIOThread(
449 int current_update_sequence) {
450 CHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
452 // Find all child processes (does not include renderers), which has to be
453 // done on the IO thread.
454 for (content::BrowserChildProcessHostIterator iter; !iter.Done(); ++iter) {
455 const content::ChildProcessData& child_process_data = iter.GetData();
456 base::ProcessHandle handle = child_process_data.handle;
457 MarkProcessAsAlive(handle, child_process_data.process_type,
458 current_update_sequence);
461 // Add the current (browser) process.
462 MarkProcessAsAlive(base::GetCurrentProcessHandle(),
463 content::PROCESS_TYPE_BROWSER, current_update_sequence);
465 BrowserThread::PostBlockingPoolSequencedTask(
466 Database::kDatabaseSequenceToken,
467 FROM_HERE,
468 base::Bind(&PerformanceMonitor::StoreMetricsOnBackgroundThread,
469 base::Unretained(this), current_update_sequence,
470 performance_data_for_io_thread_));
473 void PerformanceMonitor::StoreMetricsOnBackgroundThread(
474 int current_update_sequence,
475 const PerformanceDataForIOThread& performance_data_for_io_thread) {
476 CHECK(!BrowserThread::CurrentlyOn(BrowserThread::UI));
478 base::Time time_now = base::Time::Now();
480 // The timing can be off by kSampleIntervalInSeconds during any one particular
481 // run, but will be correct over time.
482 bool end_of_cycle = time_now >= next_collection_time_;
483 if (end_of_cycle) {
484 next_collection_time_ +=
485 base::TimeDelta::FromSeconds(gather_interval_in_seconds_);
488 double cpu_usage = 0.0;
489 size_t private_memory_sum = 0;
490 size_t shared_memory_sum = 0;
492 // Update metrics for all watched processes; remove dead entries from the map.
493 MetricsMap::iterator iter = metrics_map_.begin();
494 while (iter != metrics_map_.end()) {
495 ProcessMetricsHistory& process_metrics = iter->second;
496 if (process_metrics.last_update_sequence() != current_update_sequence) {
497 // Not touched this iteration; let's get rid of it.
498 metrics_map_.erase(iter++);
499 } else {
500 process_metrics.SampleMetrics();
502 if (end_of_cycle) {
503 // Gather averages of previously sampled metrics.
504 cpu_usage += process_metrics.GetAverageCPUUsage();
506 size_t private_memory = 0;
507 size_t shared_memory = 0;
508 process_metrics.GetAverageMemoryBytes(&private_memory, &shared_memory);
509 private_memory_sum += private_memory;
510 shared_memory_sum += shared_memory;
512 process_metrics.EndOfCycle();
515 ++iter;
519 // Store previously-sampled metrics.
520 if (end_of_cycle && database_logging_enabled_) {
521 if (!metrics_map_.empty()) {
522 database_->AddMetric(Metric(METRIC_CPU_USAGE, time_now, cpu_usage));
523 database_->AddMetric(Metric(METRIC_PRIVATE_MEMORY_USAGE,
524 time_now,
525 static_cast<double>(private_memory_sum)));
526 database_->AddMetric(Metric(METRIC_SHARED_MEMORY_USAGE,
527 time_now,
528 static_cast<double>(shared_memory_sum)));
531 database_->AddMetric(
532 Metric(METRIC_NETWORK_BYTES_READ,
533 time_now,
534 static_cast<double>(
535 performance_data_for_io_thread.network_bytes_read)));
538 BrowserThread::PostTask(
539 BrowserThread::UI,
540 FROM_HERE,
541 base::Bind(&PerformanceMonitor::StartGatherCycle,
542 base::Unretained(this)));
545 void PerformanceMonitor::BytesReadOnIOThread(const net::URLRequest& request,
546 const int bytes_read) {
547 CHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
549 if (initialized_ && !request.url().SchemeIsFile())
550 performance_data_for_io_thread_.network_bytes_read += bytes_read;
553 void PerformanceMonitor::Observe(int type,
554 const content::NotificationSource& source,
555 const content::NotificationDetails& details) {
556 DCHECK(database_logging_enabled_);
558 switch (type) {
559 case chrome::NOTIFICATION_EXTENSION_WILL_BE_INSTALLED_DEPRECATED: {
560 AddExtensionEvent(
561 EVENT_EXTENSION_INSTALL,
562 content::Details<const extensions::InstalledExtensionInfo>(details)->
563 extension);
564 break;
566 case chrome::NOTIFICATION_EXTENSION_ENABLED: {
567 AddExtensionEvent(EVENT_EXTENSION_ENABLE,
568 content::Details<Extension>(details).ptr());
569 break;
571 case chrome::NOTIFICATION_EXTENSION_UNLOADED_DEPRECATED: {
572 const UnloadedExtensionInfo* info =
573 content::Details<UnloadedExtensionInfo>(details).ptr();
575 // Check if the extension was unloaded because it was disabled.
576 if (info->reason == UnloadedExtensionInfo::REASON_DISABLE) {
577 AddExtensionEvent(EVENT_EXTENSION_DISABLE,
578 info->extension);
580 break;
582 case chrome::NOTIFICATION_CRX_INSTALLER_DONE: {
583 const extensions::CrxInstaller* installer =
584 content::Source<extensions::CrxInstaller>(source).ptr();
585 const extensions::Extension* extension =
586 content::Details<Extension>(details).ptr();
588 // Check if the reason for the install was due to a successful
589 // extension update. |extension| is NULL in case of install failure.
590 if (extension &&
591 installer->install_cause() == extension_misc::INSTALL_CAUSE_UPDATE) {
592 AddExtensionEvent(EVENT_EXTENSION_UPDATE, extension);
594 break;
596 case chrome::NOTIFICATION_EXTENSION_UNINSTALLED_DEPRECATED: {
597 AddExtensionEvent(EVENT_EXTENSION_UNINSTALL,
598 content::Details<Extension>(details).ptr());
599 break;
601 case content::NOTIFICATION_RENDER_WIDGET_HOST_HANG: {
602 std::string url;
603 content::RenderWidgetHost* widget =
604 content::Source<content::RenderWidgetHost>(source).ptr();
605 if (widget->IsRenderView()) {
606 content::RenderViewHost* view = content::RenderViewHost::From(widget);
607 MaybeGetURLFromRenderView(view, &url);
609 AddEvent(util::CreateRendererFailureEvent(base::Time::Now(),
610 EVENT_RENDERER_HANG,
611 url));
612 break;
614 case content::NOTIFICATION_RENDERER_PROCESS_CLOSED: {
615 AddRendererClosedEvent(
616 content::Source<content::RenderProcessHost>(source).ptr(),
617 *content::Details<content::RenderProcessHost::RendererClosedDetails>(
618 details).ptr());
619 break;
621 case chrome::NOTIFICATION_PROFILE_ADDED: {
622 Profile* profile = content::Source<Profile>(source).ptr();
623 if (profile->GetLastSessionExitType() == Profile::EXIT_CRASHED) {
624 BrowserThread::PostBlockingPoolSequencedTask(
625 Database::kDatabaseSequenceToken,
626 FROM_HERE,
627 base::Bind(
628 &PerformanceMonitor::AddUncleanExitEventOnBackgroundThread,
629 base::Unretained(this),
630 profile->GetDebugName()));
632 break;
634 case content::NOTIFICATION_LOAD_STOP: {
635 const content::LoadNotificationDetails* load_details =
636 content::Details<content::LoadNotificationDetails>(details).ptr();
637 if (!load_details)
638 break;
639 BrowserThread::PostBlockingPoolSequencedTask(
640 Database::kDatabaseSequenceToken,
641 FROM_HERE,
642 base::Bind(
643 &PerformanceMonitor::AddMetricOnBackgroundThread,
644 base::Unretained(this),
645 Metric(METRIC_PAGE_LOAD_TIME,
646 base::Time::Now(),
647 static_cast<double>(
648 load_details->load_time.ToInternalValue()))));
649 break;
651 default: {
652 NOTREACHED();
653 break;
658 void PerformanceMonitor::AddExtensionEvent(EventType type,
659 const Extension* extension) {
660 DCHECK(type == EVENT_EXTENSION_INSTALL ||
661 type == EVENT_EXTENSION_UNINSTALL ||
662 type == EVENT_EXTENSION_UPDATE ||
663 type == EVENT_EXTENSION_ENABLE ||
664 type == EVENT_EXTENSION_DISABLE);
665 AddEvent(util::CreateExtensionEvent(type,
666 base::Time::Now(),
667 extension->id(),
668 extension->name(),
669 extension->url().spec(),
670 extension->location(),
671 extension->VersionString(),
672 extension->description()));
675 void PerformanceMonitor::AddRendererClosedEvent(
676 content::RenderProcessHost* host,
677 const content::RenderProcessHost::RendererClosedDetails& details) {
678 // We only care if this is an invalid termination.
679 if (details.status == base::TERMINATION_STATUS_NORMAL_TERMINATION ||
680 details.status == base::TERMINATION_STATUS_STILL_RUNNING)
681 return;
683 // Determine the type of crash.
684 EventType type =
685 details.status == base::TERMINATION_STATUS_PROCESS_WAS_KILLED ?
686 EVENT_RENDERER_KILLED : EVENT_RENDERER_CRASH;
688 // A RenderProcessHost may contain multiple render views - for each valid
689 // render view, extract the url, and append it to the string, comma-separating
690 // the entries.
691 std::string url_list;
692 scoped_ptr<content::RenderWidgetHostIterator> widgets(
693 content::RenderWidgetHost::GetRenderWidgetHosts());
694 while (content::RenderWidgetHost* widget = widgets->GetNextHost()) {
695 if (widget->GetProcess()->GetID() != host->GetID())
696 continue;
697 if (!widget->IsRenderView())
698 continue;
700 content::RenderViewHost* view = content::RenderViewHost::From(widget);
701 std::string url;
702 if (!MaybeGetURLFromRenderView(view, &url))
703 continue;
705 if (!url_list.empty())
706 url_list += ", ";
708 url_list += url;
711 AddEvent(util::CreateRendererFailureEvent(base::Time::Now(), type, url_list));
714 } // namespace performance_monitor