Allocate SocketController lazily.
To work around some unit tests that use ExtensionService but don't
provide an IO thread that SocketController now needs to completely
tear itself down, we allocate SocketController lazily and DCHECK on
destruction that there is an IO thread message loop. This is a
reasonable compromise for getting the benefit of lifetime management
by sticking SocketController in ExtensionService.
BTW, aa said putting random crap in ExtensionService wasn't a good idea.
Our chickens are coming home to roost. As platform APIs get bigger,
we should provide our own dumping ground for these classes, and then
callers won't get hung up in surprising lifetime issues like this one.
BUG=106969
TEST=existing unit/heap/mem checks should cover us. Verified memcheck behavior manually.
Review URL: http://codereview.chromium.org/8925001
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@114287 0039d316-1c4b-4281-b951-d872f2087c98
diff --git a/chrome/browser/extensions/extension_service.cc b/chrome/browser/extensions/extension_service.cc
index 1549c7f8..5962a9c2 100644
--- a/chrome/browser/extensions/extension_service.cc
+++ b/chrome/browser/extensions/extension_service.cc
@@ -389,7 +389,7 @@
apps_promo_(profile->GetPrefs()),
event_routers_initialized_(false),
extension_warnings_(profile),
- socket_controller_(new extensions::SocketController()),
+ socket_controller_(NULL),
tracker_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) {
CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
@@ -478,9 +478,15 @@
// TODO(miket): if we find ourselves adding more and more per-API
// controllers, we should manage them all with an
// APIControllerController (still working on that name).
- BrowserThread::PostTask(
- BrowserThread::IO, FROM_HERE,
- new DeleteTask<extensions::SocketController>(socket_controller_));
+ if (socket_controller_) {
+ // If this check failed, then a unit test was using sockets but didn't
+ // provide the IO thread message loop needed for those sockets to do their
+ // job (including destroying themselves at shutdown).
+ DCHECK(BrowserThread::IsMessageLoopValid(BrowserThread::IO));
+ BrowserThread::PostTask(
+ BrowserThread::IO, FROM_HERE,
+ new DeleteTask<extensions::SocketController>(socket_controller_));
+ }
}
void ExtensionService::InitEventRoutersAfterImport() {
@@ -2540,3 +2546,17 @@
shortcut_info_.favicon = *image;
web_app::CreateShortcut(profile_->GetPath(), shortcut_info_);
}
+
+extensions::SocketController* ExtensionService::socket_controller() {
+ // TODO(miket): Find a better place for SocketController to live. It needs
+ // to be scoped such that it can be created and destroyed on the IO thread.
+ //
+ // To coexist with certain unit tests that don't have an IO thread message
+ // loop available at ExtensionService shutdown, we lazy-initialize this
+ // object so that those cases neither create nor destroy a SocketController.
+ CHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ if (!socket_controller_) {
+ socket_controller_ = new extensions::SocketController();
+ }
+ return socket_controller_;
+}