| Index: chrome_frame/chrome_frame_automation.cc
|
| diff --git a/chrome_frame/chrome_frame_automation.cc b/chrome_frame/chrome_frame_automation.cc
|
| deleted file mode 100644
|
| index bd75d6f67fc2616d189df2b063a4482fe2f4fd5c..0000000000000000000000000000000000000000
|
| --- a/chrome_frame/chrome_frame_automation.cc
|
| +++ /dev/null
|
| @@ -1,847 +0,0 @@
|
| -// Copyright (c) 2012 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_frame/chrome_frame_automation.h"
|
| -
|
| -#include "base/bind.h"
|
| -#include "base/bind_helpers.h"
|
| -#include "base/callback.h"
|
| -#include "base/command_line.h"
|
| -#include "base/compiler_specific.h"
|
| -#include "base/debug/trace_event.h"
|
| -#include "base/file_version_info.h"
|
| -#include "base/lazy_instance.h"
|
| -#include "base/logging.h"
|
| -#include "base/path_service.h"
|
| -#include "base/process/launch.h"
|
| -#include "base/strings/string_util.h"
|
| -#include "base/strings/utf_string_conversions.h"
|
| -#include "base/synchronization/lock.h"
|
| -#include "base/synchronization/waitable_event.h"
|
| -#include "base/sys_info.h"
|
| -#include "chrome/app/client_util.h"
|
| -#include "chrome/common/automation_messages.h"
|
| -#include "chrome/common/chrome_constants.h"
|
| -#include "chrome/common/chrome_switches.h"
|
| -#include "chrome/test/automation/tab_proxy.h"
|
| -#include "chrome_frame/chrome_launcher_utils.h"
|
| -#include "chrome_frame/crash_reporting/crash_metrics.h"
|
| -#include "chrome_frame/custom_sync_call_context.h"
|
| -#include "chrome_frame/navigation_constraints.h"
|
| -#include "chrome_frame/simple_resource_loader.h"
|
| -#include "chrome_frame/utils.h"
|
| -#include "ui/base/ui_base_switches.h"
|
| -
|
| -namespace {
|
| -
|
| -#ifdef NDEBUG
|
| -int64 kAutomationServerReasonableLaunchDelay = 1000; // in milliseconds
|
| -#else
|
| -int64 kAutomationServerReasonableLaunchDelay = 1000 * 10;
|
| -#endif
|
| -
|
| -} // namespace
|
| -
|
| -class ChromeFrameAutomationProxyImpl::TabProxyNotificationMessageFilter
|
| - : public IPC::ChannelProxy::MessageFilter {
|
| - public:
|
| - explicit TabProxyNotificationMessageFilter(AutomationHandleTracker* tracker)
|
| - : tracker_(tracker) {
|
| - }
|
| -
|
| - void AddTabProxy(AutomationHandle tab_proxy) {
|
| - base::AutoLock lock(lock_);
|
| - tabs_list_.push_back(tab_proxy);
|
| - }
|
| -
|
| - void RemoveTabProxy(AutomationHandle tab_proxy) {
|
| - base::AutoLock lock(lock_);
|
| - tabs_list_.remove(tab_proxy);
|
| - }
|
| -
|
| - virtual bool OnMessageReceived(const IPC::Message& message) {
|
| - if (message.is_reply())
|
| - return false;
|
| -
|
| - if (!ChromeFrameDelegateImpl::IsTabMessage(message))
|
| - return false;
|
| -
|
| - // Get AddRef-ed pointer to corresponding TabProxy object
|
| - TabProxy* tab = static_cast<TabProxy*>(tracker_->GetResource(
|
| - message.routing_id()));
|
| - bool handled = false;
|
| - if (tab) {
|
| - handled = tab->OnMessageReceived(message);
|
| - tab->Release();
|
| - } else {
|
| - DLOG(ERROR) << "Failed to find TabProxy for tab:" << message.routing_id();
|
| - // To prevent subsequent crashes, we set handled to true in this case.
|
| - handled = true;
|
| - }
|
| - return handled;
|
| - }
|
| -
|
| - virtual void OnChannelError() {
|
| - std::list<AutomationHandle>::const_iterator iter = tabs_list_.begin();
|
| - for (; iter != tabs_list_.end(); ++iter) {
|
| - // Get AddRef-ed pointer to corresponding TabProxy object
|
| - TabProxy* tab = static_cast<TabProxy*>(tracker_->GetResource(*iter));
|
| - if (tab) {
|
| - tab->OnChannelError();
|
| - tab->Release();
|
| - }
|
| - }
|
| - }
|
| -
|
| - private:
|
| - AutomationHandleTracker* tracker_;
|
| - std::list<AutomationHandle> tabs_list_;
|
| - base::Lock lock_;
|
| -};
|
| -
|
| -class ChromeFrameAutomationProxyImpl::CFMsgDispatcher
|
| - : public SyncMessageReplyDispatcher {
|
| - public:
|
| - CFMsgDispatcher() : SyncMessageReplyDispatcher() {}
|
| - protected:
|
| - virtual bool HandleMessageType(const IPC::Message& msg,
|
| - SyncMessageCallContext* context) {
|
| - return true;
|
| - }
|
| -};
|
| -
|
| -ChromeFrameAutomationProxyImpl::ChromeFrameAutomationProxyImpl(
|
| - AutomationProxyCacheEntry* entry,
|
| - std::string channel_id, base::TimeDelta launch_timeout)
|
| - : AutomationProxy(launch_timeout, false), proxy_entry_(entry) {
|
| - TRACE_EVENT_BEGIN_ETW("chromeframe.automationproxy", this, "");
|
| -
|
| - InitializeChannel(channel_id, false);
|
| -
|
| - sync_ = new CFMsgDispatcher();
|
| - message_filter_ = new TabProxyNotificationMessageFilter(tracker_.get());
|
| -
|
| - // Order of filters is not important.
|
| - channel_->AddFilter(message_filter_.get());
|
| - channel_->AddFilter(sync_.get());
|
| -}
|
| -
|
| -ChromeFrameAutomationProxyImpl::~ChromeFrameAutomationProxyImpl() {
|
| - TRACE_EVENT_END_ETW("chromeframe.automationproxy", this, "");
|
| -}
|
| -
|
| -void ChromeFrameAutomationProxyImpl::SendAsAsync(
|
| - IPC::SyncMessage* msg,
|
| - SyncMessageReplyDispatcher::SyncMessageCallContext* context, void* key) {
|
| - sync_->Push(msg, context, key);
|
| - channel_->ChannelProxy::Send(msg);
|
| -}
|
| -
|
| -void ChromeFrameAutomationProxyImpl::CancelAsync(void* key) {
|
| - sync_->Cancel(key);
|
| -}
|
| -
|
| -void ChromeFrameAutomationProxyImpl::OnChannelError() {
|
| - DLOG(ERROR) << "Automation server died";
|
| - if (proxy_entry_) {
|
| - proxy_entry_->OnChannelError();
|
| - } else {
|
| - NOTREACHED();
|
| - }
|
| -}
|
| -
|
| -scoped_refptr<TabProxy> ChromeFrameAutomationProxyImpl::CreateTabProxy(
|
| - int handle) {
|
| - DCHECK(tracker_->GetResource(handle) == NULL);
|
| - TabProxy* tab_proxy = new TabProxy(this, tracker_.get(), handle);
|
| - if (tab_proxy != NULL)
|
| - message_filter_->AddTabProxy(handle);
|
| - return tab_proxy;
|
| -}
|
| -
|
| -void ChromeFrameAutomationProxyImpl::ReleaseTabProxy(AutomationHandle handle) {
|
| - message_filter_->RemoveTabProxy(handle);
|
| -}
|
| -
|
| -struct LaunchTimeStats {
|
| -#ifndef NDEBUG
|
| - LaunchTimeStats() {
|
| - launch_time_begin_ = base::Time::Now();
|
| - }
|
| -
|
| - void Dump() {
|
| - base::TimeDelta launch_time = base::Time::Now() - launch_time_begin_;
|
| - UMA_HISTOGRAM_TIMES("ChromeFrame.AutomationServerLaunchTime", launch_time);
|
| - const int64 launch_milliseconds = launch_time.InMilliseconds();
|
| - if (launch_milliseconds > kAutomationServerReasonableLaunchDelay) {
|
| - LOG(WARNING) << "Automation server launch took longer than expected: " <<
|
| - launch_milliseconds << " ms.";
|
| - }
|
| - }
|
| -
|
| - base::Time launch_time_begin_;
|
| -#else
|
| - void Dump() {}
|
| -#endif
|
| -};
|
| -
|
| -AutomationProxyCacheEntry::AutomationProxyCacheEntry(
|
| - ChromeFrameLaunchParams* params, LaunchDelegate* delegate)
|
| - : profile_name(params->profile_name()),
|
| - launch_result_(AUTOMATION_LAUNCH_RESULT_INVALID) {
|
| - DCHECK(delegate);
|
| - thread_.reset(new base::Thread(WideToASCII(profile_name).c_str()));
|
| - thread_->Start();
|
| - // Use scoped_refptr so that the params will get released when the task
|
| - // has been run.
|
| - scoped_refptr<ChromeFrameLaunchParams> ref_params(params);
|
| - thread_->message_loop()->PostTask(
|
| - FROM_HERE, base::Bind(&AutomationProxyCacheEntry::CreateProxy,
|
| - base::Unretained(this), ref_params, delegate));
|
| -}
|
| -
|
| -AutomationProxyCacheEntry::~AutomationProxyCacheEntry() {
|
| - DVLOG(1) << __FUNCTION__ << profile_name;
|
| - // Attempt to fix chrome_frame_tests crash seen at times on the IE6/IE7
|
| - // builders. It appears that there are cases when we can enter here when the
|
| - // AtExitManager is tearing down the global ProxyCache which causes a crash
|
| - // while tearing down the AutomationProxy object due to a NULL MessageLoop
|
| - // The AutomationProxy class uses the SyncChannel which assumes the existence
|
| - // of a MessageLoop instance.
|
| - // We leak the AutomationProxy pointer here to avoid a crash.
|
| - if (base::MessageLoop::current() == NULL) {
|
| - proxy_.release();
|
| - }
|
| -}
|
| -
|
| -void AutomationProxyCacheEntry::CreateProxy(ChromeFrameLaunchParams* params,
|
| - LaunchDelegate* delegate) {
|
| - DCHECK(IsSameThread(base::PlatformThread::CurrentId()));
|
| - DCHECK(delegate);
|
| - DCHECK(params);
|
| - DCHECK(proxy_.get() == NULL);
|
| -
|
| - // We *must* create automationproxy in a thread that has message loop,
|
| - // since SyncChannel::Context construction registers event to be watched
|
| - // through ObjectWatcher which subscribes for the current thread message loop
|
| - // destruction notification.
|
| -
|
| - // At same time we must destroy/stop the thread from another thread.
|
| - std::string channel_id = AutomationProxy::GenerateChannelID();
|
| - ChromeFrameAutomationProxyImpl* proxy =
|
| - new ChromeFrameAutomationProxyImpl(
|
| - this,
|
| - channel_id,
|
| - base::TimeDelta::FromMilliseconds(params->launch_timeout()));
|
| -
|
| - // Ensure that the automation proxy actually respects our choice on whether
|
| - // or not to check the version.
|
| - proxy->set_perform_version_check(params->version_check());
|
| -
|
| - // Launch browser
|
| - std::wstring command_line_string;
|
| - scoped_ptr<CommandLine> command_line;
|
| - if (chrome_launcher::CreateLaunchCommandLine(&command_line)) {
|
| - command_line->AppendSwitchASCII(switches::kAutomationClientChannelID,
|
| - channel_id);
|
| -
|
| - // Run Chrome in Chrome Frame mode. In practice, this modifies the paths
|
| - // and registry keys that Chrome looks in via the BrowserDistribution
|
| - // mechanism.
|
| - command_line->AppendSwitch(switches::kChromeFrame);
|
| -
|
| - // Chrome Frame never wants Chrome to start up with a First Run UI.
|
| - command_line->AppendSwitch(switches::kNoFirstRun);
|
| -
|
| - // Chrome Frame never wants to run background extensions since they
|
| - // interfere with in-use updates.
|
| - command_line->AppendSwitch(switches::kDisableBackgroundMode);
|
| -
|
| - command_line->AppendSwitch(switches::kDisablePopupBlocking);
|
| -
|
| -#if defined(GOOGLE_CHROME_BUILD)
|
| - // Chrome Frame should use the native print dialog.
|
| - command_line->AppendSwitch(switches::kDisablePrintPreview);
|
| -#endif
|
| -
|
| - // Disable the "Whoa! Chrome has crashed." dialog, because that isn't very
|
| - // useful for Chrome Frame users.
|
| -#ifndef NDEBUG
|
| - command_line->AppendSwitch(switches::kNoErrorDialogs);
|
| -#endif
|
| -
|
| - // In headless mode runs like reliability test runs we want full crash dumps
|
| - // from chrome.
|
| - if (IsHeadlessMode())
|
| - command_line->AppendSwitch(switches::kFullMemoryCrashReport);
|
| -
|
| - // In accessible mode automation tests expect renderer accessibility to be
|
| - // enabled in chrome.
|
| - if (IsAccessibleMode())
|
| - command_line->AppendSwitch(switches::kForceRendererAccessibility);
|
| -
|
| - DVLOG(1) << "Profile path: " << params->profile_path().value();
|
| - command_line->AppendSwitchPath(switches::kUserDataDir,
|
| - params->profile_path());
|
| -
|
| - // Ensure that Chrome is running the specified version of chrome.dll.
|
| - command_line->AppendSwitchNative(switches::kChromeVersion,
|
| - GetCurrentModuleVersion());
|
| -
|
| - if (!params->language().empty())
|
| - command_line->AppendSwitchNative(switches::kLang, params->language());
|
| -
|
| - command_line_string = command_line->GetCommandLineString();
|
| - }
|
| -
|
| - automation_server_launch_start_time_ = base::TimeTicks::Now();
|
| -
|
| - if (command_line_string.empty() ||
|
| - !base::LaunchProcess(command_line_string, base::LaunchOptions(), NULL)) {
|
| - // We have no code for launch failure.
|
| - launch_result_ = AUTOMATION_LAUNCH_RESULT_INVALID;
|
| - } else {
|
| - // Launch timeout may happen if the new instance tries to communicate
|
| - // with an existing Chrome instance that is hung and displays msgbox
|
| - // asking to kill the previous one. This could be easily observed if the
|
| - // already running Chrome instance is running as high-integrity process
|
| - // (started with "Run as Administrator" or launched by another high
|
| - // integrity process) hence our medium-integrity process
|
| - // cannot SendMessage to it with request to activate itself.
|
| -
|
| - // TODO(stoyan) AutomationProxy eats Hello message, hence installing
|
| - // message filter is pointless, we can leverage ObjectWatcher and use
|
| - // system thread pool to notify us when proxy->AppLaunch event is signaled.
|
| - LaunchTimeStats launch_stats;
|
| - // Wait for the automation server launch result, then stash away the
|
| - // version string it reported.
|
| - launch_result_ = proxy->WaitForAppLaunch();
|
| - launch_stats.Dump();
|
| -
|
| - base::TimeDelta delta =
|
| - base::TimeTicks::Now() - automation_server_launch_start_time_;
|
| -
|
| - if (launch_result_ == AUTOMATION_SUCCESS) {
|
| - UMA_HISTOGRAM_TIMES(
|
| - "ChromeFrame.AutomationServerLaunchSuccessTime", delta);
|
| - } else {
|
| - UMA_HISTOGRAM_TIMES(
|
| - "ChromeFrame.AutomationServerLaunchFailedTime", delta);
|
| - }
|
| -
|
| - UMA_HISTOGRAM_CUSTOM_COUNTS("ChromeFrame.LaunchResult",
|
| - launch_result_,
|
| - AUTOMATION_SUCCESS,
|
| - AUTOMATION_CREATE_TAB_FAILED,
|
| - AUTOMATION_CREATE_TAB_FAILED + 1);
|
| - }
|
| -
|
| - TRACE_EVENT_END_ETW("chromeframe.createproxy", this, "");
|
| -
|
| - // Finally set the proxy.
|
| - proxy_.reset(proxy);
|
| - launch_delegates_.push_back(delegate);
|
| -
|
| - delegate->LaunchComplete(proxy_.get(), launch_result_);
|
| -}
|
| -
|
| -void AutomationProxyCacheEntry::RemoveDelegate(LaunchDelegate* delegate,
|
| - base::WaitableEvent* done,
|
| - bool* was_last_delegate) {
|
| - DCHECK(IsSameThread(base::PlatformThread::CurrentId()));
|
| - DCHECK(delegate);
|
| - DCHECK(done);
|
| - DCHECK(was_last_delegate);
|
| -
|
| - *was_last_delegate = false;
|
| -
|
| - LaunchDelegates::iterator it = std::find(launch_delegates_.begin(),
|
| - launch_delegates_.end(), delegate);
|
| - if (it == launch_delegates_.end()) {
|
| - NOTREACHED();
|
| - } else {
|
| - if (launch_delegates_.size() == 1) {
|
| - *was_last_delegate = true;
|
| -
|
| - // Process pending notifications.
|
| - thread_->message_loop()->RunUntilIdle();
|
| -
|
| - // Take down the proxy since we no longer have any clients.
|
| - // Make sure we only do this once all pending messages have been cleared.
|
| - proxy_.reset(NULL);
|
| - }
|
| - // Be careful to remove from the list after running pending
|
| - // tasks. Otherwise the delegate being removed might miss out
|
| - // on pending notifications such as LaunchComplete.
|
| - launch_delegates_.erase(it);
|
| - }
|
| -
|
| - done->Signal();
|
| -}
|
| -
|
| -void AutomationProxyCacheEntry::AddDelegate(LaunchDelegate* delegate) {
|
| - DCHECK(IsSameThread(base::PlatformThread::CurrentId()));
|
| - DCHECK(std::find(launch_delegates_.begin(),
|
| - launch_delegates_.end(),
|
| - delegate) == launch_delegates_.end())
|
| - << "Same delegate being added twice";
|
| - DCHECK(launch_result_ != AUTOMATION_LAUNCH_RESULT_INVALID);
|
| -
|
| - launch_delegates_.push_back(delegate);
|
| - delegate->LaunchComplete(proxy_.get(), launch_result_);
|
| -}
|
| -
|
| -void AutomationProxyCacheEntry::OnChannelError() {
|
| - DCHECK(IsSameThread(base::PlatformThread::CurrentId()));
|
| - launch_result_ = AUTOMATION_SERVER_CRASHED;
|
| - LaunchDelegates::const_iterator it = launch_delegates_.begin();
|
| - for (; it != launch_delegates_.end(); ++it) {
|
| - (*it)->AutomationServerDied();
|
| - }
|
| -}
|
| -
|
| -ProxyFactory::ProxyFactory() {
|
| -}
|
| -
|
| -ProxyFactory::~ProxyFactory() {
|
| - for (size_t i = 0; i < proxies_.container().size(); ++i) {
|
| - DWORD result = proxies_[i]->WaitForThread(0);
|
| - if (WAIT_OBJECT_0 != result)
|
| - // TODO(stoyan): Don't leak proxies on exit.
|
| - DLOG(ERROR) << "Proxies leaked on exit.";
|
| - }
|
| -}
|
| -
|
| -void ProxyFactory::GetAutomationServer(
|
| - LaunchDelegate* delegate, ChromeFrameLaunchParams* params,
|
| - void** automation_server_id) {
|
| - TRACE_EVENT_BEGIN_ETW("chromeframe.createproxy", this, "");
|
| -
|
| - scoped_refptr<AutomationProxyCacheEntry> entry;
|
| - // Find already existing launcher thread for given profile
|
| - base::AutoLock lock(lock_);
|
| - for (size_t i = 0; i < proxies_.container().size(); ++i) {
|
| - if (proxies_[i]->IsSameProfile(params->profile_name())) {
|
| - entry = proxies_[i];
|
| - break;
|
| - }
|
| - }
|
| -
|
| - if (entry == NULL) {
|
| - DVLOG(1) << __FUNCTION__ << " creating new proxy entry";
|
| - entry = new AutomationProxyCacheEntry(params, delegate);
|
| - proxies_.container().push_back(entry);
|
| - } else if (delegate) {
|
| - // Notify the new delegate of the launch status from the worker thread
|
| - // and add it to the list of delegates.
|
| - entry->message_loop()->PostTask(
|
| - FROM_HERE, base::Bind(&AutomationProxyCacheEntry::AddDelegate,
|
| - base::Unretained(entry.get()), delegate));
|
| - }
|
| -
|
| - DCHECK(automation_server_id != NULL);
|
| - DCHECK(!entry->IsSameThread(base::PlatformThread::CurrentId()));
|
| -
|
| - *automation_server_id = entry;
|
| -}
|
| -
|
| -bool ProxyFactory::ReleaseAutomationServer(void* server_id,
|
| - LaunchDelegate* delegate) {
|
| - if (!server_id) {
|
| - NOTREACHED();
|
| - return false;
|
| - }
|
| -
|
| - AutomationProxyCacheEntry* entry =
|
| - reinterpret_cast<AutomationProxyCacheEntry*>(server_id);
|
| -
|
| -#ifndef NDEBUG
|
| - lock_.Acquire();
|
| - Vector::ContainerType::iterator it = std::find(proxies_.container().begin(),
|
| - proxies_.container().end(),
|
| - entry);
|
| - DCHECK(it != proxies_.container().end());
|
| - DCHECK(!entry->IsSameThread(base::PlatformThread::CurrentId()));
|
| -
|
| - lock_.Release();
|
| -#endif
|
| -
|
| - // AddRef the entry object as we might need to take it out of the proxy
|
| - // stack and then uninitialize the entry.
|
| - entry->AddRef();
|
| -
|
| - bool last_delegate = false;
|
| - if (delegate) {
|
| - base::WaitableEvent done(true, false);
|
| - entry->message_loop()->PostTask(
|
| - FROM_HERE,
|
| - base::Bind(&AutomationProxyCacheEntry::RemoveDelegate,
|
| - base::Unretained(entry), delegate, &done, &last_delegate));
|
| - done.Wait();
|
| - }
|
| -
|
| - if (last_delegate) {
|
| - lock_.Acquire();
|
| - Vector::ContainerType::iterator it = std::find(proxies_.container().begin(),
|
| - proxies_.container().end(),
|
| - entry);
|
| - if (it != proxies_.container().end()) {
|
| - proxies_.container().erase(it);
|
| - } else {
|
| - DLOG(ERROR) << "Proxy wasn't found. Proxy map is likely empty (size="
|
| - << proxies_.container().size() << ").";
|
| - }
|
| -
|
| - lock_.Release();
|
| - }
|
| -
|
| - entry->Release();
|
| -
|
| - return true;
|
| -}
|
| -
|
| -static base::LazyInstance<ProxyFactory>::Leaky
|
| - g_proxy_factory = LAZY_INSTANCE_INITIALIZER;
|
| -
|
| -ChromeFrameAutomationClient::ChromeFrameAutomationClient()
|
| - : chrome_frame_delegate_(NULL),
|
| - chrome_window_(NULL),
|
| - tab_window_(NULL),
|
| - parent_window_(NULL),
|
| - automation_server_(NULL),
|
| - automation_server_id_(NULL),
|
| - ui_thread_id_(NULL),
|
| - init_state_(UNINITIALIZED),
|
| - use_chrome_network_(false),
|
| - proxy_factory_(g_proxy_factory.Pointer()),
|
| - handle_top_level_requests_(false),
|
| - tab_handle_(-1),
|
| - session_id_(-1),
|
| - url_fetcher_(NULL),
|
| - url_fetcher_flags_(PluginUrlRequestManager::NOT_THREADSAFE),
|
| - navigate_after_initialization_(false),
|
| - route_all_top_level_navigations_(false) {
|
| -}
|
| -
|
| -ChromeFrameAutomationClient::~ChromeFrameAutomationClient() {
|
| - // Uninitialize must be called prior to the destructor
|
| - DCHECK(automation_server_ == NULL);
|
| -}
|
| -
|
| -bool ChromeFrameAutomationClient::Initialize(
|
| - ChromeFrameDelegate* chrome_frame_delegate,
|
| - ChromeFrameLaunchParams* chrome_launch_params) {
|
| - DCHECK(!IsWindow());
|
| - chrome_frame_delegate_ = chrome_frame_delegate;
|
| -
|
| -#ifndef NDEBUG
|
| - if (chrome_launch_params_ && chrome_launch_params_ != chrome_launch_params) {
|
| - DCHECK_EQ(chrome_launch_params_->url(), chrome_launch_params->url());
|
| - DCHECK_EQ(chrome_launch_params_->referrer(),
|
| - chrome_launch_params->referrer());
|
| - }
|
| -#endif
|
| -
|
| - chrome_launch_params_ = chrome_launch_params;
|
| -
|
| - ui_thread_id_ = base::PlatformThread::CurrentId();
|
| -#ifndef NDEBUG
|
| - // In debug mode give more time to work with a debugger.
|
| - if (IsDebuggerPresent()) {
|
| - // Don't use INFINITE (which is -1) or even MAXINT since we will convert
|
| - // from milliseconds to microseconds when stored in a base::TimeDelta,
|
| - // thus * 1000. An hour should be enough.
|
| - chrome_launch_params_->set_launch_timeout(60 * 60 * 1000);
|
| - } else {
|
| - DCHECK_LT(chrome_launch_params_->launch_timeout(),
|
| - MAXINT / 2000);
|
| - chrome_launch_params_->set_launch_timeout(
|
| - chrome_launch_params_->launch_timeout() * 2);
|
| - }
|
| -#endif // NDEBUG
|
| -
|
| - // Create a window on the UI thread for marshaling messages back and forth
|
| - // from the IPC thread. This window cannot be a message only window as the
|
| - // external chrome tab window is created as a child of this window. This
|
| - // window is eventually reparented to the ActiveX plugin window.
|
| - if (!Create(GetDesktopWindow(), NULL, NULL,
|
| - WS_CHILDWINDOW | WS_CLIPCHILDREN | WS_CLIPSIBLINGS,
|
| - WS_EX_TOOLWINDOW)) {
|
| - NOTREACHED();
|
| - return false;
|
| - }
|
| -
|
| - // Keep object in memory, while the window is alive.
|
| - // Corresponding Release is in OnFinalMessage();
|
| - AddRef();
|
| -
|
| - // Mark our state as initializing. We'll reach initialized once
|
| - // InitializeComplete is called successfully.
|
| - init_state_ = INITIALIZING;
|
| -
|
| - HRESULT hr = S_OK;
|
| -
|
| - if (chrome_launch_params_->url().is_valid())
|
| - navigate_after_initialization_ = false;
|
| -
|
| - proxy_factory_->GetAutomationServer(static_cast<LaunchDelegate*>(this),
|
| - chrome_launch_params_, &automation_server_id_);
|
| -
|
| - return true;
|
| -}
|
| -
|
| -void ChromeFrameAutomationClient::Uninitialize() {
|
| - if (init_state_ == UNINITIALIZED) {
|
| - DLOG(WARNING) << __FUNCTION__ << ": Automation client not initialized";
|
| - return;
|
| - }
|
| -
|
| - init_state_ = UNINITIALIZING;
|
| -
|
| - // Called from client's FinalRelease() / destructor
|
| - if (url_fetcher_) {
|
| - url_fetcher_ = NULL;
|
| - }
|
| -
|
| - if (tab_) {
|
| - tab_->RemoveObserver(this);
|
| - if (automation_server_)
|
| - automation_server_->ReleaseTabProxy(tab_->handle());
|
| - tab_ = NULL; // scoped_refptr::Release
|
| - }
|
| -
|
| - // Wait for the automation proxy's worker thread to exit.
|
| - ReleaseAutomationServer();
|
| -
|
| - // We must destroy the window, since if there are pending tasks
|
| - // window procedure may be invoked after DLL is unloaded.
|
| - // Unfortunately pending tasks are leaked.
|
| - if (::IsWindow(m_hWnd))
|
| - DestroyWindow();
|
| -
|
| - // DCHECK(navigate_after_initialization_ == false);
|
| - handle_top_level_requests_ = false;
|
| - ui_thread_id_ = 0;
|
| - chrome_frame_delegate_ = NULL;
|
| - init_state_ = UNINITIALIZED;
|
| -}
|
| -
|
| -bool ChromeFrameAutomationClient::InitiateNavigation(
|
| - const std::string& url,
|
| - const std::string& referrer,
|
| - NavigationConstraints* navigation_constraints) {
|
| - return true;
|
| -}
|
| -
|
| -void ChromeFrameAutomationClient::BeginNavigateCompleted(
|
| - AutomationMsg_NavigationResponseValues result) {
|
| - if (result == AUTOMATION_MSG_NAVIGATION_ERROR)
|
| - ReportNavigationError(AUTOMATION_MSG_NAVIGATION_ERROR,
|
| - chrome_launch_params_->url().spec());
|
| -}
|
| -
|
| -void ChromeFrameAutomationClient::FindInPage(const std::wstring& search_string,
|
| - FindInPageDirection forward,
|
| - FindInPageCase match_case,
|
| - bool find_next) {
|
| - // Note that we can be called by the find dialog after the tab has gone away.
|
| - if (!tab_)
|
| - return;
|
| -
|
| - // What follows is quite similar to TabProxy::FindInPage() but uses
|
| - // the SyncMessageReplyDispatcher to avoid concerns about blocking
|
| - // synchronous messages.
|
| - AutomationMsg_Find_Params params;
|
| - params.search_string = base::WideToUTF16Hack(search_string);
|
| - params.find_next = find_next;
|
| - params.match_case = (match_case == CASE_SENSITIVE);
|
| - params.forward = (forward == FWD);
|
| -
|
| - IPC::SyncMessage* msg =
|
| - new AutomationMsg_Find(tab_->handle(), params, NULL, NULL);
|
| - automation_server_->SendAsAsync(msg, NULL, this);
|
| -}
|
| -
|
| -// Invoked in the automation proxy's worker thread.
|
| -void ChromeFrameAutomationClient::LaunchComplete(
|
| - ChromeFrameAutomationProxy* proxy,
|
| - AutomationLaunchResult result) {
|
| -}
|
| -
|
| -// Invoked in the automation proxy's worker thread.
|
| -void ChromeFrameAutomationClient::AutomationServerDied() {
|
| - // Then uninitialize.
|
| - PostTask(
|
| - FROM_HERE, base::Bind(&ChromeFrameAutomationClient::Uninitialize,
|
| - base::Unretained(this)));
|
| -}
|
| -
|
| -// These are invoked in channel's background thread.
|
| -// Cannot call any method of the activex here since it is a STA kind of being.
|
| -// By default we marshal the IPC message to the main/GUI thread and from there
|
| -// we safely invoke chrome_frame_delegate_->OnMessageReceived(msg).
|
| -bool ChromeFrameAutomationClient::OnMessageReceived(TabProxy* tab,
|
| - const IPC::Message& msg) {
|
| - DCHECK(tab == tab_.get());
|
| -
|
| - // Early check to avoid needless marshaling
|
| - if (chrome_frame_delegate_ == NULL)
|
| - return false;
|
| -
|
| - PostTask(FROM_HERE,
|
| - base::Bind(&ChromeFrameAutomationClient::OnMessageReceivedUIThread,
|
| - base::Unretained(this), msg));
|
| - return true;
|
| -}
|
| -
|
| -void ChromeFrameAutomationClient::OnChannelError(TabProxy* tab) {
|
| - DCHECK(tab == tab_.get());
|
| - // Early check to avoid needless marshaling
|
| - if (chrome_frame_delegate_ == NULL)
|
| - return;
|
| -
|
| - PostTask(
|
| - FROM_HERE,
|
| - base::Bind(&ChromeFrameAutomationClient::OnChannelErrorUIThread,
|
| - base::Unretained(this)));
|
| -}
|
| -
|
| -void ChromeFrameAutomationClient::OnMessageReceivedUIThread(
|
| - const IPC::Message& msg) {
|
| - DCHECK_EQ(base::PlatformThread::CurrentId(), ui_thread_id_);
|
| - // Forward to the delegate.
|
| - if (chrome_frame_delegate_)
|
| - chrome_frame_delegate_->OnMessageReceived(msg);
|
| -}
|
| -
|
| -void ChromeFrameAutomationClient::OnChannelErrorUIThread() {
|
| - DCHECK_EQ(base::PlatformThread::CurrentId(), ui_thread_id_);
|
| -
|
| - // Report a metric that something went wrong unexpectedly.
|
| - CrashMetricsReporter::GetInstance()->IncrementMetric(
|
| - CrashMetricsReporter::CHANNEL_ERROR_COUNT);
|
| -
|
| - // Forward to the delegate.
|
| - if (chrome_frame_delegate_)
|
| - chrome_frame_delegate_->OnChannelError();
|
| -}
|
| -
|
| -void ChromeFrameAutomationClient::ReportNavigationError(
|
| - AutomationMsg_NavigationResponseValues error_code,
|
| - const std::string& url) {
|
| - if (!chrome_frame_delegate_)
|
| - return;
|
| -
|
| - if (ui_thread_id_ == base::PlatformThread::CurrentId()) {
|
| - chrome_frame_delegate_->OnLoadFailed(error_code, url);
|
| - } else {
|
| - PostTask(FROM_HERE,
|
| - base::Bind(&ChromeFrameAutomationClient::ReportNavigationError,
|
| - base::Unretained(this), error_code, url));
|
| - }
|
| -}
|
| -
|
| -void ChromeFrameAutomationClient::SetParentWindow(HWND parent_window) {
|
| - parent_window_ = parent_window;
|
| - // If we're done with the initialization step, go ahead
|
| - if (is_initialized()) {
|
| - if (parent_window == NULL) {
|
| - // Hide and reparent the automation window. This window will get
|
| - // reparented to the new ActiveX/Active document window when it gets
|
| - // created.
|
| - ShowWindow(SW_HIDE);
|
| - SetParent(GetDesktopWindow());
|
| - } else {
|
| - if (!::IsWindow(chrome_window())) {
|
| - DLOG(WARNING) << "Invalid Chrome Window handle in SetParentWindow";
|
| - return;
|
| - }
|
| -
|
| - if (!SetParent(parent_window)) {
|
| - DLOG(WARNING) << "Failed to set parent window for automation window. "
|
| - << "Error = "
|
| - << GetLastError();
|
| - return;
|
| - }
|
| -
|
| - RECT parent_client_rect = {0};
|
| - ::GetClientRect(parent_window, &parent_client_rect);
|
| - int width = parent_client_rect.right - parent_client_rect.left;
|
| - int height = parent_client_rect.bottom - parent_client_rect.top;
|
| - }
|
| - }
|
| -}
|
| -
|
| -void ChromeFrameAutomationClient::ReleaseAutomationServer() {
|
| - if (automation_server_id_) {
|
| - // Cache the server id and clear the automation_server_id_ before
|
| - // calling ReleaseAutomationServer. The reason we do this is that
|
| - // we must cancel pending messages before we release the automation server.
|
| - // Furthermore, while ReleaseAutomationServer is running, we could get
|
| - // a callback to LaunchComplete which could cause an external tab to be
|
| - // created. Ideally the callbacks should be dropped.
|
| - // TODO(ananta)
|
| - // Refactor the ChromeFrameAutomationProxy code to not depend on
|
| - // AutomationProxy and simplify the whole mess.
|
| - void* server_id = automation_server_id_;
|
| - automation_server_id_ = NULL;
|
| -
|
| - if (automation_server_) {
|
| - // Make sure to clean up any pending sync messages before we go away.
|
| - automation_server_->CancelAsync(this);
|
| - }
|
| -
|
| - proxy_factory_->ReleaseAutomationServer(server_id, this);
|
| - automation_server_ = NULL;
|
| -
|
| - // automation_server_ must not have been set to non NULL.
|
| - // (if this regresses, start by looking at LaunchComplete()).
|
| - DCHECK(automation_server_ == NULL);
|
| - } else {
|
| - DCHECK(automation_server_ == NULL);
|
| - }
|
| -}
|
| -
|
| -std::wstring ChromeFrameAutomationClient::GetVersion() const {
|
| - return GetCurrentModuleVersion();
|
| -}
|
| -
|
| -void ChromeFrameAutomationClient::Print(HDC print_dc,
|
| - const RECT& print_bounds) {
|
| - if (!tab_window_) {
|
| - NOTREACHED();
|
| - return;
|
| - }
|
| -
|
| - HDC window_dc = ::GetDC(tab_window_);
|
| -
|
| - BitBlt(print_dc, print_bounds.left, print_bounds.top,
|
| - print_bounds.right - print_bounds.left,
|
| - print_bounds.bottom - print_bounds.top,
|
| - window_dc, print_bounds.left, print_bounds.top,
|
| - SRCCOPY);
|
| -
|
| - ::ReleaseDC(tab_window_, window_dc);
|
| -}
|
| -
|
| -void ChromeFrameAutomationClient::SetPageFontSize(
|
| - enum AutomationPageFontSize font_size) {
|
| - if (font_size < SMALLEST_FONT ||
|
| - font_size > LARGEST_FONT) {
|
| - NOTREACHED() << "Invalid font size specified : "
|
| - << font_size;
|
| - return;
|
| - }
|
| -
|
| - automation_server_->Send(
|
| - new AutomationMsg_SetPageFontSize(tab_handle_, font_size));
|
| -}
|
| -
|
| -void ChromeFrameAutomationClient::SetUrlFetcher(
|
| - PluginUrlRequestManager* url_fetcher) {
|
| - DCHECK(url_fetcher != NULL);
|
| - url_fetcher_ = url_fetcher;
|
| - url_fetcher_flags_ = url_fetcher->GetThreadSafeFlags();
|
| - url_fetcher_->set_delegate(this);
|
| -}
|
|
|