| OLD | NEW |
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 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 "content/browser/memory/memory_coordinator_impl.h" | 5 #include "content/browser/memory/memory_coordinator_impl.h" |
| 6 | 6 |
| 7 #include "base/memory/memory_coordinator_client_registry.h" | 7 #include "base/memory/memory_coordinator_client_registry.h" |
| 8 #include "base/memory/memory_coordinator_proxy.h" | 8 #include "base/memory/memory_coordinator_proxy.h" |
| 9 #include "base/memory/memory_pressure_monitor.h" | 9 #include "base/memory/memory_pressure_monitor.h" |
| 10 #include "base/memory/ptr_util.h" | 10 #include "base/memory/ptr_util.h" |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 59 | 59 |
| 60 // A mock MemoryCoordinatorClient, for testing interaction between MC and | 60 // A mock MemoryCoordinatorClient, for testing interaction between MC and |
| 61 // clients. | 61 // clients. |
| 62 class MockMemoryCoordinatorClient : public base::MemoryCoordinatorClient { | 62 class MockMemoryCoordinatorClient : public base::MemoryCoordinatorClient { |
| 63 public: | 63 public: |
| 64 void OnMemoryStateChange(base::MemoryState state) override { | 64 void OnMemoryStateChange(base::MemoryState state) override { |
| 65 did_state_changed_ = true; | 65 did_state_changed_ = true; |
| 66 state_ = state; | 66 state_ = state; |
| 67 } | 67 } |
| 68 | 68 |
| 69 void OnPurgeMemory() override { ++purge_memory_calls_; } |
| 70 |
| 69 bool did_state_changed() const { return did_state_changed_; } | 71 bool did_state_changed() const { return did_state_changed_; } |
| 70 base::MemoryState state() const { return state_; } | 72 base::MemoryState state() const { return state_; } |
| 73 int purge_memory_calls() const { return purge_memory_calls_; } |
| 71 | 74 |
| 72 private: | 75 private: |
| 73 bool did_state_changed_ = false; | 76 bool did_state_changed_ = false; |
| 74 base::MemoryState state_ = base::MemoryState::NORMAL; | 77 base::MemoryState state_ = base::MemoryState::NORMAL; |
| 78 int purge_memory_calls_ = 0; |
| 75 }; | 79 }; |
| 76 | 80 |
| 77 class MockMemoryMonitor : public MemoryMonitor { | 81 class MockMemoryMonitor : public MemoryMonitor { |
| 78 public: | 82 public: |
| 79 MockMemoryMonitor() {} | 83 MockMemoryMonitor() {} |
| 80 ~MockMemoryMonitor() override {} | 84 ~MockMemoryMonitor() override {} |
| 81 | 85 |
| 82 void SetFreeMemoryUntilCriticalMB(int free_memory) { | 86 void SetFreeMemoryUntilCriticalMB(int free_memory) { |
| 83 free_memory_ = free_memory; | 87 free_memory_ = free_memory; |
| 84 } | 88 } |
| 85 | 89 |
| 86 // MemoryMonitor implementation | 90 // MemoryMonitor implementation |
| 87 int GetFreeMemoryUntilCriticalMB() override { return free_memory_; } | 91 int GetFreeMemoryUntilCriticalMB() override { return free_memory_; } |
| 88 | 92 |
| 89 private: | 93 private: |
| 90 int free_memory_ = 0; | 94 int free_memory_ = 0; |
| 91 | 95 |
| 92 DISALLOW_COPY_AND_ASSIGN(MockMemoryMonitor); | 96 DISALLOW_COPY_AND_ASSIGN(MockMemoryMonitor); |
| 93 }; | 97 }; |
| 94 | 98 |
| 95 class TestMemoryCoordinatorDelegate : public MemoryCoordinatorDelegate { | 99 class TestMemoryCoordinatorDelegate : public MemoryCoordinatorDelegate { |
| 96 public: | 100 public: |
| 97 TestMemoryCoordinatorDelegate() {} | 101 TestMemoryCoordinatorDelegate() {} |
| 98 ~TestMemoryCoordinatorDelegate() override {} | 102 ~TestMemoryCoordinatorDelegate() override {} |
| 99 | 103 |
| 100 bool CanSuspendBackgroundedRenderer(int render_process_id) override { | 104 bool CanSuspendBackgroundedRenderer(int render_process_id) override { |
| 101 return true; | 105 return true; |
| 102 } | 106 } |
| 103 | 107 |
| 104 void DiscardTab() override { ++discard_tab_count_; } | 108 bool DiscardTab() override { |
| 109 const int kMaxDiscardTabCount = 2; |
| 110 if (discard_tab_count_ >= kMaxDiscardTabCount) |
| 111 return false; |
| 112 ++discard_tab_count_; |
| 113 return true; |
| 114 } |
| 105 | 115 |
| 106 int discard_tab_count() const { return discard_tab_count_; } | 116 int discard_tab_count() const { return discard_tab_count_; } |
| 107 | 117 |
| 108 private: | 118 private: |
| 109 int discard_tab_count_ = 0; | 119 int discard_tab_count_ = 0; |
| 110 | 120 |
| 111 DISALLOW_COPY_AND_ASSIGN(TestMemoryCoordinatorDelegate); | 121 DISALLOW_COPY_AND_ASSIGN(TestMemoryCoordinatorDelegate); |
| 112 }; | 122 }; |
| 113 | 123 |
| 114 // A MemoryCoordinatorImpl that can be directly constructed. | 124 // A MemoryCoordinatorImpl that can be directly constructed. |
| (...skipping 444 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 559 EXPECT_EQ(2, delegate->discard_tab_count()); | 569 EXPECT_EQ(2, delegate->discard_tab_count()); |
| 560 | 570 |
| 561 // Back to NORMAL. Tab discarding should stop. | 571 // Back to NORMAL. Tab discarding should stop. |
| 562 GetMockMemoryMonitor()->SetFreeMemoryUntilCriticalMB(50); | 572 GetMockMemoryMonitor()->SetFreeMemoryUntilCriticalMB(50); |
| 563 task_runner_->FastForwardBy(interval); | 573 task_runner_->FastForwardBy(interval); |
| 564 EXPECT_EQ(2, delegate->discard_tab_count()); | 574 EXPECT_EQ(2, delegate->discard_tab_count()); |
| 565 task_runner_->FastForwardBy(interval); | 575 task_runner_->FastForwardBy(interval); |
| 566 EXPECT_EQ(2, delegate->discard_tab_count()); | 576 EXPECT_EQ(2, delegate->discard_tab_count()); |
| 567 } | 577 } |
| 568 | 578 |
| 579 TEST_F(MemoryCoordinatorImplTest, OnWarningCondition) { |
| 580 MockMemoryCoordinatorClient client; |
| 581 base::MemoryCoordinatorClientRegistry::GetInstance()->Register(&client); |
| 582 auto* child1 = coordinator_->CreateChildMemoryCoordinator(1); |
| 583 auto* child2 = coordinator_->CreateChildMemoryCoordinator(2); |
| 584 base::TimeDelta interval = |
| 585 coordinator_->background_child_purge_candidate_period_ + |
| 586 base::TimeDelta::FromSeconds(1); |
| 587 |
| 588 // child1: Foreground, child2: Background |
| 589 coordinator_->OnChildVisibilityChanged(1, true); |
| 590 coordinator_->OnChildVisibilityChanged(2, false); |
| 591 |
| 592 // Note: we never ask foreground processes (including the browser process) to |
| 593 // purge memory on WARNING condition. |
| 594 |
| 595 // Don't ask the background child to purge until the child remains |
| 596 // backgrounded for a certain period of time. |
| 597 coordinator_->OnWarningCondition(); |
| 598 RunUntilIdle(); |
| 599 EXPECT_EQ(0, client.purge_memory_calls()); |
| 600 EXPECT_EQ(0, child1->purge_memory_calls()); |
| 601 EXPECT_EQ(0, child2->purge_memory_calls()); |
| 602 |
| 603 // After a certain period of time is passed, request the child to purge |
| 604 // memory. |
| 605 task_runner_->FastForwardBy(interval); |
| 606 coordinator_->OnWarningCondition(); |
| 607 task_runner_->RunUntilIdle(); |
| 608 RunUntilIdle(); |
| 609 EXPECT_EQ(0, client.purge_memory_calls()); |
| 610 EXPECT_EQ(0, child1->purge_memory_calls()); |
| 611 EXPECT_EQ(1, child2->purge_memory_calls()); |
| 612 |
| 613 // Don't purge memory more than once when the child stays backgrounded. |
| 614 task_runner_->FastForwardBy(interval); |
| 615 coordinator_->OnWarningCondition(); |
| 616 RunUntilIdle(); |
| 617 EXPECT_EQ(0, client.purge_memory_calls()); |
| 618 EXPECT_EQ(0, child1->purge_memory_calls()); |
| 619 EXPECT_EQ(1, child2->purge_memory_calls()); |
| 620 |
| 621 // The background child goes to foreground, goes to background, then a |
| 622 // certain period of time is passed. Another purging request should be sent. |
| 623 coordinator_->OnChildVisibilityChanged(2, true); |
| 624 coordinator_->OnChildVisibilityChanged(2, false); |
| 625 task_runner_->FastForwardBy(interval); |
| 626 coordinator_->OnWarningCondition(); |
| 627 RunUntilIdle(); |
| 628 EXPECT_EQ(0, client.purge_memory_calls()); |
| 629 EXPECT_EQ(0, child1->purge_memory_calls()); |
| 630 EXPECT_EQ(2, child2->purge_memory_calls()); |
| 631 |
| 632 base::MemoryCoordinatorClientRegistry::GetInstance()->Unregister(&client); |
| 633 } |
| 634 |
| 635 TEST_F(MemoryCoordinatorImplTest, OnCriticalCondition) { |
| 636 MockMemoryCoordinatorClient client; |
| 637 base::MemoryCoordinatorClientRegistry::GetInstance()->Register(&client); |
| 638 auto* child1 = coordinator_->CreateChildMemoryCoordinator(1); |
| 639 auto* child2 = coordinator_->CreateChildMemoryCoordinator(2); |
| 640 auto* delegate = coordinator_->GetDelegate(); |
| 641 base::TimeDelta interval = |
| 642 coordinator_->background_child_purge_candidate_period_ + |
| 643 base::TimeDelta::FromSeconds(1); |
| 644 |
| 645 // child1: Foreground, child2: Background |
| 646 coordinator_->OnChildVisibilityChanged(1, true); |
| 647 coordinator_->OnChildVisibilityChanged(2, false); |
| 648 |
| 649 // Our mocked |delegate| allows discarding tab twice. While tab discarding |
| 650 // succeeds we don't purge memory. |
| 651 coordinator_->OnCriticalCondition(); |
| 652 task_runner_->RunUntilIdle(); |
| 653 RunUntilIdle(); |
| 654 EXPECT_EQ(1, delegate->discard_tab_count()); |
| 655 EXPECT_EQ(0, client.purge_memory_calls()); |
| 656 EXPECT_EQ(0, child1->purge_memory_calls()); |
| 657 EXPECT_EQ(0, child2->purge_memory_calls()); |
| 658 task_runner_->FastForwardBy(interval); |
| 659 coordinator_->OnCriticalCondition(); |
| 660 RunUntilIdle(); |
| 661 EXPECT_EQ(2, delegate->discard_tab_count()); |
| 662 EXPECT_EQ(0, client.purge_memory_calls()); |
| 663 EXPECT_EQ(0, child1->purge_memory_calls()); |
| 664 EXPECT_EQ(0, child2->purge_memory_calls()); |
| 665 |
| 666 // Purge memory from all children regardless of their visibility. |
| 667 task_runner_->FastForwardBy(interval); |
| 668 coordinator_->OnCriticalCondition(); |
| 669 RunUntilIdle(); |
| 670 task_runner_->FastForwardBy(interval); |
| 671 coordinator_->OnCriticalCondition(); |
| 672 RunUntilIdle(); |
| 673 EXPECT_EQ(2, delegate->discard_tab_count()); |
| 674 EXPECT_EQ(0, client.purge_memory_calls()); |
| 675 EXPECT_EQ(1, child1->purge_memory_calls()); |
| 676 EXPECT_EQ(1, child2->purge_memory_calls()); |
| 677 |
| 678 // Purge memory from browser process only after we asked all children to |
| 679 // purge memory. |
| 680 task_runner_->FastForwardBy(interval); |
| 681 coordinator_->OnCriticalCondition(); |
| 682 RunUntilIdle(); |
| 683 EXPECT_EQ(2, delegate->discard_tab_count()); |
| 684 EXPECT_EQ(1, client.purge_memory_calls()); |
| 685 EXPECT_EQ(1, child1->purge_memory_calls()); |
| 686 EXPECT_EQ(1, child2->purge_memory_calls()); |
| 687 |
| 688 // Don't request purging for a certain period of time if we already requested. |
| 689 task_runner_->FastForwardBy(interval); |
| 690 coordinator_->OnCriticalCondition(); |
| 691 RunUntilIdle(); |
| 692 EXPECT_EQ(2, delegate->discard_tab_count()); |
| 693 EXPECT_EQ(1, client.purge_memory_calls()); |
| 694 EXPECT_EQ(1, child1->purge_memory_calls()); |
| 695 EXPECT_EQ(1, child2->purge_memory_calls()); |
| 696 |
| 697 base::MemoryCoordinatorClientRegistry::GetInstance()->Unregister(&client); |
| 698 } |
| 699 |
| 569 #if defined(OS_ANDROID) | 700 #if defined(OS_ANDROID) |
| 570 // TODO(jcivelli): Broken on Android. http://crbug.com/678665 | 701 // TODO(jcivelli): Broken on Android. http://crbug.com/678665 |
| 571 #define MAYBE_GetStateForProcess DISABLED_GetStateForProcess | 702 #define MAYBE_GetStateForProcess DISABLED_GetStateForProcess |
| 572 #else | 703 #else |
| 573 #define MAYBE_GetStateForProcess GetStateForProcess | 704 #define MAYBE_GetStateForProcess GetStateForProcess |
| 574 #endif | 705 #endif |
| 575 TEST_F(MemoryCoordinatorImplTest, MAYBE_GetStateForProcess) { | 706 TEST_F(MemoryCoordinatorImplTest, MAYBE_GetStateForProcess) { |
| 576 EXPECT_EQ(base::MemoryState::UNKNOWN, | 707 EXPECT_EQ(base::MemoryState::UNKNOWN, |
| 577 coordinator_->GetStateForProcess(base::kNullProcessHandle)); | 708 coordinator_->GetStateForProcess(base::kNullProcessHandle)); |
| 578 EXPECT_EQ(base::MemoryState::NORMAL, | 709 EXPECT_EQ(base::MemoryState::NORMAL, |
| (...skipping 19 matching lines...) Expand all Loading... |
| 598 | 729 |
| 599 EXPECT_TRUE( | 730 EXPECT_TRUE( |
| 600 coordinator_->SetChildMemoryState(1, MemoryState::THROTTLED)); | 731 coordinator_->SetChildMemoryState(1, MemoryState::THROTTLED)); |
| 601 EXPECT_EQ(base::MemoryState::THROTTLED, | 732 EXPECT_EQ(base::MemoryState::THROTTLED, |
| 602 coordinator_->GetStateForProcess(process1.Handle())); | 733 coordinator_->GetStateForProcess(process1.Handle())); |
| 603 EXPECT_EQ(base::MemoryState::NORMAL, | 734 EXPECT_EQ(base::MemoryState::NORMAL, |
| 604 coordinator_->GetStateForProcess(process2.Handle())); | 735 coordinator_->GetStateForProcess(process2.Handle())); |
| 605 } | 736 } |
| 606 | 737 |
| 607 } // namespace content | 738 } // namespace content |
| OLD | NEW |