| Index: webkit/glue/plugins/plugin_lib.cc
|
| ===================================================================
|
| --- webkit/glue/plugins/plugin_lib.cc (revision 69426)
|
| +++ webkit/glue/plugins/plugin_lib.cc (working copy)
|
| @@ -1,349 +0,0 @@
|
| -// 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 "webkit/glue/plugins/plugin_lib.h"
|
| -
|
| -#include "base/logging.h"
|
| -#include "base/message_loop.h"
|
| -#include "base/metrics/stats_counters.h"
|
| -#include "base/string_util.h"
|
| -#include "webkit/glue/webkit_glue.h"
|
| -#include "webkit/glue/plugins/plugin_instance.h"
|
| -#include "webkit/glue/plugins/plugin_host.h"
|
| -#include "webkit/glue/plugins/plugin_list.h"
|
| -
|
| -namespace NPAPI {
|
| -
|
| -const char kPluginLibrariesLoadedCounter[] = "PluginLibrariesLoaded";
|
| -const char kPluginInstancesActiveCounter[] = "PluginInstancesActive";
|
| -
|
| -// A list of all the instantiated plugins.
|
| -static std::vector<scoped_refptr<PluginLib> >* g_loaded_libs;
|
| -
|
| -PluginLib* PluginLib::CreatePluginLib(const FilePath& filename) {
|
| - // We can only have one PluginLib object per plugin as it controls the per
|
| - // instance function calls (i.e. NP_Initialize and NP_Shutdown). So we keep
|
| - // a map of PluginLib objects.
|
| - if (!g_loaded_libs)
|
| - g_loaded_libs = new std::vector<scoped_refptr<PluginLib> >;
|
| -
|
| - for (size_t i = 0; i < g_loaded_libs->size(); ++i) {
|
| - if ((*g_loaded_libs)[i]->plugin_info().path == filename)
|
| - return (*g_loaded_libs)[i];
|
| - }
|
| -
|
| - WebPluginInfo info;
|
| - const PluginEntryPoints* entry_points = NULL;
|
| - if (!PluginList::Singleton()->ReadPluginInfo(filename, &info, &entry_points))
|
| - return NULL;
|
| -
|
| - return new PluginLib(info, entry_points);
|
| -}
|
| -
|
| -void PluginLib::UnloadAllPlugins() {
|
| - if (g_loaded_libs) {
|
| - // PluginLib::Unload() can remove items from the list and even delete
|
| - // the list when it removes the last item, so we must work with a copy
|
| - // of the list so that we don't get the carpet removed under our feet.
|
| - std::vector<scoped_refptr<PluginLib> > loaded_libs(*g_loaded_libs);
|
| - for (size_t i = 0; i < loaded_libs.size(); ++i)
|
| - loaded_libs[i]->Unload();
|
| -
|
| - if (g_loaded_libs && g_loaded_libs->empty()) {
|
| - delete g_loaded_libs;
|
| - g_loaded_libs = NULL;
|
| - }
|
| - }
|
| -}
|
| -
|
| -void PluginLib::ShutdownAllPlugins() {
|
| - if (g_loaded_libs) {
|
| - for (size_t i = 0; i < g_loaded_libs->size(); ++i)
|
| - (*g_loaded_libs)[i]->Shutdown();
|
| - }
|
| -}
|
| -
|
| -PluginLib::PluginLib(const WebPluginInfo& info,
|
| - const PluginEntryPoints* entry_points)
|
| - : web_plugin_info_(info),
|
| - library_(NULL),
|
| - initialized_(false),
|
| - saved_data_(0),
|
| - instance_count_(0),
|
| - skip_unload_(false) {
|
| - base::StatsCounter(kPluginLibrariesLoadedCounter).Increment();
|
| - memset(static_cast<void*>(&plugin_funcs_), 0, sizeof(plugin_funcs_));
|
| - g_loaded_libs->push_back(make_scoped_refptr(this));
|
| -
|
| - if (entry_points) {
|
| - internal_ = true;
|
| - entry_points_ = *entry_points;
|
| - } else {
|
| - internal_ = false;
|
| - // We will read the entry points from the plugin directly.
|
| - memset(&entry_points_, 0, sizeof(entry_points_));
|
| - }
|
| -}
|
| -
|
| -PluginLib::~PluginLib() {
|
| - base::StatsCounter(kPluginLibrariesLoadedCounter).Decrement();
|
| - if (saved_data_ != 0) {
|
| - // TODO - delete the savedData object here
|
| - }
|
| -}
|
| -
|
| -NPPluginFuncs* PluginLib::functions() {
|
| - return &plugin_funcs_;
|
| -}
|
| -
|
| -NPError PluginLib::NP_Initialize() {
|
| - LOG_IF(ERROR, PluginList::DebugPluginLoading())
|
| - << "PluginLib::NP_Initialize(" << web_plugin_info_.path.value()
|
| - << "): initialized=" << initialized_;
|
| - if (initialized_)
|
| - return NPERR_NO_ERROR;
|
| -
|
| - if (!Load())
|
| - return NPERR_MODULE_LOAD_FAILED_ERROR;
|
| -
|
| - PluginHost* host = PluginHost::Singleton();
|
| - if (host == 0)
|
| - return NPERR_GENERIC_ERROR;
|
| -
|
| -#if defined(OS_POSIX) && !defined(OS_MACOSX)
|
| - NPError rv = entry_points_.np_initialize(host->host_functions(),
|
| - &plugin_funcs_);
|
| -#else
|
| - NPError rv = entry_points_.np_initialize(host->host_functions());
|
| -#if defined(OS_MACOSX)
|
| - // On the Mac, we need to get entry points after calling np_initialize to
|
| - // match the behavior of other browsers.
|
| - if (rv == NPERR_NO_ERROR) {
|
| - rv = entry_points_.np_getentrypoints(&plugin_funcs_);
|
| - }
|
| -#endif // OS_MACOSX
|
| -#endif
|
| - LOG_IF(ERROR, PluginList::DebugPluginLoading())
|
| - << "PluginLib::NP_Initialize(" << web_plugin_info_.path.value()
|
| - << "): result=" << rv;
|
| - initialized_ = (rv == NPERR_NO_ERROR);
|
| - return rv;
|
| -}
|
| -
|
| -void PluginLib::NP_Shutdown(void) {
|
| - DCHECK(initialized_);
|
| - entry_points_.np_shutdown();
|
| -}
|
| -
|
| -void PluginLib::PreventLibraryUnload() {
|
| - skip_unload_ = true;
|
| -}
|
| -
|
| -PluginInstance* PluginLib::CreateInstance(const std::string& mime_type) {
|
| - PluginInstance* new_instance = new PluginInstance(this, mime_type);
|
| - instance_count_++;
|
| - base::StatsCounter(kPluginInstancesActiveCounter).Increment();
|
| - DCHECK_NE(static_cast<PluginInstance*>(NULL), new_instance);
|
| - return new_instance;
|
| -}
|
| -
|
| -void PluginLib::CloseInstance() {
|
| - base::StatsCounter(kPluginInstancesActiveCounter).Decrement();
|
| - instance_count_--;
|
| - // If a plugin is running in its own process it will get unloaded on process
|
| - // shutdown.
|
| - if ((instance_count_ == 0) && webkit_glue::IsPluginRunningInRendererProcess())
|
| - Unload();
|
| -}
|
| -
|
| -bool PluginLib::Load() {
|
| - if (library_)
|
| - return true;
|
| -
|
| - bool rv = false;
|
| - base::NativeLibrary library = 0;
|
| -
|
| - if (!internal_) {
|
| -#if defined(OS_WIN)
|
| - // This is to work around a bug in the Real player recorder plugin which
|
| - // intercepts LoadLibrary calls from chrome.dll and wraps NPAPI functions
|
| - // provided by the plugin. It crashes if the media player plugin is being
|
| - // loaded. Workaround is to load the dll dynamically by getting the
|
| - // LoadLibrary API address from kernel32.dll which bypasses the recorder
|
| - // plugin.
|
| - if (web_plugin_info_.name.find(L"Windows Media Player") !=
|
| - std::wstring::npos) {
|
| - library = base::LoadNativeLibraryDynamically(web_plugin_info_.path);
|
| - } else {
|
| - library = base::LoadNativeLibrary(web_plugin_info_.path);
|
| - }
|
| -#else // OS_WIN
|
| - library = base::LoadNativeLibrary(web_plugin_info_.path);
|
| -#endif // OS_WIN
|
| - if (library == 0) {
|
| - LOG_IF(ERROR, PluginList::DebugPluginLoading())
|
| - << "Couldn't load plugin " << web_plugin_info_.path.value();
|
| - return rv;
|
| - }
|
| -
|
| -#if defined(OS_MACOSX)
|
| - // According to the WebKit source, QuickTime at least requires us to call
|
| - // UseResFile on the plugin resources before loading.
|
| - if (library->bundle_resource_ref != -1)
|
| - UseResFile(library->bundle_resource_ref);
|
| -#endif
|
| -
|
| - rv = true; // assume success now
|
| -
|
| - entry_points_.np_initialize =
|
| - (NP_InitializeFunc)base::GetFunctionPointerFromNativeLibrary(library,
|
| - "NP_Initialize");
|
| - if (entry_points_.np_initialize == 0)
|
| - rv = false;
|
| -
|
| -#if defined(OS_WIN) || defined(OS_MACOSX)
|
| - entry_points_.np_getentrypoints =
|
| - (NP_GetEntryPointsFunc)base::GetFunctionPointerFromNativeLibrary(
|
| - library, "NP_GetEntryPoints");
|
| - if (entry_points_.np_getentrypoints == 0)
|
| - rv = false;
|
| -#endif
|
| -
|
| - entry_points_.np_shutdown =
|
| - (NP_ShutdownFunc)base::GetFunctionPointerFromNativeLibrary(library,
|
| - "NP_Shutdown");
|
| - if (entry_points_.np_shutdown == 0)
|
| - rv = false;
|
| - } else {
|
| - rv = true;
|
| - }
|
| -
|
| - if (rv) {
|
| - plugin_funcs_.size = sizeof(plugin_funcs_);
|
| - plugin_funcs_.version = (NP_VERSION_MAJOR << 8) | NP_VERSION_MINOR;
|
| -#if !defined(OS_POSIX)
|
| - if (entry_points_.np_getentrypoints(&plugin_funcs_) != NPERR_NO_ERROR)
|
| - rv = false;
|
| -#else
|
| - // On Linux and Mac, we get the plugin entry points during NP_Initialize.
|
| -#endif
|
| - }
|
| -
|
| - if (!internal_) {
|
| - if (rv) {
|
| - LOG_IF(ERROR, PluginList::DebugPluginLoading())
|
| - << "Plugin " << web_plugin_info_.path.value()
|
| - << " loaded successfully.";
|
| - library_ = library;
|
| - } else {
|
| - LOG_IF(ERROR, PluginList::DebugPluginLoading())
|
| - << "Plugin " << web_plugin_info_.path.value()
|
| - << " failed to load, unloading.";
|
| - base::UnloadNativeLibrary(library);
|
| - }
|
| - }
|
| -
|
| - return rv;
|
| -}
|
| -
|
| -// This class implements delayed NP_Shutdown and FreeLibrary on the plugin dll.
|
| -class FreePluginLibraryTask : public Task {
|
| - public:
|
| - FreePluginLibraryTask(const FilePath& path,
|
| - base::NativeLibrary library,
|
| - NP_ShutdownFunc shutdown_func)
|
| - : path_(path),
|
| - library_(library),
|
| - NP_Shutdown_(shutdown_func) {
|
| - }
|
| -
|
| - ~FreePluginLibraryTask() {}
|
| -
|
| - void Run() {
|
| - if (NP_Shutdown_) {
|
| - // Don't call NP_Shutdown if the library has been reloaded since this task
|
| - // was posted.
|
| - bool reloaded = false;
|
| - if (g_loaded_libs) {
|
| - for (size_t i = 0; i < g_loaded_libs->size(); ++i) {
|
| - if ((*g_loaded_libs)[i]->plugin_info().path == path_)
|
| - reloaded = true;
|
| - }
|
| - }
|
| - if (!reloaded)
|
| - NP_Shutdown_();
|
| - }
|
| -
|
| - if (library_) {
|
| - // Always call base::UnloadNativeLibrary so that the system reference
|
| - // count is decremented.
|
| - base::UnloadNativeLibrary(library_);
|
| - library_ = NULL;
|
| - }
|
| - }
|
| -
|
| - private:
|
| - FilePath path_;
|
| - base::NativeLibrary library_;
|
| - NP_ShutdownFunc NP_Shutdown_;
|
| - DISALLOW_COPY_AND_ASSIGN(FreePluginLibraryTask);
|
| -};
|
| -
|
| -void PluginLib::Unload() {
|
| - if (!internal_ && library_) {
|
| - // In case of single process mode, a plugin can delete itself
|
| - // by executing a script. So delay the unloading of the library
|
| - // so that the plugin will have a chance to unwind.
|
| - bool defer_unload = webkit_glue::IsPluginRunningInRendererProcess();
|
| -
|
| -/* TODO(dglazkov): Revisit when re-enabling the JSC build.
|
| -#if USE(JSC)
|
| - // The plugin NPAPI instances may still be around. Delay the
|
| - // NP_Shutdown and FreeLibrary calls at least till the next
|
| - // peek message.
|
| - defer_unload = true;
|
| -#endif
|
| -*/
|
| -
|
| - if (defer_unload) {
|
| - FreePluginLibraryTask* free_library_task =
|
| - new FreePluginLibraryTask(web_plugin_info_.path,
|
| - skip_unload_ ? NULL : library_,
|
| - entry_points_.np_shutdown);
|
| - LOG_IF(ERROR, PluginList::DebugPluginLoading())
|
| - << "Scheduling delayed unload for plugin "
|
| - << web_plugin_info_.path.value();
|
| - MessageLoop::current()->PostTask(FROM_HERE, free_library_task);
|
| - } else {
|
| - Shutdown();
|
| - if (!skip_unload_) {
|
| - LOG_IF(ERROR, PluginList::DebugPluginLoading())
|
| - << "Unloading plugin " << web_plugin_info_.path.value();
|
| - base::UnloadNativeLibrary(library_);
|
| - }
|
| - }
|
| -
|
| - library_ = NULL;
|
| - }
|
| -
|
| - for (size_t i = 0; i < g_loaded_libs->size(); ++i) {
|
| - if ((*g_loaded_libs)[i].get() == this) {
|
| - g_loaded_libs->erase(g_loaded_libs->begin() + i);
|
| - break;
|
| - }
|
| - }
|
| - if (g_loaded_libs->empty()) {
|
| - delete g_loaded_libs;
|
| - g_loaded_libs = NULL;
|
| - }
|
| -}
|
| -
|
| -void PluginLib::Shutdown() {
|
| - if (initialized_ && !internal_) {
|
| - NP_Shutdown();
|
| - initialized_ = false;
|
| - }
|
| -}
|
| -
|
| -} // namespace NPAPI
|
|
|