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 |