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 |