1// Copyright 2014 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 "chrome/browser/chromeos/power/renderer_freezer.h"
6
7#include "base/bind.h"
8#include "base/logging.h"
9#include "base/message_loop/message_loop.h"
10#include "chromeos/dbus/dbus_thread_manager.h"
11
12namespace chromeos {
13
14RendererFreezer::RendererFreezer(scoped_ptr<RendererFreezer::Delegate> delegate)
15    : frozen_(false),
16      delegate_(delegate.Pass()),
17      weak_factory_(this) {
18  if (delegate_->CanFreezeRenderers())
19    DBusThreadManager::Get()->GetPowerManagerClient()->AddObserver(this);
20}
21
22RendererFreezer::~RendererFreezer() {
23  if (delegate_->CanFreezeRenderers())
24    DBusThreadManager::Get()->GetPowerManagerClient()->RemoveObserver(this);
25}
26
27void RendererFreezer::SuspendImminent() {
28  // If there was already a callback pending, this will cancel it and create a
29  // new one.
30  suspend_readiness_callback_.Reset(
31      base::Bind(&RendererFreezer::OnReadyToSuspend,
32                 weak_factory_.GetWeakPtr(),
33                 DBusThreadManager::Get()
34                     ->GetPowerManagerClient()
35                     ->GetSuspendReadinessCallback()));
36
37  base::MessageLoop::current()->PostTask(
38      FROM_HERE, suspend_readiness_callback_.callback());
39}
40
41void RendererFreezer::SuspendDone(const base::TimeDelta& sleep_duration) {
42  // If we get a SuspendDone before we've had a chance to run OnReadyForSuspend,
43  // we should cancel it because we no longer want to freeze the renderers.  If
44  // we've already run it then cancelling the callback shouldn't really make a
45  // difference.
46  suspend_readiness_callback_.Cancel();
47
48  if (!frozen_)
49    return;
50
51  if (!delegate_->ThawRenderers()) {
52    // We failed to write the thaw command and the renderers are still frozen.
53    // We are in big trouble because none of the tabs will be responsive so
54    // let's crash the browser instead.
55    LOG(FATAL) << "Unable to thaw renderers.";
56  }
57
58  frozen_ = false;
59}
60
61void RendererFreezer::OnReadyToSuspend(
62    const base::Closure& power_manager_callback) {
63  if (delegate_->FreezeRenderers())
64    frozen_ = true;
65
66  DCHECK(!power_manager_callback.is_null());
67  power_manager_callback.Run();
68}
69
70}  // namespace chromeos
71