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

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: . 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) 2012 The Chromium Authors. All rights reserved.
vsevik 2013/11/12 14:24:07 ditto
Vladislav Kaznacheev 2013/11/13 16:02:33 Done.
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 const char kAdbPackagesList[] = "packages";
60
61 const char kAdbScreenWidthField[] = "adbScreenWidth";
62 const char kAdbScreenHeightField[] = "adbScreenHeight";
63 const char kAdbAttachedForeignField[] = "adbAttachedForeign";
64
65 // RenderViewHostTargetsUIHandler ---------------------------------------------
66
67 class RenderViewHostTargetsUIHandler
68 : public DevToolsTargetsUIHandler,
69 public content::NotificationObserver {
70 public:
71 explicit RenderViewHostTargetsUIHandler(Callback callback);
72 virtual ~RenderViewHostTargetsUIHandler();
73 private:
74 // content::NotificationObserver overrides.
75 virtual void Observe(int type,
76 const content::NotificationSource& source,
77 const content::NotificationDetails& details) OVERRIDE;
78
79 void UpdateTargets();
80
81 content::NotificationRegistrar notification_registrar_;
82 };
83
84 RenderViewHostTargetsUIHandler::RenderViewHostTargetsUIHandler(
85 Callback callback)
86 : DevToolsTargetsUIHandler(kTargetSourceRenderer, callback) {
87 notification_registrar_.Add(this,
88 content::NOTIFICATION_WEB_CONTENTS_CONNECTED,
89 content::NotificationService::AllSources());
90 notification_registrar_.Add(this,
91 content::NOTIFICATION_WEB_CONTENTS_DISCONNECTED,
92 content::NotificationService::AllSources());
93 notification_registrar_.Add(this,
94 content::NOTIFICATION_WEB_CONTENTS_DESTROYED,
95 content::NotificationService::AllSources());
96 UpdateTargets();
97 }
98
99 RenderViewHostTargetsUIHandler::~RenderViewHostTargetsUIHandler() {
100 notification_registrar_.RemoveAll();
101 }
102
103 void RenderViewHostTargetsUIHandler::Observe(
104 int type,
105 const content::NotificationSource& source,
106 const content::NotificationDetails& details) {
107 UpdateTargets();
108 }
109
110 void RenderViewHostTargetsUIHandler::UpdateTargets() {
111 scoped_ptr<ListValue> list_value(new ListValue());
112
113 std::map<WebContents*, DictionaryValue*> web_contents_to_descriptor_;
114 std::vector<DevToolsTargetImpl*> guest_targets;
115
116 DevToolsTargetImpl::List targets =
117 DevToolsTargetImpl::EnumerateRenderViewHostTargets();
118
119 STLDeleteValues(&targets_);
120 for (DevToolsTargetImpl::List::iterator it = targets.begin();
121 it != targets.end(); ++it) {
122 scoped_ptr<DevToolsTargetImpl> target(*it);
123 content::RenderViewHost* rvh = target->GetRenderViewHost();
124 if (!rvh)
125 continue;
126 WebContents* web_contents = WebContents::FromRenderViewHost(rvh);
127 if (!web_contents)
128 continue;
129
130 DevToolsTargetImpl* target_ptr = target.get();
131 targets_[target_ptr->GetId()] = target.release();
132 if (rvh->GetProcess()->IsGuest()) {
133 guest_targets.push_back(target_ptr);
134 } else {
135 DictionaryValue* descriptor = Serialize(*target_ptr);
136 list_value->Append(descriptor);
137 web_contents_to_descriptor_[web_contents] = descriptor;
138 }
139 }
140
141 // Add the list of guest-views to each of its embedders.
142 for (std::vector<DevToolsTargetImpl*>::iterator it(guest_targets.begin());
143 it != guest_targets.end(); ++it) {
144 DevToolsTargetImpl* guest = (*it);
145 WebContents* guest_web_contents =
146 WebContents::FromRenderViewHost(guest->GetRenderViewHost());
147 WebContents* embedder = guest_web_contents->GetEmbedderWebContents();
148 if (embedder && web_contents_to_descriptor_.count(embedder) > 0) {
149 DictionaryValue* parent = web_contents_to_descriptor_[embedder];
150 ListValue* guests = NULL;
151 if (!parent->GetList(kGuestList, &guests)) {
152 guests = new ListValue();
153 parent->Set(kGuestList, guests);
154 }
155 guests->Append(Serialize(*guest));
156 }
157 }
158
159 SendSerializedTargets(list_value.Pass());
160 }
161
162 // WorkerObserver -------------------------------------------------------------
163
164 class WorkerObserver
165 : public content::WorkerServiceObserver,
166 public base::RefCountedThreadSafe<WorkerObserver> {
167 public:
168 WorkerObserver() {}
169
170 void Start(DevToolsTargetImpl::Callback callback) {
171 DCHECK(callback_.is_null());
172 DCHECK(!callback.is_null());
173 callback_ = callback;
174 BrowserThread::PostTask(
175 BrowserThread::IO, FROM_HERE,
176 base::Bind(&WorkerObserver::StartOnIOThread, this));
177 }
178
179 void Stop() {
180 DCHECK(!callback_.is_null());
181 callback_ = DevToolsTargetImpl::Callback();
182 BrowserThread::PostTask(
183 BrowserThread::IO, FROM_HERE,
184 base::Bind(&WorkerObserver::StopOnIOThread, this));
185 }
186
187 void Enumerate() {
188 BrowserThread::PostTask(
189 BrowserThread::IO, FROM_HERE,
190 base::Bind(&WorkerObserver::EnumerateOnUIThread,
191 this));
192 }
193
194 private:
195 friend class base::RefCountedThreadSafe<WorkerObserver>;
196 virtual ~WorkerObserver() {}
197
198 // content::WorkerServiceObserver overrides:
199 virtual void WorkerCreated(
200 const GURL& url,
201 const string16& name,
202 int process_id,
203 int route_id) OVERRIDE {
204 EnumerateOnUIThread();
205 }
206
207 virtual void WorkerDestroyed(int process_id, int route_id) OVERRIDE {
208 EnumerateOnUIThread();
209 }
210
211 void StartOnIOThread() {
212 content::WorkerService::GetInstance()->AddObserver(this);
213 EnumerateOnUIThread();
214 }
215
216 void StopOnIOThread() {
217 content::WorkerService::GetInstance()->RemoveObserver(this);
218 }
219
220 void EnumerateOnUIThread() {
vsevik 2013/11/12 14:24:07 Seeing a method with a name that ends with "OnUITh
Vladislav Kaznacheev 2013/11/13 16:02:33 Oops. What was I thinking. Done.
221 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
222 DevToolsTargetImpl::EnumerateWorkerTargets(
223 base::Bind(&WorkerObserver::RespondOnUIThread, this));
224 }
225
226 void RespondOnUIThread(const DevToolsTargetImpl::List& targets) {
227 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
228 if (callback_.is_null())
229 return;
230 callback_.Run(targets);
231 }
232
233 DevToolsTargetImpl::Callback callback_;
234 };
235
236 // WorkerTargetsUIHandler -----------------------------------------------------
237
238 class WorkerTargetsUIHandler
239 : public DevToolsTargetsUIHandler,
240 public content::BrowserChildProcessObserver {
241 public:
242 explicit WorkerTargetsUIHandler(Callback callback);
243 virtual ~WorkerTargetsUIHandler();
244
245 private:
246 // content::BrowserChildProcessObserver overrides.
247 virtual void BrowserChildProcessHostConnected(
248 const content::ChildProcessData& data) OVERRIDE;
249 virtual void BrowserChildProcessHostDisconnected(
250 const content::ChildProcessData& data) OVERRIDE;
251
252 void UpdateTargets(const DevToolsTargetImpl::List& targets);
253
254 scoped_refptr<WorkerObserver> observer_;
255 };
256
257 WorkerTargetsUIHandler::WorkerTargetsUIHandler(Callback callback)
258 : DevToolsTargetsUIHandler(kTargetSourceWorker, callback),
259 observer_(new WorkerObserver()) {
260 observer_->Start(base::Bind(&WorkerTargetsUIHandler::UpdateTargets,
261 base::Unretained(this)));
262 BrowserChildProcessObserver::Add(this);
263 }
264
265 WorkerTargetsUIHandler::~WorkerTargetsUIHandler() {
266 BrowserChildProcessObserver::Remove(this);
267 observer_->Stop();
268 }
269
270 void WorkerTargetsUIHandler::BrowserChildProcessHostConnected(
271 const content::ChildProcessData& data) {
272 if (data.process_type == content::PROCESS_TYPE_WORKER)
273 observer_->Enumerate();
274 }
275
276 void WorkerTargetsUIHandler::BrowserChildProcessHostDisconnected(
277 const content::ChildProcessData& data) {
278 if (data.process_type == content::PROCESS_TYPE_WORKER)
279 observer_->Enumerate();
280 }
281
282 void WorkerTargetsUIHandler::UpdateTargets(
283 const DevToolsTargetImpl::List& targets) {
284 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
285 scoped_ptr<ListValue> list_value(new ListValue());
286 STLDeleteValues(&targets_);
287 for (DevToolsTargetImpl::List::const_iterator it = targets.begin();
288 it != targets.end(); ++it) {
289 DevToolsTargetImpl* target = *it;
290 list_value->Append(Serialize(*target));
291 targets_[target->GetId()] = target;
292 }
293 SendSerializedTargets(list_value.Pass());
294 }
295
296 // AdbTargetsUIHandler --------------------------------------------------------
297
298 class AdbTargetsUIHandler
299 : public DevToolsRemoteTargetsUIHandler,
300 public DevToolsAdbBridge::Listener {
301 public:
302 AdbTargetsUIHandler(Callback callback, Profile* profile);
303 virtual ~AdbTargetsUIHandler();
304
305 virtual void Open(const std::string& browser_id,
306 const std::string& url) OVERRIDE;
307 virtual void Launch(const std::string& package_id) OVERRIDE;
308
309 private:
310 // DevToolsAdbBridge::Listener overrides.
311 virtual void RemoteDevicesChanged(
312 DevToolsAdbBridge::RemoteDevices* devices) OVERRIDE;
313
314 Profile* profile_;
315
316 typedef std::map<std::string,
317 scoped_refptr<DevToolsAdbBridge::RemoteBrowser> > RemoteBrowsers;
318 RemoteBrowsers remote_browsers_;
319
320 typedef std::map<std::string,
321 scoped_refptr<DevToolsAdbBridge::RemotePackage> > RemotePackages;
322 RemotePackages remote_packages_;
323 };
324
325 AdbTargetsUIHandler::AdbTargetsUIHandler(Callback callback, Profile* profile)
326 : DevToolsRemoteTargetsUIHandler(kTargetSourceAdb, callback),
327 profile_(profile) {
328 DevToolsAdbBridge* adb_bridge =
329 DevToolsAdbBridge::Factory::GetForProfile(profile_);
330 if (adb_bridge)
331 adb_bridge->AddListener(this);
332 }
333
334 AdbTargetsUIHandler::~AdbTargetsUIHandler() {
335 DevToolsAdbBridge* adb_bridge =
336 DevToolsAdbBridge::Factory::GetForProfile(profile_);
337 if (adb_bridge)
338 adb_bridge->RemoveListener(this);
339 }
340
341 void AdbTargetsUIHandler::Open(const std::string& browser_id,
342 const std::string& url) {
343 RemoteBrowsers::iterator it = remote_browsers_.find(browser_id);
344 if (it != remote_browsers_.end())
345 it->second->Open(url);
346 }
347
348 void AdbTargetsUIHandler::Launch(const std::string& package_id) {
349 RemotePackages::iterator it = remote_packages_.find(package_id);
350 if (it != remote_packages_.end())
351 it->second->Launch();
352 }
353
354 void AdbTargetsUIHandler::RemoteDevicesChanged(
355 DevToolsAdbBridge::RemoteDevices* devices) {
356 PortForwardingController* port_forwarding_controller =
357 PortForwardingController::Factory::GetForProfile(profile_);
358 PortForwardingController::DevicesStatus port_forwarding_status;
359 if (port_forwarding_controller)
360 port_forwarding_status =
361 port_forwarding_controller->UpdateDeviceList(*devices);
362
363 remote_browsers_.clear();
364 remote_packages_.clear();
365 STLDeleteValues(&targets_);
366
367 scoped_ptr<ListValue> device_list(new ListValue());
368 for (DevToolsAdbBridge::RemoteDevices::iterator dit = devices->begin();
369 dit != devices->end(); ++dit) {
370 DevToolsAdbBridge::RemoteDevice* device = dit->get();
371 DictionaryValue* device_data = new DictionaryValue();
372 device_data->SetString(kAdbModelField, device->GetModel());
373 device_data->SetString(kAdbSerialField, device->GetSerial());
374 device_data->SetBoolean(kAdbConnectedField, device->IsConnected());
375 std::string device_id = base::StringPrintf(
376 "device:%s",
377 device->GetSerial().c_str());
378 device_data->SetString(kTargetIdField, device_id);
379 ListValue* browser_list = new ListValue();
380 device_data->Set(kAdbBrowsersList, browser_list);
381
382 DevToolsAdbBridge::RemoteBrowsers& browsers = device->browsers();
383 for (DevToolsAdbBridge::RemoteBrowsers::iterator bit =
384 browsers.begin(); bit != browsers.end(); ++bit) {
385 DevToolsAdbBridge::RemoteBrowser* browser = bit->get();
386 DictionaryValue* browser_data = new DictionaryValue();
387 browser_data->SetString(kAdbBrowserNameField, browser->display_name());
388 browser_data->SetString(kAdbBrowserVersionField, browser->version());
389 DevToolsAdbBridge::RemoteBrowser::ParsedVersion parsed =
390 browser->GetParsedVersion();
391 browser_data->SetInteger(
392 kAdbBrowserChromeVersionField,
393 browser->IsChrome() && !parsed.empty() ? parsed[0] : 0);
394 std::string browser_id = base::StringPrintf(
395 "browser:%s:%s:%s:%s",
396 device->GetSerial().c_str(), // Ensure uniqueness across devices.
397 browser->display_name().c_str(), // Sort by display name.
398 browser->version().c_str(), // Then by version.
399 browser->socket().c_str()); // Ensure uniqueness on the device.
400 browser_data->SetString(kTargetIdField, browser_id);
401 browser_data->SetString(kTargetSourceField, source_id());
402 remote_browsers_[browser_id] = browser;
403 ListValue* page_list = new ListValue();
404 browser_data->Set(kAdbPagesList, page_list);
405
406 DevToolsTargetImpl::List pages = browser->CreatePageTargets();
407 for (DevToolsTargetImpl::List::iterator it =
408 pages.begin(); it != pages.end(); ++it) {
409 DevToolsTargetImpl* target = *it;
410 DictionaryValue* target_data = Serialize(*target);
411 target_data->SetBoolean(
412 kAdbAttachedForeignField,
413 target->IsAttached() &&
414 !DevToolsAdbBridge::HasDevToolsWindow(target->GetId()));
415 // Pass the screen size in the target object to make sure that
416 // the caching logic does not prevent the target item from updating
417 // when the screen size changes.
418 gfx::Size screen_size = device->screen_size();
419 target_data->SetInteger(kAdbScreenWidthField, screen_size.width());
420 target_data->SetInteger(kAdbScreenHeightField, screen_size.height());
421 targets_[target->GetId()] = target;
422 page_list->Append(target_data);
423 }
424 browser_list->Append(browser_data);
425 }
426
427 ListValue* package_list = new ListValue();
428 device_data->Set(kAdbPackagesList, package_list);
429
430 DevToolsAdbBridge::RemotePackages& packages = device->packages();
431 for (DevToolsAdbBridge::RemotePackages::iterator pit = packages.begin();
432 pit != packages.end(); ++pit) {
433 DevToolsAdbBridge::RemotePackage* package = pit->get();
434 DictionaryValue* package_data = new DictionaryValue();
435 package_data->SetString(kAdbBrowserNameField, package->display_name());
436 std::string package_id = base::StringPrintf(
437 "package:%s:%s",
438 device->GetSerial().c_str(), // Ensure uniqueness across devices.
439 package->package_name().c_str()); // Ensure uniqueness on the device.
440 package_data->SetString(kTargetIdField, package_id);
441 package_data->SetString(kTargetSourceField, source_id());
442 remote_packages_[package_id] = package;
443 package_list->Append(package_data);
444 }
445
446 if (port_forwarding_controller) {
447 PortForwardingController::DevicesStatus::iterator sit =
448 port_forwarding_status.find(device->GetSerial());
449 if (sit != port_forwarding_status.end()) {
450 DictionaryValue* port_status_dict = new DictionaryValue();
451 typedef PortForwardingController::PortStatusMap StatusMap;
452 const StatusMap& port_status = sit->second;
453 for (StatusMap::const_iterator it = port_status.begin();
454 it != port_status.end(); ++it) {
455 port_status_dict->SetInteger(
456 base::StringPrintf("%d", it->first), it->second);
457 }
458 device_data->Set(kAdbPortStatus, port_status_dict);
459 }
460 }
461
462 device_list->Append(device_data);
463 }
464 SendSerializedTargets(device_list.Pass());
465 }
466
467 } // namespace
468
469 // DevToolsTargetsUIHandler ---------------------------------------------------
470
471 DevToolsTargetsUIHandler::DevToolsTargetsUIHandler(
472 const std::string& source_id,
473 Callback callback)
474 : source_id_(source_id),
475 callback_(callback) {
476 }
477
478 DevToolsTargetsUIHandler::~DevToolsTargetsUIHandler() {
479 STLDeleteValues(&targets_);
480 }
481
482 // static
483 scoped_ptr<DevToolsTargetsUIHandler>
484 DevToolsTargetsUIHandler::CreateForRenderers(
485 DevToolsTargetsUIHandler::Callback callback) {
486 return scoped_ptr<DevToolsTargetsUIHandler>(
487 new RenderViewHostTargetsUIHandler(callback));
488 }
489
490 // static
491 scoped_ptr<DevToolsTargetsUIHandler>
492 DevToolsTargetsUIHandler::CreateForWorkers(
493 DevToolsTargetsUIHandler::Callback callback) {
494 return scoped_ptr<DevToolsTargetsUIHandler>(
495 new WorkerTargetsUIHandler(callback));
496 }
497
498 void DevToolsTargetsUIHandler::Inspect(const std::string& target_id,
499 Profile* profile) {
500 TargetMap::iterator it = targets_.find(target_id);
501 if (it != targets_.end())
502 it->second->Inspect(profile);
503 }
504
505 void DevToolsTargetsUIHandler::Activate(const std::string& target_id) {
506 TargetMap::iterator it = targets_.find(target_id);
507 if (it != targets_.end())
508 it->second->Activate();
509 }
510
511 void DevToolsTargetsUIHandler::Close(const std::string& target_id) {
512 TargetMap::iterator it = targets_.find(target_id);
513 if (it != targets_.end())
514 it->second->Close();
515 }
516
517 void DevToolsTargetsUIHandler::Reload(const std::string& target_id) {
518 TargetMap::iterator it = targets_.find(target_id);
519 if (it != targets_.end())
520 it->second->Reload();
521 }
522
523 base::DictionaryValue*
524 DevToolsTargetsUIHandler::Serialize(
525 const DevToolsTargetImpl& target) {
526 DictionaryValue* target_data = new DictionaryValue();
527 target_data->SetString(kTargetSourceField, source_id_);
528 target_data->SetString(kTargetIdField, target.GetId());
529 target_data->SetString(kTargetTypeField, target.GetType());
530 target_data->SetBoolean(kAttachedField, target.IsAttached());
531 target_data->SetString(kUrlField, target.GetUrl().spec());
532 target_data->SetString(kNameField, net::EscapeForHTML(target.GetTitle()));
533 target_data->SetString(kFaviconUrlField, target.GetFaviconUrl().spec());
534 target_data->SetString(kDescriptionField, target.GetDescription());
535 return target_data;
536 }
537
538 void DevToolsTargetsUIHandler::SendSerializedTargets(
539 scoped_ptr<ListValue> list) {
540 callback_.Run(source_id_, list.Pass());
541 }
542
543 // DevToolsRemoteTargetsUIHandler ---------------------------------------------
544
545 DevToolsRemoteTargetsUIHandler::DevToolsRemoteTargetsUIHandler(
546 const std::string& source_id,
547 Callback callback)
548 : DevToolsTargetsUIHandler(source_id, callback) {
549 }
550
551 // static
552 scoped_ptr<DevToolsRemoteTargetsUIHandler>
553 DevToolsRemoteTargetsUIHandler::CreateForAdb(
554 DevToolsTargetsUIHandler::Callback callback, Profile* profile) {
555 return scoped_ptr<DevToolsRemoteTargetsUIHandler>(
556 new AdbTargetsUIHandler(callback, profile));
557 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698