OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 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 // Implements the Chrome Extensions Debugger API. | 5 // Implements the Chrome Extensions Debugger API. |
6 | 6 |
7 #include "chrome/browser/extensions/api/debugger/debugger_api.h" | 7 #include "chrome/browser/extensions/api/debugger/debugger_api.h" |
8 | 8 |
9 #include <map> | 9 #include <map> |
10 #include <set> | 10 #include <set> |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
48 using content::WebContents; | 48 using content::WebContents; |
49 using extensions::api::debugger::Debuggee; | 49 using extensions::api::debugger::Debuggee; |
50 | 50 |
51 namespace keys = debugger_api_constants; | 51 namespace keys = debugger_api_constants; |
52 namespace Attach = extensions::api::debugger::Attach; | 52 namespace Attach = extensions::api::debugger::Attach; |
53 namespace Detach = extensions::api::debugger::Detach; | 53 namespace Detach = extensions::api::debugger::Detach; |
54 namespace OnDetach = extensions::api::debugger::OnDetach; | 54 namespace OnDetach = extensions::api::debugger::OnDetach; |
55 namespace OnEvent = extensions::api::debugger::OnEvent; | 55 namespace OnEvent = extensions::api::debugger::OnEvent; |
56 namespace SendCommand = extensions::api::debugger::SendCommand; | 56 namespace SendCommand = extensions::api::debugger::SendCommand; |
57 | 57 |
| 58 class ExtensionDevToolsClientHost; |
| 59 |
58 class ExtensionDevToolsInfoBarDelegate : public ConfirmInfoBarDelegate { | 60 class ExtensionDevToolsInfoBarDelegate : public ConfirmInfoBarDelegate { |
59 public: | 61 public: |
60 ExtensionDevToolsInfoBarDelegate( | 62 ExtensionDevToolsInfoBarDelegate( |
61 InfoBarTabHelper* infobar_helper, | 63 InfoBarTabHelper* infobar_helper, |
62 const std::string& client_name); | 64 const std::string& client_name, |
| 65 ExtensionDevToolsClientHost* client_host); |
63 virtual ~ExtensionDevToolsInfoBarDelegate(); | 66 virtual ~ExtensionDevToolsInfoBarDelegate(); |
64 | 67 |
| 68 // Notifies infobar delegate that associated DevToolsClientHost will be |
| 69 // destroyed. |
| 70 void DiscardClientHost(); |
| 71 |
65 private: | 72 private: |
66 // ConfirmInfoBarDelegate: | 73 // ConfirmInfoBarDelegate: |
67 virtual bool ShouldExpire( | 74 virtual bool ShouldExpire( |
68 const content::LoadCommittedDetails& details) const OVERRIDE; | 75 const content::LoadCommittedDetails& details) const OVERRIDE; |
69 virtual int GetButtons() const OVERRIDE; | 76 virtual int GetButtons() const OVERRIDE; |
70 virtual Type GetInfoBarType() const OVERRIDE; | 77 virtual Type GetInfoBarType() const OVERRIDE; |
71 virtual string16 GetMessageText() const OVERRIDE; | 78 virtual string16 GetMessageText() const OVERRIDE; |
| 79 virtual void InfoBarDismissed() OVERRIDE; |
| 80 virtual bool Cancel() OVERRIDE; |
72 | 81 |
73 std::string client_name_; | 82 std::string client_name_; |
| 83 ExtensionDevToolsClientHost* client_host_; |
74 DISALLOW_COPY_AND_ASSIGN(ExtensionDevToolsInfoBarDelegate); | 84 DISALLOW_COPY_AND_ASSIGN(ExtensionDevToolsInfoBarDelegate); |
75 }; | 85 }; |
76 | 86 |
77 class ExtensionDevToolsClientHost : public DevToolsClientHost, | 87 class ExtensionDevToolsClientHost : public DevToolsClientHost, |
78 public content::NotificationObserver { | 88 public content::NotificationObserver { |
79 public: | 89 public: |
80 ExtensionDevToolsClientHost(WebContents* web_contents, | 90 ExtensionDevToolsClientHost(WebContents* web_contents, |
81 const std::string& extension_id, | 91 const std::string& extension_id, |
82 const std::string& extension_name, | 92 const std::string& extension_name, |
83 int tab_id); | 93 int tab_id); |
84 | 94 |
85 ~ExtensionDevToolsClientHost(); | 95 ~ExtensionDevToolsClientHost(); |
86 | 96 |
87 bool MatchesContentsAndExtensionId(WebContents* web_contents, | 97 bool MatchesContentsAndExtensionId(WebContents* web_contents, |
88 const std::string& extension_id); | 98 const std::string& extension_id); |
89 void Close(); | 99 void Close(); |
90 void SendMessageToBackend(SendCommandDebuggerFunction* function, | 100 void SendMessageToBackend(SendCommandDebuggerFunction* function, |
91 const std::string& method, | 101 const std::string& method, |
92 SendCommand::Params::CommandParams* command_params); | 102 SendCommand::Params::CommandParams* command_params); |
93 | 103 |
| 104 // Mark methods below determine the connection termination reason. |
| 105 void MarkAsReplaced(); |
| 106 void MarkAsDismissed(); |
| 107 |
94 // DevToolsClientHost interface | 108 // DevToolsClientHost interface |
95 virtual void InspectedContentsClosing() OVERRIDE; | 109 virtual void InspectedContentsClosing() OVERRIDE; |
96 virtual void DispatchOnInspectorFrontend(const std::string& message) OVERRIDE; | 110 virtual void DispatchOnInspectorFrontend(const std::string& message) OVERRIDE; |
97 virtual void ContentsReplaced(WebContents* web_contents) OVERRIDE; | 111 virtual void ContentsReplaced(WebContents* web_contents) OVERRIDE; |
98 virtual void FrameNavigating(const std::string& url) OVERRIDE {} | 112 virtual void FrameNavigating(const std::string& url) OVERRIDE {} |
99 | 113 |
100 private: | 114 private: |
101 void SendDetachedEvent(); | 115 void SendDetachedEvent(); |
102 | 116 |
103 // content::NotificationObserver implementation. | 117 // content::NotificationObserver implementation. |
104 virtual void Observe(int type, | 118 virtual void Observe(int type, |
105 const content::NotificationSource& source, | 119 const content::NotificationSource& source, |
106 const content::NotificationDetails& details); | 120 const content::NotificationDetails& details); |
107 | 121 |
108 WebContents* web_contents_; | 122 WebContents* web_contents_; |
109 std::string extension_id_; | 123 std::string extension_id_; |
110 int tab_id_; | 124 int tab_id_; |
111 content::NotificationRegistrar registrar_; | 125 content::NotificationRegistrar registrar_; |
112 int last_request_id_; | 126 int last_request_id_; |
113 typedef std::map<int, scoped_refptr<SendCommandDebuggerFunction> > | 127 typedef std::map<int, scoped_refptr<SendCommandDebuggerFunction> > |
114 PendingRequests; | 128 PendingRequests; |
115 PendingRequests pending_requests_; | 129 PendingRequests pending_requests_; |
116 ExtensionDevToolsInfoBarDelegate* infobar_delegate_; | 130 ExtensionDevToolsInfoBarDelegate* infobar_delegate_; |
| 131 OnDetach::Reason detach_reason_; |
117 | 132 |
118 DISALLOW_COPY_AND_ASSIGN(ExtensionDevToolsClientHost); | 133 DISALLOW_COPY_AND_ASSIGN(ExtensionDevToolsClientHost); |
119 }; | 134 }; |
120 | 135 |
121 namespace { | 136 namespace { |
122 | 137 |
123 class AttachedClientHosts { | 138 class AttachedClientHosts { |
124 public: | 139 public: |
125 AttachedClientHosts() {} | 140 AttachedClientHosts() {} |
126 | 141 |
127 // Returns the singleton instance of this class | 142 // Returns the singleton instance of this class |
128 static AttachedClientHosts* GetInstance() { | 143 static AttachedClientHosts* GetInstance() { |
129 return Singleton<AttachedClientHosts>::get(); | 144 return Singleton<AttachedClientHosts>::get(); |
130 } | 145 } |
131 | 146 |
132 void Add(ExtensionDevToolsClientHost* client_host) { | 147 void Add(ExtensionDevToolsClientHost* client_host) { |
133 client_hosts_.insert(client_host); | 148 client_hosts_.insert(client_host); |
134 } | 149 } |
135 | 150 |
136 void Remove(ExtensionDevToolsClientHost* client_host) { | 151 void Remove(ExtensionDevToolsClientHost* client_host) { |
137 client_hosts_.erase(client_host); | 152 client_hosts_.erase(client_host); |
138 } | 153 } |
139 | 154 |
| 155 ExtensionDevToolsClientHost* AsExtensionDevToolsClientHost( |
| 156 DevToolsClientHost* client_host) { |
| 157 for (std::set<DevToolsClientHost*>::iterator it = client_hosts_.begin(); |
| 158 it != client_hosts_.end(); ++it) { |
| 159 if (client_host == *it) |
| 160 return static_cast<ExtensionDevToolsClientHost*>(*it); |
| 161 } |
| 162 return NULL; |
| 163 } |
| 164 |
140 ExtensionDevToolsClientHost* Lookup(WebContents* contents) { | 165 ExtensionDevToolsClientHost* Lookup(WebContents* contents) { |
141 for (std::set<DevToolsClientHost*>::iterator it = client_hosts_.begin(); | 166 for (std::set<DevToolsClientHost*>::iterator it = client_hosts_.begin(); |
142 it != client_hosts_.end(); ++it) { | 167 it != client_hosts_.end(); ++it) { |
143 DevToolsAgentHost* agent_host = | 168 DevToolsAgentHost* agent_host = |
144 DevToolsManager::GetInstance()->GetDevToolsAgentHostFor(*it); | 169 DevToolsManager::GetInstance()->GetDevToolsAgentHostFor(*it); |
145 if (!agent_host) | 170 if (!agent_host) |
146 continue; | 171 continue; |
147 content::RenderViewHost* rvh = | 172 content::RenderViewHost* rvh = |
148 DevToolsAgentHostRegistry::GetRenderViewHost(agent_host); | 173 DevToolsAgentHostRegistry::GetRenderViewHost(agent_host); |
149 if (rvh && WebContents::FromRenderViewHost(rvh) == contents) | 174 if (rvh && WebContents::FromRenderViewHost(rvh) == contents) |
(...skipping 10 matching lines...) Expand all Loading... |
160 | 185 |
161 ExtensionDevToolsClientHost::ExtensionDevToolsClientHost( | 186 ExtensionDevToolsClientHost::ExtensionDevToolsClientHost( |
162 WebContents* web_contents, | 187 WebContents* web_contents, |
163 const std::string& extension_id, | 188 const std::string& extension_id, |
164 const std::string& extension_name, | 189 const std::string& extension_name, |
165 int tab_id) | 190 int tab_id) |
166 : web_contents_(web_contents), | 191 : web_contents_(web_contents), |
167 extension_id_(extension_id), | 192 extension_id_(extension_id), |
168 tab_id_(tab_id), | 193 tab_id_(tab_id), |
169 last_request_id_(0), | 194 last_request_id_(0), |
170 infobar_delegate_(NULL) { | 195 infobar_delegate_(NULL), |
| 196 detach_reason_(OnDetach::REASON_TARGET_CLOSED) { |
171 AttachedClientHosts::GetInstance()->Add(this); | 197 AttachedClientHosts::GetInstance()->Add(this); |
172 | 198 |
173 // Detach from debugger when extension unloads. | 199 // Detach from debugger when extension unloads. |
174 Profile* profile = | 200 Profile* profile = |
175 Profile::FromBrowserContext(web_contents_->GetBrowserContext()); | 201 Profile::FromBrowserContext(web_contents_->GetBrowserContext()); |
176 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_UNLOADED, | 202 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_UNLOADED, |
177 content::Source<Profile>(profile)); | 203 content::Source<Profile>(profile)); |
178 | 204 |
179 // Attach to debugger and tell it we are ready. | 205 // Attach to debugger and tell it we are ready. |
180 DevToolsAgentHost* agent = DevToolsAgentHostRegistry::GetDevToolsAgentHost( | 206 DevToolsAgentHost* agent = DevToolsAgentHostRegistry::GetDevToolsAgentHost( |
181 web_contents_->GetRenderViewHost()); | 207 web_contents_->GetRenderViewHost()); |
182 DevToolsManager::GetInstance()->RegisterDevToolsClientHostFor(agent, this); | 208 DevToolsManager::GetInstance()->RegisterDevToolsClientHostFor(agent, this); |
183 | 209 |
184 InfoBarTabHelper* infobar_helper = | 210 InfoBarTabHelper* infobar_helper = |
185 TabContents::FromWebContents(web_contents_)->infobar_tab_helper(); | 211 TabContents::FromWebContents(web_contents_)->infobar_tab_helper(); |
186 infobar_delegate_ = | 212 infobar_delegate_ = new ExtensionDevToolsInfoBarDelegate(infobar_helper, |
187 new ExtensionDevToolsInfoBarDelegate(infobar_helper, extension_name); | 213 extension_name, |
| 214 this); |
188 if (infobar_helper->AddInfoBar(infobar_delegate_)) { | 215 if (infobar_helper->AddInfoBar(infobar_delegate_)) { |
189 registrar_.Add(this, chrome::NOTIFICATION_TAB_CONTENTS_INFOBAR_REMOVED, | 216 registrar_.Add(this, chrome::NOTIFICATION_TAB_CONTENTS_INFOBAR_REMOVED, |
190 content::Source<InfoBarTabHelper>(infobar_helper)); | 217 content::Source<InfoBarTabHelper>(infobar_helper)); |
191 } else { | 218 } else { |
192 infobar_delegate_ = NULL; | 219 infobar_delegate_ = NULL; |
193 } | 220 } |
194 } | 221 } |
195 | 222 |
196 ExtensionDevToolsClientHost::~ExtensionDevToolsClientHost() { | 223 ExtensionDevToolsClientHost::~ExtensionDevToolsClientHost() { |
197 // Ensure calling RemoveInfoBar() below won't result in Observe() trying to | 224 // Ensure calling RemoveInfoBar() below won't result in Observe() trying to |
198 // Close() us. | 225 // Close() us. |
199 registrar_.RemoveAll(); | 226 registrar_.RemoveAll(); |
200 | 227 |
201 if (infobar_delegate_) { | 228 if (infobar_delegate_) { |
| 229 infobar_delegate_->DiscardClientHost(); |
202 TabContents* tab_contents = TabContents::FromWebContents(web_contents_); | 230 TabContents* tab_contents = TabContents::FromWebContents(web_contents_); |
203 InfoBarTabHelper* helper = tab_contents->infobar_tab_helper(); | 231 InfoBarTabHelper* helper = tab_contents->infobar_tab_helper(); |
204 if (helper) | 232 if (helper) |
205 helper->RemoveInfoBar(infobar_delegate_); | 233 helper->RemoveInfoBar(infobar_delegate_); |
206 } | 234 } |
207 AttachedClientHosts::GetInstance()->Remove(this); | 235 AttachedClientHosts::GetInstance()->Remove(this); |
208 } | 236 } |
209 | 237 |
210 bool ExtensionDevToolsClientHost::MatchesContentsAndExtensionId( | 238 bool ExtensionDevToolsClientHost::MatchesContentsAndExtensionId( |
211 WebContents* web_contents, | 239 WebContents* web_contents, |
(...skipping 28 matching lines...) Expand all Loading... |
240 if (command_params) { | 268 if (command_params) { |
241 protocol_request.Set("params", | 269 protocol_request.Set("params", |
242 command_params->additional_properties.DeepCopy()); | 270 command_params->additional_properties.DeepCopy()); |
243 } | 271 } |
244 | 272 |
245 std::string json_args; | 273 std::string json_args; |
246 base::JSONWriter::Write(&protocol_request, &json_args); | 274 base::JSONWriter::Write(&protocol_request, &json_args); |
247 DevToolsManager::GetInstance()->DispatchOnInspectorBackend(this, json_args); | 275 DevToolsManager::GetInstance()->DispatchOnInspectorBackend(this, json_args); |
248 } | 276 } |
249 | 277 |
| 278 void ExtensionDevToolsClientHost::MarkAsReplaced() { |
| 279 detach_reason_ = OnDetach::REASON_REPLACED_WITH_DEVTOOLS; |
| 280 } |
| 281 |
| 282 void ExtensionDevToolsClientHost::MarkAsDismissed() { |
| 283 detach_reason_ = OnDetach::REASON_CANCELED_BY_USER; |
| 284 } |
| 285 |
250 void ExtensionDevToolsClientHost::SendDetachedEvent() { | 286 void ExtensionDevToolsClientHost::SendDetachedEvent() { |
251 Profile* profile = | 287 Profile* profile = |
252 Profile::FromBrowserContext(web_contents_->GetBrowserContext()); | 288 Profile::FromBrowserContext(web_contents_->GetBrowserContext()); |
253 if (profile != NULL && profile->GetExtensionEventRouter()) { | 289 if (profile != NULL && profile->GetExtensionEventRouter()) { |
254 Debuggee debuggee; | 290 Debuggee debuggee; |
255 debuggee.tab_id = tab_id_; | 291 debuggee.tab_id = tab_id_; |
256 | 292 scoped_ptr<base::ListValue> args(OnDetach::Create(debuggee, |
257 scoped_ptr<base::ListValue> args(OnDetach::Create(debuggee)); | 293 detach_reason_)); |
258 profile->GetExtensionEventRouter()->DispatchEventToExtension( | 294 profile->GetExtensionEventRouter()->DispatchEventToExtension( |
259 extension_id_, keys::kOnDetach, args.Pass(), profile, GURL()); | 295 extension_id_, keys::kOnDetach, args.Pass(), profile, GURL()); |
260 } | 296 } |
261 } | 297 } |
262 | 298 |
263 void ExtensionDevToolsClientHost::Observe( | 299 void ExtensionDevToolsClientHost::Observe( |
264 int type, | 300 int type, |
265 const content::NotificationSource& source, | 301 const content::NotificationSource& source, |
266 const content::NotificationDetails& details) { | 302 const content::NotificationDetails& details) { |
267 if (type == chrome::NOTIFICATION_EXTENSION_UNLOADED) { | 303 if (type == chrome::NOTIFICATION_EXTENSION_UNLOADED) { |
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
315 if (!function) | 351 if (!function) |
316 return; | 352 return; |
317 | 353 |
318 function->SendResponseBody(dictionary); | 354 function->SendResponseBody(dictionary); |
319 pending_requests_.erase(id); | 355 pending_requests_.erase(id); |
320 } | 356 } |
321 } | 357 } |
322 | 358 |
323 ExtensionDevToolsInfoBarDelegate::ExtensionDevToolsInfoBarDelegate( | 359 ExtensionDevToolsInfoBarDelegate::ExtensionDevToolsInfoBarDelegate( |
324 InfoBarTabHelper* infobar_helper, | 360 InfoBarTabHelper* infobar_helper, |
325 const std::string& client_name) | 361 const std::string& client_name, |
| 362 ExtensionDevToolsClientHost* client_host) |
326 : ConfirmInfoBarDelegate(infobar_helper), | 363 : ConfirmInfoBarDelegate(infobar_helper), |
327 client_name_(client_name) { | 364 client_name_(client_name), |
| 365 client_host_(client_host) { |
328 } | 366 } |
329 | 367 |
330 ExtensionDevToolsInfoBarDelegate::~ExtensionDevToolsInfoBarDelegate() { | 368 ExtensionDevToolsInfoBarDelegate::~ExtensionDevToolsInfoBarDelegate() { |
331 } | 369 } |
332 | 370 |
| 371 void ExtensionDevToolsInfoBarDelegate::DiscardClientHost() { |
| 372 client_host_ = NULL; |
| 373 } |
| 374 |
333 bool ExtensionDevToolsInfoBarDelegate::ShouldExpire( | 375 bool ExtensionDevToolsInfoBarDelegate::ShouldExpire( |
334 const content::LoadCommittedDetails& details) const { | 376 const content::LoadCommittedDetails& details) const { |
335 return false; | 377 return false; |
336 } | 378 } |
337 | 379 |
338 int ExtensionDevToolsInfoBarDelegate::GetButtons() const { | 380 int ExtensionDevToolsInfoBarDelegate::GetButtons() const { |
339 return BUTTON_CANCEL; | 381 return BUTTON_CANCEL; |
340 } | 382 } |
341 | 383 |
342 InfoBarDelegate::Type ExtensionDevToolsInfoBarDelegate::GetInfoBarType() const { | 384 InfoBarDelegate::Type ExtensionDevToolsInfoBarDelegate::GetInfoBarType() const { |
343 return WARNING_TYPE; | 385 return WARNING_TYPE; |
344 } | 386 } |
345 | 387 |
346 string16 ExtensionDevToolsInfoBarDelegate::GetMessageText() const { | 388 string16 ExtensionDevToolsInfoBarDelegate::GetMessageText() const { |
347 return l10n_util::GetStringFUTF16(IDS_DEV_TOOLS_INFOBAR_LABEL, | 389 return l10n_util::GetStringFUTF16(IDS_DEV_TOOLS_INFOBAR_LABEL, |
348 UTF8ToUTF16(client_name_)); | 390 UTF8ToUTF16(client_name_)); |
349 } | 391 } |
350 | 392 |
| 393 void ExtensionDevToolsInfoBarDelegate::InfoBarDismissed() { |
| 394 if (client_host_) |
| 395 client_host_->MarkAsDismissed(); |
| 396 } |
| 397 |
| 398 bool ExtensionDevToolsInfoBarDelegate::Cancel() { |
| 399 if (client_host_) |
| 400 client_host_->MarkAsDismissed(); |
| 401 return true; |
| 402 } |
| 403 |
351 DebuggerFunction::DebuggerFunction() | 404 DebuggerFunction::DebuggerFunction() |
352 : contents_(0), | 405 : contents_(0), |
353 tab_id_(0), | 406 tab_id_(0), |
354 client_host_(0) { | 407 client_host_(0) { |
355 } | 408 } |
356 | 409 |
357 bool DebuggerFunction::InitTabContents() { | 410 bool DebuggerFunction::InitTabContents() { |
358 // Find the TabContents that contains this tab id. | 411 // Find the TabContents that contains this tab id. |
359 contents_ = NULL; | 412 contents_ = NULL; |
360 TabContents* tab_contents = NULL; | 413 TabContents* tab_contents = NULL; |
(...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
481 } | 534 } |
482 | 535 |
483 DictionaryValue* result_body; | 536 DictionaryValue* result_body; |
484 SendCommand::Results::Result result; | 537 SendCommand::Results::Result result; |
485 if (response->GetDictionary("result", &result_body)) | 538 if (response->GetDictionary("result", &result_body)) |
486 result.additional_properties.Swap(result_body); | 539 result.additional_properties.Swap(result_body); |
487 | 540 |
488 results_ = SendCommand::Results::Create(result); | 541 results_ = SendCommand::Results::Create(result); |
489 SendResponse(true); | 542 SendResponse(true); |
490 } | 543 } |
| 544 |
| 545 // static |
| 546 void DebuggerApi::MarkDevToolsClientHostAsReplaced( |
| 547 DevToolsClientHost* client_host) { |
| 548 ExtensionDevToolsClientHost* host = AttachedClientHosts::GetInstance()-> |
| 549 AsExtensionDevToolsClientHost(client_host); |
| 550 if (host) |
| 551 host->MarkAsReplaced(); |
| 552 } |
OLD | NEW |