- add sources.
[platform/framework/web/crosswalk.git] / src / chrome / browser / devtools / devtools_adb_bridge.cc
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_adb_bridge.h"
6
7 #include <map>
8 #include <vector>
9
10 #include "base/base64.h"
11 #include "base/bind.h"
12 #include "base/command_line.h"
13 #include "base/compiler_specific.h"
14 #include "base/json/json_reader.h"
15 #include "base/lazy_instance.h"
16 #include "base/logging.h"
17 #include "base/memory/singleton.h"
18 #include "base/message_loop/message_loop.h"
19 #include "base/strings/string_number_conversions.h"
20 #include "base/strings/string_util.h"
21 #include "base/strings/stringprintf.h"
22 #include "base/strings/utf_string_conversions.h"
23 #include "base/threading/thread.h"
24 #include "base/values.h"
25 #include "chrome/browser/devtools/adb/android_rsa.h"
26 #include "chrome/browser/devtools/adb_client_socket.h"
27 #include "chrome/browser/devtools/adb_web_socket.h"
28 #include "chrome/browser/devtools/devtools_protocol.h"
29 #include "chrome/browser/devtools/devtools_target_impl.h"
30 #include "chrome/browser/devtools/devtools_window.h"
31 #include "chrome/browser/profiles/profile.h"
32 #include "components/browser_context_keyed_service/browser_context_dependency_manager.h"
33 #include "content/public/browser/devtools_agent_host.h"
34 #include "content/public/browser/devtools_client_host.h"
35 #include "content/public/browser/devtools_external_agent_proxy.h"
36 #include "content/public/browser/devtools_external_agent_proxy_delegate.h"
37 #include "content/public/browser/devtools_manager.h"
38 #include "crypto/rsa_private_key.h"
39 #include "net/base/escape.h"
40 #include "net/base/net_errors.h"
41
42 using content::BrowserThread;
43
44 namespace {
45
46 const char kDeviceModelCommand[] = "shell:getprop ro.product.model";
47 const char kOpenedUnixSocketsCommand[] = "shell:cat /proc/net/unix";
48 const char kListProcessesCommand[] = "shell:ps";
49 const char kDumpsysCommand[] = "shell:dumpsys window policy";
50 const char kDumpsysScreenSizePrefix[] = "mStable=";
51
52 const char kUnknownModel[] = "Offline";
53
54 const char kPageListRequest[] = "GET /json HTTP/1.1\r\n\r\n";
55 const char kVersionRequest[] = "GET /json/version HTTP/1.1\r\n\r\n";
56 const char kClosePageRequest[] = "GET /json/close/%s HTTP/1.1\r\n\r\n";
57 const char kNewPageRequest[] = "GET /json/new HTTP/1.1\r\n\r\n";
58 const char kNewPageRequestWithURL[] = "GET /json/new?%s HTTP/1.1\r\n\r\n";
59 const char kActivatePageRequest[] =
60     "GET /json/activate/%s HTTP/1.1\r\n\r\n";
61 const int kAdbPollingIntervalMs = 1000;
62
63 const char kUrlParam[] = "url";
64 const char kPageReloadCommand[] = "Page.reload";
65 const char kPageNavigateCommand[] = "Page.navigate";
66
67 const char kChromeProductName[] = "Chrome";
68 const int kMinVersionNewWithURL = 32;
69 const int kNewPageNavigateDelayMs = 500;
70
71 #if defined(DEBUG_DEVTOOLS)
72 const char kLocalChrome[] = "Local Chrome";
73 #endif  // defined(DEBUG_DEVTOOLS)
74
75 typedef DevToolsAdbBridge::Callback Callback;
76 typedef std::vector<scoped_refptr<AndroidDevice> >
77     AndroidDevices;
78 typedef base::Callback<void(const AndroidDevices&)> AndroidDevicesCallback;
79
80 // AdbPagesCommand ------------------------------------------------------------
81
82 class AdbPagesCommand : public base::RefCountedThreadSafe<
83     AdbPagesCommand,
84     BrowserThread::DeleteOnUIThread> {
85  public:
86   typedef base::Callback<void(DevToolsAdbBridge::RemoteDevices*)> Callback;
87
88   AdbPagesCommand(
89       scoped_refptr<RefCountedAdbThread> adb_thread,
90       const DevToolsAdbBridge::DeviceProviders& device_providers,
91       const Callback& callback);
92
93  private:
94   friend struct BrowserThread::DeleteOnThread<
95       BrowserThread::UI>;
96   friend class base::DeleteHelper<AdbPagesCommand>;
97
98   virtual ~AdbPagesCommand();
99   void ProcessDeviceProviders();
100   void ReceivedDevices(const AndroidDevices& devices);
101
102   void ProcessSerials();
103   void ReceivedModel(int result, const std::string& response);
104   void ReceivedSockets(int result, const std::string& response);
105   void ReceivedDumpsys(int result, const std::string& response);
106   void ReceivedProcesses(int result, const std::string& response);
107   void ProcessSockets();
108   void ReceivedVersion(int result, const std::string& response);
109   void ReceivedPages(int result, const std::string& response);
110   void Respond();
111   void ParseSocketsList(const std::string& response);
112   void ParseProcessList(const std::string& response);
113   void ParseDumpsysResponse(const std::string& response);
114   void ParseScreenSize(const std::string& str);
115
116   scoped_refptr<RefCountedAdbThread> adb_thread_;
117   Callback callback_;
118   AndroidDevices devices_;
119   DevToolsAdbBridge::RemoteBrowsers browsers_;
120   scoped_ptr<DevToolsAdbBridge::RemoteDevices> remote_devices_;
121   DevToolsAdbBridge::DeviceProviders device_providers_;
122 };
123
124 AdbPagesCommand::AdbPagesCommand(
125     scoped_refptr<RefCountedAdbThread> adb_thread,
126     const DevToolsAdbBridge::DeviceProviders& device_providers,
127     const Callback& callback)
128     : adb_thread_(adb_thread),
129       callback_(callback),
130       device_providers_(device_providers){
131   remote_devices_.reset(new DevToolsAdbBridge::RemoteDevices());
132
133   ProcessDeviceProviders();
134 }
135
136 AdbPagesCommand::~AdbPagesCommand() {
137   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
138 }
139
140 void AdbPagesCommand::ProcessDeviceProviders() {
141   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
142   if (device_providers_.empty()) {
143     adb_thread_->message_loop()->PostTask(
144               FROM_HERE, base::Bind(&AdbPagesCommand::ProcessSerials, this));
145     return;
146   }
147
148   const scoped_refptr<AndroidDeviceProvider>& device_provider =
149       device_providers_.back();
150
151   device_provider->QueryDevices(
152       base::Bind(&AdbPagesCommand::ReceivedDevices, this));
153 }
154
155 void AdbPagesCommand::ReceivedDevices(const AndroidDevices& devices) {
156   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
157   DCHECK(!device_providers_.empty());
158   device_providers_.pop_back();
159
160   devices_.insert(devices_.end(), devices.begin(), devices.end());
161
162   if (!device_providers_.empty()) {
163     ProcessDeviceProviders();
164   } else {
165     adb_thread_->message_loop()->PostTask(
166           FROM_HERE, base::Bind(&AdbPagesCommand::ProcessSerials, this));
167   }
168 }
169
170 void AdbPagesCommand::ProcessSerials() {
171   DCHECK_EQ(adb_thread_->message_loop(), base::MessageLoop::current());
172   if (devices_.size() == 0) {
173     BrowserThread::PostTask(
174         BrowserThread::UI, FROM_HERE,
175         base::Bind(&AdbPagesCommand::Respond, this));
176     return;
177   }
178
179 #if defined(DEBUG_DEVTOOLS)
180   // For desktop remote debugging.
181   if (devices_.back()->serial().empty()) {
182     scoped_refptr<AndroidDevice> device =
183         devices_.back();
184     device->set_model(kLocalChrome);
185     remote_devices_->push_back(
186         new DevToolsAdbBridge::RemoteDevice(device));
187     scoped_refptr<DevToolsAdbBridge::RemoteBrowser> remote_browser =
188         new DevToolsAdbBridge::RemoteBrowser(
189             adb_thread_, device, std::string());
190     remote_browser->set_product(kChromeProductName);
191     remote_devices_->back()->AddBrowser(remote_browser);
192     browsers_.push_back(remote_browser);
193     device->HttpQuery(
194         std::string(), kVersionRequest,
195         base::Bind(&AdbPagesCommand::ReceivedVersion, this));
196     return;
197   }
198 #endif  // defined(DEBUG_DEVTOOLS)
199
200   scoped_refptr<AndroidDevice> device = devices_.back();
201   if (device->is_connected()) {
202     device->RunCommand(kDeviceModelCommand,
203                        base::Bind(&AdbPagesCommand::ReceivedModel, this));
204   } else {
205     device->set_model(kUnknownModel);
206     remote_devices_->push_back(new DevToolsAdbBridge::RemoteDevice(device));
207     devices_.pop_back();
208     ProcessSerials();
209   }
210 }
211
212 void AdbPagesCommand::ReceivedModel(int result, const std::string& response) {
213   DCHECK_EQ(adb_thread_->message_loop(), base::MessageLoop::current());
214   if (result < 0) {
215     devices_.pop_back();
216     ProcessSerials();
217     return;
218   }
219   scoped_refptr<AndroidDevice> device = devices_.back();
220   device->set_model(response);
221   remote_devices_->push_back(
222       new DevToolsAdbBridge::RemoteDevice(device));
223   device->RunCommand(kOpenedUnixSocketsCommand,
224                      base::Bind(&AdbPagesCommand::ReceivedSockets, this));
225 }
226
227 void AdbPagesCommand::ReceivedSockets(int result,
228                                       const std::string& response) {
229   DCHECK_EQ(adb_thread_->message_loop(), base::MessageLoop::current());
230   if (result < 0) {
231     devices_.pop_back();
232     ProcessSerials();
233     return;
234   }
235
236   ParseSocketsList(response);
237   scoped_refptr<AndroidDevice> device = devices_.back();
238   device->RunCommand(kDumpsysCommand,
239                      base::Bind(&AdbPagesCommand::ReceivedDumpsys, this));
240 }
241
242 void AdbPagesCommand::ReceivedDumpsys(int result,
243                                       const std::string& response) {
244   DCHECK_EQ(adb_thread_->message_loop(), base::MessageLoop::current());
245   if (result >= 0)
246     ParseDumpsysResponse(response);
247
248   scoped_refptr<AndroidDevice> device = devices_.back();
249   device->RunCommand(kListProcessesCommand,
250                      base::Bind(&AdbPagesCommand::ReceivedProcesses, this));
251 }
252
253 void AdbPagesCommand::ReceivedProcesses(int result,
254                                         const std::string& response) {
255   if (result >= 0)
256     ParseProcessList(response);
257
258   if (browsers_.size() == 0) {
259     devices_.pop_back();
260     ProcessSerials();
261   } else {
262     ProcessSockets();
263   }
264 }
265
266 void AdbPagesCommand::ProcessSockets() {
267   DCHECK_EQ(adb_thread_->message_loop(), base::MessageLoop::current());
268   if (browsers_.size() == 0) {
269     devices_.pop_back();
270     ProcessSerials();
271   } else {
272     scoped_refptr<AndroidDevice> device = devices_.back();
273     device->HttpQuery(browsers_.back()->socket(), kVersionRequest,
274                       base::Bind(&AdbPagesCommand::ReceivedVersion, this));
275   }
276 }
277
278 void AdbPagesCommand::ReceivedVersion(int result,
279                      const std::string& response) {
280   DCHECK_EQ(adb_thread_->message_loop(), base::MessageLoop::current());
281   if (result < 0) {
282     browsers_.pop_back();
283     ProcessSockets();
284     return;
285   }
286
287   // Parse version, append to package name if available,
288   scoped_ptr<base::Value> value(base::JSONReader::Read(response));
289   base::DictionaryValue* dict;
290   if (value && value->GetAsDictionary(&dict)) {
291     std::string browser;
292     if (dict->GetString("Browser", &browser)) {
293       std::vector<std::string> parts;
294       Tokenize(browser, "/", &parts);
295       if (parts.size() == 2) {
296         if (parts[0] != "Version")  // WebView has this for legacy reasons.
297           browsers_.back()->set_product(parts[0]);
298         browsers_.back()->set_version(parts[1]);
299       } else {
300         browsers_.back()->set_version(browser);
301       }
302     }
303   }
304
305   scoped_refptr<AndroidDevice> device = devices_.back();
306   device->HttpQuery(browsers_.back()->socket(), kPageListRequest,
307                     base::Bind(&AdbPagesCommand::ReceivedPages, this));
308 }
309
310 void AdbPagesCommand::ReceivedPages(int result,
311                    const std::string& response) {
312   DCHECK_EQ(adb_thread_->message_loop(), base::MessageLoop::current());
313   scoped_refptr<DevToolsAdbBridge::RemoteBrowser> browser = browsers_.back();
314   browsers_.pop_back();
315   if (result < 0) {
316     ProcessSockets();
317     return;
318   }
319
320   scoped_ptr<base::Value> value(base::JSONReader::Read(response));
321   base::ListValue* list_value;
322   if (value && value->GetAsList(&list_value)) {
323     browser->SetPageDescriptors(*list_value);
324   }
325   ProcessSockets();
326 }
327
328 void AdbPagesCommand::Respond() {
329   callback_.Run(remote_devices_.release());
330 }
331
332 void AdbPagesCommand::ParseSocketsList(const std::string& response) {
333   // On Android, '/proc/net/unix' looks like this:
334   //
335   // Num       RefCount Protocol Flags    Type St Inode Path
336   // 00000000: 00000002 00000000 00010000 0001 01 331813 /dev/socket/zygote
337   // 00000000: 00000002 00000000 00010000 0001 01 358606 @xxx_devtools_remote
338   // 00000000: 00000002 00000000 00010000 0001 01 347300 @yyy_devtools_remote
339   //
340   // We need to find records with paths starting from '@' (abstract socket)
341   // and containing "devtools_remote". We have to extract the inode number
342   // in order to find the owning process name.
343
344   scoped_refptr<DevToolsAdbBridge::RemoteDevice> remote_device =
345       remote_devices_->back();
346
347   std::vector<std::string> entries;
348   Tokenize(response, "\n", &entries);
349   const std::string channel_pattern =
350       base::StringPrintf(kDevToolsChannelNameFormat, "");
351   for (size_t i = 1; i < entries.size(); ++i) {
352     std::vector<std::string> fields;
353     Tokenize(entries[i], " \r", &fields);
354     if (fields.size() < 8)
355       continue;
356     if (fields[3] != "00010000" || fields[5] != "01")
357       continue;
358     std::string path_field = fields[7];
359     if (path_field.size() < 1 || path_field[0] != '@')
360       continue;
361     size_t socket_name_pos = path_field.find(channel_pattern);
362     if (socket_name_pos == std::string::npos)
363       continue;
364
365     std::string socket = path_field.substr(1);
366     scoped_refptr<DevToolsAdbBridge::RemoteBrowser> remote_browser =
367         new DevToolsAdbBridge::RemoteBrowser(
368             adb_thread_, remote_device->device(), socket);
369
370     std::string product = path_field.substr(1, socket_name_pos - 1);
371     product[0] = base::ToUpperASCII(product[0]);
372     remote_browser->set_product(product);
373
374     size_t socket_name_end = socket_name_pos + channel_pattern.size();
375     if (socket_name_end < path_field.size() &&
376         path_field[socket_name_end] == '_') {
377       remote_browser->set_pid(path_field.substr(socket_name_end + 1));
378     }
379     remote_device->AddBrowser(remote_browser);
380   }
381   browsers_ = remote_device->browsers();
382 }
383
384 void AdbPagesCommand::ParseProcessList(const std::string& response) {
385   // On Android, 'ps' output looks like this:
386   // USER PID PPID VSIZE RSS WCHAN PC ? NAME
387   typedef std::map<std::string, std::string> StringMap;
388   StringMap pid_to_package;
389   std::vector<std::string> entries;
390   Tokenize(response, "\n", &entries);
391   for (size_t i = 1; i < entries.size(); ++i) {
392     std::vector<std::string> fields;
393     Tokenize(entries[i], " \r", &fields);
394     if (fields.size() < 9)
395       continue;
396     pid_to_package[fields[1]] = fields[8];
397   }
398   DevToolsAdbBridge::RemoteBrowsers browsers =
399       remote_devices_->back()->browsers();
400   for (DevToolsAdbBridge::RemoteBrowsers::iterator it = browsers.begin();
401       it != browsers.end(); ++it) {
402     StringMap::iterator pit = pid_to_package.find((*it)->pid());
403     if (pit != pid_to_package.end())
404       (*it)->set_package(pit->second);
405   }
406 }
407
408 void AdbPagesCommand::ParseDumpsysResponse(const std::string& response) {
409   std::vector<std::string> lines;
410   Tokenize(response, "\r", &lines);
411   for (size_t i = 0; i < lines.size(); ++i) {
412     std::string line = lines[i];
413     size_t pos = line.find(kDumpsysScreenSizePrefix);
414     if (pos != std::string::npos) {
415       ParseScreenSize(
416           line.substr(pos + std::string(kDumpsysScreenSizePrefix).size()));
417       break;
418     }
419   }
420 }
421
422 void AdbPagesCommand::ParseScreenSize(const std::string& str) {
423   std::vector<std::string> pairs;
424   Tokenize(str, "-", &pairs);
425   if (pairs.size() != 2)
426     return;
427
428   int width;
429   int height;
430   std::vector<std::string> numbers;
431   Tokenize(pairs[1].substr(1, pairs[1].size() - 2), ",", &numbers);
432   if (numbers.size() != 2 ||
433       !base::StringToInt(numbers[0], &width) ||
434       !base::StringToInt(numbers[1], &height))
435     return;
436
437   remote_devices_->back()->set_screen_size(gfx::Size(width, height));
438 }
439
440
441 // AdbProtocolCommand ---------------------------------------------------------
442
443 class AdbProtocolCommand : public AdbWebSocket::Delegate {
444  public:
445   AdbProtocolCommand(
446       scoped_refptr<RefCountedAdbThread> adb_thread,
447       scoped_refptr<AndroidDevice> device,
448       const std::string& socket_name,
449       const std::string& debug_url,
450       const std::string& command);
451
452  private:
453   virtual void OnSocketOpened() OVERRIDE;
454   virtual void OnFrameRead(const std::string& message) OVERRIDE;
455   virtual void OnSocketClosed(bool closed_by_device) OVERRIDE;
456   virtual bool ProcessIncomingMessage(const std::string& message) OVERRIDE;
457
458   scoped_refptr<RefCountedAdbThread> adb_thread_;
459   const std::string command_;
460   scoped_refptr<AdbWebSocket> web_socket_;
461
462   DISALLOW_COPY_AND_ASSIGN(AdbProtocolCommand);
463 };
464
465 AdbProtocolCommand::AdbProtocolCommand(
466     scoped_refptr<RefCountedAdbThread> adb_thread,
467     scoped_refptr<AndroidDevice> device,
468     const std::string& socket_name,
469     const std::string& debug_url,
470     const std::string& command)
471     : adb_thread_(adb_thread),
472       command_(command) {
473   web_socket_ = new AdbWebSocket(
474       device, socket_name, debug_url, adb_thread_->message_loop(), this);
475 }
476
477 void AdbProtocolCommand::OnSocketOpened() {
478   web_socket_->SendFrame(command_);
479   web_socket_->Disconnect();
480 }
481
482 void AdbProtocolCommand::OnFrameRead(const std::string& message) {}
483
484 void AdbProtocolCommand::OnSocketClosed(bool closed_by_device) {
485   delete this;
486 }
487
488 bool AdbProtocolCommand::ProcessIncomingMessage(const std::string& message) {
489   return false;
490 }
491
492 }  // namespace
493
494 const char kDevToolsChannelNameFormat[] = "%s_devtools_remote";
495
496 class AgentHostDelegate;
497
498 typedef std::map<std::string, AgentHostDelegate*> AgentHostDelegates;
499
500 base::LazyInstance<AgentHostDelegates>::Leaky g_host_delegates =
501     LAZY_INSTANCE_INITIALIZER;
502
503 DevToolsAdbBridge::Wrapper::Wrapper() {
504   bridge_ = new DevToolsAdbBridge();
505 }
506
507 DevToolsAdbBridge::Wrapper::~Wrapper() {
508 }
509
510 DevToolsAdbBridge* DevToolsAdbBridge::Wrapper::Get() {
511   return bridge_.get();
512 }
513
514 // static
515 DevToolsAdbBridge::Factory* DevToolsAdbBridge::Factory::GetInstance() {
516   return Singleton<DevToolsAdbBridge::Factory>::get();
517 }
518
519 // static
520 DevToolsAdbBridge* DevToolsAdbBridge::Factory::GetForProfile(
521     Profile* profile) {
522   DevToolsAdbBridge::Wrapper* wrapper =
523       static_cast<DevToolsAdbBridge::Wrapper*>(GetInstance()->
524           GetServiceForBrowserContext(profile, true));
525   return wrapper ? wrapper->Get() : NULL;
526 }
527
528 DevToolsAdbBridge::Factory::Factory()
529     : BrowserContextKeyedServiceFactory(
530           "DevToolsAdbBridge",
531           BrowserContextDependencyManager::GetInstance()) {}
532
533 DevToolsAdbBridge::Factory::~Factory() {}
534
535 BrowserContextKeyedService*
536 DevToolsAdbBridge::Factory::BuildServiceInstanceFor(
537     content::BrowserContext* context) const {
538   return new DevToolsAdbBridge::Wrapper();
539 }
540
541
542 // AgentHostDelegate ----------------------------------------------------------
543
544 class AgentHostDelegate : public content::DevToolsExternalAgentProxyDelegate,
545                           public AdbWebSocket::Delegate {
546  public:
547    static void Create(const std::string& id,
548                       scoped_refptr<DevToolsAdbBridge::RemoteBrowser> browser,
549                       const std::string& debug_url,
550                       const std::string& frontend_url,
551                       Profile* profile) {
552     DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
553     AgentHostDelegates::iterator it =
554         g_host_delegates.Get().find(id);
555     if (it != g_host_delegates.Get().end()) {
556       it->second->OpenFrontend();
557     } else if (!frontend_url.empty()) {
558       new AgentHostDelegate(
559           id, browser->device(), browser->socket(), debug_url,
560           frontend_url, browser->adb_thread()->message_loop(), profile);
561     }
562   }
563
564  private:
565   AgentHostDelegate(
566       const std::string& id,
567       scoped_refptr<AndroidDevice> device,
568       const std::string& socket_name,
569       const std::string& debug_url,
570       const std::string& frontend_url,
571       base::MessageLoop* adb_message_loop,
572       Profile* profile)
573       : id_(id),
574         frontend_url_(frontend_url),
575         adb_message_loop_(adb_message_loop),
576         profile_(profile) {
577     web_socket_ = new AdbWebSocket(
578         device, socket_name, debug_url, adb_message_loop, this);
579     g_host_delegates.Get()[id] = this;
580   }
581
582   void OpenFrontend() {
583     if (!proxy_)
584       return;
585     DevToolsWindow::OpenExternalFrontend(
586         profile_, frontend_url_, proxy_->GetAgentHost().get());
587   }
588
589   virtual ~AgentHostDelegate() {
590     g_host_delegates.Get().erase(id_);
591   }
592
593   virtual void Attach() OVERRIDE {}
594
595   virtual void Detach() OVERRIDE {
596     web_socket_->Disconnect();
597   }
598
599   virtual void SendMessageToBackend(const std::string& message) OVERRIDE {
600     web_socket_->SendFrame(message);
601   }
602
603   virtual void OnSocketOpened() OVERRIDE {
604     proxy_.reset(content::DevToolsExternalAgentProxy::Create(this));
605     OpenFrontend();
606   }
607
608   virtual void OnFrameRead(const std::string& message) OVERRIDE {
609     proxy_->DispatchOnClientHost(message);
610   }
611
612   virtual void OnSocketClosed(bool closed_by_device) OVERRIDE {
613     if (proxy_ && closed_by_device)
614       proxy_->ConnectionClosed();
615     delete this;
616   }
617
618   virtual bool ProcessIncomingMessage(const std::string& message) OVERRIDE {
619     return false;
620   }
621
622   const std::string id_;
623   const std::string frontend_url_;
624   base::MessageLoop* adb_message_loop_;
625   Profile* profile_;
626
627   scoped_ptr<content::DevToolsExternalAgentProxy> proxy_;
628   scoped_refptr<AdbWebSocket> web_socket_;
629   DISALLOW_COPY_AND_ASSIGN(AgentHostDelegate);
630 };
631
632 //// RemotePageTarget ----------------------------------------------
633
634 class RemotePageTarget : public DevToolsTargetImpl {
635  public:
636   RemotePageTarget(scoped_refptr<DevToolsAdbBridge::RemoteBrowser> browser,
637                    const base::DictionaryValue& value);
638   virtual ~RemotePageTarget();
639
640   // content::DevToolsTarget overrides:
641   virtual bool IsAttached() const OVERRIDE;
642   virtual bool Activate() const OVERRIDE;
643   virtual bool Close() const OVERRIDE;
644
645   // DevToolsTargetImpl overrides:
646   virtual void Inspect(Profile* profile) const OVERRIDE;
647   virtual void Reload() const OVERRIDE;
648
649   void Navigate(const std::string& url) const;
650
651  private:
652   scoped_refptr<DevToolsAdbBridge::RemoteBrowser> browser_;
653   std::string debug_url_;
654   std::string frontend_url_;
655   std::string agent_id_;
656   DISALLOW_COPY_AND_ASSIGN(RemotePageTarget);
657 };
658
659 RemotePageTarget::RemotePageTarget(
660     scoped_refptr<DevToolsAdbBridge::RemoteBrowser> browser,
661     const base::DictionaryValue& value)
662     : browser_(browser) {
663   type_ = "adb_page";
664   value.GetString("id", &id_);
665   std::string url;
666   value.GetString("url", &url);
667   url_ = GURL(url);
668   value.GetString("title", &title_);
669   title_ = UTF16ToUTF8(net::UnescapeForHTML(UTF8ToUTF16(title_)));
670   value.GetString("description", &description_);
671   std::string favicon_url;
672   value.GetString("faviconUrl", &favicon_url);
673   favicon_url_ = GURL(favicon_url);
674   value.GetString("webSocketDebuggerUrl", &debug_url_);
675   value.GetString("devtoolsFrontendUrl", &frontend_url_);
676
677   if (id_.empty() && !debug_url_.empty())  {
678     // Target id is not available until Chrome 26. Use page id at the end of
679     // debug_url_ instead. For attached targets the id will remain empty.
680     std::vector<std::string> parts;
681     Tokenize(debug_url_, "/", &parts);
682     id_ = parts[parts.size()-1];
683   }
684
685   if (debug_url_.find("ws://") == 0)
686     debug_url_ = debug_url_.substr(5);
687   else
688     debug_url_ = "";
689
690   size_t ws_param = frontend_url_.find("?ws");
691   if (ws_param != std::string::npos)
692     frontend_url_ = frontend_url_.substr(0, ws_param);
693   if (frontend_url_.find("http:") == 0)
694     frontend_url_ = "https:" + frontend_url_.substr(5);
695
696   agent_id_ = base::StringPrintf("%s:%s:%s",
697       browser_->device()->serial().c_str(),
698       browser_->socket().c_str(),
699       id_.c_str());
700 }
701
702 RemotePageTarget::~RemotePageTarget() {
703 }
704
705 bool RemotePageTarget::IsAttached() const {
706   return debug_url_.empty();
707 }
708
709 void RemotePageTarget::Inspect(Profile* profile) const {
710   std::string request = base::StringPrintf(kActivatePageRequest, id_.c_str());
711   base::Closure inspect_callback = base::Bind(&AgentHostDelegate::Create,
712       id_, browser_, debug_url_, frontend_url_, profile);
713   browser_->SendJsonRequest(request, inspect_callback);
714 }
715
716 bool RemotePageTarget::Activate() const {
717   std::string request = base::StringPrintf(kActivatePageRequest, id_.c_str());
718   browser_->SendJsonRequest(request, base::Closure());
719   return true;
720 }
721
722 bool RemotePageTarget::Close() const {
723   if (IsAttached())
724     return false;
725   std::string request = base::StringPrintf(kClosePageRequest, id_.c_str());
726   browser_->SendJsonRequest(request, base::Closure());
727   return true;
728 }
729
730 void RemotePageTarget::Reload() const {
731   browser_->SendProtocolCommand(debug_url_, kPageReloadCommand, NULL);
732 }
733
734 void RemotePageTarget::Navigate(const std::string& url) const {
735   base::DictionaryValue params;
736   params.SetString(kUrlParam, url);
737   browser_->SendProtocolCommand(debug_url_, kPageNavigateCommand, &params);
738 }
739
740 // DevToolsAdbBridge::RemoteBrowser -------------------------------------------
741
742 DevToolsAdbBridge::RemoteBrowser::RemoteBrowser(
743     scoped_refptr<RefCountedAdbThread> adb_thread,
744     scoped_refptr<AndroidDevice> device,
745     const std::string& socket)
746     : adb_thread_(adb_thread),
747       device_(device),
748       socket_(socket),
749       page_descriptors_(new base::ListValue()) {
750 }
751
752 bool DevToolsAdbBridge::RemoteBrowser::IsChrome() const {
753   return product_.find(kChromeProductName) == 0;
754 }
755
756 DevToolsAdbBridge::RemoteBrowser::ParsedVersion
757 DevToolsAdbBridge::RemoteBrowser::GetParsedVersion() const {
758   ParsedVersion result;
759   std::vector<std::string> parts;
760   Tokenize(version_, ".", &parts);
761   for (size_t i = 0; i != parts.size(); ++i) {
762     int value = 0;
763     base::StringToInt(parts[i], &value);
764     result.push_back(value);
765   }
766   return result;
767 }
768
769 std::vector<DevToolsTargetImpl*>
770 DevToolsAdbBridge::RemoteBrowser::CreatePageTargets() {
771   std::vector<DevToolsTargetImpl*> result;
772   for (size_t i = 0; i < page_descriptors_->GetSize(); ++i) {
773     base::Value* item;
774     page_descriptors_->Get(i, &item);
775     if (!item)
776       continue;
777     base::DictionaryValue* dict;
778     if (!item->GetAsDictionary(&dict))
779       continue;
780     result.push_back(new RemotePageTarget(this, *dict));
781   }
782   return result;
783 }
784
785 void DevToolsAdbBridge::RemoteBrowser::SetPageDescriptors(
786     const base::ListValue& list) {
787   page_descriptors_.reset(list.DeepCopy());
788 }
789
790 static void RespondOnUIThread(base::Closure callback, int, const std::string&) {
791   if (!callback.is_null())
792     BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, callback);
793 }
794
795 void DevToolsAdbBridge::RemoteBrowser::SendJsonRequest(
796     const std::string& request, base::Closure callback) {
797   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
798   adb_thread_->message_loop()->PostTask(FROM_HERE,
799       base::Bind(&AndroidDevice::HttpQuery, device_, socket_, request,
800           base::Bind(&RespondOnUIThread, callback)));
801 }
802
803 void DevToolsAdbBridge::RemoteBrowser::SendProtocolCommand(
804     const std::string& debug_url,
805     const std::string& method,
806     base::DictionaryValue* params) {
807   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
808   if (debug_url.empty())
809     return;
810   DevToolsProtocol::Command command(1, method, params);
811   new AdbProtocolCommand(
812       adb_thread_, device_, socket_, debug_url, command.Serialize());
813 }
814
815 static void NoOp(int, const std::string&) {}
816
817 void DevToolsAdbBridge::RemoteBrowser::Open(const std::string& url) {
818   ParsedVersion parsed_version = GetParsedVersion();
819   if (IsChrome() &&
820       !parsed_version.empty() &&
821       parsed_version[0] >= kMinVersionNewWithURL) {
822     std::string query = net::EscapeQueryParamValue(url, false /* use_plus */);
823     std::string request =
824         base::StringPrintf(kNewPageRequestWithURL, query.c_str());
825     adb_thread_->message_loop()->PostTask(FROM_HERE,
826         base::Bind(&AndroidDevice::HttpQuery,
827             device_, socket_, request, base::Bind(&NoOp)));
828   } else {
829     adb_thread_->message_loop()->PostTask(FROM_HERE,
830         base::Bind(&AndroidDevice::HttpQuery,
831             device_, socket_, kNewPageRequest,
832             base::Bind(&RemoteBrowser::PageCreatedOnHandlerThread, this, url)));
833   }
834 }
835
836 void DevToolsAdbBridge::RemoteBrowser::PageCreatedOnHandlerThread(
837     const std::string& url, int result, const std::string& response) {
838   if (result < 0)
839     return;
840   // Navigating too soon after the page creation breaks navigation history
841   // (crbug.com/311014). This can be avoided by adding a moderate delay.
842   BrowserThread::PostDelayedTask(
843       BrowserThread::UI, FROM_HERE,
844       base::Bind(&RemoteBrowser::PageCreatedOnUIThread, this, response, url),
845       base::TimeDelta::FromMilliseconds(kNewPageNavigateDelayMs));
846 }
847
848 void DevToolsAdbBridge::RemoteBrowser::PageCreatedOnUIThread(
849     const std::string& response, const std::string& url) {
850   scoped_ptr<base::Value> value(base::JSONReader::Read(response));
851   base::DictionaryValue* dict;
852   if (value && value->GetAsDictionary(&dict)) {
853     RemotePageTarget new_page(this, *dict);
854     new_page.Navigate(url);
855   }
856 }
857
858 DevToolsAdbBridge::RemoteBrowser::~RemoteBrowser() {
859 }
860
861
862 // DevToolsAdbBridge::RemoteDevice --------------------------------------------
863
864 DevToolsAdbBridge::RemoteDevice::RemoteDevice(
865     scoped_refptr<AndroidDevice> device)
866     : device_(device) {
867 }
868
869 std::string DevToolsAdbBridge::RemoteDevice::GetSerial() {
870   return device_->serial();
871 }
872
873 std::string DevToolsAdbBridge::RemoteDevice::GetModel() {
874   return device_->model();
875 }
876
877 bool DevToolsAdbBridge::RemoteDevice::IsConnected() {
878   return device_->is_connected();
879 }
880
881 void DevToolsAdbBridge::RemoteDevice::AddBrowser(
882     scoped_refptr<RemoteBrowser> browser) {
883   browsers_.push_back(browser);
884 }
885
886 DevToolsAdbBridge::RemoteDevice::~RemoteDevice() {
887 }
888
889
890 // DevToolsAdbBridge ----------------------------------------------------------
891
892 DevToolsAdbBridge::DevToolsAdbBridge()
893     : adb_thread_(RefCountedAdbThread::GetInstance()),
894       has_message_loop_(adb_thread_->message_loop() != NULL) {
895 }
896
897 void DevToolsAdbBridge::AddListener(Listener* listener) {
898   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
899   if (listeners_.empty())
900     RequestRemoteDevices();
901   listeners_.push_back(listener);
902 }
903
904 void DevToolsAdbBridge::RemoveListener(Listener* listener) {
905   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
906   Listeners::iterator it =
907       std::find(listeners_.begin(), listeners_.end(), listener);
908   DCHECK(it != listeners_.end());
909   listeners_.erase(it);
910 }
911
912 bool DevToolsAdbBridge::HasDevToolsWindow(const std::string& agent_id) {
913   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
914   return g_host_delegates.Get().find(agent_id) != g_host_delegates.Get().end();
915 }
916
917 DevToolsAdbBridge::~DevToolsAdbBridge() {
918   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
919   DCHECK(listeners_.empty());
920 }
921
922 void DevToolsAdbBridge::RequestRemoteDevices() {
923   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
924   if (!has_message_loop_)
925     return;
926
927   new AdbPagesCommand(
928       adb_thread_, device_providers_,
929       base::Bind(&DevToolsAdbBridge::ReceivedRemoteDevices, this));
930 }
931
932 void DevToolsAdbBridge::ReceivedRemoteDevices(RemoteDevices* devices_ptr) {
933   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
934
935   scoped_ptr<RemoteDevices> devices(devices_ptr);
936
937   Listeners copy(listeners_);
938   for (Listeners::iterator it = copy.begin(); it != copy.end(); ++it)
939     (*it)->RemoteDevicesChanged(devices.get());
940
941   if (listeners_.empty())
942     return;
943
944   BrowserThread::PostDelayedTask(
945       BrowserThread::UI,
946       FROM_HERE,
947       base::Bind(&DevToolsAdbBridge::RequestRemoteDevices, this),
948       base::TimeDelta::FromMilliseconds(kAdbPollingIntervalMs));
949 }