blob: d08d5e7719b6d86fe4b42bb745f6b2061668eb43 [file] [log] [blame]
// Copyright (c) 2006-2008 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 <windows.h>
#include <objbase.h>
#include "chrome/plugin/plugin_thread.h"
#include "chrome/common/chrome_plugin_lib.h"
#include "chrome/common/ipc_logging.h"
#include "chrome/common/notification_service.h"
#include "chrome/common/plugin_messages.h"
#include "chrome/plugin/chrome_plugin_host.h"
#include "chrome/plugin/npobject_util.h"
#include "chrome/plugin/plugin_process.h"
#include "webkit/glue/plugins/plugin_lib.h"
#include "webkit/glue/webkit_glue.h"
PluginThread* PluginThread::plugin_thread_;
PluginThread::PluginThread(PluginProcess* process,
const std::wstring& channel_name)
: plugin_process_(process),
channel_name_(channel_name),
owner_loop_(MessageLoop::current()),
preloaded_plugin_module_(NULL),
Thread("Chrome_PluginThread") {
DCHECK(plugin_process_);
DCHECK(owner_loop_);
DCHECK(!plugin_thread_);
plugin_thread_ = this;
// We need to run a UI message loop to support plugin execution.
base::Thread::Options options;
options.message_loop_type = MessageLoop::TYPE_UI;
StartWithOptions(options);
}
PluginThread::~PluginThread() {
Stop();
plugin_thread_ = NULL;
}
void PluginThread::OnChannelError() {
owner_loop_->PostTask(FROM_HERE, new MessageLoop::QuitTask());
}
bool PluginThread::Send(IPC::Message* msg) {
return channel_.get() ? channel_->Send(msg) : false;
}
void PluginThread::OnMessageReceived(const IPC::Message& msg) {
if (msg.routing_id() == MSG_ROUTING_CONTROL) {
// Resource responses are sent to the resource dispatcher.
if (resource_dispatcher_->OnMessageReceived(msg))
return;
IPC_BEGIN_MESSAGE_MAP(PluginThread, msg)
IPC_MESSAGE_HANDLER(PluginProcessMsg_CreateChannel, OnCreateChannel)
IPC_MESSAGE_HANDLER(PluginProcessMsg_ShutdownResponse, OnShutdownResponse)
IPC_MESSAGE_HANDLER(PluginProcessMsg_PluginMessage, OnPluginMessage)
IPC_MESSAGE_HANDLER(PluginProcessMsg_BrowserShutdown, OnBrowserShutdown)
IPC_END_MESSAGE_MAP()
} else {
NOTREACHED() << "Only control messages should reach PluginThread.";
}
}
void PluginThread::Init() {
PatchNPNFunctions();
CoInitialize(NULL);
channel_.reset(new IPC::SyncChannel(channel_name_,
IPC::Channel::MODE_CLIENT, this, NULL, owner_loop_, true,
PluginProcess::GetShutDownEvent()));
notification_service_.reset(new NotificationService);
resource_dispatcher_ = new ResourceDispatcher(this);
// Preload the library to avoid loading, unloading then reloading
preloaded_plugin_module_ = NPAPI::PluginLib::LoadNativeLibrary(
plugin_process_->plugin_path());
ChromePluginLib::Create(plugin_process_->plugin_path(),
GetCPBrowserFuncsForPlugin());
scoped_refptr<NPAPI::PluginLib> plugin =
NPAPI::PluginLib::CreatePluginLib(plugin_process_->plugin_path());
if (plugin.get()) {
plugin->NP_Initialize();
}
// Certain plugins, such as flash, steal the unhandled exception filter
// thus we never get crash reports when they fault. This call fixes it.
message_loop()->set_exception_restoration(true);
#ifdef IPC_MESSAGE_LOG_ENABLED
IPC::Logging::current()->SetIPCSender(this);
#endif
}
void PluginThread::CleanUp() {
#ifdef IPC_MESSAGE_LOG_ENABLED
IPC::Logging::current()->SetIPCSender(NULL);
#endif
if (preloaded_plugin_module_) {
FreeLibrary(preloaded_plugin_module_);
preloaded_plugin_module_ = NULL;
}
// Need to destruct the SyncChannel to the browser before we go away because
// it caches a pointer to this thread.
channel_.reset();
PluginChannelBase::CleanupChannels();
NPAPI::PluginLib::UnloadAllPlugins();
ChromePluginLib::UnloadAllPlugins();
notification_service_.reset();
resource_dispatcher_ = NULL;
CoUninitialize();
if (webkit_glue::ShouldForcefullyTerminatePluginProcess())
TerminateProcess(GetCurrentProcess(), 0);
}
void PluginThread::OnCreateChannel(int process_id, HANDLE renderer_handle) {
std::wstring channel_name;
scoped_refptr<PluginChannel> channel =
PluginChannel::GetPluginChannel(process_id, renderer_handle, owner_loop_);
if (channel.get())
channel_name = channel->channel_name();
Send(new PluginProcessHostMsg_ChannelCreated(process_id, channel_name));
}
void PluginThread::OnShutdownResponse(bool ok_to_shutdown) {
PluginProcess::ShutdownProcessResponse(ok_to_shutdown);
}
void PluginThread::OnBrowserShutdown() {
PluginProcess::BrowserShutdown();
}
void PluginThread::OnPluginMessage(const std::vector<unsigned char> &data) {
// We Add/Release ref here to ensure that something will trigger the
// shutdown mechanism for processes started in the absence of renderer's
// opening a plugin channel.
PluginProcess::AddRefProcess();
ChromePluginLib *chrome_plugin =
ChromePluginLib::Find(plugin_process_->plugin_path());
if (chrome_plugin) {
void *data_ptr = const_cast<void*>(reinterpret_cast<const void*>(&data[0]));
uint32 data_len = static_cast<uint32>(data.size());
chrome_plugin->functions().on_message(data_ptr, data_len);
}
PluginProcess::ReleaseProcess();
}
namespace webkit_glue {
bool DownloadUrl(const std::string& url, HWND caller_window) {
PluginThread* plugin_thread = PluginThread::GetPluginThread();
if (!plugin_thread) {
return false;
}
IPC::Message* message =
new PluginProcessHostMsg_DownloadUrl(MSG_ROUTING_NONE, url,
::GetCurrentProcessId(),
caller_window);
return plugin_thread->Send(message);
}
bool GetPluginFinderURL(std::string* plugin_finder_url) {
if (!plugin_finder_url) {
NOTREACHED();
return false;
}
PluginThread* plugin_thread = PluginThread::GetPluginThread();
if (!plugin_thread) {
return false;
}
plugin_thread->Send(
new PluginProcessHostMsg_GetPluginFinderUrl(plugin_finder_url));
DCHECK(!plugin_finder_url->empty());
return true;
}
bool IsDefaultPluginEnabled() {
return true;
}
} // namespace webkit_glue