| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "chrome/common/chrome_plugin_lib.h" | |
| 6 | |
| 7 #include "base/command_line.h" | |
| 8 #include "base/hash_tables.h" | |
| 9 #include "base/message_loop.h" | |
| 10 #include "base/metrics/histogram.h" | |
| 11 #include "base/path_service.h" | |
| 12 #include "base/perftimer.h" | |
| 13 #include "base/string_util.h" | |
| 14 #include "base/threading/thread.h" | |
| 15 #include "base/threading/platform_thread.h" | |
| 16 #include "chrome/common/chrome_counters.h" | |
| 17 #include "chrome/common/chrome_switches.h" | |
| 18 #include "chrome/common/notification_service.h" | |
| 19 #include "chrome/common/chrome_paths.h" | |
| 20 #include "webkit/plugins/npapi/plugin_list.h" | |
| 21 | |
| 22 #if defined(OS_WIN) | |
| 23 #include "base/win/registry.h" | |
| 24 #endif | |
| 25 | |
| 26 using base::TimeDelta; | |
| 27 | |
| 28 // TODO(port): revisit when plugins happier | |
| 29 #if defined(OS_WIN) | |
| 30 const wchar_t ChromePluginLib::kRegistryChromePlugins[] = | |
| 31 L"Software\\Google\\Chrome\\Plugins"; | |
| 32 static const wchar_t kRegistryLoadOnStartup[] = L"LoadOnStartup"; | |
| 33 static const wchar_t kRegistryPath[] = L"Path"; | |
| 34 #endif | |
| 35 | |
| 36 typedef base::hash_map<FilePath, scoped_refptr<ChromePluginLib> > | |
| 37 PluginMap; | |
| 38 | |
| 39 // A map of all the instantiated plugins. | |
| 40 static PluginMap* g_loaded_libs; | |
| 41 | |
| 42 // The thread plugins are loaded and used in, lazily initialized upon | |
| 43 // the first creation call. | |
| 44 static base::PlatformThreadId g_plugin_thread_id = 0; | |
| 45 static MessageLoop* g_plugin_thread_loop = NULL; | |
| 46 | |
| 47 static bool IsSingleProcessMode() { | |
| 48 // We don't support ChromePlugins in single-process mode. | |
| 49 return CommandLine::ForCurrentProcess()->HasSwitch(switches::kSingleProcess); | |
| 50 } | |
| 51 | |
| 52 // static | |
| 53 bool ChromePluginLib::IsInitialized() { | |
| 54 return (g_loaded_libs != NULL); | |
| 55 } | |
| 56 | |
| 57 // static | |
| 58 ChromePluginLib* ChromePluginLib::Create(const FilePath& filename, | |
| 59 const CPBrowserFuncs* bfuncs) { | |
| 60 // Keep a map of loaded plugins to ensure we only load each library once. | |
| 61 if (!g_loaded_libs) { | |
| 62 g_loaded_libs = new PluginMap(); | |
| 63 g_plugin_thread_id = base::PlatformThread::CurrentId(); | |
| 64 g_plugin_thread_loop = MessageLoop::current(); | |
| 65 } | |
| 66 DCHECK(IsPluginThread()); | |
| 67 | |
| 68 PluginMap::const_iterator iter = g_loaded_libs->find(filename); | |
| 69 if (iter != g_loaded_libs->end()) | |
| 70 return iter->second; | |
| 71 | |
| 72 scoped_refptr<ChromePluginLib> plugin(new ChromePluginLib(filename)); | |
| 73 if (!plugin->CP_Initialize(bfuncs)) | |
| 74 return NULL; | |
| 75 | |
| 76 (*g_loaded_libs)[filename] = plugin; | |
| 77 return plugin; | |
| 78 } | |
| 79 | |
| 80 // static | |
| 81 ChromePluginLib* ChromePluginLib::Find(const FilePath& filename) { | |
| 82 if (g_loaded_libs) { | |
| 83 PluginMap::const_iterator iter = g_loaded_libs->find(filename); | |
| 84 if (iter != g_loaded_libs->end()) | |
| 85 return iter->second; | |
| 86 } | |
| 87 return NULL; | |
| 88 } | |
| 89 | |
| 90 // static | |
| 91 void ChromePluginLib::Destroy(const FilePath& filename) { | |
| 92 DCHECK(g_loaded_libs); | |
| 93 PluginMap::iterator iter = g_loaded_libs->find(filename); | |
| 94 if (iter != g_loaded_libs->end()) { | |
| 95 iter->second->Unload(); | |
| 96 g_loaded_libs->erase(iter); | |
| 97 } | |
| 98 } | |
| 99 | |
| 100 // static | |
| 101 bool ChromePluginLib::IsPluginThread() { | |
| 102 return base::PlatformThread::CurrentId() == g_plugin_thread_id; | |
| 103 } | |
| 104 | |
| 105 // static | |
| 106 MessageLoop* ChromePluginLib::GetPluginThreadLoop() { | |
| 107 return g_plugin_thread_loop; | |
| 108 } | |
| 109 | |
| 110 // static | |
| 111 void ChromePluginLib::RegisterPluginsWithNPAPI() { | |
| 112 // We don't support ChromePlugins in single-process mode. | |
| 113 if (IsSingleProcessMode()) | |
| 114 return; | |
| 115 | |
| 116 FilePath path; | |
| 117 // Register Gears, if available. | |
| 118 if (PathService::Get(chrome::FILE_GEARS_PLUGIN, &path)) | |
| 119 webkit::npapi::PluginList::Singleton()->AddExtraPluginPath(path); | |
| 120 } | |
| 121 | |
| 122 static void LogPluginLoadTime(const TimeDelta &time) { | |
| 123 UMA_HISTOGRAM_TIMES("Gears.LoadTime", time); | |
| 124 } | |
| 125 | |
| 126 // static | |
| 127 void ChromePluginLib::LoadChromePlugins(const CPBrowserFuncs* bfuncs) { | |
| 128 static bool loaded = false; | |
| 129 if (loaded) | |
| 130 return; | |
| 131 loaded = true; | |
| 132 | |
| 133 // We don't support ChromePlugins in single-process mode. | |
| 134 if (IsSingleProcessMode()) | |
| 135 return; | |
| 136 | |
| 137 FilePath path; | |
| 138 if (!PathService::Get(chrome::FILE_GEARS_PLUGIN, &path)) | |
| 139 return; | |
| 140 | |
| 141 PerfTimer timer; | |
| 142 ChromePluginLib::Create(path, bfuncs); | |
| 143 LogPluginLoadTime(timer.Elapsed()); | |
| 144 | |
| 145 // TODO(mpcomplete): disabled loading of plugins from the registry until we | |
| 146 // phase out registry keys from the gears installer. | |
| 147 #if 0 | |
| 148 for (RegistryKeyIterator iter(HKEY_CURRENT_USER, kRegistryChromePlugins); | |
| 149 iter.Valid(); ++iter) { | |
| 150 // Use the registry to gather plugin across the file system. | |
| 151 std::wstring reg_path = kRegistryChromePlugins; | |
| 152 reg_path.append(L"\\"); | |
| 153 reg_path.append(iter.Name()); | |
| 154 base::win::RegKey key(HKEY_CURRENT_USER, reg_path.c_str()); | |
| 155 | |
| 156 DWORD is_persistent = 0; | |
| 157 key.ReadValueDW(kRegistryLoadOnStartup, &is_persistent); | |
| 158 if (is_persistent) { | |
| 159 std::wstring path; | |
| 160 if (key.ReadValue(kRegistryPath, &path) == ERROR_SUCCESS) { | |
| 161 ChromePluginLib::Create(path, bfuncs); | |
| 162 } | |
| 163 } | |
| 164 } | |
| 165 #endif | |
| 166 } | |
| 167 | |
| 168 // static | |
| 169 void ChromePluginLib::UnloadAllPlugins() { | |
| 170 if (g_loaded_libs) { | |
| 171 PluginMap::iterator it; | |
| 172 for (PluginMap::iterator it = g_loaded_libs->begin(); | |
| 173 it != g_loaded_libs->end(); ++it) { | |
| 174 it->second->Unload(); | |
| 175 } | |
| 176 delete g_loaded_libs; | |
| 177 g_loaded_libs = NULL; | |
| 178 } | |
| 179 } | |
| 180 | |
| 181 const CPPluginFuncs& ChromePluginLib::functions() const { | |
| 182 DCHECK(initialized_); | |
| 183 DCHECK(IsPluginThread()); | |
| 184 return plugin_funcs_; | |
| 185 } | |
| 186 | |
| 187 ChromePluginLib::ChromePluginLib(const FilePath& filename) | |
| 188 : filename_(filename), | |
| 189 #if defined(OS_WIN) | |
| 190 module_(0), | |
| 191 #endif | |
| 192 initialized_(false), | |
| 193 CP_VersionNegotiate_(NULL), | |
| 194 CP_Initialize_(NULL), | |
| 195 CP_Test_(NULL) { | |
| 196 memset((void*)&plugin_funcs_, 0, sizeof(plugin_funcs_)); | |
| 197 } | |
| 198 | |
| 199 ChromePluginLib::~ChromePluginLib() { | |
| 200 } | |
| 201 | |
| 202 bool ChromePluginLib::CP_Initialize(const CPBrowserFuncs* bfuncs) { | |
| 203 VLOG(1) << "ChromePluginLib::CP_Initialize(" << filename_.value() | |
| 204 << "): initialized=" << initialized_; | |
| 205 if (initialized_) | |
| 206 return true; | |
| 207 | |
| 208 if (!Load()) | |
| 209 return false; | |
| 210 | |
| 211 if (CP_VersionNegotiate_) { | |
| 212 uint16 selected_version = 0; | |
| 213 CPError rv = CP_VersionNegotiate_(CP_VERSION, CP_VERSION, | |
| 214 &selected_version); | |
| 215 if ((rv != CPERR_SUCCESS) || (selected_version != CP_VERSION)) | |
| 216 return false; | |
| 217 } | |
| 218 | |
| 219 plugin_funcs_.size = sizeof(plugin_funcs_); | |
| 220 CPError rv = CP_Initialize_(cpid(), bfuncs, &plugin_funcs_); | |
| 221 initialized_ = (rv == CPERR_SUCCESS) && | |
| 222 (CP_GET_MAJOR_VERSION(plugin_funcs_.version) == CP_MAJOR_VERSION) && | |
| 223 (CP_GET_MINOR_VERSION(plugin_funcs_.version) <= CP_MINOR_VERSION); | |
| 224 VLOG(1) << "ChromePluginLib::CP_Initialize(" << filename_.value() | |
| 225 << "): initialized=" << initialized_ << "): result=" << rv; | |
| 226 | |
| 227 return initialized_; | |
| 228 } | |
| 229 | |
| 230 void ChromePluginLib::CP_Shutdown() { | |
| 231 DCHECK(initialized_); | |
| 232 functions().shutdown(); | |
| 233 initialized_ = false; | |
| 234 memset((void*)&plugin_funcs_, 0, sizeof(plugin_funcs_)); | |
| 235 } | |
| 236 | |
| 237 int ChromePluginLib::CP_Test(void* param) { | |
| 238 DCHECK(initialized_); | |
| 239 if (!CP_Test_) | |
| 240 return -1; | |
| 241 return CP_Test_(param); | |
| 242 } | |
| 243 | |
| 244 bool ChromePluginLib::Load() { | |
| 245 #if !defined(OS_WIN) | |
| 246 // Mac and Linux won't implement Gears. | |
| 247 return false; | |
| 248 #else | |
| 249 DCHECK(module_ == 0); | |
| 250 | |
| 251 module_ = LoadLibrary(filename_.value().c_str()); | |
| 252 if (module_ == 0) | |
| 253 return false; | |
| 254 | |
| 255 // required initialization function | |
| 256 CP_Initialize_ = reinterpret_cast<CP_InitializeFunc> | |
| 257 (GetProcAddress(module_, "CP_Initialize")); | |
| 258 | |
| 259 if (!CP_Initialize_) { | |
| 260 FreeLibrary(module_); | |
| 261 module_ = 0; | |
| 262 return false; | |
| 263 } | |
| 264 | |
| 265 // optional version negotiation function | |
| 266 CP_VersionNegotiate_ = reinterpret_cast<CP_VersionNegotiateFunc> | |
| 267 (GetProcAddress(module_, "CP_VersionNegotiate")); | |
| 268 | |
| 269 // optional test function | |
| 270 CP_Test_ = reinterpret_cast<CP_TestFunc> | |
| 271 (GetProcAddress(module_, "CP_Test")); | |
| 272 | |
| 273 return true; | |
| 274 #endif | |
| 275 } | |
| 276 | |
| 277 void ChromePluginLib::Unload() { | |
| 278 NotificationService::current()->Notify( | |
| 279 NotificationType::CHROME_PLUGIN_UNLOADED, | |
| 280 Source<ChromePluginLib>(this), | |
| 281 NotificationService::NoDetails()); | |
| 282 | |
| 283 if (initialized_) | |
| 284 CP_Shutdown(); | |
| 285 | |
| 286 #if defined(OS_WIN) | |
| 287 if (module_) { | |
| 288 FreeLibrary(module_); | |
| 289 module_ = 0; | |
| 290 } | |
| 291 #endif | |
| 292 } | |
| OLD | NEW |