Switch global error menu icon to vectorized MD asset
[chromium-blink-merge.git] / chrome / browser / chromeos / power / renderer_freezer.cc
blobc2394449bf9abff57c835a2340c78f2b3e8d6918
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.
5 #include "chrome/browser/chromeos/power/renderer_freezer.h"
7 #include <string>
9 #include "base/bind.h"
10 #include "base/logging.h"
11 #include "base/message_loop/message_loop.h"
12 #include "base/process/process_handle.h"
13 #include "chrome/browser/chrome_notification_types.h"
14 #include "chrome/browser/chromeos/login/lock/screen_locker.h"
15 #include "chrome/browser/chromeos/login/lock/screen_locker_delegate.h"
16 #include "chromeos/dbus/dbus_thread_manager.h"
17 #include "content/public/browser/notification_details.h"
18 #include "content/public/browser/notification_service.h"
19 #include "content/public/browser/notification_source.h"
20 #include "content/public/browser/notification_types.h"
21 #include "content/public/browser/render_process_host.h"
22 #include "content/public/browser/web_contents.h"
23 #include "content/public/browser/web_ui.h"
24 #include "extensions/browser/extension_registry.h"
25 #include "extensions/browser/notification_types.h"
26 #include "extensions/browser/process_map.h"
27 #include "extensions/common/extension.h"
28 #include "extensions/common/permissions/api_permission.h"
29 #include "extensions/common/permissions/permissions_data.h"
31 namespace chromeos {
33 RendererFreezer::RendererFreezer(scoped_ptr<RendererFreezer::Delegate> delegate)
34 : delegate_(delegate.Pass()),
35 weak_factory_(this) {
36 delegate_->CheckCanFreezeRenderers(
37 base::Bind(&RendererFreezer::OnCheckCanFreezeRenderersComplete,
38 weak_factory_.GetWeakPtr()));
41 RendererFreezer::~RendererFreezer() {
42 for (int rph_id : gcm_extension_processes_) {
43 content::RenderProcessHost* host =
44 content::RenderProcessHost::FromID(rph_id);
45 if (host)
46 host->RemoveObserver(this);
50 void RendererFreezer::SuspendImminent() {
51 // All the delegate's operations are asynchronous so they may not complete
52 // before the system suspends. This is ok since the renderers only need to be
53 // frozen in dark resume. As long as they do get frozen soon after we enter
54 // dark resume, there shouldn't be a problem.
55 delegate_->FreezeRenderers();
58 void RendererFreezer::SuspendDone() {
59 delegate_->ThawRenderers(base::Bind(&RendererFreezer::OnThawRenderersComplete,
60 weak_factory_.GetWeakPtr()));
63 void RendererFreezer::Observe(int type,
64 const content::NotificationSource& source,
65 const content::NotificationDetails& details) {
66 switch (type) {
67 case chrome::NOTIFICATION_SCREEN_LOCK_STATE_CHANGED: {
68 OnScreenLockStateChanged(
69 content::Source<chromeos::ScreenLocker>(source).ptr(),
70 *(content::Details<bool>(details).ptr()));
71 break;
73 case content::NOTIFICATION_RENDERER_PROCESS_CREATED: {
74 content::RenderProcessHost* process =
75 content::Source<content::RenderProcessHost>(source).ptr();
76 OnRenderProcessCreated(process);
77 break;
79 default: {
80 NOTREACHED();
81 break;
86 void RendererFreezer::RenderProcessExited(content::RenderProcessHost* host,
87 base::TerminationStatus status,
88 int exit_code) {
89 auto it = gcm_extension_processes_.find(host->GetID());
90 if (it == gcm_extension_processes_.end()) {
91 LOG(ERROR) << "Received unrequested RenderProcessExited message";
92 return;
94 gcm_extension_processes_.erase(it);
96 // When this function is called, the renderer process has died but the
97 // RenderProcessHost will not be destroyed. If a new renderer process is
98 // created for this RPH, registering as an observer again will trigger a
99 // warning about duplicate observers. To prevent this we just stop observing
100 // this RPH until another renderer process is created for it.
101 host->RemoveObserver(this);
104 void RendererFreezer::RenderProcessHostDestroyed(
105 content::RenderProcessHost* host) {
106 auto it = gcm_extension_processes_.find(host->GetID());
107 if (it == gcm_extension_processes_.end()) {
108 LOG(ERROR) << "Received unrequested RenderProcessHostDestroyed message";
109 return;
112 gcm_extension_processes_.erase(it);
115 void RendererFreezer::OnCheckCanFreezeRenderersComplete(bool can_freeze) {
116 if (!can_freeze)
117 return;
119 DBusThreadManager::Get()
120 ->GetPowerManagerClient()
121 ->SetRenderProcessManagerDelegate(weak_factory_.GetWeakPtr());
123 registrar_.Add(this, chrome::NOTIFICATION_SCREEN_LOCK_STATE_CHANGED,
124 content::NotificationService::AllBrowserContextsAndSources());
125 registrar_.Add(
126 this,
127 content::NOTIFICATION_RENDERER_PROCESS_CREATED,
128 content::NotificationService::AllBrowserContextsAndSources());
131 void RendererFreezer::OnThawRenderersComplete(bool success) {
132 if (success)
133 return;
135 // We failed to write the thaw command and the renderers are still frozen. We
136 // are in big trouble because none of the tabs will be responsive so let's
137 // crash the browser instead.
138 LOG(FATAL) << "Unable to thaw renderers.";
141 void RendererFreezer::OnScreenLockStateChanged(chromeos::ScreenLocker* locker,
142 bool is_locked) {
143 // The ScreenLocker class sends NOTIFICATION_SCREEN_LOCK_STATE_CHANGED when
144 // the lock screen becomes ready, resulting in this code running synchronously
145 // to mark the screen locker renderer to remain unfrozen during a suspend
146 // request. Since this happens before the PowerManagerClient calls
147 // RendererFreezer::SuspendImminent(), it is guaranteed that the screen locker
148 // renderer will not be frozen at any point.
149 if (is_locked) {
150 delegate_->SetShouldFreezeRenderer(locker->delegate()
151 ->GetAssociatedWebUI()
152 ->GetWebContents()
153 ->GetRenderProcessHost()
154 ->GetHandle(),
155 false);
159 void RendererFreezer::OnRenderProcessCreated(content::RenderProcessHost* rph) {
160 const int rph_id = rph->GetID();
162 if (gcm_extension_processes_.find(rph_id) != gcm_extension_processes_.end()) {
163 LOG(ERROR) << "Received duplicate notifications about the creation of a "
164 << "RenderProcessHost with id " << rph_id;
165 return;
168 // According to extensions::ProcessMap, extensions and renderers have a
169 // many-to-many relationship. Specifically, a hosted app can appear in many
170 // renderers while any other kind of extension can be running in "split mode"
171 // if there is an incognito window open and so could appear in two renderers.
173 // We don't care about hosted apps because they cannot use GCM so we only need
174 // to worry about extensions in "split mode". Luckily for us this function is
175 // called any time a new renderer process is created so we don't really need
176 // to care whether we are currently in an incognito context. We just need to
177 // iterate over all the extensions in the newly created process and take the
178 // appropriate action based on whether we find an extension using GCM.
179 content::BrowserContext* context = rph->GetBrowserContext();
180 extensions::ExtensionRegistry* registry =
181 extensions::ExtensionRegistry::Get(context);
182 for (const std::string& extension_id :
183 extensions::ProcessMap::Get(context)->GetExtensionsInProcess(rph_id)) {
184 const extensions::Extension* extension = registry->GetExtensionById(
185 extension_id, extensions::ExtensionRegistry::ENABLED);
186 if (!extension ||
187 !extension->permissions_data()->HasAPIPermission(
188 extensions::APIPermission::kGcm)) {
189 continue;
192 // This renderer has an extension that is using GCM. Make sure it is not
193 // frozen during suspend.
194 delegate_->SetShouldFreezeRenderer(rph->GetHandle(), false);
195 gcm_extension_processes_.insert(rph_id);
197 // Watch to see if the renderer process or the RenderProcessHost is
198 // destroyed.
199 rph->AddObserver(this);
200 return;
203 // We didn't find an extension in this RenderProcessHost that is using GCM so
204 // we can go ahead and freeze it on suspend.
205 delegate_->SetShouldFreezeRenderer(rph->GetHandle(), true);
208 } // namespace chromeos