| 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 |