Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1165)

Side by Side Diff: chrome/browser/devtools/devtools_targets_ui.cc

Issue 65143004: DevTools: Refactor InspectUI class for extensibility (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Addressed comments, rebased Created 7 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright (c) 2013 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 "chrome/browser/devtools/devtools_targets_ui.h"
6
7 #include "base/stl_util.h"
8 #include "base/strings/stringprintf.h"
9 #include "base/values.h"
10 #include "chrome/browser/devtools/devtools_adb_bridge.h"
11 #include "chrome/browser/devtools/devtools_target_impl.h"
12 #include "chrome/browser/devtools/port_forwarding_controller.h"
13 #include "content/public/browser/browser_child_process_observer.h"
14 #include "content/public/browser/browser_thread.h"
15 #include "content/public/browser/child_process_data.h"
16 #include "content/public/browser/notification_observer.h"
17 #include "content/public/browser/notification_registrar.h"
18 #include "content/public/browser/notification_service.h"
19 #include "content/public/browser/notification_source.h"
20 #include "content/public/browser/notification_types.h"
21 #include "content/public/browser/render_process_host.h"
22 #include "content/public/browser/render_view_host.h"
23 #include "content/public/browser/web_contents.h"
24 #include "content/public/browser/worker_service.h"
25 #include "content/public/browser/worker_service_observer.h"
26 #include "content/public/common/process_type.h"
27 #include "net/base/escape.h"
28
29 using content::BrowserThread;
30 using content::WebContents;
31
32 namespace {
33
34 const char kTargetSourceField[] = "source";
35 const char kTargetSourceRenderer[] = "renderers";
36 const char kTargetSourceWorker[] = "workers";
37 const char kTargetSourceAdb[] = "adb";
38
39 const char kTargetIdField[] = "id";
40 const char kTargetTypeField[] = "type";
41 const char kAttachedField[] = "attached";
42 const char kUrlField[] = "url";
43 const char kNameField[] = "name";
44 const char kFaviconUrlField[] = "faviconUrl";
45 const char kDescriptionField[] = "description";
46
47 const char kGuestList[] = "guests";
48
49 const char kAdbModelField[] = "adbModel";
50 const char kAdbConnectedField[] = "adbConnected";
51 const char kAdbSerialField[] = "adbSerial";
52 const char kAdbPortStatus[] = "adbPortStatus";
53 const char kAdbBrowsersList[] = "browsers";
54
55 const char kAdbBrowserNameField[] = "adbBrowserName";
56 const char kAdbBrowserVersionField[] = "adbBrowserVersion";
57 const char kAdbBrowserChromeVersionField[] = "adbBrowserChromeVersion";
58 const char kAdbPagesList[] = "pages";
59
60 const char kAdbScreenWidthField[] = "adbScreenWidth";
61 const char kAdbScreenHeightField[] = "adbScreenHeight";
62 const char kAdbAttachedForeignField[] = "adbAttachedForeign";
63
64 // RenderViewHostTargetsUIHandler ---------------------------------------------
65
66 class RenderViewHostTargetsUIHandler
67 : public DevToolsTargetsUIHandler,
68 public content::NotificationObserver {
69 public:
70 explicit RenderViewHostTargetsUIHandler(Callback callback);
71 virtual ~RenderViewHostTargetsUIHandler();
72 private:
73 // content::NotificationObserver overrides.
74 virtual void Observe(int type,
75 const content::NotificationSource& source,
76 const content::NotificationDetails& details) OVERRIDE;
77
78 void UpdateTargets();
79
80 content::NotificationRegistrar notification_registrar_;
81 };
82
83 RenderViewHostTargetsUIHandler::RenderViewHostTargetsUIHandler(
84 Callback callback)
85 : DevToolsTargetsUIHandler(kTargetSourceRenderer, callback) {
86 notification_registrar_.Add(this,
87 content::NOTIFICATION_WEB_CONTENTS_CONNECTED,
88 content::NotificationService::AllSources());
89 notification_registrar_.Add(this,
90 content::NOTIFICATION_WEB_CONTENTS_DISCONNECTED,
91 content::NotificationService::AllSources());
92 notification_registrar_.Add(this,
93 content::NOTIFICATION_WEB_CONTENTS_DESTROYED,
94 content::NotificationService::AllSources());
95 UpdateTargets();
96 }
97
98 RenderViewHostTargetsUIHandler::~RenderViewHostTargetsUIHandler() {
99 notification_registrar_.RemoveAll();
100 }
101
102 void RenderViewHostTargetsUIHandler::Observe(
103 int type,
104 const content::NotificationSource& source,
105 const content::NotificationDetails& details) {
106 UpdateTargets();
107 }
108
109 void RenderViewHostTargetsUIHandler::UpdateTargets() {
110 scoped_ptr<ListValue> list_value(new ListValue());
111
112 std::map<WebContents*, DictionaryValue*> web_contents_to_descriptor_;
113 std::vector<DevToolsTargetImpl*> guest_targets;
114
115 DevToolsTargetImpl::List targets =
116 DevToolsTargetImpl::EnumerateRenderViewHostTargets();
117
118 STLDeleteValues(&targets_);
119 for (DevToolsTargetImpl::List::iterator it = targets.begin();
120 it != targets.end(); ++it) {
121 scoped_ptr<DevToolsTargetImpl> target(*it);
122 content::RenderViewHost* rvh = target->GetRenderViewHost();
123 if (!rvh)
124 continue;
125 WebContents* web_contents = WebContents::FromRenderViewHost(rvh);
126 if (!web_contents)
127 continue;
128
129 DevToolsTargetImpl* target_ptr = target.get();
130 targets_[target_ptr->GetId()] = target.release();
131 if (rvh->GetProcess()->IsGuest()) {
132 guest_targets.push_back(target_ptr);
133 } else {
134 DictionaryValue* descriptor = Serialize(*target_ptr);
135 list_value->Append(descriptor);
136 web_contents_to_descriptor_[web_contents] = descriptor;
137 }
138 }
139
140 // Add the list of guest-views to each of its embedders.
141 for (std::vector<DevToolsTargetImpl*>::iterator it(guest_targets.begin());
142 it != guest_targets.end(); ++it) {
143 DevToolsTargetImpl* guest = (*it);
144 WebContents* guest_web_contents =
145 WebContents::FromRenderViewHost(guest->GetRenderViewHost());
146 WebContents* embedder = guest_web_contents->GetEmbedderWebContents();
147 if (embedder && web_contents_to_descriptor_.count(embedder) > 0) {
148 DictionaryValue* parent = web_contents_to_descriptor_[embedder];
149 ListValue* guests = NULL;
150 if (!parent->GetList(kGuestList, &guests)) {
151 guests = new ListValue();
152 parent->Set(kGuestList, guests);
153 }
154 guests->Append(Serialize(*guest));
155 }
156 }
157
158 SendSerializedTargets(list_value.Pass());
159 }
160
161 // WorkerObserver -------------------------------------------------------------
162
163 class WorkerObserver
164 : public content::WorkerServiceObserver,
165 public base::RefCountedThreadSafe<WorkerObserver> {
166 public:
167 WorkerObserver() {}
168
169 void Start(DevToolsTargetImpl::Callback callback) {
170 DCHECK(callback_.is_null());
171 DCHECK(!callback.is_null());
172 callback_ = callback;
173 BrowserThread::PostTask(
174 BrowserThread::IO, FROM_HERE,
175 base::Bind(&WorkerObserver::StartOnIOThread, this));
176 }
177
178 void Stop() {
179 DCHECK(!callback_.is_null());
180 callback_ = DevToolsTargetImpl::Callback();
181 BrowserThread::PostTask(
182 BrowserThread::IO, FROM_HERE,
183 base::Bind(&WorkerObserver::StopOnIOThread, this));
184 }
185
186 void Enumerate() {
187 BrowserThread::PostTask(
188 BrowserThread::IO, FROM_HERE,
189 base::Bind(&WorkerObserver::EnumerateOnIOThread,
190 this));
191 }
192
193 private:
194 friend class base::RefCountedThreadSafe<WorkerObserver>;
195 virtual ~WorkerObserver() {}
196
197 // content::WorkerServiceObserver overrides:
198 virtual void WorkerCreated(
199 const GURL& url,
200 const string16& name,
201 int process_id,
202 int route_id) OVERRIDE {
203 EnumerateOnIOThread();
204 }
205
206 virtual void WorkerDestroyed(int process_id, int route_id) OVERRIDE {
207 EnumerateOnIOThread();
208 }
209
210 void StartOnIOThread() {
211 content::WorkerService::GetInstance()->AddObserver(this);
212 EnumerateOnIOThread();
213 }
214
215 void StopOnIOThread() {
216 content::WorkerService::GetInstance()->RemoveObserver(this);
217 }
218
219 void EnumerateOnIOThread() {
220 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
221 DevToolsTargetImpl::EnumerateWorkerTargets(
222 base::Bind(&WorkerObserver::RespondOnUIThread, this));
223 }
224
225 void RespondOnUIThread(const DevToolsTargetImpl::List& targets) {
226 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
227 if (callback_.is_null())
228 return;
229 callback_.Run(targets);
230 }
231
232 DevToolsTargetImpl::Callback callback_;
233 };
234
235 // WorkerTargetsUIHandler -----------------------------------------------------
236
237 class WorkerTargetsUIHandler
238 : public DevToolsTargetsUIHandler,
239 public content::BrowserChildProcessObserver {
240 public:
241 explicit WorkerTargetsUIHandler(Callback callback);
242 virtual ~WorkerTargetsUIHandler();
243
244 private:
245 // content::BrowserChildProcessObserver overrides.
246 virtual void BrowserChildProcessHostConnected(
247 const content::ChildProcessData& data) OVERRIDE;
248 virtual void BrowserChildProcessHostDisconnected(
249 const content::ChildProcessData& data) OVERRIDE;
250
251 void UpdateTargets(const DevToolsTargetImpl::List& targets);
252
253 scoped_refptr<WorkerObserver> observer_;
254 };
255
256 WorkerTargetsUIHandler::WorkerTargetsUIHandler(Callback callback)
257 : DevToolsTargetsUIHandler(kTargetSourceWorker, callback),
258 observer_(new WorkerObserver()) {
259 observer_->Start(base::Bind(&WorkerTargetsUIHandler::UpdateTargets,
260 base::Unretained(this)));
261 BrowserChildProcessObserver::Add(this);
262 }
263
264 WorkerTargetsUIHandler::~WorkerTargetsUIHandler() {
265 BrowserChildProcessObserver::Remove(this);
266 observer_->Stop();
267 }
268
269 void WorkerTargetsUIHandler::BrowserChildProcessHostConnected(
270 const content::ChildProcessData& data) {
271 if (data.process_type == content::PROCESS_TYPE_WORKER)
272 observer_->Enumerate();
273 }
274
275 void WorkerTargetsUIHandler::BrowserChildProcessHostDisconnected(
276 const content::ChildProcessData& data) {
277 if (data.process_type == content::PROCESS_TYPE_WORKER)
278 observer_->Enumerate();
279 }
280
281 void WorkerTargetsUIHandler::UpdateTargets(
282 const DevToolsTargetImpl::List& targets) {
283 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
284 scoped_ptr<ListValue> list_value(new ListValue());
285 STLDeleteValues(&targets_);
286 for (DevToolsTargetImpl::List::const_iterator it = targets.begin();
287 it != targets.end(); ++it) {
288 DevToolsTargetImpl* target = *it;
289 list_value->Append(Serialize(*target));
290 targets_[target->GetId()] = target;
291 }
292 SendSerializedTargets(list_value.Pass());
293 }
294
295 // AdbTargetsUIHandler --------------------------------------------------------
296
297 class AdbTargetsUIHandler
298 : public DevToolsRemoteTargetsUIHandler,
299 public DevToolsAdbBridge::Listener {
300 public:
301 AdbTargetsUIHandler(Callback callback, Profile* profile);
302 virtual ~AdbTargetsUIHandler();
303
304 virtual void Open(const std::string& browser_id,
305 const std::string& url) OVERRIDE;
306
307 private:
308 // DevToolsAdbBridge::Listener overrides.
309 virtual void RemoteDevicesChanged(
310 DevToolsAdbBridge::RemoteDevices* devices) OVERRIDE;
311
312 Profile* profile_;
313
314 typedef std::map<std::string,
315 scoped_refptr<DevToolsAdbBridge::RemoteBrowser> > RemoteBrowsers;
316 RemoteBrowsers remote_browsers_;
317 };
318
319 AdbTargetsUIHandler::AdbTargetsUIHandler(Callback callback, Profile* profile)
320 : DevToolsRemoteTargetsUIHandler(kTargetSourceAdb, callback),
321 profile_(profile) {
322 DevToolsAdbBridge* adb_bridge =
323 DevToolsAdbBridge::Factory::GetForProfile(profile_);
324 if (adb_bridge)
325 adb_bridge->AddListener(this);
326 }
327
328 AdbTargetsUIHandler::~AdbTargetsUIHandler() {
329 DevToolsAdbBridge* adb_bridge =
330 DevToolsAdbBridge::Factory::GetForProfile(profile_);
331 if (adb_bridge)
332 adb_bridge->RemoveListener(this);
333 }
334
335 void AdbTargetsUIHandler::Open(const std::string& browser_id,
336 const std::string& url) {
337 RemoteBrowsers::iterator it = remote_browsers_.find(browser_id);
338 if (it != remote_browsers_.end())
339 it->second->Open(url);
340 }
341
342 void AdbTargetsUIHandler::RemoteDevicesChanged(
343 DevToolsAdbBridge::RemoteDevices* devices) {
344 PortForwardingController* port_forwarding_controller =
345 PortForwardingController::Factory::GetForProfile(profile_);
346 PortForwardingController::DevicesStatus port_forwarding_status;
347 if (port_forwarding_controller)
348 port_forwarding_status =
349 port_forwarding_controller->UpdateDeviceList(*devices);
350
351 remote_browsers_.clear();
352 STLDeleteValues(&targets_);
353
354 scoped_ptr<ListValue> device_list(new ListValue());
355 for (DevToolsAdbBridge::RemoteDevices::iterator dit = devices->begin();
356 dit != devices->end(); ++dit) {
357 DevToolsAdbBridge::RemoteDevice* device = dit->get();
358 DictionaryValue* device_data = new DictionaryValue();
359 device_data->SetString(kAdbModelField, device->GetModel());
360 device_data->SetString(kAdbSerialField, device->GetSerial());
361 device_data->SetBoolean(kAdbConnectedField, device->IsConnected());
362 std::string device_id = base::StringPrintf(
363 "device:%s",
364 device->GetSerial().c_str());
365 device_data->SetString(kTargetIdField, device_id);
366 ListValue* browser_list = new ListValue();
367 device_data->Set(kAdbBrowsersList, browser_list);
368
369 DevToolsAdbBridge::RemoteBrowsers& browsers = device->browsers();
370 for (DevToolsAdbBridge::RemoteBrowsers::iterator bit =
371 browsers.begin(); bit != browsers.end(); ++bit) {
372 DevToolsAdbBridge::RemoteBrowser* browser = bit->get();
373 DictionaryValue* browser_data = new DictionaryValue();
374 browser_data->SetString(kAdbBrowserNameField, browser->display_name());
375 browser_data->SetString(kAdbBrowserVersionField, browser->version());
376 DevToolsAdbBridge::RemoteBrowser::ParsedVersion parsed =
377 browser->GetParsedVersion();
378 browser_data->SetInteger(
379 kAdbBrowserChromeVersionField,
380 browser->IsChrome() && !parsed.empty() ? parsed[0] : 0);
381 std::string browser_id = base::StringPrintf(
382 "browser:%s:%s:%s:%s",
383 device->GetSerial().c_str(), // Ensure uniqueness across devices.
384 browser->display_name().c_str(), // Sort by display name.
385 browser->version().c_str(), // Then by version.
386 browser->socket().c_str()); // Ensure uniqueness on the device.
387 browser_data->SetString(kTargetIdField, browser_id);
388 browser_data->SetString(kTargetSourceField, source_id());
389 remote_browsers_[browser_id] = browser;
390 ListValue* page_list = new ListValue();
391 browser_data->Set(kAdbPagesList, page_list);
392
393 DevToolsTargetImpl::List pages = browser->CreatePageTargets();
394 for (DevToolsTargetImpl::List::iterator it =
395 pages.begin(); it != pages.end(); ++it) {
396 DevToolsTargetImpl* target = *it;
397 DictionaryValue* target_data = Serialize(*target);
398 target_data->SetBoolean(
399 kAdbAttachedForeignField,
400 target->IsAttached() &&
401 !DevToolsAdbBridge::HasDevToolsWindow(target->GetId()));
402 // Pass the screen size in the target object to make sure that
403 // the caching logic does not prevent the target item from updating
404 // when the screen size changes.
405 gfx::Size screen_size = device->screen_size();
406 target_data->SetInteger(kAdbScreenWidthField, screen_size.width());
407 target_data->SetInteger(kAdbScreenHeightField, screen_size.height());
408 targets_[target->GetId()] = target;
409 page_list->Append(target_data);
410 }
411 browser_list->Append(browser_data);
412 }
413
414 if (port_forwarding_controller) {
415 PortForwardingController::DevicesStatus::iterator sit =
416 port_forwarding_status.find(device->GetSerial());
417 if (sit != port_forwarding_status.end()) {
418 DictionaryValue* port_status_dict = new DictionaryValue();
419 typedef PortForwardingController::PortStatusMap StatusMap;
420 const StatusMap& port_status = sit->second;
421 for (StatusMap::const_iterator it = port_status.begin();
422 it != port_status.end(); ++it) {
423 port_status_dict->SetInteger(
424 base::StringPrintf("%d", it->first), it->second);
425 }
426 device_data->Set(kAdbPortStatus, port_status_dict);
427 }
428 }
429
430 device_list->Append(device_data);
431 }
432 SendSerializedTargets(device_list.Pass());
433 }
434
435 } // namespace
436
437 // DevToolsTargetsUIHandler ---------------------------------------------------
438
439 DevToolsTargetsUIHandler::DevToolsTargetsUIHandler(
440 const std::string& source_id,
441 Callback callback)
442 : source_id_(source_id),
443 callback_(callback) {
444 }
445
446 DevToolsTargetsUIHandler::~DevToolsTargetsUIHandler() {
447 STLDeleteValues(&targets_);
448 }
449
450 // static
451 scoped_ptr<DevToolsTargetsUIHandler>
452 DevToolsTargetsUIHandler::CreateForRenderers(
453 DevToolsTargetsUIHandler::Callback callback) {
454 return scoped_ptr<DevToolsTargetsUIHandler>(
455 new RenderViewHostTargetsUIHandler(callback));
456 }
457
458 // static
459 scoped_ptr<DevToolsTargetsUIHandler>
460 DevToolsTargetsUIHandler::CreateForWorkers(
461 DevToolsTargetsUIHandler::Callback callback) {
462 return scoped_ptr<DevToolsTargetsUIHandler>(
463 new WorkerTargetsUIHandler(callback));
464 }
465
466 void DevToolsTargetsUIHandler::Inspect(const std::string& target_id,
467 Profile* profile) {
468 TargetMap::iterator it = targets_.find(target_id);
469 if (it != targets_.end())
470 it->second->Inspect(profile);
471 }
472
473 void DevToolsTargetsUIHandler::Activate(const std::string& target_id) {
474 TargetMap::iterator it = targets_.find(target_id);
475 if (it != targets_.end())
476 it->second->Activate();
477 }
478
479 void DevToolsTargetsUIHandler::Close(const std::string& target_id) {
480 TargetMap::iterator it = targets_.find(target_id);
481 if (it != targets_.end())
482 it->second->Close();
483 }
484
485 void DevToolsTargetsUIHandler::Reload(const std::string& target_id) {
486 TargetMap::iterator it = targets_.find(target_id);
487 if (it != targets_.end())
488 it->second->Reload();
489 }
490
491 base::DictionaryValue*
492 DevToolsTargetsUIHandler::Serialize(
493 const DevToolsTargetImpl& target) {
494 DictionaryValue* target_data = new DictionaryValue();
495 target_data->SetString(kTargetSourceField, source_id_);
496 target_data->SetString(kTargetIdField, target.GetId());
497 target_data->SetString(kTargetTypeField, target.GetType());
498 target_data->SetBoolean(kAttachedField, target.IsAttached());
499 target_data->SetString(kUrlField, target.GetUrl().spec());
500 target_data->SetString(kNameField, net::EscapeForHTML(target.GetTitle()));
501 target_data->SetString(kFaviconUrlField, target.GetFaviconUrl().spec());
502 target_data->SetString(kDescriptionField, target.GetDescription());
503 return target_data;
504 }
505
506 void DevToolsTargetsUIHandler::SendSerializedTargets(
507 scoped_ptr<ListValue> list) {
508 callback_.Run(source_id_, list.Pass());
509 }
510
511 // DevToolsRemoteTargetsUIHandler ---------------------------------------------
512
513 DevToolsRemoteTargetsUIHandler::DevToolsRemoteTargetsUIHandler(
514 const std::string& source_id,
515 Callback callback)
516 : DevToolsTargetsUIHandler(source_id, callback) {
517 }
518
519 // static
520 scoped_ptr<DevToolsRemoteTargetsUIHandler>
521 DevToolsRemoteTargetsUIHandler::CreateForAdb(
522 DevToolsTargetsUIHandler::Callback callback, Profile* profile) {
523 return scoped_ptr<DevToolsRemoteTargetsUIHandler>(
524 new AdbTargetsUIHandler(callback, profile));
525 }
OLDNEW
« no previous file with comments | « chrome/browser/devtools/devtools_targets_ui.h ('k') | chrome/browser/resources/inspect/inspect.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698