Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1275)

Unified Diff: chrome/browser/memory/tab_manager_delegate_chromeos.cc

Issue 2095413002: TabManagerDelegate: Better prioritize ARC processes. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: sync to ToT Created 4 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
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 5ffbd0b6d4f490d7f156a4f2726f80c3e3adbe2d..f2c3a075c6c6a44d3f4e11ced88fa124f1ad4a70 100644
--- a/chrome/browser/memory/tab_manager_delegate_chromeos.cc
+++ b/chrome/browser/memory/tab_manager_delegate_chromeos.cc
@@ -76,83 +76,85 @@ bool IsArcWindow(aura::Window* window) {
base::CompareCase::SENSITIVE);
}
-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);
}
} // namespace
+std::ostream& operator<<(std::ostream& os, const ProcessType& type) {
+ switch (type) {
+ case ProcessType::FOCUSED_APP:
+ return os << "FOCUSED_APP/FOCUSED_TAB";
+ case ProcessType::VISIBLE_APP:
+ return os << "VISIBLE_APP";
+ case ProcessType::BACKGROUND_APP:
+ return os << "BACKGROUND_APP";
+ case ProcessType::BACKGROUND_TAB:
+ return os << "BACKGROUND_TAB";
+ case ProcessType::UNKNOWN_TYPE:
+ return os << "UNKNOWN_TYPE";
+ default:
+ return os << "NOT_IMPLEMENTED_ERROR";
+ }
+ return os;
+}
+
+// TabManagerDelegate::Candidate implementation.
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() << ")"
+ << ", process_state " << candidate.app()->process_state()
+ << ", is_focused " << candidate.app()->is_focused()
+ << ", 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;
}
+TabManagerDelegate::Candidate& TabManagerDelegate::Candidate::operator=(
+ TabManagerDelegate::Candidate&& other) {
+ tab_ = other.tab_;
+ app_ = other.app_;
+ process_type_ = other.process_type_;
+ return *this;
+}
+
+bool TabManagerDelegate::Candidate::operator<(
+ const TabManagerDelegate::Candidate& rhs) const {
+ if (process_type() != rhs.process_type())
+ return process_type() < rhs.process_type();
+ if (app() && rhs.app())
+ return *app() < *rhs.app();
+ if (tab() && rhs.tab())
+ return TabManager::CompareTabStats(*tab(), *rhs.tab());
+ // Impossible case. If app and tab are mixed in one process type, favor
+ // apps.
+ NOTREACHED() << "Undefined comparison between apps and tabs";
+ return app();
+}
+
+ProcessType TabManagerDelegate::Candidate::GetProcessTypeInternal() const {
+ if (app()) {
+ if (app()->is_focused())
+ return ProcessType::FOCUSED_APP;
+ if (app()->process_state() == arc::mojom::ProcessState::TOP)
+ return ProcessType::VISIBLE_APP;
+ return ProcessType::BACKGROUND_APP;
+ }
+ if (tab()) {
+ if (tab()->is_selected)
+ return ProcessType::FOCUSED_TAB;
+ return ProcessType::BACKGROUND_TAB;
+ }
+ NOTREACHED() << "Unexpected process type";
+ return ProcessType::UNKNOWN_TYPE;
+}
+
// Holds the info of a newly focused tab or app window. The focused process is
// set to highest priority (lowest OOM score), but not immediately. To avoid
// redundant settings the OOM score adjusting only happens after a timeout. If
@@ -405,6 +407,10 @@ void TabManagerDelegate::OnInstanceClosed() {
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,
@@ -598,32 +604,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 constexpr 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.emplace_back(&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)
+ // Skip persistent android processes since they should never be killed here.
+ // Neither do we set their OOM scores so their score remains minimum.
+ //
+ // 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.process_state() <= arc::mojom::ProcessState::PERSISTENT_UI ||
+ app.process_name() == kAppLauncherProcessName)
continue;
- candidates.push_back(candidate);
+ candidates.emplace_back(&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;
@@ -648,37 +659,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 descending importance, 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) {
- int estimated_memory_freed_kb =
- mem_stat_->EstimatedMemoryFreedKB(entry.app->pid());
- if (KillArcProcess(entry.app->nspid())) {
- target_memory_to_free_kb -= estimated_memory_freed_kb;
- uma_->ReportKill(estimated_memory_freed_kb);
- VLOG(2) << "Killed " << entry;
- }
+ if (it->app()) {
+ int estimated_memory_freed_kb =
+ 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 " << *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)
@@ -690,7 +705,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
@@ -710,10 +725,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;
}
@@ -722,13 +736,12 @@ 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(),
- range_middle, chrome::kHighestRendererOomScore,
- &new_map);
+ DistributeOomScoreInRange(lower_priority_part, candidates.end(), range_middle,
+ chrome::kHighestRendererOomScore, &new_map);
base::AutoLock oom_score_autolock(oom_score_lock_);
oom_score_map_.swap(new_map);
}
@@ -762,8 +775,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) {
@@ -774,27 +787,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
« no previous file with comments | « chrome/browser/memory/tab_manager_delegate_chromeos.h ('k') | chrome/browser/memory/tab_manager_delegate_chromeos_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698