--------------------------
一,调用过程: (1)首先,看一下webkit在load一个plugin时候的调用栈:
#0 WebCore::PluginPackage::load (this=0x9ed7868) at WebCore/plugins/gtk/PluginPackageGtk.cpp:142 #1 WebCore::PluginPackage::fetchInfo (this=0x9ed7868) at WebCore/plugins/gtk/PluginPackageGtk.cpp:68 #2 WebCore::PluginPackage::createPackage (path=, lastModified=@0xbffd6458: 1264400336) at WebCore/plugins/PluginPackage.cpp:149 #3 WebCore::PluginDatabase::refresh (this=0x9ed6d60) at WebCore/plugins/PluginDatabase.cpp:111 #4 WebCore::PluginDatabase::installedPlugins () at WebCore/plugins/PluginDatabase.cpp:46 #5 WebKit::FrameLoaderClient::objectContentType (this=0x9e6c460, url=, mimeType=) at WebKit/gtk/WebCoreSupport/FrameLoaderClientGtk.cpp:352 #6 WebCore::RenderPartObject::updateWidget (this=0x9eec744, onlyCreateNonNetscapePlugins=true) at WebCore/rendering/RenderPartObject.cpp:217 #7 WebCore::HTMLObjectElement::updateWidget (this=0x9eebbf8) at WebCore/html/HTMLObjectElement.cpp:191 #8 WebCore::HTMLPlugInElement::updateWidgetCallback (n=0x9eebbf8) at WebCore/html/HTMLPlugInElement.cpp:213 #9 WebCore::ContainerNode::dispatchPostAttachCallbacks () at WebCore/dom/ContainerNode.cpp:640 #10 WebCore::ContainerNode::resumePostAttachCallbacks () at WebCore/dom/ContainerNode.cpp:619 #11 WebCore::Document::recalcStyle (this=0x9e83798, change=WebCore::Node::NoChange) at WebCore/dom/Document.cpp:1159 #12 WebCore::Document::updateRendering (this=0x30) at WebCore/dom/Document.cpp:1172 #13 WebCore::Document::updateDocumentsRendering () at WebCore/dom/Document.cpp:1182 #14 WebCore::EventTarget::dispatchGenericEvent (this=0x9e837c4, referenceNode=0x9e83798, e=, tempEvent=false) at WebCore/dom/EventTarget.cpp:270 #15 WebCore::EventTargetNode::dispatchEvent (this=0x9e83798, e=, ec=@0xbffd6988: 0, tempEvent=<value optimized out>) at WebCore/dom/EventTargetNode.cpp:135 #16 WebCore::Document::finishedParsing (this=0x9e83798) at WebCore/dom/Document.cpp:3721 #17 WebCore::HTMLParser::finished (this=0x9ec8be8) at WebCore/html/HTMLParser.cpp:1544 #18 WebCore::HTMLTokenizer::end (this=0x9ee87b0) at WebCore/html/HTMLTokenizer.cpp:1833 #19 WebCore::HTMLTokenizer::finish (this=0x9ee87b0) at WebCore/html/HTMLTokenizer.cpp:1873 #20 WebCore::Document::finishParsing (this=0x9e83798) at WebCore/dom/Document.cpp:1687 #21 WebCore::FrameLoader::endIfNotLoadingMainResource (this=0x9e6c924) at WebCore/loader/FrameLoader.cpp:1075 #22 WebCore::FrameLoader::end (this=0x9e6c924) at WebCore/loader/FrameLoader.cpp:1059 #23 WebCore::DocumentLoader::finishedLoading (this=0x9eb2428) at WebCore/loader/DocumentLoader.cpp:343 #24 WebCore::FrameLoader::finishedLoading (this=0x9e6c924) at WebCore/loader/FrameLoader.cpp:2931 #25 WebCore::MainResourceLoader::didFinishLoading (this=0x9eb3a48) at WebCore/loader/MainResourceLoader.cpp:320 #26 WebCore::ResourceLoader::didFinishLoading (this=0x9eb3a48) at WebCore/loader/ResourceLoader.cpp:389 #27 WebCore::ResourceHandleManager::downloadTimerCallback (this=0x9eb4560, timer=0x9eb4560) at WebCore/platform/network/curl/ResourceHandleManager.cpp:298 #28 WebCore::Timer<WebCore::ResourceHandleManager>::fired (this=0x9eb4560) at ./WebCore/platform/Timer.h:99 #29 WebCore::TimerBase::fireTimers (fireTime=1269409078.032583, firingTimers=) at WebCore/platform/Timer.cpp:347 #30 WebCore::TimerBase::sharedTimerFired () at WebCore/platform/Timer.cpp:368 #31 timeout_cb () at WebCore/platform/gtk/SharedTimerGtk.cpp:48 #32 ?? () at :0 #33 g_main_context_dispatch () at :0 #34 ?? () at :0 #35 g_main_loop_run () at :0 #36 gtk_main () at :0 #37 main (argc=4, argv=0xbffd7134) at WebKitTools/GtkLauncher/main.cpp:52}}}
#8 中:
void HTMLPlugInElement::updateWidgetCallback(Node* n) { static_cast<HTMLPlugInElement*>(n)->updateWidget(); }
#7 中:
void HTMLObjectElement::updateWidget() { document()->updateRendering(); if (m_needWidgetUpdate && renderer() && !m_useFallbackContent && !isImageType()) static_cast<RenderPartObject*>(renderer())->updateWidget(true); //在这里,调用了 RenderPartObject::updateWidget 函数 }#6 中:(这个函数很复杂,只截取对我们有用的部分来)
void RenderPartObject::updateWidget(bool onlyCreateNonNetscapePlugins) { .... if (on lyCreateNonNetscapePlugins) { KURL completedURL; if (!url.isEmpty()) completedURL = frame->loader()->completeURL(url); //这里,就是要判断 objectContentType,而在判断这个 objectContentType的过程中,发生了很多事,下面会详细解释 if (frame->loader()->client()->objectContentType(completedURL, serviceType) == ObjectContentNetscapePlugin) return; } .... } #5 中 :
ObjectContentType FrameLoaderClient::objectContentType(const KURL& url, const String& mimeType) { String type = mimeType; // We don't use MIMETypeRegistry::getMIMETypeForPath() because it returns "application/octet-stream" upon failure if (type.isEmpty()) type = MIMETypeRegistry::getMIMETypeForExtension(url.path().substring(url.path().reverseFind('.') + 1)); if (type.isEmpty()) return WebCore::ObjectContentFrame; if (MIMETypeRegistry::isSupportedImageMIMEType(type)) return WebCore::ObjectContentImage; //这里,要寻找已经安装过的 plugin, if (PluginDatabase::installedPlugins()->isMIMETypeRegistered(mimeType)) return WebCore::ObjectContentNetscapePlugin; if (MIMETypeRegistry::isSupportedNonImageMIMEType(type)) return WebCore::ObjectContentFrame; return WebCore::ObjectContentNone; }#4 中 :
PluginDatabase* PluginDatabase::installedPlugins() { static PluginDatabase* plugins = 0; if (!plugins) { plugins = new PluginDatabase; //新建一个 plugin的集合 plugins->setPluginDirectories(PluginDatabase::defaultPluginDirectories()); //设置它的搜索路径,defaultPluginDirectories函数中默认写了很多系统路径 //这里将要刷新plugin,继续往下看 plugins->refresh(); } return plugins; }#3 中 :
//这个函数比较长, 只分析有用的部分, //函数的主要过程是: //1,Unload plugins, //2,检查所有路径中的 plugin,如果从上次refresh 到现在,没有改变过(检验时间戳),那么跳过它, // 否则,就要 建立 PluginPackage(重点分析这里), //3, 注册 plug-in MIME types bool PluginDatabase::refresh() { bool pluginSetChanged = false; if (!m_plugins.isEmpty()) { PluginSet pluginsToUnload; getDeletedPlugins(pluginsToUnload); // Unload plugins PluginSet::const_iterator end = pluginsToUnload.end(); for (PluginSet::const_iterator it = pluginsToUnload.begin(); it != end; ++it) remove(it->get()); pluginSetChanged = !pluginsToUnload.isEmpty(); } HashSet<String> paths; getPluginPathsInDirectories(paths); HashMap<String, time_t> pathsWithTimes; // We should only skip unchanged files if we didn't remove any plugins above. If we did remove // any plugins, we need to look at every plugin file so that, e.g., if the user has two versions // of RealPlayer installed and just removed the newer on e, we'll pick up the older on e. bool shouldSkipUnchangedFiles = !pluginSetChanged; HashSet<String>::const_iterator pathsEnd = paths.end(); for (HashSet<String>::const_iterator it = paths.begin(); it != pathsEnd; ++it) { time_t lastModified; if (!getFileModificationTime(*it, lastModified)) continue; pathsWithTimes.add(*it, lastModified); // If the path's timestamp hasn't changed since the last time we ran refresh(), we don't have to do anything. if (shouldSkipUnchangedFiles && m_pluginPathsWithTimes.get(*it) == lastModified) continue; if (RefPtr<PluginPackage> oldPackage = m_pluginsByPath.get(*it)) { ASSERT(!shouldSkipUnchangedFiles || oldPackage->lastModified() != lastModified); remove(oldPackage.get()); } //这里建立一个新的 PluginPackage RefPtr<PluginPackage> package = PluginPackage::createPackage(*it, lastModified); if (package && add(package.release())) pluginSetChanged = true; } // Cache all the paths we found with their timestamps for next time. pathsWithTimes.swap(m_pluginPathsWithTimes); if (!pluginSetChanged) return false; m_registeredMIMETypes.clear(); // Register plug-in MIME types PluginSet::const_iterator end = m_plugins.end(); for (PluginSet::const_iterator it = m_plugins.begin(); it != end; ++it) { // Get MIME types MIMEToDescriptionsMap::const_iterator map_end = (*it)->mimeToDescriptions().end(); for (MIMEToDescriptionsMap::const_iterator map_it = (*it)->mimeToDescriptions().begin(); map_it != map_end; ++map_it) { m_registeredMIMETypes.add(map_it->first); } } return true; }
#2 中 :
PassRefPtr<PluginPackage> PluginPackage::createPackage(const String& path, const time_t& lastModified) { //建立一个 PluginPackage ,具体过程待具体分析, RefPtr<PluginPackage> package = adoptRef(new PluginPackage(path, lastModified)); //获得 PluginPackage 的信息,重点看这里 if (!package->fetchInfo()) return 0; return package.release(); }#1 中:
//这里就是插件初始化的过程了, //过程下面将解释 bool PluginPackage::fetchInfo() { #if defined(XP_UNIX) if (!load()) //这里 load 一个 PluginPackage,实质上的作用是 给PluginPackage类的如下成员赋值:m_pluginFuncs, m_module return false; NP_GetMIMEDescriptionFuncPtr NP_GetMIMEDescription; NPP_GetValueProcPtr NPP_GetValue; //通过上面的load 过程,m_module已经指向了一个 so文件(也就是我们的plugin) //这里 找到 这个插件中实现的 NP_GetMIMEDescription 和 NP_GetValue 函数 g_module_symbol(m_module, "NP_GetMIMEDescription", (void**)&NP_GetMIMEDescription); g_module_symbol(m_module, "NP_GetValue", (void**)&NPP_GetValue); //例如 types = application/x-java-vm:jar,jad:IPTV MIDP Application; ......... //这里分解 types中的内容,并保存 const gchar* types = NP_GetMIMEDescription(); gchar** mimeDescs = g_strsplit(types, ";", -1); for (int i = 0; mimeDescs[i] && mimeDescs[i][0]; i++) { gchar** mimeData = g_strsplit(mimeDescs[i], ":", 3); String description = String::fromUTF8(mimeData[2]); gchar** extensions = g_strsplit(mimeData[1], ",", -1); Vector<String> extVector; for (int j = 0; extensions[j]; j++) extVector.append(String::fromUTF8(extensions[j])); determineQuirks(mimeData[0]); m_mimeToExtensions.add(mimeData[0], extVector); m_mimeToDescriptions.add(mimeData[0], description); g_strfreev(extensions); g_strfreev(mimeData); } g_strfreev(mimeDescs); char* buffer = 0; //调用 插件中的GetValue 方法,得到 name NPError err = NPP_GetValue(0, NPPVpluginNameString, &buffer); if (err == NPERR_NO_ERROR) m_name = buffer; buffer = 0; //调用 插件中的GetValue 方法,得到 description err = NPP_GetValue(0, NPPVpluginDescriptionString, &buffer); if (err == NPERR_NO_ERROR) m_description = buffer; return true; #else notImplemented(); return false; #endif }#0 中:
bool PluginPackage::load() { if (m_isLoaded) { m_loadCount++; return true; } //调用 g_module_open 打开一个 plugin, 实质上这个函数是gtk里面用来打开库文件的, 这里将打开例如 /usr/lib/mozilla/plugins/libmidplugin.so m_module = g_module_open((m_path.utf8()).data(), G_MODULE_BIND_LOCAL); if (!m_module) { LOG(Plugin,"Module Load Failed :%s, Error:%s\n", (m_path.utf8()).da ta(), g_module_error()); return false; } m_isLoaded = true; NP_InitializeFuncPtr NP_Initialize; NPError npErr; //函数g_module_symble来取得插件中的函数指针,调用这一函数的前题是我们声明的函数指针的格式和插件中的定义的函数的格式要相同 //这里就是把 函数指针 (void**)&NP_Initialize 对应到 /usr/lib/mozilla/plugins/libmidplugin.so 中已经实现的函数 NP_Initialize g_module_symbol(m_module, "NP_Initialize", (void**)&NP_Initialize); //同上, g_module_symbol(m_module, "NP_Shutdown", (void**)&m_NPP_Shutdown); if (!NP_Initialize || !m_NPP_Shutdown) goto abort; memset(&m_pluginFuncs, 0, sizeof(m_pluginFuncs)); m_pluginFuncs.size = sizeof(m_pluginFuncs); //给 m_browserFuncs 的各个成员赋值 m_browserFuncs.size = sizeof (m_browserFuncs); m_browserFuncs.version = NP_VERSION_MINOR; m_browserFuncs.geturl = NPN_GetURL; m_browserFuncs.posturl = NPN_PostURL; m_browserFuncs.requestread = NPN_RequestRead; m_browserFuncs.newstream = NPN_NewStream; m_browserFuncs.write = NPN_Write; m_browserFuncs.destroystream = NPN_DestroyStream; m_browserFuncs.status = NPN_Status; m_browserFuncs.uagent = NPN_UserAgent; m_browserFuncs.memalloc = NPN_MemAlloc; m_browserFuncs.memfree = NPN_MemFree; m_browserFuncs.memflush = NPN_MemFlush; m_browserFuncs.reloadplugins = NPN_ReloadPlugins; m_browserFuncs.geturlnotify = NPN_GetURLNotify; m_browserFuncs.posturlnotify = NPN_PostURLNotify; m_browserFuncs.getvalue = NPN_GetValue; m_browserFuncs.setvalue = NPN_SetValue; m_browserFuncs.invalidaterect = NPN_InvalidateRect; m_browserFuncs.invalidateregion = NPN_InvalidateRegion; m_browserFuncs.forceredraw = NPN_ForceRedraw; m_browserFuncs.getJavaEnv = NPN_GetJavaEnv; m_browserFuncs.getJavaPeer = NPN_GetJavaPeer; m_browserFuncs.pushpopupsenabledstate = NPN_PushPopupsEnabledState; m_browserFuncs.poppopupsenabledstate = NPN_PopPopupsEnabledState; m_browserFuncs.releasevariantvalue = _NPN_ReleaseVariantValue; m_browserFuncs.getstringidentifier = _NPN_GetStringIdentifier; m_browserFuncs.getstringidentifiers = _NPN_GetStringIdentifiers; m_browserFuncs.getintidentifier = _NPN_GetIntIdentifier; m_browserFuncs.identifierisstring = _NPN_IdentifierIsString; m_browserFuncs.utf8fromidentifier = _NPN_UTF8FromIdentifier; m_browserFuncs.createobject = _NPN_CreateObject; m_browserFuncs.retainobject = _NPN_RetainObject; m_browserFuncs.releaseobject = _NPN_ReleaseObject; m_browserFuncs.invoke = _NPN_Invoke; m_browserFuncs.invokeDefault = _NPN_InvokeDefault; m_browserFuncs.evaluate = _NPN_Evaluate; m_browserFuncs.getproperty = _NPN_GetProperty; m_browserFuncs.setproperty = _NPN_SetProperty; m_browserFuncs.removeproperty = _NPN_RemoveProperty; m_browserFuncs.hasproperty = _NPN_HasMethod; m_browserFuncs.hasmethod = _NPN_HasProperty; m_browserFuncs.setexception = _NPN_SetException; m_browserFuncs.enumerate = _NPN_Enumerate; //赋值完成 //初始化 plugin(调用 *.so 中已经实现的初始化方法) #if defined(XP_UNIX) npErr = NP_Initialize(&m_browserFuncs, &m_pluginFuncs); #else npErr = NP_Initialize(&m_browserFuncs); #endif if (npErr != NPERR_NO_ERROR) goto abort; m_loadCount++; return true; abort: unloadWithoutShutdown(); return false; }
至此, 分析了webkit在加载一个 plugin 时候所做的一些操作, 过程都是通过调试器查看调用栈,分析源代码完成的,其中难免会有错误, 如果有任何好的建议,请马上留下
转自http://zxw0521.blog.163.com/blog/static/743535620102301302750/