OLD | NEW |
1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "content/browser/devtools/protocol/target_handler.h" | 5 #include "content/browser/devtools/protocol/target_handler.h" |
6 | 6 |
7 #include "content/browser/devtools/devtools_manager.h" | 7 #include "content/browser/devtools/devtools_manager.h" |
8 #include "content/browser/devtools/devtools_session.h" | 8 #include "content/browser/devtools/devtools_session.h" |
9 #include "content/browser/devtools/render_frame_devtools_agent_host.h" | |
10 #include "content/browser/devtools/service_worker_devtools_agent_host.h" | |
11 #include "content/browser/frame_host/frame_tree.h" | |
12 #include "content/browser/frame_host/frame_tree_node.h" | |
13 #include "content/browser/frame_host/render_frame_host_impl.h" | |
14 | 9 |
15 namespace content { | 10 namespace content { |
16 namespace protocol { | 11 namespace protocol { |
17 | 12 |
18 namespace { | 13 namespace { |
19 | 14 |
20 using ScopeAgentsMap = | |
21 std::map<GURL, std::unique_ptr<ServiceWorkerDevToolsAgentHost::List>>; | |
22 | |
23 void GetMatchingHostsByScopeMap( | |
24 const ServiceWorkerDevToolsAgentHost::List& agent_hosts, | |
25 const std::set<GURL>& urls, | |
26 ScopeAgentsMap* scope_agents_map) { | |
27 std::set<base::StringPiece> host_name_set; | |
28 for (const GURL& url : urls) | |
29 host_name_set.insert(url.host_piece()); | |
30 for (const auto& host : agent_hosts) { | |
31 if (host_name_set.find(host->scope().host_piece()) == host_name_set.end()) | |
32 continue; | |
33 const auto& it = scope_agents_map->find(host->scope()); | |
34 if (it == scope_agents_map->end()) { | |
35 std::unique_ptr<ServiceWorkerDevToolsAgentHost::List> new_list( | |
36 new ServiceWorkerDevToolsAgentHost::List()); | |
37 new_list->push_back(host); | |
38 (*scope_agents_map)[host->scope()] = std::move(new_list); | |
39 } else { | |
40 it->second->push_back(host); | |
41 } | |
42 } | |
43 } | |
44 | |
45 void AddEligibleHosts(const ServiceWorkerDevToolsAgentHost::List& list, | |
46 ServiceWorkerDevToolsAgentHost::Map* result) { | |
47 base::Time last_installed_time; | |
48 base::Time last_doomed_time; | |
49 for (const auto& host : list) { | |
50 if (host->version_installed_time() > last_installed_time) | |
51 last_installed_time = host->version_installed_time(); | |
52 if (host->version_doomed_time() > last_doomed_time) | |
53 last_doomed_time = host->version_doomed_time(); | |
54 } | |
55 for (const auto& host : list) { | |
56 // We don't attech old redundant Service Workers when there is newer | |
57 // installed Service Worker. | |
58 if (host->version_doomed_time().is_null() || | |
59 (last_installed_time < last_doomed_time && | |
60 last_doomed_time == host->version_doomed_time())) { | |
61 (*result)[host->GetId()] = host; | |
62 } | |
63 } | |
64 } | |
65 | |
66 ServiceWorkerDevToolsAgentHost::Map GetMatchingServiceWorkers( | |
67 BrowserContext* browser_context, | |
68 const std::set<GURL>& urls) { | |
69 ServiceWorkerDevToolsAgentHost::Map result; | |
70 if (!browser_context) | |
71 return result; | |
72 | |
73 ServiceWorkerDevToolsAgentHost::List agent_hosts; | |
74 ServiceWorkerDevToolsManager::GetInstance() | |
75 ->AddAllAgentHostsForBrowserContext(browser_context, &agent_hosts); | |
76 | |
77 ScopeAgentsMap scope_agents_map; | |
78 GetMatchingHostsByScopeMap(agent_hosts, urls, &scope_agents_map); | |
79 | |
80 for (const auto& it : scope_agents_map) | |
81 AddEligibleHosts(*it.second.get(), &result); | |
82 | |
83 return result; | |
84 } | |
85 | |
86 std::unique_ptr<Target::TargetInfo> CreateInfo(DevToolsAgentHost* host) { | 15 std::unique_ptr<Target::TargetInfo> CreateInfo(DevToolsAgentHost* host) { |
87 return Target::TargetInfo::Create() | 16 return Target::TargetInfo::Create() |
88 .SetTargetId(host->GetId()) | 17 .SetTargetId(host->GetId()) |
89 .SetTitle(host->GetTitle()) | 18 .SetTitle(host->GetTitle()) |
90 .SetUrl(host->GetURL().spec()) | 19 .SetUrl(host->GetURL().spec()) |
91 .SetType(host->GetType()) | 20 .SetType(host->GetType()) |
92 .SetAttached(host->IsAttached()) | 21 .SetAttached(host->IsAttached()) |
93 .Build(); | 22 .Build(); |
94 } | 23 } |
95 | 24 |
96 } // namespace | 25 } // namespace |
97 | 26 |
98 TargetHandler::TargetHandler() | 27 TargetHandler::TargetHandler() |
99 : DevToolsDomainHandler(Target::Metainfo::domainName), | 28 : DevToolsDomainHandler(Target::Metainfo::domainName), |
100 discover_(false), | 29 auto_attacher_(base::Bind(&TargetHandler::AttachToTargetInternal, |
101 auto_attach_(false), | 30 base::Unretained(this)), |
102 wait_for_debugger_on_start_(false), | 31 base::Bind(&TargetHandler::DetachFromTargetInternal, |
103 attach_to_frames_(false), | 32 base::Unretained(this))), |
104 render_frame_host_(nullptr) { | 33 discover_(false) {} |
105 } | |
106 | 34 |
107 TargetHandler::~TargetHandler() { | 35 TargetHandler::~TargetHandler() { |
108 } | 36 } |
109 | 37 |
110 // static | 38 // static |
111 std::vector<TargetHandler*> TargetHandler::ForAgentHost( | 39 std::vector<TargetHandler*> TargetHandler::ForAgentHost( |
112 DevToolsAgentHostImpl* host) { | 40 DevToolsAgentHostImpl* host) { |
113 return DevToolsSession::HandlersForAgentHost<TargetHandler>( | 41 return DevToolsSession::HandlersForAgentHost<TargetHandler>( |
114 host, Target::Metainfo::domainName); | 42 host, Target::Metainfo::domainName); |
115 } | 43 } |
116 | 44 |
117 void TargetHandler::Wire(UberDispatcher* dispatcher) { | 45 void TargetHandler::Wire(UberDispatcher* dispatcher) { |
118 frontend_.reset(new Target::Frontend(dispatcher->channel())); | 46 frontend_.reset(new Target::Frontend(dispatcher->channel())); |
119 Target::Dispatcher::wire(dispatcher, this); | 47 Target::Dispatcher::wire(dispatcher, this); |
120 } | 48 } |
121 | 49 |
122 void TargetHandler::SetRenderFrameHost(RenderFrameHostImpl* render_frame_host) { | 50 void TargetHandler::SetRenderFrameHost(RenderFrameHostImpl* render_frame_host) { |
123 render_frame_host_ = render_frame_host; | 51 auto_attacher_.SetRenderFrameHost(render_frame_host); |
124 UpdateFrames(); | |
125 } | 52 } |
126 | 53 |
127 Response TargetHandler::Disable() { | 54 Response TargetHandler::Disable() { |
128 SetAutoAttach(false, false); | 55 SetAutoAttach(false, false); |
129 SetDiscoverTargets(false); | 56 SetDiscoverTargets(false); |
130 for (const auto& id_host : attached_hosts_) | 57 for (const auto& id_host : attached_hosts_) |
131 id_host.second->DetachClient(this); | 58 id_host.second->DetachClient(this); |
132 attached_hosts_.clear(); | 59 attached_hosts_.clear(); |
133 return Response::OK(); | 60 return Response::OK(); |
134 } | 61 } |
135 | 62 |
136 void TargetHandler::UpdateServiceWorkers() { | 63 void TargetHandler::DidCommitNavigation() { |
137 UpdateServiceWorkers(false); | 64 auto_attacher_.UpdateServiceWorkers(); |
138 } | 65 } |
139 | 66 |
140 void TargetHandler::UpdateFrames() { | 67 void TargetHandler::RenderFrameHostChanged() { |
141 if (!auto_attach_ || !attach_to_frames_) | 68 auto_attacher_.UpdateFrames(); |
142 return; | |
143 | |
144 HostsMap new_hosts; | |
145 if (render_frame_host_) { | |
146 FrameTreeNode* root = render_frame_host_->frame_tree_node(); | |
147 std::queue<FrameTreeNode*> queue; | |
148 queue.push(root); | |
149 while (!queue.empty()) { | |
150 FrameTreeNode* node = queue.front(); | |
151 queue.pop(); | |
152 bool cross_process = node->current_frame_host()->IsCrossProcessSubframe(); | |
153 if (node != root && cross_process) { | |
154 scoped_refptr<DevToolsAgentHost> new_host = | |
155 RenderFrameDevToolsAgentHost::GetOrCreateFor(node); | |
156 new_hosts[new_host->GetId()] = new_host; | |
157 } else { | |
158 for (size_t i = 0; i < node->child_count(); ++i) | |
159 queue.push(node->child_at(i)); | |
160 } | |
161 } | |
162 } | |
163 | |
164 // TODO(dgozman): support wait_for_debugger_on_start_. | |
165 ReattachTargetsOfType(new_hosts, DevToolsAgentHost::kTypeFrame, false); | |
166 } | |
167 | |
168 void TargetHandler::UpdateServiceWorkers(bool waiting_for_debugger) { | |
169 if (!auto_attach_) | |
170 return; | |
171 | |
172 frame_urls_.clear(); | |
173 BrowserContext* browser_context = nullptr; | |
174 if (render_frame_host_) { | |
175 // TODO(dgozman): do not traverse inside cross-process subframes. | |
176 for (FrameTreeNode* node : | |
177 render_frame_host_->frame_tree_node()->frame_tree()->Nodes()) { | |
178 frame_urls_.insert(node->current_url()); | |
179 } | |
180 browser_context = render_frame_host_->GetProcess()->GetBrowserContext(); | |
181 } | |
182 | |
183 auto matching = GetMatchingServiceWorkers(browser_context, frame_urls_); | |
184 HostsMap new_hosts; | |
185 for (const auto& pair : matching) { | |
186 if (pair.second->IsReadyForInspection()) | |
187 new_hosts[pair.first] = pair.second; | |
188 } | |
189 ReattachTargetsOfType( | |
190 new_hosts, DevToolsAgentHost::kTypeServiceWorker, waiting_for_debugger); | |
191 } | |
192 | |
193 void TargetHandler::ReattachTargetsOfType( | |
194 const HostsMap& new_hosts, | |
195 const std::string& type, | |
196 bool waiting_for_debugger) { | |
197 HostsMap old_hosts = attached_hosts_; | |
198 for (const auto& pair : old_hosts) { | |
199 if (pair.second->GetType() == type && | |
200 new_hosts.find(pair.first) == new_hosts.end()) { | |
201 DetachFromTargetInternal(pair.second.get()); | |
202 } | |
203 } | |
204 for (const auto& pair : new_hosts) { | |
205 if (old_hosts.find(pair.first) == old_hosts.end()) | |
206 AttachToTargetInternal(pair.second.get(), waiting_for_debugger); | |
207 } | |
208 } | 69 } |
209 | 70 |
210 void TargetHandler::TargetCreatedInternal(DevToolsAgentHost* host) { | 71 void TargetHandler::TargetCreatedInternal(DevToolsAgentHost* host) { |
211 if (reported_hosts_.find(host->GetId()) != reported_hosts_.end()) | 72 if (reported_hosts_.find(host->GetId()) != reported_hosts_.end()) |
212 return; | 73 return; |
213 frontend_->TargetCreated(CreateInfo(host)); | 74 frontend_->TargetCreated(CreateInfo(host)); |
214 reported_hosts_[host->GetId()] = host; | 75 reported_hosts_[host->GetId()] = host; |
215 } | 76 } |
216 | 77 |
217 void TargetHandler::TargetInfoChangedInternal(DevToolsAgentHost* host) { | 78 void TargetHandler::TargetInfoChangedInternal(DevToolsAgentHost* host) { |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
261 DevToolsAgentHost::RemoveObserver(this); | 122 DevToolsAgentHost::RemoveObserver(this); |
262 RawHostsMap copy = reported_hosts_; | 123 RawHostsMap copy = reported_hosts_; |
263 for (const auto& id_host : copy) | 124 for (const auto& id_host : copy) |
264 TargetDestroyedInternal(id_host.second); | 125 TargetDestroyedInternal(id_host.second); |
265 } | 126 } |
266 return Response::OK(); | 127 return Response::OK(); |
267 } | 128 } |
268 | 129 |
269 Response TargetHandler::SetAutoAttach( | 130 Response TargetHandler::SetAutoAttach( |
270 bool auto_attach, bool wait_for_debugger_on_start) { | 131 bool auto_attach, bool wait_for_debugger_on_start) { |
271 wait_for_debugger_on_start_ = wait_for_debugger_on_start; | 132 auto_attacher_.SetAutoAttach(auto_attach, wait_for_debugger_on_start); |
272 if (auto_attach_ == auto_attach) | |
273 return Response::FallThrough(); | |
274 auto_attach_ = auto_attach; | |
275 if (auto_attach_) { | |
276 ServiceWorkerDevToolsManager::GetInstance()->AddObserver(this); | |
277 UpdateServiceWorkers(); | |
278 UpdateFrames(); | |
279 } else { | |
280 ServiceWorkerDevToolsManager::GetInstance()->RemoveObserver(this); | |
281 HostsMap empty; | |
282 ReattachTargetsOfType(empty, DevToolsAgentHost::kTypeFrame, false); | |
283 ReattachTargetsOfType(empty, DevToolsAgentHost::kTypeServiceWorker, false); | |
284 } | |
285 return Response::FallThrough(); | 133 return Response::FallThrough(); |
286 } | 134 } |
287 | 135 |
288 Response TargetHandler::SetAttachToFrames(bool value) { | 136 Response TargetHandler::SetAttachToFrames(bool value) { |
289 if (attach_to_frames_ == value) | 137 auto_attacher_.SetAttachToFrames(value); |
290 return Response::OK(); | |
291 attach_to_frames_ = value; | |
292 if (attach_to_frames_) { | |
293 UpdateFrames(); | |
294 } else { | |
295 HostsMap empty; | |
296 ReattachTargetsOfType(empty, DevToolsAgentHost::kTypeFrame, false); | |
297 } | |
298 return Response::OK(); | 138 return Response::OK(); |
299 } | 139 } |
300 | 140 |
301 Response TargetHandler::SetRemoteLocations( | 141 Response TargetHandler::SetRemoteLocations( |
302 std::unique_ptr<protocol::Array<Target::RemoteLocation>>) { | 142 std::unique_ptr<protocol::Array<Target::RemoteLocation>>) { |
303 return Response::Error("Not supported"); | 143 return Response::Error("Not supported"); |
304 } | 144 } |
305 | 145 |
306 Response TargetHandler::AttachToTarget(const std::string& target_id, | 146 Response TargetHandler::AttachToTarget(const std::string& target_id, |
307 bool* out_success) { | 147 bool* out_success) { |
(...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
409 return; // Already disconnected. | 249 return; // Already disconnected. |
410 | 250 |
411 frontend_->ReceivedMessageFromTarget(host->GetId(), message); | 251 frontend_->ReceivedMessageFromTarget(host->GetId(), message); |
412 } | 252 } |
413 | 253 |
414 void TargetHandler::AgentHostClosed( | 254 void TargetHandler::AgentHostClosed( |
415 DevToolsAgentHost* host, | 255 DevToolsAgentHost* host, |
416 bool replaced_with_another_client) { | 256 bool replaced_with_another_client) { |
417 frontend_->DetachedFromTarget(host->GetId()); | 257 frontend_->DetachedFromTarget(host->GetId()); |
418 attached_hosts_.erase(host->GetId()); | 258 attached_hosts_.erase(host->GetId()); |
| 259 auto_attacher_.AgentHostClosed(host); |
419 } | 260 } |
420 | 261 |
421 // -------------- DevToolsAgentHostObserver ----------------- | 262 // -------------- DevToolsAgentHostObserver ----------------- |
422 | 263 |
423 bool TargetHandler::ShouldForceDevToolsAgentHostCreation() { | 264 bool TargetHandler::ShouldForceDevToolsAgentHostCreation() { |
424 return true; | 265 return true; |
425 } | 266 } |
426 | 267 |
427 void TargetHandler::DevToolsAgentHostCreated(DevToolsAgentHost* agent_host) { | 268 void TargetHandler::DevToolsAgentHostCreated(DevToolsAgentHost* agent_host) { |
428 // If we start discovering late, all existing agent hosts will be reported, | 269 // If we start discovering late, all existing agent hosts will be reported, |
429 // but we could have already attached to some. | 270 // but we could have already attached to some. |
430 TargetCreatedInternal(agent_host); | 271 TargetCreatedInternal(agent_host); |
431 } | 272 } |
432 | 273 |
433 void TargetHandler::DevToolsAgentHostDestroyed(DevToolsAgentHost* agent_host) { | 274 void TargetHandler::DevToolsAgentHostDestroyed(DevToolsAgentHost* agent_host) { |
434 DCHECK(attached_hosts_.find(agent_host->GetId()) == attached_hosts_.end()); | 275 DCHECK(attached_hosts_.find(agent_host->GetId()) == attached_hosts_.end()); |
435 TargetDestroyedInternal(agent_host); | 276 TargetDestroyedInternal(agent_host); |
436 } | 277 } |
437 | 278 |
438 void TargetHandler::DevToolsAgentHostAttached(DevToolsAgentHost* host) { | 279 void TargetHandler::DevToolsAgentHostAttached(DevToolsAgentHost* host) { |
439 TargetInfoChangedInternal(host); | 280 TargetInfoChangedInternal(host); |
440 } | 281 } |
441 | 282 |
442 void TargetHandler::DevToolsAgentHostDetached(DevToolsAgentHost* host) { | 283 void TargetHandler::DevToolsAgentHostDetached(DevToolsAgentHost* host) { |
443 TargetInfoChangedInternal(host); | 284 TargetInfoChangedInternal(host); |
444 } | 285 } |
445 | 286 |
446 // -------- ServiceWorkerDevToolsManager::Observer ---------- | |
447 | |
448 void TargetHandler::WorkerCreated( | |
449 ServiceWorkerDevToolsAgentHost* host) { | |
450 BrowserContext* browser_context = nullptr; | |
451 if (render_frame_host_) | |
452 browser_context = render_frame_host_->GetProcess()->GetBrowserContext(); | |
453 auto hosts = GetMatchingServiceWorkers(browser_context, frame_urls_); | |
454 if (hosts.find(host->GetId()) != hosts.end() && !host->IsAttached() && | |
455 !host->IsPausedForDebugOnStart() && wait_for_debugger_on_start_) { | |
456 host->PauseForDebugOnStart(); | |
457 } | |
458 } | |
459 | |
460 void TargetHandler::WorkerReadyForInspection( | |
461 ServiceWorkerDevToolsAgentHost* host) { | |
462 DCHECK(host->IsReadyForInspection()); | |
463 if (ServiceWorkerDevToolsManager::GetInstance() | |
464 ->debug_service_worker_on_start()) { | |
465 // When debug_service_worker_on_start is true, a new DevTools window will | |
466 // be opened in ServiceWorkerDevToolsManager::WorkerReadyForInspection. | |
467 return; | |
468 } | |
469 UpdateServiceWorkers(host->IsPausedForDebugOnStart()); | |
470 } | |
471 | |
472 void TargetHandler::WorkerVersionInstalled( | |
473 ServiceWorkerDevToolsAgentHost* host) { | |
474 UpdateServiceWorkers(); | |
475 } | |
476 | |
477 void TargetHandler::WorkerVersionDoomed( | |
478 ServiceWorkerDevToolsAgentHost* host) { | |
479 UpdateServiceWorkers(); | |
480 } | |
481 | |
482 void TargetHandler::WorkerDestroyed( | |
483 ServiceWorkerDevToolsAgentHost* host) { | |
484 UpdateServiceWorkers(); | |
485 } | |
486 | |
487 } // namespace protocol | 287 } // namespace protocol |
488 } // namespace content | 288 } // namespace content |
OLD | NEW |