Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(382)

Side by Side Diff: content/browser/memory/memory_coordinator_impl.cc

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

Powered by Google App Engine
This is Rietveld 408576698