OLD | NEW |
| (Empty) |
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 | |
3 // found in the LICENSE file. | |
4 | |
5 #include "content/browser/memory/memory_pressure_controller_impl.h" | |
6 | |
7 #include "base/bind.h" | |
8 #include "content/browser/memory/memory_message_filter.h" | |
9 #include "content/public/browser/browser_thread.h" | |
10 | |
11 namespace content { | |
12 | |
13 MemoryPressureControllerImpl::MemoryPressureControllerImpl() {} | |
14 | |
15 MemoryPressureControllerImpl::~MemoryPressureControllerImpl() {} | |
16 | |
17 void MemoryPressureControllerImpl::OnMemoryMessageFilterAdded( | |
18 MemoryMessageFilter* filter) { | |
19 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
20 | |
21 // Add the message filter to the set of all memory message filters and check | |
22 // that it wasn't there beforehand. | |
23 const bool success = | |
24 memory_message_filters_.insert( | |
25 std::make_pair(filter->process_host(), filter)) | |
26 .second; | |
27 DCHECK(success); | |
28 | |
29 // There's no need to send a message to the child process if memory pressure | |
30 // notifications are not suppressed. | |
31 if (base::MemoryPressureListener::AreNotificationsSuppressed()) | |
32 filter->SendSetPressureNotificationsSuppressed(true); | |
33 } | |
34 | |
35 void MemoryPressureControllerImpl::OnMemoryMessageFilterRemoved( | |
36 MemoryMessageFilter* filter) { | |
37 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
38 | |
39 // Remove the message filter from the set of all memory message filters, | |
40 // ensuring that it was there beforehand. | |
41 auto it = memory_message_filters_.find(filter->process_host()); | |
42 if (it == memory_message_filters_.end()) | |
43 return; | |
44 DCHECK_EQ(filter, it->second); | |
45 memory_message_filters_.erase(it); | |
46 } | |
47 | |
48 // static | |
49 MemoryPressureControllerImpl* MemoryPressureControllerImpl::GetInstance() { | |
50 return base::Singleton< | |
51 MemoryPressureControllerImpl, | |
52 base::LeakySingletonTraits<MemoryPressureControllerImpl>>::get(); | |
53 } | |
54 | |
55 void | |
56 MemoryPressureControllerImpl::SetPressureNotificationsSuppressedInAllProcesses( | |
57 bool suppressed) { | |
58 if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) { | |
59 // Note that passing base::Unretained(this) is safe here because the | |
60 // controller is a leaky singleton. | |
61 BrowserThread::PostTask( | |
62 BrowserThread::IO, FROM_HERE, | |
63 base::Bind(&MemoryPressureControllerImpl:: | |
64 SetPressureNotificationsSuppressedInAllProcesses, | |
65 base::Unretained(this), suppressed)); | |
66 return; | |
67 } | |
68 | |
69 // Enable/disable suppressing memory notifications in the browser process. | |
70 base::MemoryPressureListener::SetNotificationsSuppressed(suppressed); | |
71 | |
72 // Enable/disable suppressing memory notifications in all child processes. | |
73 for (const auto& filter_pair : memory_message_filters_) | |
74 filter_pair.second->SendSetPressureNotificationsSuppressed(suppressed); | |
75 } | |
76 | |
77 void MemoryPressureControllerImpl::SimulatePressureNotificationInAllProcesses( | |
78 base::MemoryPressureListener::MemoryPressureLevel level) { | |
79 DCHECK_NE(level, base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE); | |
80 | |
81 if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) { | |
82 // Note that passing base::Unretained(this) is safe here because the | |
83 // controller is a leaky singleton. | |
84 BrowserThread::PostTask( | |
85 BrowserThread::IO, FROM_HERE, | |
86 base::Bind(&MemoryPressureControllerImpl:: | |
87 SimulatePressureNotificationInAllProcesses, | |
88 base::Unretained(this), level)); | |
89 return; | |
90 } | |
91 | |
92 // Simulate memory pressure notification in the browser process. | |
93 base::MemoryPressureListener::SimulatePressureNotification(level); | |
94 | |
95 // Simulate memory pressure notification in all child processes. | |
96 for (const auto& filter_pair : memory_message_filters_) | |
97 filter_pair.second->SendSimulatePressureNotification(level); | |
98 } | |
99 | |
100 void MemoryPressureControllerImpl::SendPressureNotification( | |
101 const BrowserChildProcessHost* child_process_host, | |
102 base::MemoryPressureListener::MemoryPressureLevel level) { | |
103 SendPressureNotificationImpl(child_process_host, level); | |
104 } | |
105 | |
106 void MemoryPressureControllerImpl::SendPressureNotification( | |
107 const RenderProcessHost* render_process_host, | |
108 base::MemoryPressureListener::MemoryPressureLevel level) { | |
109 SendPressureNotificationImpl(render_process_host, level); | |
110 } | |
111 | |
112 void MemoryPressureControllerImpl::SendPressureNotificationImpl( | |
113 const void* child_process_host, | |
114 base::MemoryPressureListener::MemoryPressureLevel level) { | |
115 if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) { | |
116 // Note that passing base::Unretained(this) is safe here because the | |
117 // controller is a leaky singleton. It's also safe to pass an untyped | |
118 // child process pointer as the address is only used as a key for lookup in | |
119 // a map; at no point is it dereferenced. | |
120 BrowserThread::PostTask( | |
121 BrowserThread::IO, FROM_HERE, | |
122 base::Bind(&MemoryPressureControllerImpl::SendPressureNotificationImpl, | |
123 base::Unretained(this), child_process_host, level)); | |
124 return; | |
125 } | |
126 | |
127 if (base::MemoryPressureListener::AreNotificationsSuppressed()) | |
128 return; | |
129 | |
130 // Find the appropriate message filter and dispatch the message. | |
131 auto it = memory_message_filters_.find(child_process_host); | |
132 if (it != memory_message_filters_.end()) | |
133 it->second->SendPressureNotification(level); | |
134 } | |
135 | |
136 } // namespace content | |
OLD | NEW |