Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / devtools / devtools_targets_ui.cc
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.
4
5 #include "chrome/browser/devtools/devtools_targets_ui.h"
6
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"
27
28 using content::BrowserThread;
29
30 namespace {
31
32 const char kTargetSourceField[]  = "source";
33 const char kTargetSourceLocal[]  = "local";
34 const char kTargetSourceRemote[]  = "remote";
35
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";
43
44 const char kGuestList[] = "guests";
45
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";
51
52 const char kAdbBrowserNameField[] = "adbBrowserName";
53 const char kAdbBrowserVersionField[] = "adbBrowserVersion";
54 const char kAdbBrowserChromeVersionField[] = "adbBrowserChromeVersion";
55 const char kCompatibleVersion[] = "compatibleVersion";
56 const char kAdbPagesList[] = "pages";
57
58 const char kAdbScreenWidthField[] = "adbScreenWidth";
59 const char kAdbScreenHeightField[] = "adbScreenHeight";
60 const char kAdbAttachedForeignField[]  = "adbAttachedForeign";
61
62 const char kPortForwardingPorts[] = "ports";
63 const char kPortForwardingBrowserId[] = "browserId";
64
65 std::string SerializeBrowserId(
66     scoped_refptr<DevToolsAndroidBridge::RemoteBrowser> browser) {
67   return base::StringPrintf(
68       "browser:%s:%s:%s:%s",
69       browser->serial().c_str(), // Ensure uniqueness across devices.
70       browser->display_name().c_str(),  // Sort by display name.
71       browser->version().c_str(),  // Then by version.
72       browser->socket().c_str());  // Ensure uniqueness on the device.
73 }
74
75 // CancelableTimer ------------------------------------------------------------
76
77 class CancelableTimer {
78  public:
79   CancelableTimer(base::Closure callback, base::TimeDelta delay)
80       : callback_(callback),
81         weak_factory_(this) {
82     base::MessageLoop::current()->PostDelayedTask(
83         FROM_HERE,
84         base::Bind(&CancelableTimer::Fire, weak_factory_.GetWeakPtr()),
85         delay);
86   }
87
88  private:
89   void Fire() { callback_.Run(); }
90
91   base::Closure callback_;
92   base::WeakPtrFactory<CancelableTimer> weak_factory_;
93 };
94
95 // WorkerObserver -------------------------------------------------------------
96
97 class WorkerObserver
98     : public content::WorkerServiceObserver,
99       public base::RefCountedThreadSafe<WorkerObserver> {
100  public:
101   WorkerObserver() {}
102
103   void Start(base::Closure callback) {
104     DCHECK(callback_.is_null());
105     DCHECK(!callback.is_null());
106     callback_ = callback;
107     BrowserThread::PostTask(
108         BrowserThread::IO, FROM_HERE,
109         base::Bind(&WorkerObserver::StartOnIOThread, this));
110   }
111
112   void Stop() {
113     DCHECK(!callback_.is_null());
114     callback_ = base::Closure();
115     BrowserThread::PostTask(
116         BrowserThread::IO, FROM_HERE,
117         base::Bind(&WorkerObserver::StopOnIOThread, this));
118   }
119
120  private:
121   friend class base::RefCountedThreadSafe<WorkerObserver>;
122   ~WorkerObserver() override {}
123
124   // content::WorkerServiceObserver overrides:
125   void WorkerCreated(const GURL& url,
126                      const base::string16& name,
127                      int process_id,
128                      int route_id) override {
129     NotifyOnIOThread();
130   }
131
132   void WorkerDestroyed(int process_id, int route_id) override {
133     NotifyOnIOThread();
134   }
135
136   void StartOnIOThread() {
137     content::WorkerService::GetInstance()->AddObserver(this);
138   }
139
140   void StopOnIOThread() {
141     content::WorkerService::GetInstance()->RemoveObserver(this);
142   }
143
144   void NotifyOnIOThread() {
145     DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
146     BrowserThread::PostTask(
147         BrowserThread::UI, FROM_HERE,
148         base::Bind(&WorkerObserver::NotifyOnUIThread, this));
149   }
150
151   void NotifyOnUIThread() {
152     DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
153     if (callback_.is_null())
154       return;
155     callback_.Run();
156   }
157
158   // Accessed on UI thread.
159   base::Closure callback_;
160 };
161
162 // LocalTargetsUIHandler ---------------------------------------------
163
164 class LocalTargetsUIHandler
165     : public DevToolsTargetsUIHandler,
166       public content::NotificationObserver {
167  public:
168   explicit LocalTargetsUIHandler(const Callback& callback);
169   ~LocalTargetsUIHandler() override;
170
171   // DevToolsTargetsUIHandler overrides.
172   void ForceUpdate() override;
173
174 private:
175   // content::NotificationObserver overrides.
176  void Observe(int type,
177               const content::NotificationSource& source,
178               const content::NotificationDetails& details) override;
179
180   void ScheduleUpdate();
181   void UpdateTargets();
182   void SendTargets(const DevToolsTargetImpl::List& targets);
183
184   content::NotificationRegistrar notification_registrar_;
185   scoped_ptr<CancelableTimer> timer_;
186   scoped_refptr<WorkerObserver> observer_;
187   base::WeakPtrFactory<LocalTargetsUIHandler> weak_factory_;
188 };
189
190 LocalTargetsUIHandler::LocalTargetsUIHandler(
191     const Callback& callback)
192     : DevToolsTargetsUIHandler(kTargetSourceLocal, callback),
193       observer_(new WorkerObserver()),
194       weak_factory_(this) {
195   notification_registrar_.Add(this,
196                               content::NOTIFICATION_WEB_CONTENTS_CONNECTED,
197                               content::NotificationService::AllSources());
198   notification_registrar_.Add(this,
199                               content::NOTIFICATION_WEB_CONTENTS_DISCONNECTED,
200                               content::NotificationService::AllSources());
201   notification_registrar_.Add(this,
202                               content::NOTIFICATION_WEB_CONTENTS_DESTROYED,
203                               content::NotificationService::AllSources());
204   observer_->Start(base::Bind(&LocalTargetsUIHandler::ScheduleUpdate,
205                               base::Unretained(this)));
206   UpdateTargets();
207 }
208
209 LocalTargetsUIHandler::~LocalTargetsUIHandler() {
210   notification_registrar_.RemoveAll();
211   observer_->Stop();
212 }
213
214 void LocalTargetsUIHandler::Observe(
215     int type,
216     const content::NotificationSource& source,
217     const content::NotificationDetails& details) {
218   ScheduleUpdate();
219 }
220
221 void LocalTargetsUIHandler::ForceUpdate() {
222   ScheduleUpdate();
223 }
224
225 void LocalTargetsUIHandler::ScheduleUpdate() {
226   const int kUpdateDelay = 100;
227   timer_.reset(
228       new CancelableTimer(
229           base::Bind(&LocalTargetsUIHandler::UpdateTargets,
230                      base::Unretained(this)),
231           base::TimeDelta::FromMilliseconds(kUpdateDelay)));
232 }
233
234 void LocalTargetsUIHandler::UpdateTargets() {
235   DevToolsTargetImpl::EnumerateAllTargets(base::Bind(
236       &LocalTargetsUIHandler::SendTargets,
237       weak_factory_.GetWeakPtr()));
238 }
239
240 void LocalTargetsUIHandler::SendTargets(
241     const DevToolsTargetImpl::List& targets) {
242   base::ListValue list_value;
243   std::map<std::string, base::DictionaryValue*> id_to_descriptor;
244
245   STLDeleteValues(&targets_);
246   for (DevToolsTargetImpl::List::const_iterator it = targets.begin();
247       it != targets.end(); ++it) {
248     DevToolsTargetImpl* target = *it;
249     targets_[target->GetId()] = target;
250     id_to_descriptor[target->GetId()] = Serialize(*target);
251   }
252
253   for (TargetMap::iterator it(targets_.begin()); it != targets_.end(); ++it) {
254     DevToolsTargetImpl* target = it->second;
255     base::DictionaryValue* descriptor = id_to_descriptor[target->GetId()];
256     std::string parent_id = target->GetParentId();
257     if (parent_id.empty() || id_to_descriptor.count(parent_id) == 0) {
258       list_value.Append(descriptor);
259     } else {
260       base::DictionaryValue* parent = id_to_descriptor[parent_id];
261       base::ListValue* guests = NULL;
262       if (!parent->GetList(kGuestList, &guests)) {
263         guests = new base::ListValue();
264         parent->Set(kGuestList, guests);
265       }
266       guests->Append(descriptor);
267     }
268   }
269
270   SendSerializedTargets(list_value);
271 }
272
273 // AdbTargetsUIHandler --------------------------------------------------------
274
275 class AdbTargetsUIHandler
276     : public DevToolsTargetsUIHandler,
277       public DevToolsAndroidBridge::DeviceListListener {
278  public:
279   AdbTargetsUIHandler(const Callback& callback, Profile* profile);
280   ~AdbTargetsUIHandler() override;
281
282   void Open(const std::string& browser_id,
283             const std::string& url,
284             const DevToolsTargetsUIHandler::TargetCallback&) override;
285
286   scoped_refptr<content::DevToolsAgentHost> GetBrowserAgentHost(
287       const std::string& browser_id) override;
288
289  private:
290   // DevToolsAndroidBridge::Listener overrides.
291   void DeviceListChanged(
292       const DevToolsAndroidBridge::RemoteDevices& devices) override;
293
294   DevToolsAndroidBridge* GetAndroidBridge();
295
296   Profile* profile_;
297   scoped_refptr<DevToolsAndroidBridge> android_bridge_;
298
299   typedef std::map<std::string,
300       scoped_refptr<DevToolsAndroidBridge::RemoteBrowser> > RemoteBrowsers;
301   RemoteBrowsers remote_browsers_;
302 };
303
304 AdbTargetsUIHandler::AdbTargetsUIHandler(const Callback& callback,
305                                          Profile* profile)
306     : DevToolsTargetsUIHandler(kTargetSourceRemote, callback),
307       profile_(profile),
308       android_bridge_(
309           DevToolsAndroidBridge::Factory::GetForProfile(profile_)) {
310   DCHECK(android_bridge_.get());
311   android_bridge_->AddDeviceListListener(this);
312 }
313
314 AdbTargetsUIHandler::~AdbTargetsUIHandler() {
315   android_bridge_->RemoveDeviceListListener(this);
316 }
317
318 static void CallOnTarget(
319     const DevToolsTargetsUIHandler::TargetCallback& callback,
320     scoped_refptr<DevToolsAndroidBridge> bridge,
321     scoped_refptr<DevToolsAndroidBridge::RemotePage> page) {
322   callback.Run(page.get() ? bridge->CreatePageTarget(page) : nullptr);
323 }
324
325 void AdbTargetsUIHandler::Open(
326     const std::string& browser_id,
327     const std::string& url,
328     const DevToolsTargetsUIHandler::TargetCallback& callback) {
329   RemoteBrowsers::iterator it = remote_browsers_.find(browser_id);
330   if (it == remote_browsers_.end())
331     return;
332
333   android_bridge_->OpenRemotePage(
334       it->second,
335       url,
336       base::Bind(&CallOnTarget, callback, android_bridge_));
337 }
338
339 scoped_refptr<content::DevToolsAgentHost>
340 AdbTargetsUIHandler::GetBrowserAgentHost(
341     const std::string& browser_id) {
342   RemoteBrowsers::iterator it = remote_browsers_.find(browser_id);
343   if (it == remote_browsers_.end())
344     return NULL;
345
346   return android_bridge_->GetBrowserAgentHost(it->second);
347 }
348
349 void AdbTargetsUIHandler::DeviceListChanged(
350     const DevToolsAndroidBridge::RemoteDevices& devices) {
351   remote_browsers_.clear();
352   STLDeleteValues(&targets_);
353
354   base::ListValue device_list;
355   for (DevToolsAndroidBridge::RemoteDevices::const_iterator dit =
356       devices.begin(); dit != devices.end(); ++dit) {
357     DevToolsAndroidBridge::RemoteDevice* device = dit->get();
358     base::DictionaryValue* device_data = new base::DictionaryValue();
359     device_data->SetString(kAdbModelField, device->model());
360     device_data->SetString(kAdbSerialField, device->serial());
361     device_data->SetBoolean(kAdbConnectedField, device->is_connected());
362     std::string device_id = base::StringPrintf(
363         kAdbDeviceIdFormat,
364         device->serial().c_str());
365     device_data->SetString(kTargetIdField, device_id);
366     base::ListValue* browser_list = new base::ListValue();
367     device_data->Set(kAdbBrowsersList, browser_list);
368
369     DevToolsAndroidBridge::RemoteBrowsers& browsers = device->browsers();
370     for (DevToolsAndroidBridge::RemoteBrowsers::iterator bit =
371         browsers.begin(); bit != browsers.end(); ++bit) {
372       DevToolsAndroidBridge::RemoteBrowser* browser = bit->get();
373       base::DictionaryValue* browser_data = new base::DictionaryValue();
374       browser_data->SetString(kAdbBrowserNameField, browser->display_name());
375       browser_data->SetString(kAdbBrowserVersionField, browser->version());
376       DevToolsAndroidBridge::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 = SerializeBrowserId(browser);
382       browser_data->SetString(kTargetIdField, browser_id);
383       browser_data->SetString(kTargetSourceField, source_id());
384
385       base::Version remote_version;
386       remote_version = base::Version(browser->version());
387
388       chrome::VersionInfo version_info;
389       base::Version local_version(version_info.Version());
390
391       browser_data->SetBoolean(kCompatibleVersion,
392           (!remote_version.IsValid()) || (!local_version.IsValid()) ||
393           remote_version.components()[0] <= local_version.components()[0]);
394
395       base::ListValue* page_list = new base::ListValue();
396       remote_browsers_[browser_id] = browser;
397             browser_data->Set(kAdbPagesList, page_list);
398       for (const auto& page : browser->pages()) {
399         DevToolsTargetImpl* target = android_bridge_->CreatePageTarget(page);
400         base::DictionaryValue* target_data = Serialize(*target);
401         target_data->SetBoolean(
402             kAdbAttachedForeignField,
403             target->IsAttached() &&
404                 !android_bridge_->HasDevToolsWindow(target->GetId()));
405         // Pass the screen size in the target object to make sure that
406         // the caching logic does not prevent the target item from updating
407         // when the screen size changes.
408         gfx::Size screen_size = device->screen_size();
409         target_data->SetInteger(kAdbScreenWidthField, screen_size.width());
410         target_data->SetInteger(kAdbScreenHeightField, screen_size.height());
411         targets_[target->GetId()] = target;
412         page_list->Append(target_data);
413       }
414       browser_list->Append(browser_data);
415     }
416
417     device_list.Append(device_data);
418   }
419   SendSerializedTargets(device_list);
420 }
421
422 } // namespace
423
424 // DevToolsTargetsUIHandler ---------------------------------------------------
425
426 DevToolsTargetsUIHandler::DevToolsTargetsUIHandler(
427     const std::string& source_id,
428     const Callback& callback)
429     : source_id_(source_id),
430       callback_(callback) {
431 }
432
433 DevToolsTargetsUIHandler::~DevToolsTargetsUIHandler() {
434   STLDeleteValues(&targets_);
435 }
436
437 // static
438 scoped_ptr<DevToolsTargetsUIHandler>
439 DevToolsTargetsUIHandler::CreateForLocal(
440     const DevToolsTargetsUIHandler::Callback& callback) {
441   return scoped_ptr<DevToolsTargetsUIHandler>(
442       new LocalTargetsUIHandler(callback));
443 }
444
445 // static
446 scoped_ptr<DevToolsTargetsUIHandler>
447 DevToolsTargetsUIHandler::CreateForAdb(
448     const DevToolsTargetsUIHandler::Callback& callback, Profile* profile) {
449   return scoped_ptr<DevToolsTargetsUIHandler>(
450       new AdbTargetsUIHandler(callback, profile));
451 }
452
453 DevToolsTargetImpl* DevToolsTargetsUIHandler::GetTarget(
454     const std::string& target_id) {
455   TargetMap::iterator it = targets_.find(target_id);
456   if (it != targets_.end())
457     return it->second;
458   return NULL;
459 }
460
461 void DevToolsTargetsUIHandler::Open(const std::string& browser_id,
462                                     const std::string& url,
463                                     const TargetCallback& callback) {
464   callback.Run(NULL);
465 }
466
467 scoped_refptr<content::DevToolsAgentHost>
468 DevToolsTargetsUIHandler::GetBrowserAgentHost(const std::string& browser_id) {
469   return NULL;
470 }
471
472 base::DictionaryValue* DevToolsTargetsUIHandler::Serialize(
473     const DevToolsTargetImpl& target) {
474   base::DictionaryValue* target_data = new base::DictionaryValue();
475   target_data->SetString(kTargetSourceField, source_id_);
476   target_data->SetString(kTargetIdField, target.GetId());
477   target_data->SetString(kTargetTypeField, target.GetType());
478   target_data->SetBoolean(kAttachedField, target.IsAttached());
479   target_data->SetString(kUrlField, target.GetURL().spec());
480   target_data->SetString(kNameField, net::EscapeForHTML(target.GetTitle()));
481   target_data->SetString(kFaviconUrlField, target.GetFaviconURL().spec());
482   target_data->SetString(kDescriptionField, target.GetDescription());
483   return target_data;
484 }
485
486 void DevToolsTargetsUIHandler::SendSerializedTargets(
487     const base::ListValue& list) {
488   callback_.Run(source_id_, list);
489 }
490
491 void DevToolsTargetsUIHandler::ForceUpdate() {
492 }
493
494 // PortForwardingStatusSerializer ---------------------------------------------
495
496 PortForwardingStatusSerializer::PortForwardingStatusSerializer(
497     const Callback& callback, Profile* profile)
498       : callback_(callback),
499         profile_(profile) {
500   DevToolsAndroidBridge* android_bridge =
501       DevToolsAndroidBridge::Factory::GetForProfile(profile_);
502   if (android_bridge)
503     android_bridge->AddPortForwardingListener(this);
504 }
505
506 PortForwardingStatusSerializer::~PortForwardingStatusSerializer() {
507   DevToolsAndroidBridge* android_bridge =
508       DevToolsAndroidBridge::Factory::GetForProfile(profile_);
509   if (android_bridge)
510     android_bridge->RemovePortForwardingListener(this);
511 }
512
513 void PortForwardingStatusSerializer::PortStatusChanged(
514     const ForwardingStatus& status) {
515   base::DictionaryValue result;
516   for (ForwardingStatus::const_iterator sit = status.begin();
517       sit != status.end(); ++sit) {
518     base::DictionaryValue* port_status_dict = new base::DictionaryValue();
519     const PortStatusMap& port_status_map = sit->second;
520     for (PortStatusMap::const_iterator it = port_status_map.begin();
521          it != port_status_map.end(); ++it) {
522       port_status_dict->SetInteger(
523           base::StringPrintf("%d", it->first), it->second);
524     }
525
526     base::DictionaryValue* device_status_dict = new base::DictionaryValue();
527     device_status_dict->Set(kPortForwardingPorts, port_status_dict);
528     device_status_dict->SetString(kPortForwardingBrowserId,
529                                   SerializeBrowserId(sit->first));
530
531     std::string device_id = base::StringPrintf(
532         kAdbDeviceIdFormat,
533         sit->first->serial().c_str());
534     result.Set(device_id, device_status_dict);
535   }
536   callback_.Run(result);
537 }