1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "content/browser/devtools/render_frame_devtools_agent_host.h"
6 
7 #include <set>
8 #include <string>
9 #include <tuple>
10 #include <utility>
11 
12 #include "base/bind.h"
13 #include "base/json/json_reader.h"
14 #include "base/lazy_instance.h"
15 #include "base/memory/ptr_util.h"
16 #include "base/strings/utf_string_conversions.h"
17 #include "base/task/post_task.h"
18 #include "build/build_config.h"
19 #include "content/browser/bad_message.h"
20 #include "content/browser/child_process_security_policy_impl.h"
21 #include "content/browser/devtools/devtools_manager.h"
22 #include "content/browser/devtools/devtools_renderer_channel.h"
23 #include "content/browser/devtools/devtools_session.h"
24 #include "content/browser/devtools/protocol/background_service_handler.h"
25 #include "content/browser/devtools/protocol/browser_handler.h"
26 #include "content/browser/devtools/protocol/dom_handler.h"
27 #include "content/browser/devtools/protocol/emulation_handler.h"
28 #include "content/browser/devtools/protocol/fetch_handler.h"
29 #include "content/browser/devtools/protocol/input_handler.h"
30 #include "content/browser/devtools/protocol/inspector_handler.h"
31 #include "content/browser/devtools/protocol/io_handler.h"
32 #include "content/browser/devtools/protocol/memory_handler.h"
33 #include "content/browser/devtools/protocol/network_handler.h"
34 #include "content/browser/devtools/protocol/overlay_handler.h"
35 #include "content/browser/devtools/protocol/page_handler.h"
36 #include "content/browser/devtools/protocol/protocol.h"
37 #include "content/browser/devtools/protocol/schema_handler.h"
38 #include "content/browser/devtools/protocol/security_handler.h"
39 #include "content/browser/devtools/protocol/service_worker_handler.h"
40 #include "content/browser/devtools/protocol/storage_handler.h"
41 #include "content/browser/devtools/protocol/target_handler.h"
42 #include "content/browser/devtools/protocol/tracing_handler.h"
43 #include "content/browser/frame_host/navigation_request.h"
44 #include "content/browser/frame_host/render_frame_host_impl.h"
45 #include "content/browser/renderer_host/render_process_host_impl.h"
46 #include "content/browser/renderer_host/render_view_host_impl.h"
47 #include "content/browser/site_instance_impl.h"
48 #include "content/browser/web_contents/web_contents_impl.h"
49 #include "content/browser/web_package/signed_exchange_envelope.h"
50 #include "content/common/view_messages.h"
51 #include "content/public/browser/back_forward_cache.h"
52 #include "content/public/browser/browser_context.h"
53 #include "content/public/browser/browser_task_traits.h"
54 #include "content/public/browser/browser_thread.h"
55 #include "content/public/browser/content_browser_client.h"
56 #include "content/public/browser/navigation_handle.h"
57 #include "content/public/browser/network_service_instance.h"
58 #include "content/public/browser/render_widget_host_iterator.h"
59 #include "content/public/browser/web_contents_delegate.h"
60 #include "mojo/public/cpp/bindings/associated_binding.h"
61 #include "third_party/blink/public/common/associated_interfaces/associated_interface_provider.h"
62 #include "third_party/blink/public/mojom/devtools/devtools_agent.mojom.h"
63 
64 #if defined(OS_ANDROID)
65 #include "content/browser/devtools/devtools_frame_trace_recorder.h"
66 #include "content/browser/renderer_host/compositor_impl_android.h"
67 #include "content/public/browser/render_widget_host_view.h"
68 #include "mojo/public/cpp/bindings/pending_receiver.h"
69 #include "services/device/public/mojom/wake_lock_context.mojom.h"
70 #elif BUILDFLAG(ENABLE_WEB_AUTH)
71 #include "content/browser/devtools/protocol/webauthn_handler.h"
72 #endif
73 
74 namespace content {
75 
76 namespace {
77 using RenderFrameDevToolsMap =
78     std::map<FrameTreeNode*, RenderFrameDevToolsAgentHost*>;
79 base::LazyInstance<RenderFrameDevToolsMap>::Leaky g_agent_host_instances =
80     LAZY_INSTANCE_INITIALIZER;
81 
FindAgentHost(FrameTreeNode * frame_tree_node)82 RenderFrameDevToolsAgentHost* FindAgentHost(FrameTreeNode* frame_tree_node) {
83   if (!g_agent_host_instances.IsCreated())
84     return nullptr;
85   auto it = g_agent_host_instances.Get().find(frame_tree_node);
86   return it == g_agent_host_instances.Get().end() ? nullptr : it->second;
87 }
88 
ShouldCreateDevToolsForNode(FrameTreeNode * ftn)89 bool ShouldCreateDevToolsForNode(FrameTreeNode* ftn) {
90   return !ftn->parent() || ftn->current_frame_host()->IsCrossProcessSubframe();
91 }
92 
GetFrameTreeNodeAncestor(FrameTreeNode * frame_tree_node)93 FrameTreeNode* GetFrameTreeNodeAncestor(FrameTreeNode* frame_tree_node) {
94   while (frame_tree_node && !ShouldCreateDevToolsForNode(frame_tree_node))
95     frame_tree_node = frame_tree_node->parent();
96   DCHECK(frame_tree_node);
97   return frame_tree_node;
98 }
99 
100 }  // namespace
101 
102 // static
103 scoped_refptr<DevToolsAgentHost>
GetOrCreateFor(WebContents * web_contents)104 DevToolsAgentHost::GetOrCreateFor(WebContents* web_contents) {
105   FrameTreeNode* node =
106       static_cast<WebContentsImpl*>(web_contents)->GetFrameTree()->root();
107   // TODO(dgozman): this check should not be necessary. See
108   // http://crbug.com/489664.
109   if (!node)
110     return nullptr;
111   return RenderFrameDevToolsAgentHost::GetOrCreateFor(node);
112 }
113 
114 // static
GetFor(FrameTreeNode * frame_tree_node)115 DevToolsAgentHostImpl* RenderFrameDevToolsAgentHost::GetFor(
116     FrameTreeNode* frame_tree_node) {
117   frame_tree_node = GetFrameTreeNodeAncestor(frame_tree_node);
118   return FindAgentHost(frame_tree_node);
119 }
120 
121 // static
GetFor(RenderFrameHostImpl * rfh)122 DevToolsAgentHostImpl* RenderFrameDevToolsAgentHost::GetFor(
123     RenderFrameHostImpl* rfh) {
124   return ShouldCreateDevToolsForHost(rfh)
125              ? FindAgentHost(rfh->frame_tree_node())
126              : GetFor(rfh->frame_tree_node());
127 }
128 
GetOrCreateFor(FrameTreeNode * frame_tree_node)129 scoped_refptr<DevToolsAgentHost> RenderFrameDevToolsAgentHost::GetOrCreateFor(
130     FrameTreeNode* frame_tree_node) {
131   frame_tree_node = GetFrameTreeNodeAncestor(frame_tree_node);
132   RenderFrameDevToolsAgentHost* result = FindAgentHost(frame_tree_node);
133   if (!result)
134     result = new RenderFrameDevToolsAgentHost(
135         frame_tree_node, frame_tree_node->current_frame_host());
136   return result;
137 }
138 
139 // static
ShouldCreateDevToolsForHost(RenderFrameHost * rfh)140 bool RenderFrameDevToolsAgentHost::ShouldCreateDevToolsForHost(
141     RenderFrameHost* rfh) {
142   return rfh->IsCrossProcessSubframe() || !rfh->GetParent();
143 }
144 
145 // static
146 scoped_refptr<DevToolsAgentHost>
CreateForCrossProcessNavigation(NavigationRequest * request)147 RenderFrameDevToolsAgentHost::CreateForCrossProcessNavigation(
148     NavigationRequest* request) {
149   // Note that this method does not use FrameTreeNode::current_frame_host(),
150   // since it is used while the frame host may not be set as current yet,
151   // for example right before commit time. Instead target frame from the
152   // navigation handle is used. When this method is invoked it's already known
153   // that the navigation will commit to the new frame host.
154   FrameTreeNode* frame_tree_node = request->frame_tree_node();
155   DCHECK(!FindAgentHost(frame_tree_node));
156   return new RenderFrameDevToolsAgentHost(frame_tree_node,
157                                           request->GetRenderFrameHost());
158 }
159 
160 // static
FindForDangling(FrameTreeNode * frame_tree_node)161 scoped_refptr<DevToolsAgentHost> RenderFrameDevToolsAgentHost::FindForDangling(
162     FrameTreeNode* frame_tree_node) {
163   return FindAgentHost(frame_tree_node);
164 }
165 
166 // static
HasFor(WebContents * web_contents)167 bool DevToolsAgentHost::HasFor(WebContents* web_contents) {
168   FrameTreeNode* node =
169       static_cast<WebContentsImpl*>(web_contents)->GetFrameTree()->root();
170   return node ? FindAgentHost(node) != nullptr : false;
171 }
172 
173 // static
IsDebuggerAttached(WebContents * web_contents)174 bool DevToolsAgentHost::IsDebuggerAttached(WebContents* web_contents) {
175   FrameTreeNode* node =
176       static_cast<WebContentsImpl*>(web_contents)->GetFrameTree()->root();
177   RenderFrameDevToolsAgentHost* host = node ? FindAgentHost(node) : nullptr;
178   return host && host->IsAttached();
179 }
180 
181 // static
AddAllAgentHosts(DevToolsAgentHost::List * result)182 void RenderFrameDevToolsAgentHost::AddAllAgentHosts(
183     DevToolsAgentHost::List* result) {
184   for (WebContentsImpl* wc : WebContentsImpl::GetAllWebContents()) {
185     for (FrameTreeNode* node : wc->GetFrameTree()->Nodes()) {
186       if (!node->current_frame_host() || !ShouldCreateDevToolsForNode(node))
187         continue;
188       if (!node->current_frame_host()->IsRenderFrameLive())
189         continue;
190       result->push_back(RenderFrameDevToolsAgentHost::GetOrCreateFor(node));
191     }
192   }
193 }
194 
195 // static
WebContentsCreated(WebContents * web_contents)196 void RenderFrameDevToolsAgentHost::WebContentsCreated(
197     WebContents* web_contents) {
198   if (ShouldForceCreation()) {
199     // Force agent host.
200     DevToolsAgentHost::GetOrCreateFor(web_contents);
201   }
202 }
203 
204 // static
UpdateRawHeadersAccess(RenderFrameHostImpl * old_rfh,RenderFrameHostImpl * new_rfh)205 void RenderFrameDevToolsAgentHost::UpdateRawHeadersAccess(
206     RenderFrameHostImpl* old_rfh,
207     RenderFrameHostImpl* new_rfh) {
208   DCHECK_NE(old_rfh, new_rfh);
209   RenderProcessHost* old_rph = old_rfh ? old_rfh->GetProcess() : nullptr;
210   RenderProcessHost* new_rph = new_rfh ? new_rfh->GetProcess() : nullptr;
211   if (old_rph == new_rph)
212     return;
213   std::set<url::Origin> old_process_origins;
214   std::set<url::Origin> new_process_origins;
215   for (const auto& entry : g_agent_host_instances.Get()) {
216     RenderFrameHostImpl* frame_host = entry.second->frame_host_;
217     if (!frame_host)
218       continue;
219     // Do not skip the nodes if they're about to get attached.
220     if (!entry.second->IsAttached() &&
221         (!new_rfh || entry.first != new_rfh->frame_tree_node())) {
222       continue;
223     }
224     RenderProcessHost* process_host = frame_host->GetProcess();
225     if (process_host == old_rph)
226       old_process_origins.insert(frame_host->GetLastCommittedOrigin());
227     else if (process_host == new_rph)
228       new_process_origins.insert(frame_host->GetLastCommittedOrigin());
229   }
230   if (old_rph) {
231     GetNetworkService()->SetRawHeadersAccess(
232         old_rph->GetID(), std::vector<url::Origin>(old_process_origins.begin(),
233                                                    old_process_origins.end()));
234   }
235   if (new_rph) {
236     GetNetworkService()->SetRawHeadersAccess(
237         new_rph->GetID(), std::vector<url::Origin>(new_process_origins.begin(),
238                                                    new_process_origins.end()));
239   }
240 }
241 
RenderFrameDevToolsAgentHost(FrameTreeNode * frame_tree_node,RenderFrameHostImpl * frame_host)242 RenderFrameDevToolsAgentHost::RenderFrameDevToolsAgentHost(
243     FrameTreeNode* frame_tree_node,
244     RenderFrameHostImpl* frame_host)
245     : DevToolsAgentHostImpl(frame_tree_node->devtools_frame_token().ToString()),
246       frame_tree_node_(nullptr) {
247   SetFrameTreeNode(frame_tree_node);
248   ChangeFrameHostAndObservedProcess(frame_host);
249   render_frame_alive_ = frame_host_ && frame_host_->IsRenderFrameLive();
250   if (frame_tree_node->parent()) {
251     render_frame_crashed_ = !render_frame_alive_;
252   } else {
253     WebContents* web_contents = WebContents::FromRenderFrameHost(frame_host);
254     render_frame_crashed_ = web_contents && web_contents->IsCrashed();
255   }
256   AddRef();  // Balanced in DestroyOnRenderFrameGone.
257   NotifyCreated();
258 }
259 
SetFrameTreeNode(FrameTreeNode * frame_tree_node)260 void RenderFrameDevToolsAgentHost::SetFrameTreeNode(
261     FrameTreeNode* frame_tree_node) {
262   if (frame_tree_node_)
263     g_agent_host_instances.Get().erase(frame_tree_node_);
264   frame_tree_node_ = frame_tree_node;
265   if (frame_tree_node_) {
266     // TODO(dgozman): with ConnectWebContents/DisconnectWebContents,
267     // we may get two agent hosts for the same FrameTreeNode.
268     // That is definitely a bug, and we should fix that, and DCHECK
269     // here that there is no other agent host.
270     g_agent_host_instances.Get()[frame_tree_node] = this;
271   }
272   WebContentsObserver::Observe(
273       frame_tree_node_ ? WebContentsImpl::FromFrameTreeNode(frame_tree_node_)
274                        : nullptr);
275 }
276 
GetBrowserContext()277 BrowserContext* RenderFrameDevToolsAgentHost::GetBrowserContext() {
278   WebContents* contents = web_contents();
279   return contents ? contents->GetBrowserContext() : nullptr;
280 }
281 
GetWebContents()282 WebContents* RenderFrameDevToolsAgentHost::GetWebContents() {
283   return web_contents();
284 }
285 
AttachSession(DevToolsSession * session)286 bool RenderFrameDevToolsAgentHost::AttachSession(DevToolsSession* session) {
287   if (!ShouldAllowSession(session))
288     return false;
289 
290   auto emulation_handler = std::make_unique<protocol::EmulationHandler>();
291   protocol::EmulationHandler* emulation_handler_ptr = emulation_handler.get();
292 
293   session->AddHandler(std::make_unique<protocol::BackgroundServiceHandler>());
294   auto browser_handler = std::make_unique<protocol::BrowserHandler>(
295       session->GetClient()->MayWriteLocalFiles());
296   auto* browser_handler_ptr = browser_handler.get();
297   session->AddHandler(std::move(browser_handler));
298   session->AddHandler(std::make_unique<protocol::DOMHandler>(
299       session->GetClient()->MayReadLocalFiles()));
300   session->AddHandler(std::move(emulation_handler));
301   auto input_handler = std::make_unique<protocol::InputHandler>();
302   input_handler->OnPageScaleFactorChanged(page_scale_factor_);
303   session->AddHandler(std::move(input_handler));
304   session->AddHandler(std::make_unique<protocol::InspectorHandler>());
305   session->AddHandler(std::make_unique<protocol::IOHandler>(GetIOContext()));
306   session->AddHandler(std::make_unique<protocol::MemoryHandler>());
307   if (!frame_tree_node_ || !frame_tree_node_->parent())
308     session->AddHandler(std::make_unique<protocol::OverlayHandler>());
309   session->AddHandler(std::make_unique<protocol::NetworkHandler>(
310       GetId(),
311       frame_tree_node_ ? frame_tree_node_->devtools_frame_token()
312                        : base::UnguessableToken(),
313       GetIOContext(),
314       base::BindRepeating(
315           &RenderFrameDevToolsAgentHost::UpdateResourceLoaderFactories,
316           base::Unretained(this))));
317   session->AddHandler(std::make_unique<protocol::FetchHandler>(
318       GetIOContext(), base::BindRepeating(
319                           [](RenderFrameDevToolsAgentHost* self,
320                              base::OnceClosure done_callback) {
321                             self->UpdateResourceLoaderFactories();
322                             std::move(done_callback).Run();
323                           },
324                           base::Unretained(this))));
325   session->AddHandler(std::make_unique<protocol::SchemaHandler>());
326   const bool may_attach_to_brower = session->GetClient()->MayAttachToBrowser();
327   session->AddHandler(std::make_unique<protocol::ServiceWorkerHandler>(
328       /* allow_inspect_worker= */ may_attach_to_brower));
329   session->AddHandler(std::make_unique<protocol::StorageHandler>());
330   session->AddHandler(std::make_unique<protocol::TargetHandler>(
331       may_attach_to_brower
332           ? protocol::TargetHandler::AccessMode::kRegular
333           : protocol::TargetHandler::AccessMode::kAutoAttachOnly,
334       GetId(), GetRendererChannel(), session->GetRootSession()));
335   session->AddHandler(std::make_unique<protocol::PageHandler>(
336       emulation_handler_ptr, browser_handler_ptr,
337       session->GetClient()->MayReadLocalFiles()));
338   session->AddHandler(std::make_unique<protocol::SecurityHandler>());
339   if (!frame_tree_node_ || !frame_tree_node_->parent()) {
340     session->AddHandler(std::make_unique<protocol::TracingHandler>(
341         frame_tree_node_, GetIOContext()));
342   }
343 #if BUILDFLAG(ENABLE_WEB_AUTH)
344   session->AddHandler(std::make_unique<protocol::WebAuthnHandler>());
345 #endif  // BUILDFLAG(ENABLE_WEB_AUTH)
346 
347   if (sessions().empty()) {
348 #ifdef OS_ANDROID
349     // With video capture API snapshots happen in TracingHandler. However, the
350     // video capture API cannot be used with Android WebView so
351     // DevToolsFrameTraceRecorder takes snapshots.
352     if (!CompositorImpl::IsInitialized())
353       frame_trace_recorder_ = std::make_unique<DevToolsFrameTraceRecorder>();
354 #endif
355     UpdateRawHeadersAccess(nullptr, frame_host_);
356 #if defined(OS_ANDROID)
357     GetWakeLock()->RequestWakeLock();
358 #endif
359   }
360   return true;
361 }
362 
DetachSession(DevToolsSession * session)363 void RenderFrameDevToolsAgentHost::DetachSession(DevToolsSession* session) {
364   // Destroying session automatically detaches in renderer.
365   if (sessions().empty()) {
366 #if defined(OS_ANDROID)
367     frame_trace_recorder_.reset();
368 #endif
369     UpdateRawHeadersAccess(frame_host_, nullptr);
370 #if defined(OS_ANDROID)
371     GetWakeLock()->CancelWakeLock();
372 #endif
373   }
374 }
375 
InspectElement(RenderFrameHost * frame_host,int x,int y)376 void RenderFrameDevToolsAgentHost::InspectElement(RenderFrameHost* frame_host,
377                                                   int x,
378                                                   int y) {
379   FrameTreeNode* ftn =
380       static_cast<RenderFrameHostImpl*>(frame_host)->frame_tree_node();
381   RenderFrameDevToolsAgentHost* host =
382       static_cast<RenderFrameDevToolsAgentHost*>(GetOrCreateFor(ftn).get());
383 
384   gfx::Point point(x, y);
385   // The renderer expects coordinates relative to the local frame root,
386   // so we need to transform the coordinates from the root space
387   // to the local frame root widget's space.
388   if (host->frame_host_) {
389     if (RenderWidgetHostView* view = host->frame_host_->GetView()) {
390       point = gfx::ToRoundedPoint(
391           view->TransformRootPointToViewCoordSpace(gfx::PointF(point)));
392     }
393   }
394   host->GetRendererChannel()->InspectElement(point);
395 }
396 
~RenderFrameDevToolsAgentHost()397 RenderFrameDevToolsAgentHost::~RenderFrameDevToolsAgentHost() {
398   SetFrameTreeNode(nullptr);
399   ChangeFrameHostAndObservedProcess(nullptr);
400 }
401 
ReadyToCommitNavigation(NavigationHandle * navigation_handle)402 void RenderFrameDevToolsAgentHost::ReadyToCommitNavigation(
403     NavigationHandle* navigation_handle) {
404   NavigationRequest* request = NavigationRequest::From(navigation_handle);
405   for (auto* tracing : protocol::TracingHandler::ForAgentHost(this))
406     tracing->ReadyToCommitNavigation(request);
407 
408   if (request->frame_tree_node() != frame_tree_node_) {
409     if (ShouldForceCreation() && request->GetRenderFrameHost() &&
410         request->GetRenderFrameHost()->IsCrossProcessSubframe()) {
411       // An agent may have been created earlier if auto attach is on.
412       if (!FindAgentHost(request->frame_tree_node()))
413         CreateForCrossProcessNavigation(request);
414     }
415     return;
416   }
417 
418   // Child workers will eventually disconnect, but timing depends on the
419   // renderer process. To ensure consistent view over protocol, disconnect them
420   // right now.
421   GetRendererChannel()->ForceDetachWorkerSessions();
422   UpdateFrameHost(request->GetRenderFrameHost());
423   // UpdateFrameHost may destruct |this|.
424 }
425 
DidFinishNavigation(NavigationHandle * navigation_handle)426 void RenderFrameDevToolsAgentHost::DidFinishNavigation(
427     NavigationHandle* navigation_handle) {
428   NavigationRequest* request = NavigationRequest::From(navigation_handle);
429   if (request->frame_tree_node() != frame_tree_node_)
430     return;
431   navigation_requests_.erase(request);
432   if (request->HasCommitted())
433     NotifyNavigated();
434 
435   // UpdateFrameHost may destruct |this|.
436   scoped_refptr<RenderFrameDevToolsAgentHost> protect(this);
437   UpdateFrameHost(frame_tree_node_->current_frame_host());
438 
439   if (navigation_requests_.empty()) {
440     for (DevToolsSession* session : sessions())
441       session->ResumeSendingMessagesToAgent();
442   }
443   for (auto* target : protocol::TargetHandler::ForAgentHost(this))
444     target->DidFinishNavigation();
445 
446   // RenderFrameDevToolsAgentHost is associated with frame_tree_node, while
447   // documents in the back-forward cache share a node, therefore we can't cache
448   // them. TODO(1001087): add support long-term.
449   content::BackForwardCache::DisableForRenderFrameHost(
450       navigation_handle->GetPreviousRenderFrameHostId(),
451       "RenderFrameDevToolsAgentHost");
452 }
453 
UpdateFrameHost(RenderFrameHostImpl * frame_host)454 void RenderFrameDevToolsAgentHost::UpdateFrameHost(
455     RenderFrameHostImpl* frame_host) {
456   if (frame_host == frame_host_) {
457     if (frame_host && !render_frame_alive_)
458       UpdateFrameAlive();
459     return;
460   }
461 
462   if (frame_host && !ShouldCreateDevToolsForHost(frame_host)) {
463     DestroyOnRenderFrameGone();
464     // |this| may be deleted at this point.
465     return;
466   }
467 
468   RenderFrameHostImpl* old_host = frame_host_;
469   ChangeFrameHostAndObservedProcess(frame_host);
470   if (IsAttached())
471     UpdateRawHeadersAccess(old_host, frame_host);
472 
473   std::vector<DevToolsSession*> restricted_sessions;
474   for (DevToolsSession* session : sessions()) {
475     if (!ShouldAllowSession(session))
476       restricted_sessions.push_back(session);
477   }
478   if (!restricted_sessions.empty())
479     ForceDetachRestrictedSessions(restricted_sessions);
480 
481   UpdateFrameAlive();
482 }
483 
DidStartNavigation(NavigationHandle * navigation_handle)484 void RenderFrameDevToolsAgentHost::DidStartNavigation(
485     NavigationHandle* navigation_handle) {
486   NavigationRequest* request = NavigationRequest::From(navigation_handle);
487   if (request->frame_tree_node() != frame_tree_node_)
488     return;
489   if (navigation_requests_.empty()) {
490     for (DevToolsSession* session : sessions())
491       session->SuspendSendingMessagesToAgent();
492   }
493   navigation_requests_.insert(request);
494 }
495 
RenderFrameHostChanged(RenderFrameHost * old_host,RenderFrameHost * new_host)496 void RenderFrameDevToolsAgentHost::RenderFrameHostChanged(
497     RenderFrameHost* old_host,
498     RenderFrameHost* new_host) {
499   auto* new_host_impl = static_cast<RenderFrameHostImpl*>(new_host);
500   FrameTreeNode* frame_tree_node = new_host_impl->frame_tree_node();
501   if (frame_tree_node != frame_tree_node_)
502     return;
503   UpdateFrameHost(new_host_impl);
504   // UpdateFrameHost may destruct |this|.
505 }
506 
FrameDeleted(RenderFrameHost * rfh)507 void RenderFrameDevToolsAgentHost::FrameDeleted(RenderFrameHost* rfh) {
508   RenderFrameHostImpl* host = static_cast<RenderFrameHostImpl*>(rfh);
509   for (auto* tracing : protocol::TracingHandler::ForAgentHost(this))
510     tracing->FrameDeleted(host);
511   if (host->frame_tree_node() == frame_tree_node_) {
512     DestroyOnRenderFrameGone();
513     // |this| may be deleted at this point.
514   }
515 }
516 
RenderFrameDeleted(RenderFrameHost * rfh)517 void RenderFrameDevToolsAgentHost::RenderFrameDeleted(RenderFrameHost* rfh) {
518   if (rfh == frame_host_) {
519     render_frame_alive_ = false;
520     UpdateRendererChannel(IsAttached());
521   }
522 }
523 
DestroyOnRenderFrameGone()524 void RenderFrameDevToolsAgentHost::DestroyOnRenderFrameGone() {
525   scoped_refptr<RenderFrameDevToolsAgentHost> protect(this);
526   if (IsAttached()) {
527     ForceDetachAllSessions();
528     UpdateRawHeadersAccess(frame_host_, nullptr);
529   }
530   ChangeFrameHostAndObservedProcess(nullptr);
531   UpdateRendererChannel(IsAttached());
532   SetFrameTreeNode(nullptr);
533   Release();
534 }
535 
536 #if defined(OS_ANDROID)
GetWakeLock()537 device::mojom::WakeLock* RenderFrameDevToolsAgentHost::GetWakeLock() {
538   // Here is a lazy binding, and will not reconnect after connection error.
539   if (!wake_lock_) {
540     mojo::PendingReceiver<device::mojom::WakeLock> receiver =
541         wake_lock_.BindNewPipeAndPassReceiver();
542     device::mojom::WakeLockContext* wake_lock_context =
543         web_contents()->GetWakeLockContext();
544     if (wake_lock_context) {
545       wake_lock_context->GetWakeLock(
546           device::mojom::WakeLockType::kPreventDisplaySleep,
547           device::mojom::WakeLockReason::kOther, "DevTools",
548           std::move(receiver));
549     }
550   }
551   return wake_lock_.get();
552 }
553 #endif
554 
ChangeFrameHostAndObservedProcess(RenderFrameHostImpl * frame_host)555 void RenderFrameDevToolsAgentHost::ChangeFrameHostAndObservedProcess(
556     RenderFrameHostImpl* frame_host) {
557   if (frame_host_)
558     frame_host_->GetProcess()->RemoveObserver(this);
559   frame_host_ = frame_host;
560   if (frame_host_)
561     frame_host_->GetProcess()->AddObserver(this);
562 }
563 
UpdateFrameAlive()564 void RenderFrameDevToolsAgentHost::UpdateFrameAlive() {
565   render_frame_alive_ = frame_host_ && frame_host_->IsRenderFrameLive();
566   if (render_frame_alive_ && render_frame_crashed_) {
567     render_frame_crashed_ = false;
568     for (auto* inspector : protocol::InspectorHandler::ForAgentHost(this))
569       inspector->TargetReloadedAfterCrash();
570   }
571   UpdateRendererChannel(IsAttached());
572 }
573 
RenderProcessExited(RenderProcessHost * host,const ChildProcessTerminationInfo & info)574 void RenderFrameDevToolsAgentHost::RenderProcessExited(
575     RenderProcessHost* host,
576     const ChildProcessTerminationInfo& info) {
577   switch (info.status) {
578     case base::TERMINATION_STATUS_ABNORMAL_TERMINATION:
579     case base::TERMINATION_STATUS_PROCESS_WAS_KILLED:
580 #if defined(OS_CHROMEOS)
581     case base::TERMINATION_STATUS_PROCESS_WAS_KILLED_BY_OOM:
582 #endif
583     case base::TERMINATION_STATUS_PROCESS_CRASHED:
584 #if defined(OS_ANDROID)
585     case base::TERMINATION_STATUS_OOM_PROTECTED:
586 #endif
587     case base::TERMINATION_STATUS_LAUNCH_FAILED:
588       for (auto* inspector : protocol::InspectorHandler::ForAgentHost(this))
589         inspector->TargetCrashed();
590       NotifyCrashed(info.status);
591       render_frame_crashed_ = true;
592       break;
593     default:
594       for (auto* inspector : protocol::InspectorHandler::ForAgentHost(this))
595         inspector->TargetDetached("Render process gone.");
596       break;
597   }
598 }
599 
DidAttachInterstitialPage()600 void RenderFrameDevToolsAgentHost::DidAttachInterstitialPage() {
601   for (auto* page : protocol::PageHandler::ForAgentHost(this))
602     page->DidAttachInterstitialPage();
603 }
604 
DidDetachInterstitialPage()605 void RenderFrameDevToolsAgentHost::DidDetachInterstitialPage() {
606   for (auto* page : protocol::PageHandler::ForAgentHost(this))
607     page->DidDetachInterstitialPage();
608 }
609 
OnVisibilityChanged(content::Visibility visibility)610 void RenderFrameDevToolsAgentHost::OnVisibilityChanged(
611     content::Visibility visibility) {
612 #if defined(OS_ANDROID)
613   if (!sessions().empty()) {
614     if (visibility == content::Visibility::HIDDEN) {
615       GetWakeLock()->CancelWakeLock();
616     } else {
617       GetWakeLock()->RequestWakeLock();
618     }
619   }
620 #endif
621 }
622 
OnPageScaleFactorChanged(float page_scale_factor)623 void RenderFrameDevToolsAgentHost::OnPageScaleFactorChanged(
624     float page_scale_factor) {
625   page_scale_factor_ = page_scale_factor;
626   for (auto* input : protocol::InputHandler::ForAgentHost(this))
627     input->OnPageScaleFactorChanged(page_scale_factor);
628 }
629 
OnNavigationRequestWillBeSent(const NavigationRequest & navigation_request)630 void RenderFrameDevToolsAgentHost::OnNavigationRequestWillBeSent(
631     const NavigationRequest& navigation_request) {
632   GURL url = navigation_request.common_params().url;
633   if (url.SchemeIs(url::kJavaScriptScheme) && frame_host_)
634     url = frame_host_->GetLastCommittedURL();
635   std::vector<DevToolsSession*> restricted_sessions;
636   bool is_webui = frame_host_ && frame_host_->web_ui();
637   for (DevToolsSession* session : sessions()) {
638     if (!session->GetClient()->MayAttachToURL(url, is_webui))
639       restricted_sessions.push_back(session);
640   }
641   if (!restricted_sessions.empty())
642     ForceDetachRestrictedSessions(restricted_sessions);
643 }
644 
DisconnectWebContents()645 void RenderFrameDevToolsAgentHost::DisconnectWebContents() {
646   navigation_requests_.clear();
647   SetFrameTreeNode(nullptr);
648   // UpdateFrameHost may destruct |this|.
649   scoped_refptr<RenderFrameDevToolsAgentHost> protect(this);
650   UpdateFrameHost(nullptr);
651   for (DevToolsSession* session : sessions())
652     session->ResumeSendingMessagesToAgent();
653 }
654 
ConnectWebContents(WebContents * wc)655 void RenderFrameDevToolsAgentHost::ConnectWebContents(WebContents* wc) {
656   RenderFrameHostImpl* host =
657       static_cast<RenderFrameHostImpl*>(wc->GetMainFrame());
658   DCHECK(host);
659   SetFrameTreeNode(host->frame_tree_node());
660   UpdateFrameHost(host);
661   // UpdateFrameHost may destruct |this|.
662 }
663 
GetParentId()664 std::string RenderFrameDevToolsAgentHost::GetParentId() {
665   if (IsChildFrame()) {
666     FrameTreeNode* frame_tree_node =
667         GetFrameTreeNodeAncestor(frame_tree_node_->parent());
668     return RenderFrameDevToolsAgentHost::GetOrCreateFor(frame_tree_node)
669         ->GetId();
670   }
671 
672   WebContentsImpl* contents = static_cast<WebContentsImpl*>(web_contents());
673   if (!contents)
674     return "";
675   contents = contents->GetOuterWebContents();
676   if (contents)
677     return DevToolsAgentHost::GetOrCreateFor(contents)->GetId();
678   return "";
679 }
680 
GetOpenerId()681 std::string RenderFrameDevToolsAgentHost::GetOpenerId() {
682   if (!frame_tree_node_)
683     return std::string();
684   FrameTreeNode* opener = frame_tree_node_->original_opener();
685   return opener ? opener->devtools_frame_token().ToString() : std::string();
686 }
687 
GetType()688 std::string RenderFrameDevToolsAgentHost::GetType() {
689   if (web_contents() &&
690       static_cast<WebContentsImpl*>(web_contents())->IsPortal()) {
691     return kTypePage;
692   }
693   if (web_contents() &&
694       static_cast<WebContentsImpl*>(web_contents())->GetOuterWebContents()) {
695     return kTypeGuest;
696   }
697   if (IsChildFrame())
698     return kTypeFrame;
699   DevToolsManager* manager = DevToolsManager::GetInstance();
700   if (manager->delegate() && web_contents()) {
701     std::string type = manager->delegate()->GetTargetType(web_contents());
702     if (!type.empty())
703       return type;
704   }
705   return kTypePage;
706 }
707 
GetTitle()708 std::string RenderFrameDevToolsAgentHost::GetTitle() {
709   DevToolsManager* manager = DevToolsManager::GetInstance();
710   if (manager->delegate() && web_contents()) {
711     std::string title = manager->delegate()->GetTargetTitle(web_contents());
712     if (!title.empty())
713       return title;
714   }
715   if (IsChildFrame() && frame_host_)
716     return frame_host_->GetLastCommittedURL().spec();
717   if (web_contents())
718     return base::UTF16ToUTF8(web_contents()->GetTitle());
719   return GetURL().spec();
720 }
721 
GetDescription()722 std::string RenderFrameDevToolsAgentHost::GetDescription() {
723   DevToolsManager* manager = DevToolsManager::GetInstance();
724   if (manager->delegate() && web_contents())
725     return manager->delegate()->GetTargetDescription(web_contents());
726   return std::string();
727 }
728 
GetURL()729 GURL RenderFrameDevToolsAgentHost::GetURL() {
730   // Order is important here.
731   WebContents* web_contents = GetWebContents();
732   if (web_contents && !IsChildFrame())
733     return web_contents->GetVisibleURL();
734   if (frame_host_)
735     return frame_host_->GetLastCommittedURL();
736   return GURL();
737 }
738 
GetFaviconURL()739 GURL RenderFrameDevToolsAgentHost::GetFaviconURL() {
740   WebContents* wc = web_contents();
741   if (!wc)
742     return GURL();
743   NavigationEntry* entry = wc->GetController().GetLastCommittedEntry();
744   if (entry)
745     return entry->GetFavicon().url;
746   return GURL();
747 }
748 
Activate()749 bool RenderFrameDevToolsAgentHost::Activate() {
750   WebContentsImpl* wc = static_cast<WebContentsImpl*>(web_contents());
751   if (wc) {
752     wc->Activate();
753     return true;
754   }
755   return false;
756 }
757 
Reload()758 void RenderFrameDevToolsAgentHost::Reload() {
759   WebContentsImpl* wc = static_cast<WebContentsImpl*>(web_contents());
760   if (wc)
761     wc->GetController().Reload(ReloadType::NORMAL, true);
762 }
763 
Close()764 bool RenderFrameDevToolsAgentHost::Close() {
765   if (web_contents()) {
766     web_contents()->ClosePage();
767     return true;
768   }
769   return false;
770 }
771 
GetLastActivityTime()772 base::TimeTicks RenderFrameDevToolsAgentHost::GetLastActivityTime() {
773   if (WebContents* contents = web_contents())
774     return contents->GetLastActiveTime();
775   return base::TimeTicks();
776 }
777 
778 #if defined(OS_ANDROID)
SignalSynchronousSwapCompositorFrame(RenderFrameHost * frame_host,const cc::RenderFrameMetadata & frame_metadata)779 void RenderFrameDevToolsAgentHost::SignalSynchronousSwapCompositorFrame(
780     RenderFrameHost* frame_host,
781     const cc::RenderFrameMetadata& frame_metadata) {
782   scoped_refptr<RenderFrameDevToolsAgentHost> dtah(FindAgentHost(
783       static_cast<RenderFrameHostImpl*>(frame_host)->frame_tree_node()));
784   if (dtah) {
785     // Unblock the compositor.
786     base::PostTask(
787         FROM_HERE, {BrowserThread::UI},
788         base::BindOnce(
789             &RenderFrameDevToolsAgentHost::SynchronousSwapCompositorFrame,
790             dtah.get(), frame_metadata));
791   }
792 }
793 
SynchronousSwapCompositorFrame(const cc::RenderFrameMetadata & frame_metadata)794 void RenderFrameDevToolsAgentHost::SynchronousSwapCompositorFrame(
795     const cc::RenderFrameMetadata& frame_metadata) {
796   for (auto* page : protocol::PageHandler::ForAgentHost(this))
797     page->OnSynchronousSwapCompositorFrame(frame_metadata);
798 
799   if (!frame_trace_recorder_)
800     return;
801   bool did_initiate_recording = false;
802   for (auto* tracing : protocol::TracingHandler::ForAgentHost(this))
803     did_initiate_recording |= tracing->did_initiate_recording();
804   if (did_initiate_recording) {
805     frame_trace_recorder_->OnSynchronousSwapCompositorFrame(frame_host_,
806                                                             frame_metadata);
807   }
808 }
809 #endif
810 
UpdateRendererChannel(bool force)811 void RenderFrameDevToolsAgentHost::UpdateRendererChannel(bool force) {
812   mojo::PendingAssociatedRemote<blink::mojom::DevToolsAgent> agent_remote;
813   mojo::PendingAssociatedReceiver<blink::mojom::DevToolsAgentHost>
814       host_receiver;
815   if (frame_host_ && render_frame_alive_ && force) {
816     mojo::PendingAssociatedRemote<blink::mojom::DevToolsAgentHost> host_remote;
817     host_receiver = host_remote.InitWithNewEndpointAndPassReceiver();
818     frame_host_->BindDevToolsAgent(
819         std::move(host_remote),
820         agent_remote.InitWithNewEndpointAndPassReceiver());
821   }
822   int process_id = frame_host_ ? frame_host_->GetProcess()->GetID()
823                                : ChildProcessHost::kInvalidUniqueID;
824   GetRendererChannel()->SetRendererAssociated(std::move(agent_remote),
825                                               std::move(host_receiver),
826                                               process_id, frame_host_);
827 }
828 
IsChildFrame()829 bool RenderFrameDevToolsAgentHost::IsChildFrame() {
830   return frame_tree_node_ && frame_tree_node_->parent();
831 }
832 
ShouldAllowSession(DevToolsSession * session)833 bool RenderFrameDevToolsAgentHost::ShouldAllowSession(
834     DevToolsSession* session) {
835   // There's not much we can say if there's not host yet, but we'll
836   // check again when host is updated.
837   if (!frame_host_)
838     return true;
839   DevToolsManager* manager = DevToolsManager::GetInstance();
840   if (manager->delegate() &&
841       !manager->delegate()->AllowInspectingRenderFrameHost(frame_host_)) {
842     return false;
843   }
844   auto* root = static_cast<RenderFrameHostImpl*>(frame_host_)->frame_tree_node();
845   for (FrameTreeNode* node : root->frame_tree()->SubtreeNodes(root)) {
846     // Note this may be called before navigation is committed.
847     RenderFrameHostImpl* rfh = node->current_frame_host();
848     const GURL& url = rfh->GetSiteInstance()->GetSiteURL();
849     if (!session->GetClient()->MayAttachToURL(url, rfh->web_ui())) {
850       return false;
851     }
852   }
853   return true;
854 }
855 
UpdateResourceLoaderFactories()856 void RenderFrameDevToolsAgentHost::UpdateResourceLoaderFactories() {
857   if (!frame_tree_node_)
858     return;
859   base::queue<FrameTreeNode*> queue;
860   queue.push(frame_tree_node_);
861   while (!queue.empty()) {
862     FrameTreeNode* node = queue.front();
863     queue.pop();
864     RenderFrameHostImpl* host = node->current_frame_host();
865     if (node != frame_tree_node_ && host->IsCrossProcessSubframe())
866       continue;
867     host->UpdateSubresourceLoaderFactories();
868     for (size_t i = 0; i < node->child_count(); ++i)
869       queue.push(node->child_at(i));
870   }
871 }
872 
873 }  // namespace content
874