Chromium Code Reviews| Index: chrome/browser/memory/tab_manager_delegate_chromeos.cc |
| diff --git a/chrome/browser/memory/tab_manager_delegate_chromeos.cc b/chrome/browser/memory/tab_manager_delegate_chromeos.cc |
| index 482efe35c44111ba25b9837e121bd96f85e14e03..0042182f527b58c509aef7b779185e245c224b53 100644 |
| --- a/chrome/browser/memory/tab_manager_delegate_chromeos.cc |
| +++ b/chrome/browser/memory/tab_manager_delegate_chromeos.cc |
| @@ -75,65 +75,6 @@ bool IsArcWindow(aura::Window* window) { |
| return application_id.find(kArcProcessNamePrefix) == 0; |
| } |
| -bool IsArcWindowInForeground() { |
| - auto activation_client = GetActivationClient(); |
| - return activation_client && IsArcWindow(activation_client->GetActiveWindow()); |
| -} |
| - |
| -int AppStateToPriority( |
| - const arc::mojom::ProcessState& process_state) { |
| - // Logic copied from Android: |
| - // frameworks/base/core/java/android/app/ActivityManager.java |
| - // Note that ProcessState enumerates from most important (lower value) to |
| - // least important (higher value), while ProcessPriority enumerates the |
| - // opposite. |
| - if (process_state >= arc::mojom::ProcessState::HOME) { |
| - return ProcessPriority::ANDROID_BACKGROUND; |
| - } else if (process_state >= arc::mojom::ProcessState::SERVICE) { |
| - return ProcessPriority::ANDROID_SERVICE; |
| - } else if (process_state >= arc::mojom::ProcessState::HEAVY_WEIGHT) { |
| - return ProcessPriority::ANDROID_CANT_SAVE_STATE; |
| - } else if (process_state >= arc::mojom::ProcessState::IMPORTANT_BACKGROUND) { |
| - return ProcessPriority::ANDROID_PERCEPTIBLE; |
| - } else if (process_state >= arc::mojom::ProcessState::IMPORTANT_FOREGROUND) { |
| - return ProcessPriority::ANDROID_VISIBLE; |
| - } else if (process_state >= arc::mojom::ProcessState::TOP_SLEEPING) { |
| - return ProcessPriority::ANDROID_TOP_SLEEPING; |
| - } else if (process_state >= arc::mojom::ProcessState::FOREGROUND_SERVICE) { |
| - return ProcessPriority::ANDROID_FOREGROUND_SERVICE; |
| - } else if (process_state >= arc::mojom::ProcessState::TOP) { |
| - return IsArcWindowInForeground() ? |
| - ProcessPriority::ANDROID_TOP : |
| - ProcessPriority::ANDROID_TOP_INACTIVE; |
| - } else if (process_state >= arc::mojom::ProcessState::PERSISTENT) { |
| - return ProcessPriority::ANDROID_PERSISTENT; |
| - } |
| - return ProcessPriority::ANDROID_NON_EXISTS; |
| -} |
| - |
| -int TabStatsToPriority(const TabStats& tab) { |
| - if (tab.is_selected) |
| - return ProcessPriority::CHROME_SELECTED; |
| - |
| - int priority = 0; |
| - |
| - if (tab.is_app) { |
| - priority = ProcessPriority::CHROME_APP; |
| - } else if (tab.is_internal_page) { |
| - priority = ProcessPriority::CHROME_INTERNAL; |
| - } else { |
| - priority = ProcessPriority::CHROME_NORMAL; |
| - } |
| - if (tab.is_pinned) |
| - priority |= ProcessPriority::CHROME_PINNED; |
| - if (tab.is_media) |
| - priority |= ProcessPriority::CHROME_MEDIA; |
| - if (tab.has_form_entry) |
| - priority |= ProcessPriority::CHROME_CANT_SAVE_STATE; |
| - |
| - return priority; |
| -} |
| - |
| bool IsArcMemoryManagementEnabled() { |
| return base::FeatureList::IsEnabled(features::kArcMemoryManagement); |
| } |
| @@ -142,13 +83,15 @@ bool IsArcMemoryManagementEnabled() { |
| std::ostream& operator<<( |
| std::ostream& out, const TabManagerDelegate::Candidate& candidate) { |
| - if (candidate.is_arc_app) { |
| - out << "app " << candidate.app->pid() |
| - << " (" << candidate.app->process_name() << ")"; |
| - } else { |
| - out << "tab " << candidate.tab->renderer_handle; |
| + if (candidate.app()) { |
| + out << "app " << candidate.app()->pid() |
| + << " (" << candidate.app()->process_name() << ")" |
| + << ", adj " << candidate.app()->adj() |
| + << ", lastActivityTime " << candidate.app()->last_activity_time(); |
| + } else if (candidate.tab()) { |
| + out << "tab " << candidate.tab()->renderer_handle; |
| } |
| - out << " with priority " << candidate.priority; |
| + out << ", process_type " << candidate.process_type(); |
| return out; |
| } |
| @@ -284,15 +227,15 @@ int TabManagerDelegate::MemoryStat::EstimatedMemoryFreedKB( |
| } |
| class TabManagerDelegate::UmaReporter { |
| - public: |
| - UmaReporter() |
| - : last_kill_time_(), total_kills_(0) {} |
| - ~UmaReporter() {} |
| - void ReportKill(const int memory_freed); |
| - |
| - private: |
| - base::Time last_kill_time_; |
| - int total_kills_; |
| + public: |
| + UmaReporter() |
| + : last_kill_time_(), total_kills_(0) {} |
| + ~UmaReporter() {} |
| + void ReportKill(const int memory_freed); |
| + |
| + private: |
| + base::Time last_kill_time_; |
| + int total_kills_; |
| }; |
| void TabManagerDelegate::UmaReporter::ReportKill(const int memory_freed) { |
| @@ -404,6 +347,10 @@ void TabManagerDelegate::OnProcessInstanceClosed() { |
| arc_process_instance_version_ = 0; |
| } |
| +// TODO(cylee): Remove this function if Android process OOM score settings |
| +// is moved back to Android. |
| +// For example, negotiate non-overlapping OOM score ranges so Chrome and Android |
| +// can set OOM score for processes in their own world. |
| void TabManagerDelegate::OnWindowActivated( |
| aura::client::ActivationChangeObserver::ActivationReason reason, |
| aura::Window* gained_active, |
| @@ -597,32 +544,37 @@ void TabManagerDelegate::AdjustOomPriorities(const TabStatsList& tab_list) { |
| } |
| // Excludes persistent ARC apps, but still preserves active chrome tabs and |
| -// top ARC apps. The latter ones should not be killed by TabManager since |
| -// we still want to adjust their oom_score_adj. |
| +// focused ARC apps. The latter ones should not be killed by TabManager here, |
| +// but we want to adjust their oom_score_adj. |
| // static |
| std::vector<TabManagerDelegate::Candidate> |
| TabManagerDelegate::GetSortedCandidates( |
| const TabStatsList& tab_list, |
| const std::vector<arc::ArcProcess>& arc_processes) { |
| + static const char kAppLauncherProcessName[] = "org.chromium.arc.applauncher"; |
| + |
| std::vector<Candidate> candidates; |
| candidates.reserve(tab_list.size() + arc_processes.size()); |
| for (const auto& tab : tab_list) { |
| - candidates.push_back(Candidate(&tab, TabStatsToPriority(tab))); |
| + candidates.push_back(Candidate(&tab)); |
| } |
| for (const auto& app : arc_processes) { |
| - Candidate candidate(&app, AppStateToPriority(app.process_state())); |
| - // Skip persistent android processes since we should never kill them. |
| - // Also don't ajust OOM score so their score remains min oom_score_adj. |
| - if (candidate.priority >= ProcessPriority::ANDROID_PERSISTENT) |
| + // Persistent an system android processes has negative adj value. |
|
Georges Khalil
2016/06/27 20:15:04
nits:
- an -> and
- has -> have
cylee1
2016/07/14 19:15:24
Done.
|
| + // Skip them since they should never be killed here. Also don't ajust |
| + // OOM score so their score remains min oom_score_adj. |
| + // |
| + // AppLauncher is treated specially in ARC++. For example it is taken |
| + // as the dummy foreground app from Android's point of view when the focused |
| + // window is not an Android app. We prefer never kill it. |
| + if (app.adj() < 0 || app.process_name() == kAppLauncherProcessName) |
| continue; |
| - candidates.push_back(candidate); |
| + candidates.push_back(Candidate(&app)); |
| } |
| // Sort candidates according to priority. |
| - // TODO(cylee): Missing LRU property. Fix it when apps has the information. |
| std::sort(candidates.begin(), candidates.end()); |
| return candidates; |
| @@ -647,37 +599,41 @@ void TabManagerDelegate::LowMemoryKillImpl( |
| const std::vector<arc::ArcProcess>& arc_processes) { |
| VLOG(2) << "LowMemoryKilleImpl"; |
| - std::vector<TabManagerDelegate::Candidate> candidates = |
| + const std::vector<TabManagerDelegate::Candidate> candidates = |
| GetSortedCandidates(tab_list, arc_processes); |
| int target_memory_to_free_kb = mem_stat_->TargetMemoryToFreeKB(); |
| - for (const auto& entry : candidates) { |
| + // Kill processes until the estimated amount of freed memory is sufficient to |
| + // bring the system memory back to a normal level. |
| + // The list is sorted by importance descendingly, so we go through the list |
| + // backwards. |
| + for (auto it = candidates.rbegin(); it != candidates.rend(); ++it) { |
| VLOG(3) << "Target memory to free: " << target_memory_to_free_kb << " KB"; |
| // Never kill selected tab or Android foreground app, regardless whether |
| // they're in the active window. Since the user experience would be bad. |
| - if ((!entry.is_arc_app && |
| - entry.priority >= ProcessPriority::CHROME_SELECTED) || |
| - (entry.is_arc_app && |
| - entry.priority >= ProcessPriority::ANDROID_TOP_INACTIVE)) { |
| - VLOG(2) << "Skipped killing " << entry; |
| + ProcessType process_type = it->process_type(); |
| + if (process_type == ProcessType::VISIBLE_APP || |
| + process_type == ProcessType::FOCUSED_APP || |
| + process_type == ProcessType::FOCUSED_TAB) { |
| + VLOG(2) << "Skipped killing " << *it; |
| continue; |
| } |
| - if (entry.is_arc_app) { |
| + if (it->app()) { |
| int estimated_memory_freed_kb = |
| - mem_stat_->EstimatedMemoryFreedKB(entry.app->pid()); |
| - if (KillArcProcess(entry.app->nspid())) { |
| + mem_stat_->EstimatedMemoryFreedKB(it->app()->pid()); |
| + if (KillArcProcess(it->app()->nspid())) { |
| target_memory_to_free_kb -= estimated_memory_freed_kb; |
| uma_->ReportKill(estimated_memory_freed_kb); |
| - VLOG(2) << "Killed " << entry; |
| + VLOG(2) << "Killed " << *it; |
| } |
| } else { |
| - int64_t tab_id = entry.tab->tab_contents_id; |
| + int64_t tab_id = it->tab()->tab_contents_id; |
| int estimated_memory_freed_kb = |
| - mem_stat_->EstimatedMemoryFreedKB(entry.tab->renderer_handle); |
| + mem_stat_->EstimatedMemoryFreedKB(it->tab()->renderer_handle); |
| if (KillTab(tab_id)) { |
| target_memory_to_free_kb -= estimated_memory_freed_kb; |
| uma_->ReportKill(estimated_memory_freed_kb); |
| - VLOG(2) << "Killed " << entry; |
| + VLOG(2) << "Killed " << *it; |
| } |
| } |
| if (target_memory_to_free_kb < 0) |
| @@ -689,7 +645,7 @@ void TabManagerDelegate::AdjustOomPrioritiesImpl( |
| const TabStatsList& tab_list, |
| const std::vector<arc::ArcProcess>& arc_processes) { |
| // Least important first. |
| - auto candidates = GetSortedCandidates(tab_list, arc_processes); |
| + const auto candidates = GetSortedCandidates(tab_list, arc_processes); |
| // Now we assign priorities based on the sorted list. We're assigning |
| // priorities in the range of kLowestRendererOomScore to |
| @@ -709,10 +665,9 @@ void TabManagerDelegate::AdjustOomPrioritiesImpl( |
| // Find some pivot point. For now processes with priority >= CHROME_INTERNAL |
| // are prone to be affected by LRU change. Taking them as "high priority" |
| // processes. |
| - auto lower_priority_part = candidates.rend(); |
| - // Iterate in reverse order since the list is sorted by least importance. |
| - for (auto it = candidates.rbegin(); it != candidates.rend(); ++it) { |
| - if (it->priority < ProcessPriority::CHROME_INTERNAL) { |
| + auto lower_priority_part = candidates.end(); |
| + for (auto it = candidates.begin(); it != candidates.end(); ++it) { |
| + if (it->process_type() >= ProcessType::BACKGROUND_APP) { |
| lower_priority_part = it; |
| break; |
| } |
| @@ -721,11 +676,11 @@ void TabManagerDelegate::AdjustOomPrioritiesImpl( |
| ProcessScoreMap new_map; |
| // Higher priority part. |
| - DistributeOomScoreInRange(candidates.rbegin(), lower_priority_part, |
| + DistributeOomScoreInRange(candidates.begin(), lower_priority_part, |
| chrome::kLowestRendererOomScore, range_middle, |
| &new_map); |
| // Lower priority part. |
| - DistributeOomScoreInRange(lower_priority_part, candidates.rend(), |
| + DistributeOomScoreInRange(lower_priority_part, candidates.end(), |
| range_middle, chrome::kHighestRendererOomScore, |
| &new_map); |
| base::AutoLock oom_score_autolock(oom_score_lock_); |
| @@ -761,8 +716,8 @@ void TabManagerDelegate::SetOomScoreAdjForTabsOnFileThread( |
| } |
| void TabManagerDelegate::DistributeOomScoreInRange( |
| - std::vector<TabManagerDelegate::Candidate>::reverse_iterator rbegin, |
| - std::vector<TabManagerDelegate::Candidate>::reverse_iterator rend, |
| + std::vector<TabManagerDelegate::Candidate>::const_iterator begin, |
| + std::vector<TabManagerDelegate::Candidate>::const_iterator end, |
| int range_begin, |
| int range_end, |
| ProcessScoreMap* new_map) { |
| @@ -773,27 +728,27 @@ void TabManagerDelegate::DistributeOomScoreInRange( |
| // Though there might be duplicate process handles, it doesn't matter to |
| // overestimate the number of processes here since the we don't need to |
| // use up the full range. |
| - int num = (rend - rbegin); |
| + int num = (end - begin); |
| const float priority_increment = |
| static_cast<float>(range_end - range_begin) / num; |
| float priority = range_begin; |
| - for (auto cur = rbegin; cur != rend; ++cur) { |
| + for (auto cur = begin; cur != end; ++cur) { |
| int score = static_cast<int>(priority + 0.5f); |
| - if (cur->is_arc_app) { |
| + if (cur->app()) { |
| // Use pid as map keys so it's globally unique. |
| - (*new_map)[cur->app->pid()] = score; |
| + (*new_map)[cur->app()->pid()] = score; |
| int cur_app_pid_score = 0; |
| { |
| base::AutoLock oom_score_autolock(oom_score_lock_); |
| - cur_app_pid_score = oom_score_map_[cur->app->pid()]; |
| + cur_app_pid_score = oom_score_map_[cur->app()->pid()]; |
| } |
| if (cur_app_pid_score != score) { |
| VLOG(3) << "Set OOM score " << score << " for " << *cur; |
| - SetOomScoreAdjForApp(cur->app->nspid(), score); |
| + SetOomScoreAdjForApp(cur->app()->nspid(), score); |
| } |
| } else { |
| - base::ProcessHandle process_handle = cur->tab->renderer_handle; |
| + base::ProcessHandle process_handle = cur->tab()->renderer_handle; |
| // 1. tab_list contains entries for already-discarded tabs. If the PID |
| // (renderer_handle) is zero, we don't need to adjust the oom_score. |
| // 2. Only add unseen process handle so if there's multiple tab maps to |