Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 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_delegate_chromeos.h" | 5 #include "chrome/browser/memory/tab_manager_delegate_chromeos.h" |
| 6 | 6 |
| 7 #include <stdint.h> | 7 #include <stdint.h> |
| 8 | 8 |
| 9 #include <algorithm> | 9 #include <algorithm> |
| 10 #include <map> | 10 #include <map> |
| (...skipping 18 matching lines...) Expand all Loading... | |
| 29 #include "chrome/browser/memory/memory_kills_monitor.h" | 29 #include "chrome/browser/memory/memory_kills_monitor.h" |
| 30 #include "chrome/browser/memory/tab_stats.h" | 30 #include "chrome/browser/memory/tab_stats.h" |
| 31 #include "chrome/browser/ui/browser.h" | 31 #include "chrome/browser/ui/browser.h" |
| 32 #include "chrome/browser/ui/browser_list.h" | 32 #include "chrome/browser/ui/browser_list.h" |
| 33 #include "chrome/browser/ui/tabs/tab_strip_model.h" | 33 #include "chrome/browser/ui/tabs/tab_strip_model.h" |
| 34 #include "chrome/common/chrome_constants.h" | 34 #include "chrome/common/chrome_constants.h" |
| 35 #include "chrome/common/chrome_features.h" | 35 #include "chrome/common/chrome_features.h" |
| 36 #include "chromeos/dbus/dbus_thread_manager.h" | 36 #include "chromeos/dbus/dbus_thread_manager.h" |
| 37 #include "components/arc/arc_bridge_service.h" | 37 #include "components/arc/arc_bridge_service.h" |
| 38 #include "components/arc/arc_service_manager.h" | 38 #include "components/arc/arc_service_manager.h" |
| 39 #include "components/arc/common/process.mojom.h" | |
| 40 #include "components/device_event_log/device_event_log.h" | 39 #include "components/device_event_log/device_event_log.h" |
| 41 #include "components/exo/shell_surface.h" | 40 #include "components/exo/shell_surface.h" |
| 42 #include "content/public/browser/browser_thread.h" | 41 #include "content/public/browser/browser_thread.h" |
| 43 #include "content/public/browser/notification_service.h" | 42 #include "content/public/browser/notification_service.h" |
| 44 #include "content/public/browser/notification_types.h" | 43 #include "content/public/browser/notification_types.h" |
| 45 #include "content/public/browser/render_process_host.h" | 44 #include "content/public/browser/render_process_host.h" |
| 46 #include "content/public/browser/render_widget_host.h" | 45 #include "content/public/browser/render_widget_host.h" |
| 47 #include "content/public/browser/zygote_host_linux.h" | 46 #include "content/public/browser/zygote_host_linux.h" |
| 48 #include "ui/aura/window.h" | 47 #include "ui/aura/window.h" |
| 49 #include "ui/wm/public/activation_client.h" | 48 #include "ui/wm/public/activation_client.h" |
| (...skipping 29 matching lines...) Expand all Loading... | |
| 79 return base::StartsWith(application_id, kArcProcessNamePrefix, | 78 return base::StartsWith(application_id, kArcProcessNamePrefix, |
| 80 base::CompareCase::SENSITIVE); | 79 base::CompareCase::SENSITIVE); |
| 81 } | 80 } |
| 82 | 81 |
| 83 bool IsArcMemoryManagementEnabled() { | 82 bool IsArcMemoryManagementEnabled() { |
| 84 return base::FeatureList::IsEnabled(features::kArcMemoryManagement); | 83 return base::FeatureList::IsEnabled(features::kArcMemoryManagement); |
| 85 } | 84 } |
| 86 | 85 |
| 87 void OnSetOomScoreAdj(bool success, const std::string& output) { | 86 void OnSetOomScoreAdj(bool success, const std::string& output) { |
| 88 VLOG(2) << "OnSetOomScoreAdj " << success << " " << output; | 87 VLOG(2) << "OnSetOomScoreAdj " << success << " " << output; |
| 89 if (!success || output != "") | 88 if (!success) |
| 90 LOG(WARNING) << "Set OOM score error: " << output; | 89 LOG(ERROR) << "Set OOM score error: " << output; |
|
Yusuke Sato
2017/05/09 22:54:35
Since this is a serious failure, I'd use ERROR.
| |
| 90 else if (!output.empty()) | |
| 91 LOG(WARNING) << "Set OOM score: " << output; | |
| 91 } | 92 } |
| 92 | 93 |
| 93 } // namespace | 94 } // namespace |
| 94 | 95 |
| 96 // static | |
| 97 const int TabManagerDelegate::kLowestOomScore = -1000; | |
| 98 | |
| 95 std::ostream& operator<<(std::ostream& os, const ProcessType& type) { | 99 std::ostream& operator<<(std::ostream& os, const ProcessType& type) { |
| 96 switch (type) { | 100 switch (type) { |
| 97 case ProcessType::FOCUSED_TAB: | 101 case ProcessType::FOCUSED_TAB: |
| 98 return os << "FOCUSED_TAB"; | 102 return os << "FOCUSED_TAB"; |
| 99 case ProcessType::FOCUSED_APP: | 103 case ProcessType::FOCUSED_APP: |
| 100 return os << "FOCUSED_APP"; | 104 return os << "FOCUSED_APP"; |
| 101 case ProcessType::VISIBLE_APP: | 105 case ProcessType::VISIBLE_APP: |
| 102 return os << "VISIBLE_APP"; | 106 return os << "VISIBLE_APP"; |
| 103 case ProcessType::BACKGROUND_TAB: | 107 case ProcessType::BACKGROUND_TAB: |
| 104 return os << "BACKGROUND_TAB"; | 108 return os << "BACKGROUND_TAB"; |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 148 // apps. | 152 // apps. |
| 149 NOTREACHED() << "Undefined comparison between apps and tabs: process_type=" | 153 NOTREACHED() << "Undefined comparison between apps and tabs: process_type=" |
| 150 << process_type(); | 154 << process_type(); |
| 151 return app(); | 155 return app(); |
| 152 } | 156 } |
| 153 | 157 |
| 154 ProcessType TabManagerDelegate::Candidate::GetProcessTypeInternal() const { | 158 ProcessType TabManagerDelegate::Candidate::GetProcessTypeInternal() const { |
| 155 if (app()) { | 159 if (app()) { |
| 156 if (app()->is_focused()) | 160 if (app()->is_focused()) |
| 157 return ProcessType::FOCUSED_APP; | 161 return ProcessType::FOCUSED_APP; |
| 158 if (app()->process_state() <= | 162 if (app()->IsUserVisible()) |
| 159 arc::mojom::ProcessState::IMPORTANT_FOREGROUND) { | |
| 160 return ProcessType::VISIBLE_APP; | 163 return ProcessType::VISIBLE_APP; |
| 161 } | |
| 162 return ProcessType::BACKGROUND_APP; | 164 return ProcessType::BACKGROUND_APP; |
| 163 } | 165 } |
| 164 if (tab()) { | 166 if (tab()) { |
| 165 if (tab()->is_selected) | 167 if (tab()->is_selected) |
| 166 return ProcessType::FOCUSED_TAB; | 168 return ProcessType::FOCUSED_TAB; |
| 167 return ProcessType::BACKGROUND_TAB; | 169 return ProcessType::BACKGROUND_TAB; |
| 168 } | 170 } |
| 169 NOTREACHED() << "Unexpected process type"; | 171 NOTREACHED() << "Unexpected process type"; |
| 170 return ProcessType::UNKNOWN_TYPE; | 172 return ProcessType::UNKNOWN_TYPE; |
| 171 } | 173 } |
| (...skipping 352 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 524 TabManagerDelegate::GetSortedCandidates( | 526 TabManagerDelegate::GetSortedCandidates( |
| 525 const TabStatsList& tab_list, | 527 const TabStatsList& tab_list, |
| 526 const std::vector<arc::ArcProcess>& arc_processes) { | 528 const std::vector<arc::ArcProcess>& arc_processes) { |
| 527 std::vector<Candidate> candidates; | 529 std::vector<Candidate> candidates; |
| 528 candidates.reserve(tab_list.size() + arc_processes.size()); | 530 candidates.reserve(tab_list.size() + arc_processes.size()); |
| 529 | 531 |
| 530 for (const auto& tab : tab_list) { | 532 for (const auto& tab : tab_list) { |
| 531 candidates.emplace_back(&tab); | 533 candidates.emplace_back(&tab); |
| 532 } | 534 } |
| 533 | 535 |
| 534 // A special process on Android side which serves as a dummy "focused" app | |
| 535 // when the focused window is a Chrome side window (i.e., all Android | |
| 536 // processes are running in the background). We don't want to kill it anyway. | |
| 537 static constexpr char kArcInBackgroundDummyprocess[] = | |
| 538 "org.chromium.arc.home"; | |
| 539 | |
| 540 for (const auto& app : arc_processes) { | 536 for (const auto& app : arc_processes) { |
| 541 // Skip persistent android processes since they should never be killed here. | |
| 542 // Neither do we set their OOM scores so their score remains minimum. | |
| 543 if (app.process_state() <= arc::mojom::ProcessState::PERSISTENT_UI || | |
| 544 app.process_name() == kArcInBackgroundDummyprocess) { | |
| 545 continue; | |
| 546 } | |
| 547 candidates.emplace_back(&app); | 537 candidates.emplace_back(&app); |
| 548 } | 538 } |
| 549 | 539 |
| 550 // Sort candidates according to priority. | 540 // Sort candidates according to priority. |
| 551 std::sort(candidates.begin(), candidates.end()); | 541 std::sort(candidates.begin(), candidates.end()); |
| 552 | 542 |
| 553 return candidates; | 543 return candidates; |
| 554 } | 544 } |
| 555 | 545 |
| 556 bool TabManagerDelegate::IsRecentlyKilledArcProcess( | 546 bool TabManagerDelegate::IsRecentlyKilledArcProcess( |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 602 | 592 |
| 603 // Kill processes until the estimated amount of freed memory is sufficient to | 593 // Kill processes until the estimated amount of freed memory is sufficient to |
| 604 // bring the system memory back to a normal level. | 594 // bring the system memory back to a normal level. |
| 605 // The list is sorted by descending importance, so we go through the list | 595 // The list is sorted by descending importance, so we go through the list |
| 606 // backwards. | 596 // backwards. |
| 607 for (auto it = candidates.rbegin(); it != candidates.rend(); ++it) { | 597 for (auto it = candidates.rbegin(); it != candidates.rend(); ++it) { |
| 608 MEMORY_LOG(ERROR) << "Target memory to free: " << target_memory_to_free_kb | 598 MEMORY_LOG(ERROR) << "Target memory to free: " << target_memory_to_free_kb |
| 609 << " KB"; | 599 << " KB"; |
| 610 if (target_memory_to_free_kb <= 0) | 600 if (target_memory_to_free_kb <= 0) |
| 611 break; | 601 break; |
| 612 // Never kill selected tab or Android foreground app, regardless whether | 602 // Never kill selected tab, foreground app, and visible apps regardless of |
| 613 // they're in the active window. Since the user experience would be bad. | 603 // whether they're in the active window. Since the user experience would be |
| 604 // bad. | |
| 614 ProcessType process_type = it->process_type(); | 605 ProcessType process_type = it->process_type(); |
| 615 if (process_type == ProcessType::VISIBLE_APP || | 606 if (process_type <= ProcessType::VISIBLE_APP) { |
| 616 process_type == ProcessType::FOCUSED_APP || | |
| 617 process_type == ProcessType::FOCUSED_TAB) { | |
| 618 MEMORY_LOG(ERROR) << "Skipped killing " << *it; | 607 MEMORY_LOG(ERROR) << "Skipped killing " << *it; |
| 619 continue; | 608 continue; |
| 620 } | 609 } |
| 621 if (it->app()) { | 610 if (it->app()) { |
| 622 if (IsRecentlyKilledArcProcess(it->app()->process_name(), now)) { | 611 if (IsRecentlyKilledArcProcess(it->app()->process_name(), now)) { |
| 623 MEMORY_LOG(ERROR) << "Avoided killing " << *it << " too often"; | 612 MEMORY_LOG(ERROR) << "Avoided killing " << *it << " too often"; |
| 624 continue; | 613 continue; |
| 625 } | 614 } |
| 626 int estimated_memory_freed_kb = | 615 int estimated_memory_freed_kb = |
| 627 mem_stat_->EstimatedMemoryFreedKB(it->app()->pid()); | 616 mem_stat_->EstimatedMemoryFreedKB(it->app()->pid()); |
| (...skipping 25 matching lines...) Expand all Loading... | |
| 653 } | 642 } |
| 654 if (target_memory_to_free_kb > 0) { | 643 if (target_memory_to_free_kb > 0) { |
| 655 MEMORY_LOG(ERROR) | 644 MEMORY_LOG(ERROR) |
| 656 << "Unable to kill enough candidates to meet target_memory_to_free_kb "; | 645 << "Unable to kill enough candidates to meet target_memory_to_free_kb "; |
| 657 } | 646 } |
| 658 } | 647 } |
| 659 | 648 |
| 660 void TabManagerDelegate::AdjustOomPrioritiesImpl( | 649 void TabManagerDelegate::AdjustOomPrioritiesImpl( |
| 661 const TabStatsList& tab_list, | 650 const TabStatsList& tab_list, |
| 662 const std::vector<arc::ArcProcess>& arc_processes) { | 651 const std::vector<arc::ArcProcess>& arc_processes) { |
| 652 std::vector<TabManagerDelegate::Candidate> candidates; | |
| 653 std::vector<TabManagerDelegate::Candidate> apps_non_killable; | |
| 654 | |
| 663 // Least important first. | 655 // Least important first. |
| 664 const auto candidates = GetSortedCandidates(tab_list, arc_processes); | 656 auto all_candidates = GetSortedCandidates(tab_list, arc_processes); |
| 657 for (auto& candidate : all_candidates) { | |
| 658 if (!candidate.app() || candidate.app()->IsKillableForKernel()) { | |
| 659 // Add tabs and killable apps to |candidates|. | |
| 660 candidates.emplace_back(std::move(candidate)); | |
| 661 } else { | |
| 662 // Add non-killable apps to |apps_non_killable|. | |
| 663 apps_non_killable.emplace_back(std::move(candidate)); | |
| 664 } | |
| 665 } | |
| 665 | 666 |
| 666 // Now we assign priorities based on the sorted list. We're assigning | 667 // Now we assign priorities based on the sorted list. We're assigning |
| 667 // priorities in the range of kLowestRendererOomScore to | 668 // priorities in the range of kLowestRendererOomScore to |
| 668 // kHighestRendererOomScore (defined in chrome_constants.h). oom_score_adj | 669 // kHighestRendererOomScore (defined in chrome_constants.h). oom_score_adj |
| 669 // takes values from -1000 to 1000. Negative values are reserved for system | 670 // takes values from -1000 to 1000. Negative values are reserved for system |
| 670 // processes, and we want to give some room below the range we're using to | 671 // processes, and we want to give some room below the range we're using to |
| 671 // allow for things that want to be above the renderers in priority, so the | 672 // allow for things that want to be above the renderers in priority, so the |
| 672 // defined range gives us some variation in priority without taking up the | 673 // defined range gives us some variation in priority without taking up the |
| 673 // whole range. In the end, however, it's a pretty arbitrary range to use. | 674 // whole range. In the end, however, it's a pretty arbitrary range to use. |
| 674 // Higher values are more likely to be killed by the OOM killer. | 675 // Higher values are more likely to be killed by the OOM killer. |
| 675 | 676 |
| 676 // Break the processes into 2 parts. This is to help lower the chance of | 677 // Break the processes into 2 parts. This is to help lower the chance of |
| 677 // altering OOM score for many processes on any small change. | 678 // altering OOM score for many processes on any small change. |
| 678 int range_middle = | 679 int range_middle = |
| 679 (chrome::kLowestRendererOomScore + chrome::kHighestRendererOomScore) / 2; | 680 (chrome::kLowestRendererOomScore + chrome::kHighestRendererOomScore) / 2; |
| 680 | 681 |
| 681 // Find some pivot point. For now processes with priority >= CHROME_INTERNAL | 682 // Find some pivot point. For now processes with priority >= CHROME_INTERNAL |
| 682 // are prone to be affected by LRU change. Taking them as "high priority" | 683 // are prone to be affected by LRU change. Taking them as "high priority" |
| 683 // processes. | 684 // processes. |
| 684 auto lower_priority_part = candidates.end(); | 685 auto lower_priority_part = candidates.end(); |
| 685 for (auto it = candidates.begin(); it != candidates.end(); ++it) { | 686 for (auto it = candidates.begin(); it != candidates.end(); ++it) { |
| 686 if (it->process_type() >= ProcessType::BACKGROUND_APP) { | 687 if (it->process_type() >= ProcessType::BACKGROUND_APP) { |
| 687 lower_priority_part = it; | 688 lower_priority_part = it; |
| 688 break; | 689 break; |
| 689 } | 690 } |
| 690 } | 691 } |
| 691 | 692 |
| 692 ProcessScoreMap new_map; | 693 ProcessScoreMap new_map; |
| 693 | 694 |
| 695 // Make the apps non-killable. | |
| 696 if (!apps_non_killable.empty()) | |
| 697 SetOomScore(apps_non_killable, kLowestOomScore, &new_map); | |
| 698 | |
| 694 // Higher priority part. | 699 // Higher priority part. |
| 695 DistributeOomScoreInRange(candidates.begin(), lower_priority_part, | 700 DistributeOomScoreInRange(candidates.begin(), lower_priority_part, |
| 696 chrome::kLowestRendererOomScore, range_middle, | 701 chrome::kLowestRendererOomScore, range_middle, |
| 697 &new_map); | 702 &new_map); |
| 698 // Lower priority part. | 703 // Lower priority part. |
| 699 DistributeOomScoreInRange(lower_priority_part, candidates.end(), range_middle, | 704 DistributeOomScoreInRange(lower_priority_part, candidates.end(), range_middle, |
| 700 chrome::kHighestRendererOomScore, &new_map); | 705 chrome::kHighestRendererOomScore, &new_map); |
| 706 | |
| 701 oom_score_map_.swap(new_map); | 707 oom_score_map_.swap(new_map); |
| 702 } | 708 } |
| 703 | 709 |
| 710 void TabManagerDelegate::SetOomScore( | |
| 711 const std::vector<TabManagerDelegate::Candidate>& candidates, | |
| 712 int score, | |
| 713 ProcessScoreMap* new_map) { | |
| 714 DistributeOomScoreInRange(candidates.begin(), candidates.end(), score - 1, | |
| 715 score - 1, new_map); | |
| 716 } | |
| 717 | |
| 704 void TabManagerDelegate::DistributeOomScoreInRange( | 718 void TabManagerDelegate::DistributeOomScoreInRange( |
| 705 std::vector<TabManagerDelegate::Candidate>::const_iterator begin, | 719 std::vector<TabManagerDelegate::Candidate>::const_iterator begin, |
| 706 std::vector<TabManagerDelegate::Candidate>::const_iterator end, | 720 std::vector<TabManagerDelegate::Candidate>::const_iterator end, |
| 707 int range_begin, | 721 int range_begin, |
| 708 int range_end, | 722 int range_end, |
| 709 ProcessScoreMap* new_map) { | 723 ProcessScoreMap* new_map) { |
| 710 // Processes whose OOM scores should be updated. Ignore duplicated pids but | 724 // Processes whose OOM scores should be updated. Ignore duplicated pids but |
| 711 // the last occurrence. | 725 // the last occurrence. |
| 712 std::map<base::ProcessHandle, int32_t> oom_scores_to_change; | 726 std::map<base::ProcessHandle, int32_t> oom_scores_to_change; |
| 713 | 727 |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 752 } | 766 } |
| 753 priority += priority_increment; | 767 priority += priority_increment; |
| 754 } | 768 } |
| 755 | 769 |
| 756 if (oom_scores_to_change.size()) | 770 if (oom_scores_to_change.size()) |
| 757 GetDebugDaemonClient()->SetOomScoreAdj( | 771 GetDebugDaemonClient()->SetOomScoreAdj( |
| 758 oom_scores_to_change, base::Bind(&OnSetOomScoreAdj)); | 772 oom_scores_to_change, base::Bind(&OnSetOomScoreAdj)); |
| 759 } | 773 } |
| 760 | 774 |
| 761 } // namespace memory | 775 } // namespace memory |
| OLD | NEW |