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/memory/tab_manager.h" | 5 #include "chrome/browser/memory/tab_manager.h" |
6 | 6 |
7 #include <stddef.h> | 7 #include <stddef.h> |
8 | 8 |
9 #include <algorithm> | 9 #include <algorithm> |
10 #include <set> | 10 #include <set> |
(...skipping 12 matching lines...) Expand all Loading... |
23 #include "base/metrics/histogram.h" | 23 #include "base/metrics/histogram.h" |
24 #include "base/process/process.h" | 24 #include "base/process/process.h" |
25 #include "base/strings/string16.h" | 25 #include "base/strings/string16.h" |
26 #include "base/strings/string_number_conversions.h" | 26 #include "base/strings/string_number_conversions.h" |
27 #include "base/strings/string_util.h" | 27 #include "base/strings/string_util.h" |
28 #include "base/strings/utf_string_conversions.h" | 28 #include "base/strings/utf_string_conversions.h" |
29 #include "base/threading/thread.h" | 29 #include "base/threading/thread.h" |
30 #include "base/time/tick_clock.h" | 30 #include "base/time/tick_clock.h" |
31 #include "build/build_config.h" | 31 #include "build/build_config.h" |
32 #include "chrome/browser/browser_process.h" | 32 #include "chrome/browser/browser_process.h" |
| 33 #include "chrome/browser/media/media_capture_devices_dispatcher.h" |
| 34 #include "chrome/browser/media/media_stream_capture_indicator.h" |
33 #include "chrome/browser/memory/oom_memory_details.h" | 35 #include "chrome/browser/memory/oom_memory_details.h" |
34 #include "chrome/browser/memory/tab_manager_web_contents_data.h" | 36 #include "chrome/browser/memory/tab_manager_web_contents_data.h" |
35 #include "chrome/browser/profiles/profile.h" | 37 #include "chrome/browser/profiles/profile.h" |
36 #include "chrome/browser/ui/browser.h" | 38 #include "chrome/browser/ui/browser.h" |
37 #include "chrome/browser/ui/browser_iterator.h" | 39 #include "chrome/browser/ui/browser_iterator.h" |
38 #include "chrome/browser/ui/browser_list.h" | 40 #include "chrome/browser/ui/browser_list.h" |
39 #include "chrome/browser/ui/host_desktop.h" | 41 #include "chrome/browser/ui/host_desktop.h" |
40 #include "chrome/browser/ui/tab_contents/tab_contents_iterator.h" | 42 #include "chrome/browser/ui/tab_contents/tab_contents_iterator.h" |
41 #include "chrome/browser/ui/tabs/tab_strip_model.h" | 43 #include "chrome/browser/ui/tabs/tab_strip_model.h" |
42 #include "chrome/browser/ui/tabs/tab_utils.h" | 44 #include "chrome/browser/ui/tabs/tab_utils.h" |
(...skipping 377 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
420 Browser* browser = *browser_iterator; | 422 Browser* browser = *browser_iterator; |
421 bool is_browser_for_app = browser->is_app(); | 423 bool is_browser_for_app = browser->is_app(); |
422 const TabStripModel* model = browser->tab_strip_model(); | 424 const TabStripModel* model = browser->tab_strip_model(); |
423 for (int i = 0; i < model->count(); i++) { | 425 for (int i = 0; i < model->count(); i++) { |
424 WebContents* contents = model->GetWebContentsAt(i); | 426 WebContents* contents = model->GetWebContentsAt(i); |
425 if (!contents->IsCrashed()) { | 427 if (!contents->IsCrashed()) { |
426 TabStats stats; | 428 TabStats stats; |
427 stats.is_app = is_browser_for_app; | 429 stats.is_app = is_browser_for_app; |
428 stats.is_internal_page = | 430 stats.is_internal_page = |
429 IsInternalPage(contents->GetLastCommittedURL()); | 431 IsInternalPage(contents->GetLastCommittedURL()); |
430 stats.is_playing_audio = IsAudioTab(contents); | 432 stats.is_media = IsMediaTab(contents); |
431 stats.is_pinned = model->IsTabPinned(i); | 433 stats.is_pinned = model->IsTabPinned(i); |
432 stats.is_selected = browser_active && model->IsTabSelected(i); | 434 stats.is_selected = browser_active && model->IsTabSelected(i); |
433 stats.is_discarded = GetWebContentsData(contents)->IsDiscarded(); | 435 stats.is_discarded = GetWebContentsData(contents)->IsDiscarded(); |
434 stats.has_form_entry = | 436 stats.has_form_entry = |
435 contents->GetPageImportanceSignals().had_form_interaction; | 437 contents->GetPageImportanceSignals().had_form_interaction; |
436 stats.discard_count = GetWebContentsData(contents)->DiscardCount(); | 438 stats.discard_count = GetWebContentsData(contents)->DiscardCount(); |
437 stats.last_active = contents->GetLastActiveTime(); | 439 stats.last_active = contents->GetLastActiveTime(); |
438 stats.renderer_handle = contents->GetRenderProcessHost()->GetHandle(); | 440 stats.renderer_handle = contents->GetRenderProcessHost()->GetHandle(); |
439 stats.child_process_host_id = contents->GetRenderProcessHost()->GetID(); | 441 stats.child_process_host_id = contents->GetRenderProcessHost()->GetID(); |
440 #if defined(OS_CHROMEOS) | 442 #if defined(OS_CHROMEOS) |
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
498 if (!web_contents->GetLastCommittedURL().is_valid() || | 500 if (!web_contents->GetLastCommittedURL().is_valid() || |
499 web_contents->GetLastCommittedURL().is_empty()) { | 501 web_contents->GetLastCommittedURL().is_empty()) { |
500 return false; | 502 return false; |
501 } | 503 } |
502 | 504 |
503 // Do not discard tabs in which the user has entered text in a form, lest that | 505 // Do not discard tabs in which the user has entered text in a form, lest that |
504 // state gets lost. | 506 // state gets lost. |
505 if (web_contents->GetPageImportanceSignals().had_form_interaction) | 507 if (web_contents->GetPageImportanceSignals().had_form_interaction) |
506 return false; | 508 return false; |
507 | 509 |
508 // Do not discard tabs that are playing audio as it's too distruptive to the | 510 // Do not discard tabs that are playing either playing audio or accessing the |
509 // user experience. Note that tabs that have recently stopped playing audio by | 511 // microphone or camera as it's too distruptive to the user experience. Note |
510 // at least |kAudioProtectionTimeSeconds| seconds are protected as well. | 512 // that tabs that have recently stopped playing audio by at least |
511 if (IsAudioTab(web_contents)) | 513 // |kAudioProtectionTimeSeconds| seconds are protected as well. |
| 514 if (IsMediaTab(web_contents)) |
512 return false; | 515 return false; |
513 | 516 |
514 // Do not discard PDFs as they might contain entry that is not saved and they | 517 // Do not discard PDFs as they might contain entry that is not saved and they |
515 // don't remember their scrolling positions. See crbug.com/547286 and | 518 // don't remember their scrolling positions. See crbug.com/547286 and |
516 // crbug.com/65244. | 519 // crbug.com/65244. |
517 // TODO(georgesak): Remove this workaround when the bugs are fixed. | 520 // TODO(georgesak): Remove this workaround when the bugs are fixed. |
518 if (web_contents->GetContentsMimeType() == "application/pdf") | 521 if (web_contents->GetContentsMimeType() == "application/pdf") |
519 return false; | 522 return false; |
520 | 523 |
521 // Do not discard a previously discarded tab if that's the desired behavior. | 524 // Do not discard a previously discarded tab if that's the desired behavior. |
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
587 | 590 |
588 // For the moment only do something when critical state is reached. | 591 // For the moment only do something when critical state is reached. |
589 if (memory_pressure_level == | 592 if (memory_pressure_level == |
590 base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL) { | 593 base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL) { |
591 LogMemoryAndDiscardTab(); | 594 LogMemoryAndDiscardTab(); |
592 } | 595 } |
593 // TODO(skuhne): If more memory pressure levels are introduced, consider | 596 // TODO(skuhne): If more memory pressure levels are introduced, consider |
594 // calling PurgeBrowserMemory() before CRITICAL is reached. | 597 // calling PurgeBrowserMemory() before CRITICAL is reached. |
595 } | 598 } |
596 | 599 |
597 bool TabManager::IsAudioTab(WebContents* contents) const { | 600 bool TabManager::IsMediaTab(WebContents* contents) const { |
598 if (contents->WasRecentlyAudible()) | 601 if (contents->WasRecentlyAudible()) |
599 return true; | 602 return true; |
| 603 |
| 604 scoped_refptr<MediaStreamCaptureIndicator> media_indicator = |
| 605 MediaCaptureDevicesDispatcher::GetInstance() |
| 606 ->GetMediaStreamCaptureIndicator(); |
| 607 if (media_indicator->IsCapturingUserMedia(contents) || |
| 608 media_indicator->IsBeingMirrored(contents)) { |
| 609 return true; |
| 610 } |
| 611 |
600 auto delta = NowTicks() - GetWebContentsData(contents)->LastAudioChangeTime(); | 612 auto delta = NowTicks() - GetWebContentsData(contents)->LastAudioChangeTime(); |
601 return delta < TimeDelta::FromSeconds(kAudioProtectionTimeSeconds); | 613 return delta < TimeDelta::FromSeconds(kAudioProtectionTimeSeconds); |
602 } | 614 } |
603 | 615 |
604 TabManager::WebContentsData* TabManager::GetWebContentsData( | 616 TabManager::WebContentsData* TabManager::GetWebContentsData( |
605 content::WebContents* contents) const { | 617 content::WebContents* contents) const { |
606 WebContentsData::CreateForWebContents(contents); | 618 WebContentsData::CreateForWebContents(contents); |
607 auto web_contents_data = WebContentsData::FromWebContents(contents); | 619 auto web_contents_data = WebContentsData::FromWebContents(contents); |
608 web_contents_data->set_test_tick_clock(test_tick_clock_); | 620 web_contents_data->set_test_tick_clock(test_tick_clock_); |
609 return web_contents_data; | 621 return web_contents_data; |
610 } | 622 } |
611 | 623 |
612 // static | 624 // static |
613 bool TabManager::CompareTabStats(TabStats first, TabStats second) { | 625 bool TabManager::CompareTabStats(TabStats first, TabStats second) { |
614 // Being currently selected is most important to protect. | 626 // Being currently selected is most important to protect. |
615 if (first.is_selected != second.is_selected) | 627 if (first.is_selected != second.is_selected) |
616 return first.is_selected; | 628 return first.is_selected; |
617 | 629 |
618 // Protect tabs with pending form entries. | 630 // Protect tabs with pending form entries. |
619 if (first.has_form_entry != second.has_form_entry) | 631 if (first.has_form_entry != second.has_form_entry) |
620 return first.has_form_entry; | 632 return first.has_form_entry; |
621 | 633 |
622 // Protect streaming audio and video conferencing tabs as these are similar to | 634 // Protect streaming audio and video conferencing tabs as these are similar to |
623 // active tabs. | 635 // active tabs. |
624 if (first.is_playing_audio != second.is_playing_audio) | 636 if (first.is_media != second.is_media) |
625 return first.is_playing_audio; | 637 return first.is_media; |
626 | 638 |
627 // Tab with internal web UI like NTP or Settings are good choices to discard, | 639 // Tab with internal web UI like NTP or Settings are good choices to discard, |
628 // so protect non-Web UI and let the other conditionals finish the sort. | 640 // so protect non-Web UI and let the other conditionals finish the sort. |
629 if (first.is_internal_page != second.is_internal_page) | 641 if (first.is_internal_page != second.is_internal_page) |
630 return !first.is_internal_page; | 642 return !first.is_internal_page; |
631 | 643 |
632 // Being pinned is important to protect. | 644 // Being pinned is important to protect. |
633 if (first.is_pinned != second.is_pinned) | 645 if (first.is_pinned != second.is_pinned) |
634 return first.is_pinned; | 646 return first.is_pinned; |
635 | 647 |
(...skipping 14 matching lines...) Expand all Loading... |
650 } | 662 } |
651 | 663 |
652 TimeTicks TabManager::NowTicks() const { | 664 TimeTicks TabManager::NowTicks() const { |
653 if (!test_tick_clock_) | 665 if (!test_tick_clock_) |
654 return TimeTicks::Now(); | 666 return TimeTicks::Now(); |
655 | 667 |
656 return test_tick_clock_->NowTicks(); | 668 return test_tick_clock_->NowTicks(); |
657 } | 669 } |
658 | 670 |
659 } // namespace memory | 671 } // namespace memory |
OLD | NEW |