summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--chrome/browser/background_contents_service.cc256
-rw-r--r--chrome/browser/background_contents_service.h113
-rw-r--r--chrome/browser/background_contents_service_unittest.cc238
-rw-r--r--chrome/browser/browser_init.cc2
-rw-r--r--chrome/browser/browser_prefs.cc2
-rw-r--r--chrome/browser/browser_process_impl.cc6
-rw-r--r--chrome/browser/extensions/extensions_ui.cc19
-rw-r--r--chrome/browser/extensions/extensions_ui.h3
-rw-r--r--chrome/browser/profile.cc17
-rw-r--r--chrome/browser/profile.h6
-rw-r--r--chrome/browser/tab_contents/background_contents.cc46
-rw-r--r--chrome/browser/tab_contents/background_contents.h18
-rw-r--r--chrome/browser/tab_contents/render_view_host_delegate_helper.cc64
-rw-r--r--chrome/browser/tab_contents/render_view_host_delegate_helper.h11
-rwxr-xr-xchrome/chrome_browser.gypi2
-rwxr-xr-xchrome/chrome_tests.gypi1
-rw-r--r--chrome/common/chrome_switches.cc7
-rw-r--r--chrome/common/chrome_switches.h2
-rw-r--r--chrome/common/notification_type.h15
-rw-r--r--chrome/common/pref_names.cc5
-rw-r--r--chrome/common/pref_names.h2
-rw-r--r--chrome/test/testing_browser_process.h11
-rw-r--r--chrome/test/testing_profile.h3
23 files changed, 786 insertions, 63 deletions
diff --git a/chrome/browser/background_contents_service.cc b/chrome/browser/background_contents_service.cc
new file mode 100644
index 0000000..685b12b
--- /dev/null
+++ b/chrome/browser/background_contents_service.cc
@@ -0,0 +1,256 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/background_contents_service.h"
+
+#include "base/basictypes.h"
+#include "base/command_line.h"
+#include "base/string_util.h"
+#include "base/utf_string_conversions.h"
+#include "base/values.h"
+#include "chrome/browser/browser_process.h"
+#include "chrome/browser/pref_service.h"
+#include "chrome/browser/profile.h"
+#include "chrome/browser/tab_contents/background_contents.h"
+#include "chrome/common/chrome_switches.h"
+#include "chrome/common/extensions/extension.h"
+#include "chrome/common/notification_service.h"
+#include "chrome/common/notification_type.h"
+#include "chrome/common/pref_names.h"
+
+// Keys for the information we store about individual BackgroundContents in
+// prefs. There is one top-level DictionaryValue (stored at
+// prefs::kRegisteredBackgroundContents). Information about each
+// BackgroundContents is stored under that top-level DictionaryValue, keyed
+// by the parent application ID for easy lookup.
+//
+// kRegisteredBackgroundContents:
+// DictionaryValue {
+// <appid_1>: { "url": <url1>, "name": <frame_name> },
+// <appid_2>: { "url": <url2>, "name": <frame_name> },
+// ... etc ...
+// }
+const wchar_t kUrlKey[] = L"url";
+const wchar_t kFrameNameKey[] = L"name";
+
+BackgroundContentsService::BackgroundContentsService(
+ Profile* profile, const CommandLine* command_line)
+ : prefs_(NULL) {
+ // Don't load/store preferences if the proper switch is not enabled, or if
+ // the parent profile is off the record.
+ if (!profile->IsOffTheRecord() &&
+ command_line->HasSwitch(switches::kRestoreBackgroundContents))
+ prefs_ = profile->GetPrefs();
+
+ // Listen for events to tell us when to load/unload persisted background
+ // contents.
+ StartObserving(profile);
+}
+
+BackgroundContentsService::~BackgroundContentsService() {
+ // BackgroundContents should be shutdown before we go away, as otherwise
+ // our browser process refcount will be off.
+ DCHECK(contents_map_.empty());
+}
+
+void BackgroundContentsService::StartObserving(Profile* profile) {
+ // On startup, load our background pages after extension-apps have loaded.
+ registrar_.Add(this, NotificationType::EXTENSIONS_READY,
+ Source<Profile>(profile));
+
+ // Track the lifecycle of all BackgroundContents in the system to allow us
+ // to store an up-to-date list of the urls. Start tracking contents when they
+ // have been opened, and stop tracking them when they are closed by script.
+ registrar_.Add(this, NotificationType::BACKGROUND_CONTENTS_OPENED,
+ Source<Profile>(profile));
+ registrar_.Add(this, NotificationType::BACKGROUND_CONTENTS_CLOSED,
+ Source<Profile>(profile));
+
+ // Stop tracking BackgroundContents when they have been deleted (happens
+ // during shutdown or if the render process dies).
+ registrar_.Add(this, NotificationType::BACKGROUND_CONTENTS_DELETED,
+ Source<Profile>(profile));
+ // Track when the BackgroundContents navigates to a new URL so we can update
+ // our persisted information as appropriate.
+ registrar_.Add(this, NotificationType::BACKGROUND_CONTENTS_NAVIGATED,
+ Source<Profile>(profile));
+
+ // Listen for extensions to be unloaded so we can shutdown associated
+ // BackgroundContents.
+ registrar_.Add(this, NotificationType::EXTENSION_UNLOADED,
+ Source<Profile>(profile));
+}
+
+void BackgroundContentsService::Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details) {
+ switch (type.value) {
+ case NotificationType::EXTENSIONS_READY:
+ LoadBackgroundContentsFromPrefs();
+ break;
+ case NotificationType::BACKGROUND_CONTENTS_DELETED:
+ BackgroundContentsShutdown(Details<BackgroundContents>(details).ptr());
+ break;
+ case NotificationType::BACKGROUND_CONTENTS_OPENED:
+ BackgroundContentsOpened(
+ Details<BackgroundContentsOpenedDetails>(details).ptr());
+ break;
+ case NotificationType::BACKGROUND_CONTENTS_CLOSED:
+ DCHECK(IsTracked(Details<BackgroundContents>(details).ptr()));
+ UnregisterBackgroundContents(Details<BackgroundContents>(details).ptr());
+ break;
+ case NotificationType::BACKGROUND_CONTENTS_NAVIGATED:
+ DCHECK(IsTracked(Details<BackgroundContents>(details).ptr()));
+ RegisterBackgroundContents(Details<BackgroundContents>(details).ptr());
+ break;
+ case NotificationType::EXTENSION_UNLOADED:
+ ShutdownAssociatedBackgroundContents(
+ ASCIIToUTF16(Details<Extension>(details)->id()));
+ break;
+ default:
+ NOTREACHED();
+ break;
+ }
+}
+
+// Loads all background contents whose urls have been stored in prefs.
+void BackgroundContentsService::LoadBackgroundContentsFromPrefs() {
+ if (!prefs_)
+ return;
+ DLOG(INFO) << "Starting to load background contents";
+ const DictionaryValue* contents =
+ prefs_->GetDictionary(prefs::kRegisteredBackgroundContents);
+ if (!contents)
+ return;
+ DLOG(INFO) << "Loading " << contents->size() << " background contents";
+ for (DictionaryValue::key_iterator it = contents->begin_keys();
+ it != contents->end_keys(); ++it) {
+ DictionaryValue* dict;
+ contents->GetDictionaryWithoutPathExpansion(*it, &dict);
+ string16 frame_name;
+ std::string url;
+ dict->GetString(kUrlKey, &url);
+ dict->GetStringAsUTF16(kFrameNameKey, &frame_name);
+ CreateBackgroundContents(GURL(url),
+ frame_name,
+ WideToUTF16(*it));
+ }
+}
+
+void BackgroundContentsService::CreateBackgroundContents(
+ const GURL& url,
+ const string16& frame_name,
+ const string16& application_id) {
+ // We are depending on the fact that we will initialize before any user
+ // actions or session restore can take place, so no BackgroundContents should
+ // be running yet for the passed application_id.
+ DCHECK(!GetAppBackgroundContents(application_id));
+ DCHECK(url.is_valid());
+ // TODO(atwilson): Fire up renderer and load BackgroundContents for this url,
+ // and set its initial url in the contents_map.
+ DLOG(INFO) << "Loading background content url: " << url;
+}
+
+void BackgroundContentsService::RegisterBackgroundContents(
+ BackgroundContents* background_contents) {
+ DCHECK(IsTracked(background_contents));
+ if (!prefs_)
+ return;
+
+ // We store the first URL we receive for a given application. If there's
+ // already an entry for this application, no need to do anything.
+ DictionaryValue* pref = prefs_->GetMutableDictionary(
+ prefs::kRegisteredBackgroundContents);
+ const string16& appid = GetParentApplicationId(background_contents);
+ DictionaryValue* current;
+ if (pref->GetDictionaryWithoutPathExpansion(UTF16ToWide(appid), &current))
+ return;
+
+ // No entry for this application yet, so add one.
+ DictionaryValue* dict = new DictionaryValue();
+ dict->SetString(kUrlKey, background_contents->GetURL().spec());
+ dict->SetStringFromUTF16(kFrameNameKey, contents_map_[appid].frame_name);
+ pref->SetWithoutPathExpansion(UTF16ToWide(appid), dict);
+ prefs_->ScheduleSavePersistentPrefs();
+}
+
+void BackgroundContentsService::UnregisterBackgroundContents(
+ BackgroundContents* background_contents) {
+ if (!prefs_)
+ return;
+ DCHECK(IsTracked(background_contents));
+ const string16 appid = GetParentApplicationId(background_contents);
+ DictionaryValue* pref = prefs_->GetMutableDictionary(
+ prefs::kRegisteredBackgroundContents);
+ pref->RemoveWithoutPathExpansion(UTF16ToWide(appid), NULL);
+ prefs_->ScheduleSavePersistentPrefs();
+}
+
+void BackgroundContentsService::ShutdownAssociatedBackgroundContents(
+ const string16& appid) {
+ BackgroundContents* contents = GetAppBackgroundContents(appid);
+ if (contents) {
+ UnregisterBackgroundContents(contents);
+ // Background contents destructor shuts down the renderer.
+ delete contents;
+ }
+}
+
+void BackgroundContentsService::BackgroundContentsOpened(
+ BackgroundContentsOpenedDetails* details) {
+ // If this is the first BackgroundContents loaded, kick ourselves into
+ // persistent mode.
+ // TODO(atwilson): Enable this when we support running with no active windows
+ // on all platforms (http://crbug.com/45275).
+ // if (contents_map_.empty())
+ // g_browser_process->AddRefModule();
+
+ // Add the passed object to our list. Should not already be tracked.
+ DCHECK(!IsTracked(details->contents));
+ DCHECK(!details->application_id.empty());
+ contents_map_[details->application_id].contents = details->contents;
+ contents_map_[details->application_id].frame_name = details->frame_name;
+}
+
+// Used by test code and debug checks to verify whether a given
+// BackgroundContents is being tracked by this instance.
+bool BackgroundContentsService::IsTracked(
+ BackgroundContents* background_contents) const {
+ return !GetParentApplicationId(background_contents).empty();
+}
+
+void BackgroundContentsService::BackgroundContentsShutdown(
+ BackgroundContents* background_contents) {
+ // Remove the passed object from our list.
+ DCHECK(IsTracked(background_contents));
+ string16 appid = GetParentApplicationId(background_contents);
+ contents_map_.erase(appid);
+ // If we have no more BackgroundContents active, then stop keeping the browser
+ // process alive.
+ // TODO(atwilson): Enable this when we support running with no active windows
+ // on all platforms (http://crbug.com/45275).
+ // if (contents_map_.empty())
+ // g_browser_process->ReleaseModule();
+}
+
+BackgroundContents* BackgroundContentsService::GetAppBackgroundContents(
+ const string16& application_id) {
+ BackgroundContentsMap::const_iterator it = contents_map_.find(application_id);
+ return (it != contents_map_.end()) ? it->second.contents : NULL;
+}
+
+const string16& BackgroundContentsService::GetParentApplicationId(
+ BackgroundContents* contents) const {
+ for (BackgroundContentsMap::const_iterator it = contents_map_.begin();
+ it != contents_map_.end(); ++it) {
+ if (contents == it->second.contents)
+ return it->first;
+ }
+ return EmptyString16();
+}
+
+// static
+void BackgroundContentsService::RegisterUserPrefs(PrefService* prefs) {
+ prefs->RegisterDictionaryPref(prefs::kRegisteredBackgroundContents);
+}
diff --git a/chrome/browser/background_contents_service.h b/chrome/browser/background_contents_service.h
new file mode 100644
index 0000000..d9e9e67
--- /dev/null
+++ b/chrome/browser/background_contents_service.h
@@ -0,0 +1,113 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_BACKGROUND_CONTENTS_SERVICE_H_
+#define CHROME_BROWSER_BACKGROUND_CONTENTS_SERVICE_H_
+
+#include <map>
+
+#include "chrome/common/notification_observer.h"
+#include "chrome/common/notification_registrar.h"
+#include "googleurl/src/gurl.h"
+#include "testing/gtest/include/gtest/gtest_prod.h"
+
+class BackgroundContents;
+class CommandLine;
+class PrefService;
+class Profile;
+struct BackgroundContentsOpenedDetails;
+
+// BackgroundContentsService is owned by the profile, and is responsible for
+// managing the lifetime of BackgroundContents (tracking the set of background
+// urls, loading them at startup, and keeping the browser process alive as long
+// as there are BackgroundContents loaded).
+//
+// It is also responsible for tracking the association between
+// BackgroundContents and their parent app, and shutting them down when the
+// parent app is unloaded.
+class BackgroundContentsService : private NotificationObserver {
+ public:
+ BackgroundContentsService(Profile* profile, const CommandLine* command_line);
+ virtual ~BackgroundContentsService();
+
+ // Returns the BackgroundContents associated with the passed application id,
+ // or NULL if none.
+ BackgroundContents* GetAppBackgroundContents(const string16& appid);
+
+ static void RegisterUserPrefs(PrefService* prefs);
+
+ private:
+ friend class BackgroundContentsServiceTest;
+ FRIEND_TEST(BackgroundContentsServiceTest, BackgroundContentsCreateDestroy);
+ FRIEND_TEST(BackgroundContentsServiceTest, TestApplicationIDLinkage);
+
+ // Registers for various notifications.
+ void StartObserving(Profile* profile);
+
+ // NotificationObserver implementation.
+ virtual void Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details);
+
+ // Loads all registered BackgroundContents at startup.
+ void LoadBackgroundContentsFromPrefs();
+
+ // Creates a single BackgroundContents associated with the specified |appid|.
+ // The BackgroundContents frame will be given the name specified by
+ // |frame_name| and navigated to the passed URL.
+ void CreateBackgroundContents(const GURL& url,
+ const string16& frame_name,
+ const string16& appid);
+
+ // Invoked when a new BackgroundContents is opened.
+ void BackgroundContentsOpened(BackgroundContentsOpenedDetails* details);
+
+ // Invoked when a BackgroundContents object is destroyed.
+ void BackgroundContentsShutdown(BackgroundContents* contents);
+
+ // Registers the |contents->GetURL()| to be run at startup. Only happens for
+ // the first navigation after window.open() (future calls to
+ // RegisterBackgroundContents() for the same BackgroundContents will do
+ // nothing).
+ void RegisterBackgroundContents(BackgroundContents* contents);
+
+ // Stops loading the passed BackgroundContents on startup.
+ void UnregisterBackgroundContents(BackgroundContents* contents);
+
+ // Unregisters and deletes the BackgroundContents associated with the
+ // passed extension.
+ void ShutdownAssociatedBackgroundContents(const string16& appid);
+
+ // Returns true if this BackgroundContents is in the contents_list_.
+ bool IsTracked(BackgroundContents* contents) const;
+
+ // Gets the parent application id for the passed BackgroundContents. Returns
+ // an empty string if no parent application found (e.g. passed
+ // BackgroundContents has already shut down).
+ const string16& GetParentApplicationId(BackgroundContents* contents) const;
+
+ // PrefService used to store list of background pages (or NULL if this is
+ // running under an off-the-record profile).
+ PrefService* prefs_;
+ NotificationRegistrar registrar_;
+
+ // Information we track about each BackgroundContents.
+ struct BackgroundContentsInfo {
+ // The BackgroundContents whose information we are tracking.
+ BackgroundContents* contents;
+ // The name of the top level frame for this BackgroundContents.
+ string16 frame_name;
+ };
+
+ // Map associating currently loaded BackgroundContents with their parent
+ // applications.
+ // Key: application id
+ // Value: BackgroundContentsInfo for the BC associated with that application
+ typedef std::map<string16, BackgroundContentsInfo> BackgroundContentsMap;
+ BackgroundContentsMap contents_map_;
+
+ DISALLOW_COPY_AND_ASSIGN(BackgroundContentsService);
+};
+
+#endif // CHROME_BROWSER_BACKGROUND_CONTENTS_SERVICE_H_
diff --git a/chrome/browser/background_contents_service_unittest.cc b/chrome/browser/background_contents_service_unittest.cc
new file mode 100644
index 0000000..8e4394e
--- /dev/null
+++ b/chrome/browser/background_contents_service_unittest.cc
@@ -0,0 +1,238 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+
+#include "base/basictypes.h"
+#include "base/command_line.h"
+#include "base/scoped_ptr.h"
+#include "base/utf_string_conversions.h"
+#include "chrome/browser/background_contents_service.h"
+#include "chrome/browser/pref_service.h"
+#include "chrome/browser/tab_contents/background_contents.h"
+#include "chrome/common/chrome_switches.h"
+#include "chrome/common/pref_names.h"
+#include "chrome/test/testing_browser_process.h"
+#include "chrome/test/testing_profile.h"
+#include "googleurl/src/gurl.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/platform_test.h"
+
+class BackgroundContentsServiceTest : public testing::Test {
+ public:
+ BackgroundContentsServiceTest() {}
+ ~BackgroundContentsServiceTest() {}
+ void SetUp() {
+ command_line_.reset(new CommandLine(CommandLine::ARGUMENTS_ONLY));
+ command_line_->AppendSwitch(switches::kRestoreBackgroundContents);
+ }
+
+ DictionaryValue* GetPrefs(Profile* profile) {
+ return profile->GetPrefs()->GetMutableDictionary(
+ prefs::kRegisteredBackgroundContents);
+ }
+
+ // Returns the stored pref URL for the passed app id.
+ std::string GetPrefURLForApp(Profile* profile, const string16& appid) {
+ DictionaryValue* pref = GetPrefs(profile);
+ EXPECT_TRUE(pref->HasKey(UTF16ToWide(appid)));
+ DictionaryValue* value;
+ pref->GetDictionaryWithoutPathExpansion(UTF16ToWide(appid), &value);
+ std::string url;
+ value->GetString(L"url", &url);
+ return url;
+ }
+
+ scoped_ptr<CommandLine> command_line_;
+};
+
+class MockBackgroundContents : public BackgroundContents {
+ public:
+ explicit MockBackgroundContents(Profile* profile)
+ : appid_(ASCIIToUTF16("app_id")),
+ profile_(profile) {
+ }
+ MockBackgroundContents(Profile* profile, const std::string& id)
+ : appid_(ASCIIToUTF16(id)),
+ profile_(profile) {
+ }
+
+ void SendOpenedNotification() {
+ string16 frame_name = ASCIIToUTF16("background");
+ BackgroundContentsOpenedDetails details = {
+ this, frame_name, appid_ };
+ NotificationService::current()->Notify(
+ NotificationType::BACKGROUND_CONTENTS_OPENED,
+ Source<Profile>(profile_),
+ Details<BackgroundContentsOpenedDetails>(&details));
+ }
+
+ virtual const void Navigate(GURL url) {
+ url_ = url;
+ NotificationService::current()->Notify(
+ NotificationType::BACKGROUND_CONTENTS_NAVIGATED,
+ Source<Profile>(profile_),
+ Details<BackgroundContents>(this));
+ }
+ virtual const GURL& GetURL() const { return url_; }
+
+ void MockClose(Profile* profile) {
+ NotificationService::current()->Notify(
+ NotificationType::BACKGROUND_CONTENTS_CLOSED,
+ Source<Profile>(profile),
+ Details<BackgroundContents>(this));
+ delete this;
+ }
+
+ ~MockBackgroundContents() {
+ NotificationService::current()->Notify(
+ NotificationType::BACKGROUND_CONTENTS_DELETED,
+ Source<Profile>(profile_),
+ Details<BackgroundContents>(this));
+ }
+
+ const string16& appid() { return appid_; }
+
+ private:
+ GURL url_;
+
+ // The ID of our parent application
+ string16 appid_;
+
+ // Parent profile
+ Profile* profile_;
+};
+
+TEST_F(BackgroundContentsServiceTest, Create) {
+ // Check for creation and leaks.
+ TestingProfile profile;
+ BackgroundContentsService service(&profile, command_line_.get());
+}
+
+TEST_F(BackgroundContentsServiceTest, BackgroundContentsCreateDestroy) {
+ TestingProfile profile;
+ BackgroundContentsService service(&profile, command_line_.get());
+ // TODO(atwilson): Enable the refcount part of the test once we fix the
+ // APP_TERMINATING notification to be sent at the proper time.
+ // (http://crbug.com/45275).
+ //
+ // TestingBrowserProcess* process =
+ // static_cast<TestingBrowserProcess*>(g_browser_process);
+ // unsigned int starting_ref_count = process->module_ref_count();
+ MockBackgroundContents* contents = new MockBackgroundContents(&profile);
+ EXPECT_FALSE(service.IsTracked(contents));
+ contents->SendOpenedNotification();
+ // EXPECT_EQ(starting_ref_count+1, process->module_ref_count());
+ EXPECT_TRUE(service.IsTracked(contents));
+ delete contents;
+ // EXPECT_EQ(starting_ref_count, process->module_ref_count());
+ EXPECT_FALSE(service.IsTracked(contents));
+}
+
+TEST_F(BackgroundContentsServiceTest, BackgroundContentsUrlAdded) {
+ TestingProfile profile;
+ GetPrefs(&profile)->Clear();
+ BackgroundContentsService service(&profile, command_line_.get());
+ GURL orig_url;
+ GURL url("http://a/");
+ GURL url2("http://a/");
+ {
+ scoped_ptr<MockBackgroundContents> contents(
+ new MockBackgroundContents(&profile));
+ EXPECT_EQ(0U, GetPrefs(&profile)->size());
+ contents->SendOpenedNotification();
+
+ contents->Navigate(url);
+ EXPECT_EQ(1U, GetPrefs(&profile)->size());
+ EXPECT_EQ(url.spec(), GetPrefURLForApp(&profile, contents->appid()));
+
+ // Navigate the contents to a new url, should not change url.
+ contents->Navigate(url2);
+ EXPECT_EQ(1U, GetPrefs(&profile)->size());
+ EXPECT_EQ(url.spec(), GetPrefURLForApp(&profile, contents->appid()));
+
+ }
+ // Contents are deleted, url should persist.
+ EXPECT_EQ(1U, GetPrefs(&profile)->size());
+}
+
+TEST_F(BackgroundContentsServiceTest, BackgroundContentsUrlAddedAndClosed) {
+ TestingProfile profile;
+ GetPrefs(&profile)->Clear();
+ BackgroundContentsService service(&profile, command_line_.get());
+ GURL url("http://a/");
+ MockBackgroundContents* contents = new MockBackgroundContents(&profile);
+ EXPECT_EQ(0U, GetPrefs(&profile)->size());
+ contents->SendOpenedNotification();
+ contents->Navigate(url);
+ EXPECT_EQ(1U, GetPrefs(&profile)->size());
+ EXPECT_EQ(url.spec(), GetPrefURLForApp(&profile, contents->appid()));
+
+ // Fake a window closed by script.
+ contents->MockClose(&profile);
+ EXPECT_EQ(0U, GetPrefs(&profile)->size());
+}
+
+// Test what happens if a BackgroundContents shuts down (say, due to a renderer
+// crash) then is restarted. Should not persist URL twice.
+TEST_F(BackgroundContentsServiceTest, RestartBackgroundContents) {
+ TestingProfile profile;
+ GetPrefs(&profile)->Clear();
+ BackgroundContentsService service(&profile, command_line_.get());
+ GURL url("http://a/");
+ {
+ scoped_ptr<MockBackgroundContents> contents(new MockBackgroundContents(
+ &profile, "appid"));
+ contents->SendOpenedNotification();
+ contents->Navigate(url);
+ EXPECT_EQ(1U, GetPrefs(&profile)->size());
+ EXPECT_EQ(url.spec(), GetPrefURLForApp(&profile, contents->appid()));
+ }
+ // Contents deleted, url should be persisted.
+ EXPECT_EQ(1U, GetPrefs(&profile)->size());
+
+ {
+ // Reopen the BackgroundContents to the same URL, we should not register the
+ // URL again.
+ scoped_ptr<MockBackgroundContents> contents(new MockBackgroundContents(
+ &profile, "appid"));
+ contents->SendOpenedNotification();
+ contents->Navigate(url);
+ EXPECT_EQ(1U, GetPrefs(&profile)->size());
+ }
+}
+
+// Ensures that BackgroundContentsService properly tracks the association
+// between a BackgroundContents and its parent extension, including
+// unregistering the BC when the extension is uninstalled.
+TEST_F(BackgroundContentsServiceTest, TestApplicationIDLinkage) {
+ TestingProfile profile;
+ BackgroundContentsService service(&profile, command_line_.get());
+ GetPrefs(&profile)->Clear();
+
+ EXPECT_EQ(NULL, service.GetAppBackgroundContents(ASCIIToUTF16("appid")));
+ MockBackgroundContents* contents = new MockBackgroundContents(&profile,
+ "appid");
+ scoped_ptr<MockBackgroundContents> contents2(
+ new MockBackgroundContents(&profile, "appid2"));
+ contents->SendOpenedNotification();
+ EXPECT_EQ(contents, service.GetAppBackgroundContents(contents->appid()));
+ contents2->SendOpenedNotification();
+ EXPECT_EQ(contents2.get(), service.GetAppBackgroundContents(
+ contents2->appid()));
+ EXPECT_EQ(0U, GetPrefs(&profile)->size());
+
+ // Navigate the contents, then make sure the one associated with the extension
+ // is unregistered.
+ GURL url("http://a/");
+ GURL url2("http://b/");
+ contents->Navigate(url);
+ EXPECT_EQ(1U, GetPrefs(&profile)->size());
+ contents2->Navigate(url2);
+ EXPECT_EQ(2U, GetPrefs(&profile)->size());
+ service.ShutdownAssociatedBackgroundContents(ASCIIToUTF16("appid"));
+ EXPECT_FALSE(service.IsTracked(contents));
+ EXPECT_EQ(NULL, service.GetAppBackgroundContents(ASCIIToUTF16("appid")));
+ EXPECT_EQ(1U, GetPrefs(&profile)->size());
+ EXPECT_EQ(url2.spec(), GetPrefURLForApp(&profile, contents2->appid()));
+}
diff --git a/chrome/browser/browser_init.cc b/chrome/browser/browser_init.cc
index a38224f..63b6d32 100644
--- a/chrome/browser/browser_init.cc
+++ b/chrome/browser/browser_init.cc
@@ -439,7 +439,7 @@ bool BrowserInit::LaunchBrowser(
}
#endif
- if (command_line.HasSwitch(switches::kLongLivedExtensions)) {
+ if (command_line.HasSwitch(switches::kRestoreBackgroundContents)) {
// Create status icons
StatusTrayManager* tray = g_browser_process->status_tray_manager();
if (tray)
diff --git a/chrome/browser/browser_prefs.cc b/chrome/browser/browser_prefs.cc
index 816c50b..251a4f0 100644
--- a/chrome/browser/browser_prefs.cc
+++ b/chrome/browser/browser_prefs.cc
@@ -5,6 +5,7 @@
#include "chrome/browser/browser_prefs.h"
#include "chrome/browser/autofill/autofill_manager.h"
+#include "chrome/browser/background_contents_service.h"
#include "chrome/browser/bookmarks/bookmark_utils.h"
#include "chrome/browser/browser.h"
#include "chrome/browser/browser_shutdown.h"
@@ -126,6 +127,7 @@ void RegisterUserPrefs(PrefService* user_prefs) {
#if defined(OS_CHROMEOS)
chromeos::Preferences::RegisterUserPrefs(user_prefs);
#endif
+ BackgroundContentsService::RegisterUserPrefs(user_prefs);
}
} // namespace browser
diff --git a/chrome/browser/browser_process_impl.cc b/chrome/browser/browser_process_impl.cc
index a74f5ab..486dd1e 100644
--- a/chrome/browser/browser_process_impl.cc
+++ b/chrome/browser/browser_process_impl.cc
@@ -576,10 +576,8 @@ void BrowserProcessImpl::RestartPersistentInstance() {
}
}
- // TODO(atwilson): Uncomment the following two lines to add the "persistence"
- // switch when the corresponding CL is committed.
- // if (!new_cl->HasSwitch(switches::kLongLivedExtensions))
- // new_cl->AppendSwitch(switches::kLongLivedExtensions);
+ if (!new_cl->HasSwitch(switches::kRestoreBackgroundContents))
+ new_cl->AppendSwitch(switches::kRestoreBackgroundContents);
DLOG(WARNING) << "Shutting down current instance of the browser.";
BrowserList::CloseAllBrowsersAndExit();
diff --git a/chrome/browser/extensions/extensions_ui.cc b/chrome/browser/extensions/extensions_ui.cc
index 8c6664b..5cd3711 100644
--- a/chrome/browser/extensions/extensions_ui.cc
+++ b/chrome/browser/extensions/extensions_ui.cc
@@ -28,6 +28,7 @@
#include "chrome/browser/renderer_host/render_process_host.h"
#include "chrome/browser/renderer_host/render_widget_host.h"
#include "chrome/browser/renderer_host/render_view_host.h"
+#include "chrome/browser/tab_contents/background_contents.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/tab_contents/tab_contents_view.h"
#include "chrome/common/chrome_switches.h"
@@ -698,8 +699,13 @@ void ExtensionsDOMHandler::Observe(NotificationType type,
// Doing it this way gets everything but causes the page to be rendered
// more than we need. It doesn't seem to result in any noticeable flicker.
case NotificationType::RENDER_VIEW_HOST_DELETED:
- case NotificationType::BACKGROUND_CONTENTS_DELETED:
deleting_rvh_ = Details<RenderViewHost>(details).ptr();
+ MaybeUpdateAfterNotification();
+ break;
+ case NotificationType::BACKGROUND_CONTENTS_DELETED:
+ deleting_rvh_ = Details<BackgroundContents>(details)->render_view_host();
+ MaybeUpdateAfterNotification();
+ break;
case NotificationType::EXTENSION_LOADED:
case NotificationType::EXTENSION_PROCESS_CREATED:
case NotificationType::EXTENSION_UNLOADED:
@@ -709,16 +715,19 @@ void ExtensionsDOMHandler::Observe(NotificationType type,
case NotificationType::EXTENSION_FUNCTION_DISPATCHER_DESTROYED:
case NotificationType::NAV_ENTRY_COMMITTED:
case NotificationType::BACKGROUND_CONTENTS_NAVIGATED:
- if (!ignore_notifications_ && dom_ui_->tab_contents())
- HandleRequestExtensionsData(NULL);
- deleting_rvh_ = NULL;
+ MaybeUpdateAfterNotification();
break;
-
default:
NOTREACHED();
}
}
+void ExtensionsDOMHandler::MaybeUpdateAfterNotification() {
+ if (!ignore_notifications_ && dom_ui_->tab_contents())
+ HandleRequestExtensionsData(NULL);
+ deleting_rvh_ = NULL;
+}
+
static void CreateScriptFileDetailValue(
const FilePath& extension_path, const UserScript::FileList& scripts,
const wchar_t* key, DictionaryValue* script_data) {
diff --git a/chrome/browser/extensions/extensions_ui.h b/chrome/browser/extensions/extensions_ui.h
index 449c8da..e85e586 100644
--- a/chrome/browser/extensions/extensions_ui.h
+++ b/chrome/browser/extensions/extensions_ui.h
@@ -170,6 +170,9 @@ class ExtensionsDOMHandler
// Callback for "selectFilePath" message.
void HandleSelectFilePathMessage(const Value* value);
+ // Forces a UI update if appropriate after a notification is received.
+ void MaybeUpdateAfterNotification();
+
// SelectFileDialog::Listener
virtual void FileSelected(const FilePath& path,
int index, void* params);
diff --git a/chrome/browser/profile.cc b/chrome/browser/profile.cc
index bbfd60d..a2fbff3 100644
--- a/chrome/browser/profile.cc
+++ b/chrome/browser/profile.cc
@@ -16,6 +16,7 @@
#include "chrome/browser/appcache/chrome_appcache_service.h"
#include "chrome/browser/autocomplete/autocomplete_classifier.h"
#include "chrome/browser/autofill/personal_data_manager.h"
+#include "chrome/browser/background_contents_service.h"
#include "chrome/browser/bookmarks/bookmark_model.h"
#include "chrome/browser/browser_list.h"
#include "chrome/browser/browser_prefs.h"
@@ -309,6 +310,8 @@ class OffTheRecordProfileImpl : public Profile,
// (cookies, downloads...).
registrar_.Add(this, NotificationType::BROWSER_CLOSED,
NotificationService::AllSources());
+ background_contents_service_.reset(
+ new BackgroundContentsService(this, CommandLine::ForCurrentProcess()));
}
virtual ~OffTheRecordProfileImpl() {
@@ -366,6 +369,10 @@ class OffTheRecordProfileImpl : public Profile,
return GetOriginalProfile()->GetExtensionsService();
}
+ virtual BackgroundContentsService* GetBackgroundContentsService() {
+ return background_contents_service_.get();
+ }
+
virtual UserScriptMaster* GetUserScriptMaster() {
return GetOriginalProfile()->GetUserScriptMaster();
}
@@ -721,6 +728,9 @@ class OffTheRecordProfileImpl : public Profile,
FilePath last_selected_directory_;
+ // Tracks all BackgroundContents running under this profile.
+ scoped_ptr<BackgroundContentsService> background_contents_service_;
+
DISALLOW_COPY_AND_ASSIGN(OffTheRecordProfileImpl);
};
@@ -808,6 +818,9 @@ ProfileImpl::ProfileImpl(const FilePath& path)
pinned_tab_service_.reset(new PinnedTabService(this));
+ background_contents_service_.reset(
+ new BackgroundContentsService(this, CommandLine::ForCurrentProcess()));
+
// Log the profile size after a reasonable startup delay.
ChromeThread::PostDelayedTask(ChromeThread::FILE, FROM_HERE,
new ProfileSizeTask(path_), 112000);
@@ -1049,6 +1062,10 @@ ExtensionsService* ProfileImpl::GetExtensionsService() {
return extensions_service_.get();
}
+BackgroundContentsService* ProfileImpl::GetBackgroundContentsService() {
+ return background_contents_service_.get();
+}
+
UserScriptMaster* ProfileImpl::GetUserScriptMaster() {
return user_script_master_.get();
}
diff --git a/chrome/browser/profile.h b/chrome/browser/profile.h
index 5ec66d6..4fc6223 100644
--- a/chrome/browser/profile.h
+++ b/chrome/browser/profile.h
@@ -40,6 +40,7 @@ class DatabaseTracker;
}
class AutocompleteClassifier;
+class BackgroundContentsService;
class Blacklist;
class BookmarkModel;
class BrowserThemeProvider;
@@ -403,6 +404,9 @@ class Profile {
// Returns the provider of desktop notifications for this profile.
virtual DesktopNotificationService* GetDesktopNotificationService() = 0;
+ // Returns the service that manages BackgroundContents for this profile.
+ virtual BackgroundContentsService* GetBackgroundContentsService() = 0;
+
// Marks the profile as cleanly shutdown.
//
// NOTE: this is invoked internally on a normal shutdown, but is public so
@@ -537,6 +541,7 @@ class ProfileImpl : public Profile,
virtual void ReinitializeSpellCheckHost(bool force);
virtual WebKitContext* GetWebKitContext();
virtual DesktopNotificationService* GetDesktopNotificationService();
+ virtual BackgroundContentsService* GetBackgroundContentsService();
virtual void MarkAsCleanShutdown();
virtual void InitExtensions();
virtual void InitWebResources();
@@ -634,6 +639,7 @@ class ProfileImpl : public Profile,
scoped_ptr<BrowserThemeProvider> theme_provider_;
scoped_refptr<WebKitContext> webkit_context_;
scoped_ptr<DesktopNotificationService> desktop_notification_service_;
+ scoped_ptr<BackgroundContentsService> background_contents_service_;
scoped_refptr<PersonalDataManager> personal_data_manager_;
scoped_ptr<PinnedTabService> pinned_tab_service_;
bool history_service_created_;
diff --git a/chrome/browser/tab_contents/background_contents.cc b/chrome/browser/tab_contents/background_contents.cc
index 5409d65..2e65d9d 100644
--- a/chrome/browser/tab_contents/background_contents.cc
+++ b/chrome/browser/tab_contents/background_contents.cc
@@ -4,6 +4,7 @@
#include "chrome/browser/tab_contents/background_contents.h"
+#include "chrome/browser/background_contents_service.h"
#include "chrome/browser/browser.h"
#include "chrome/browser/browser_list.h"
#include "chrome/browser/browsing_instance.h"
@@ -14,6 +15,7 @@
#include "chrome/browser/renderer_host/site_instance.h"
#include "chrome/browser/renderer_preferences_util.h"
#include "chrome/common/notification_service.h"
+#include "chrome/common/url_constants.h"
#include "chrome/common/view_types.h"
#include "chrome/common/render_messages.h"
@@ -32,13 +34,15 @@ BackgroundContents::BackgroundContents(SiteInstance* site_instance,
session_storage_namespace_id);
render_view_host_->AllowScriptToClose(true);
-#if defined(OS_WIN) || defined(OS_LINUX)
- registrar_.Add(this, NotificationType::BROWSER_CLOSED,
- NotificationService::AllSources());
-#elif defined(OS_MACOSX)
- registrar_.Add(this, NotificationType::APP_TERMINATING,
- NotificationService::AllSources());
-#endif
+ // Register for our parent profile to shutdown, so we can shut ourselves down
+ // as well.
+ registrar_.Add(this, NotificationType::PROFILE_DESTROYED,
+ Source<Profile>(profile));
+}
+
+// Exposed to allow creating mocks.
+BackgroundContents::BackgroundContents()
+ : render_view_host_(NULL) {
}
void BackgroundContents::Observe(NotificationType type,
@@ -47,19 +51,10 @@ void BackgroundContents::Observe(NotificationType type,
// TODO(rafaelw): Implement pagegroup ref-counting so that non-persistent
// background pages are closed when the last referencing frame is closed.
switch (type.value) {
-#if defined(OS_WIN) || defined(OS_LINUX)
- case NotificationType::BROWSER_CLOSED: {
- bool app_closing = *Details<bool>(details).ptr();
- if (app_closing)
- delete this;
- break;
- }
-#elif defined(OS_MACOSX)
- case NotificationType::APP_TERMINATING: {
+ case NotificationType::PROFILE_DESTROYED: {
delete this;
break;
}
-#endif
default:
NOTREACHED() << "Unexpected notification sent.";
break;
@@ -67,10 +62,13 @@ void BackgroundContents::Observe(NotificationType type,
}
BackgroundContents::~BackgroundContents() {
+ if (!render_view_host_) // Will be null for unit tests.
+ return;
+ Profile* profile = render_view_host_->process()->profile();
NotificationService::current()->Notify(
NotificationType::BACKGROUND_CONTENTS_DELETED,
- Source<BackgroundContents>(this),
- Details<RenderViewHost>(render_view_host_));
+ Source<Profile>(profile),
+ Details<BackgroundContents>(this));
render_view_host_->Shutdown(); // deletes render_view_host
}
@@ -90,10 +88,11 @@ void BackgroundContents::DidNavigate(
// extent a background page will be opened but will remain at about:blank.
url_ = params.url;
+ Profile* profile = render_view_host->process()->profile();
NotificationService::current()->Notify(
NotificationType::BACKGROUND_CONTENTS_NAVIGATED,
- Source<BackgroundContents>(this),
- Details<RenderViewHost>(render_view_host_));
+ Source<Profile>(profile),
+ Details<BackgroundContents>(this));
}
void BackgroundContents::RunJavaScriptMessage(
@@ -126,6 +125,11 @@ void BackgroundContents::OnMessageBoxClosed(IPC::Message* reply_msg,
}
void BackgroundContents::Close(RenderViewHost* render_view_host) {
+ Profile* profile = render_view_host->process()->profile();
+ NotificationService::current()->Notify(
+ NotificationType::BACKGROUND_CONTENTS_CLOSED,
+ Source<Profile>(profile),
+ Details<BackgroundContents>(this));
delete this;
}
diff --git a/chrome/browser/tab_contents/background_contents.h b/chrome/browser/tab_contents/background_contents.h
index af07a19..6b94c82 100644
--- a/chrome/browser/tab_contents/background_contents.h
+++ b/chrome/browser/tab_contents/background_contents.h
@@ -32,7 +32,7 @@ class BackgroundContents : public RenderViewHostDelegate,
public:
BackgroundContents(SiteInstance* site_instance,
int routing_id);
- ~BackgroundContents();
+ virtual ~BackgroundContents();
// Provide access to the RenderViewHost for the
// RenderViewHostDelegateViewHelper
@@ -109,6 +109,10 @@ class BackgroundContents : public RenderViewHostDelegate,
virtual TabContents* AsTabContents() { return NULL; }
virtual ExtensionHost* AsExtensionHost() { return NULL; }
+ protected:
+ // Exposed for testing.
+ BackgroundContents();
+
private:
// The host for our HTML content.
RenderViewHost* render_view_host_;
@@ -124,4 +128,16 @@ class BackgroundContents : public RenderViewHostDelegate,
DISALLOW_COPY_AND_ASSIGN(BackgroundContents);
};
+// This is the data sent out as the details with BACKGROUND_CONTENTS_OPENED.
+struct BackgroundContentsOpenedDetails {
+ // The BackgroundContents object that has just been opened.
+ BackgroundContents* contents;
+
+ // The name of the parent frame for these contents.
+ const string16& frame_name;
+
+ // The ID of the parent application (if any).
+ const string16& application_id;
+};
+
#endif // CHROME_BROWSER_TAB_CONTENTS_BACKGROUND_CONTENTS_H_
diff --git a/chrome/browser/tab_contents/render_view_host_delegate_helper.cc b/chrome/browser/tab_contents/render_view_host_delegate_helper.cc
index be662e2..6edd873 100644
--- a/chrome/browser/tab_contents/render_view_host_delegate_helper.cc
+++ b/chrome/browser/tab_contents/render_view_host_delegate_helper.cc
@@ -6,6 +6,7 @@
#include "base/command_line.h"
#include "base/string_util.h"
+#include "chrome/browser/background_contents_service.h"
#include "chrome/browser/browser.h"
#include "chrome/browser/character_encoding.h"
#include "chrome/browser/extensions/extensions_service.h"
@@ -21,35 +22,56 @@
#include "chrome/browser/tab_contents/tab_contents_view.h"
#include "chrome/browser/user_style_sheet_watcher.h"
#include "chrome/common/chrome_switches.h"
+#include "chrome/common/notification_service.h"
#include "chrome/common/pref_names.h"
-bool RenderViewHostDelegateViewHelper::ShouldOpenBackgroundContents(
- WindowContainerType window_container_type,
+BackgroundContents*
+RenderViewHostDelegateViewHelper::MaybeCreateBackgroundContents(
+ int route_id,
+ Profile* profile,
+ SiteInstance* site,
GURL opener_url,
- RenderProcessHost* opener_process,
- Profile* profile) {
+ const string16& frame_name) {
ExtensionsService* extensions_service = profile->GetExtensionsService();
- if (window_container_type != WINDOW_CONTAINER_TYPE_BACKGROUND ||
- !opener_url.is_valid() ||
+
+ if (!opener_url.is_valid() ||
+ frame_name.empty() ||
!extensions_service ||
!extensions_service->is_ready())
- return false;
+ return NULL;
Extension* extension = extensions_service->GetExtensionByURL(opener_url);
if (!extension)
extension = extensions_service->GetExtensionByWebExtent(opener_url);
if (!extension ||
!extension->HasApiPermission(Extension::kBackgroundPermission))
- return false;
+ return NULL;
+ // Only allow a single background contents per app.
+ if (!profile->GetBackgroundContentsService() ||
+ profile->GetBackgroundContentsService()->GetAppBackgroundContents(
+ ASCIIToUTF16(extension->id())))
+ return NULL;
+
+ // Ensure that we're trying to open this from the extension's process.
ExtensionProcessManager* process_manager =
profile->GetExtensionProcessManager();
- if (!opener_process || !process_manager ||
- opener_process != process_manager->GetExtensionProcess(opener_url))
- return false;
+ if (!site->GetProcess() || !process_manager ||
+ site->GetProcess() != process_manager->GetExtensionProcess(opener_url))
+ return NULL;
+
+ // Passed all the checks, so this should be created as a BackgroundContents.
+ BackgroundContents* contents = new BackgroundContents(site, route_id);
+ string16 appid = ASCIIToUTF16(extension->id());
+ BackgroundContentsOpenedDetails details = { contents, frame_name, appid };
+ NotificationService::current()->Notify(
+ NotificationType::BACKGROUND_CONTENTS_OPENED,
+ Source<Profile>(profile),
+ Details<BackgroundContentsOpenedDetails>(&details));
- return true;
+ return contents;
}
+
TabContents* RenderViewHostDelegateViewHelper::CreateNewWindow(
int route_id,
Profile* profile,
@@ -58,13 +80,17 @@ TabContents* RenderViewHostDelegateViewHelper::CreateNewWindow(
RenderViewHostDelegate* opener,
WindowContainerType window_container_type,
const string16& frame_name) {
- if (ShouldOpenBackgroundContents(window_container_type,
- opener->GetURL(),
- site->GetProcess(),
- profile)) {
- BackgroundContents* contents = new BackgroundContents(site, route_id);
- pending_contents_[route_id] = contents->render_view_host();
- return NULL;
+ if (window_container_type == WINDOW_CONTAINER_TYPE_BACKGROUND) {
+ BackgroundContents* contents = MaybeCreateBackgroundContents(
+ route_id,
+ profile,
+ site,
+ opener->GetURL(),
+ frame_name);
+ if (contents) {
+ pending_contents_[route_id] = contents->render_view_host();
+ return NULL;
+ }
}
// Create the new web contents. This will automatically create the new
diff --git a/chrome/browser/tab_contents/render_view_host_delegate_helper.h b/chrome/browser/tab_contents/render_view_host_delegate_helper.h
index 08ef2db..5b1d99b0 100644
--- a/chrome/browser/tab_contents/render_view_host_delegate_helper.h
+++ b/chrome/browser/tab_contents/render_view_host_delegate_helper.h
@@ -16,6 +16,7 @@
#include "webkit/glue/webpreferences.h"
#include "webkit/glue/window_open_disposition.h"
+class BackgroundContents;
class Browser;
class ExtensionsService;
class PrefService;
@@ -68,10 +69,12 @@ class RenderViewHostDelegateViewHelper {
void RenderWidgetHostDestroyed(RenderWidgetHost* host);
private:
- bool ShouldOpenBackgroundContents(WindowContainerType window_container_type,
- GURL opener_url,
- RenderProcessHost* opener_process,
- Profile* profile);
+ BackgroundContents* MaybeCreateBackgroundContents(
+ int route_id,
+ Profile* profile,
+ SiteInstance* site,
+ GURL opener_url,
+ const string16& frame_name);
// Tracks created RenderViewHost objects that have not been shown yet.
// They are identified by the route ID passed to CreateNewWindow.
diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi
index 291f5dc..a5f6a24 100755
--- a/chrome/chrome_browser.gypi
+++ b/chrome/chrome_browser.gypi
@@ -221,6 +221,8 @@
'browser/automation/ui_controls.h',
'browser/back_forward_menu_model.cc',
'browser/back_forward_menu_model.h',
+ 'browser/background_contents_service.h',
+ 'browser/background_contents_service.cc',
'browser/blocked_popup_container.cc',
'browser/blocked_popup_container.h',
'browser/bookmarks/bookmark_codec.cc',
diff --git a/chrome/chrome_tests.gypi b/chrome/chrome_tests.gypi
index 72d24db..46a855d 100755
--- a/chrome/chrome_tests.gypi
+++ b/chrome/chrome_tests.gypi
@@ -582,6 +582,7 @@
'browser/autofill/phone_number_unittest.cc',
'browser/automation/automation_provider_unittest.cc',
'browser/back_forward_menu_model_unittest.cc',
+ 'browser/background_contents_service_unittest.cc',
'browser/bookmarks/bookmark_codec_unittest.cc',
'browser/bookmarks/bookmark_context_menu_controller_unittest.cc',
'browser/bookmarks/bookmark_drag_data_unittest.cc',
diff --git a/chrome/common/chrome_switches.cc b/chrome/common/chrome_switches.cc
index f5b6dac..da839ae 100644
--- a/chrome/common/chrome_switches.cc
+++ b/chrome/common/chrome_switches.cc
@@ -514,9 +514,6 @@ const char kLoadExtension[] = "load-extension";
// Load an NPAPI plugin from the specified path.
const char kLoadPlugin[] = "load-plugin";
-// Long lived extensions.
-const char kLongLivedExtensions[] = "long-lived-extensions";
-
// Will filter log messages to show only the messages that are prefixed
// with the specified value. See also kEnableLogging and kLoggingLevel.
const char kLogFilterPrefix[] = "log-filter-prefix";
@@ -711,6 +708,10 @@ const char kRendererProcess[] = "renderer";
// Causes the renderer process to display a dialog on launch.
const char kRendererStartupDialog[] = "renderer-startup-dialog";
+// Causes the URLs of BackgroundContents to be remembered and re-launched when
+// the browser restarts.
+const char kRestoreBackgroundContents[] = "restore-background-contents";
+
// Indicates the last session should be restored on startup. This overrides
// the preferences value and is primarily intended for testing. The value of
// this switch is the number of tabs to wait until loaded before
diff --git a/chrome/common/chrome_switches.h b/chrome/common/chrome_switches.h
index a6ea1d4..3144673 100644
--- a/chrome/common/chrome_switches.h
+++ b/chrome/common/chrome_switches.h
@@ -154,7 +154,6 @@ extern const char kInternalPepper[];
extern const char kJavaScriptFlags[];
extern const char kLoadExtension[];
extern const char kLoadPlugin[];
-extern const char kLongLivedExtensions[];
extern const char kLogFilterPrefix[];
extern const char kLogPluginMessages[];
extern const char kLoggingLevel[];
@@ -203,6 +202,7 @@ extern const char kRendererCmdPrefix[];
extern const char kRendererCrashTest[];
extern const char kRendererProcess[];
extern const char kRendererStartupDialog[];
+extern const char kRestoreBackgroundContents[];
extern const char kRestoreLastSession[];
extern const char kSafePlugins[];
extern const char kSdchFilter[];
diff --git a/chrome/common/notification_type.h b/chrome/common/notification_type.h
index f47088c..93145d1 100644
--- a/chrome/common/notification_type.h
+++ b/chrome/common/notification_type.h
@@ -482,12 +482,23 @@ class NotificationType {
// BackgroundContents ------------------------------------------------------
+ // A new background contents was opened by script. The source is the parent
+ // profile and the details are BackgroundContentsOpenedDetails.
+ BACKGROUND_CONTENTS_OPENED,
+
// The background contents navigated to a new location. The source is the
- // BackgroundContents, and the details are contained RenderViewHost.
+ // parent Profile, and the details are the BackgroundContents that was
+ // navigated.
BACKGROUND_CONTENTS_NAVIGATED,
+ // The background contents were closed by someone invoking window.close()
+ // or the parent application was uninstalled.
+ // The source is the parent profile, and the details are the
+ // BackgroundContents.
+ BACKGROUND_CONTENTS_CLOSED,
+
// The background contents is being deleted. The source is the
- // BackgroundContents, and the details are the contained RendeViewHost.
+ // parent Profile, and the details are the BackgroundContents being deleted.
BACKGROUND_CONTENTS_DELETED,
// Child Processes ---------------------------------------------------------
diff --git a/chrome/common/pref_names.cc b/chrome/common/pref_names.cc
index 9e13585..f3a8e2b 100644
--- a/chrome/common/pref_names.cc
+++ b/chrome/common/pref_names.cc
@@ -868,6 +868,11 @@ const wchar_t kLoginDatabaseMigrated[] = L"login_database.migrated";
// The root URL of the cloud print service.
const wchar_t kCloudPrintServiceURL[] = L"cloud_print.service_url";
+// The list of BackgroundContents that should be loaded when the browser
+// launches.
+const wchar_t kRegisteredBackgroundContents[] =
+ L"background_contents.registered";
+
// *************** SERVICE PREFS ***************
// These are attached to the service process.
diff --git a/chrome/common/pref_names.h b/chrome/common/pref_names.h
index 192b598..6441e9d 100644
--- a/chrome/common/pref_names.h
+++ b/chrome/common/pref_names.h
@@ -336,6 +336,8 @@ extern const wchar_t kProxyServer[];
extern const wchar_t kProxyPacUrl[];
extern const wchar_t kProxyBypassList[];
+extern const wchar_t kRegisteredBackgroundContents[];
+
} // namespace prefs
#endif // CHROME_COMMON_PREF_NAMES_H_
diff --git a/chrome/test/testing_browser_process.h b/chrome/test/testing_browser_process.h
index fdfe776..bf1744f 100644
--- a/chrome/test/testing_browser_process.h
+++ b/chrome/test/testing_browser_process.h
@@ -26,6 +26,7 @@ class TestingBrowserProcess : public BrowserProcess {
public:
TestingBrowserProcess()
: shutdown_event_(new base::WaitableEvent(true, false)),
+ module_ref_count_(0),
app_locale_("en") {
}
@@ -125,10 +126,15 @@ class TestingBrowserProcess : public BrowserProcess {
}
virtual unsigned int AddRefModule() {
- return 1;
+ return ++module_ref_count_;
}
virtual unsigned int ReleaseModule() {
- return 1;
+ DCHECK(module_ref_count_ > 0);
+ return --module_ref_count_;
+ }
+
+ unsigned int module_ref_count() {
+ return module_ref_count_;
}
virtual bool IsShuttingDown() {
@@ -165,6 +171,7 @@ class TestingBrowserProcess : public BrowserProcess {
private:
NotificationService notification_service_;
scoped_ptr<base::WaitableEvent> shutdown_event_;
+ unsigned int module_ref_count_;
scoped_ptr<Clipboard> clipboard_;
std::string app_locale_;
diff --git a/chrome/test/testing_profile.h b/chrome/test/testing_profile.h
index 50bd1fe..adc8d95 100644
--- a/chrome/test/testing_profile.h
+++ b/chrome/test/testing_profile.h
@@ -265,6 +265,9 @@ class TestingProfile : public Profile {
virtual DesktopNotificationService* GetDesktopNotificationService() {
return NULL;
}
+ virtual BackgroundContentsService* GetBackgroundContentsService() {
+ return NULL;
+ }
virtual FilePath last_selected_directory() {
return last_selected_directory_;
}