summaryrefslogtreecommitdiffstats
path: root/chrome
diff options
context:
space:
mode:
authordarin@google.com <darin@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2008-08-15 04:32:57 +0000
committerdarin@google.com <darin@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2008-08-15 04:32:57 +0000
commit295039bdf97f08bf5c1c1c136dd977b7e97ddd31 (patch)
treeae3b47308e7d2f2db903f6a61c193e7a8c9ec882 /chrome
parent1c33790ef99bf8301260b9144110e71e7723d0f4 (diff)
downloadchromium_src-295039bdf97f08bf5c1c1c136dd977b7e97ddd31.zip
chromium_src-295039bdf97f08bf5c1c1c136dd977b7e97ddd31.tar.gz
chromium_src-295039bdf97f08bf5c1c1c136dd977b7e97ddd31.tar.bz2
Introduce MessagePump to represent the native message pump used to drive a
MessageLoop. A MessageLoop now has a MessagePump. This will make it possible to port the MessagePump interface to other platforms as well as to use an IO completion port for our worker threads on Windows. Currently, there is only MessagePumpWin, which attempts to preserve the pre-existing behavior of the MessageLoop. API changes to MessageLoop: 1. MessageLoop::Quit means return from Run when the MessageLoop would otherwise wait for more work. 2. MessageLoop::Quit can no longer be called outside the context of an active Run call. So, things like this: MessageLoop::current()->Quit(); MessageLoop::current()->Run(); are now: MessageLoop::current()->RunAllPending(); 3. MessageLoop::Quit can no longer be called from other threads. This means that PostTask(..., new MessageLoop::QuitTask()) must be used explicitly to Quit across thread boundaries. 4. No protection is made to deal with nested MessageLoops involving watched objects or APCs. In fact, an assertion is added to flag such cases. This is a temporary measure until object watching and APC facilities are removed in favor of a MessagePump designed around an IO completion port. As part of this CL, I also changed the automation system to use an IPC::ChannelProxy instead of an IPC::Channel. This moves the automation IPC onto Chrome's IO thread where it belongs. I also fixed some abuses of RefCounted in the AutomationProvider class. It was deleting itself in some cases! This led to having to fix the ownership model for AutomationProvider, which explains the changes to AutomationProviderList and so on. git-svn-id: svn://svn.chromium.org/chrome/trunk/src@928 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome')
-rw-r--r--chrome/app/chrome_dll_main.cc9
-rw-r--r--chrome/browser/automation/automation_provider.cc39
-rw-r--r--chrome/browser/automation/automation_provider.h7
-rw-r--r--chrome/browser/automation/automation_provider_list.cc8
-rw-r--r--chrome/browser/browser_init.cc9
-rw-r--r--chrome/browser/browser_main.cc2
-rw-r--r--chrome/browser/browser_process_impl.cc14
-rw-r--r--chrome/browser/navigation_controller_unittest.cc9
-rw-r--r--chrome/browser/printing/printing_layout_uitest.cc2
-rw-r--r--chrome/browser/render_process_host.cc1
-rw-r--r--chrome/browser/resource_dispatcher_host_unittest.cc6
-rw-r--r--chrome/browser/site_instance_unittest.cc3
-rw-r--r--chrome/browser/url_fetcher_unittest.cc6
-rw-r--r--chrome/browser/web_contents_unittest.cc3
-rw-r--r--chrome/common/child_process.cc2
-rw-r--r--chrome/common/chrome_switches.cc4
-rw-r--r--chrome/common/chrome_switches.h1
-rw-r--r--chrome/common/message_router.h1
-rw-r--r--chrome/renderer/render_thread.cc3
-rw-r--r--chrome/test/automation/automation_proxy.cc13
-rw-r--r--chrome/test/automation/automation_proxy.h8
-rw-r--r--chrome/test/ui/ui_test.cc4
22 files changed, 70 insertions, 84 deletions
diff --git a/chrome/app/chrome_dll_main.cc b/chrome/app/chrome_dll_main.cc
index 0294bd2..8bf6493 100644
--- a/chrome/app/chrome_dll_main.cc
+++ b/chrome/app/chrome_dll_main.cc
@@ -193,15 +193,6 @@ DLLEXPORT int __cdecl ChromeMain(HINSTANCE instance,
exit(-1);
// Enable Message Loop related state asap.
- if (parsed_command_line.HasSwitch(switches::kMessageLoopStrategy)) {
- std::wstring details =
- parsed_command_line.GetSwitchValue(switches::kMessageLoopStrategy);
- int strategy = 0;
- if (details.size()) {
- strategy = static_cast<int>(StringToInt64(details));
- }
- MessageLoop::SetStrategy(strategy);
- }
if (parsed_command_line.HasSwitch(switches::kMessageLoopHistogrammer))
MessageLoop::EnableHistogrammer(true);
diff --git a/chrome/browser/automation/automation_provider.cc b/chrome/browser/automation/automation_provider.cc
index f23e7d1..d6e6b08 100644
--- a/chrome/browser/automation/automation_provider.cc
+++ b/chrome/browser/automation/automation_provider.cc
@@ -582,13 +582,8 @@ class DocumentPrintedNotificationObserver : public NotificationObserver {
};
AutomationProvider::AutomationProvider(Profile* profile)
- : connected_(false),
- redirect_query_(0),
+ : redirect_query_(0),
profile_(profile) {
- AutomationProviderList* list =
- g_browser_process->InitAutomationProviderList();
- DCHECK(NULL != list);
- list->AddProvider(this);
browser_tracker_.reset(new AutomationBrowserTracker(this));
window_tracker_.reset(new AutomationWindowTracker(this));
tab_tracker_.reset(new AutomationTabTracker(this));
@@ -601,21 +596,13 @@ AutomationProvider::AutomationProvider(Profile* profile)
}
AutomationProvider::~AutomationProvider() {
- // TODO(vibhor) : Delete the pending observer objects.
- AutomationProviderList* list =
- g_browser_process->InitAutomationProviderList();
- DCHECK(NULL != list);
- list->RemoveProvider(this);
}
void AutomationProvider::ConnectToChannel(const std::wstring& channel_id) {
- scoped_ptr<IPC::Channel> channel(
- new IPC::Channel(channel_id, IPC::Channel::MODE_CLIENT, this));
- connected_ = channel->Connect();
- if (connected_) {
- channel_.swap(channel);
- channel_->Send(new AutomationMsg_Hello(0));
- }
+ channel_.reset(
+ new IPC::ChannelProxy(channel_id, IPC::Channel::MODE_CLIENT, this, NULL,
+ g_browser_process->io_thread()->message_loop()));
+ channel_->Send(new AutomationMsg_Hello(0));
}
void AutomationProvider::SetExpectedTabCount(size_t expected_tabs) {
@@ -1450,7 +1437,7 @@ void AutomationProvider::HandleUnused(const IPC::Message& message, int handle) {
void AutomationProvider::OnChannelError() {
LOG(ERROR) << "AutomationProxy went away, shutting down app.";
- delete this;
+ AutomationProviderList::GetInstance()->RemoveProvider(this);
}
// TODO(brettw) change this to accept GURLs when history supports it
@@ -1478,11 +1465,8 @@ void AutomationProvider::OnRedirectQueryComplete(
}
bool AutomationProvider::Send(IPC::Message* msg) {
- if (connected_) {
- DCHECK(channel_.get());
- return channel_->Send(msg);
- }
- return false;
+ DCHECK(channel_.get());
+ return channel_->Send(msg);
}
Browser* AutomationProvider::FindAndActivateTab(
@@ -2235,7 +2219,8 @@ void TestingAutomationProvider::OnBrowserRemoving(const Browser* browser) {
// last browser goes away.
if (BrowserList::size() == 1) {
// If you change this, update Observer for NOTIFY_SESSION_END below.
- MessageLoop::current()->ReleaseSoon(FROM_HERE, this);
+ MessageLoop::current()->PostTask(FROM_HERE,
+ NewRunnableMethod(this, &TestingAutomationProvider::OnRemoveProvider));
}
}
@@ -2248,3 +2233,7 @@ void TestingAutomationProvider::Observe(NotificationType type,
// Release balance out the Release scheduled by OnBrowserRemoving.
Release();
}
+
+void TestingAutomationProvider::OnRemoveProvider() {
+ AutomationProviderList::GetInstance()->RemoveProvider(this);
+}
diff --git a/chrome/browser/automation/automation_provider.h b/chrome/browser/automation/automation_provider.h
index 20f34a1..1bde370 100644
--- a/chrome/browser/automation/automation_provider.h
+++ b/chrome/browser/automation/automation_provider.h
@@ -47,7 +47,7 @@
#include "chrome/browser/automation/automation_autocomplete_edit_tracker.h"
#include "chrome/browser/browser_list.h"
#include "chrome/browser/history/history.h"
-#include "chrome/common/ipc_channel.h"
+#include "chrome/common/ipc_channel_proxy.h"
#include "chrome/common/ipc_message.h"
#include "chrome/common/notification_service.h"
@@ -321,8 +321,7 @@ class AutomationProvider : public base::RefCounted<AutomationProvider>,
typedef ObserverList<NotificationObserver> NotificationObserverList;
typedef std::map<NavigationController*, LoginHandler*> LoginHandlerMap;
- bool connected_;
- scoped_ptr<IPC::Channel> channel_;
+ scoped_ptr<IPC::ChannelProxy> channel_;
scoped_ptr<NotificationObserver> initial_load_observer_;
scoped_ptr<NotificationObserver> new_tab_ui_load_observer_;
scoped_ptr<NotificationObserver> find_in_page_observer_;
@@ -383,5 +382,7 @@ class TestingAutomationProvider : public AutomationProvider,
virtual void Observe(NotificationType type,
const NotificationSource& source,
const NotificationDetails& details);
+
+ void OnRemoveProvider(); // Called via PostTask
};
#endif // CHROME_BROWSER_AUTOMATION_AUTOMATION_PROVIDER_H_
diff --git a/chrome/browser/automation/automation_provider_list.cc b/chrome/browser/automation/automation_provider_list.cc
index 4d9bb93..8d683d8 100644
--- a/chrome/browser/automation/automation_provider_list.cc
+++ b/chrome/browser/automation/automation_provider_list.cc
@@ -41,18 +41,15 @@ AutomationProviderList::AutomationProviderList() {
AutomationProviderList::~AutomationProviderList() {
iterator iter = automation_providers_.begin();
while (iter != automation_providers_.end()) {
- AutomationProvider* provider = (*iter);
- // Delete the entry first and update the iterator first because the d'tor
- // of AutomationProvider will call RemoveProvider, making this iterator
- // invalid
+ (*iter)->Release();
iter = automation_providers_.erase(iter);
g_browser_process->ReleaseModule();
- delete provider;
}
instance_ = NULL;
}
bool AutomationProviderList::AddProvider(AutomationProvider* provider) {
+ provider->AddRef();
automation_providers_.push_back(provider);
g_browser_process->AddRefModule();
return true;
@@ -62,6 +59,7 @@ bool AutomationProviderList::RemoveProvider(AutomationProvider* provider) {
const iterator remove_provider =
find(automation_providers_.begin(), automation_providers_.end(), provider);
if (remove_provider != automation_providers_.end()) {
+ (*remove_provider)->Release();
automation_providers_.erase(remove_provider);
g_browser_process->ReleaseModule();
return true;
diff --git a/chrome/browser/browser_init.cc b/chrome/browser/browser_init.cc
index ff1fa47..e3a4630 100644
--- a/chrome/browser/browser_init.cc
+++ b/chrome/browser/browser_init.cc
@@ -718,8 +718,13 @@ template <class AutomationProviderClass>
void BrowserInit::CreateAutomationProvider(const std::wstring& channel_id,
Profile* profile,
size_t expected_tabs) {
- AutomationProviderClass* automation = new AutomationProviderClass(profile);
- automation->AddRef();
+ scoped_refptr<AutomationProviderClass> automation =
+ new AutomationProviderClass(profile);
automation->ConnectToChannel(channel_id);
automation->SetExpectedTabCount(expected_tabs);
+
+ AutomationProviderList* list =
+ g_browser_process->InitAutomationProviderList();
+ DCHECK(list);
+ list->AddProvider(automation);
}
diff --git a/chrome/browser/browser_main.cc b/chrome/browser/browser_main.cc
index 24f07ce..2287533 100644
--- a/chrome/browser/browser_main.cc
+++ b/chrome/browser/browser_main.cc
@@ -271,7 +271,7 @@ int BrowserMain(CommandLine &parsed_command_line, int show_command,
const char* main_thread_name = "Chrome_BrowserMain";
Thread::SetThreadName(main_thread_name, GetCurrentThreadId());
- MessageLoop::current()->SetThreadName(main_thread_name);
+ MessageLoop::current()->set_thread_name(main_thread_name);
bool already_running = CreateUniqueChromeEvent();
// Make the selection of network stacks early on before any consumers try to
diff --git a/chrome/browser/browser_process_impl.cc b/chrome/browser/browser_process_impl.cc
index ad12c305..3b0560b 100644
--- a/chrome/browser/browser_process_impl.cc
+++ b/chrome/browser/browser_process_impl.cc
@@ -216,14 +216,10 @@ BrowserProcessImpl::~BrowserProcessImpl() {
g_browser_process = NULL;
}
-// Need to define this so InvokeLater on the MessageLoop works. It's ok
-// not to addref/release the MessageLoop here as we *know* the main thread
-// isn't going to go away on us.
-template <>
-struct RunnableMethodTraits<MessageLoop> {
- static void RetainCallee(MessageLoop* obj) { }
- static void ReleaseCallee(MessageLoop* obj) { }
-};
+// Send a QuitTask to the given MessageLoop.
+static void PostQuit(MessageLoop* message_loop) {
+ message_loop->PostTask(FROM_HERE, new MessageLoop::QuitTask());
+}
void BrowserProcessImpl::EndSession() {
// Notify we are going away.
@@ -249,7 +245,7 @@ void BrowserProcessImpl::EndSession() {
// otherwise on startup we'll think we crashed. So we block until done and
// then proceed with normal shutdown.
g_browser_process->file_thread()->message_loop()->PostTask(FROM_HERE,
- NewRunnableMethod(MessageLoop::current(), &MessageLoop::Quit));
+ NewRunnableFunction(PostQuit, MessageLoop::current()));
MessageLoop::current()->Run();
}
diff --git a/chrome/browser/navigation_controller_unittest.cc b/chrome/browser/navigation_controller_unittest.cc
index 51eeb67..cce2cf9 100644
--- a/chrome/browser/navigation_controller_unittest.cc
+++ b/chrome/browser/navigation_controller_unittest.cc
@@ -666,8 +666,7 @@ TEST_F(NavigationControllerTest, SwitchTypes) {
EXPECT_TRUE(contents->controller()->CanGoForward());
// There may be TabContentsCollector tasks pending, so flush them from queue.
- MessageLoop::current()->Quit();
- MessageLoop::current()->Run();
+ MessageLoop::current()->RunAllPending();
}
// Tests what happens when we begin to navigate to a new contents type, but
@@ -700,8 +699,7 @@ TEST_F(NavigationControllerTest, SwitchTypes_Discard) {
EXPECT_FALSE(contents->controller()->CanGoForward());
// There may be TabContentsCollector tasks pending, so flush them from queue.
- MessageLoop::current()->Quit();
- MessageLoop::current()->Run();
+ MessageLoop::current()->RunAllPending();
}
// Tests that TabContentsTypes that are not in use are deleted (via a
@@ -729,8 +727,7 @@ TEST_F(NavigationControllerTest, SwitchTypesCleanup) {
contents->CompleteNavigation(1);
// There may be TabContentsCollector tasks pending, so flush them from queue.
- MessageLoop::current()->Quit();
- MessageLoop::current()->Run();
+ MessageLoop::current()->RunAllPending();
// Now that the tasks have been flushed, the first tab type should be gone.
ASSERT_TRUE(
diff --git a/chrome/browser/printing/printing_layout_uitest.cc b/chrome/browser/printing/printing_layout_uitest.cc
index 87c2c13..c3e2060 100644
--- a/chrome/browser/printing/printing_layout_uitest.cc
+++ b/chrome/browser/printing/printing_layout_uitest.cc
@@ -492,7 +492,7 @@ class DismissTheWindow : public Task {
MessageLoop::current()->timer_manager()->StopTimer(timer_);
timer_ = NULL;
// Unlock the other thread.
- other_thread_->Quit();
+ other_thread_->PostTask(FROM_HERE, new MessageLoop::QuitTask());
} else {
// Maybe it's time to try to click it again. Restart from the begining.
dialog_window_ = NULL;
diff --git a/chrome/browser/render_process_host.cc b/chrome/browser/render_process_host.cc
index be36149..558a161 100644
--- a/chrome/browser/render_process_host.cc
+++ b/chrome/browser/render_process_host.cc
@@ -285,7 +285,6 @@ bool RenderProcessHost::Init() {
switches::kAllowAllActiveX,
switches::kMemoryProfiling,
switches::kEnableWatchdog,
- switches::kMessageLoopStrategy,
switches::kMessageLoopHistogrammer,
switches::kEnableDCHECK,
switches::kSilentDumpOnDCHECK,
diff --git a/chrome/browser/resource_dispatcher_host_unittest.cc b/chrome/browser/resource_dispatcher_host_unittest.cc
index f2d8154..7d00f6a 100644
--- a/chrome/browser/resource_dispatcher_host_unittest.cc
+++ b/chrome/browser/resource_dispatcher_host_unittest.cc
@@ -146,11 +146,7 @@ class ResourceDispatcherHostTest : public testing::Test,
// Spin up the message loop to kick off the request.
static void KickOffRequest() {
- // First we post a Quit message to the loop, causing it to terminate after
- // processing the messages it currently has queued up.
- MessageLoop::current()->Quit();
- // Then we spin up the loop.
- MessageLoop::current()->Run();
+ MessageLoop::current()->RunAllPending();
}
void ResourceDispatcherHostTest::MakeTestRequest(int request_id,
diff --git a/chrome/browser/site_instance_unittest.cc b/chrome/browser/site_instance_unittest.cc
index 61fb7f0..d1cb055 100644
--- a/chrome/browser/site_instance_unittest.cc
+++ b/chrome/browser/site_instance_unittest.cc
@@ -129,8 +129,7 @@ TEST(SiteInstanceTest, SiteInstanceDestructor) {
contents->CloseContents();
// Make sure that we flush any messages related to WebContents destruction.
- MessageLoop::current()->Quit();
- MessageLoop::current()->Run();
+ MessageLoop::current()->RunAllPending();
EXPECT_EQ(2, siteDeleteCounter);
EXPECT_EQ(2, browsingDeleteCounter);
diff --git a/chrome/browser/url_fetcher_unittest.cc b/chrome/browser/url_fetcher_unittest.cc
index 2a3b034..4948e27 100644
--- a/chrome/browser/url_fetcher_unittest.cc
+++ b/chrome/browser/url_fetcher_unittest.cc
@@ -157,7 +157,7 @@ namespace {
// because the destructor won't necessarily run on the
// same thread that CreateFetcher() did.
- main_loop_->Quit();
+ main_loop_->PostTask(FROM_HERE, new MessageLoop::QuitTask());
// If MessageLoop::current() != main_loop_, it will be shut down when the
// main loop returns and this thread subsequently goes out of scope.
}
@@ -209,7 +209,7 @@ namespace {
start_time_ = Time::Now();
fetcher_->Start();
}
-
+
void URLFetcherProtectTest::OnURLFetchComplete(const URLFetcher* source,
const GURL& url,
const URLRequestStatus& status,
@@ -224,7 +224,7 @@ namespace {
EXPECT_TRUE(status.is_success());
EXPECT_FALSE(data.empty());
delete fetcher_;
- main_loop_->Quit();
+ main_loop_->Quit();
} else {
// Now running Overload test.
static int count = 0;
diff --git a/chrome/browser/web_contents_unittest.cc b/chrome/browser/web_contents_unittest.cc
index 3b7450c..c62fcfd 100644
--- a/chrome/browser/web_contents_unittest.cc
+++ b/chrome/browser/web_contents_unittest.cc
@@ -316,8 +316,7 @@ class WebContentsTest : public testing::Test {
// Make sure that we flush any messages related to WebContents destruction
// before we destroy the profile.
- MessageLoop::current()->Quit();
- MessageLoop::current()->Run();
+ MessageLoop::current()->RunAllPending();
}
scoped_ptr<WebContentsTestingProfile> profile;
diff --git a/chrome/common/child_process.cc b/chrome/common/child_process.cc
index f501ba5..7d84338 100644
--- a/chrome/common/child_process.cc
+++ b/chrome/common/child_process.cc
@@ -68,7 +68,7 @@ bool ChildProcess::ProcessRefCountIsZero() {
void ChildProcess::OnFinalRelease() {
DCHECK(main_thread_loop_);
- main_thread_loop_->Quit();
+ main_thread_loop_->PostTask(FROM_HERE, new MessageLoop::QuitTask());
}
HANDLE ChildProcess::GetShutDownEvent() {
diff --git a/chrome/common/chrome_switches.cc b/chrome/common/chrome_switches.cc
index 5b9985e..47f3080 100644
--- a/chrome/common/chrome_switches.cc
+++ b/chrome/common/chrome_switches.cc
@@ -289,10 +289,6 @@ const wchar_t kEnableWatchdog[] = L"enable-watchdog";
// whether or not it's actually the first run.
const wchar_t kFirstRun[] = L"first-run";
-// Select an alternate message loop task dispatch strategy.
-// Usage -message-loop-strategy=n
-const wchar_t kMessageLoopStrategy[] = L"message-loop-strategy";
-
// Enable histograming of tasks served by MessageLoop. See about:histograms/Loop
// for results, which show frequency of messages on each thread, including APC
// count, object signalling count, etc.
diff --git a/chrome/common/chrome_switches.h b/chrome/common/chrome_switches.h
index 591eded..fbffc88 100644
--- a/chrome/common/chrome_switches.h
+++ b/chrome/common/chrome_switches.h
@@ -117,7 +117,6 @@ extern const wchar_t kEnableWatchdog[];
extern const wchar_t kFirstRun[];
-extern const wchar_t kMessageLoopStrategy[];
extern const wchar_t kMessageLoopHistogrammer[];
extern const wchar_t kImport[];
diff --git a/chrome/common/message_router.h b/chrome/common/message_router.h
index a5fabf4..0558646 100644
--- a/chrome/common/message_router.h
+++ b/chrome/common/message_router.h
@@ -30,6 +30,7 @@
#ifndef CHROME_COMMON_MESSAGE_ROUTER_H__
#define CHROME_COMMON_MESSAGE_ROUTER_H__
+#include "base/id_map.h"
#include "chrome/common/ipc_channel.h"
// The MessageRouter handles all incoming messages sent to it by routing them
diff --git a/chrome/renderer/render_thread.cc b/chrome/renderer/render_thread.cc
index ddc8ebd..5282cad 100644
--- a/chrome/renderer/render_thread.cc
+++ b/chrome/renderer/render_thread.cc
@@ -68,8 +68,7 @@ RenderThread::~RenderThread() {
}
void RenderThread::OnChannelError() {
- // XXX(darin): is this really correct/sufficient?
- owner_loop_->Quit();
+ owner_loop_->PostTask(FROM_HERE, new MessageLoop::QuitTask());
}
bool RenderThread::Send(IPC::Message* msg) {
diff --git a/chrome/test/automation/automation_proxy.cc b/chrome/test/automation/automation_proxy.cc
index 07e5387..6d98f0d 100644
--- a/chrome/test/automation/automation_proxy.cc
+++ b/chrome/test/automation/automation_proxy.cc
@@ -325,6 +325,10 @@ bool AutomationProxy::SetFilteredInet(bool enabled) {
return Send(new AutomationMsg_SetFilteredInet(0, enabled));
}
+void AutomationProxy::Disconnect() {
+ channel_.reset();
+}
+
void AutomationProxy::OnMessageReceived(const IPC::Message& msg) {
// This won't get called unless AutomationProxy is run from
// inside a message loop.
@@ -491,6 +495,15 @@ AutocompleteEditProxy* AutomationProxy::GetAutocompleteEditForBrowser(
autocomplete_edit_handle);
}
+bool AutomationProxy::Send(IPC::Message* message) {
+ if (channel_.get())
+ return channel_->Send(message);
+
+ DLOG(WARNING) << "Channel has been closed; dropping message!";
+ delete message;
+ return false;
+}
+
bool AutomationProxy::SendAndWaitForResponse(IPC::Message* request,
IPC::Message** response,
int response_type) {
diff --git a/chrome/test/automation/automation_proxy.h b/chrome/test/automation/automation_proxy.h
index e8d63b5..58ffbac 100644
--- a/chrome/test/automation/automation_proxy.h
+++ b/chrome/test/automation/automation_proxy.h
@@ -91,6 +91,9 @@ class AutomationProxy : public IPC::Channel::Listener,
virtual void OnMessageReceived(const IPC::Message& msg);
virtual void OnChannelError();
+ // Close the automation IPC channel.
+ void Disconnect();
+
// Waits for the app to launch and the automation provider to say hello
// (the app isn't fully done loading by this point).
// Returns true if the launch is successful
@@ -188,7 +191,7 @@ class AutomationProxy : public IPC::Channel::Listener,
const std::wstring& channel_id() const { return channel_id_; }
// AutomationMessageSender implementations.
- virtual bool Send(IPC::Message* message) { return channel_->Send(message); }
+ virtual bool Send(IPC::Message* message);
virtual bool SendAndWaitForResponse(IPC::Message* request,
IPC::Message** response,
int response_type);
@@ -211,7 +214,8 @@ class AutomationProxy : public IPC::Channel::Listener,
// Creates a tab that can hosted in an external process. The function
// returns a TabProxy representing the tab as well as a window handle
// that can be reparented in another process.
- TabProxy* AutomationProxy::CreateExternalTab(HWND* external_tab_container);
+ TabProxy* CreateExternalTab(HWND* external_tab_container);
+
private:
DISALLOW_EVIL_CONSTRUCTORS(AutomationProxy);
diff --git a/chrome/test/ui/ui_test.cc b/chrome/test/ui/ui_test.cc
index cd439118..439846f 100644
--- a/chrome/test/ui/ui_test.cc
+++ b/chrome/test/ui/ui_test.cc
@@ -296,6 +296,10 @@ void UITest::QuitBrowser() {
++iter) {
::PostMessage(*iter, WM_CLOSE, 0, 0);
}
+
+ // Now, drop the automation IPC channel so that the automation provider in
+ // the browser notices and drops its reference to the browser process.
+ server_->Disconnect();
// Wait for the browser process to quit. It should quit once all tabs have
// been closed.