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 <algorithm> | 7 #include <algorithm> |
| 8 #include <set> | 8 #include <set> |
| 9 #include <string> | 9 #include <string> |
| 10 #include <vector> | 10 #include <vector> |
| (...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 69 | 69 |
| 70 // Checks if a window renders ARC apps. | 70 // Checks if a window renders ARC apps. |
| 71 bool IsArcWindow(aura::Window* window) { | 71 bool IsArcWindow(aura::Window* window) { |
| 72 if (!window || window->name() != kExoShellSurfaceWindowName) | 72 if (!window || window->name() != kExoShellSurfaceWindowName) |
| 73 return false; | 73 return false; |
| 74 std::string application_id = exo::ShellSurface::GetApplicationId(window); | 74 std::string application_id = exo::ShellSurface::GetApplicationId(window); |
| 75 return base::StartsWith(application_id, kArcProcessNamePrefix, | 75 return base::StartsWith(application_id, kArcProcessNamePrefix, |
| 76 base::CompareCase::SENSITIVE); | 76 base::CompareCase::SENSITIVE); |
| 77 } | 77 } |
| 78 | 78 |
| 79 bool IsArcWindowInForeground() { | |
| 80 auto activation_client = GetActivationClient(); | |
| 81 return activation_client && IsArcWindow(activation_client->GetActiveWindow()); | |
| 82 } | |
| 83 | |
| 84 int AppStateToPriority( | |
| 85 const arc::mojom::ProcessState& process_state) { | |
| 86 // Logic copied from Android: | |
| 87 // frameworks/base/core/java/android/app/ActivityManager.java | |
| 88 // Note that ProcessState enumerates from most important (lower value) to | |
| 89 // least important (higher value), while ProcessPriority enumerates the | |
| 90 // opposite. | |
| 91 if (process_state >= arc::mojom::ProcessState::HOME) { | |
| 92 return ProcessPriority::ANDROID_BACKGROUND; | |
| 93 } else if (process_state >= arc::mojom::ProcessState::SERVICE) { | |
| 94 return ProcessPriority::ANDROID_SERVICE; | |
| 95 } else if (process_state >= arc::mojom::ProcessState::HEAVY_WEIGHT) { | |
| 96 return ProcessPriority::ANDROID_CANT_SAVE_STATE; | |
| 97 } else if (process_state >= arc::mojom::ProcessState::IMPORTANT_BACKGROUND) { | |
| 98 return ProcessPriority::ANDROID_PERCEPTIBLE; | |
| 99 } else if (process_state >= arc::mojom::ProcessState::IMPORTANT_FOREGROUND) { | |
| 100 return ProcessPriority::ANDROID_VISIBLE; | |
| 101 } else if (process_state >= arc::mojom::ProcessState::TOP_SLEEPING) { | |
| 102 return ProcessPriority::ANDROID_TOP_SLEEPING; | |
| 103 } else if (process_state >= arc::mojom::ProcessState::FOREGROUND_SERVICE) { | |
| 104 return ProcessPriority::ANDROID_FOREGROUND_SERVICE; | |
| 105 } else if (process_state >= arc::mojom::ProcessState::TOP) { | |
| 106 return IsArcWindowInForeground() ? | |
| 107 ProcessPriority::ANDROID_TOP : | |
| 108 ProcessPriority::ANDROID_TOP_INACTIVE; | |
| 109 } else if (process_state >= arc::mojom::ProcessState::PERSISTENT) { | |
| 110 return ProcessPriority::ANDROID_PERSISTENT; | |
| 111 } | |
| 112 return ProcessPriority::ANDROID_NON_EXISTS; | |
| 113 } | |
| 114 | |
| 115 int TabStatsToPriority(const TabStats& tab) { | |
| 116 if (tab.is_selected) | |
| 117 return ProcessPriority::CHROME_SELECTED; | |
| 118 | |
| 119 int priority = 0; | |
| 120 | |
| 121 if (tab.is_app) { | |
| 122 priority = ProcessPriority::CHROME_APP; | |
| 123 } else if (tab.is_internal_page) { | |
| 124 priority = ProcessPriority::CHROME_INTERNAL; | |
| 125 } else { | |
| 126 priority = ProcessPriority::CHROME_NORMAL; | |
| 127 } | |
| 128 if (tab.is_pinned) | |
| 129 priority |= ProcessPriority::CHROME_PINNED; | |
| 130 if (tab.is_media) | |
| 131 priority |= ProcessPriority::CHROME_MEDIA; | |
| 132 if (tab.has_form_entry) | |
| 133 priority |= ProcessPriority::CHROME_CANT_SAVE_STATE; | |
| 134 | |
| 135 return priority; | |
| 136 } | |
| 137 | |
| 138 bool IsArcMemoryManagementEnabled() { | 79 bool IsArcMemoryManagementEnabled() { |
| 139 return base::FeatureList::IsEnabled(features::kArcMemoryManagement); | 80 return base::FeatureList::IsEnabled(features::kArcMemoryManagement); |
| 140 } | 81 } |
| 141 | 82 |
| 142 } // namespace | 83 } // namespace |
| 143 | 84 |
| 85 std::ostream& operator<<(std::ostream& os, const ProcessType& type) { | |
| 86 switch (type) { | |
| 87 case ProcessType::FOCUSED_APP: | |
| 88 os << "FOCUSED_APP/FOCUSED_TAB"; | |
|
Luis Héctor Chávez
2016/07/22 03:01:43
style nit: having "return os << ..." saves you one
cylee1
2016/07/22 22:18:43
Done.
| |
| 89 break; | |
| 90 case ProcessType::VISIBLE_APP: | |
| 91 os << "VISIBLE_APP"; | |
| 92 break; | |
| 93 case ProcessType::BACKGROUND_APP: | |
| 94 os << "BACKGROUND_APP"; | |
| 95 break; | |
| 96 case ProcessType::BACKGROUND_TAB: | |
| 97 os << "BACKGROUND_TAB"; | |
| 98 break; | |
| 99 case ProcessType::UNKNOWN_TYPE: | |
| 100 os << "UNKNOWN_TYPE"; | |
| 101 break; | |
| 102 default: | |
| 103 os << "NOT_IMPLEMENTED_ERROR"; | |
| 104 } | |
| 105 return os; | |
| 106 } | |
| 107 | |
| 108 // TabManagerDelegate::Candidate implementation. | |
| 144 std::ostream& operator<<( | 109 std::ostream& operator<<( |
| 145 std::ostream& out, const TabManagerDelegate::Candidate& candidate) { | 110 std::ostream& out, const TabManagerDelegate::Candidate& candidate) { |
| 146 if (candidate.is_arc_app) { | 111 if (candidate.app()) { |
| 147 out << "app " << candidate.app->pid() | 112 out << "app " << candidate.app()->pid() << " (" |
| 148 << " (" << candidate.app->process_name() << ")"; | 113 << candidate.app()->process_name() << ")" |
| 149 } else { | 114 << ", process_state " << candidate.app()->process_state() |
| 150 out << "tab " << candidate.tab->renderer_handle; | 115 << ", is_focused " << candidate.app()->is_focused() |
| 116 << ", lastActivityTime " << candidate.app()->last_activity_time(); | |
| 117 } else if (candidate.tab()) { | |
| 118 out << "tab " << candidate.tab()->renderer_handle; | |
| 151 } | 119 } |
| 152 out << " with priority " << candidate.priority; | 120 out << ", process_type " << candidate.process_type(); |
| 153 return out; | 121 return out; |
| 154 } | 122 } |
| 155 | 123 |
| 124 TabManagerDelegate::Candidate& TabManagerDelegate::Candidate::operator=( | |
| 125 TabManagerDelegate::Candidate&& other) { | |
| 126 tab_ = other.tab_; | |
| 127 app_ = other.app_; | |
| 128 process_type_ = other.process_type_; | |
| 129 return *this; | |
| 130 } | |
| 131 | |
| 132 bool TabManagerDelegate::Candidate::operator<( | |
| 133 const TabManagerDelegate::Candidate& rhs) const { | |
| 134 if (process_type() != rhs.process_type()) | |
| 135 return process_type() < rhs.process_type(); | |
| 136 if (app() && rhs.app()) | |
| 137 return *app() < *rhs.app(); | |
| 138 if (tab() && rhs.tab()) | |
| 139 return TabManager::CompareTabStats(*tab(), *rhs.tab()); | |
| 140 // Impossible case. If app and tab are mixed in one process type, favor | |
| 141 // apps. | |
| 142 NOTREACHED() << "Undefined comparison between apps and tabs"; | |
| 143 return app(); | |
| 144 } | |
| 145 | |
| 146 ProcessType TabManagerDelegate::Candidate::GetProcessTypeInternal() const { | |
| 147 if (app()) { | |
| 148 if (app()->is_focused()) | |
| 149 return ProcessType::FOCUSED_APP; | |
| 150 if (app()->process_state() == arc::mojom::ProcessState::TOP) | |
| 151 return ProcessType::VISIBLE_APP; | |
| 152 return ProcessType::BACKGROUND_APP; | |
| 153 } | |
| 154 if (tab()) { | |
| 155 if (tab()->is_selected) | |
| 156 return ProcessType::FOCUSED_TAB; | |
| 157 return ProcessType::BACKGROUND_TAB; | |
| 158 } | |
| 159 NOTREACHED() << "Unexpected process type"; | |
| 160 return ProcessType::UNKNOWN_TYPE; | |
| 161 } | |
| 162 | |
| 156 // Holds the info of a newly focused tab or app window. The focused process is | 163 // Holds the info of a newly focused tab or app window. The focused process is |
| 157 // set to highest priority (lowest OOM score), but not immediately. To avoid | 164 // set to highest priority (lowest OOM score), but not immediately. To avoid |
| 158 // redundant settings the OOM score adjusting only happens after a timeout. If | 165 // redundant settings the OOM score adjusting only happens after a timeout. If |
| 159 // the process loses focus before the timeout, the adjustment is canceled. | 166 // the process loses focus before the timeout, the adjustment is canceled. |
| 160 // | 167 // |
| 161 // This information might be set on UI thread and looked up on FILE thread. So a | 168 // This information might be set on UI thread and looked up on FILE thread. So a |
| 162 // lock is needed to avoid racing. | 169 // lock is needed to avoid racing. |
| 163 class TabManagerDelegate::FocusedProcess { | 170 class TabManagerDelegate::FocusedProcess { |
| 164 public: | 171 public: |
| 165 static const int kInvalidArcAppNspid = 0; | 172 static const int kInvalidArcAppNspid = 0; |
| (...skipping 232 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 398 } | 405 } |
| 399 VLOG(2) << "Disable LowMemoryKiller"; | 406 VLOG(2) << "Disable LowMemoryKiller"; |
| 400 arc_process_instance_->DisableLowMemoryKiller(); | 407 arc_process_instance_->DisableLowMemoryKiller(); |
| 401 } | 408 } |
| 402 | 409 |
| 403 void TabManagerDelegate::OnInstanceClosed() { | 410 void TabManagerDelegate::OnInstanceClosed() { |
| 404 arc_process_instance_ = nullptr; | 411 arc_process_instance_ = nullptr; |
| 405 arc_process_instance_version_ = 0; | 412 arc_process_instance_version_ = 0; |
| 406 } | 413 } |
| 407 | 414 |
| 415 // TODO(cylee): Remove this function if Android process OOM score settings | |
| 416 // is moved back to Android. | |
| 417 // For example, negotiate non-overlapping OOM score ranges so Chrome and Android | |
| 418 // can set OOM score for processes in their own world. | |
| 408 void TabManagerDelegate::OnWindowActivated( | 419 void TabManagerDelegate::OnWindowActivated( |
| 409 aura::client::ActivationChangeObserver::ActivationReason reason, | 420 aura::client::ActivationChangeObserver::ActivationReason reason, |
| 410 aura::Window* gained_active, | 421 aura::Window* gained_active, |
| 411 aura::Window* lost_active) { | 422 aura::Window* lost_active) { |
| 412 if (IsArcWindow(gained_active)) { | 423 if (IsArcWindow(gained_active)) { |
| 413 // Currently there is no way to know which app is displayed in the ARC | 424 // Currently there is no way to know which app is displayed in the ARC |
| 414 // window, so schedule an early adjustment for all processes to reflect | 425 // window, so schedule an early adjustment for all processes to reflect |
| 415 // the change. | 426 // the change. |
| 416 // Put a dummy FocusedProcess with nspid = kInvalidArcAppNspid for now to | 427 // Put a dummy FocusedProcess with nspid = kInvalidArcAppNspid for now to |
| 417 // indicate the focused process is an arc app. | 428 // indicate the focused process is an arc app. |
| (...skipping 173 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 591 base::Bind(&TabManagerDelegate::AdjustOomPrioritiesImpl, | 602 base::Bind(&TabManagerDelegate::AdjustOomPrioritiesImpl, |
| 592 weak_ptr_factory_.GetWeakPtr(), tab_list))) { | 603 weak_ptr_factory_.GetWeakPtr(), tab_list))) { |
| 593 return; | 604 return; |
| 594 } | 605 } |
| 595 } | 606 } |
| 596 // Pass in a dummy list if unable to get ARC processes. | 607 // Pass in a dummy list if unable to get ARC processes. |
| 597 AdjustOomPrioritiesImpl(tab_list, std::vector<arc::ArcProcess>()); | 608 AdjustOomPrioritiesImpl(tab_list, std::vector<arc::ArcProcess>()); |
| 598 } | 609 } |
| 599 | 610 |
| 600 // Excludes persistent ARC apps, but still preserves active chrome tabs and | 611 // Excludes persistent ARC apps, but still preserves active chrome tabs and |
| 601 // top ARC apps. The latter ones should not be killed by TabManager since | 612 // focused ARC apps. The latter ones should not be killed by TabManager here, |
| 602 // we still want to adjust their oom_score_adj. | 613 // but we want to adjust their oom_score_adj. |
| 603 // static | 614 // static |
| 604 std::vector<TabManagerDelegate::Candidate> | 615 std::vector<TabManagerDelegate::Candidate> |
| 605 TabManagerDelegate::GetSortedCandidates( | 616 TabManagerDelegate::GetSortedCandidates( |
| 606 const TabStatsList& tab_list, | 617 const TabStatsList& tab_list, |
| 607 const std::vector<arc::ArcProcess>& arc_processes) { | 618 const std::vector<arc::ArcProcess>& arc_processes) { |
| 619 static constexpr char kAppLauncherProcessName[] = | |
| 620 "org.chromium.arc.applauncher"; | |
| 608 | 621 |
| 609 std::vector<Candidate> candidates; | 622 std::vector<Candidate> candidates; |
| 610 candidates.reserve(tab_list.size() + arc_processes.size()); | 623 candidates.reserve(tab_list.size() + arc_processes.size()); |
| 611 | 624 |
| 612 for (const auto& tab : tab_list) { | 625 for (const auto& tab : tab_list) { |
| 613 candidates.push_back(Candidate(&tab, TabStatsToPriority(tab))); | 626 candidates.push_back(Candidate(&tab)); |
|
Luis Héctor Chávez
2016/07/22 03:01:43
nit: can all the calls to candidates.push_back(Can
cylee1
2016/07/22 22:18:43
Done.
| |
| 614 } | 627 } |
| 615 | 628 |
| 616 for (const auto& app : arc_processes) { | 629 for (const auto& app : arc_processes) { |
| 617 Candidate candidate(&app, AppStateToPriority(app.process_state())); | 630 // Skip persistent android processes since they should never be killed here. |
| 618 // Skip persistent android processes since we should never kill them. | 631 // Neither do we set their OOM scores so their score remains minimum. |
| 619 // Also don't ajust OOM score so their score remains min oom_score_adj. | 632 // |
| 620 if (candidate.priority >= ProcessPriority::ANDROID_PERSISTENT) | 633 // AppLauncher is treated specially in ARC++. For example it is taken |
| 634 // as the dummy foreground app from Android's point of view when the focused | |
| 635 // window is not an Android app. We prefer never kill it. | |
| 636 if (app.process_state() <= arc::mojom::ProcessState::PERSISTENT_UI || | |
| 637 app.process_name() == kAppLauncherProcessName) | |
| 621 continue; | 638 continue; |
| 622 candidates.push_back(candidate); | 639 candidates.push_back(Candidate(&app)); |
| 623 } | 640 } |
| 624 | 641 |
| 625 // Sort candidates according to priority. | 642 // Sort candidates according to priority. |
| 626 // TODO(cylee): Missing LRU property. Fix it when apps has the information. | |
| 627 std::sort(candidates.begin(), candidates.end()); | 643 std::sort(candidates.begin(), candidates.end()); |
| 628 | 644 |
| 629 return candidates; | 645 return candidates; |
| 630 } | 646 } |
| 631 | 647 |
| 632 bool TabManagerDelegate::KillArcProcess(const int nspid) { | 648 bool TabManagerDelegate::KillArcProcess(const int nspid) { |
| 633 if (!arc_process_instance_) | 649 if (!arc_process_instance_) |
| 634 return false; | 650 return false; |
| 635 arc_process_instance_->KillProcess(nspid, "LowMemoryKill"); | 651 arc_process_instance_->KillProcess(nspid, "LowMemoryKill"); |
| 636 return true; | 652 return true; |
| 637 } | 653 } |
| 638 | 654 |
| 639 bool TabManagerDelegate::KillTab(int64_t tab_id) { | 655 bool TabManagerDelegate::KillTab(int64_t tab_id) { |
| 640 // Check |tab_manager_| is alive before taking tabs into consideration. | 656 // Check |tab_manager_| is alive before taking tabs into consideration. |
| 641 return tab_manager_ && | 657 return tab_manager_ && |
| 642 tab_manager_->CanDiscardTab(tab_id) && | 658 tab_manager_->CanDiscardTab(tab_id) && |
| 643 tab_manager_->DiscardTabById(tab_id); | 659 tab_manager_->DiscardTabById(tab_id); |
| 644 } | 660 } |
| 645 | 661 |
| 646 void TabManagerDelegate::LowMemoryKillImpl( | 662 void TabManagerDelegate::LowMemoryKillImpl( |
| 647 const TabStatsList& tab_list, | 663 const TabStatsList& tab_list, |
| 648 const std::vector<arc::ArcProcess>& arc_processes) { | 664 const std::vector<arc::ArcProcess>& arc_processes) { |
| 649 | 665 |
| 650 VLOG(2) << "LowMemoryKilleImpl"; | 666 VLOG(2) << "LowMemoryKilleImpl"; |
| 651 std::vector<TabManagerDelegate::Candidate> candidates = | 667 const std::vector<TabManagerDelegate::Candidate> candidates = |
| 652 GetSortedCandidates(tab_list, arc_processes); | 668 GetSortedCandidates(tab_list, arc_processes); |
| 653 | 669 |
| 654 int target_memory_to_free_kb = mem_stat_->TargetMemoryToFreeKB(); | 670 int target_memory_to_free_kb = mem_stat_->TargetMemoryToFreeKB(); |
| 655 for (const auto& entry : candidates) { | 671 // Kill processes until the estimated amount of freed memory is sufficient to |
| 672 // bring the system memory back to a normal level. | |
| 673 // The list is sorted by descending importance, so we go through the list | |
| 674 // backwards. | |
| 675 for (auto it = candidates.rbegin(); it != candidates.rend(); ++it) { | |
| 656 VLOG(3) << "Target memory to free: " << target_memory_to_free_kb << " KB"; | 676 VLOG(3) << "Target memory to free: " << target_memory_to_free_kb << " KB"; |
| 657 // Never kill selected tab or Android foreground app, regardless whether | 677 // Never kill selected tab or Android foreground app, regardless whether |
| 658 // they're in the active window. Since the user experience would be bad. | 678 // they're in the active window. Since the user experience would be bad. |
| 659 if ((!entry.is_arc_app && | 679 ProcessType process_type = it->process_type(); |
| 660 entry.priority >= ProcessPriority::CHROME_SELECTED) || | 680 if (process_type == ProcessType::VISIBLE_APP || |
| 661 (entry.is_arc_app && | 681 process_type == ProcessType::FOCUSED_APP || |
| 662 entry.priority >= ProcessPriority::ANDROID_TOP_INACTIVE)) { | 682 process_type == ProcessType::FOCUSED_TAB) { |
| 663 VLOG(2) << "Skipped killing " << entry; | 683 VLOG(2) << "Skipped killing " << *it; |
| 664 continue; | 684 continue; |
| 665 } | 685 } |
| 666 if (entry.is_arc_app) { | 686 if (it->app()) { |
| 667 int estimated_memory_freed_kb = | 687 int estimated_memory_freed_kb = |
| 668 mem_stat_->EstimatedMemoryFreedKB(entry.app->pid()); | 688 mem_stat_->EstimatedMemoryFreedKB(it->app()->pid()); |
| 669 if (KillArcProcess(entry.app->nspid())) { | 689 if (KillArcProcess(it->app()->nspid())) { |
| 670 target_memory_to_free_kb -= estimated_memory_freed_kb; | 690 target_memory_to_free_kb -= estimated_memory_freed_kb; |
| 671 uma_->ReportKill(estimated_memory_freed_kb); | 691 uma_->ReportKill(estimated_memory_freed_kb); |
| 672 VLOG(2) << "Killed " << entry; | 692 VLOG(2) << "Killed " << *it; |
| 673 } | 693 } |
| 674 } else { | 694 } else { |
| 675 int64_t tab_id = entry.tab->tab_contents_id; | 695 int64_t tab_id = it->tab()->tab_contents_id; |
| 676 int estimated_memory_freed_kb = | 696 int estimated_memory_freed_kb = |
| 677 mem_stat_->EstimatedMemoryFreedKB(entry.tab->renderer_handle); | 697 mem_stat_->EstimatedMemoryFreedKB(it->tab()->renderer_handle); |
| 678 if (KillTab(tab_id)) { | 698 if (KillTab(tab_id)) { |
| 679 target_memory_to_free_kb -= estimated_memory_freed_kb; | 699 target_memory_to_free_kb -= estimated_memory_freed_kb; |
| 680 uma_->ReportKill(estimated_memory_freed_kb); | 700 uma_->ReportKill(estimated_memory_freed_kb); |
| 681 VLOG(2) << "Killed " << entry; | 701 VLOG(2) << "Killed " << *it; |
| 682 } | 702 } |
| 683 } | 703 } |
| 684 if (target_memory_to_free_kb < 0) | 704 if (target_memory_to_free_kb < 0) |
| 685 break; | 705 break; |
| 686 } | 706 } |
| 687 } | 707 } |
| 688 | 708 |
| 689 void TabManagerDelegate::AdjustOomPrioritiesImpl( | 709 void TabManagerDelegate::AdjustOomPrioritiesImpl( |
| 690 const TabStatsList& tab_list, | 710 const TabStatsList& tab_list, |
| 691 const std::vector<arc::ArcProcess>& arc_processes) { | 711 const std::vector<arc::ArcProcess>& arc_processes) { |
| 692 // Least important first. | 712 // Least important first. |
| 693 auto candidates = GetSortedCandidates(tab_list, arc_processes); | 713 const auto candidates = GetSortedCandidates(tab_list, arc_processes); |
| 694 | 714 |
| 695 // Now we assign priorities based on the sorted list. We're assigning | 715 // Now we assign priorities based on the sorted list. We're assigning |
| 696 // priorities in the range of kLowestRendererOomScore to | 716 // priorities in the range of kLowestRendererOomScore to |
| 697 // kHighestRendererOomScore (defined in chrome_constants.h). oom_score_adj | 717 // kHighestRendererOomScore (defined in chrome_constants.h). oom_score_adj |
| 698 // takes values from -1000 to 1000. Negative values are reserved for system | 718 // takes values from -1000 to 1000. Negative values are reserved for system |
| 699 // processes, and we want to give some room below the range we're using to | 719 // processes, and we want to give some room below the range we're using to |
| 700 // allow for things that want to be above the renderers in priority, so the | 720 // allow for things that want to be above the renderers in priority, so the |
| 701 // defined range gives us some variation in priority without taking up the | 721 // defined range gives us some variation in priority without taking up the |
| 702 // whole range. In the end, however, it's a pretty arbitrary range to use. | 722 // whole range. In the end, however, it's a pretty arbitrary range to use. |
| 703 // Higher values are more likely to be killed by the OOM killer. | 723 // Higher values are more likely to be killed by the OOM killer. |
| 704 | 724 |
| 705 // Break the processes into 2 parts. This is to help lower the chance of | 725 // Break the processes into 2 parts. This is to help lower the chance of |
| 706 // altering OOM score for many processes on any small change. | 726 // altering OOM score for many processes on any small change. |
| 707 int range_middle = | 727 int range_middle = |
| 708 (chrome::kLowestRendererOomScore + chrome::kHighestRendererOomScore) / 2; | 728 (chrome::kLowestRendererOomScore + chrome::kHighestRendererOomScore) / 2; |
| 709 | 729 |
| 710 // Find some pivot point. For now processes with priority >= CHROME_INTERNAL | 730 // Find some pivot point. For now processes with priority >= CHROME_INTERNAL |
| 711 // are prone to be affected by LRU change. Taking them as "high priority" | 731 // are prone to be affected by LRU change. Taking them as "high priority" |
| 712 // processes. | 732 // processes. |
| 713 auto lower_priority_part = candidates.rend(); | 733 auto lower_priority_part = candidates.end(); |
| 714 // Iterate in reverse order since the list is sorted by least importance. | 734 for (auto it = candidates.begin(); it != candidates.end(); ++it) { |
| 715 for (auto it = candidates.rbegin(); it != candidates.rend(); ++it) { | 735 if (it->process_type() >= ProcessType::BACKGROUND_APP) { |
| 716 if (it->priority < ProcessPriority::CHROME_INTERNAL) { | |
| 717 lower_priority_part = it; | 736 lower_priority_part = it; |
| 718 break; | 737 break; |
| 719 } | 738 } |
| 720 } | 739 } |
| 721 | 740 |
| 722 ProcessScoreMap new_map; | 741 ProcessScoreMap new_map; |
| 723 | 742 |
| 724 // Higher priority part. | 743 // Higher priority part. |
| 725 DistributeOomScoreInRange(candidates.rbegin(), lower_priority_part, | 744 DistributeOomScoreInRange(candidates.begin(), lower_priority_part, |
| 726 chrome::kLowestRendererOomScore, range_middle, | 745 chrome::kLowestRendererOomScore, range_middle, |
| 727 &new_map); | 746 &new_map); |
| 728 // Lower priority part. | 747 // Lower priority part. |
| 729 DistributeOomScoreInRange(lower_priority_part, candidates.rend(), | 748 DistributeOomScoreInRange(lower_priority_part, candidates.end(), range_middle, |
| 730 range_middle, chrome::kHighestRendererOomScore, | 749 chrome::kHighestRendererOomScore, &new_map); |
| 731 &new_map); | |
| 732 base::AutoLock oom_score_autolock(oom_score_lock_); | 750 base::AutoLock oom_score_autolock(oom_score_lock_); |
| 733 oom_score_map_.swap(new_map); | 751 oom_score_map_.swap(new_map); |
| 734 } | 752 } |
| 735 | 753 |
| 736 void TabManagerDelegate::SetOomScoreAdjForApp(int nspid, int score) { | 754 void TabManagerDelegate::SetOomScoreAdjForApp(int nspid, int score) { |
| 737 if (!arc_process_instance_) | 755 if (!arc_process_instance_) |
| 738 return; | 756 return; |
| 739 if (arc_process_instance_version_ < 2) { | 757 if (arc_process_instance_version_ < 2) { |
| 740 VLOG(1) << "ProcessInstance version < 2 does not " | 758 VLOG(1) << "ProcessInstance version < 2 does not " |
| 741 "support SetOomScoreAdj() yet."; | 759 "support SetOomScoreAdj() yet."; |
| (...skipping 13 matching lines...) Expand all Loading... | |
| 755 void TabManagerDelegate::SetOomScoreAdjForTabsOnFileThread( | 773 void TabManagerDelegate::SetOomScoreAdjForTabsOnFileThread( |
| 756 const std::vector<std::pair<base::ProcessHandle, int>>& entries) { | 774 const std::vector<std::pair<base::ProcessHandle, int>>& entries) { |
| 757 DCHECK_CURRENTLY_ON(BrowserThread::FILE); | 775 DCHECK_CURRENTLY_ON(BrowserThread::FILE); |
| 758 for (const auto& entry : entries) { | 776 for (const auto& entry : entries) { |
| 759 content::ZygoteHost::GetInstance()->AdjustRendererOOMScore(entry.first, | 777 content::ZygoteHost::GetInstance()->AdjustRendererOOMScore(entry.first, |
| 760 entry.second); | 778 entry.second); |
| 761 } | 779 } |
| 762 } | 780 } |
| 763 | 781 |
| 764 void TabManagerDelegate::DistributeOomScoreInRange( | 782 void TabManagerDelegate::DistributeOomScoreInRange( |
| 765 std::vector<TabManagerDelegate::Candidate>::reverse_iterator rbegin, | 783 std::vector<TabManagerDelegate::Candidate>::const_iterator begin, |
| 766 std::vector<TabManagerDelegate::Candidate>::reverse_iterator rend, | 784 std::vector<TabManagerDelegate::Candidate>::const_iterator end, |
| 767 int range_begin, | 785 int range_begin, |
| 768 int range_end, | 786 int range_end, |
| 769 ProcessScoreMap* new_map) { | 787 ProcessScoreMap* new_map) { |
| 770 // OOM score setting for tabs involves file system operation so should be | 788 // OOM score setting for tabs involves file system operation so should be |
| 771 // done on file thread. | 789 // done on file thread. |
| 772 std::vector<std::pair<base::ProcessHandle, int>> oom_score_for_tabs; | 790 std::vector<std::pair<base::ProcessHandle, int>> oom_score_for_tabs; |
| 773 | 791 |
| 774 // Though there might be duplicate process handles, it doesn't matter to | 792 // Though there might be duplicate process handles, it doesn't matter to |
| 775 // overestimate the number of processes here since the we don't need to | 793 // overestimate the number of processes here since the we don't need to |
| 776 // use up the full range. | 794 // use up the full range. |
| 777 int num = (rend - rbegin); | 795 int num = (end - begin); |
| 778 const float priority_increment = | 796 const float priority_increment = |
| 779 static_cast<float>(range_end - range_begin) / num; | 797 static_cast<float>(range_end - range_begin) / num; |
| 780 | 798 |
| 781 float priority = range_begin; | 799 float priority = range_begin; |
| 782 for (auto cur = rbegin; cur != rend; ++cur) { | 800 for (auto cur = begin; cur != end; ++cur) { |
| 783 int score = static_cast<int>(priority + 0.5f); | 801 int score = static_cast<int>(priority + 0.5f); |
| 784 if (cur->is_arc_app) { | 802 if (cur->app()) { |
| 785 // Use pid as map keys so it's globally unique. | 803 // Use pid as map keys so it's globally unique. |
| 786 (*new_map)[cur->app->pid()] = score; | 804 (*new_map)[cur->app()->pid()] = score; |
| 787 int cur_app_pid_score = 0; | 805 int cur_app_pid_score = 0; |
| 788 { | 806 { |
| 789 base::AutoLock oom_score_autolock(oom_score_lock_); | 807 base::AutoLock oom_score_autolock(oom_score_lock_); |
| 790 cur_app_pid_score = oom_score_map_[cur->app->pid()]; | 808 cur_app_pid_score = oom_score_map_[cur->app()->pid()]; |
| 791 } | 809 } |
| 792 if (cur_app_pid_score != score) { | 810 if (cur_app_pid_score != score) { |
| 793 VLOG(3) << "Set OOM score " << score << " for " << *cur; | 811 VLOG(3) << "Set OOM score " << score << " for " << *cur; |
| 794 SetOomScoreAdjForApp(cur->app->nspid(), score); | 812 SetOomScoreAdjForApp(cur->app()->nspid(), score); |
| 795 } | 813 } |
| 796 } else { | 814 } else { |
| 797 base::ProcessHandle process_handle = cur->tab->renderer_handle; | 815 base::ProcessHandle process_handle = cur->tab()->renderer_handle; |
| 798 // 1. tab_list contains entries for already-discarded tabs. If the PID | 816 // 1. tab_list contains entries for already-discarded tabs. If the PID |
| 799 // (renderer_handle) is zero, we don't need to adjust the oom_score. | 817 // (renderer_handle) is zero, we don't need to adjust the oom_score. |
| 800 // 2. Only add unseen process handle so if there's multiple tab maps to | 818 // 2. Only add unseen process handle so if there's multiple tab maps to |
| 801 // the same process, the process is set to an OOM score based on its "most | 819 // the same process, the process is set to an OOM score based on its "most |
| 802 // important" tab. | 820 // important" tab. |
| 803 if (process_handle != 0 && | 821 if (process_handle != 0 && |
| 804 new_map->find(process_handle) == new_map->end()) { | 822 new_map->find(process_handle) == new_map->end()) { |
| 805 (*new_map)[process_handle] = score; | 823 (*new_map)[process_handle] = score; |
| 806 int process_handle_score = 0; | 824 int process_handle_score = 0; |
| 807 { | 825 { |
| 808 base::AutoLock oom_score_autolock(oom_score_lock_); | 826 base::AutoLock oom_score_autolock(oom_score_lock_); |
| 809 process_handle_score = oom_score_map_[process_handle]; | 827 process_handle_score = oom_score_map_[process_handle]; |
| 810 } | 828 } |
| 811 if (process_handle_score != score) { | 829 if (process_handle_score != score) { |
| 812 oom_score_for_tabs.push_back(std::make_pair(process_handle, score)); | 830 oom_score_for_tabs.push_back(std::make_pair(process_handle, score)); |
| 813 VLOG(3) << "Set OOM score " << score << " for " << *cur; | 831 VLOG(3) << "Set OOM score " << score << " for " << *cur; |
| 814 } | 832 } |
| 815 } else { | 833 } else { |
| 816 continue; // Skip priority increment. | 834 continue; // Skip priority increment. |
| 817 } | 835 } |
| 818 } | 836 } |
| 819 priority += priority_increment; | 837 priority += priority_increment; |
| 820 } | 838 } |
| 821 | 839 |
| 822 if (oom_score_for_tabs.size()) | 840 if (oom_score_for_tabs.size()) |
| 823 SetOomScoreAdjForTabs(oom_score_for_tabs); | 841 SetOomScoreAdjForTabs(oom_score_for_tabs); |
| 824 } | 842 } |
| 825 | 843 |
| 826 } // namespace memory | 844 } // namespace memory |
| OLD | NEW |