| 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::DidFinishNavigation() { |
| 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 |