OLD | NEW |
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> | 7 #include <string> |
8 | 8 |
9 #include "base/command_line.h" | |
10 #include "base/memory/ref_counted.h" | |
11 #include "base/memory/scoped_ptr.h" | |
12 #include "base/message_loop/message_loop.h" | 9 #include "base/message_loop/message_loop.h" |
13 #include "base/run_loop.h" | 10 #include "base/run_loop.h" |
14 #include "chrome/browser/chromeos/login/users/scoped_test_user_manager.h" | |
15 #include "chrome/browser/chromeos/settings/cros_settings.h" | |
16 #include "chrome/browser/chromeos/settings/device_settings_service.h" | |
17 #include "chrome/browser/extensions/extension_service.h" | |
18 #include "chrome/browser/extensions/test_extension_system.h" | |
19 #include "chrome/test/base/testing_browser_process.h" | |
20 #include "chrome/test/base/testing_profile.h" | |
21 #include "chrome/test/base/testing_profile_manager.h" | |
22 #include "chromeos/dbus/dbus_thread_manager.h" | 11 #include "chromeos/dbus/dbus_thread_manager.h" |
23 #include "chromeos/dbus/fake_power_manager_client.h" | 12 #include "chromeos/dbus/fake_power_manager_client.h" |
24 #include "content/public/browser/notification_service.h" | |
25 #include "content/public/browser/notification_source.h" | |
26 #include "content/public/browser/notification_types.h" | |
27 #include "content/public/browser/site_instance.h" | |
28 #include "content/public/test/mock_render_process_host.h" | |
29 #include "content/public/test/test_browser_thread_bundle.h" | |
30 #include "extensions/browser/notification_types.h" | |
31 #include "extensions/browser/process_manager.h" | |
32 #include "extensions/browser/process_map.h" | |
33 #include "extensions/common/extension_builder.h" | |
34 #include "extensions/common/manifest_handlers/background_info.h" | |
35 #include "extensions/common/value_builder.h" | |
36 #include "testing/gtest/include/gtest/gtest-death-test.h" | 13 #include "testing/gtest/include/gtest/gtest-death-test.h" |
37 #include "testing/gtest/include/gtest/gtest.h" | 14 #include "testing/gtest/include/gtest/gtest.h" |
38 | 15 |
39 namespace chromeos { | 16 namespace chromeos { |
40 | 17 |
41 namespace { | 18 namespace { |
42 // Class that delegates used in testing can inherit from to record calls that | 19 // Class that delegates used in testing can inherit from to record calls that |
43 // are made by the code being tested. | 20 // are made by the code being tested. |
44 class ActionRecorder { | 21 class ActionRecorder { |
45 public: | 22 public: |
(...skipping 19 matching lines...) Expand all Loading... |
65 } | 42 } |
66 | 43 |
67 private: | 44 private: |
68 // Comma-separated list of actions that have been performed. | 45 // Comma-separated list of actions that have been performed. |
69 std::string actions_; | 46 std::string actions_; |
70 | 47 |
71 DISALLOW_COPY_AND_ASSIGN(ActionRecorder); | 48 DISALLOW_COPY_AND_ASSIGN(ActionRecorder); |
72 }; | 49 }; |
73 | 50 |
74 // Actions that can be returned by TestDelegate::GetActions(). | 51 // Actions that can be returned by TestDelegate::GetActions(). |
75 const char kSetShouldFreezeRenderer[] = "set_should_freeze_renderer"; | |
76 const char kSetShouldNotFreezeRenderer[] = "set_should_not_freeze_renderer"; | |
77 const char kFreezeRenderers[] = "freeze_renderers"; | 52 const char kFreezeRenderers[] = "freeze_renderers"; |
78 const char kThawRenderers[] = "thaw_renderers"; | 53 const char kThawRenderers[] = "thaw_renderers"; |
79 const char kNoActions[] = ""; | 54 const char kNoActions[] = ""; |
80 | 55 |
81 // Test implementation of RendererFreezer::Delegate that records the actions it | 56 // Test implementation of RendererFreezer::Delegate that records the actions it |
82 // was asked to perform. | 57 // was asked to perform. |
83 class TestDelegate : public RendererFreezer::Delegate, public ActionRecorder { | 58 class TestDelegate : public RendererFreezer::Delegate, public ActionRecorder { |
84 public: | 59 public: |
85 TestDelegate() | 60 TestDelegate() |
86 : can_freeze_renderers_(true), | 61 : can_freeze_renderers_(true), |
87 freeze_renderers_result_(true), | 62 freeze_renderers_result_(true), |
88 thaw_renderers_result_(true) {} | 63 thaw_renderers_result_(true) {} |
89 | 64 |
90 ~TestDelegate() override {} | 65 virtual ~TestDelegate() {} |
91 | 66 |
92 // RendererFreezer::Delegate overrides. | 67 // RendererFreezer::Delegate overrides. |
93 void SetShouldFreezeRenderer(base::ProcessHandle handle, | 68 virtual bool FreezeRenderers() override { |
94 bool frozen) override { | |
95 AppendAction(frozen ? kSetShouldFreezeRenderer | |
96 : kSetShouldNotFreezeRenderer); | |
97 } | |
98 bool FreezeRenderers() override { | |
99 AppendAction(kFreezeRenderers); | 69 AppendAction(kFreezeRenderers); |
100 | 70 |
101 return freeze_renderers_result_; | 71 return freeze_renderers_result_; |
102 } | 72 } |
103 bool ThawRenderers() override { | 73 virtual bool ThawRenderers() override { |
104 AppendAction(kThawRenderers); | 74 AppendAction(kThawRenderers); |
105 | 75 |
106 return thaw_renderers_result_; | 76 return thaw_renderers_result_; |
107 } | 77 } |
108 bool CanFreezeRenderers() override { return can_freeze_renderers_; } | 78 virtual bool CanFreezeRenderers() override { return can_freeze_renderers_; } |
109 | 79 |
110 void set_freeze_renderers_result(bool result) { | 80 void set_freeze_renderers_result(bool result) { |
111 freeze_renderers_result_ = result; | 81 freeze_renderers_result_ = result; |
112 } | 82 } |
113 | 83 |
114 void set_thaw_renderers_result(bool result) { | 84 void set_thaw_renderers_result(bool result) { |
115 thaw_renderers_result_ = result; | 85 thaw_renderers_result_ = result; |
116 } | 86 } |
117 | 87 |
118 // Sets whether the delegate is capable of freezing renderers. This also | 88 // Sets whether the delegate is capable of freezing renderers. This also |
(...skipping 19 matching lines...) Expand all Loading... |
138 | 108 |
139 class RendererFreezerTest : public testing::Test { | 109 class RendererFreezerTest : public testing::Test { |
140 public: | 110 public: |
141 RendererFreezerTest() | 111 RendererFreezerTest() |
142 : power_manager_client_(new FakePowerManagerClient()), | 112 : power_manager_client_(new FakePowerManagerClient()), |
143 test_delegate_(new TestDelegate()) { | 113 test_delegate_(new TestDelegate()) { |
144 DBusThreadManager::GetSetterForTesting()->SetPowerManagerClient( | 114 DBusThreadManager::GetSetterForTesting()->SetPowerManagerClient( |
145 scoped_ptr<PowerManagerClient>(power_manager_client_)); | 115 scoped_ptr<PowerManagerClient>(power_manager_client_)); |
146 } | 116 } |
147 | 117 |
148 ~RendererFreezerTest() override { | 118 virtual ~RendererFreezerTest() { |
149 renderer_freezer_.reset(); | 119 renderer_freezer_.reset(); |
150 | 120 |
151 DBusThreadManager::Shutdown(); | 121 DBusThreadManager::Shutdown(); |
152 } | 122 } |
153 | 123 |
154 protected: | |
155 void Init() { | 124 void Init() { |
156 renderer_freezer_.reset(new RendererFreezer( | 125 renderer_freezer_.reset(new RendererFreezer( |
157 scoped_ptr<RendererFreezer::Delegate>(test_delegate_))); | 126 scoped_ptr<RendererFreezer::Delegate>(test_delegate_))); |
158 } | 127 } |
159 | 128 |
160 // Owned by DBusThreadManager. | 129 protected: |
161 FakePowerManagerClient* power_manager_client_; | 130 FakePowerManagerClient* power_manager_client_; |
| 131 TestDelegate* test_delegate_; |
162 | 132 |
163 // Owned by |renderer_freezer_|. | |
164 TestDelegate* test_delegate_; | |
165 scoped_ptr<RendererFreezer> renderer_freezer_; | 133 scoped_ptr<RendererFreezer> renderer_freezer_; |
166 | 134 |
167 private: | 135 private: |
168 content::TestBrowserThreadBundle browser_thread_bundle_; | 136 base::MessageLoop message_loop_; |
169 | |
170 DISALLOW_COPY_AND_ASSIGN(RendererFreezerTest); | 137 DISALLOW_COPY_AND_ASSIGN(RendererFreezerTest); |
171 }; | 138 }; |
172 | 139 |
173 // Tests that the RendererFreezer freezes renderers on suspend and thaws them on | 140 // Tests that the RendererFreezer freezes renderers on suspend and thaws them on |
174 // resume. | 141 // resume. |
175 TEST_F(RendererFreezerTest, SuspendResume) { | 142 TEST_F(RendererFreezerTest, SuspendResume) { |
176 Init(); | 143 Init(); |
177 | 144 |
178 power_manager_client_->SendSuspendImminent(); | 145 power_manager_client_->SendSuspendImminent(); |
| 146 |
| 147 // The RendererFreezer should have grabbed an asynchronous callback and done |
| 148 // nothing else. |
| 149 EXPECT_EQ(1, power_manager_client_->GetNumPendingSuspendReadinessCallbacks()); |
| 150 EXPECT_EQ(kNoActions, test_delegate_->GetActions()); |
| 151 |
| 152 // The RendererFreezer should eventually freeze the renderers and run the |
| 153 // callback. |
| 154 base::RunLoop().RunUntilIdle(); |
| 155 EXPECT_EQ(0, power_manager_client_->GetNumPendingSuspendReadinessCallbacks()); |
179 EXPECT_EQ(kFreezeRenderers, test_delegate_->GetActions()); | 156 EXPECT_EQ(kFreezeRenderers, test_delegate_->GetActions()); |
180 | 157 |
181 // The renderers should be thawed when we resume. | 158 // The renderers should be thawed when we resume. |
182 power_manager_client_->SendSuspendDone(); | 159 power_manager_client_->SendSuspendDone(); |
183 EXPECT_EQ(kThawRenderers, test_delegate_->GetActions()); | 160 EXPECT_EQ(kThawRenderers, test_delegate_->GetActions()); |
184 } | 161 } |
185 | 162 |
| 163 // Tests that the RendereFreezer doesn't freeze renderers if the suspend attempt |
| 164 // was canceled before it had a chance to complete. |
| 165 TEST_F(RendererFreezerTest, SuspendCanceled) { |
| 166 Init(); |
| 167 |
| 168 // We shouldn't do anything yet. |
| 169 power_manager_client_->SendSuspendImminent(); |
| 170 EXPECT_EQ(kNoActions, test_delegate_->GetActions()); |
| 171 |
| 172 // If a suspend gets canceled for any reason, we should see a SuspendDone(). |
| 173 power_manager_client_->SendSuspendDone(); |
| 174 |
| 175 // We shouldn't try to freeze the renderers now. |
| 176 base::RunLoop().RunUntilIdle(); |
| 177 EXPECT_EQ(kNoActions, test_delegate_->GetActions()); |
| 178 } |
| 179 |
186 // Tests that the renderer freezer does nothing if the delegate cannot freeze | 180 // Tests that the renderer freezer does nothing if the delegate cannot freeze |
187 // renderers. | 181 // renderers. |
188 TEST_F(RendererFreezerTest, DelegateCannotFreezeRenderers) { | 182 TEST_F(RendererFreezerTest, DelegateCannotFreezeRenderers) { |
189 test_delegate_->set_can_freeze_renderers(false); | 183 test_delegate_->set_can_freeze_renderers(false); |
190 Init(); | 184 Init(); |
191 | 185 |
192 // Nothing happens on suspend. | |
193 power_manager_client_->SendSuspendImminent(); | 186 power_manager_client_->SendSuspendImminent(); |
| 187 |
| 188 // The RendererFreezer should not have grabbed a callback or done anything |
| 189 // else. |
| 190 EXPECT_EQ(0, power_manager_client_->GetNumPendingSuspendReadinessCallbacks()); |
| 191 EXPECT_EQ(kNoActions, test_delegate_->GetActions()); |
| 192 |
| 193 // There should be nothing in the message loop. |
| 194 base::RunLoop().RunUntilIdle(); |
194 EXPECT_EQ(kNoActions, test_delegate_->GetActions()); | 195 EXPECT_EQ(kNoActions, test_delegate_->GetActions()); |
195 | 196 |
196 // Nothing happens on resume. | 197 // Nothing happens on resume. |
197 power_manager_client_->SendSuspendDone(); | 198 power_manager_client_->SendSuspendDone(); |
198 EXPECT_EQ(kNoActions, test_delegate_->GetActions()); | 199 EXPECT_EQ(kNoActions, test_delegate_->GetActions()); |
199 } | 200 } |
200 | 201 |
201 // Tests that the RendererFreezer does nothing on resume if the freezing | 202 // Tests that the RendererFreezer does nothing on resume if the freezing |
202 // operation was unsuccessful. | 203 // operation was unsuccessful. |
203 TEST_F(RendererFreezerTest, ErrorFreezingRenderers) { | 204 TEST_F(RendererFreezerTest, ErrorFreezingRenderers) { |
204 Init(); | 205 Init(); |
205 test_delegate_->set_freeze_renderers_result(false); | 206 test_delegate_->set_freeze_renderers_result(false); |
206 | 207 |
207 // The freezing operation will fail. | |
208 power_manager_client_->SendSuspendImminent(); | 208 power_manager_client_->SendSuspendImminent(); |
| 209 EXPECT_EQ(1, power_manager_client_->GetNumPendingSuspendReadinessCallbacks()); |
| 210 |
| 211 // The freezing operation should fail, but we should still report readiness. |
| 212 base::RunLoop().RunUntilIdle(); |
209 EXPECT_EQ(kFreezeRenderers, test_delegate_->GetActions()); | 213 EXPECT_EQ(kFreezeRenderers, test_delegate_->GetActions()); |
| 214 EXPECT_EQ(0, power_manager_client_->GetNumPendingSuspendReadinessCallbacks()); |
210 | 215 |
211 // Since the delegate reported that the freezing was unsuccessful, don't do | 216 // Since the delegate reported that the freezing was unsuccessful, don't do |
212 // anything on resume. | 217 // anything on resume. |
213 power_manager_client_->SendSuspendDone(); | 218 power_manager_client_->SendSuspendDone(); |
214 EXPECT_EQ(kNoActions, test_delegate_->GetActions()); | 219 EXPECT_EQ(kNoActions, test_delegate_->GetActions()); |
215 } | 220 } |
216 | 221 |
217 #if defined(GTEST_HAS_DEATH_TEST) | 222 #if defined(GTEST_HAS_DEATH_TEST) |
218 // Tests that the RendererFreezer crashes the browser if the freezing operation | 223 // Tests that the RendererFreezer crashes the browser if the freezing operation |
219 // was successful but the thawing operation failed. | 224 // was successful but the thawing operation failed. |
220 TEST_F(RendererFreezerTest, ErrorThawingRenderers) { | 225 TEST_F(RendererFreezerTest, ErrorThawingRenderers) { |
221 // The "threadsafe" style of death test re-executes the unit test binary, | |
222 // which in turn re-initializes some global state leading to failed CHECKs. | |
223 // Instead, we use the "fast" style here to prevent re-initialization. | |
224 ::testing::FLAGS_gtest_death_test_style = "fast"; | |
225 Init(); | 226 Init(); |
226 test_delegate_->set_thaw_renderers_result(false); | 227 test_delegate_->set_thaw_renderers_result(false); |
227 | 228 |
228 power_manager_client_->SendSuspendImminent(); | 229 power_manager_client_->SendSuspendImminent(); |
| 230 base::RunLoop().RunUntilIdle(); |
229 EXPECT_EQ(kFreezeRenderers, test_delegate_->GetActions()); | 231 EXPECT_EQ(kFreezeRenderers, test_delegate_->GetActions()); |
230 | 232 |
231 EXPECT_DEATH(power_manager_client_->SendSuspendDone(), "Unable to thaw"); | 233 EXPECT_DEATH(power_manager_client_->SendSuspendDone(), "Unable to thaw"); |
232 } | 234 } |
233 #endif // GTEST_HAS_DEATH_TEST | 235 #endif // GTEST_HAS_DEATH_TEST |
234 | 236 |
235 class RendererFreezerTestWithExtensions : public RendererFreezerTest { | |
236 public: | |
237 RendererFreezerTestWithExtensions() {} | |
238 ~RendererFreezerTestWithExtensions() override {} | |
239 | |
240 // testing::Test overrides. | |
241 void SetUp() override { | |
242 RendererFreezerTest::SetUp(); | |
243 | |
244 profile_manager_.reset( | |
245 new TestingProfileManager(TestingBrowserProcess::GetGlobal())); | |
246 | |
247 // Must be called from testing::Test::SetUp. | |
248 EXPECT_TRUE(profile_manager_->SetUp()); | |
249 | |
250 profile_ = profile_manager_->CreateTestingProfile("RendererFreezerTest"); | |
251 | |
252 extensions::TestExtensionSystem* extension_system = | |
253 static_cast<extensions::TestExtensionSystem*>( | |
254 extensions::ExtensionSystem::Get(profile_)); | |
255 extension_system->CreateExtensionService( | |
256 base::CommandLine::ForCurrentProcess(), | |
257 base::FilePath() /* install_directory */, | |
258 false /* autoupdate_enabled*/); | |
259 } | |
260 void TearDown() override { | |
261 extensions::ExtensionSystem::Get(profile_)->Shutdown(); | |
262 | |
263 profile_ = NULL; | |
264 | |
265 profile_manager_->DeleteAllTestingProfiles(); | |
266 | |
267 base::RunLoop().RunUntilIdle(); | |
268 | |
269 profile_manager_.reset(); | |
270 | |
271 RendererFreezerTest::TearDown(); | |
272 } | |
273 | |
274 protected: | |
275 void CreateRenderProcessForExtension(extensions::Extension* extension) { | |
276 scoped_ptr<content::MockRenderProcessHostFactory> rph_factory( | |
277 new content::MockRenderProcessHostFactory()); | |
278 scoped_refptr<content::SiteInstance> site_instance( | |
279 extensions::ProcessManager::Get(profile_)->GetSiteInstanceForURL( | |
280 extensions::BackgroundInfo::GetBackgroundURL(extension))); | |
281 scoped_ptr<content::RenderProcessHost> rph( | |
282 rph_factory->CreateRenderProcessHost(profile_, site_instance.get())); | |
283 | |
284 // Fake that the RenderProcessHost is hosting the gcm app. | |
285 extensions::ProcessMap::Get(profile_) | |
286 ->Insert(extension->id(), rph->GetID(), site_instance->GetId()); | |
287 | |
288 // Send the notification that the RenderProcessHost has been created. | |
289 content::NotificationService::current()->Notify( | |
290 content::NOTIFICATION_RENDERER_PROCESS_CREATED, | |
291 content::Source<content::RenderProcessHost>(rph.get()), | |
292 content::NotificationService::NoDetails()); | |
293 } | |
294 | |
295 // Owned by |profile_manager_|. | |
296 TestingProfile* profile_; | |
297 scoped_ptr<TestingProfileManager> profile_manager_; | |
298 | |
299 private: | |
300 // Chrome OS needs extra services to run in the following order. | |
301 chromeos::ScopedTestDeviceSettingsService test_device_settings_service_; | |
302 chromeos::ScopedTestCrosSettings test_cros_settings_; | |
303 chromeos::ScopedTestUserManager test_user_manager_; | |
304 | |
305 DISALLOW_COPY_AND_ASSIGN(RendererFreezerTestWithExtensions); | |
306 }; | |
307 | |
308 // Tests that the RendererFreezer freezes renderers that are not hosting | |
309 // GCM extensions. | |
310 TEST_F(RendererFreezerTestWithExtensions, FreezesNonExtensionRenderers) { | |
311 Init(); | |
312 | |
313 // Create the mock RenderProcessHost. | |
314 scoped_ptr<content::MockRenderProcessHostFactory> rph_factory( | |
315 new content::MockRenderProcessHostFactory()); | |
316 scoped_refptr<content::SiteInstance> site_instance( | |
317 content::SiteInstance::Create(profile_)); | |
318 scoped_ptr<content::RenderProcessHost> rph( | |
319 rph_factory->CreateRenderProcessHost(profile_, site_instance.get())); | |
320 | |
321 // Send the notification that the RenderProcessHost has been created. | |
322 content::NotificationService::current()->Notify( | |
323 content::NOTIFICATION_RENDERER_PROCESS_CREATED, | |
324 content::Source<content::RenderProcessHost>(rph.get()), | |
325 content::NotificationService::NoDetails()); | |
326 | |
327 EXPECT_EQ(kSetShouldFreezeRenderer, test_delegate_->GetActions()); | |
328 } | |
329 | |
330 // Tests that the RendererFreezer does not freeze renderers that are hosting | |
331 // extensions that use GCM. | |
332 TEST_F(RendererFreezerTestWithExtensions, DoesNotFreezeGcmExtensionRenderers) { | |
333 Init(); | |
334 | |
335 // First build the GCM extension. | |
336 scoped_refptr<extensions::Extension> gcm_app = | |
337 extensions::ExtensionBuilder() | |
338 .SetManifest(extensions::DictionaryBuilder() | |
339 .Set("name", "GCM App") | |
340 .Set("version", "1.0.0") | |
341 .Set("manifest_version", 2) | |
342 .Set("app", | |
343 extensions::DictionaryBuilder() | |
344 .Set("background", | |
345 extensions::DictionaryBuilder() | |
346 .Set("scripts", | |
347 extensions::ListBuilder() | |
348 .Append("background.js")))) | |
349 .Set("permissions", | |
350 extensions::ListBuilder() | |
351 .Append("gcm"))) | |
352 .Build(); | |
353 | |
354 // Now install it and give it a renderer. | |
355 extensions::ExtensionSystem::Get(profile_) | |
356 ->extension_service() | |
357 ->AddExtension(gcm_app.get()); | |
358 CreateRenderProcessForExtension(gcm_app.get()); | |
359 | |
360 EXPECT_EQ(kSetShouldNotFreezeRenderer, test_delegate_->GetActions()); | |
361 } | |
362 | |
363 // Tests that the RendererFreezer freezes renderers that are hosting extensions | |
364 // that do not use GCM. | |
365 TEST_F(RendererFreezerTestWithExtensions, FreezesNonGcmExtensionRenderers) { | |
366 Init(); | |
367 | |
368 // First build the extension. | |
369 scoped_refptr<extensions::Extension> background_app = | |
370 extensions::ExtensionBuilder() | |
371 .SetManifest(extensions::DictionaryBuilder() | |
372 .Set("name", "Background App") | |
373 .Set("version", "1.0.0") | |
374 .Set("manifest_version", 2) | |
375 .Set("app", | |
376 extensions::DictionaryBuilder() | |
377 .Set("background", | |
378 extensions::DictionaryBuilder() | |
379 .Set("scripts", | |
380 extensions::ListBuilder() | |
381 .Append("background.js"))))) | |
382 .Build(); | |
383 | |
384 // Now install it and give it a renderer. | |
385 extensions::ExtensionSystem::Get(profile_) | |
386 ->extension_service() | |
387 ->AddExtension(background_app.get()); | |
388 CreateRenderProcessForExtension(background_app.get()); | |
389 | |
390 EXPECT_EQ(kSetShouldFreezeRenderer, test_delegate_->GetActions()); | |
391 } | |
392 | |
393 } // namespace chromeos | 237 } // namespace chromeos |
OLD | NEW |