• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2012 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 "base/path_service.h"
6 #include "base/strings/stringprintf.h"
7 #include "base/strings/utf_string_conversions.h"
8 #include "chrome/browser/background/background_contents_service.h"
9 #include "chrome/browser/background/background_contents_service_factory.h"
10 #include "chrome/browser/background/background_mode_manager.h"
11 #include "chrome/browser/browser_process.h"
12 #include "chrome/browser/chrome_notification_types.h"
13 #include "chrome/browser/extensions/extension_apitest.h"
14 #include "chrome/browser/extensions/extension_service.h"
15 #include "chrome/browser/extensions/extension_test_message_listener.h"
16 #include "chrome/browser/profiles/profile.h"
17 #include "chrome/browser/ui/browser.h"
18 #include "chrome/browser/ui/browser_dialogs.h"
19 #include "chrome/browser/ui/browser_window.h"
20 #include "chrome/browser/ui/extensions/application_launch.h"
21 #include "chrome/common/chrome_paths.h"
22 #include "chrome/common/chrome_switches.h"
23 #include "components/nacl/browser/nacl_process_host.h"
24 #include "content/public/browser/notification_service.h"
25 #include "content/public/test/test_notification_tracker.h"
26 #include "content/public/test/test_utils.h"
27 #include "extensions/common/extension.h"
28 #include "extensions/common/switches.h"
29 #include "net/dns/mock_host_resolver.h"
30 #include "net/test/embedded_test_server/embedded_test_server.h"
31 
32 #if defined(OS_MACOSX)
33 #include "base/mac/scoped_nsautorelease_pool.h"
34 #endif
35 
36 using base::ASCIIToUTF16;
37 using extensions::Extension;
38 
39 class AppBackgroundPageApiTest : public ExtensionApiTest {
40  public:
SetUpCommandLine(CommandLine * command_line)41   virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
42     ExtensionApiTest::SetUpCommandLine(command_line);
43     command_line->AppendSwitch(switches::kDisablePopupBlocking);
44     command_line->AppendSwitch(extensions::switches::kAllowHTTPBackgroundPage);
45   }
46 
CreateApp(const std::string & app_manifest,base::FilePath * app_dir)47   bool CreateApp(const std::string& app_manifest,
48                  base::FilePath* app_dir) {
49     if (!app_dir_.CreateUniqueTempDir()) {
50       LOG(ERROR) << "Unable to create a temporary directory.";
51       return false;
52     }
53     base::FilePath manifest_path = app_dir_.path().AppendASCII("manifest.json");
54     int bytes_written = base::WriteFile(manifest_path,
55                                         app_manifest.data(),
56                                         app_manifest.size());
57     if (bytes_written != static_cast<int>(app_manifest.size())) {
58       LOG(ERROR) << "Unable to write complete manifest to file. Return code="
59                  << bytes_written;
60       return false;
61     }
62     *app_dir = app_dir_.path();
63     return true;
64   }
65 
WaitForBackgroundMode(bool expected_background_mode)66   bool WaitForBackgroundMode(bool expected_background_mode) {
67 #if defined(OS_CHROMEOS)
68     // BackgroundMode is not supported on chromeos, so we should test the
69     // behavior of BackgroundContents, but not the background mode state itself.
70     return true;
71 #else
72     BackgroundModeManager* manager =
73         g_browser_process->background_mode_manager();
74     // If background mode is disabled on this platform (e.g. cros), then skip
75     // this check.
76     if (!manager || !manager->IsBackgroundModePrefEnabled()) {
77       DLOG(WARNING) << "Skipping check - background mode disabled";
78       return true;
79     }
80     if (manager->IsBackgroundModeActive() == expected_background_mode)
81       return true;
82 
83     // We are not currently in the expected state - wait for the state to
84     // change.
85     content::WindowedNotificationObserver watcher(
86         chrome::NOTIFICATION_BACKGROUND_MODE_CHANGED,
87         content::NotificationService::AllSources());
88     watcher.Wait();
89     return manager->IsBackgroundModeActive() == expected_background_mode;
90 #endif
91   }
92 
CloseBrowser(Browser * browser)93   void CloseBrowser(Browser* browser) {
94     content::WindowedNotificationObserver observer(
95         chrome::NOTIFICATION_BROWSER_CLOSED,
96         content::NotificationService::AllSources());
97     browser->window()->Close();
98 #if defined(OS_MACOSX)
99     // BrowserWindowController depends on the auto release pool being recycled
100     // in the message loop to delete itself, which frees the Browser object
101     // which fires this event.
102     AutoreleasePool()->Recycle();
103 #endif
104     observer.Wait();
105   }
106 
UnloadExtensionViaTask(const std::string & id)107   void UnloadExtensionViaTask(const std::string& id) {
108     base::MessageLoop::current()->PostTask(
109         FROM_HERE,
110         base::Bind(&AppBackgroundPageApiTest::UnloadExtension, this, id));
111   }
112 
113  private:
114   base::ScopedTempDir app_dir_;
115 };
116 
117 namespace {
118 
119 // Fixture to assist in testing v2 app background pages containing
120 // Native Client embeds.
121 class AppBackgroundPageNaClTest : public AppBackgroundPageApiTest {
122  public:
AppBackgroundPageNaClTest()123   AppBackgroundPageNaClTest()
124       : extension_(NULL) {}
~AppBackgroundPageNaClTest()125   virtual ~AppBackgroundPageNaClTest() {
126   }
127 
SetUpCommandLine(CommandLine * command_line)128   virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
129     AppBackgroundPageApiTest::SetUpCommandLine(command_line);
130 #if !defined(DISABLE_NACL)
131     nacl::NaClProcessHost::SetPpapiKeepAliveThrottleForTesting(50);
132 #endif
133     command_line->AppendSwitchASCII(
134         extensions::switches::kEventPageIdleTime, "1000");
135     command_line->AppendSwitchASCII(
136         extensions::switches::kEventPageSuspendingTime, "1000");
137   }
138 
extension()139   const Extension* extension() { return extension_; }
140 
141  protected:
LaunchTestingApp()142   void LaunchTestingApp() {
143     base::FilePath app_dir;
144     PathService::Get(chrome::DIR_GEN_TEST_DATA, &app_dir);
145     app_dir = app_dir.AppendASCII(
146         "ppapi/tests/extensions/background_keepalive/newlib");
147     extension_ = LoadExtension(app_dir);
148     ASSERT_TRUE(extension_);
149   }
150 
151  private:
152   const Extension* extension_;
153 };
154 
155 // Produces an extensions::ProcessManager::ImpulseCallbackForTesting callback
156 // that will match a specified goal and can be waited on.
157 class ImpulseCallbackCounter {
158  public:
ImpulseCallbackCounter(extensions::ProcessManager * manager,const std::string & extension_id)159   explicit ImpulseCallbackCounter(extensions::ProcessManager* manager,
160                                   const std::string& extension_id)
161       : observed_(0),
162         goal_(0),
163         manager_(manager),
164         extension_id_(extension_id) {
165   }
166 
167   extensions::ProcessManager::ImpulseCallbackForTesting
SetGoalAndGetCallback(int goal)168       SetGoalAndGetCallback(int goal) {
169     observed_ = 0;
170     goal_ = goal;
171     message_loop_runner_ = new content::MessageLoopRunner();
172     return base::Bind(&ImpulseCallbackCounter::ImpulseCallback,
173                       base::Unretained(this),
174                       message_loop_runner_->QuitClosure(),
175                       extension_id_);
176   }
177 
Wait()178   void Wait() {
179     message_loop_runner_->Run();
180   }
181  private:
ImpulseCallback(const base::Closure & quit_callback,const std::string & extension_id_from_test,const std::string & extension_id_from_manager)182   void ImpulseCallback(
183       const base::Closure& quit_callback,
184       const std::string& extension_id_from_test,
185       const std::string& extension_id_from_manager) {
186     if (extension_id_from_test == extension_id_from_manager) {
187       if (++observed_ >= goal_) {
188         // Clear callback to free reference to message loop.
189         manager_->SetKeepaliveImpulseCallbackForTesting(
190             extensions::ProcessManager::ImpulseCallbackForTesting());
191         manager_->SetKeepaliveImpulseDecrementCallbackForTesting(
192             extensions::ProcessManager::ImpulseCallbackForTesting());
193         quit_callback.Run();
194       }
195     }
196   }
197 
198   int observed_;
199   int goal_;
200   extensions::ProcessManager* manager_;
201   const std::string extension_id_;
202   scoped_refptr<content::MessageLoopRunner> message_loop_runner_;
203 };
204 
205 }  // namespace
206 
207 // Disable on Mac only.  http://crbug.com/95139
208 #if defined(OS_MACOSX)
209 #define MAYBE_Basic DISABLED_Basic
210 #else
211 #define MAYBE_Basic Basic
212 #endif
213 
IN_PROC_BROWSER_TEST_F(AppBackgroundPageApiTest,MAYBE_Basic)214 IN_PROC_BROWSER_TEST_F(AppBackgroundPageApiTest, MAYBE_Basic) {
215   host_resolver()->AddRule("a.com", "127.0.0.1");
216   ASSERT_TRUE(StartEmbeddedTestServer());
217 
218   std::string app_manifest = base::StringPrintf(
219       "{"
220       "  \"name\": \"App\","
221       "  \"version\": \"0.1\","
222       "  \"manifest_version\": 2,"
223       "  \"app\": {"
224       "    \"urls\": ["
225       "      \"http://a.com/\""
226       "    ],"
227       "    \"launch\": {"
228       "      \"web_url\": \"http://a.com:%d/\""
229       "    }"
230       "  },"
231       "  \"permissions\": [\"background\"]"
232       "}",
233       embedded_test_server()->port());
234 
235   base::FilePath app_dir;
236   ASSERT_TRUE(CreateApp(app_manifest, &app_dir));
237   ASSERT_TRUE(LoadExtension(app_dir));
238   // Background mode should not be active until a background page is created.
239   ASSERT_TRUE(WaitForBackgroundMode(false));
240   ASSERT_TRUE(RunExtensionTest("app_background_page/basic")) << message_;
241   // The test closes the background contents, so we should fall back to no
242   // background mode at the end.
243   ASSERT_TRUE(WaitForBackgroundMode(false));
244 }
245 
246 // Crashy, http://crbug.com/69215.
IN_PROC_BROWSER_TEST_F(AppBackgroundPageApiTest,DISABLED_LacksPermission)247 IN_PROC_BROWSER_TEST_F(AppBackgroundPageApiTest, DISABLED_LacksPermission) {
248   host_resolver()->AddRule("a.com", "127.0.0.1");
249   ASSERT_TRUE(StartEmbeddedTestServer());
250 
251   std::string app_manifest = base::StringPrintf(
252       "{"
253       "  \"name\": \"App\","
254       "  \"version\": \"0.1\","
255       "  \"manifest_version\": 2,"
256       "  \"app\": {"
257       "    \"urls\": ["
258       "      \"http://a.com/\""
259       "    ],"
260       "    \"launch\": {"
261       "      \"web_url\": \"http://a.com:%d/\""
262       "    }"
263       "  }"
264       "}",
265       embedded_test_server()->port());
266 
267   base::FilePath app_dir;
268   ASSERT_TRUE(CreateApp(app_manifest, &app_dir));
269   ASSERT_TRUE(LoadExtension(app_dir));
270   ASSERT_TRUE(RunExtensionTest("app_background_page/lacks_permission"))
271       << message_;
272   ASSERT_TRUE(WaitForBackgroundMode(false));
273 }
274 
IN_PROC_BROWSER_TEST_F(AppBackgroundPageApiTest,ManifestBackgroundPage)275 IN_PROC_BROWSER_TEST_F(AppBackgroundPageApiTest, ManifestBackgroundPage) {
276   host_resolver()->AddRule("a.com", "127.0.0.1");
277   ASSERT_TRUE(StartEmbeddedTestServer());
278 
279   std::string app_manifest = base::StringPrintf(
280       "{"
281       "  \"name\": \"App\","
282       "  \"version\": \"0.1\","
283       "  \"manifest_version\": 2,"
284       "  \"app\": {"
285       "    \"urls\": ["
286       "      \"http://a.com/\""
287       "    ],"
288       "    \"launch\": {"
289       "      \"web_url\": \"http://a.com:%d/\""
290       "    }"
291       "  },"
292       "  \"permissions\": [\"background\"],"
293       "  \"background\": {"
294       "    \"page\": \"http://a.com:%d/test.html\""
295       "  }"
296       "}",
297       embedded_test_server()->port(),
298       embedded_test_server()->port());
299 
300   base::FilePath app_dir;
301   ASSERT_TRUE(CreateApp(app_manifest, &app_dir));
302   // Background mode should not be active now because no background app was
303   // loaded.
304   ASSERT_TRUE(LoadExtension(app_dir));
305   // Background mode be active now because a background page was created when
306   // the app was loaded.
307   ASSERT_TRUE(WaitForBackgroundMode(true));
308 
309   const Extension* extension = GetSingleLoadedExtension();
310   ASSERT_TRUE(
311       BackgroundContentsServiceFactory::GetForProfile(browser()->profile())->
312           GetAppBackgroundContents(ASCIIToUTF16(extension->id())));
313   UnloadExtension(extension->id());
314 }
315 
IN_PROC_BROWSER_TEST_F(AppBackgroundPageApiTest,NoJsBackgroundPage)316 IN_PROC_BROWSER_TEST_F(AppBackgroundPageApiTest, NoJsBackgroundPage) {
317   // Keep the task manager up through this test to verify that a crash doesn't
318   // happen when window.open creates a background page that switches
319   // RenderViewHosts. See http://crbug.com/165138.
320   chrome::ShowTaskManager(browser());
321 
322   // Make sure that no BackgroundContentses get deleted (a signal that repeated
323   // window.open calls recreate instances, instead of being no-ops).
324   content::TestNotificationTracker background_deleted_tracker;
325   background_deleted_tracker.ListenFor(
326       chrome::NOTIFICATION_BACKGROUND_CONTENTS_DELETED,
327       content::Source<Profile>(browser()->profile()));
328 
329   host_resolver()->AddRule("a.com", "127.0.0.1");
330   ASSERT_TRUE(StartEmbeddedTestServer());
331 
332   std::string app_manifest = base::StringPrintf(
333       "{"
334       "  \"name\": \"App\","
335       "  \"version\": \"0.1\","
336       "  \"manifest_version\": 2,"
337       "  \"app\": {"
338       "    \"urls\": ["
339       "      \"http://a.com/\""
340       "    ],"
341       "    \"launch\": {"
342       "      \"web_url\": \"http://a.com:%d/test.html\""
343       "    }"
344       "  },"
345       "  \"permissions\": [\"background\"],"
346       "  \"background\": {"
347       "    \"allow_js_access\": false"
348       "  }"
349       "}",
350       embedded_test_server()->port());
351 
352   base::FilePath app_dir;
353   ASSERT_TRUE(CreateApp(app_manifest, &app_dir));
354   ASSERT_TRUE(LoadExtension(app_dir));
355 
356   // There isn't a background page loaded initially.
357   const Extension* extension = GetSingleLoadedExtension();
358   ASSERT_FALSE(
359       BackgroundContentsServiceFactory::GetForProfile(browser()->profile())->
360           GetAppBackgroundContents(ASCIIToUTF16(extension->id())));
361   // The test makes sure that window.open returns null.
362   ASSERT_TRUE(RunExtensionTest("app_background_page/no_js")) << message_;
363   // And after it runs there should be a background page.
364   ASSERT_TRUE(
365       BackgroundContentsServiceFactory::GetForProfile(browser()->profile())->
366           GetAppBackgroundContents(ASCIIToUTF16(extension->id())));
367 
368   EXPECT_EQ(0u, background_deleted_tracker.size());
369   UnloadExtension(extension->id());
370 }
371 
IN_PROC_BROWSER_TEST_F(AppBackgroundPageApiTest,NoJsManifestBackgroundPage)372 IN_PROC_BROWSER_TEST_F(AppBackgroundPageApiTest, NoJsManifestBackgroundPage) {
373   host_resolver()->AddRule("a.com", "127.0.0.1");
374   ASSERT_TRUE(StartEmbeddedTestServer());
375 
376   std::string app_manifest = base::StringPrintf(
377       "{"
378       "  \"name\": \"App\","
379       "  \"version\": \"0.1\","
380       "  \"manifest_version\": 2,"
381       "  \"app\": {"
382       "    \"urls\": ["
383       "      \"http://a.com/\""
384       "    ],"
385       "    \"launch\": {"
386       "      \"web_url\": \"http://a.com:%d/\""
387       "    }"
388       "  },"
389       "  \"permissions\": [\"background\"],"
390       "  \"background\": {"
391       "    \"page\": \"http://a.com:%d/bg.html\","
392       "    \"allow_js_access\": false"
393       "  }"
394       "}",
395       embedded_test_server()->port(),
396       embedded_test_server()->port());
397 
398   base::FilePath app_dir;
399   ASSERT_TRUE(CreateApp(app_manifest, &app_dir));
400   ASSERT_TRUE(LoadExtension(app_dir));
401 
402   // The background page should load, but window.open should return null.
403   const Extension* extension = GetSingleLoadedExtension();
404   ASSERT_TRUE(
405       BackgroundContentsServiceFactory::GetForProfile(browser()->profile())->
406           GetAppBackgroundContents(ASCIIToUTF16(extension->id())));
407   ASSERT_TRUE(RunExtensionTest("app_background_page/no_js_manifest")) <<
408       message_;
409   UnloadExtension(extension->id());
410 }
411 
IN_PROC_BROWSER_TEST_F(AppBackgroundPageApiTest,OpenTwoBackgroundPages)412 IN_PROC_BROWSER_TEST_F(AppBackgroundPageApiTest, OpenTwoBackgroundPages) {
413   host_resolver()->AddRule("a.com", "127.0.0.1");
414   ASSERT_TRUE(StartEmbeddedTestServer());
415 
416   std::string app_manifest = base::StringPrintf(
417       "{"
418       "  \"name\": \"App\","
419       "  \"version\": \"0.1\","
420       "  \"manifest_version\": 2,"
421       "  \"app\": {"
422       "    \"urls\": ["
423       "      \"http://a.com/\""
424       "    ],"
425       "    \"launch\": {"
426       "      \"web_url\": \"http://a.com:%d/\""
427       "    }"
428       "  },"
429       "  \"permissions\": [\"background\"]"
430       "}",
431       embedded_test_server()->port());
432 
433   base::FilePath app_dir;
434   ASSERT_TRUE(CreateApp(app_manifest, &app_dir));
435   ASSERT_TRUE(LoadExtension(app_dir));
436   const Extension* extension = GetSingleLoadedExtension();
437   ASSERT_TRUE(RunExtensionTest("app_background_page/two_pages")) << message_;
438   UnloadExtension(extension->id());
439 }
440 
IN_PROC_BROWSER_TEST_F(AppBackgroundPageApiTest,OpenTwoPagesWithManifest)441 IN_PROC_BROWSER_TEST_F(AppBackgroundPageApiTest, OpenTwoPagesWithManifest) {
442   host_resolver()->AddRule("a.com", "127.0.0.1");
443   ASSERT_TRUE(StartEmbeddedTestServer());
444 
445   std::string app_manifest = base::StringPrintf(
446       "{"
447       "  \"name\": \"App\","
448       "  \"version\": \"0.1\","
449       "  \"manifest_version\": 2,"
450       "  \"app\": {"
451       "    \"urls\": ["
452       "      \"http://a.com/\""
453       "    ],"
454       "    \"launch\": {"
455       "      \"web_url\": \"http://a.com:%d/\""
456       "    }"
457       "  },"
458       "  \"background\": {"
459       "    \"page\": \"http://a.com:%d/bg.html\""
460       "  },"
461       "  \"permissions\": [\"background\"]"
462       "}",
463       embedded_test_server()->port(),
464       embedded_test_server()->port());
465 
466   base::FilePath app_dir;
467   ASSERT_TRUE(CreateApp(app_manifest, &app_dir));
468   ASSERT_TRUE(LoadExtension(app_dir));
469   const Extension* extension = GetSingleLoadedExtension();
470   ASSERT_TRUE(RunExtensionTest("app_background_page/two_with_manifest")) <<
471       message_;
472   UnloadExtension(extension->id());
473 }
474 
475 // Times out occasionally -- see crbug.com/108493
IN_PROC_BROWSER_TEST_F(AppBackgroundPageApiTest,DISABLED_OpenPopupFromBGPage)476 IN_PROC_BROWSER_TEST_F(AppBackgroundPageApiTest, DISABLED_OpenPopupFromBGPage) {
477   host_resolver()->AddRule("a.com", "127.0.0.1");
478   ASSERT_TRUE(StartEmbeddedTestServer());
479 
480   std::string app_manifest = base::StringPrintf(
481       "{"
482       "  \"name\": \"App\","
483       "  \"version\": \"0.1\","
484       "  \"manifest_version\": 2,"
485       "  \"app\": {"
486       "    \"urls\": ["
487       "      \"http://a.com/\""
488       "    ],"
489       "    \"launch\": {"
490       "      \"web_url\": \"http://a.com:%d/\""
491       "    }"
492       "  },"
493       "  \"background\": { \"page\": \"http://a.com:%d/extensions/api_test/"
494       "app_background_page/bg_open/bg_open_bg.html\" },"
495       "  \"permissions\": [\"background\"]"
496       "}",
497       embedded_test_server()->port(),
498       embedded_test_server()->port());
499 
500   base::FilePath app_dir;
501   ASSERT_TRUE(CreateApp(app_manifest, &app_dir));
502   ASSERT_TRUE(LoadExtension(app_dir));
503   ASSERT_TRUE(RunExtensionTest("app_background_page/bg_open")) << message_;
504 }
505 
IN_PROC_BROWSER_TEST_F(AppBackgroundPageApiTest,DISABLED_OpenThenClose)506 IN_PROC_BROWSER_TEST_F(AppBackgroundPageApiTest, DISABLED_OpenThenClose) {
507   host_resolver()->AddRule("a.com", "127.0.0.1");
508   ASSERT_TRUE(StartEmbeddedTestServer());
509 
510   std::string app_manifest = base::StringPrintf(
511       "{"
512       "  \"name\": \"App\","
513       "  \"version\": \"0.1\","
514       "  \"manifest_version\": 2,"
515       "  \"app\": {"
516       "    \"urls\": ["
517       "      \"http://a.com/\""
518       "    ],"
519       "    \"launch\": {"
520       "      \"web_url\": \"http://a.com:%d/\""
521       "    }"
522       "  },"
523       "  \"permissions\": [\"background\"]"
524       "}",
525       embedded_test_server()->port());
526 
527   base::FilePath app_dir;
528   ASSERT_TRUE(CreateApp(app_manifest, &app_dir));
529   ASSERT_TRUE(LoadExtension(app_dir));
530   // There isn't a background page loaded initially.
531   const Extension* extension = GetSingleLoadedExtension();
532   ASSERT_FALSE(
533       BackgroundContentsServiceFactory::GetForProfile(browser()->profile())->
534           GetAppBackgroundContents(ASCIIToUTF16(extension->id())));
535   // Background mode should not be active until a background page is created.
536   ASSERT_TRUE(WaitForBackgroundMode(false));
537   ASSERT_TRUE(RunExtensionTest("app_background_page/basic_open")) << message_;
538   // Background mode should be active now because a background page was created.
539   ASSERT_TRUE(WaitForBackgroundMode(true));
540   ASSERT_TRUE(
541       BackgroundContentsServiceFactory::GetForProfile(browser()->profile())->
542           GetAppBackgroundContents(ASCIIToUTF16(extension->id())));
543   // Now close the BackgroundContents.
544   ASSERT_TRUE(RunExtensionTest("app_background_page/basic_close")) << message_;
545   // Background mode should no longer be active.
546   ASSERT_TRUE(WaitForBackgroundMode(false));
547   ASSERT_FALSE(
548       BackgroundContentsServiceFactory::GetForProfile(browser()->profile())->
549           GetAppBackgroundContents(ASCIIToUTF16(extension->id())));
550 }
551 
IN_PROC_BROWSER_TEST_F(AppBackgroundPageApiTest,UnloadExtensionWhileHidden)552 IN_PROC_BROWSER_TEST_F(AppBackgroundPageApiTest, UnloadExtensionWhileHidden) {
553   host_resolver()->AddRule("a.com", "127.0.0.1");
554   ASSERT_TRUE(StartEmbeddedTestServer());
555 
556   std::string app_manifest = base::StringPrintf(
557       "{"
558       "  \"name\": \"App\","
559       "  \"version\": \"0.1\","
560       "  \"manifest_version\": 2,"
561       "  \"app\": {"
562       "    \"urls\": ["
563       "      \"http://a.com/\""
564       "    ],"
565       "    \"launch\": {"
566       "      \"web_url\": \"http://a.com:%d/\""
567       "    }"
568       "  },"
569       "  \"permissions\": [\"background\"],"
570       "  \"background\": {"
571       "    \"page\": \"http://a.com:%d/test.html\""
572       "  }"
573       "}",
574       embedded_test_server()->port(),
575       embedded_test_server()->port());
576 
577   base::FilePath app_dir;
578   ASSERT_TRUE(CreateApp(app_manifest, &app_dir));
579   // Background mode should not be active now because no background app was
580   // loaded.
581   ASSERT_TRUE(LoadExtension(app_dir));
582   // Background mode be active now because a background page was created when
583   // the app was loaded.
584   ASSERT_TRUE(WaitForBackgroundMode(true));
585 
586   const Extension* extension = GetSingleLoadedExtension();
587   ASSERT_TRUE(
588       BackgroundContentsServiceFactory::GetForProfile(browser()->profile())->
589           GetAppBackgroundContents(ASCIIToUTF16(extension->id())));
590 
591   // Close all browsers - app should continue running.
592   set_exit_when_last_browser_closes(false);
593   CloseBrowser(browser());
594 
595   // Post a task to unload the extension - this should cause Chrome to exit
596   // cleanly (not crash).
597   UnloadExtensionViaTask(extension->id());
598   content::RunAllPendingInMessageLoop();
599   ASSERT_TRUE(WaitForBackgroundMode(false));
600 }
601 
602 // Verify active NaCl embeds cause many keepalive impulses to be sent.
603 // Disabled on Windows due to flakiness: http://crbug.com/346278
604 #if defined(OS_WIN)
605 #define MAYBE_BackgroundKeepaliveActive DISABLED_BackgroundKeepaliveActive
606 #else
607 #define MAYBE_BackgroundKeepaliveActive BackgroundKeepaliveActive
608 #endif
IN_PROC_BROWSER_TEST_F(AppBackgroundPageNaClTest,MAYBE_BackgroundKeepaliveActive)609 IN_PROC_BROWSER_TEST_F(AppBackgroundPageNaClTest,
610                        MAYBE_BackgroundKeepaliveActive) {
611 #if !defined(DISABLE_NACL)
612   ExtensionTestMessageListener nacl_modules_loaded("nacl_modules_loaded", true);
613   LaunchTestingApp();
614   extensions::ProcessManager* manager =
615     extensions::ExtensionSystem::Get(browser()->profile())->process_manager();
616   ImpulseCallbackCounter active_impulse_counter(manager, extension()->id());
617   EXPECT_TRUE(nacl_modules_loaded.WaitUntilSatisfied());
618 
619   // Target .5 seconds: .5 seconds / 50ms throttle * 2 embeds == 20 impulses.
620   manager->SetKeepaliveImpulseCallbackForTesting(
621       active_impulse_counter.SetGoalAndGetCallback(20));
622   active_impulse_counter.Wait();
623 #endif
624 }
625 
626 // Verify that nacl modules that go idle will not send keepalive impulses.
627 // Disabled on windows due to Win XP failures:
628 // DesktopWindowTreeHostWin::HandleCreate not implemented. crbug.com/331954
629 #if defined(OS_WIN)
630 #define MAYBE_BackgroundKeepaliveIdle DISABLED_BackgroundKeepaliveIdle
631 #else
632 // ASAN errors appearing: https://crbug.com/332440
633 #define MAYBE_BackgroundKeepaliveIdle DISABLED_BackgroundKeepaliveIdle
634 #endif
IN_PROC_BROWSER_TEST_F(AppBackgroundPageNaClTest,MAYBE_BackgroundKeepaliveIdle)635 IN_PROC_BROWSER_TEST_F(AppBackgroundPageNaClTest,
636                        MAYBE_BackgroundKeepaliveIdle) {
637 #if !defined(DISABLE_NACL)
638   ExtensionTestMessageListener nacl_modules_loaded("nacl_modules_loaded", true);
639   LaunchTestingApp();
640   extensions::ProcessManager* manager =
641     extensions::ExtensionSystem::Get(browser()->profile())->process_manager();
642   ImpulseCallbackCounter idle_impulse_counter(manager, extension()->id());
643   EXPECT_TRUE(nacl_modules_loaded.WaitUntilSatisfied());
644 
645   manager->SetKeepaliveImpulseDecrementCallbackForTesting(
646       idle_impulse_counter.SetGoalAndGetCallback(1));
647   nacl_modules_loaded.Reply("be idle");
648   idle_impulse_counter.Wait();
649 #endif
650 }
651 
652