Move message routing from CefBrowser to CefFrame (see issue #2498).

This change moves the SendProcessMessage method from CefBrowser to CefFrame and
adds CefBrowser parameters to OnProcessMessageReceived and
OnDraggableRegionsChanged.

The internal implementation has changed as follows:
- Frame IDs are now a 64-bit combination of the 32-bit render_process_id and
  render_routing_id values that uniquely identify a RenderFrameHost (RFH).
- CefFrameHostImpl objects are now managed by CefBrowserInfo with life span tied
  to RFH expectations. Specifically, a CefFrameHostImpl object representing a
  sub-frame will be created when a RenderFrame is created in the renderer
  process and detached when the associated RenderFrame is deleted or the
  renderer process in which it runs has died.
- The CefFrameHostImpl object representing the main frame will always be valid
  but the underlying RFH (and associated frame ID) may change over time as a
  result of cross-origin navigations. Despite these changes calling LoadURL on
  the main frame object in the browser process will always navigate as expected.
- Speculative RFHs, which may be created as a result of a cross-origin
  navigation and discarded if that navigation is not committed, are now handled
  correctly (e.g. ignored in most cases until they're committed).
- It is less likely, but still possible, to receive a CefFrame object with an
  invalid frame ID (ID < 0). This can happen in cases where a RFH has not yet
  been created for a sub-frame. For example, when OnBeforeBrowse is called
  before initiating navigation in a previously nonexisting sub-frame.

To test: All tests pass with NetworkService enabled and disabled.
This commit is contained in:
Marshall Greenblatt
2019-05-24 23:23:43 +03:00
parent 35295d2e27
commit 241941a44a
80 changed files with 2382 additions and 2378 deletions

View File

@@ -65,13 +65,10 @@ scoped_refptr<CefBrowserInfo> CefBrowserInfoManager::CreateBrowserInfo(
CefRefPtr<CefDictionaryValue> extra_info) {
base::AutoLock lock_scope(browser_info_lock_);
scoped_refptr<CefBrowserInfo> browser_info =
new CefBrowserInfo(++next_browser_id_, is_popup, extra_info);
scoped_refptr<CefBrowserInfo> browser_info = new CefBrowserInfo(
++next_browser_id_, is_popup, is_windowless, extra_info);
browser_info_list_.push_back(browser_info);
if (is_windowless)
browser_info->set_windowless(true);
return browser_info;
}
@@ -81,32 +78,20 @@ scoped_refptr<CefBrowserInfo> CefBrowserInfoManager::CreatePopupBrowserInfo(
CefRefPtr<CefDictionaryValue> extra_info) {
base::AutoLock lock_scope(browser_info_lock_);
content::RenderFrameHost* frame_host = new_contents->GetMainFrame();
auto frame_host = new_contents->GetMainFrame();
const int render_process_id = frame_host->GetProcess()->GetID();
const int render_frame_routing_id = frame_host->GetRoutingID();
const auto frame_id = CefFrameHostImpl::MakeFrameId(frame_host);
scoped_refptr<CefBrowserInfo> browser_info =
new CefBrowserInfo(++next_browser_id_, true, extra_info);
browser_info->render_id_manager()->add_render_frame_id(
render_process_id, render_frame_routing_id);
new CefBrowserInfo(++next_browser_id_, true, is_windowless, extra_info);
browser_info_list_.push_back(browser_info);
if (is_windowless)
browser_info->set_windowless(true);
// Continue any pending NewBrowserInfo requests.
PendingNewBrowserInfoList::iterator it =
pending_new_browser_info_list_.begin();
for (; it != pending_new_browser_info_list_.end(); ++it) {
PendingNewBrowserInfo* info = it->get();
if (info->render_process_id == render_process_id &&
info->render_frame_routing_id == render_frame_routing_id) {
SendNewBrowserInfoResponse(render_process_id, browser_info, false,
info->reply_msg);
pending_new_browser_info_list_.erase(it);
break;
}
auto it = pending_new_browser_info_map_.find(frame_id);
if (it != pending_new_browser_info_map_.end()) {
SendNewBrowserInfoResponse(render_process_id, browser_info, false,
it->second->reply_msg);
pending_new_browser_info_map_.erase(it);
}
return browser_info;
@@ -159,8 +144,8 @@ bool CefBrowserInfoManager::CanCreateWindow(
auto pending_popup = std::make_unique<CefBrowserInfoManager::PendingPopup>();
pending_popup->step = CefBrowserInfoManager::PendingPopup::CAN_CREATE_WINDOW;
pending_popup->opener_process_id = opener->GetProcess()->GetID();
pending_popup->opener_frame_id = opener->GetRoutingID();
pending_popup->opener_render_process_id = opener->GetProcess()->GetID();
pending_popup->opener_render_routing_id = opener->GetRoutingID();
pending_popup->target_url = target_url;
pending_popup->target_frame_name = frame_name;
@@ -171,8 +156,8 @@ bool CefBrowserInfoManager::CanCreateWindow(
if (client.get()) {
CefRefPtr<CefLifeSpanHandler> handler = client->GetLifeSpanHandler();
if (handler.get()) {
CefRefPtr<CefFrame> frame =
browser->GetFrame(pending_popup->opener_frame_id);
CefRefPtr<CefFrame> opener_frame = browser->GetFrameForHost(opener);
DCHECK(opener_frame);
CefPopupFeatures cef_features;
TranslatePopupFeatures(features, cef_features);
@@ -190,7 +175,7 @@ bool CefBrowserInfoManager::CanCreateWindow(
#endif
allow = !handler->OnBeforePopup(
browser.get(), frame, pending_popup->target_url.spec(),
browser.get(), opener_frame, pending_popup->target_url.spec(),
pending_popup->target_frame_name,
static_cast<cef_window_open_disposition_t>(disposition), user_gesture,
cef_features, *window_info, pending_popup->client,
@@ -229,14 +214,14 @@ bool CefBrowserInfoManager::CanCreateWindow(
void CefBrowserInfoManager::GetCustomWebContentsView(
const GURL& target_url,
int opener_render_process_id,
int opener_render_frame_id,
int opener_render_routing_id,
content::WebContentsView** view,
content::RenderViewHostDelegateView** delegate_view) {
CEF_REQUIRE_UIT();
std::unique_ptr<CefBrowserInfoManager::PendingPopup> pending_popup =
PopPendingPopup(CefBrowserInfoManager::PendingPopup::CAN_CREATE_WINDOW,
opener_render_process_id, opener_render_frame_id,
opener_render_process_id, opener_render_routing_id,
target_url);
DCHECK(pending_popup.get());
DCHECK(pending_popup->platform_delegate.get());
@@ -254,7 +239,7 @@ void CefBrowserInfoManager::GetCustomWebContentsView(
void CefBrowserInfoManager::WebContentsCreated(
const GURL& target_url,
int opener_render_process_id,
int opener_render_frame_id,
int opener_render_routing_id,
CefBrowserSettings& settings,
CefRefPtr<CefClient>& client,
std::unique_ptr<CefBrowserPlatformDelegate>& platform_delegate,
@@ -264,7 +249,7 @@ void CefBrowserInfoManager::WebContentsCreated(
std::unique_ptr<CefBrowserInfoManager::PendingPopup> pending_popup =
PopPendingPopup(
CefBrowserInfoManager::PendingPopup::GET_CUSTOM_WEB_CONTENTS_VIEW,
opener_render_process_id, opener_render_frame_id, target_url);
opener_render_process_id, opener_render_routing_id, target_url);
DCHECK(pending_popup.get());
DCHECK(pending_popup->platform_delegate.get());
@@ -275,18 +260,18 @@ void CefBrowserInfoManager::WebContentsCreated(
}
void CefBrowserInfoManager::OnGetNewBrowserInfo(int render_process_id,
int render_frame_routing_id,
int render_routing_id,
IPC::Message* reply_msg) {
DCHECK_NE(render_process_id, content::ChildProcessHost::kInvalidUniqueID);
DCHECK_GT(render_frame_routing_id, 0);
DCHECK_GT(render_routing_id, 0);
DCHECK(reply_msg);
base::AutoLock lock_scope(browser_info_lock_);
bool is_guest_view = false;
scoped_refptr<CefBrowserInfo> browser_info = GetBrowserInfo(
render_process_id, render_frame_routing_id, &is_guest_view);
scoped_refptr<CefBrowserInfo> browser_info =
GetBrowserInfo(render_process_id, render_routing_id, &is_guest_view);
if (browser_info.get()) {
// Send the response immediately.
@@ -295,27 +280,20 @@ void CefBrowserInfoManager::OnGetNewBrowserInfo(int render_process_id,
return;
}
#if DCHECK_IS_ON()
const auto frame_id =
CefFrameHostImpl::MakeFrameId(render_process_id, render_routing_id);
// Verify that no request for the same route is currently queued.
{
PendingNewBrowserInfoList::const_iterator it =
pending_new_browser_info_list_.begin();
for (; it != pending_new_browser_info_list_.end(); ++it) {
PendingNewBrowserInfo* info = it->get();
if (info->render_process_id == render_process_id &&
info->render_frame_routing_id == render_frame_routing_id) {
NOTREACHED();
}
}
}
#endif
DCHECK(pending_new_browser_info_map_.find(frame_id) ==
pending_new_browser_info_map_.end());
// Queue the request.
std::unique_ptr<PendingNewBrowserInfo> pending(new PendingNewBrowserInfo());
pending->render_process_id = render_process_id;
pending->render_frame_routing_id = render_frame_routing_id;
pending->render_routing_id = render_routing_id;
pending->reply_msg = reply_msg;
pending_new_browser_info_list_.push_back(std::move(pending));
pending_new_browser_info_map_.insert(
std::make_pair(frame_id, std::move(pending)));
}
void CefBrowserInfoManager::RemoveBrowserInfo(
@@ -363,26 +341,32 @@ void CefBrowserInfoManager::DestroyAllBrowsers() {
#endif
}
scoped_refptr<CefBrowserInfo> CefBrowserInfoManager::GetBrowserInfoForFrame(
int render_process_id,
int render_routing_id,
bool* is_guest_view) {
scoped_refptr<CefBrowserInfo>
CefBrowserInfoManager::GetBrowserInfoForFrameRoute(int render_process_id,
int render_routing_id,
bool* is_guest_view) {
base::AutoLock lock_scope(browser_info_lock_);
return GetBrowserInfo(render_process_id, render_routing_id, is_guest_view);
}
scoped_refptr<CefBrowserInfo>
CefBrowserInfoManager::GetBrowserInfoForFrameTreeNode(int frame_tree_node_id) {
CefBrowserInfoManager::GetBrowserInfoForFrameTreeNode(int frame_tree_node_id,
bool* is_guest_view) {
if (is_guest_view)
*is_guest_view = false;
if (frame_tree_node_id < 0)
return nullptr;
base::AutoLock lock_scope(browser_info_lock_);
BrowserInfoList::const_iterator it = browser_info_list_.begin();
for (; it != browser_info_list_.end(); ++it) {
const scoped_refptr<CefBrowserInfo>& browser_info = *it;
if (browser_info->frame_tree_node_id_manager()->is_frame_tree_node_id_match(
frame_tree_node_id)) {
for (const auto& browser_info : browser_info_list_) {
bool is_guest_view_tmp;
auto frame = browser_info->GetFrameForFrameTreeNode(frame_tree_node_id,
&is_guest_view_tmp);
if (frame || is_guest_view_tmp) {
if (is_guest_view)
*is_guest_view = is_guest_view_tmp;
return browser_info;
}
}
@@ -390,9 +374,12 @@ CefBrowserInfoManager::GetBrowserInfoForFrameTreeNode(int frame_tree_node_id) {
return nullptr;
}
void CefBrowserInfoManager::GetBrowserInfoList(BrowserInfoList& list) {
CefBrowserInfoManager::BrowserInfoList
CefBrowserInfoManager::GetBrowserInfoList() {
base::AutoLock lock_scope(browser_info_lock_);
list = browser_info_list_;
BrowserInfoList copy;
copy.assign(browser_info_list_.begin(), browser_info_list_.end());
return copy;
}
void CefBrowserInfoManager::RenderProcessHostDestroyed(
@@ -406,12 +393,12 @@ void CefBrowserInfoManager::RenderProcessHostDestroyed(
{
base::AutoLock lock_scope(browser_info_lock_);
PendingNewBrowserInfoList::iterator it =
pending_new_browser_info_list_.begin();
while (it != pending_new_browser_info_list_.end()) {
PendingNewBrowserInfo* info = it->get();
PendingNewBrowserInfoMap::iterator it =
pending_new_browser_info_map_.begin();
while (it != pending_new_browser_info_map_.end()) {
auto info = it->second.get();
if (info->render_process_id == render_process_id)
it = pending_new_browser_info_list_.erase(it);
it = pending_new_browser_info_map_.erase(it);
else
++it;
}
@@ -422,7 +409,7 @@ void CefBrowserInfoManager::RenderProcessHostDestroyed(
PendingPopupList::iterator it = pending_popup_list_.begin();
while (it != pending_popup_list_.end()) {
PendingPopup* popup = it->get();
if (popup->opener_process_id == render_process_id) {
if (popup->opener_render_process_id == render_process_id) {
it = pending_popup_list_.erase(it);
} else {
++it;
@@ -439,18 +426,19 @@ void CefBrowserInfoManager::PushPendingPopup(
std::unique_ptr<CefBrowserInfoManager::PendingPopup>
CefBrowserInfoManager::PopPendingPopup(PendingPopup::Step step,
int opener_process_id,
int opener_frame_id,
int opener_render_process_id,
int opener_render_routing_id,
const GURL& target_url) {
CEF_REQUIRE_UIT();
DCHECK_GT(opener_process_id, 0);
DCHECK_GT(opener_frame_id, 0);
DCHECK_GT(opener_render_process_id, 0);
DCHECK_GT(opener_render_routing_id, 0);
PendingPopupList::iterator it = pending_popup_list_.begin();
for (; it != pending_popup_list_.end(); ++it) {
PendingPopup* popup = it->get();
if (popup->step == step && popup->opener_process_id == opener_process_id &&
popup->opener_frame_id == opener_frame_id &&
if (popup->step == step &&
popup->opener_render_process_id == opener_render_process_id &&
popup->opener_render_routing_id == opener_render_routing_id &&
popup->target_url == target_url) {
// Transfer ownership of the pointer.
it->release();
@@ -463,29 +451,24 @@ CefBrowserInfoManager::PopPendingPopup(PendingPopup::Step step,
}
scoped_refptr<CefBrowserInfo> CefBrowserInfoManager::GetBrowserInfo(
int render_frame_process_id,
int render_frame_routing_id,
int render_process_id,
int render_routing_id,
bool* is_guest_view) {
browser_info_lock_.AssertAcquired();
if (is_guest_view)
*is_guest_view = false;
if (render_frame_process_id < 0 || render_frame_routing_id < 0)
if (render_process_id < 0 || render_routing_id < 0)
return nullptr;
BrowserInfoList::const_iterator it = browser_info_list_.begin();
for (; it != browser_info_list_.end(); ++it) {
const scoped_refptr<CefBrowserInfo>& browser_info = *it;
if (browser_info->render_id_manager()->is_render_frame_id_match(
render_frame_process_id, render_frame_routing_id)) {
return browser_info;
}
if (extensions::ExtensionsEnabled() &&
browser_info->guest_render_id_manager()->is_render_frame_id_match(
render_frame_process_id, render_frame_routing_id)) {
for (const auto& browser_info : browser_info_list_) {
bool is_guest_view_tmp;
auto frame = browser_info->GetFrameForRoute(
render_process_id, render_routing_id, &is_guest_view_tmp);
if (frame || is_guest_view_tmp) {
if (is_guest_view)
*is_guest_view = true;
*is_guest_view = is_guest_view_tmp;
return browser_info;
}
}