{"id":97,"date":"2023-01-12T10:52:12","date_gmt":"2023-01-12T10:52:12","guid":{"rendered":"https:\/\/blogs.igalia.com\/mshin\/?p=97"},"modified":"2023-01-12T10:52:12","modified_gmt":"2023-01-12T10:52:12","slug":"removing-reference-frametreenode-from-renderframehost","status":"publish","type":"post","link":"https:\/\/blogs.igalia.com\/mshin\/2023\/01\/12\/removing-reference-frametreenode-from-renderframehost\/","title":{"rendered":"Removing Reference FrameTreeNode from RenderFrameHost"},"content":{"rendered":"\nMPArch stands for Multiple Pages Architecture, and the Chromium teams at Igalia and Google are working together on an MPArch project that unites the implementation of several features (back\/forward-cache, pre-rendering, guest views, and ports) that support multiple pages in the same tab but are implemented with different architecture models into a single architecture.\n\n\n\nI recommend you read <a href=\"https:\/\/blogs.igalia.com\/gyuyoung\/2022\/10\/13\/mparchmultiple-page-architecture-project-in-chromium\/\" target=\"_blank\" rel=\"noreferrer noopener\" aria-label=\"the recently posted blog by Que (opens in a new tab)\">the recently posted blog by Que<\/a> first if you are not familiar with MPArch. It will help you understand the detailed history and structure of MPArch.\n\n\n\nThis post assumes that the reader is familiar with the \/\/content API and describes the ongoing task of removing reference <code>FrameTreeNode<\/code> from <code>RenderFrameHost<\/code> on the MPArch project.\n\n\n\n\n<h3 class=\"wp-block-heading\">Relationship between <code>FrameTreeNode<\/code> and <code>RenderFrameHost<\/code> in MPArch<\/h3>\n\n\n\n\nThe main frame and iframe are mirrored as <code>FrameTreeNode<\/code> and the document of each frame is mirrored as <code>RenderFrameHost<\/code>. Each <code>FrameTreeNode<\/code> has a current <code>RenderFrameHost<\/code>, which can change over time as the frame is navigated.\n\n\n\nLet&#8217;s look at the relationship between <code>FrameTreeNode<\/code> and <code>RenderFrameHost<\/code> of features using the MPArch structure.\n\n\n\n<br><br><strong>BFCache<\/strong>\n\n\n\n<br>BFCache (back\/forward cache) is a feature to cache pages in-memory (preserving javascript state and the DOM state) when the user navigates away from them.\n\n\n\n\n<ul class=\"wp-block-gallery columns-1 is-cropped wp-block-gallery-1 is-layout-flex wp-block-gallery-is-layout-flex\"><li class=\"blocks-gallery-item\"><figure><img loading=\"lazy\" decoding=\"async\" width=\"940\" height=\"529\" src=\"https:\/\/blogs.igalia.com\/mshin\/files\/2023\/01\/bfcache-940x529.png\" alt=\"\" data-id=\"99\" data-link=\"https:\/\/blogs.igalia.com\/mshin\/?attachment_id=99\" class=\"wp-image-99\" srcset=\"https:\/\/blogs.igalia.com\/mshin\/files\/2023\/01\/bfcache-940x529.png 940w, https:\/\/blogs.igalia.com\/mshin\/files\/2023\/01\/bfcache-580x327.png 580w, https:\/\/blogs.igalia.com\/mshin\/files\/2023\/01\/bfcache-768x433.png 768w, https:\/\/blogs.igalia.com\/mshin\/files\/2023\/01\/bfcache.png 1298w\" sizes=\"auto, (max-width: 940px) 100vw, 940px\" \/><\/figure><\/li><\/ul>\n\n\n\n\nWhen the document of the new page is navigated, the existing document, <code>RenderFrameHost<\/code>, is saved in BFCache, and when the back\/forward action occurs, <code>RenderFrameHost<\/code> is restored from BFCache. The <code>FrameTreeNode<\/code> is kept when <code>RenderFrameHost<\/code> is saved\/restored.\n\n\n\n<br><br><strong>Prerendering<\/strong>\n\n\n\n<br>Prerender2 is a feature to pre-render the next page for faster navigation. In prerender, a document will be invisible to the user and isn&#8217;t allowed to show any UI changes, but the page is allowed to load and run in the background.\n\n\n\n\n<ul class=\"wp-block-gallery columns-1 is-cropped wp-block-gallery-2 is-layout-flex wp-block-gallery-is-layout-flex\"><li class=\"blocks-gallery-item\"><figure><img loading=\"lazy\" decoding=\"async\" width=\"940\" height=\"530\" src=\"https:\/\/blogs.igalia.com\/mshin\/files\/2023\/01\/prerender-940x530.png\" alt=\"\" data-id=\"101\" data-link=\"https:\/\/blogs.igalia.com\/mshin\/?attachment_id=101\" class=\"wp-image-101\" srcset=\"https:\/\/blogs.igalia.com\/mshin\/files\/2023\/01\/prerender-940x530.png 940w, https:\/\/blogs.igalia.com\/mshin\/files\/2023\/01\/prerender-580x327.png 580w, https:\/\/blogs.igalia.com\/mshin\/files\/2023\/01\/prerender-768x433.png 768w, https:\/\/blogs.igalia.com\/mshin\/files\/2023\/01\/prerender.png 1308w\" sizes=\"auto, (max-width: 940px) 100vw, 940px\" \/><\/figure><\/li><\/ul>\n\n\n\n\n\n<p style=\"font-size:14px;text-align:center\"><a href=\"https:\/\/docs.google.com\/document\/d\/1CV2uwpfWk-0kUucGv_yIkgoGrqVvRlTzyseZMEKq0HM\/edit\" target=\"_blank\" rel=\"noreferrer noopener\" aria-label=\"Navigation changes to support multiple pages in WebContents (opens in a new tab)\">Navigation changes to support multiple pages in WebContents<\/a><\/p>\n\n\n\n\nWhen the prerendered page is activated, the current <code>RenderFrameHost<\/code> that <code>FrameTreeNode<\/code> had is replaced with <code>RenderFrameHost<\/code> in Prerender.\n\n\n\n<br><br><strong>Fenced Frame<\/strong>\n\n\n\n<br>The fenced frame enforces a boundary between the embedding page and the cross-site embedded document such that user data visible to the two sites is not able to be joined together.\n\n\n\n\n<ul class=\"wp-block-gallery columns-1 is-cropped wp-block-gallery-3 is-layout-flex wp-block-gallery-is-layout-flex\"><li class=\"blocks-gallery-item\"><figure><img loading=\"lazy\" decoding=\"async\" width=\"940\" height=\"530\" src=\"https:\/\/blogs.igalia.com\/mshin\/files\/2023\/01\/fencedframe-940x530.png\" alt=\"\" data-id=\"102\" data-link=\"https:\/\/blogs.igalia.com\/mshin\/?attachment_id=102\" class=\"wp-image-102\" srcset=\"https:\/\/blogs.igalia.com\/mshin\/files\/2023\/01\/fencedframe-940x530.png 940w, https:\/\/blogs.igalia.com\/mshin\/files\/2023\/01\/fencedframe-580x327.png 580w, https:\/\/blogs.igalia.com\/mshin\/files\/2023\/01\/fencedframe-768x433.png 768w, https:\/\/blogs.igalia.com\/mshin\/files\/2023\/01\/fencedframe.png 1300w\" sizes=\"auto, (max-width: 940px) 100vw, 940px\" \/><\/figure><\/li><\/ul>\n\n\n\n\nThe fenced frame works similarly to the main frame for security and privacy-related access, and to the subframe for other cases on the browser side. To this end, it is wrapped as a dummy <code>FrameTreeNode<\/code> in <code>FrameTree<\/code>, and the fenced frame can be accessed through a delegate.\n\n\n\n<br><br><strong>GuestView &amp; Portals<\/strong>\n\n\n\n<br>Chromium implements a tag with a GuestVIew which is the templated base class for out-of-process frames in the chrome layer.<br>For more detail, please refer to <a rel=\"noreferrer noopener\" aria-label=\"Julie's blog (opens in a new tab)\" href=\"https:\/\/blogs.igalia.com\/jkim\/2022\/10\/18\/a-webview-tag-in-chromium\/\" target=\"_blank\">Julie&#8217;s blog<\/a>.\n\n\n\n<br><br>Portals allow the embedding of a page inside another page, which can later be activated and replace the main page.\n\n\n\n\n<ul class=\"wp-block-gallery columns-1 is-cropped wp-block-gallery-4 is-layout-flex wp-block-gallery-is-layout-flex\"><li class=\"blocks-gallery-item\"><figure><img loading=\"lazy\" decoding=\"async\" width=\"940\" height=\"488\" src=\"https:\/\/blogs.igalia.com\/mshin\/files\/2023\/01\/portal-1-940x488.png\" alt=\"\" data-id=\"104\" data-link=\"https:\/\/blogs.igalia.com\/mshin\/?attachment_id=104\" class=\"wp-image-104\" srcset=\"https:\/\/blogs.igalia.com\/mshin\/files\/2023\/01\/portal-1-940x488.png 940w, https:\/\/blogs.igalia.com\/mshin\/files\/2023\/01\/portal-1-580x301.png 580w, https:\/\/blogs.igalia.com\/mshin\/files\/2023\/01\/portal-1-768x399.png 768w, https:\/\/blogs.igalia.com\/mshin\/files\/2023\/01\/portal-1.png 1202w\" sizes=\"auto, (max-width: 940px) 100vw, 940px\" \/><\/figure><\/li><\/ul>\n\n\n\n\n\n<p style=\"font-size:14px;text-align:center\"><a href=\"https:\/\/docs.google.com\/document\/d\/1CV2uwpfWk-0kUucGv_yIkgoGrqVvRlTzyseZMEKq0HM\/edit\" target=\"_blank\" rel=\"noreferrer noopener\" aria-label=\"Navigation changes to support multiple pages in WebContents (opens in a new tab)\">Navigation changes to support multiple pages in WebContents<\/a><\/p>\n\n\n\n\n<br>The GuestView and Portals are implemented with a multiple <code>WebContents<\/code> model and considering refactoring to MPArch.\n\n\n\n<br><br><strong>Pending Deletion<\/strong>\n\n\n\n<br>When <code>RenderFrameHost<\/code> has started running unload handlers (this includes handlers for the <code>unload<\/code>, <code>pagehide<\/code>, and <code>visibilitychange<\/code> events) or when <code>RenderFrameHost<\/code> has completed running the unload handlers, <code>RenderFrameHost<\/code>&#8216;s lifecycle is in the pending Deletion.\n\n\n\n\n<h3 class=\"wp-block-heading\">Reference <code>FrameTreeNode<\/code> from <code>RenderFrameHost<\/code><\/h3>\n\n\n\n\nAccessing <code>FrameTreeNode<\/code> from <code>RenderFrameHost<\/code> that enters BFCache, accessing <code>FrameTreeNode<\/code> from old <code>RenderFrameHost<\/code> that has already been swapped from the prerendered page, or accessing <code>FrameTreeNode<\/code> in the pending deletion status all have security issues. Currently, <code>RenderFrameHost<\/code> has direct access to <code>FrameTreeNode<\/code> internally and exposed methods to allow access to <code>FrameTreeNode<\/code> externally.\n\n\n\n<br><br><a href=\"https:\/\/crbug.com\/1179502\" target=\"_blank\" rel=\"noreferrer noopener\" aria-label=\" (opens in a new tab)\">A meta bug 1179502<\/a> addresses this issue.\n\n\n\n<br><br><strong>Introduce <code>RenderFrameHostOwner<\/code><\/strong>\n\n\n\n<br><code>RenderFrameHostOwner<\/code> is an interface for <code>RenderFrameHost<\/code> to communicate with <code>FrameTreeNode<\/code> owning it which can be null or can change during the lifetime of <code>RenderFrameHost<\/code> to prevent accidental violation of implicit &#8220;associated FrameTreeNode stays the same&#8221; assumptions.\n\n\n\n<code>RenderFrameHostOwner<\/code> is,<\/p><br \/>\n\n\n\n\n<pre class=\"wp-block-code\"><code>  \/\/ - Owning FrameTreeNode for main RenderFrameHosts in kActive, kPrerender,\n  \/\/   kSpeculative or kPendingCommit lifecycle states.\n  \/\/ - Null for main RenderFrameHosts in kPendingDeletion lifecycle state.\n  \/\/ - Null for main RenderFrameHosts stored in BFCache.\n  \/\/ - Owning FrameTreeNode for subframes (which stays the same for the entire\n  \/\/   lifetime of a subframe RenderFrameHostImpl).<\/code><\/pre>\n\n\n\n\n\n<p style=\"font-size:14px;text-align:center\"><a href=\"https:\/\/source.chromium.org\/chromium\/chromium\/src\/+\/main:content\/browser\/renderer_host\/render_frame_host_impl.h;l=3794-3799;drc=3c15773d007439201c5d3f03d09aab8a4d96b956\" target=\"_blank\" rel=\"noreferrer noopener\" aria-label=\"\/\/content\/browser\/renderer_host\/render_frame_host_impl.h (opens in a new tab)\">\/\/content\/browser\/renderer_host\/render_frame_host_impl.h<\/a><\/p>\n\n<br>\n\n\n\nAt all places where <code>FrameTreeNode<\/code> is used, we are auditing them if we could replace <code>FrameTreeNode<\/code> with <code>RenderFrameHostOwner<\/code> after checking what lifecycle states of <code>RenderFrameHost<\/code> we can have. However, there are still some places that are not available to use <code>RenderFrameHostOwner<\/code> (e.g. unload handler). We are still investigating how to deal with these cases. It would be necessary to refactor <code>for RenderFrameHost::frame_tree_node()<\/code>, which is widely used inside and outside <code>RenderFrameHost<\/code>, and that work is ongoing.\n","protected":false},"excerpt":{"rendered":"<p>MPArch stands for Multiple Pages Architecture, and the Chromium teams at Igalia and Google are working together on an MPArch project that unites the implementation of several features (back\/forward-cache, pre-rendering, guest views, and ports) that support multiple pages in the same tab but are implemented with different architecture models into a single architecture. I recommend &hellip; <a href=\"https:\/\/blogs.igalia.com\/mshin\/2023\/01\/12\/removing-reference-frametreenode-from-renderframehost\/\" class=\"more-link\">Continue reading <span class=\"screen-reader-text\">Removing Reference FrameTreeNode from RenderFrameHost<\/span><\/a><\/p>\n","protected":false},"author":58,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[2,3],"tags":[4,6,9],"class_list":["post-97","post","type-post","status-publish","format-standard","hentry","category-chromium","category-igalia","tag-chromium","tag-igalia","tag-mparch"],"_links":{"self":[{"href":"https:\/\/blogs.igalia.com\/mshin\/wp-json\/wp\/v2\/posts\/97","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blogs.igalia.com\/mshin\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blogs.igalia.com\/mshin\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blogs.igalia.com\/mshin\/wp-json\/wp\/v2\/users\/58"}],"replies":[{"embeddable":true,"href":"https:\/\/blogs.igalia.com\/mshin\/wp-json\/wp\/v2\/comments?post=97"}],"version-history":[{"count":40,"href":"https:\/\/blogs.igalia.com\/mshin\/wp-json\/wp\/v2\/posts\/97\/revisions"}],"predecessor-version":[{"id":144,"href":"https:\/\/blogs.igalia.com\/mshin\/wp-json\/wp\/v2\/posts\/97\/revisions\/144"}],"wp:attachment":[{"href":"https:\/\/blogs.igalia.com\/mshin\/wp-json\/wp\/v2\/media?parent=97"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blogs.igalia.com\/mshin\/wp-json\/wp\/v2\/categories?post=97"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blogs.igalia.com\/mshin\/wp-json\/wp\/v2\/tags?post=97"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}