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> |
| 11 #include <string> | |
| 12 #include <vector> | 11 #include <vector> |
| 13 | 12 |
| 14 #include "ash/shell.h" | 13 #include "ash/shell.h" |
| 15 #include "base/bind.h" | 14 #include "base/bind.h" |
| 16 #include "base/command_line.h" | 15 #include "base/command_line.h" |
| 17 #include "base/files/file_path.h" | 16 #include "base/files/file_path.h" |
| 18 #include "base/files/file_util.h" | 17 #include "base/files/file_util.h" |
| 19 #include "base/memory/memory_pressure_monitor_chromeos.h" | 18 #include "base/memory/memory_pressure_monitor_chromeos.h" |
| 20 #include "base/metrics/histogram_macros.h" | 19 #include "base/metrics/histogram_macros.h" |
| 21 #include "base/process/process_handle.h" // kNullProcessHandle. | 20 #include "base/process/process_handle.h" // kNullProcessHandle. |
| (...skipping 22 matching lines...) Expand all Loading... | |
| 44 #include "content/public/browser/notification_service.h" | 43 #include "content/public/browser/notification_service.h" |
| 45 #include "content/public/browser/notification_types.h" | 44 #include "content/public/browser/notification_types.h" |
| 46 #include "content/public/browser/render_process_host.h" | 45 #include "content/public/browser/render_process_host.h" |
| 47 #include "content/public/browser/render_widget_host.h" | 46 #include "content/public/browser/render_widget_host.h" |
| 48 #include "content/public/browser/zygote_host_linux.h" | 47 #include "content/public/browser/zygote_host_linux.h" |
| 49 #include "ui/aura/window.h" | 48 #include "ui/aura/window.h" |
| 50 #include "ui/wm/public/activation_client.h" | 49 #include "ui/wm/public/activation_client.h" |
| 51 | 50 |
| 52 using base::ProcessHandle; | 51 using base::ProcessHandle; |
| 53 using base::TimeDelta; | 52 using base::TimeDelta; |
| 53 using base::TimeTicks; | |
| 54 using content::BrowserThread; | 54 using content::BrowserThread; |
| 55 | 55 |
| 56 namespace memory { | 56 namespace memory { |
| 57 namespace { | 57 namespace { |
| 58 | 58 |
| 59 const char kExoShellSurfaceWindowName[] = "ExoShellSurface"; | 59 const char kExoShellSurfaceWindowName[] = "ExoShellSurface"; |
| 60 const char kArcProcessNamePrefix[] = "org.chromium.arc."; | 60 const char kArcProcessNamePrefix[] = "org.chromium.arc."; |
| 61 | 61 |
| 62 // When switching to a new tab the tab's renderer's OOM score needs to be | 62 // When switching to a new tab the tab's renderer's OOM score needs to be |
| 63 // updated to reflect its front-most status and protect it from discard. | 63 // updated to reflect its front-most status and protect it from discard. |
| (...skipping 21 matching lines...) Expand all Loading... | |
| 85 } | 85 } |
| 86 | 86 |
| 87 void OnSetOomScoreAdj(bool success, const std::string& output) { | 87 void OnSetOomScoreAdj(bool success, const std::string& output) { |
| 88 VLOG(2) << "OnSetOomScoreAdj " << success << " " << output; | 88 VLOG(2) << "OnSetOomScoreAdj " << success << " " << output; |
| 89 if (!success || output != "") | 89 if (!success || output != "") |
| 90 LOG(WARNING) << "Set OOM score error: " << output; | 90 LOG(WARNING) << "Set OOM score error: " << output; |
| 91 } | 91 } |
| 92 | 92 |
| 93 } // namespace | 93 } // namespace |
| 94 | 94 |
| 95 // static | |
| 96 const int64_t TabManagerDelegate::kArcSkipKillingTimeInSeconds = 60; | |
| 97 | |
| 95 std::ostream& operator<<(std::ostream& os, const ProcessType& type) { | 98 std::ostream& operator<<(std::ostream& os, const ProcessType& type) { |
| 96 switch (type) { | 99 switch (type) { |
| 97 case ProcessType::FOCUSED_APP: | 100 case ProcessType::FOCUSED_APP: |
| 98 return os << "FOCUSED_APP/FOCUSED_TAB"; | 101 return os << "FOCUSED_APP/FOCUSED_TAB"; |
| 99 case ProcessType::VISIBLE_APP: | 102 case ProcessType::VISIBLE_APP: |
| 100 return os << "VISIBLE_APP"; | 103 return os << "VISIBLE_APP"; |
| 101 case ProcessType::BACKGROUND_APP: | 104 case ProcessType::BACKGROUND_APP: |
| 102 return os << "BACKGROUND_APP"; | 105 return os << "BACKGROUND_APP"; |
| 103 case ProcessType::BACKGROUND_TAB: | 106 case ProcessType::BACKGROUND_TAB: |
| 104 return os << "BACKGROUND_TAB"; | 107 return os << "BACKGROUND_TAB"; |
| (...skipping 440 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 545 } | 548 } |
| 546 candidates.emplace_back(&app); | 549 candidates.emplace_back(&app); |
| 547 } | 550 } |
| 548 | 551 |
| 549 // Sort candidates according to priority. | 552 // Sort candidates according to priority. |
| 550 std::sort(candidates.begin(), candidates.end()); | 553 std::sort(candidates.begin(), candidates.end()); |
| 551 | 554 |
| 552 return candidates; | 555 return candidates; |
| 553 } | 556 } |
| 554 | 557 |
| 558 bool TabManagerDelegate::IsRecentlyKilledArcProcess( | |
| 559 const std::string& process_name, | |
| 560 const TimeTicks& now) { | |
| 561 static constexpr TimeDelta kArcSkipKillingTime = | |
| 562 TimeDelta::FromSeconds(kArcSkipKillingTimeInSeconds); | |
| 563 | |
| 564 auto it = recently_killed_arc_processes_.find(process_name); | |
|
Luis Héctor Chávez
2017/05/02 20:16:27
nit: maybe const auto.
Yusuke Sato
2017/05/02 20:47:32
Done.
| |
| 565 if (it == recently_killed_arc_processes_.end()) | |
| 566 return false; | |
| 567 return (now - it->second) <= kArcSkipKillingTime; | |
| 568 } | |
| 569 | |
| 555 bool TabManagerDelegate::KillArcProcess(const int nspid) { | 570 bool TabManagerDelegate::KillArcProcess(const int nspid) { |
| 556 auto* arc_service_manager = arc::ArcServiceManager::Get(); | 571 auto* arc_service_manager = arc::ArcServiceManager::Get(); |
| 557 if (!arc_service_manager) | 572 if (!arc_service_manager) |
| 558 return false; | 573 return false; |
| 559 | 574 |
| 560 auto* arc_process_instance = ARC_GET_INSTANCE_FOR_METHOD( | 575 auto* arc_process_instance = ARC_GET_INSTANCE_FOR_METHOD( |
| 561 arc_service_manager->arc_bridge_service()->process(), KillProcess); | 576 arc_service_manager->arc_bridge_service()->process(), KillProcess); |
| 562 if (!arc_process_instance) | 577 if (!arc_process_instance) |
| 563 return false; | 578 return false; |
| 564 | 579 |
| (...skipping 16 matching lines...) Expand all Loading... | |
| 581 void TabManagerDelegate::LowMemoryKillImpl( | 596 void TabManagerDelegate::LowMemoryKillImpl( |
| 582 const TabStatsList& tab_list, | 597 const TabStatsList& tab_list, |
| 583 const std::vector<arc::ArcProcess>& arc_processes) { | 598 const std::vector<arc::ArcProcess>& arc_processes) { |
| 584 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); | 599 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
| 585 VLOG(2) << "LowMemoryKillImpl"; | 600 VLOG(2) << "LowMemoryKillImpl"; |
| 586 | 601 |
| 587 const std::vector<TabManagerDelegate::Candidate> candidates = | 602 const std::vector<TabManagerDelegate::Candidate> candidates = |
| 588 GetSortedCandidates(tab_list, arc_processes); | 603 GetSortedCandidates(tab_list, arc_processes); |
| 589 | 604 |
| 590 int target_memory_to_free_kb = mem_stat_->TargetMemoryToFreeKB(); | 605 int target_memory_to_free_kb = mem_stat_->TargetMemoryToFreeKB(); |
| 606 const TimeTicks now = TimeTicks::Now(); | |
| 591 | 607 |
| 592 // Kill processes until the estimated amount of freed memory is sufficient to | 608 // Kill processes until the estimated amount of freed memory is sufficient to |
| 593 // bring the system memory back to a normal level. | 609 // bring the system memory back to a normal level. |
| 594 // The list is sorted by descending importance, so we go through the list | 610 // The list is sorted by descending importance, so we go through the list |
| 595 // backwards. | 611 // backwards. |
| 596 for (auto it = candidates.rbegin(); it != candidates.rend(); ++it) { | 612 for (auto it = candidates.rbegin(); it != candidates.rend(); ++it) { |
| 597 MEMORY_LOG(ERROR) << "Target memory to free: " << target_memory_to_free_kb | 613 MEMORY_LOG(ERROR) << "Target memory to free: " << target_memory_to_free_kb |
| 598 << " KB"; | 614 << " KB"; |
| 599 if (target_memory_to_free_kb <= 0) | 615 if (target_memory_to_free_kb <= 0) |
| 600 break; | 616 break; |
| 601 // Never kill selected tab or Android foreground app, regardless whether | 617 // Never kill selected tab or Android foreground app, regardless whether |
| 602 // they're in the active window. Since the user experience would be bad. | 618 // they're in the active window. Since the user experience would be bad. |
| 603 ProcessType process_type = it->process_type(); | 619 ProcessType process_type = it->process_type(); |
| 604 if (process_type == ProcessType::VISIBLE_APP || | 620 if (process_type == ProcessType::VISIBLE_APP || |
| 605 process_type == ProcessType::FOCUSED_APP || | 621 process_type == ProcessType::FOCUSED_APP || |
| 606 process_type == ProcessType::FOCUSED_TAB) { | 622 process_type == ProcessType::FOCUSED_TAB) { |
| 607 MEMORY_LOG(ERROR) << "Skipped killing " << *it; | 623 MEMORY_LOG(ERROR) << "Skipped killing " << *it; |
| 608 continue; | 624 continue; |
| 609 } | 625 } |
| 610 if (it->app()) { | 626 if (it->app()) { |
| 627 if (IsRecentlyKilledArcProcess(it->app()->process_name(), now)) { | |
| 628 MEMORY_LOG(ERROR) << "Avoided killing " << *it << " too often"; | |
| 629 continue; | |
| 630 } | |
| 611 int estimated_memory_freed_kb = | 631 int estimated_memory_freed_kb = |
| 612 mem_stat_->EstimatedMemoryFreedKB(it->app()->pid()); | 632 mem_stat_->EstimatedMemoryFreedKB(it->app()->pid()); |
| 613 if (KillArcProcess(it->app()->nspid())) { | 633 if (KillArcProcess(it->app()->nspid())) { |
| 634 recently_killed_arc_processes_[it->app()->process_name()] = now; | |
| 614 target_memory_to_free_kb -= estimated_memory_freed_kb; | 635 target_memory_to_free_kb -= estimated_memory_freed_kb; |
| 615 MemoryKillsMonitor::LogLowMemoryKill("APP", estimated_memory_freed_kb); | 636 MemoryKillsMonitor::LogLowMemoryKill("APP", estimated_memory_freed_kb); |
| 616 MEMORY_LOG(ERROR) << "Killed " << *it << ", estimated " | 637 MEMORY_LOG(ERROR) << "Killed " << *it << ", estimated " |
| 617 << estimated_memory_freed_kb << " KB freed"; | 638 << estimated_memory_freed_kb << " KB freed"; |
| 618 } else { | 639 } else { |
| 619 MEMORY_LOG(ERROR) << "Failed to kill " << *it; | 640 MEMORY_LOG(ERROR) << "Failed to kill " << *it; |
| 620 } | 641 } |
| 621 } else { | 642 } else { |
| 622 int64_t tab_id = it->tab()->tab_contents_id; | 643 int64_t tab_id = it->tab()->tab_contents_id; |
| 623 // The estimation is problematic since multiple tabs may share the same | 644 // The estimation is problematic since multiple tabs may share the same |
| (...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 736 } | 757 } |
| 737 priority += priority_increment; | 758 priority += priority_increment; |
| 738 } | 759 } |
| 739 | 760 |
| 740 if (oom_scores_to_change.size()) | 761 if (oom_scores_to_change.size()) |
| 741 GetDebugDaemonClient()->SetOomScoreAdj( | 762 GetDebugDaemonClient()->SetOomScoreAdj( |
| 742 oom_scores_to_change, base::Bind(&OnSetOomScoreAdj)); | 763 oom_scores_to_change, base::Bind(&OnSetOomScoreAdj)); |
| 743 } | 764 } |
| 744 | 765 |
| 745 } // namespace memory | 766 } // namespace memory |
| OLD | NEW |