This page provides high level information on our plans to support out-of-process iframes (OOPIF) in Chromium, as part of the Site Isolation project. The work is tracked in issue https://crbug.com/99379.
Many parts of Chromium's architecture will need to change to support rendering and interacting with a frame in a different process from its parent page. Our intended changes include keeping track of frames in multiple processes, routing certain script calls between processes, supporting cross-process navigations in frames, rendering and compositing frames in multiple processes, and sending input events to the correct processes.
Process Models page). BrowsingInstances often contain only a single tab, but they can include multiple tabs when a page uses window.open or targeted links. Note that BrowsingInstances are not related to the number of tabs in a window, since tabs created manually are in their own BrowsingInstance.
To support cross-process interactions like postMessage, Chromium must keep a proxy version of the document's DOMWindow in each of the other processes of its BrowsingInstance, as a placeholder. As shown in the diagram at right, this allows a document from site A to find a proxy DOMWindow in its own process for a tab that is currently active on site B. The proxy DOMWindow can then forward the postMessage call to the browser and then to the correct document in the process for site B.
With out-of-process iframes, Chromium needs to keep track of proxy DOMWindows for subframes as well as main frames.
In the browser process, Chromium must keep track of the full frame tree for each tab. WebContents will host a tree of FrameTreeNode objects, mirroring the frame tree of the current page. Each FrameTreeNode will contain frame-specific information (e.g., the frame's name). It will be responsible for cross-process navigations in the frame, and it will support routing messages from other processes to the active frame.
We plan to pull the frame-specific logic out of the content module's RenderView and RenderViewHost classes, into new RenderFrame and RenderFrameHost classes. These new classes will allocate their own routing ids, so IPC messages can be targeted to specific frames. We will have a full RenderFrame for every active frame, regardless of process, and we will have a corresponding, slimmed down RenderFrameProxy as a placeholder in the other processes of the BrowsingInstance. These proxies are shown with dashed lines in the diagram below, which shows one BrowsingInstance with two tabs, containing two subframes each.
It is important to note that remote frames and remote DOM windows have very little state: in general, the only state maintained in the remote proxy objects is data needed to service synchronous operations. For example, a remote DOM window does not have a Document object.
Both LocalFrame and RemoteFrame inherit from a new interface, Frame, which represents operations that are valid on both local and remote frames. It is possible to downcast from Frame to LocalFrame, but having to do this usually indicates that the code structure is suboptimal for OOPIF. In the blink API layer (Source/web), there are also corresponding WebLocalFrame / WebRemoteFrame / WebFrame classes. content::RenderFrame is responsible for managing a WebLocalFrame, while content::RemoteFrameProxy is responsible for managing a WebRemoteFrame.
In addition, Blink has the ability to swap any frame in the frame tree between the local and remote versions. Generally, the process of swapping frames should not be observable, but it's worth mentioning, because it will allow the current content::RenderView swap out logic to be removed. The current swap out implementation is tricky to understand, and prone to bugs: code incorrectly assumed that a content::RenderViewHost would never change, it required IPC filtering to make sure a swapped out page didn't try to do something funny, etc.
Finally, the <webview> implementation is being migrated to work on top of this new infrastructure. For the most part, Blink code will be able to treat a <webview> similar to an <iframe> However, there is one important difference: the parent frame of the root frame in an <iframe> is the document that contains the <iframe> element. The root frame of a <webview> has no parent and is itself a main frame. It will likely live in a separate frame tree.
These changes have several major implications for Blink:
Some further information on the refactoring goals can be found in the FrameHandle design doc, however that is largely obsolete.
Note: We are attempting to minimize the memory requirements of these swapped out RemoteFrames and RemoteDOMWindows, because there will be many more than in Chromium today. Today, the space required is O(tabs * processes) within a BrowsingInstance, and most BrowsingInstances only contain 1 or 2 tabs. This new model would require O(frames * processes) space. This could be much higher, because the number of frames can be much larger than the number of tabs, and because the number of processes will increase based on cross-site frames. Fortunately, RemoteFrames require far less memory than LocalFrames, and not all cross-site iframes will require separate processes.
A tab's session history also becomes more complicated when subframes may be rendered by different processes. Currently, Blink takes care of tracking the frame tree in each HistoryItem in the renderer process, and the browser process just tracks each back/forward entry using NavigationEntry. We will remove the frame tracking logic from Blink's HistoryController and keep track of each frame's navigations in the browser process directly.
We will also change the representation of a tab's session history to more closely match the HTML5 spec. Rather than cloning the frame tree for each HistoryItem, we will keep track of each frame's session history separately in the browser process, and we will use a separate "joint session history" list for back and forward navigations. Each entry in this list will have a tree of pointers to each frame's corresponding session history item. We expect this to require changes to the session restore logic as well.
All details of navigation refactoring are described in a design document.
To render an iframe in a different process than its parent frame, the browser process will pass information back and forth between the renderer processes and help the GPU process composite the images together in the correct sizes and locations. We expect to use the Surfaces implementation to maintain a set of textures from multiple renderer processes, compositing them into a single output image.
The design for rendering is encapsulated in a separate document.
We are continuing to investigate the changes required to support hit testing and delivering input events to the correct iframe process without having to ask multiple renderer processes. As with rendering, we expect to use the Surfaces implementation to do hit testing in the browser process to deliver input events directly to the intended frame's renderer process. We also need to manage focus in the browser process to send keyboard events directly to the renderer process of the focused frame.
The mailing list for technical discussions on Site Isolations and Out-of-Process iframes is firstname.lastname@example.org.