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" |
9 #include "base/message_loop/message_loop.h" | 12 #include "base/message_loop/message_loop.h" |
10 #include "base/run_loop.h" | 13 #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" |
11 #include "chromeos/dbus/dbus_thread_manager.h" | 22 #include "chromeos/dbus/dbus_thread_manager.h" |
12 #include "chromeos/dbus/fake_power_manager_client.h" | 23 #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" |
13 #include "testing/gtest/include/gtest/gtest-death-test.h" | 36 #include "testing/gtest/include/gtest/gtest-death-test.h" |
14 #include "testing/gtest/include/gtest/gtest.h" | 37 #include "testing/gtest/include/gtest/gtest.h" |
15 | 38 |
16 namespace chromeos { | 39 namespace chromeos { |
17 | 40 |
18 namespace { | 41 namespace { |
19 // Class that delegates used in testing can inherit from to record calls that | 42 // Class that delegates used in testing can inherit from to record calls that |
20 // are made by the code being tested. | 43 // are made by the code being tested. |
21 class ActionRecorder { | 44 class ActionRecorder { |
22 public: | 45 public: |
(...skipping 19 matching lines...) Expand all Loading... |
42 } | 65 } |
43 | 66 |
44 private: | 67 private: |
45 // Comma-separated list of actions that have been performed. | 68 // Comma-separated list of actions that have been performed. |
46 std::string actions_; | 69 std::string actions_; |
47 | 70 |
48 DISALLOW_COPY_AND_ASSIGN(ActionRecorder); | 71 DISALLOW_COPY_AND_ASSIGN(ActionRecorder); |
49 }; | 72 }; |
50 | 73 |
51 // Actions that can be returned by TestDelegate::GetActions(). | 74 // 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"; |
52 const char kFreezeRenderers[] = "freeze_renderers"; | 77 const char kFreezeRenderers[] = "freeze_renderers"; |
53 const char kThawRenderers[] = "thaw_renderers"; | 78 const char kThawRenderers[] = "thaw_renderers"; |
54 const char kNoActions[] = ""; | 79 const char kNoActions[] = ""; |
55 | 80 |
56 // Test implementation of RendererFreezer::Delegate that records the actions it | 81 // Test implementation of RendererFreezer::Delegate that records the actions it |
57 // was asked to perform. | 82 // was asked to perform. |
58 class TestDelegate : public RendererFreezer::Delegate, public ActionRecorder { | 83 class TestDelegate : public RendererFreezer::Delegate, public ActionRecorder { |
59 public: | 84 public: |
60 TestDelegate() | 85 TestDelegate() |
61 : can_freeze_renderers_(true), | 86 : can_freeze_renderers_(true), |
62 freeze_renderers_result_(true), | 87 freeze_renderers_result_(true), |
63 thaw_renderers_result_(true) {} | 88 thaw_renderers_result_(true) {} |
64 | 89 |
65 virtual ~TestDelegate() {} | 90 ~TestDelegate() override {} |
66 | 91 |
67 // RendererFreezer::Delegate overrides. | 92 // RendererFreezer::Delegate overrides. |
68 virtual bool FreezeRenderers() override { | 93 void SetShouldFreezeRenderer(base::ProcessHandle handle, |
| 94 bool frozen) override { |
| 95 AppendAction(frozen ? kSetShouldFreezeRenderer |
| 96 : kSetShouldNotFreezeRenderer); |
| 97 } |
| 98 bool FreezeRenderers() override { |
69 AppendAction(kFreezeRenderers); | 99 AppendAction(kFreezeRenderers); |
70 | 100 |
71 return freeze_renderers_result_; | 101 return freeze_renderers_result_; |
72 } | 102 } |
73 virtual bool ThawRenderers() override { | 103 bool ThawRenderers() override { |
74 AppendAction(kThawRenderers); | 104 AppendAction(kThawRenderers); |
75 | 105 |
76 return thaw_renderers_result_; | 106 return thaw_renderers_result_; |
77 } | 107 } |
78 virtual bool CanFreezeRenderers() override { return can_freeze_renderers_; } | 108 bool CanFreezeRenderers() override { return can_freeze_renderers_; } |
79 | 109 |
80 void set_freeze_renderers_result(bool result) { | 110 void set_freeze_renderers_result(bool result) { |
81 freeze_renderers_result_ = result; | 111 freeze_renderers_result_ = result; |
82 } | 112 } |
83 | 113 |
84 void set_thaw_renderers_result(bool result) { | 114 void set_thaw_renderers_result(bool result) { |
85 thaw_renderers_result_ = result; | 115 thaw_renderers_result_ = result; |
86 } | 116 } |
87 | 117 |
88 // Sets whether the delegate is capable of freezing renderers. This also | 118 // Sets whether the delegate is capable of freezing renderers. This also |
(...skipping 19 matching lines...) Expand all Loading... |
108 | 138 |
109 class RendererFreezerTest : public testing::Test { | 139 class RendererFreezerTest : public testing::Test { |
110 public: | 140 public: |
111 RendererFreezerTest() | 141 RendererFreezerTest() |
112 : power_manager_client_(new FakePowerManagerClient()), | 142 : power_manager_client_(new FakePowerManagerClient()), |
113 test_delegate_(new TestDelegate()) { | 143 test_delegate_(new TestDelegate()) { |
114 DBusThreadManager::GetSetterForTesting()->SetPowerManagerClient( | 144 DBusThreadManager::GetSetterForTesting()->SetPowerManagerClient( |
115 scoped_ptr<PowerManagerClient>(power_manager_client_)); | 145 scoped_ptr<PowerManagerClient>(power_manager_client_)); |
116 } | 146 } |
117 | 147 |
118 virtual ~RendererFreezerTest() { | 148 ~RendererFreezerTest() override { |
119 renderer_freezer_.reset(); | 149 renderer_freezer_.reset(); |
120 | 150 |
121 DBusThreadManager::Shutdown(); | 151 DBusThreadManager::Shutdown(); |
122 } | 152 } |
123 | 153 |
| 154 protected: |
124 void Init() { | 155 void Init() { |
125 renderer_freezer_.reset(new RendererFreezer( | 156 renderer_freezer_.reset(new RendererFreezer( |
126 scoped_ptr<RendererFreezer::Delegate>(test_delegate_))); | 157 scoped_ptr<RendererFreezer::Delegate>(test_delegate_))); |
127 } | 158 } |
128 | 159 |
129 protected: | 160 // Owned by DBusThreadManager. |
130 FakePowerManagerClient* power_manager_client_; | 161 FakePowerManagerClient* power_manager_client_; |
| 162 |
| 163 // Owned by |renderer_freezer_|. |
131 TestDelegate* test_delegate_; | 164 TestDelegate* test_delegate_; |
132 | |
133 scoped_ptr<RendererFreezer> renderer_freezer_; | 165 scoped_ptr<RendererFreezer> renderer_freezer_; |
134 | 166 |
135 private: | 167 private: |
136 base::MessageLoop message_loop_; | 168 content::TestBrowserThreadBundle browser_thread_bundle_; |
| 169 |
137 DISALLOW_COPY_AND_ASSIGN(RendererFreezerTest); | 170 DISALLOW_COPY_AND_ASSIGN(RendererFreezerTest); |
138 }; | 171 }; |
139 | 172 |
140 // Tests that the RendererFreezer freezes renderers on suspend and thaws them on | 173 // Tests that the RendererFreezer freezes renderers on suspend and thaws them on |
141 // resume. | 174 // resume. |
142 TEST_F(RendererFreezerTest, SuspendResume) { | 175 TEST_F(RendererFreezerTest, SuspendResume) { |
143 Init(); | 176 Init(); |
144 | 177 |
145 power_manager_client_->SendSuspendImminent(); | 178 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()); | |
156 EXPECT_EQ(kFreezeRenderers, test_delegate_->GetActions()); | 179 EXPECT_EQ(kFreezeRenderers, test_delegate_->GetActions()); |
157 | 180 |
158 // The renderers should be thawed when we resume. | 181 // The renderers should be thawed when we resume. |
159 power_manager_client_->SendSuspendDone(); | 182 power_manager_client_->SendSuspendDone(); |
160 EXPECT_EQ(kThawRenderers, test_delegate_->GetActions()); | 183 EXPECT_EQ(kThawRenderers, test_delegate_->GetActions()); |
161 } | 184 } |
162 | 185 |
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 | |
180 // Tests that the renderer freezer does nothing if the delegate cannot freeze | 186 // Tests that the renderer freezer does nothing if the delegate cannot freeze |
181 // renderers. | 187 // renderers. |
182 TEST_F(RendererFreezerTest, DelegateCannotFreezeRenderers) { | 188 TEST_F(RendererFreezerTest, DelegateCannotFreezeRenderers) { |
183 test_delegate_->set_can_freeze_renderers(false); | 189 test_delegate_->set_can_freeze_renderers(false); |
184 Init(); | 190 Init(); |
185 | 191 |
| 192 // Nothing happens on suspend. |
186 power_manager_client_->SendSuspendImminent(); | 193 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(); | |
195 EXPECT_EQ(kNoActions, test_delegate_->GetActions()); | 194 EXPECT_EQ(kNoActions, test_delegate_->GetActions()); |
196 | 195 |
197 // Nothing happens on resume. | 196 // Nothing happens on resume. |
198 power_manager_client_->SendSuspendDone(); | 197 power_manager_client_->SendSuspendDone(); |
199 EXPECT_EQ(kNoActions, test_delegate_->GetActions()); | 198 EXPECT_EQ(kNoActions, test_delegate_->GetActions()); |
200 } | 199 } |
201 | 200 |
202 // Tests that the RendererFreezer does nothing on resume if the freezing | 201 // Tests that the RendererFreezer does nothing on resume if the freezing |
203 // operation was unsuccessful. | 202 // operation was unsuccessful. |
204 TEST_F(RendererFreezerTest, ErrorFreezingRenderers) { | 203 TEST_F(RendererFreezerTest, ErrorFreezingRenderers) { |
205 Init(); | 204 Init(); |
206 test_delegate_->set_freeze_renderers_result(false); | 205 test_delegate_->set_freeze_renderers_result(false); |
207 | 206 |
| 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(); | |
213 EXPECT_EQ(kFreezeRenderers, test_delegate_->GetActions()); | 209 EXPECT_EQ(kFreezeRenderers, test_delegate_->GetActions()); |
214 EXPECT_EQ(0, power_manager_client_->GetNumPendingSuspendReadinessCallbacks()); | |
215 | 210 |
216 // Since the delegate reported that the freezing was unsuccessful, don't do | 211 // Since the delegate reported that the freezing was unsuccessful, don't do |
217 // anything on resume. | 212 // anything on resume. |
218 power_manager_client_->SendSuspendDone(); | 213 power_manager_client_->SendSuspendDone(); |
219 EXPECT_EQ(kNoActions, test_delegate_->GetActions()); | 214 EXPECT_EQ(kNoActions, test_delegate_->GetActions()); |
220 } | 215 } |
221 | 216 |
222 #if defined(GTEST_HAS_DEATH_TEST) | 217 #if defined(GTEST_HAS_DEATH_TEST) |
223 // Tests that the RendererFreezer crashes the browser if the freezing operation | 218 // Tests that the RendererFreezer crashes the browser if the freezing operation |
224 // was successful but the thawing operation failed. | 219 // was successful but the thawing operation failed. |
225 TEST_F(RendererFreezerTest, ErrorThawingRenderers) { | 220 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"; |
226 Init(); | 225 Init(); |
227 test_delegate_->set_thaw_renderers_result(false); | 226 test_delegate_->set_thaw_renderers_result(false); |
228 | 227 |
229 power_manager_client_->SendSuspendImminent(); | 228 power_manager_client_->SendSuspendImminent(); |
230 base::RunLoop().RunUntilIdle(); | |
231 EXPECT_EQ(kFreezeRenderers, test_delegate_->GetActions()); | 229 EXPECT_EQ(kFreezeRenderers, test_delegate_->GetActions()); |
232 | 230 |
233 EXPECT_DEATH(power_manager_client_->SendSuspendDone(), "Unable to thaw"); | 231 EXPECT_DEATH(power_manager_client_->SendSuspendDone(), "Unable to thaw"); |
234 } | 232 } |
235 #endif // GTEST_HAS_DEATH_TEST | 233 #endif // GTEST_HAS_DEATH_TEST |
236 | 234 |
| 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 |
237 } // namespace chromeos | 393 } // namespace chromeos |
OLD | NEW |