[Cronet] Delay StartNetLog and StopNetLog until native request context is initialized
[chromium-blink-merge.git] / chrome / browser / devtools / devtools_targets_ui.cc
blobf5aa559c3a7da2c10e2862734dd31b8c9189021d
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 static void NoOp(scoped_refptr<DevToolsAndroidBridge::RemotePage> page) {
309 void AdbTargetsUIHandler::Open(const std::string& browser_id,
310 const std::string& url) {
311 RemoteBrowsers::iterator it = remote_browsers_.find(browser_id);
312 if (it == remote_browsers_.end())
313 return;
315 android_bridge_->OpenRemotePage(
316 it->second,
317 url,
318 base::Bind(&NoOp));
321 scoped_refptr<content::DevToolsAgentHost>
322 AdbTargetsUIHandler::GetBrowserAgentHost(
323 const std::string& browser_id) {
324 RemoteBrowsers::iterator it = remote_browsers_.find(browser_id);
325 if (it == remote_browsers_.end())
326 return NULL;
328 return android_bridge_->GetBrowserAgentHost(it->second);
331 void AdbTargetsUIHandler::DeviceListChanged(
332 const DevToolsAndroidBridge::RemoteDevices& devices) {
333 remote_browsers_.clear();
334 STLDeleteValues(&targets_);
336 base::ListValue device_list;
337 for (DevToolsAndroidBridge::RemoteDevices::const_iterator dit =
338 devices.begin(); dit != devices.end(); ++dit) {
339 DevToolsAndroidBridge::RemoteDevice* device = dit->get();
340 base::DictionaryValue* device_data = new base::DictionaryValue();
341 device_data->SetString(kAdbModelField, device->model());
342 device_data->SetString(kAdbSerialField, device->serial());
343 device_data->SetBoolean(kAdbConnectedField, device->is_connected());
344 std::string device_id = base::StringPrintf(
345 kAdbDeviceIdFormat,
346 device->serial().c_str());
347 device_data->SetString(kTargetIdField, device_id);
348 base::ListValue* browser_list = new base::ListValue();
349 device_data->Set(kAdbBrowsersList, browser_list);
351 DevToolsAndroidBridge::RemoteBrowsers& browsers = device->browsers();
352 for (DevToolsAndroidBridge::RemoteBrowsers::iterator bit =
353 browsers.begin(); bit != browsers.end(); ++bit) {
354 DevToolsAndroidBridge::RemoteBrowser* browser = bit->get();
355 base::DictionaryValue* browser_data = new base::DictionaryValue();
356 browser_data->SetString(kAdbBrowserNameField, browser->display_name());
357 browser_data->SetString(kAdbBrowserUserField, browser->user());
358 browser_data->SetString(kAdbBrowserVersionField, browser->version());
359 DevToolsAndroidBridge::RemoteBrowser::ParsedVersion parsed =
360 browser->GetParsedVersion();
361 browser_data->SetInteger(
362 kAdbBrowserChromeVersionField,
363 browser->IsChrome() && !parsed.empty() ? parsed[0] : 0);
364 std::string browser_id = browser->GetId();
365 browser_data->SetString(kTargetIdField, browser_id);
366 browser_data->SetString(kTargetSourceField, source_id());
368 base::ListValue* page_list = new base::ListValue();
369 remote_browsers_[browser_id] = browser;
370 browser_data->Set(kAdbPagesList, page_list);
371 for (const auto& page : browser->pages()) {
372 DevToolsTargetImpl* target = android_bridge_->CreatePageTarget(page);
373 base::DictionaryValue* target_data = Serialize(*target);
374 target_data->SetBoolean(
375 kAdbAttachedForeignField,
376 target->IsAttached() &&
377 !android_bridge_->HasDevToolsWindow(target->GetId()));
378 // Pass the screen size in the target object to make sure that
379 // the caching logic does not prevent the target item from updating
380 // when the screen size changes.
381 gfx::Size screen_size = device->screen_size();
382 target_data->SetInteger(kAdbScreenWidthField, screen_size.width());
383 target_data->SetInteger(kAdbScreenHeightField, screen_size.height());
384 targets_[target->GetId()] = target;
385 page_list->Append(target_data);
387 browser_list->Append(browser_data);
390 device_list.Append(device_data);
392 SendSerializedTargets(device_list);
395 } // namespace
397 // DevToolsTargetsUIHandler ---------------------------------------------------
399 DevToolsTargetsUIHandler::DevToolsTargetsUIHandler(
400 const std::string& source_id,
401 const Callback& callback)
402 : source_id_(source_id),
403 callback_(callback) {
406 DevToolsTargetsUIHandler::~DevToolsTargetsUIHandler() {
407 STLDeleteValues(&targets_);
410 // static
411 scoped_ptr<DevToolsTargetsUIHandler>
412 DevToolsTargetsUIHandler::CreateForLocal(
413 const DevToolsTargetsUIHandler::Callback& callback) {
414 return scoped_ptr<DevToolsTargetsUIHandler>(
415 new LocalTargetsUIHandler(callback));
418 // static
419 scoped_ptr<DevToolsTargetsUIHandler>
420 DevToolsTargetsUIHandler::CreateForAdb(
421 const DevToolsTargetsUIHandler::Callback& callback, Profile* profile) {
422 return scoped_ptr<DevToolsTargetsUIHandler>(
423 new AdbTargetsUIHandler(callback, profile));
426 DevToolsTargetImpl* DevToolsTargetsUIHandler::GetTarget(
427 const std::string& target_id) {
428 TargetMap::iterator it = targets_.find(target_id);
429 if (it != targets_.end())
430 return it->second;
431 return NULL;
434 void DevToolsTargetsUIHandler::Open(const std::string& browser_id,
435 const std::string& url) {
438 scoped_refptr<content::DevToolsAgentHost>
439 DevToolsTargetsUIHandler::GetBrowserAgentHost(const std::string& browser_id) {
440 return NULL;
443 base::DictionaryValue* DevToolsTargetsUIHandler::Serialize(
444 const DevToolsTargetImpl& target) {
445 base::DictionaryValue* target_data = new base::DictionaryValue();
446 target_data->SetString(kTargetSourceField, source_id_);
447 target_data->SetString(kTargetIdField, target.GetId());
448 target_data->SetString(kTargetTypeField, target.GetType());
449 target_data->SetBoolean(kAttachedField, target.IsAttached());
450 target_data->SetString(kUrlField, target.GetURL().spec());
451 target_data->SetString(kNameField, net::EscapeForHTML(target.GetTitle()));
452 target_data->SetString(kFaviconUrlField, target.GetFaviconURL().spec());
453 target_data->SetString(kDescriptionField, target.GetDescription());
454 return target_data;
457 void DevToolsTargetsUIHandler::SendSerializedTargets(
458 const base::ListValue& list) {
459 callback_.Run(source_id_, list);
462 void DevToolsTargetsUIHandler::ForceUpdate() {
465 // PortForwardingStatusSerializer ---------------------------------------------
467 PortForwardingStatusSerializer::PortForwardingStatusSerializer(
468 const Callback& callback, Profile* profile)
469 : callback_(callback),
470 profile_(profile) {
471 DevToolsAndroidBridge* android_bridge =
472 DevToolsAndroidBridge::Factory::GetForProfile(profile_);
473 if (android_bridge)
474 android_bridge->AddPortForwardingListener(this);
477 PortForwardingStatusSerializer::~PortForwardingStatusSerializer() {
478 DevToolsAndroidBridge* android_bridge =
479 DevToolsAndroidBridge::Factory::GetForProfile(profile_);
480 if (android_bridge)
481 android_bridge->RemovePortForwardingListener(this);
484 void PortForwardingStatusSerializer::PortStatusChanged(
485 const ForwardingStatus& status) {
486 base::DictionaryValue result;
487 for (ForwardingStatus::const_iterator sit = status.begin();
488 sit != status.end(); ++sit) {
489 base::DictionaryValue* port_status_dict = new base::DictionaryValue();
490 const PortStatusMap& port_status_map = sit->second;
491 for (PortStatusMap::const_iterator it = port_status_map.begin();
492 it != port_status_map.end(); ++it) {
493 port_status_dict->SetInteger(
494 base::StringPrintf("%d", it->first), it->second);
497 base::DictionaryValue* device_status_dict = new base::DictionaryValue();
498 device_status_dict->Set(kPortForwardingPorts, port_status_dict);
499 device_status_dict->SetString(kPortForwardingBrowserId,
500 sit->first->GetId());
502 std::string device_id = base::StringPrintf(
503 kAdbDeviceIdFormat,
504 sit->first->serial().c_str());
505 result.Set(device_id, device_status_dict);
507 callback_.Run(result);