blob: ac30470579f75d2632eef708a7d227042ebc67b1 [file] [log] [blame]
// 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/automation/testing_automation_provider.h"
#include "base/command_line.h"
#include "base/utf_string_conversions.h"
#include "chrome/app/chrome_dll_resource.h"
#include "chrome/browser/automation/automation_browser_tracker.h"
#include "chrome/browser/automation/automation_provider_list.h"
#include "chrome/browser/automation/automation_provider_observers.h"
#include "chrome/browser/automation/automation_tab_tracker.h"
#include "chrome/browser/automation/automation_window_tracker.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/browser_window.h"
#include "chrome/browser/login_prompt.h"
#include "chrome/browser/platform_util.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/net/url_request_context_getter.h"
#include "chrome/common/notification_service.h"
#include "chrome/test/automation/automation_messages.h"
#include "net/url_request/url_request_context.h"
namespace {
class GetCookiesTask : public Task {
public:
GetCookiesTask(const GURL& url,
URLRequestContextGetter* context_getter,
base::WaitableEvent* event,
std::string* cookies)
: url_(url),
context_getter_(context_getter),
event_(event),
cookies_(cookies) {}
virtual void Run() {
*cookies_ = context_getter_->GetCookieStore()->GetCookies(url_);
event_->Signal();
}
private:
const GURL& url_;
URLRequestContextGetter* const context_getter_;
base::WaitableEvent* const event_;
std::string* const cookies_;
DISALLOW_COPY_AND_ASSIGN(GetCookiesTask);
};
std::string GetCookiesForURL(
const GURL& url,
URLRequestContextGetter* context_getter) {
std::string cookies;
base::WaitableEvent event(true /* manual reset */,
false /* not initially signaled */);
CHECK(ChromeThread::PostTask(
ChromeThread::IO, FROM_HERE,
new GetCookiesTask(url, context_getter, &event, &cookies)));
event.Wait();
return cookies;
}
class SetCookieTask : public Task {
public:
SetCookieTask(const GURL& url,
const std::string& value,
URLRequestContextGetter* context_getter,
base::WaitableEvent* event,
bool* rv)
: url_(url),
value_(value),
context_getter_(context_getter),
event_(event),
rv_(rv) {}
virtual void Run() {
*rv_ = context_getter_->GetCookieStore()->SetCookie(url_, value_);
event_->Signal();
}
private:
const GURL& url_;
const std::string& value_;
URLRequestContextGetter* const context_getter_;
base::WaitableEvent* const event_;
bool* const rv_;
DISALLOW_COPY_AND_ASSIGN(SetCookieTask);
};
bool SetCookieForURL(
const GURL& url,
const std::string& value,
URLRequestContextGetter* context_getter) {
base::WaitableEvent event(true /* manual reset */,
false /* not initially signaled */);
bool rv = false;
CHECK(ChromeThread::PostTask(
ChromeThread::IO, FROM_HERE,
new SetCookieTask(url, value, context_getter, &event, &rv)));
event.Wait();
return rv;
}
class DeleteCookieTask : public Task {
public:
DeleteCookieTask(const GURL& url,
const std::string& name,
const scoped_refptr<URLRequestContextGetter>& context_getter)
: url_(url),
name_(name),
context_getter_(context_getter) {}
virtual void Run() {
net::CookieStore* cookie_store = context_getter_->GetCookieStore();
cookie_store->DeleteCookie(url_, name_);
}
private:
const GURL url_;
const std::string name_;
const scoped_refptr<URLRequestContextGetter> context_getter_;
DISALLOW_COPY_AND_ASSIGN(DeleteCookieTask);
};
} // namespace
TestingAutomationProvider::TestingAutomationProvider(Profile* profile)
: AutomationProvider(profile),
redirect_query_(0) {
BrowserList::AddObserver(this);
registrar_.Add(this, NotificationType::SESSION_END,
NotificationService::AllSources());
}
TestingAutomationProvider::~TestingAutomationProvider() {
BrowserList::RemoveObserver(this);
}
void TestingAutomationProvider::OnMessageReceived(
const IPC::Message& message) {
IPC_BEGIN_MESSAGE_MAP(TestingAutomationProvider, message)
IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_CloseBrowser, CloseBrowser)
IPC_MESSAGE_HANDLER(AutomationMsg_CloseBrowserRequestAsync,
CloseBrowserAsync)
IPC_MESSAGE_HANDLER(AutomationMsg_ActivateTab, ActivateTab)
IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_AppendTab, AppendTab)
IPC_MESSAGE_HANDLER(AutomationMsg_ActiveTabIndex, GetActiveTabIndex)
IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_CloseTab, CloseTab)
IPC_MESSAGE_HANDLER(AutomationMsg_GetCookies, GetCookies)
IPC_MESSAGE_HANDLER(AutomationMsg_SetCookie, SetCookie)
IPC_MESSAGE_HANDLER(AutomationMsg_DeleteCookie, DeleteCookie)
IPC_MESSAGE_HANDLER(AutomationMsg_ShowCollectedCookiesDialog,
ShowCollectedCookiesDialog)
IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_NavigateToURL, NavigateToURL)
IPC_MESSAGE_HANDLER_DELAY_REPLY(
AutomationMsg_NavigateToURLBlockUntilNavigationsComplete,
NavigateToURLBlockUntilNavigationsComplete)
IPC_MESSAGE_HANDLER(AutomationMsg_NavigationAsync, NavigationAsync)
IPC_MESSAGE_HANDLER(AutomationMsg_NavigationAsyncWithDisposition,
NavigationAsyncWithDisposition)
IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_GoBack, GoBack)
IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_GoForward, GoForward)
IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_Reload, Reload)
IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_SetAuth, SetAuth)
IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_CancelAuth, CancelAuth)
IPC_MESSAGE_HANDLER(AutomationMsg_NeedsAuth, NeedsAuth)
IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_RedirectsFrom,
GetRedirectsFrom)
IPC_MESSAGE_HANDLER(AutomationMsg_BrowserWindowCount, GetBrowserWindowCount)
IPC_MESSAGE_HANDLER(AutomationMsg_NormalBrowserWindowCount,
GetNormalBrowserWindowCount)
IPC_MESSAGE_HANDLER(AutomationMsg_BrowserWindow, GetBrowserWindow)
IPC_MESSAGE_HANDLER(AutomationMsg_GetBrowserLocale, GetBrowserLocale)
IPC_MESSAGE_HANDLER(AutomationMsg_LastActiveBrowserWindow,
GetLastActiveBrowserWindow)
IPC_MESSAGE_HANDLER(AutomationMsg_ActiveWindow, GetActiveWindow)
IPC_MESSAGE_HANDLER(AutomationMsg_FindNormalBrowserWindow,
FindNormalBrowserWindow)
IPC_MESSAGE_HANDLER(AutomationMsg_IsWindowActive, IsWindowActive)
IPC_MESSAGE_HANDLER(AutomationMsg_ActivateWindow, ActivateWindow)
IPC_MESSAGE_HANDLER(AutomationMsg_IsWindowMaximized, IsWindowMaximized)
IPC_MESSAGE_HANDLER(AutomationMsg_WindowExecuteCommandAsync,
ExecuteBrowserCommandAsync)
IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_WindowExecuteCommand,
ExecuteBrowserCommand)
IPC_MESSAGE_UNHANDLED(AutomationProvider::OnMessageReceived(message));
IPC_END_MESSAGE_MAP()
}
void TestingAutomationProvider::OnChannelError() {
BrowserList::CloseAllBrowsersAndExit();
AutomationProvider::OnChannelError();
}
void TestingAutomationProvider::CloseBrowser(int browser_handle,
IPC::Message* reply_message) {
if (browser_tracker_->ContainsHandle(browser_handle)) {
Browser* browser = browser_tracker_->GetResource(browser_handle);
new BrowserClosedNotificationObserver(browser, this,
reply_message);
browser->window()->Close();
} else {
NOTREACHED();
}
}
void TestingAutomationProvider::CloseBrowserAsync(int browser_handle) {
if (browser_tracker_->ContainsHandle(browser_handle)) {
Browser* browser = browser_tracker_->GetResource(browser_handle);
browser->window()->Close();
} else {
NOTREACHED();
}
}
void TestingAutomationProvider::ActivateTab(int handle,
int at_index,
int* status) {
*status = -1;
if (browser_tracker_->ContainsHandle(handle) && at_index > -1) {
Browser* browser = browser_tracker_->GetResource(handle);
if (at_index >= 0 && at_index < browser->tab_count()) {
browser->SelectTabContentsAt(at_index, true);
*status = 0;
}
}
}
void TestingAutomationProvider::AppendTab(int handle, const GURL& url,
IPC::Message* reply_message) {
int append_tab_response = -1; // -1 is the error code
NotificationObserver* observer = NULL;
if (browser_tracker_->ContainsHandle(handle)) {
Browser* browser = browser_tracker_->GetResource(handle);
observer = AddTabStripObserver(browser, reply_message);
TabContents* tab_contents = browser->AddTabWithURL(
url, GURL(), PageTransition::TYPED, -1, TabStripModel::ADD_SELECTED,
NULL, std::string(), &browser);
if (tab_contents) {
append_tab_response =
GetIndexForNavigationController(&tab_contents->controller(), browser);
}
}
if (append_tab_response < 0) {
// The append tab failed. Remove the TabStripObserver
if (observer) {
RemoveTabStripObserver(observer);
delete observer;
}
AutomationMsg_AppendTab::WriteReplyParams(reply_message,
append_tab_response);
Send(reply_message);
}
}
void TestingAutomationProvider::GetActiveTabIndex(int handle,
int* active_tab_index) {
*active_tab_index = -1; // -1 is the error code
if (browser_tracker_->ContainsHandle(handle)) {
Browser* browser = browser_tracker_->GetResource(handle);
*active_tab_index = browser->selected_index();
}
}
void TestingAutomationProvider::CloseTab(int tab_handle,
bool wait_until_closed,
IPC::Message* reply_message) {
if (tab_tracker_->ContainsHandle(tab_handle)) {
NavigationController* controller = tab_tracker_->GetResource(tab_handle);
int index;
Browser* browser = Browser::GetBrowserForController(controller, &index);
DCHECK(browser);
new TabClosedNotificationObserver(this, wait_until_closed, reply_message);
browser->CloseTabContents(controller->tab_contents());
return;
}
AutomationMsg_CloseTab::WriteReplyParams(reply_message, false);
Send(reply_message);
}
void TestingAutomationProvider::GetCookies(const GURL& url, int handle,
int* value_size,
std::string* value) {
*value_size = -1;
if (url.is_valid() && tab_tracker_->ContainsHandle(handle)) {
NavigationController* tab = tab_tracker_->GetResource(handle);
// Since we are running on the UI thread don't call GetURLRequestContext().
*value = GetCookiesForURL(url, tab->profile()->GetRequestContext());
*value_size = static_cast<int>(value->size());
}
}
void TestingAutomationProvider::SetCookie(const GURL& url,
const std::string value,
int handle,
int* response_value) {
*response_value = -1;
if (url.is_valid() && tab_tracker_->ContainsHandle(handle)) {
NavigationController* tab = tab_tracker_->GetResource(handle);
if (SetCookieForURL(url, value, tab->profile()->GetRequestContext()))
*response_value = 1;
}
}
void TestingAutomationProvider::DeleteCookie(const GURL& url,
const std::string& cookie_name,
int handle, bool* success) {
*success = false;
if (url.is_valid() && tab_tracker_->ContainsHandle(handle)) {
NavigationController* tab = tab_tracker_->GetResource(handle);
ChromeThread::PostTask(
ChromeThread::IO, FROM_HERE,
new DeleteCookieTask(url, cookie_name,
tab->profile()->GetRequestContext()));
*success = true;
}
}
void TestingAutomationProvider::ShowCollectedCookiesDialog(
int handle, bool* success) {
*success = false;
if (tab_tracker_->ContainsHandle(handle)) {
TabContents* tab_contents =
tab_tracker_->GetResource(handle)->tab_contents();
tab_contents->delegate()->ShowCollectedCookiesDialog(tab_contents);
*success = true;
}
}
void TestingAutomationProvider::NavigateToURL(int handle,
const GURL& url,
IPC::Message* reply_message) {
NavigateToURLBlockUntilNavigationsComplete(handle, url, 1, reply_message);
}
void TestingAutomationProvider::NavigateToURLBlockUntilNavigationsComplete(
int handle, const GURL& url, int number_of_navigations,
IPC::Message* reply_message) {
if (tab_tracker_->ContainsHandle(handle)) {
NavigationController* tab = tab_tracker_->GetResource(handle);
// Simulate what a user would do. Activate the tab and then navigate.
// We could allow navigating in a background tab in future.
Browser* browser = FindAndActivateTab(tab);
if (browser) {
AddNavigationStatusListener(tab, reply_message, number_of_navigations,
false);
// TODO(darin): avoid conversion to GURL
browser->OpenURL(url, GURL(), CURRENT_TAB, PageTransition::TYPED);
return;
}
}
AutomationMsg_NavigateToURL::WriteReplyParams(
reply_message, AUTOMATION_MSG_NAVIGATION_ERROR);
Send(reply_message);
}
void TestingAutomationProvider::NavigationAsync(int handle,
const GURL& url,
bool* status) {
NavigationAsyncWithDisposition(handle, url, CURRENT_TAB, status);
}
void TestingAutomationProvider::NavigationAsyncWithDisposition(
int handle,
const GURL& url,
WindowOpenDisposition disposition,
bool* status) {
*status = false;
if (tab_tracker_->ContainsHandle(handle)) {
NavigationController* tab = tab_tracker_->GetResource(handle);
// Simulate what a user would do. Activate the tab and then navigate.
// We could allow navigating in a background tab in future.
Browser* browser = FindAndActivateTab(tab);
if (browser) {
// Don't add any listener unless a callback mechanism is desired.
// TODO(vibhor): Do this if such a requirement arises in future.
browser->OpenURL(url, GURL(), disposition, PageTransition::TYPED);
*status = true;
}
}
}
void TestingAutomationProvider::GoBack(int handle,
IPC::Message* reply_message) {
if (tab_tracker_->ContainsHandle(handle)) {
NavigationController* tab = tab_tracker_->GetResource(handle);
Browser* browser = FindAndActivateTab(tab);
if (browser && browser->command_updater()->IsCommandEnabled(IDC_BACK)) {
AddNavigationStatusListener(tab, reply_message, 1, false);
browser->GoBack(CURRENT_TAB);
return;
}
}
AutomationMsg_GoBack::WriteReplyParams(
reply_message, AUTOMATION_MSG_NAVIGATION_ERROR);
Send(reply_message);
}
void TestingAutomationProvider::GoForward(int handle,
IPC::Message* reply_message) {
if (tab_tracker_->ContainsHandle(handle)) {
NavigationController* tab = tab_tracker_->GetResource(handle);
Browser* browser = FindAndActivateTab(tab);
if (browser && browser->command_updater()->IsCommandEnabled(IDC_FORWARD)) {
AddNavigationStatusListener(tab, reply_message, 1, false);
browser->GoForward(CURRENT_TAB);
return;
}
}
AutomationMsg_GoForward::WriteReplyParams(
reply_message, AUTOMATION_MSG_NAVIGATION_ERROR);
Send(reply_message);
}
void TestingAutomationProvider::Reload(int handle,
IPC::Message* reply_message) {
if (tab_tracker_->ContainsHandle(handle)) {
NavigationController* tab = tab_tracker_->GetResource(handle);
Browser* browser = FindAndActivateTab(tab);
if (browser && browser->command_updater()->IsCommandEnabled(IDC_RELOAD)) {
AddNavigationStatusListener(tab, reply_message, 1, false);
browser->Reload(CURRENT_TAB);
return;
}
}
AutomationMsg_Reload::WriteReplyParams(
reply_message, AUTOMATION_MSG_NAVIGATION_ERROR);
Send(reply_message);
}
void TestingAutomationProvider::SetAuth(int tab_handle,
const std::wstring& username,
const std::wstring& password,
IPC::Message* reply_message) {
if (tab_tracker_->ContainsHandle(tab_handle)) {
NavigationController* tab = tab_tracker_->GetResource(tab_handle);
LoginHandlerMap::iterator iter = login_handler_map_.find(tab);
if (iter != login_handler_map_.end()) {
// If auth is needed again after this, assume login has failed. This is
// not strictly correct, because a navigation can require both proxy and
// server auth, but it should be OK for now.
LoginHandler* handler = iter->second;
AddNavigationStatusListener(tab, reply_message, 1, false);
handler->SetAuth(username, password);
return;
}
}
AutomationMsg_SetAuth::WriteReplyParams(
reply_message, AUTOMATION_MSG_NAVIGATION_AUTH_NEEDED);
Send(reply_message);
}
void TestingAutomationProvider::CancelAuth(int tab_handle,
IPC::Message* reply_message) {
if (tab_tracker_->ContainsHandle(tab_handle)) {
NavigationController* tab = tab_tracker_->GetResource(tab_handle);
LoginHandlerMap::iterator iter = login_handler_map_.find(tab);
if (iter != login_handler_map_.end()) {
// If auth is needed again after this, something is screwy.
LoginHandler* handler = iter->second;
AddNavigationStatusListener(tab, reply_message, 1, false);
handler->CancelAuth();
return;
}
}
AutomationMsg_CancelAuth::WriteReplyParams(
reply_message, AUTOMATION_MSG_NAVIGATION_AUTH_NEEDED);
Send(reply_message);
}
void TestingAutomationProvider::NeedsAuth(int tab_handle, bool* needs_auth) {
*needs_auth = false;
if (tab_tracker_->ContainsHandle(tab_handle)) {
NavigationController* tab = tab_tracker_->GetResource(tab_handle);
LoginHandlerMap::iterator iter = login_handler_map_.find(tab);
if (iter != login_handler_map_.end()) {
// The LoginHandler will be in our map IFF the tab needs auth.
*needs_auth = true;
}
}
}
void TestingAutomationProvider::GetRedirectsFrom(int tab_handle,
const GURL& source_url,
IPC::Message* reply_message) {
DCHECK(!redirect_query_) << "Can only handle one redirect query at once.";
if (tab_tracker_->ContainsHandle(tab_handle)) {
NavigationController* tab = tab_tracker_->GetResource(tab_handle);
HistoryService* history_service =
tab->profile()->GetHistoryService(Profile::EXPLICIT_ACCESS);
DCHECK(history_service) << "Tab " << tab_handle << "'s profile " <<
"has no history service";
if (history_service) {
DCHECK(reply_message_ == NULL);
reply_message_ = reply_message;
// Schedule a history query for redirects. The response will be sent
// asynchronously from the callback the history system uses to notify us
// that it's done: OnRedirectQueryComplete.
redirect_query_ = history_service->QueryRedirectsFrom(
source_url, &consumer_,
NewCallback(this,
&TestingAutomationProvider::OnRedirectQueryComplete));
return; // Response will be sent when query completes.
}
}
// Send failure response.
std::vector<GURL> empty;
AutomationMsg_RedirectsFrom::WriteReplyParams(reply_message, false, empty);
Send(reply_message);
}
void TestingAutomationProvider::GetBrowserWindowCount(int* window_count) {
*window_count = static_cast<int>(BrowserList::size());
}
void TestingAutomationProvider::GetNormalBrowserWindowCount(int* window_count) {
*window_count = static_cast<int>(
BrowserList::GetBrowserCountForType(profile_, Browser::TYPE_NORMAL));
}
void TestingAutomationProvider::GetBrowserWindow(int index, int* handle) {
*handle = 0;
if (index >= 0) {
BrowserList::const_iterator iter = BrowserList::begin();
for (; (iter != BrowserList::end()) && (index > 0); ++iter, --index) {}
if (iter != BrowserList::end()) {
*handle = browser_tracker_->Add(*iter);
}
}
}
void TestingAutomationProvider::FindNormalBrowserWindow(int* handle) {
*handle = 0;
Browser* browser = BrowserList::FindBrowserWithType(profile_,
Browser::TYPE_NORMAL,
false);
if (browser)
*handle = browser_tracker_->Add(browser);
}
void TestingAutomationProvider::GetLastActiveBrowserWindow(int* handle) {
*handle = 0;
Browser* browser = BrowserList::GetLastActive();
if (browser)
*handle = browser_tracker_->Add(browser);
}
void TestingAutomationProvider::GetActiveWindow(int* handle) {
gfx::NativeWindow window =
BrowserList::GetLastActive()->window()->GetNativeHandle();
*handle = window_tracker_->Add(window);
}
void TestingAutomationProvider::ExecuteBrowserCommandAsync(int handle,
int command,
bool* success) {
*success = false;
if (browser_tracker_->ContainsHandle(handle)) {
Browser* browser = browser_tracker_->GetResource(handle);
if (browser->command_updater()->SupportsCommand(command) &&
browser->command_updater()->IsCommandEnabled(command)) {
browser->ExecuteCommand(command);
*success = true;
}
}
}
void TestingAutomationProvider::ExecuteBrowserCommand(
int handle, int command, IPC::Message* reply_message) {
// List of commands which just finish synchronously and don't require
// setting up an observer.
static const int kSynchronousCommands[] = {
IDC_HOME,
IDC_SELECT_NEXT_TAB,
IDC_SELECT_PREVIOUS_TAB,
IDC_SHOW_BOOKMARK_MANAGER,
};
if (browser_tracker_->ContainsHandle(handle)) {
Browser* browser = browser_tracker_->GetResource(handle);
if (browser->command_updater()->SupportsCommand(command) &&
browser->command_updater()->IsCommandEnabled(command)) {
// First check if we can handle the command without using an observer.
for (size_t i = 0; i < arraysize(kSynchronousCommands); i++) {
if (command == kSynchronousCommands[i]) {
browser->ExecuteCommand(command);
AutomationMsg_WindowExecuteCommand::WriteReplyParams(reply_message,
true);
Send(reply_message);
return;
}
}
// Use an observer if we have one, otherwise fail.
if (ExecuteBrowserCommandObserver::CreateAndRegisterObserver(
this, browser, command, reply_message)) {
browser->ExecuteCommand(command);
return;
}
}
}
AutomationMsg_WindowExecuteCommand::WriteReplyParams(reply_message, false);
Send(reply_message);
}
void TestingAutomationProvider::GetBrowserLocale(string16* locale) {
DCHECK(g_browser_process);
*locale = ASCIIToUTF16(g_browser_process->GetApplicationLocale());
}
void TestingAutomationProvider::IsWindowActive(int handle,
bool* success,
bool* is_active) {
if (window_tracker_->ContainsHandle(handle)) {
*is_active =
platform_util::IsWindowActive(window_tracker_->GetResource(handle));
*success = true;
} else {
*success = false;
*is_active = false;
}
}
// TODO(brettw) change this to accept GURLs when history supports it
void TestingAutomationProvider::OnRedirectQueryComplete(
HistoryService::Handle request_handle,
GURL from_url,
bool success,
history::RedirectList* redirects) {
DCHECK(request_handle == redirect_query_);
DCHECK(reply_message_ != NULL);
std::vector<GURL> redirects_gurl;
reply_message_->WriteBool(success);
if (success) {
for (size_t i = 0; i < redirects->size(); i++)
redirects_gurl.push_back(redirects->at(i));
}
IPC::ParamTraits<std::vector<GURL> >::Write(reply_message_, redirects_gurl);
Send(reply_message_);
redirect_query_ = 0;
reply_message_ = NULL;
}
void TestingAutomationProvider::OnBrowserAdded(const Browser* browser) {
}
void TestingAutomationProvider::OnBrowserRemoving(const Browser* browser) {
// For backwards compatibility with the testing automation interface, we
// want the automation provider (and hence the process) to go away when the
// last browser goes away.
if (BrowserList::size() == 1 && !CommandLine::ForCurrentProcess()->HasSwitch(
switches::kKeepAliveForTest)) {
// If you change this, update Observer for NotificationType::SESSION_END
// below.
MessageLoop::current()->PostTask(FROM_HERE,
NewRunnableMethod(this, &TestingAutomationProvider::OnRemoveProvider));
}
}
void TestingAutomationProvider::Observe(NotificationType type,
const NotificationSource& source,
const NotificationDetails& details) {
DCHECK(type == NotificationType::SESSION_END);
// OnBrowserRemoving does a ReleaseLater. When session end is received we exit
// before the task runs resulting in this object not being deleted. This
// Release balance out the Release scheduled by OnBrowserRemoving.
Release();
}
void TestingAutomationProvider::OnRemoveProvider() {
AutomationProviderList::GetInstance()->RemoveProvider(this);
}