Big +1 from my side to shipping the RenderDocumentHost (maybe its cross-origin version to start with) being the right solution here — let's do it as soon as we can :). A few additional random thoughts below:
- I don't think that making RenderFrameHost::GetMainFrame returning nullptr is a good solution — it will require a significant amount of work to add a lot of null checks to the codebase — and we'll have to remove them after shipping RenderDocument, which doesn't sound ideal.
- Maintaining a parallel tree of Documents is possible, but seems to be a roundabout way to get to the RenderDocument. I think we can do this if we hit a major roadblock to RenderDocument, but I'd really like us to start with making a push towards RenderDocument.
- Making the most important individual callsites more robust is an option as well: they could explicitly check for RenderFrameHost::IsActive / GetLifecycleState to detect RFHs whose ancestors are not current in their frames.
Many places also use RFH::GetMainFrame to check if they are same-origin with the main frame or not. We could introduce a dedicated helper for this (e.g. RenderFrameHost::IsSameOriginWithPrimaryDocument), which will always return false to non-active RFHs.
This might nicely align with MPArch / Fenced Frames work, where we want to rethink what "same-origin with main frame" works for fenced frames anyway.
- (this idea is too exciting even for me and I'm pretty sure that it's unreasonable)
We already destroy child RenderFrameHosts before committing a new document in the parent RFH if there are no unload (or similar) handlers: when renderer is committing navigation, it detaches the frame (e.g. RemoteFrameHost::Detach), which means that browser processes
RenderFrameHostImpl::DeleteRenderFrame before processing DidCommitNavigation and if there are no unload handlers DeleteRenderFrame
causes RFH to be deleted in the same task. If there is an unload handler, the child RFH will outlive the document in the parent RFH.
There are two main reasons why we'd want to keep child RFH alive there — to ensure that the renderer process isn't destroyed before unload has a chance to run and to ensure that the (associated) IPCs sent from unload handler (e.g. ones modifying
window.name) are processed.
I believe that we can achieve the same effect without keeping RFHI alive — delaying process destruction is easy, and for processing IPCs (associated, as non-associated already don't have ordering guarantees) we can unbind LocalFrameHost interface and bind it again to a new smaller content-internal class.