1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161
|
// 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 "content/plugin/plugin_thread.h"
#include "build/build_config.h"
#if defined(OS_MACOSX)
#include <CoreFoundation/CoreFoundation.h>
#endif
#include <string>
#include <vector>
#include "base/bind.h"
#include "base/command_line.h"
#include "base/lazy_instance.h"
#include "base/process/kill.h"
#include "base/process/process_handle.h"
#include "base/threading/thread_local.h"
#include "content/child/blink_platform_impl.h"
#include "content/child/child_process.h"
#include "content/child/npapi/npobject_util.h"
#include "content/child/npapi/plugin_lib.h"
#include "content/common/plugin_process_messages.h"
#include "content/public/common/content_switches.h"
#include "content/public/plugin/content_plugin_client.h"
#include "third_party/WebKit/public/web/WebKit.h"
#include "ipc/ipc_channel_handle.h"
#include "ipc/message_filter.h"
namespace content {
namespace {
class EnsureTerminateMessageFilter : public IPC::MessageFilter {
public:
EnsureTerminateMessageFilter() {}
protected:
~EnsureTerminateMessageFilter() override {}
// IPC::MessageFilter:
void OnChannelError() override {
// How long we wait before forcibly shutting down the process.
const base::TimeDelta kPluginProcessTerminateTimeout =
base::TimeDelta::FromSeconds(3);
// Ensure that we don't wait indefinitely for the plugin to shutdown.
// as the browser does not terminate plugin processes on shutdown.
// We achieve this by posting an exit process task on the IO thread.
base::MessageLoop::current()->PostDelayedTask(
FROM_HERE,
base::Bind(&EnsureTerminateMessageFilter::Terminate, this),
kPluginProcessTerminateTimeout);
}
private:
void Terminate() {
base::KillProcess(base::GetCurrentProcessHandle(), 0, false);
}
};
} // namespace
static base::LazyInstance<base::ThreadLocalPointer<PluginThread> > lazy_tls =
LAZY_INSTANCE_INITIALIZER;
PluginThread::PluginThread()
: preloaded_plugin_module_(NULL),
forcefully_terminate_plugin_process_(false) {
base::FilePath plugin_path =
base::CommandLine::ForCurrentProcess()->GetSwitchValuePath(
switches::kPluginPath);
lazy_tls.Pointer()->Set(this);
PatchNPNFunctions();
// Preload the library to avoid loading, unloading then reloading
preloaded_plugin_module_ = base::LoadNativeLibrary(plugin_path, NULL);
scoped_refptr<PluginLib> plugin(PluginLib::CreatePluginLib(plugin_path));
if (plugin.get()) {
plugin->NP_Initialize();
// For OOP plugins the plugin dll will be unloaded during process shutdown
// time.
plugin->set_defer_unload(true);
}
GetContentClient()->plugin()->PluginProcessStarted(
plugin.get() ? plugin->plugin_info().name : base::string16());
channel()->AddFilter(new EnsureTerminateMessageFilter());
// This is needed because we call some code which uses Blink strings.
blink_platform_impl_.reset(new BlinkPlatformImpl);
blink::initialize(blink_platform_impl_.get());
}
PluginThread::~PluginThread() {
}
void PluginThread::SetForcefullyTerminatePluginProcess() {
forcefully_terminate_plugin_process_ = true;
}
void PluginThread::Shutdown() {
ChildThread::Shutdown();
if (preloaded_plugin_module_) {
base::UnloadNativeLibrary(preloaded_plugin_module_);
preloaded_plugin_module_ = NULL;
}
NPChannelBase::CleanupChannels();
PluginLib::UnloadAllPlugins();
if (forcefully_terminate_plugin_process_)
base::KillProcess(base::GetCurrentProcessHandle(), 0, /* wait= */ false);
lazy_tls.Pointer()->Set(NULL);
}
PluginThread* PluginThread::current() {
return lazy_tls.Pointer()->Get();
}
bool PluginThread::OnControlMessageReceived(const IPC::Message& msg) {
bool handled = true;
IPC_BEGIN_MESSAGE_MAP(PluginThread, msg)
IPC_MESSAGE_HANDLER(PluginProcessMsg_CreateChannel, OnCreateChannel)
IPC_MESSAGE_HANDLER(PluginProcessMsg_NotifyRenderersOfPendingShutdown,
OnNotifyRenderersOfPendingShutdown)
IPC_MESSAGE_UNHANDLED(handled = false)
IPC_END_MESSAGE_MAP()
return handled;
}
void PluginThread::OnCreateChannel(int renderer_id,
bool incognito) {
scoped_refptr<PluginChannel> channel(PluginChannel::GetPluginChannel(
renderer_id, ChildProcess::current()->io_message_loop_proxy()));
IPC::ChannelHandle channel_handle;
if (channel.get()) {
channel_handle.name = channel->channel_handle().name;
#if defined(OS_POSIX)
// On POSIX, pass the renderer-side FD.
channel_handle.socket =
base::FileDescriptor(channel->TakeRendererFileDescriptor());
#endif
channel->set_incognito(incognito);
}
Send(new PluginProcessHostMsg_ChannelCreated(channel_handle));
}
void PluginThread::OnNotifyRenderersOfPendingShutdown() {
PluginChannel::NotifyRenderersOfPendingShutdown();
}
} // namespace content
|