| 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.
|
| + // 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
|
|
|