Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / devtools / device / adb / mock_adb_server.cc
1 // Copyright 2014 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 "base/memory/weak_ptr.h"
6 #include "base/strings/string_number_conversions.h"
7 #include "base/strings/string_util.h"
8 #include "base/strings/stringprintf.h"
9 #include "base/threading/non_thread_safe.h"
10 #include "content/public/browser/browser_thread.h"
11 #include "content/public/test/browser_test.h"
12 #include "content/public/test/test_utils.h"
13 #include "net/base/io_buffer.h"
14 #include "net/base/ip_endpoint.h"
15 #include "net/base/net_errors.h"
16 #include "net/socket/stream_socket.h"
17 #include "net/socket/tcp_server_socket.h"
18
19 using content::BrowserThread;
20
21 namespace {
22
23 const char kHostTransportPrefix[] = "host:transport:";
24 const char kLocalAbstractPrefix[] = "localabstract:";
25
26 const char kOpenedUnixSocketsCommand[] = "shell:cat /proc/net/unix";
27 const char kDeviceModelCommand[] = "shell:getprop ro.product.model";
28 const char kDumpsysCommand[] = "shell:dumpsys window policy";
29 const char kListProcessesCommand[] = "shell:ps";
30
31 const char kSerialOnline[] = "01498B321301A00A";
32 const char kSerialOffline[] = "01498B2B0D01300E";
33 const char kDeviceModel[] = "Nexus 6";
34
35 const char kJsonVersionPath[] = "/json/version";
36 const char kJsonPath[] = "/json";
37 const char kJsonListPath[] = "/json/list";
38
39 const char kHttpRequestTerminator[] = "\r\n\r\n";
40
41 const char kHttpResponse[] =
42     "HTTP/1.1 200 OK\r\n"
43     "Content-Length:%d\r\n"
44     "Content-Type:application/json; charset=UTF-8\r\n\r\n%s";
45
46 const char kSampleOpenedUnixSockets[] =
47     "Num       RefCount Protocol Flags    Type St Inode Path\n"
48     "00000000: 00000004 00000000"
49     " 00000000 0002 01  3328 /dev/socket/wpa_wlan0\n"
50     "00000000: 00000002 00000000"
51     " 00010000 0001 01  5394 /dev/socket/vold\n"
52     "00000000: 00000002 00000000"
53     " 00010000 0001 01 11810 @webview_devtools_remote_2425\n"
54     "00000000: 00000002 00000000"
55     " 00010000 0001 01 20893 @chrome_devtools_remote\n"
56     "00000000: 00000002 00000000"
57     " 00010000 0001 01 20894 @chrome_devtools_remote_1002\n"
58     "00000000: 00000002 00000000"
59     " 00010000 0001 01 20895 @noprocess_devtools_remote\n";
60
61 const char kSampleListProcesses[] =
62     "USER   PID  PPID VSIZE  RSS    WCHAN    PC         NAME\n"
63     "root   1    0    688    508    ffffffff 00000000 S /init\r\n"
64     "u0_a75 2425 123  933736 193024 ffffffff 00000000 S com.sample.feed\r\n"
65     "nfc    741  123  706448 26316  ffffffff 00000000 S com.android.nfc\r\n"
66     "u0_a76 1001 124  111111 222222 ffffffff 00000000 S com.android.chrome\r\n"
67     "u0_a77 1002 125  111111 222222 ffffffff 00000000 S com.chrome.beta\r\n"
68     "u0_a78 1003 126  111111 222222 ffffffff 00000000 S com.noprocess.app\r\n";
69
70 const char kSampleDumpsys[] =
71     "WINDOW MANAGER POLICY STATE (dumpsys window policy)\r\n"
72     "    mSafeMode=false mSystemReady=true mSystemBooted=true\r\n"
73     "    mStable=(0,50)-(720,1184)\r\n" // Only mStable parameter is parsed
74     "    mForceStatusBar=false mForceStatusBarFromKeyguard=false\r\n";
75
76 char kSampleChromeVersion[] = "{\n"
77     "   \"Browser\": \"Chrome/32.0.1679.0\",\n"
78     "   \"Protocol-Version\": \"1.0\",\n"
79     "   \"User-Agent\": \"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 "
80     "(KHTML, like Gecko) Chrome/32.0.1679.0 Safari/537.36\",\n"
81     "   \"WebKit-Version\": \"537.36 (@160162)\"\n"
82     "}";
83
84 char kSampleChromeBetaVersion[] = "{\n"
85     "   \"Browser\": \"Chrome/31.0.1599.0\",\n"
86     "   \"Protocol-Version\": \"1.0\",\n"
87     "   \"User-Agent\": \"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 "
88     "(KHTML, like Gecko) Chrome/32.0.1679.0 Safari/537.36\",\n"
89     "   \"WebKit-Version\": \"537.36 (@160162)\"\n"
90     "}";
91
92 char kSampleWebViewVersion[] = "{\n"
93     "   \"Browser\": \"Version/4.0\",\n"
94     "   \"Protocol-Version\": \"1.0\",\n"
95     "   \"User-Agent\": \"Mozilla/5.0 (Linux; Android 4.3; Build/KRS74B) "
96     "AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Safari/537.36\",\n"
97     "   \"WebKit-Version\": \"537.36 (@157588)\"\n"
98     "}";
99
100 char kSampleChromePages[] = "[ {\n"
101     "   \"description\": \"\",\n"
102     "   \"devtoolsFrontendUrl\": \"/devtools/devtools.html?"
103     "ws=/devtools/page/0\",\n"
104     "   \"id\": \"0\",\n"
105     "   \"title\": \"The Chromium Projects\",\n"
106     "   \"type\": \"page\",\n"
107     "   \"url\": \"http://www.chromium.org/\",\n"
108     "   \"webSocketDebuggerUrl\": \""
109     "ws:///devtools/page/0\"\n"
110     "} ]";
111
112 char kSampleChromeBetaPages[] = "[ {\n"
113     "   \"description\": \"\",\n"
114     "   \"devtoolsFrontendUrl\": \"/devtools/devtools.html?"
115     "ws=/devtools/page/0\",\n"
116     "   \"id\": \"0\",\n"
117     "   \"title\": \"The Chromium Projects\",\n"
118     "   \"type\": \"page\",\n"
119     "   \"url\": \"http://www.chromium.org/\",\n"
120     "   \"webSocketDebuggerUrl\": \""
121     "ws:///devtools/page/0\"\n"
122     "} ]";
123
124 char kSampleWebViewPages[] = "[ {\n"
125     "   \"description\": \"{\\\"attached\\\":false,\\\"empty\\\":false,"
126     "\\\"height\\\":1173,\\\"screenX\\\":0,\\\"screenY\\\":0,"
127     "\\\"visible\\\":true,\\\"width\\\":800}\",\n"
128     "   \"devtoolsFrontendUrl\": \"http://chrome-devtools-frontend.appspot.com/"
129     "serve_rev/@157588/devtools.html?ws="
130     "/devtools/page/3E962D4D-B676-182D-3BE8-FAE7CE224DE7\",\n"
131     "   \"faviconUrl\": \"http://chromium.org/favicon.ico\",\n"
132     "   \"id\": \"3E962D4D-B676-182D-3BE8-FAE7CE224DE7\",\n"
133     "   \"thumbnailUrl\": \"/thumb/3E962D4D-B676-182D-3BE8-FAE7CE224DE7\",\n"
134     "   \"title\": \"Blink - The Chromium Projects\",\n"
135     "   \"type\": \"page\",\n"
136     "   \"url\": \"http://www.chromium.org/blink\",\n"
137     "   \"webSocketDebuggerUrl\": \"ws:///devtools/"
138     "page/3E962D4D-B676-182D-3BE8-FAE7CE224DE7\"\n"
139     "}, {\n"
140     "   \"description\": \"{\\\"attached\\\":true,\\\"empty\\\":true,"
141     "\\\"screenX\\\":0,\\\"screenY\\\":33,\\\"visible\\\":false}\",\n"
142     "   \"devtoolsFrontendUrl\": \"http://chrome-devtools-frontend.appspot.com/"
143     "serve_rev/@157588/devtools.html?ws="
144     "/devtools/page/44681551-ADFD-2411-076B-3AB14C1C60E2\",\n"
145     "   \"faviconUrl\": \"\",\n"
146     "   \"id\": \"44681551-ADFD-2411-076B-3AB14C1C60E2\",\n"
147     "   \"thumbnailUrl\": \"/thumb/44681551-ADFD-2411-076B-3AB14C1C60E2\",\n"
148     "   \"title\": \"More Activity\",\n"
149     "   \"type\": \"page\",\n"
150     "   \"url\": \"about:blank\",\n"
151     "   \"webSocketDebuggerUrl\": \"ws:///devtools/page/"
152     "44681551-ADFD-2411-076B-3AB14C1C60E2\"\n"
153     "}]";
154
155 static const int kBufferSize = 16*1024;
156 static const int kAdbPort = 5037;
157
158 static const int kAdbMessageHeaderSize = 4;
159
160 class SimpleHttpServer : base::NonThreadSafe {
161  public:
162   class Parser {
163    public:
164     virtual int Consume(const char* data, int size) = 0;
165     virtual ~Parser() {}
166   };
167
168   typedef base::Callback<void(const std::string&)> SendCallback;
169   typedef base::Callback<Parser*(const SendCallback&)> ParserFactory;
170
171   SimpleHttpServer(const ParserFactory& factory, net::IPEndPoint endpoint);
172   virtual ~SimpleHttpServer();
173
174  private:
175   class Connection : base::NonThreadSafe {
176    public:
177     Connection(net::StreamSocket* socket, const ParserFactory& factory);
178     virtual ~Connection();
179
180    private:
181     void Send(const std::string& message);
182     void ReadData();
183     void OnDataRead(int count);
184     void WriteData();
185     void OnDataWritten(int count);
186
187     scoped_ptr<net::StreamSocket> socket_;
188     scoped_ptr<Parser> parser_;
189     scoped_refptr<net::GrowableIOBuffer> input_buffer_;
190     scoped_refptr<net::GrowableIOBuffer> output_buffer_;
191     int bytes_to_write_;
192     bool read_closed_;
193     base::WeakPtrFactory<Connection> weak_factory_;
194
195     DISALLOW_COPY_AND_ASSIGN(Connection);
196   };
197
198   void AcceptConnection();
199   void OnAccepted(int result);
200
201   ParserFactory factory_;
202   scoped_ptr<net::TCPServerSocket> socket_;
203   scoped_ptr<net::StreamSocket> client_socket_;
204   base::WeakPtrFactory<SimpleHttpServer> weak_factory_;
205
206   DISALLOW_COPY_AND_ASSIGN(SimpleHttpServer);
207 };
208
209 SimpleHttpServer::SimpleHttpServer(const ParserFactory& factory,
210                                    net::IPEndPoint endpoint)
211     : factory_(factory),
212       socket_(new net::TCPServerSocket(NULL, net::NetLog::Source())),
213       weak_factory_(this) {
214   socket_->Listen(endpoint, 5);
215   AcceptConnection();
216 }
217
218 SimpleHttpServer::~SimpleHttpServer() {
219 }
220
221 SimpleHttpServer::Connection::Connection(net::StreamSocket* socket,
222                                          const ParserFactory& factory)
223     : socket_(socket),
224       parser_(factory.Run(base::Bind(&Connection::Send,
225                                      base::Unretained(this)))),
226       input_buffer_(new net::GrowableIOBuffer()),
227       output_buffer_(new net::GrowableIOBuffer()),
228       bytes_to_write_(0),
229       read_closed_(false),
230       weak_factory_(this) {
231   input_buffer_->SetCapacity(kBufferSize);
232   ReadData();
233 }
234
235 SimpleHttpServer::Connection::~Connection() {
236 }
237
238 void SimpleHttpServer::Connection::Send(const std::string& message) {
239   CHECK(CalledOnValidThread());
240   const char* data = message.c_str();
241   int size = message.size();
242
243   if ((output_buffer_->offset() + bytes_to_write_ + size) >
244       output_buffer_->capacity()) {
245     // If not enough space without relocation
246     if (output_buffer_->capacity() < (bytes_to_write_ + size)) {
247       // If even buffer is not enough
248       int new_size = std::max(output_buffer_->capacity() * 2, size * 2);
249       output_buffer_->SetCapacity(new_size);
250     }
251     memmove(output_buffer_->StartOfBuffer(),
252             output_buffer_->data(),
253             bytes_to_write_);
254     output_buffer_->set_offset(0);
255   }
256
257   memcpy(output_buffer_->data() + bytes_to_write_, data, size);
258   bytes_to_write_ += size;
259
260   if (bytes_to_write_ == size)
261     // If write loop wasn't yet started, then start it
262     WriteData();
263 }
264
265 void SimpleHttpServer::Connection::ReadData() {
266   CHECK(CalledOnValidThread());
267
268   if (input_buffer_->RemainingCapacity() == 0)
269     input_buffer_->SetCapacity(input_buffer_->capacity() * 2);
270
271   int read_result = socket_->Read(
272       input_buffer_.get(),
273       input_buffer_->RemainingCapacity(),
274       base::Bind(&Connection::OnDataRead, base::Unretained(this)));
275
276   if (read_result != net::ERR_IO_PENDING)
277     OnDataRead(read_result);
278 }
279
280 void SimpleHttpServer::Connection::OnDataRead(int count) {
281   CHECK(CalledOnValidThread());
282   if (count <= 0) {
283     if (bytes_to_write_ == 0)
284       delete this;
285     else
286       read_closed_ = true;
287     return;
288   }
289   input_buffer_->set_offset(input_buffer_->offset() + count);
290   int bytes_processed;
291
292   do {
293     char* data = input_buffer_->StartOfBuffer();
294     int data_size = input_buffer_->offset();
295     bytes_processed = parser_->Consume(data, data_size);
296
297     if (bytes_processed) {
298       memmove(data, data + bytes_processed, data_size - bytes_processed);
299       input_buffer_->set_offset(data_size - bytes_processed);
300     }
301   } while (bytes_processed);
302   // Posting to avoid deep recursion in case of synchronous IO
303   base::MessageLoop::current()->PostTask(
304       FROM_HERE,
305       base::Bind(&Connection::ReadData, weak_factory_.GetWeakPtr()));
306 }
307
308 void SimpleHttpServer::Connection::WriteData() {
309   CHECK(CalledOnValidThread());
310   CHECK_GE(output_buffer_->capacity(),
311            output_buffer_->offset() + bytes_to_write_) << "Overflow";
312
313   int write_result = socket_->Write(
314       output_buffer_.get(),
315       bytes_to_write_,
316       base::Bind(&Connection::OnDataWritten, base::Unretained(this)));
317
318   if (write_result != net::ERR_IO_PENDING)
319     OnDataWritten(write_result);
320 }
321
322 void SimpleHttpServer::Connection::OnDataWritten(int count) {
323   CHECK(CalledOnValidThread());
324   if (count < 0) {
325     delete this;
326     return;
327   }
328   CHECK_GT(count, 0);
329   CHECK_GE(output_buffer_->capacity(),
330            output_buffer_->offset() + bytes_to_write_) << "Overflow";
331
332   bytes_to_write_ -= count;
333   output_buffer_->set_offset(output_buffer_->offset() + count);
334
335   if (bytes_to_write_ != 0)
336     // Posting to avoid deep recursion in case of synchronous IO
337     base::MessageLoop::current()->PostTask(
338         FROM_HERE,
339         base::Bind(&Connection::WriteData, weak_factory_.GetWeakPtr()));
340   else if (read_closed_)
341     delete this;
342 }
343
344 void SimpleHttpServer::AcceptConnection() {
345   CHECK(CalledOnValidThread());
346
347   int accept_result = socket_->Accept(&client_socket_,
348       base::Bind(&SimpleHttpServer::OnAccepted, base::Unretained(this)));
349
350   if (accept_result != net::ERR_IO_PENDING)
351     base::MessageLoop::current()->PostTask(
352         FROM_HERE,
353         base::Bind(&SimpleHttpServer::OnAccepted,
354                    weak_factory_.GetWeakPtr(),
355                    accept_result));
356 }
357
358 void SimpleHttpServer::OnAccepted(int result) {
359   CHECK(CalledOnValidThread());
360   ASSERT_EQ(result, 0);  // Fails if the socket is already in use.
361   new Connection(client_socket_.release(), factory_);
362   AcceptConnection();
363 }
364
365 class AdbParser : SimpleHttpServer::Parser, base::NonThreadSafe {
366  public:
367   static Parser* Create(const SimpleHttpServer::SendCallback& callback) {
368     return new AdbParser(callback);
369   }
370
371   explicit AdbParser(const SimpleHttpServer::SendCallback& callback)
372       : callback_(callback) {
373   }
374
375   virtual ~AdbParser() {
376   }
377
378  private:
379   virtual int Consume(const char* data, int size) OVERRIDE {
380     CHECK(CalledOnValidThread());
381     if (!selected_socket_.empty()) {
382       std::string message(data, size);
383       size_t request_end_pos = message.find(kHttpRequestTerminator);
384       if (request_end_pos != std::string::npos) {
385         ProcessHTTPRequest(message.substr(0, request_end_pos));
386         return request_end_pos + strlen(kHttpRequestTerminator);
387       }
388       return 0;
389     }
390     if (size >= kAdbMessageHeaderSize) {
391       std::string message_header(data, kAdbMessageHeaderSize);
392       int message_size;
393
394       EXPECT_TRUE(base::HexStringToInt(message_header, &message_size));
395
396       if (size >= message_size + kAdbMessageHeaderSize) {
397         std::string message_body(data + kAdbMessageHeaderSize, message_size);
398         ProcessCommand(message_body);
399         return kAdbMessageHeaderSize + message_size;
400       }
401     }
402     return 0;
403   }
404
405   void ProcessHTTPRequest(const std::string& request) {
406     CHECK(CalledOnValidThread());
407     std::vector<std::string> tokens;
408     Tokenize(request, " ", &tokens);
409     CHECK_EQ(3U, tokens.size());
410     CHECK_EQ("GET", tokens[0]);
411     CHECK_EQ("HTTP/1.1", tokens[2]);
412
413     std::string path(tokens[1]);
414     if (path == kJsonPath)
415       path = kJsonListPath;
416
417     if (selected_socket_ == "chrome_devtools_remote") {
418       if (path == kJsonVersionPath)
419         SendHTTPResponse(kSampleChromeVersion);
420       else if (path == kJsonListPath)
421         SendHTTPResponse(kSampleChromePages);
422       else
423         NOTREACHED() << "Unknown command " << request;
424     } else if (selected_socket_ == "chrome_devtools_remote_1002") {
425       if (path == kJsonVersionPath)
426         SendHTTPResponse(kSampleChromeBetaVersion);
427       else if (path == kJsonListPath)
428         SendHTTPResponse(kSampleChromeBetaPages);
429       else
430         NOTREACHED() << "Unknown command " << request;
431     } else if (selected_socket_.find("noprocess_devtools_remote") == 0) {
432       if (path == kJsonVersionPath)
433         SendHTTPResponse("{}");
434       else if (path == kJsonListPath)
435         SendHTTPResponse("[]");
436       else
437         NOTREACHED() << "Unknown command " << request;
438     } else if (selected_socket_ == "webview_devtools_remote_2425") {
439       if (path == kJsonVersionPath)
440         SendHTTPResponse(kSampleWebViewVersion);
441       else if (path == kJsonListPath)
442         SendHTTPResponse(kSampleWebViewPages);
443       else
444         NOTREACHED() << "Unknown command " << request;
445     } else {
446       NOTREACHED() << "Unknown socket " << selected_socket_;
447     }
448   }
449
450   void ProcessCommand(const std::string& command) {
451     CHECK(CalledOnValidThread());
452     if (command == "host:devices") {
453       SendResponse(base::StringPrintf("%s\tdevice\n%s\toffline",
454                                       kSerialOnline,
455                                       kSerialOffline));
456     } else if (command.find(kHostTransportPrefix) == 0) {
457       selected_device_ = command.substr(strlen(kHostTransportPrefix));
458       SendResponse("");
459     } else if (selected_device_ != kSerialOnline) {
460       Send("FAIL", "device offline (x)");
461     } else if (command == kDeviceModelCommand) {
462       SendResponse(kDeviceModel);
463     } else if (command == kOpenedUnixSocketsCommand) {
464       SendResponse(kSampleOpenedUnixSockets);
465     } else if (command == kDumpsysCommand) {
466       SendResponse(kSampleDumpsys);
467     } else if (command == kListProcessesCommand) {
468       SendResponse(kSampleListProcesses);
469     } else if (command.find(kLocalAbstractPrefix) == 0) {
470       selected_socket_ = command.substr(strlen(kLocalAbstractPrefix));
471       SendResponse("");
472     } else {
473       NOTREACHED() << "Unknown command - " << command;
474     }
475   }
476
477   void SendResponse(const std::string& response) {
478     Send("OKAY", response);
479   }
480
481   void Send(const std::string& status, const std::string& response) {
482     CHECK(CalledOnValidThread());
483     CHECK_EQ(4U, status.size());
484
485     std::stringstream response_stream;
486     response_stream << status;
487
488     int size = response.size();
489     if (size > 0) {
490       static const char kHexChars[] = "0123456789ABCDEF";
491       for (int i = 3; i >= 0; i--)
492         response_stream << kHexChars[ (size >> 4*i) & 0x0f ];
493       response_stream << response;
494     }
495     callback_.Run(response_stream.str());
496   }
497
498   void SendHTTPResponse(const std::string& body) {
499     CHECK(CalledOnValidThread());
500     std::string response_data(base::StringPrintf(kHttpResponse,
501                                                  static_cast<int>(body.size()),
502                                                  body.c_str()));
503     callback_.Run(response_data);
504   }
505
506   std::string selected_device_;
507   std::string selected_socket_;
508   SimpleHttpServer::SendCallback callback_;
509 };
510
511 static SimpleHttpServer* mock_adb_server_ = NULL;
512
513 void StartMockAdbServerOnIOThread() {
514   CHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
515   CHECK(mock_adb_server_ == NULL);
516   net::IPAddressNumber address;
517   net::ParseIPLiteralToNumber("127.0.0.1", &address);
518   net::IPEndPoint endpoint(address, kAdbPort);
519   mock_adb_server_ =
520       new SimpleHttpServer(base::Bind(&AdbParser::Create), endpoint);
521 }
522
523 void StopMockAdbServerOnIOThread() {
524   CHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
525   CHECK(mock_adb_server_ != NULL);
526   delete mock_adb_server_;
527   mock_adb_server_ = NULL;
528 }
529
530 } // namespace
531
532 void StartMockAdbServer() {
533   BrowserThread::PostTaskAndReply(
534       BrowserThread::IO,
535       FROM_HERE,
536       base::Bind(&StartMockAdbServerOnIOThread),
537       base::MessageLoop::QuitClosure());
538   content::RunMessageLoop();
539 }
540
541 void StopMockAdbServer() {
542   BrowserThread::PostTaskAndReply(
543       BrowserThread::IO,
544       FROM_HERE,
545       base::Bind(&StopMockAdbServerOnIOThread),
546       base::MessageLoop::QuitClosure());
547   content::RunMessageLoop();
548 }
549