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

Side by Side Diff: chrome/browser/chromeos/power/renderer_freezer.cc

Issue 738993002: Re-land chromeos: Add non-extension renderers to the freezer cgroup (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Address comments Created 6 years, 1 month 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 2014 The Chromium Authors. All rights reserved. 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 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 "chrome/browser/chromeos/power/renderer_freezer.h" 5 #include "chrome/browser/chromeos/power/renderer_freezer.h"
6 6
7 #include <string>
8
7 #include "base/bind.h" 9 #include "base/bind.h"
8 #include "base/logging.h" 10 #include "base/logging.h"
9 #include "base/message_loop/message_loop.h" 11 #include "base/message_loop/message_loop.h"
12 #include "base/process/process_handle.h"
10 #include "chromeos/dbus/dbus_thread_manager.h" 13 #include "chromeos/dbus/dbus_thread_manager.h"
14 #include "content/public/browser/notification_details.h"
15 #include "content/public/browser/notification_service.h"
16 #include "content/public/browser/notification_source.h"
17 #include "content/public/browser/notification_types.h"
18 #include "content/public/browser/render_process_host.h"
19 #include "extensions/browser/extension_registry.h"
20 #include "extensions/browser/notification_types.h"
21 #include "extensions/browser/process_map.h"
22 #include "extensions/common/extension.h"
23 #include "extensions/common/permissions/api_permission.h"
24 #include "extensions/common/permissions/permissions_data.h"
11 25
12 namespace chromeos { 26 namespace chromeos {
13 27
14 RendererFreezer::RendererFreezer(scoped_ptr<RendererFreezer::Delegate> delegate) 28 RendererFreezer::RendererFreezer(scoped_ptr<RendererFreezer::Delegate> delegate)
15 : frozen_(false), 29 : frozen_(false),
16 delegate_(delegate.Pass()), 30 delegate_(delegate.Pass()),
17 weak_factory_(this) { 31 weak_factory_(this) {
18 if (delegate_->CanFreezeRenderers()) 32 if (delegate_->CanFreezeRenderers()) {
19 DBusThreadManager::Get()->GetPowerManagerClient()->AddObserver(this); 33 DBusThreadManager::Get()
34 ->GetPowerManagerClient()
35 ->SetRenderProcessManagerDelegate(weak_factory_.GetWeakPtr());
36
37 registrar_.Add(
38 this,
39 content::NOTIFICATION_RENDERER_PROCESS_CREATED,
40 content::NotificationService::AllBrowserContextsAndSources());
41 }
20 } 42 }
21 43
22 RendererFreezer::~RendererFreezer() { 44 RendererFreezer::~RendererFreezer() {
23 if (delegate_->CanFreezeRenderers()) 45 for (int rph_id : gcm_extension_processes_) {
24 DBusThreadManager::Get()->GetPowerManagerClient()->RemoveObserver(this); 46 content::RenderProcessHost* host =
47 content::RenderProcessHost::FromID(rph_id);
48 if (host)
49 host->RemoveObserver(this);
50 }
25 } 51 }
26 52
27 void RendererFreezer::SuspendImminent() { 53 void RendererFreezer::SuspendImminent() {
28 // If there was already a callback pending, this will cancel it and create a 54 if (delegate_->FreezeRenderers())
29 // new one. 55 frozen_ = true;
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 } 56 }
40 57
41 void RendererFreezer::SuspendDone(const base::TimeDelta& sleep_duration) { 58 void RendererFreezer::SuspendDone() {
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_) 59 if (!frozen_)
49 return; 60 return;
50 61
51 if (!delegate_->ThawRenderers()) { 62 if (!delegate_->ThawRenderers()) {
52 // We failed to write the thaw command and the renderers are still frozen. 63 // 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 64 // We are in big trouble because none of the tabs will be responsive so
54 // let's crash the browser instead. 65 // let's crash the browser instead.
55 LOG(FATAL) << "Unable to thaw renderers."; 66 LOG(FATAL) << "Unable to thaw renderers.";
56 } 67 }
57 68
58 frozen_ = false; 69 frozen_ = false;
59 } 70 }
60 71
61 void RendererFreezer::OnReadyToSuspend( 72 void RendererFreezer::Observe(int type,
62 const base::Closure& power_manager_callback) { 73 const content::NotificationSource& source,
63 if (delegate_->FreezeRenderers()) 74 const content::NotificationDetails& details) {
64 frozen_ = true; 75 switch (type) {
76 case content::NOTIFICATION_RENDERER_PROCESS_CREATED: {
77 content::RenderProcessHost* process =
78 content::Source<content::RenderProcessHost>(source).ptr();
79 OnRenderProcessCreated(process);
80 break;
81 }
82 default: {
83 NOTREACHED();
84 break;
85 }
86 }
87 }
65 88
66 DCHECK(!power_manager_callback.is_null()); 89 void RendererFreezer::RenderProcessExited(content::RenderProcessHost* host,
67 power_manager_callback.Run(); 90 base::TerminationStatus status,
91 int exit_code) {
92 auto it = gcm_extension_processes_.find(host->GetID());
93 if (it == gcm_extension_processes_.end()) {
94 LOG(ERROR) << "Received unrequested RenderProcessExited message";
95 return;
96 }
97 gcm_extension_processes_.erase(it);
98
99 // When this function is called, the renderer process has died but the
100 // RenderProcessHost will not be destroyed. If a new renderer process is
101 // created for this RPH, registering as an observer again will trigger a
102 // warning about duplicate observers. To prevent this we just stop observing
103 // this RPH until another renderer process is created for it.
104 host->RemoveObserver(this);
105 }
106
107 void RendererFreezer::RenderProcessHostDestroyed(
108 content::RenderProcessHost* host) {
109 auto it = gcm_extension_processes_.find(host->GetID());
110 if (it == gcm_extension_processes_.end()) {
111 LOG(ERROR) << "Received unrequested RenderProcessHostDestroyed message";
112 return;
113 }
114
115 gcm_extension_processes_.erase(it);
116 }
117
118 void RendererFreezer::OnRenderProcessCreated(content::RenderProcessHost* rph) {
119 const int rph_id = rph->GetID();
120
121 if (gcm_extension_processes_.find(rph_id) != gcm_extension_processes_.end()) {
122 LOG(ERROR) << "Received duplicate notifications about the creation of a "
123 << "RenderProcessHost with id " << rph_id;
124 return;
125 }
126
127 // According to extensions::ProcessMap, extensions and renderers have a
128 // many-to-many relationship. Specifically, a hosted app can appear in many
129 // renderers while any other kind of extension can be running in "split mode"
130 // if there is an incognito window open and so could appear in two renderers.
131 //
132 // We don't care about hosted apps because they cannot use GCM so we only need
133 // to worry about extensions in "split mode". Luckily for us this function is
134 // called any time a new renderer process is created so we don't really need
135 // to care whether we are currently in an incognito context. We just need to
136 // iterate over all the extensions in the newly created process and take the
137 // appropriate action based on whether we find an extension using GCM.
138 content::BrowserContext* context = rph->GetBrowserContext();
139 extensions::ExtensionRegistry* registry =
140 extensions::ExtensionRegistry::Get(context);
141 for (const std::string& extension_id :
142 extensions::ProcessMap::Get(context)->GetExtensionsInProcess(rph_id)) {
143 if (!registry->GetExtensionById(extension_id,
144 extensions::ExtensionRegistry::ENABLED)
145 ->permissions_data()
146 ->HasAPIPermission(extensions::APIPermission::kGcm)) {
147 continue;
148 }
149
150 // This renderer has an extension that is using GCM. Make sure it is not
151 // frozen during suspend.
152 delegate_->SetShouldFreezeRenderer(rph->GetHandle(), false);
153 gcm_extension_processes_.insert(rph_id);
154
155 // Watch to see if the renderer process or the RenderProcessHost is
156 // destroyed.
157 rph->AddObserver(this);
158 return;
159 }
160
161 // We didn't find an extension in this RenderProcessHost that is using GCM so
162 // we can go ahead and freeze it on suspend.
163 delegate_->SetShouldFreezeRenderer(rph->GetHandle(), true);
68 } 164 }
69 165
70 } // namespace chromeos 166 } // namespace chromeos
OLDNEW
« no previous file with comments | « chrome/browser/chromeos/power/renderer_freezer.h ('k') | chrome/browser/chromeos/power/renderer_freezer_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698