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/ptr_util.h" | 8 #include "base/memory/ptr_util.h" |
9 #include "base/metrics/histogram_macros.h" | 9 #include "base/metrics/histogram_macros.h" |
10 #include "base/process/process_handle.h" | 10 #include "base/process/process_handle.h" |
11 #include "base/threading/thread_task_runner_handle.h" | 11 #include "base/threading/thread_task_runner_handle.h" |
12 #include "base/trace_event/trace_event.h" | 12 #include "base/trace_event/trace_event.h" |
| 13 #include "content/browser/memory/memory_condition_observer.h" |
13 #include "content/browser/memory/memory_monitor.h" | 14 #include "content/browser/memory/memory_monitor.h" |
14 #include "content/browser/memory/memory_state_updater.h" | |
15 #include "content/public/browser/content_browser_client.h" | 15 #include "content/public/browser/content_browser_client.h" |
16 #include "content/public/browser/notification_service.h" | 16 #include "content/public/browser/notification_service.h" |
17 #include "content/public/browser/notification_types.h" | 17 #include "content/public/browser/notification_types.h" |
18 #include "content/public/browser/render_process_host.h" | 18 #include "content/public/browser/render_process_host.h" |
19 #include "content/public/browser/render_widget_host.h" | 19 #include "content/public/browser/render_widget_host.h" |
20 #include "content/public/common/content_features.h" | 20 #include "content/public/common/content_features.h" |
21 #include "mojo/public/cpp/bindings/binding.h" | 21 #include "mojo/public/cpp/bindings/binding.h" |
22 | 22 |
23 namespace content { | 23 namespace content { |
24 | 24 |
| 25 using MemoryState = base::MemoryState; |
| 26 |
25 namespace { | 27 namespace { |
26 | 28 |
27 mojom::MemoryState ToMojomMemoryState(base::MemoryState state) { | 29 const int kDefaultMinimumTransitionPeriodSeconds = 30; |
| 30 |
| 31 mojom::MemoryState ToMojomMemoryState(MemoryState state) { |
28 switch (state) { | 32 switch (state) { |
29 case base::MemoryState::UNKNOWN: | 33 case MemoryState::UNKNOWN: |
30 return mojom::MemoryState::UNKNOWN; | 34 return mojom::MemoryState::UNKNOWN; |
31 case base::MemoryState::NORMAL: | 35 case MemoryState::NORMAL: |
32 return mojom::MemoryState::NORMAL; | 36 return mojom::MemoryState::NORMAL; |
33 case base::MemoryState::THROTTLED: | 37 case MemoryState::THROTTLED: |
34 return mojom::MemoryState::THROTTLED; | 38 return mojom::MemoryState::THROTTLED; |
35 case base::MemoryState::SUSPENDED: | 39 case MemoryState::SUSPENDED: |
36 return mojom::MemoryState::SUSPENDED; | 40 return mojom::MemoryState::SUSPENDED; |
37 default: | 41 default: |
38 NOTREACHED(); | 42 NOTREACHED(); |
39 return mojom::MemoryState::UNKNOWN; | 43 return mojom::MemoryState::UNKNOWN; |
40 } | 44 } |
41 } | 45 } |
42 | 46 |
| 47 const char* MemoryConditionToString(MemoryCondition condition) { |
| 48 switch (condition) { |
| 49 case MemoryCondition::NORMAL: |
| 50 return "normal"; |
| 51 case MemoryCondition::WARNING: |
| 52 return "warning"; |
| 53 case MemoryCondition::CRITICAL: |
| 54 return "critical"; |
| 55 } |
| 56 NOTREACHED(); |
| 57 return "N/A"; |
| 58 } |
| 59 |
43 } // namespace | 60 } // namespace |
44 | 61 |
45 // The implementation of MemoryCoordinatorHandle. See memory_coordinator.mojom | 62 // The implementation of MemoryCoordinatorHandle. See memory_coordinator.mojom |
46 // for the role of this class. | 63 // for the role of this class. |
47 class MemoryCoordinatorHandleImpl : public mojom::MemoryCoordinatorHandle { | 64 class MemoryCoordinatorHandleImpl : public mojom::MemoryCoordinatorHandle { |
48 public: | 65 public: |
49 MemoryCoordinatorHandleImpl(mojom::MemoryCoordinatorHandleRequest request, | 66 MemoryCoordinatorHandleImpl(mojom::MemoryCoordinatorHandleRequest request, |
50 MemoryCoordinatorImpl* coordinator, | 67 MemoryCoordinatorImpl* coordinator, |
51 int render_process_id); | 68 int render_process_id); |
52 ~MemoryCoordinatorHandleImpl() override; | 69 ~MemoryCoordinatorHandleImpl() override; |
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
106 return nullptr; | 123 return nullptr; |
107 return base::Singleton<MemoryCoordinatorImpl, | 124 return base::Singleton<MemoryCoordinatorImpl, |
108 MemoryCoordinatorImplSingletonTraits>::get(); | 125 MemoryCoordinatorImplSingletonTraits>::get(); |
109 } | 126 } |
110 | 127 |
111 MemoryCoordinatorImpl::MemoryCoordinatorImpl( | 128 MemoryCoordinatorImpl::MemoryCoordinatorImpl( |
112 scoped_refptr<base::SingleThreadTaskRunner> task_runner, | 129 scoped_refptr<base::SingleThreadTaskRunner> task_runner, |
113 std::unique_ptr<MemoryMonitor> memory_monitor) | 130 std::unique_ptr<MemoryMonitor> memory_monitor) |
114 : delegate_(GetContentClient()->browser()->GetMemoryCoordinatorDelegate()), | 131 : delegate_(GetContentClient()->browser()->GetMemoryCoordinatorDelegate()), |
115 memory_monitor_(std::move(memory_monitor)), | 132 memory_monitor_(std::move(memory_monitor)), |
116 state_updater_(base::MakeUnique<MemoryStateUpdater>(this, task_runner)) { | 133 condition_observer_( |
| 134 base::MakeUnique<MemoryConditionObserver>(this, task_runner)), |
| 135 minimum_state_transition_period_(base::TimeDelta::FromSeconds( |
| 136 kDefaultMinimumTransitionPeriodSeconds)) { |
117 DCHECK(memory_monitor_.get()); | 137 DCHECK(memory_monitor_.get()); |
118 base::MemoryCoordinatorProxy::SetMemoryCoordinator(this); | 138 base::MemoryCoordinatorProxy::SetMemoryCoordinator(this); |
119 } | 139 } |
120 | 140 |
121 MemoryCoordinatorImpl::~MemoryCoordinatorImpl() {} | 141 MemoryCoordinatorImpl::~MemoryCoordinatorImpl() {} |
122 | 142 |
123 void MemoryCoordinatorImpl::Start() { | 143 void MemoryCoordinatorImpl::Start() { |
124 DCHECK(CalledOnValidThread()); | 144 DCHECK(CalledOnValidThread()); |
125 DCHECK(last_state_change_.is_null()); | 145 DCHECK(last_state_change_.is_null()); |
126 | 146 |
127 notification_registrar_.Add( | 147 notification_registrar_.Add( |
128 this, NOTIFICATION_RENDER_WIDGET_VISIBILITY_CHANGED, | 148 this, NOTIFICATION_RENDER_WIDGET_VISIBILITY_CHANGED, |
129 NotificationService::AllBrowserContextsAndSources()); | 149 NotificationService::AllBrowserContextsAndSources()); |
130 last_state_change_ = base::TimeTicks::Now(); | 150 condition_observer_->ScheduleUpdateCondition(base::TimeDelta()); |
131 state_updater_->ScheduleUpdateState(base::TimeDelta()); | |
132 } | 151 } |
133 | 152 |
134 void MemoryCoordinatorImpl::CreateHandle( | 153 void MemoryCoordinatorImpl::CreateHandle( |
135 int render_process_id, | 154 int render_process_id, |
136 mojom::MemoryCoordinatorHandleRequest request) { | 155 mojom::MemoryCoordinatorHandleRequest request) { |
137 std::unique_ptr<MemoryCoordinatorHandleImpl> handle( | 156 std::unique_ptr<MemoryCoordinatorHandleImpl> handle( |
138 new MemoryCoordinatorHandleImpl(std::move(request), this, | 157 new MemoryCoordinatorHandleImpl(std::move(request), this, |
139 render_process_id)); | 158 render_process_id)); |
140 handle->binding().set_connection_error_handler( | 159 handle->binding().set_connection_error_handler( |
141 base::Bind(&MemoryCoordinatorImpl::OnConnectionError, | 160 base::Bind(&MemoryCoordinatorImpl::OnConnectionError, |
142 base::Unretained(this), render_process_id)); | 161 base::Unretained(this), render_process_id)); |
143 CreateChildInfoMapEntry(render_process_id, std::move(handle)); | 162 CreateChildInfoMapEntry(render_process_id, std::move(handle)); |
144 } | 163 } |
145 | 164 |
146 bool MemoryCoordinatorImpl::SetChildMemoryState(int render_process_id, | 165 bool MemoryCoordinatorImpl::SetChildMemoryState(int render_process_id, |
147 MemoryState memory_state) { | 166 MemoryState memory_state) { |
148 // Can't set an invalid memory state. | 167 // Can't set an invalid memory state. |
149 if (memory_state == MemoryState::UNKNOWN) | 168 if (memory_state == MemoryState::UNKNOWN) |
150 return false; | 169 return false; |
151 | 170 |
152 // Can't send a message to a child that doesn't exist. | 171 // Can't send a message to a child that doesn't exist. |
153 auto iter = children_.find(render_process_id); | 172 auto iter = children_.find(render_process_id); |
154 if (iter == children_.end()) | 173 if (iter == children_.end()) |
155 return false; | 174 return false; |
156 | 175 |
157 // Can't send a message to a child that isn't bound. | 176 // Can't send a message to a child that isn't bound. |
158 if (!iter->second.handle->child().is_bound()) | 177 if (!iter->second.handle->child().is_bound()) |
159 return false; | 178 return false; |
160 | 179 |
161 memory_state = OverrideGlobalState(memory_state, iter->second); | 180 memory_state = OverrideState(memory_state, iter->second); |
162 | 181 |
163 // A nop doesn't need to be sent, but is considered successful. | 182 // A nop doesn't need to be sent, but is considered successful. |
164 if (iter->second.memory_state == memory_state) | 183 if (iter->second.memory_state == memory_state) |
165 return true; | 184 return true; |
166 | 185 |
167 // Can't suspend the given renderer. | 186 // Can't suspend the given renderer. |
168 if (memory_state == MemoryState::SUSPENDED && | 187 if (memory_state == MemoryState::SUSPENDED && |
169 !CanSuspendRenderer(render_process_id)) | 188 !CanSuspendRenderer(render_process_id)) |
170 return false; | 189 return false; |
171 | 190 |
172 // Update the internal state and send the message. | 191 // Update the internal state and send the message. |
173 iter->second.memory_state = memory_state; | 192 iter->second.memory_state = memory_state; |
174 iter->second.handle->child()->OnStateChange(ToMojomMemoryState(memory_state)); | 193 iter->second.handle->child()->OnStateChange(ToMojomMemoryState(memory_state)); |
175 return true; | 194 return true; |
176 } | 195 } |
177 | 196 |
178 base::MemoryState MemoryCoordinatorImpl::GetChildMemoryState( | 197 MemoryState MemoryCoordinatorImpl::GetChildMemoryState( |
179 int render_process_id) const { | 198 int render_process_id) const { |
180 auto iter = children_.find(render_process_id); | 199 auto iter = children_.find(render_process_id); |
181 if (iter == children_.end()) | 200 if (iter == children_.end()) |
182 return base::MemoryState::UNKNOWN; | 201 return MemoryState::UNKNOWN; |
183 return iter->second.memory_state; | 202 return iter->second.memory_state; |
184 } | 203 } |
185 | 204 |
186 void MemoryCoordinatorImpl::RecordMemoryPressure( | 205 void MemoryCoordinatorImpl::RecordMemoryPressure( |
187 base::MemoryPressureMonitor::MemoryPressureLevel level) { | 206 base::MemoryPressureMonitor::MemoryPressureLevel level) { |
188 // TODO(bashi): Record memory pressure level. | 207 // TODO(bashi): Record memory pressure level. |
189 } | 208 } |
190 | 209 |
191 base::MemoryState MemoryCoordinatorImpl::GetGlobalMemoryState() const { | 210 MemoryState MemoryCoordinatorImpl::GetBrowserMemoryState() const { |
192 return current_state_; | 211 return browser_memory_state_; |
193 } | 212 } |
194 | 213 |
195 base::MemoryState MemoryCoordinatorImpl::GetCurrentMemoryState() const { | 214 MemoryState MemoryCoordinatorImpl::GetCurrentMemoryState() const { |
196 // SUSPENDED state may not make sense to the browser process. Use THROTTLED | 215 return GetBrowserMemoryState(); |
197 // instead when the global state is SUSPENDED. | |
198 // TODO(bashi): Maybe worth considering another state for the browser. | |
199 return current_state_ == MemoryState::SUSPENDED ? MemoryState::THROTTLED | |
200 : current_state_; | |
201 } | 216 } |
202 | 217 |
203 void MemoryCoordinatorImpl::SetCurrentMemoryStateForTesting( | 218 void MemoryCoordinatorImpl::SetCurrentMemoryStateForTesting( |
204 base::MemoryState memory_state) { | 219 MemoryState memory_state) { |
205 // This changes the current state temporariy for testing. The state will be | 220 // Resets |last_state_change_| so that |
206 // updated 1 minute later. | 221 // UpdateBrowserStateAndNotifyStateToClients() to set memory state forcibly. |
207 ForceSetGlobalState(memory_state, base::TimeDelta::FromMinutes(1)); | 222 last_state_change_ = base::TimeTicks(); |
| 223 UpdateBrowserStateAndNotifyStateToClients(memory_state); |
208 } | 224 } |
209 | 225 |
210 void MemoryCoordinatorImpl::ForceSetGlobalState(base::MemoryState new_state, | 226 void MemoryCoordinatorImpl::ForceSetMemoryCondition(MemoryCondition condition, |
211 base::TimeDelta duration) { | 227 base::TimeDelta duration) { |
212 DCHECK(new_state != MemoryState::UNKNOWN); | 228 UpdateConditionIfNeeded(condition); |
213 ChangeStateIfNeeded(current_state_, new_state); | 229 condition_observer_->ScheduleUpdateCondition(duration); |
214 state_updater_->ScheduleUpdateState(duration); | |
215 } | 230 } |
216 | 231 |
217 void MemoryCoordinatorImpl::Observe(int type, | 232 void MemoryCoordinatorImpl::Observe(int type, |
218 const NotificationSource& source, | 233 const NotificationSource& source, |
219 const NotificationDetails& details) { | 234 const NotificationDetails& details) { |
220 DCHECK(type == NOTIFICATION_RENDER_WIDGET_VISIBILITY_CHANGED); | 235 DCHECK(type == NOTIFICATION_RENDER_WIDGET_VISIBILITY_CHANGED); |
221 RenderWidgetHost* render_widget_host = Source<RenderWidgetHost>(source).ptr(); | 236 RenderWidgetHost* render_widget_host = Source<RenderWidgetHost>(source).ptr(); |
222 RenderProcessHost* process = render_widget_host->GetProcess(); | 237 RenderProcessHost* process = render_widget_host->GetProcess(); |
223 if (!process) | 238 if (!process) |
224 return; | 239 return; |
225 auto iter = children().find(process->GetID()); | 240 auto iter = children().find(process->GetID()); |
226 if (iter == children().end()) | 241 if (iter == children().end()) |
227 return; | 242 return; |
| 243 |
228 iter->second.is_visible = *Details<bool>(details).ptr(); | 244 iter->second.is_visible = *Details<bool>(details).ptr(); |
229 auto new_state = GetGlobalMemoryState(); | 245 // The current heuristics for state calculation: |
| 246 // - Foregrounded renderers: THROTTLED when condition is CRITICAL, otherwise |
| 247 // NORMAL. |
| 248 // - Backgrounded renderers: THROTTLED when condition is WARNING/CRITICAL, |
| 249 // otherwise NORMAL. |
| 250 MemoryState new_state = MemoryState::NORMAL; |
| 251 MemoryCondition condition = GetMemoryCondition(); |
| 252 if (condition == MemoryCondition::WARNING) { |
| 253 new_state = |
| 254 iter->second.is_visible ? MemoryState::NORMAL : MemoryState::THROTTLED; |
| 255 } else if (condition == MemoryCondition::CRITICAL) { |
| 256 new_state = MemoryState::THROTTLED; |
| 257 } |
230 SetChildMemoryState(iter->first, new_state); | 258 SetChildMemoryState(iter->first, new_state); |
231 } | 259 } |
232 | 260 |
233 base::MemoryState MemoryCoordinatorImpl::GetStateForProcess( | 261 MemoryState MemoryCoordinatorImpl::GetStateForProcess( |
234 base::ProcessHandle handle) { | 262 base::ProcessHandle handle) { |
235 DCHECK(CalledOnValidThread()); | 263 DCHECK(CalledOnValidThread()); |
236 if (handle == base::kNullProcessHandle) | 264 if (handle == base::kNullProcessHandle) |
237 return MemoryState::UNKNOWN; | 265 return MemoryState::UNKNOWN; |
238 if (handle == base::GetCurrentProcessHandle()) | 266 if (handle == base::GetCurrentProcessHandle()) |
239 return GetCurrentMemoryState(); | 267 return browser_memory_state_; |
240 | 268 |
241 for (auto& iter : children()) { | 269 for (auto& iter : children()) { |
242 auto* render_process_host = GetRenderProcessHost(iter.first); | 270 auto* render_process_host = GetRenderProcessHost(iter.first); |
243 if (render_process_host && render_process_host->GetHandle() == handle) | 271 if (render_process_host && render_process_host->GetHandle() == handle) |
244 return iter.second.memory_state; | 272 return iter.second.memory_state; |
245 } | 273 } |
246 return MemoryState::UNKNOWN; | 274 return MemoryState::UNKNOWN; |
247 } | 275 } |
248 | 276 |
249 bool MemoryCoordinatorImpl::ChangeStateIfNeeded(base::MemoryState prev_state, | 277 void MemoryCoordinatorImpl::UpdateConditionIfNeeded( |
250 base::MemoryState next_state) { | 278 MemoryCondition next_condition) { |
251 DCHECK(CalledOnValidThread()); | 279 DCHECK(CalledOnValidThread()); |
252 if (prev_state == next_state) | 280 if (memory_condition_ == next_condition) |
253 return false; | 281 return; |
254 | 282 |
255 last_state_change_ = base::TimeTicks::Now(); | 283 MemoryCondition prev_condition = memory_condition_; |
256 current_state_ = next_state; | 284 memory_condition_ = next_condition; |
257 | 285 |
258 TRACE_EVENT2(TRACE_DISABLED_BY_DEFAULT("memory-infra"), | 286 TRACE_EVENT2(TRACE_DISABLED_BY_DEFAULT("memory-infra"), |
259 "MemoryCoordinatorImpl::ChangeStateIfNeeded", "prev", | 287 "MemoryCoordinatorImpl::UpdateConditionIfNeeded", "prev", |
260 MemoryStateToString(prev_state), "next", | 288 MemoryConditionToString(prev_condition), "next", |
261 MemoryStateToString(next_state)); | 289 MemoryConditionToString(next_condition)); |
262 NotifyStateToClients(); | 290 |
263 NotifyStateToChildren(); | 291 // TODO(bashi): Following actions are tentative. We might want to prioritize |
264 return true; | 292 // processes and handle them one-by-one. |
| 293 |
| 294 if (next_condition == MemoryCondition::NORMAL) { |
| 295 // Set NORMAL state to all clients/processes. |
| 296 UpdateBrowserStateAndNotifyStateToClients(MemoryState::NORMAL); |
| 297 NotifyStateToChildren(MemoryState::NORMAL); |
| 298 } else if (next_condition == MemoryCondition::WARNING) { |
| 299 // Set NORMAL state to foreground proceses and clients in the browser |
| 300 // process. Set THROTTLED state to background processes. |
| 301 UpdateBrowserStateAndNotifyStateToClients(MemoryState::NORMAL); |
| 302 for (auto& iter : children()) { |
| 303 auto state = |
| 304 iter.second.is_visible ? MemoryState::NORMAL : MemoryState::THROTTLED; |
| 305 SetChildMemoryState(iter.first, state); |
| 306 } |
| 307 // Idea: Purge memory from background processes. |
| 308 } else if (next_condition == MemoryCondition::CRITICAL) { |
| 309 // Set THROTTLED state to all clients/processes. |
| 310 UpdateBrowserStateAndNotifyStateToClients(MemoryState::THROTTLED); |
| 311 NotifyStateToChildren(MemoryState::THROTTLED); |
| 312 // Idea: Start discarding tabs. |
| 313 } |
265 } | 314 } |
266 | 315 |
267 void MemoryCoordinatorImpl::DiscardTab() { | 316 void MemoryCoordinatorImpl::DiscardTab() { |
268 if (delegate_) | 317 if (delegate_) |
269 delegate_->DiscardTab(); | 318 delegate_->DiscardTab(); |
270 } | 319 } |
271 | 320 |
272 RenderProcessHost* MemoryCoordinatorImpl::GetRenderProcessHost( | 321 RenderProcessHost* MemoryCoordinatorImpl::GetRenderProcessHost( |
273 int render_process_id) { | 322 int render_process_id) { |
274 return RenderProcessHost::FromID(render_process_id); | 323 return RenderProcessHost::FromID(render_process_id); |
(...skipping 26 matching lines...) Expand all Loading... |
301 return false; | 350 return false; |
302 if (render_process_host->GetWorkerRefCount() > 0) | 351 if (render_process_host->GetWorkerRefCount() > 0) |
303 return false; | 352 return false; |
304 // Assumes that we can't suspend renderers if there is no delegate. | 353 // Assumes that we can't suspend renderers if there is no delegate. |
305 if (!delegate_) | 354 if (!delegate_) |
306 return false; | 355 return false; |
307 return delegate_->CanSuspendBackgroundedRenderer(render_process_id); | 356 return delegate_->CanSuspendBackgroundedRenderer(render_process_id); |
308 } | 357 } |
309 | 358 |
310 void MemoryCoordinatorImpl::OnChildAdded(int render_process_id) { | 359 void MemoryCoordinatorImpl::OnChildAdded(int render_process_id) { |
311 // Populate the global state as an initial state of a newly created process. | 360 // Populate an initial state of a newly created process, assuming it's |
312 auto new_state = GetGlobalMemoryState(); | 361 // foregrounded. |
| 362 // TODO(bashi): Don't assume the process is foregrounded. It can be added |
| 363 // as a background process. |
| 364 auto new_state = GetMemoryCondition() == MemoryCondition::CRITICAL |
| 365 ? MemoryState::THROTTLED |
| 366 : MemoryState::NORMAL; |
313 SetChildMemoryState(render_process_id, new_state); | 367 SetChildMemoryState(render_process_id, new_state); |
314 } | 368 } |
315 | 369 |
316 base::MemoryState MemoryCoordinatorImpl::OverrideGlobalState( | 370 MemoryState MemoryCoordinatorImpl::OverrideState(MemoryState memory_state, |
317 MemoryState memory_state, | 371 const ChildInfo& child) { |
318 const ChildInfo& child) { | |
319 // We don't suspend foreground renderers. Throttle them instead. | 372 // We don't suspend foreground renderers. Throttle them instead. |
320 if (child.is_visible && memory_state == MemoryState::SUSPENDED) | 373 if (child.is_visible && memory_state == MemoryState::SUSPENDED) |
321 return MemoryState::THROTTLED; | 374 return MemoryState::THROTTLED; |
322 #if defined(OS_ANDROID) | 375 #if defined(OS_ANDROID) |
323 // On Android, we throttle background renderers immediately. | 376 // On Android, we throttle background renderers immediately. |
324 // TODO(bashi): Create a specialized class of MemoryCoordinator for Android | 377 // TODO(bashi): Create a specialized class of MemoryCoordinator for Android |
325 // and move this ifdef to the class. | 378 // and move this ifdef to the class. |
326 if (!child.is_visible && memory_state == MemoryState::NORMAL) | 379 if (!child.is_visible && memory_state == MemoryState::NORMAL) |
327 return MemoryState::THROTTLED; | 380 return MemoryState::THROTTLED; |
328 // TODO(bashi): Suspend background renderers after a certain period of time. | 381 // TODO(bashi): Suspend background renderers after a certain period of time. |
329 #endif // defined(OS_ANDROID) | 382 #endif // defined(OS_ANDROID) |
330 return memory_state; | 383 return memory_state; |
331 } | 384 } |
332 | 385 |
333 void MemoryCoordinatorImpl::CreateChildInfoMapEntry( | 386 void MemoryCoordinatorImpl::CreateChildInfoMapEntry( |
334 int render_process_id, | 387 int render_process_id, |
335 std::unique_ptr<MemoryCoordinatorHandleImpl> handle) { | 388 std::unique_ptr<MemoryCoordinatorHandleImpl> handle) { |
336 auto& child_info = children_[render_process_id]; | 389 auto& child_info = children_[render_process_id]; |
337 // Process always start with normal memory state. | 390 // Process always start with normal memory state. |
338 // We'll set renderer's memory state to the current global state when the | 391 // We'll set renderer's memory state to the current global state when the |
339 // corresponding renderer process is ready to communicate. Renderer processes | 392 // corresponding renderer process is ready to communicate. Renderer processes |
340 // call AddChild() when they are ready. | 393 // call AddChild() when they are ready. |
341 child_info.memory_state = MemoryState::NORMAL; | 394 child_info.memory_state = MemoryState::NORMAL; |
342 child_info.is_visible = true; | 395 child_info.is_visible = true; |
343 child_info.handle = std::move(handle); | 396 child_info.handle = std::move(handle); |
344 } | 397 } |
345 | 398 |
346 void MemoryCoordinatorImpl::NotifyStateToClients() { | 399 void MemoryCoordinatorImpl::UpdateBrowserStateAndNotifyStateToClients( |
347 auto state = GetCurrentMemoryState(); | 400 MemoryState memory_state) { |
| 401 if (memory_state == browser_memory_state_) |
| 402 return; |
| 403 |
| 404 base::TimeTicks now = base::TimeTicks::Now(); |
| 405 if (!last_state_change_.is_null() && |
| 406 (now - last_state_change_ < minimum_state_transition_period_)) |
| 407 return; |
| 408 |
| 409 last_state_change_ = now; |
| 410 browser_memory_state_ = memory_state; |
| 411 NotifyStateToClients(memory_state); |
| 412 } |
| 413 |
| 414 void MemoryCoordinatorImpl::NotifyStateToClients(MemoryState state) { |
348 base::MemoryCoordinatorClientRegistry::GetInstance()->Notify(state); | 415 base::MemoryCoordinatorClientRegistry::GetInstance()->Notify(state); |
349 } | 416 } |
350 | 417 |
351 void MemoryCoordinatorImpl::NotifyStateToChildren() { | 418 void MemoryCoordinatorImpl::NotifyStateToChildren(MemoryState state) { |
352 // It's OK to call SetChildMemoryState() unconditionally because it checks | 419 // It's OK to call SetChildMemoryState() unconditionally because it checks |
353 // whether this state transition is valid. | 420 // whether this state transition is valid. |
354 for (auto& iter : children()) | 421 for (auto& iter : children()) |
355 SetChildMemoryState(iter.first, current_state_); | 422 SetChildMemoryState(iter.first, state); |
356 } | 423 } |
357 | 424 |
358 MemoryCoordinatorImpl::ChildInfo::ChildInfo() {} | 425 MemoryCoordinatorImpl::ChildInfo::ChildInfo() {} |
359 | 426 |
360 MemoryCoordinatorImpl::ChildInfo::ChildInfo(const ChildInfo& rhs) { | 427 MemoryCoordinatorImpl::ChildInfo::ChildInfo(const ChildInfo& rhs) { |
361 // This is a nop, but exists for compatibility with STL containers. | 428 // This is a nop, but exists for compatibility with STL containers. |
362 } | 429 } |
363 | 430 |
364 MemoryCoordinatorImpl::ChildInfo::~ChildInfo() {} | 431 MemoryCoordinatorImpl::ChildInfo::~ChildInfo() {} |
365 | 432 |
366 } // namespace content | 433 } // namespace content |
OLD | NEW |