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.
5 #include "base/strings/string_number_conversions.h"
6 #include "base/strings/string_util.h"
7 #include "base/strings/stringprintf.h"
8 #include "base/threading/non_thread_safe.h"
9 #include "content/public/browser/browser_thread.h"
10 #include "content/public/test/browser_test.h"
11 #include "content/public/test/test_utils.h"
12 #include "net/base/io_buffer.h"
13 #include "net/base/ip_endpoint.h"
14 #include "net/base/net_errors.h"
15 #include "net/socket/stream_socket.h"
16 #include "net/socket/tcp_server_socket.h"
18 using content::BrowserThread
;
22 const char kHostTransportPrefix
[] = "host:transport:";
23 const char kLocalAbstractPrefix
[] = "localabstract:";
25 const char kOpenedUnixSocketsCommand
[] = "shell:cat /proc/net/unix";
26 const char kDeviceModelCommand
[] = "shell:getprop ro.product.model";
27 const char kDumpsysCommand
[] = "shell:dumpsys window policy";
28 const char kListProcessesCommand
[] = "shell:ps";
29 const char kInstalledChromePackagesCommand
[] = "shell:pm list packages";
31 const char kSerialOnline
[] = "01498B321301A00A";
32 const char kSerialOffline
[] = "01498B2B0D01300E";
33 const char kDeviceModel
[] = "Nexus 6";
35 const char kJsonVersionPath
[] = "/json/version";
36 const char kJsonPath
[] = "/json";
37 const char kJsonListPath
[] = "/json/list";
39 const char kHttpRequestTerminator
[] = "\r\n\r\n";
41 const char kHttpResponse
[] =
43 "Content-Length:%d\r\n"
44 "Content-Type:application/json; charset=UTF-8\r\n\r\n%s";
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";
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";
70 const char kSampleListPackages
[] =
71 "package:com.sample.feed\r\n"
72 "package:com.android.nfc\r\n"
73 "package:com.android.chrome\r\n"
74 "package:com.chrome.beta\r\n"
75 "package:com.google.android.apps.chrome\r\n";
77 const char kSampleDumpsys
[] =
78 "WINDOW MANAGER POLICY STATE (dumpsys window policy)\r\n"
79 " mSafeMode=false mSystemReady=true mSystemBooted=true\r\n"
80 " mStable=(0,50)-(720,1184)\r\n" // Only mStable parameter is parsed
81 " mForceStatusBar=false mForceStatusBarFromKeyguard=false\r\n";
83 char kSampleChromeVersion
[] = "{\n"
84 " \"Browser\": \"Chrome/32.0.1679.0\",\n"
85 " \"Protocol-Version\": \"1.0\",\n"
86 " \"User-Agent\": \"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 "
87 "(KHTML, like Gecko) Chrome/32.0.1679.0 Safari/537.36\",\n"
88 " \"WebKit-Version\": \"537.36 (@160162)\"\n"
91 char kSampleChromeBetaVersion
[] = "{\n"
92 " \"Browser\": \"Chrome/31.0.1599.0\",\n"
93 " \"Protocol-Version\": \"1.0\",\n"
94 " \"User-Agent\": \"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 "
95 "(KHTML, like Gecko) Chrome/32.0.1679.0 Safari/537.36\",\n"
96 " \"WebKit-Version\": \"537.36 (@160162)\"\n"
99 char kSampleWebViewVersion
[] = "{\n"
100 " \"Browser\": \"Version/4.0\",\n"
101 " \"Protocol-Version\": \"1.0\",\n"
102 " \"User-Agent\": \"Mozilla/5.0 (Linux; Android 4.3; Build/KRS74B) "
103 "AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Safari/537.36\",\n"
104 " \"WebKit-Version\": \"537.36 (@157588)\"\n"
107 char kSampleChromePages
[] = "[ {\n"
108 " \"description\": \"\",\n"
109 " \"devtoolsFrontendUrl\": \"/devtools/devtools.html?"
110 "ws=/devtools/page/755DE5C9-D49F-811D-0693-51B8E15C80D2\",\n"
111 " \"id\": \"755DE5C9-D49F-811D-0693-51B8E15C80D2\",\n"
112 " \"title\": \"The Chromium Projects\",\n"
113 " \"type\": \"page\",\n"
114 " \"url\": \"http://www.chromium.org/\",\n"
115 " \"webSocketDebuggerUrl\": \""
116 "ws:///devtools/page/755DE5C9-D49F-811D-0693-51B8E15C80D2\"\n"
119 char kSampleChromeBetaPages
[] = "[]";
121 char kSampleWebViewPages
[] = "[ {\n"
122 " \"description\": \"{\\\"attached\\\":false,\\\"empty\\\":false,"
123 "\\\"height\\\":1173,\\\"screenX\\\":0,\\\"screenY\\\":0,"
124 "\\\"visible\\\":true,\\\"width\\\":800}\",\n"
125 " \"devtoolsFrontendUrl\": \"http://chrome-devtools-frontend.appspot.com/"
126 "serve_rev/@157588/devtools.html?ws="
127 "/devtools/page/3E962D4D-B676-182D-3BE8-FAE7CE224DE7\",\n"
128 " \"faviconUrl\": \"http://chromium.org/favicon.ico\",\n"
129 " \"id\": \"3E962D4D-B676-182D-3BE8-FAE7CE224DE7\",\n"
130 " \"thumbnailUrl\": \"/thumb/3E962D4D-B676-182D-3BE8-FAE7CE224DE7\",\n"
131 " \"title\": \"Blink - The Chromium Projects\",\n"
132 " \"type\": \"page\",\n"
133 " \"url\": \"http://www.chromium.org/blink\",\n"
134 " \"webSocketDebuggerUrl\": \"ws:///devtools/"
135 "page/3E962D4D-B676-182D-3BE8-FAE7CE224DE7\"\n"
137 " \"description\": \"{\\\"attached\\\":true,\\\"empty\\\":true,"
138 "\\\"screenX\\\":0,\\\"screenY\\\":33,\\\"visible\\\":false}\",\n"
139 " \"devtoolsFrontendUrl\": \"http://chrome-devtools-frontend.appspot.com/"
140 "serve_rev/@157588/devtools.html?ws="
141 "/devtools/page/44681551-ADFD-2411-076B-3AB14C1C60E2\",\n"
142 " \"faviconUrl\": \"\",\n"
143 " \"id\": \"44681551-ADFD-2411-076B-3AB14C1C60E2\",\n"
144 " \"thumbnailUrl\": \"/thumb/44681551-ADFD-2411-076B-3AB14C1C60E2\",\n"
145 " \"title\": \"More Activity\",\n"
146 " \"type\": \"page\",\n"
147 " \"url\": \"about:blank\",\n"
148 " \"webSocketDebuggerUrl\": \"ws:///devtools/page/"
149 "44681551-ADFD-2411-076B-3AB14C1C60E2\"\n"
152 static const int kBufferSize
= 16*1024;
153 static const int kAdbPort
= 5037;
155 static const int kAdbMessageHeaderSize
= 4;
158 class SingleConnectionServer
: base::NonThreadSafe
{
162 virtual int Consume(const char* data
, int size
) = 0;
163 virtual void Reset() = 0;
169 SingleConnectionServer(
170 Parser
* parser
, net::IPEndPoint endpoint
, int buffer_size
);
172 virtual ~SingleConnectionServer();
174 void Send(const std::string
& message
);
177 void SendData(const char* data
, int size
);
179 void AcceptConnection();
180 void OnAccepted(int result
);
183 void OnDataRead(int count
);
186 void OnDataWritten(int count
);
190 scoped_ptr
<net::TCPServerSocket
> server_socket_
;
191 scoped_ptr
<net::StreamSocket
> client_socket_
;
192 scoped_refptr
<net::GrowableIOBuffer
> input_buffer_
;
193 scoped_refptr
<net::GrowableIOBuffer
> output_buffer_
;
195 DISALLOW_COPY_AND_ASSIGN(SingleConnectionServer
);
198 SingleConnectionServer::SingleConnectionServer(Parser
* parser
,
199 net::IPEndPoint endpoint
,
203 CHECK(CalledOnValidThread());
205 input_buffer_
= new net::GrowableIOBuffer();
206 input_buffer_
->SetCapacity(buffer_size
);
208 output_buffer_
= new net::GrowableIOBuffer();
210 server_socket_
.reset(new net::TCPServerSocket(NULL
, net::NetLog::Source()));
211 server_socket_
->Listen(endpoint
, 1);
216 SingleConnectionServer::~SingleConnectionServer() {
217 CHECK(CalledOnValidThread());
219 server_socket_
.reset();
221 if (client_socket_
) {
222 client_socket_
->Disconnect();
223 client_socket_
.reset();
227 void SingleConnectionServer::Send(const std::string
& message
) {
228 SendData(message
.c_str(), message
.size());
231 void SingleConnectionServer::SendData(const char* data
, int size
) {
232 CHECK(CalledOnValidThread());
234 if ((output_buffer_
->offset() + bytes_to_write_
+ size
) >
235 output_buffer_
->capacity()) {
236 // If not enough space without relocation
237 if (output_buffer_
->capacity() < (bytes_to_write_
+ size
)) {
238 // If even buffer is not enough
239 int new_size
= std::max(output_buffer_
->capacity() * 2, size
* 2);
240 output_buffer_
->SetCapacity(new_size
);
242 memmove(output_buffer_
->StartOfBuffer(),
243 output_buffer_
->data(),
245 output_buffer_
->set_offset(0);
248 memcpy(output_buffer_
->data() + bytes_to_write_
, data
, size
);
249 bytes_to_write_
+= size
;
251 if (bytes_to_write_
== size
)
252 // If write loop wasn't yet started, then start it
256 void SingleConnectionServer::AcceptConnection() {
257 CHECK(CalledOnValidThread());
259 if (client_socket_
) {
260 client_socket_
->Disconnect();
261 client_socket_
.reset();
264 int accept_result
= server_socket_
->Accept(&client_socket_
,
265 base::Bind(&SingleConnectionServer::OnAccepted
, base::Unretained(this)));
267 if (accept_result
!= net::ERR_IO_PENDING
)
268 base::MessageLoop::current()->PostTask(
270 base::Bind(&SingleConnectionServer::OnAccepted
,
271 base::Unretained(this),
275 void SingleConnectionServer::OnAccepted(int result
) {
276 CHECK(CalledOnValidThread());
278 ASSERT_EQ(result
, 0); // Fails if the socket is already in use.
283 void SingleConnectionServer::ReadData() {
284 CHECK(CalledOnValidThread());
286 if (input_buffer_
->RemainingCapacity() == 0)
287 input_buffer_
->SetCapacity(input_buffer_
->capacity() * 2);
289 int read_result
= client_socket_
->Read(
291 input_buffer_
->RemainingCapacity(),
292 base::Bind(&SingleConnectionServer::OnDataRead
, base::Unretained(this)));
294 if (read_result
!= net::ERR_IO_PENDING
)
295 OnDataRead(read_result
);
298 void SingleConnectionServer::OnDataRead(int count
) {
299 CHECK(CalledOnValidThread());
306 input_buffer_
->set_offset(input_buffer_
->offset() + count
);
311 char* data
= input_buffer_
->StartOfBuffer();
312 int data_size
= input_buffer_
->offset();
314 bytes_processed
= parser_
->Consume(data
, data_size
);
316 if (bytes_processed
) {
317 memmove(data
, data
+ bytes_processed
, data_size
- bytes_processed
);
318 input_buffer_
->set_offset(data_size
- bytes_processed
);
320 } while (bytes_processed
);
322 // Posting is needed not to enter deep recursion in case too synchronous IO
323 base::MessageLoop::current()->PostTask(
325 base::Bind(&SingleConnectionServer::ReadData
, base::Unretained(this)));
328 void SingleConnectionServer::WriteData() {
329 CHECK(CalledOnValidThread());
331 CHECK_GE(output_buffer_
->capacity(),
332 output_buffer_
->offset() + bytes_to_write_
) << "Overflow";
334 int write_result
= client_socket_
->Write(
337 base::Bind(&SingleConnectionServer::OnDataWritten
,
338 base::Unretained(this)));
339 if (write_result
!= net::ERR_IO_PENDING
)
340 OnDataWritten(write_result
);
343 void SingleConnectionServer::OnDataWritten(int count
) {
344 CHECK(CalledOnValidThread());
352 CHECK_GE(output_buffer_
->capacity(),
353 output_buffer_
->offset() + bytes_to_write_
) << "Overflow";
355 bytes_to_write_
-= count
;
356 output_buffer_
->set_offset(output_buffer_
->offset() + count
);
358 if (bytes_to_write_
!= 0)
359 // Posting is needed not to enter deep recursion in case too synchronous IO
360 base::MessageLoop::current()->PostTask(
362 base::Bind(&SingleConnectionServer::WriteData
, base::Unretained(this)));
366 class MockAdbServer
: SingleConnectionServer::Parser
,
367 base::NonThreadSafe
{
370 CHECK(CalledOnValidThread());
371 net::IPAddressNumber address
;
372 net::ParseIPLiteralToNumber("127.0.0.1", &address
);
373 net::IPEndPoint
endpoint(address
, kAdbPort
);
374 server_
.reset(new SingleConnectionServer(this, endpoint
, kBufferSize
));
377 virtual ~MockAdbServer() {
378 CHECK(CalledOnValidThread());
382 virtual int Consume(const char* data
, int size
) OVERRIDE
{
383 CHECK(CalledOnValidThread());
384 if (!selected_socket_
.empty()) {
385 std::string
message(data
, size
);
386 size_t request_end_pos
= message
.find(kHttpRequestTerminator
);
387 if (request_end_pos
!= std::string::npos
) {
388 ProcessHTTPRequest(message
.substr(0, request_end_pos
));
389 return request_end_pos
+ strlen(kHttpRequestTerminator
);
394 if (size
>= kAdbMessageHeaderSize
) {
395 std::string
message_header(data
, kAdbMessageHeaderSize
);
398 EXPECT_TRUE(base::HexStringToInt(message_header
, &message_size
));
400 if (size
>= message_size
+ kAdbMessageHeaderSize
) {
401 std::string
message_body(data
+ kAdbMessageHeaderSize
, message_size
);
403 ProcessCommand(message_body
);
405 return kAdbMessageHeaderSize
+ message_size
;
412 virtual void Reset() OVERRIDE
{
413 CHECK(CalledOnValidThread());
414 selected_device_
= std::string();
415 selected_socket_
= std::string();
418 void ProcessHTTPRequest(const std::string
& request
) {
419 CHECK(CalledOnValidThread());
420 std::vector
<std::string
> tokens
;
421 Tokenize(request
, " ", &tokens
);
422 CHECK_EQ(3U, tokens
.size());
423 CHECK_EQ("GET", tokens
[0]);
424 CHECK_EQ("HTTP/1.1", tokens
[2]);
426 std::string
path(tokens
[1]);
428 if (path
== kJsonPath
)
429 path
= kJsonListPath
;
431 if (selected_socket_
== "chrome_devtools_remote") {
432 if (path
== kJsonVersionPath
)
433 SendHTTPResponse(kSampleChromeVersion
);
434 else if (path
== kJsonListPath
)
435 SendHTTPResponse(kSampleChromePages
);
437 NOTREACHED() << "Unknown command " << request
;
438 } else if (selected_socket_
== "chrome_devtools_remote_1002") {
439 if (path
== kJsonVersionPath
)
440 SendHTTPResponse(kSampleChromeBetaVersion
);
441 else if (path
== kJsonListPath
)
442 SendHTTPResponse(kSampleChromeBetaPages
);
444 NOTREACHED() << "Unknown command " << request
;
445 } else if (selected_socket_
.find("noprocess_devtools_remote") == 0) {
446 if (path
== kJsonVersionPath
)
447 SendHTTPResponse("{}");
448 else if (path
== kJsonListPath
)
449 SendHTTPResponse("[]");
451 NOTREACHED() << "Unknown command " << request
;
452 } else if (selected_socket_
== "webview_devtools_remote_2425") {
453 if (path
== kJsonVersionPath
)
454 SendHTTPResponse(kSampleWebViewVersion
);
455 else if (path
== kJsonListPath
)
456 SendHTTPResponse(kSampleWebViewPages
);
458 NOTREACHED() << "Unknown command " << request
;
460 NOTREACHED() << "Unknown socket " << selected_socket_
;
464 void ProcessCommand(const std::string
& command
) {
465 CHECK(CalledOnValidThread());
466 if (command
== "host:devices") {
467 SendResponse(base::StringPrintf("%s\tdevice\n%s\toffline",
470 } else if (command
.find(kHostTransportPrefix
) == 0) {
471 selected_device_
= command
.substr(strlen(kHostTransportPrefix
));
473 } else if (selected_device_
!= kSerialOnline
) {
474 NOTREACHED() << "Unknown device - " << selected_device_
;
475 } else if (command
== kDeviceModelCommand
) {
476 SendResponse(kDeviceModel
);
477 } else if (command
== kOpenedUnixSocketsCommand
) {
478 SendResponse(kSampleOpenedUnixSockets
);
479 } else if (command
== kDumpsysCommand
) {
480 SendResponse(kSampleDumpsys
);
481 } else if (command
== kListProcessesCommand
) {
482 SendResponse(kSampleListProcesses
);
483 } else if (command
== kInstalledChromePackagesCommand
) {
484 SendResponse(kSampleListPackages
);
485 } else if (command
.find(kLocalAbstractPrefix
) == 0) {
486 selected_socket_
= command
.substr(strlen(kLocalAbstractPrefix
));
489 NOTREACHED() << "Unknown command - " << command
;
493 void SendResponse(const std::string
& response
) {
494 CHECK(CalledOnValidThread());
495 std::stringstream response_stream
;
496 response_stream
<< "OKAY";
498 int size
= response
.size();
500 static const char kHexChars
[] = "0123456789ABCDEF";
501 for (int i
= 3; i
>= 0; i
--)
502 response_stream
<< kHexChars
[ (size
>> 4*i
) & 0x0f ];
503 response_stream
<< response
;
506 server_
->Send(response_stream
.str());
509 void SendHTTPResponse(const std::string
& body
) {
510 CHECK(CalledOnValidThread());
511 std::string
response_data(base::StringPrintf(kHttpResponse
,
512 static_cast<int>(body
.size()),
514 server_
->Send(response_data
);
517 std::string selected_device_
;
518 std::string selected_socket_
;
520 scoped_ptr
<SingleConnectionServer
> server_
;
523 static MockAdbServer
* mock_adb_server_
= NULL
;
525 void StartMockAdbServerOnIOThread() {
526 CHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
527 CHECK(mock_adb_server_
== NULL
);
528 mock_adb_server_
= new MockAdbServer();
531 void StopMockAdbServerOnIOThread() {
532 CHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
533 CHECK(mock_adb_server_
!= NULL
);
534 delete mock_adb_server_
;
535 mock_adb_server_
= NULL
;
540 void StartMockAdbServer() {
541 BrowserThread::PostTaskAndReply(
544 base::Bind(&StartMockAdbServerOnIOThread
),
545 base::MessageLoop::QuitClosure());
546 content::RunMessageLoop();
549 void StopMockAdbServer() {
550 BrowserThread::PostTaskAndReply(
553 base::Bind(&StopMockAdbServerOnIOThread
),
554 base::MessageLoop::QuitClosure());
555 content::RunMessageLoop();