Make castv2 performance test work.
[chromium-blink-merge.git] / chrome / browser / devtools / devtools_targets_ui.cc
blobadaa84bdec03697be02ed051cb6d2ea13affa939
1 // Copyright 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.
5 #include "chrome/browser/devtools/devtools_targets_ui.h"
7 #include "base/memory/weak_ptr.h"
8 #include "base/stl_util.h"
9 #include "base/strings/stringprintf.h"
10 #include "base/values.h"
11 #include "base/version.h"
12 #include "chrome/browser/devtools/device/devtools_android_bridge.h"
13 #include "chrome/browser/devtools/devtools_target_impl.h"
14 #include "chrome/common/chrome_version_info.h"
15 #include "content/public/browser/browser_child_process_observer.h"
16 #include "content/public/browser/browser_thread.h"
17 #include "content/public/browser/child_process_data.h"
18 #include "content/public/browser/notification_observer.h"
19 #include "content/public/browser/notification_registrar.h"
20 #include "content/public/browser/notification_service.h"
21 #include "content/public/browser/notification_source.h"
22 #include "content/public/browser/notification_types.h"
23 #include "content/public/browser/worker_service.h"
24 #include "content/public/browser/worker_service_observer.h"
25 #include "content/public/common/process_type.h"
26 #include "net/base/escape.h"
28 using content::BrowserThread;
30 namespace {
32 const char kTargetSourceField[] = "source";
33 const char kTargetSourceLocal[] = "local";
34 const char kTargetSourceRemote[] = "remote";
36 const char kTargetIdField[] = "id";
37 const char kTargetTypeField[] = "type";
38 const char kAttachedField[] = "attached";
39 const char kUrlField[] = "url";
40 const char kNameField[] = "name";
41 const char kFaviconUrlField[] = "faviconUrl";
42 const char kDescriptionField[] = "description";
44 const char kGuestList[] = "guests";
46 const char kAdbModelField[] = "adbModel";
47 const char kAdbConnectedField[] = "adbConnected";
48 const char kAdbSerialField[] = "adbSerial";
49 const char kAdbBrowsersList[] = "browsers";
50 const char kAdbDeviceIdFormat[] = "device:%s";
52 const char kAdbBrowserNameField[] = "adbBrowserName";
53 const char kAdbBrowserUserField[] = "adbBrowserUser";
54 const char kAdbBrowserVersionField[] = "adbBrowserVersion";
55 const char kAdbBrowserChromeVersionField[] = "adbBrowserChromeVersion";
56 const char kAdbPagesList[] = "pages";
58 const char kAdbScreenWidthField[] = "adbScreenWidth";
59 const char kAdbScreenHeightField[] = "adbScreenHeight";
60 const char kAdbAttachedForeignField[] = "adbAttachedForeign";
62 const char kPortForwardingPorts[] = "ports";
63 const char kPortForwardingBrowserId[] = "browserId";
65 // CancelableTimer ------------------------------------------------------------
67 class CancelableTimer {
68 public:
69 CancelableTimer(base::Closure callback, base::TimeDelta delay)
70 : callback_(callback),
71 weak_factory_(this) {
72 base::MessageLoop::current()->PostDelayedTask(
73 FROM_HERE,
74 base::Bind(&CancelableTimer::Fire, weak_factory_.GetWeakPtr()),
75 delay);
78 private:
79 void Fire() { callback_.Run(); }
81 base::Closure callback_;
82 base::WeakPtrFactory<CancelableTimer> weak_factory_;
85 // WorkerObserver -------------------------------------------------------------
87 class WorkerObserver
88 : public content::WorkerServiceObserver,
89 public base::RefCountedThreadSafe<WorkerObserver> {
90 public:
91 WorkerObserver() {}
93 void Start(base::Closure callback) {
94 DCHECK(callback_.is_null());
95 DCHECK(!callback.is_null());
96 callback_ = callback;
97 BrowserThread::PostTask(
98 BrowserThread::IO, FROM_HERE,
99 base::Bind(&WorkerObserver::StartOnIOThread, this));
102 void Stop() {
103 DCHECK(!callback_.is_null());
104 callback_ = base::Closure();
105 BrowserThread::PostTask(
106 BrowserThread::IO, FROM_HERE,
107 base::Bind(&WorkerObserver::StopOnIOThread, this));
110 private:
111 friend class base::RefCountedThreadSafe<WorkerObserver>;
112 ~WorkerObserver() override {}
114 // content::WorkerServiceObserver overrides:
115 void WorkerCreated(const GURL& url,
116 const base::string16& name,
117 int process_id,
118 int route_id) override {
119 NotifyOnIOThread();
122 void WorkerDestroyed(int process_id, int route_id) override {
123 NotifyOnIOThread();
126 void StartOnIOThread() {
127 content::WorkerService::GetInstance()->AddObserver(this);
130 void StopOnIOThread() {
131 content::WorkerService::GetInstance()->RemoveObserver(this);
134 void NotifyOnIOThread() {
135 DCHECK_CURRENTLY_ON(BrowserThread::IO);
136 BrowserThread::PostTask(
137 BrowserThread::UI, FROM_HERE,
138 base::Bind(&WorkerObserver::NotifyOnUIThread, this));
141 void NotifyOnUIThread() {
142 DCHECK_CURRENTLY_ON(BrowserThread::UI);
143 if (callback_.is_null())
144 return;
145 callback_.Run();
148 // Accessed on UI thread.
149 base::Closure callback_;
152 // LocalTargetsUIHandler ---------------------------------------------
154 class LocalTargetsUIHandler
155 : public DevToolsTargetsUIHandler,
156 public content::NotificationObserver {
157 public:
158 explicit LocalTargetsUIHandler(const Callback& callback);
159 ~LocalTargetsUIHandler() override;
161 // DevToolsTargetsUIHandler overrides.
162 void ForceUpdate() override;
164 private:
165 // content::NotificationObserver overrides.
166 void Observe(int type,
167 const content::NotificationSource& source,
168 const content::NotificationDetails& details) override;
170 void ScheduleUpdate();
171 void UpdateTargets();
172 void SendTargets(const DevToolsTargetImpl::List& targets);
174 content::NotificationRegistrar notification_registrar_;
175 scoped_ptr<CancelableTimer> timer_;
176 scoped_refptr<WorkerObserver> observer_;
177 base::WeakPtrFactory<LocalTargetsUIHandler> weak_factory_;
180 LocalTargetsUIHandler::LocalTargetsUIHandler(
181 const Callback& callback)
182 : DevToolsTargetsUIHandler(kTargetSourceLocal, callback),
183 observer_(new WorkerObserver()),
184 weak_factory_(this) {
185 notification_registrar_.Add(this,
186 content::NOTIFICATION_WEB_CONTENTS_CONNECTED,
187 content::NotificationService::AllSources());
188 notification_registrar_.Add(this,
189 content::NOTIFICATION_WEB_CONTENTS_DISCONNECTED,
190 content::NotificationService::AllSources());
191 notification_registrar_.Add(this,
192 content::NOTIFICATION_WEB_CONTENTS_DESTROYED,
193 content::NotificationService::AllSources());
194 observer_->Start(base::Bind(&LocalTargetsUIHandler::ScheduleUpdate,
195 base::Unretained(this)));
196 UpdateTargets();
199 LocalTargetsUIHandler::~LocalTargetsUIHandler() {
200 notification_registrar_.RemoveAll();
201 observer_->Stop();
204 void LocalTargetsUIHandler::Observe(
205 int type,
206 const content::NotificationSource& source,
207 const content::NotificationDetails& details) {
208 ScheduleUpdate();
211 void LocalTargetsUIHandler::ForceUpdate() {
212 ScheduleUpdate();
215 void LocalTargetsUIHandler::ScheduleUpdate() {
216 const int kUpdateDelay = 100;
217 timer_.reset(
218 new CancelableTimer(
219 base::Bind(&LocalTargetsUIHandler::UpdateTargets,
220 base::Unretained(this)),
221 base::TimeDelta::FromMilliseconds(kUpdateDelay)));
224 void LocalTargetsUIHandler::UpdateTargets() {
225 DevToolsTargetImpl::EnumerateAllTargets(base::Bind(
226 &LocalTargetsUIHandler::SendTargets,
227 weak_factory_.GetWeakPtr()));
230 void LocalTargetsUIHandler::SendTargets(
231 const DevToolsTargetImpl::List& targets) {
232 base::ListValue list_value;
233 std::map<std::string, base::DictionaryValue*> id_to_descriptor;
235 STLDeleteValues(&targets_);
236 for (DevToolsTargetImpl::List::const_iterator it = targets.begin();
237 it != targets.end(); ++it) {
238 DevToolsTargetImpl* target = *it;
239 targets_[target->GetId()] = target;
240 id_to_descriptor[target->GetId()] = Serialize(*target);
243 for (TargetMap::iterator it(targets_.begin()); it != targets_.end(); ++it) {
244 DevToolsTargetImpl* target = it->second;
245 base::DictionaryValue* descriptor = id_to_descriptor[target->GetId()];
246 std::string parent_id = target->GetParentId();
247 if (parent_id.empty() || id_to_descriptor.count(parent_id) == 0) {
248 list_value.Append(descriptor);
249 } else {
250 base::DictionaryValue* parent = id_to_descriptor[parent_id];
251 base::ListValue* guests = NULL;
252 if (!parent->GetList(kGuestList, &guests)) {
253 guests = new base::ListValue();
254 parent->Set(kGuestList, guests);
256 guests->Append(descriptor);
260 SendSerializedTargets(list_value);
263 // AdbTargetsUIHandler --------------------------------------------------------
265 class AdbTargetsUIHandler
266 : public DevToolsTargetsUIHandler,
267 public DevToolsAndroidBridge::DeviceListListener {
268 public:
269 AdbTargetsUIHandler(const Callback& callback, Profile* profile);
270 ~AdbTargetsUIHandler() override;
272 void Open(const std::string& browser_id, const std::string& url) override;
274 scoped_refptr<content::DevToolsAgentHost> GetBrowserAgentHost(
275 const std::string& browser_id) override;
277 private:
278 // DevToolsAndroidBridge::Listener overrides.
279 void DeviceListChanged(
280 const DevToolsAndroidBridge::RemoteDevices& devices) override;
282 DevToolsAndroidBridge* GetAndroidBridge();
284 Profile* const profile_;
285 DevToolsAndroidBridge* const android_bridge_;
287 typedef std::map<std::string,
288 scoped_refptr<DevToolsAndroidBridge::RemoteBrowser> > RemoteBrowsers;
289 RemoteBrowsers remote_browsers_;
292 AdbTargetsUIHandler::AdbTargetsUIHandler(const Callback& callback,
293 Profile* profile)
294 : DevToolsTargetsUIHandler(kTargetSourceRemote, callback),
295 profile_(profile),
296 android_bridge_(
297 DevToolsAndroidBridge::Factory::GetForProfile(profile_)) {
298 DCHECK(android_bridge_);
299 android_bridge_->AddDeviceListListener(this);
302 AdbTargetsUIHandler::~AdbTargetsUIHandler() {
303 android_bridge_->RemoveDeviceListListener(this);
306 void AdbTargetsUIHandler::Open(const std::string& browser_id,
307 const std::string& url) {
308 RemoteBrowsers::iterator it = remote_browsers_.find(browser_id);
309 if (it != remote_browsers_.end())
310 android_bridge_->OpenRemotePage(it->second, url);
313 scoped_refptr<content::DevToolsAgentHost>
314 AdbTargetsUIHandler::GetBrowserAgentHost(
315 const std::string& browser_id) {
316 RemoteBrowsers::iterator it = remote_browsers_.find(browser_id);
317 if (it == remote_browsers_.end())
318 return NULL;
320 return android_bridge_->GetBrowserAgentHost(it->second);
323 void AdbTargetsUIHandler::DeviceListChanged(
324 const DevToolsAndroidBridge::RemoteDevices& devices) {
325 remote_browsers_.clear();
326 STLDeleteValues(&targets_);
328 base::ListValue device_list;
329 for (DevToolsAndroidBridge::RemoteDevices::const_iterator dit =
330 devices.begin(); dit != devices.end(); ++dit) {
331 DevToolsAndroidBridge::RemoteDevice* device = dit->get();
332 base::DictionaryValue* device_data = new base::DictionaryValue();
333 device_data->SetString(kAdbModelField, device->model());
334 device_data->SetString(kAdbSerialField, device->serial());
335 device_data->SetBoolean(kAdbConnectedField, device->is_connected());
336 std::string device_id = base::StringPrintf(
337 kAdbDeviceIdFormat,
338 device->serial().c_str());
339 device_data->SetString(kTargetIdField, device_id);
340 base::ListValue* browser_list = new base::ListValue();
341 device_data->Set(kAdbBrowsersList, browser_list);
343 DevToolsAndroidBridge::RemoteBrowsers& browsers = device->browsers();
344 for (DevToolsAndroidBridge::RemoteBrowsers::iterator bit =
345 browsers.begin(); bit != browsers.end(); ++bit) {
346 DevToolsAndroidBridge::RemoteBrowser* browser = bit->get();
347 base::DictionaryValue* browser_data = new base::DictionaryValue();
348 browser_data->SetString(kAdbBrowserNameField, browser->display_name());
349 browser_data->SetString(kAdbBrowserUserField, browser->user());
350 browser_data->SetString(kAdbBrowserVersionField, browser->version());
351 DevToolsAndroidBridge::RemoteBrowser::ParsedVersion parsed =
352 browser->GetParsedVersion();
353 browser_data->SetInteger(
354 kAdbBrowserChromeVersionField,
355 browser->IsChrome() && !parsed.empty() ? parsed[0] : 0);
356 std::string browser_id = browser->GetId();
357 browser_data->SetString(kTargetIdField, browser_id);
358 browser_data->SetString(kTargetSourceField, source_id());
360 base::ListValue* page_list = new base::ListValue();
361 remote_browsers_[browser_id] = browser;
362 browser_data->Set(kAdbPagesList, page_list);
363 for (const auto& page : browser->pages()) {
364 DevToolsTargetImpl* target = android_bridge_->CreatePageTarget(page);
365 base::DictionaryValue* target_data = Serialize(*target);
366 target_data->SetBoolean(
367 kAdbAttachedForeignField,
368 target->IsAttached() &&
369 !android_bridge_->HasDevToolsWindow(target->GetId()));
370 // Pass the screen size in the target object to make sure that
371 // the caching logic does not prevent the target item from updating
372 // when the screen size changes.
373 gfx::Size screen_size = device->screen_size();
374 target_data->SetInteger(kAdbScreenWidthField, screen_size.width());
375 target_data->SetInteger(kAdbScreenHeightField, screen_size.height());
376 targets_[target->GetId()] = target;
377 page_list->Append(target_data);
379 browser_list->Append(browser_data);
382 device_list.Append(device_data);
384 SendSerializedTargets(device_list);
387 } // namespace
389 // DevToolsTargetsUIHandler ---------------------------------------------------
391 DevToolsTargetsUIHandler::DevToolsTargetsUIHandler(
392 const std::string& source_id,
393 const Callback& callback)
394 : source_id_(source_id),
395 callback_(callback) {
398 DevToolsTargetsUIHandler::~DevToolsTargetsUIHandler() {
399 STLDeleteValues(&targets_);
402 // static
403 scoped_ptr<DevToolsTargetsUIHandler>
404 DevToolsTargetsUIHandler::CreateForLocal(
405 const DevToolsTargetsUIHandler::Callback& callback) {
406 return scoped_ptr<DevToolsTargetsUIHandler>(
407 new LocalTargetsUIHandler(callback));
410 // static
411 scoped_ptr<DevToolsTargetsUIHandler>
412 DevToolsTargetsUIHandler::CreateForAdb(
413 const DevToolsTargetsUIHandler::Callback& callback, Profile* profile) {
414 return scoped_ptr<DevToolsTargetsUIHandler>(
415 new AdbTargetsUIHandler(callback, profile));
418 DevToolsTargetImpl* DevToolsTargetsUIHandler::GetTarget(
419 const std::string& target_id) {
420 TargetMap::iterator it = targets_.find(target_id);
421 if (it != targets_.end())
422 return it->second;
423 return NULL;
426 void DevToolsTargetsUIHandler::Open(const std::string& browser_id,
427 const std::string& url) {
430 scoped_refptr<content::DevToolsAgentHost>
431 DevToolsTargetsUIHandler::GetBrowserAgentHost(const std::string& browser_id) {
432 return NULL;
435 base::DictionaryValue* DevToolsTargetsUIHandler::Serialize(
436 const DevToolsTargetImpl& target) {
437 base::DictionaryValue* target_data = new base::DictionaryValue();
438 target_data->SetString(kTargetSourceField, source_id_);
439 target_data->SetString(kTargetIdField, target.GetId());
440 target_data->SetString(kTargetTypeField, target.GetType());
441 target_data->SetBoolean(kAttachedField, target.IsAttached());
442 target_data->SetString(kUrlField, target.GetURL().spec());
443 target_data->SetString(kNameField, net::EscapeForHTML(target.GetTitle()));
444 target_data->SetString(kFaviconUrlField, target.GetFaviconURL().spec());
445 target_data->SetString(kDescriptionField, target.GetDescription());
446 return target_data;
449 void DevToolsTargetsUIHandler::SendSerializedTargets(
450 const base::ListValue& list) {
451 callback_.Run(source_id_, list);
454 void DevToolsTargetsUIHandler::ForceUpdate() {
457 // PortForwardingStatusSerializer ---------------------------------------------
459 PortForwardingStatusSerializer::PortForwardingStatusSerializer(
460 const Callback& callback, Profile* profile)
461 : callback_(callback),
462 profile_(profile) {
463 DevToolsAndroidBridge* android_bridge =
464 DevToolsAndroidBridge::Factory::GetForProfile(profile_);
465 if (android_bridge)
466 android_bridge->AddPortForwardingListener(this);
469 PortForwardingStatusSerializer::~PortForwardingStatusSerializer() {
470 DevToolsAndroidBridge* android_bridge =
471 DevToolsAndroidBridge::Factory::GetForProfile(profile_);
472 if (android_bridge)
473 android_bridge->RemovePortForwardingListener(this);
476 void PortForwardingStatusSerializer::PortStatusChanged(
477 const ForwardingStatus& status) {
478 base::DictionaryValue result;
479 for (ForwardingStatus::const_iterator sit = status.begin();
480 sit != status.end(); ++sit) {
481 base::DictionaryValue* port_status_dict = new base::DictionaryValue();
482 const PortStatusMap& port_status_map = sit->second;
483 for (PortStatusMap::const_iterator it = port_status_map.begin();
484 it != port_status_map.end(); ++it) {
485 port_status_dict->SetInteger(
486 base::StringPrintf("%d", it->first), it->second);
489 base::DictionaryValue* device_status_dict = new base::DictionaryValue();
490 device_status_dict->Set(kPortForwardingPorts, port_status_dict);
491 device_status_dict->SetString(kPortForwardingBrowserId,
492 sit->first->GetId());
494 std::string device_id = base::StringPrintf(
495 kAdbDeviceIdFormat,
496 sit->first->serial().c_str());
497 result.Set(device_id, device_status_dict);
499 callback_.Run(result);