BackgroundBefore reading this document, you should be familiar with Chromium's multi-process architecture.
OverviewPlugins are a major source of browser crashes. (Flash is in the callstack of a nontrivial percentage of Firefox crashes.) Plugins also make sandboxing the process where the renderer runs impractical, as plugins are written by third-parties and we can't control their access to the operating system. The solution is to run plugins in their own separate process.Detailed designPlugin interfacesTo run plugins in a separate process, the first step is to separate the code that needs to run in the same process as the plugin from the code that needs to run in the same process as the renderer. TheWebPlugin interface runs in the render process, and WebPluginDelegate is in the plugin process. All communication from the renderer to the plugin, and vice versa, goes through these interfaces.
With these interfaces, simply running plugins in process requires an implementation of The issues with running plugins in the same process as the renderer are:
Moving plugins out-of-processWhen running plugins in a separate process from the renderer, the For these two objects to communicate transparently, we use the proxy/stub concept from COM. Similarly, the Windowless PluginsWindowless plugins are designed to run directly within the rendering pipeline. When WebKit wants to draw a region of the screen involving the plugin it calls into the plugin code, handing it a drawing context. Windowless plugins are often used in situations where the plugin is expected to be transparent over the page -- it's up to the plugin drawing code to decide how it munges the bit of the page it's given. To take windowless plugins out of process, you still need to incorporate their rendering in the (synchronous) rendering pass done by WebKit. A naively slow option is to clip out the region that the plugin will draw on then synchronously ship that over to the plugin process and let it draw. This can then be sped up with some shared memory. However, rendering speed is then at the mercy of the plugin process (imagine a page with 30 transparent plugins -- we'd need 30 round trips to the plugin process). So instead we have windowless plugins asynchronously paint, much like how our existing page rendering is asynchronous with respect to the screen. The renderer has effectively a backing store of what the plugin's rendered area looks like and uses this image when drawing, and the plugin is free to asynchronously send over new updates representing changes to the rendered area. All of this is complicated a bit by "transparent" plugins. The plugin process needs to know what pixels it wants to draw over. So it also keeps a cache of what the renderer last sent it as the page background behind the plugin, then lets the plugin repeatedly draw over that. So, in all, here are the buffers involved for the region drawn by a windowless plugin: Renderer process - backing store of what the plugin last rendered as - shared memory with the plugin for receiving updates ("transport DIB") - copy of the page background behind the plugin (described below) Plugin process - copy of the page background behind the plugin, used as the source material when drawing - shared memory with the renderer for sending updates ("transport DIB") Why does the renderer keep a copy of the page background? Because if the page background changes, we need to synchronously get the plugin to redraw over the new background it will appear to lag. We can tell that the background changed by comparing the newly-rendered background against our copy of what the plugin thinks the background. Since the plugin and renderer processes are asynchronous with respect to one another, they need separate copies. |

