Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(791)

Side by Side Diff: chrome/browser/devtools/device/adb/mock_adb_server.cc

Issue 257563003: DevTools: Unify ADB-related browser tests (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Fixed clang compile Created 6 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
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/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"
17
18 using content::BrowserThread;
19
20 namespace {
21
22 const char kHostTransportPrefix[] = "host:transport:";
23 const char kLocalAbstractPrefix[] = "localabstract:";
24
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";
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 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";
76
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";
82
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"
89 "}";
90
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"
97 "}";
98
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"
105 "}";
106
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"
117 "} ]";
118
119 char kSampleChromeBetaPages[] = "[]";
120
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"
136 "}, {\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"
150 "}]";
151
152 static const int kBufferSize = 16*1024;
153 static const int kAdbPort = 5037;
154
155 static const int kAdbMessageHeaderSize = 4;
156
157
158 class SingleConnectionServer : base::NonThreadSafe {
159 public:
160 class Parser {
161 public:
162 virtual int Consume(const char* data, int size) = 0;
163 virtual void Reset() = 0;
164
165 protected:
166 virtual ~Parser() {}
167 };
168
169 SingleConnectionServer(
170 Parser* parser, net::IPEndPoint endpoint, int buffer_size);
171
172 virtual ~SingleConnectionServer();
173
174 void Send(const std::string& message);
175
176 private:
177 void SendData(const char* data, int size);
178
179 void AcceptConnection();
180 void OnAccepted(int result);
181
182 void ReadData();
183 void OnDataRead(int count);
184
185 void WriteData();
186 void OnDataWritten(int count);
187
188 Parser* parser_;
189 int bytes_to_write_;
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_;
194
195 DISALLOW_COPY_AND_ASSIGN(SingleConnectionServer);
196 };
197
198 SingleConnectionServer::SingleConnectionServer(Parser* parser,
199 net::IPEndPoint endpoint,
200 int buffer_size)
201 : parser_(parser),
202 bytes_to_write_(0) {
203 CHECK(CalledOnValidThread());
204
205 input_buffer_ = new net::GrowableIOBuffer();
206 input_buffer_->SetCapacity(buffer_size);
207
208 output_buffer_ = new net::GrowableIOBuffer();
209
210 server_socket_.reset(new net::TCPServerSocket(NULL, net::NetLog::Source()));
211 server_socket_->Listen(endpoint, 1);
212
213 AcceptConnection();
214 }
215
216 SingleConnectionServer::~SingleConnectionServer() {
217 CHECK(CalledOnValidThread());
218
219 server_socket_.reset();
220
221 if (client_socket_) {
222 client_socket_->Disconnect();
223 client_socket_.reset();
224 }
225 }
226
227 void SingleConnectionServer::Send(const std::string& message) {
228 SendData(message.c_str(), message.size());
229 }
230
231 void SingleConnectionServer::SendData(const char* data, int size) {
232 CHECK(CalledOnValidThread());
233
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);
241 }
242 memmove(output_buffer_->StartOfBuffer(),
243 output_buffer_->data(),
244 bytes_to_write_);
245 output_buffer_->set_offset(0);
246 }
247
248 memcpy(output_buffer_->data() + bytes_to_write_, data, size);
249 bytes_to_write_ += size;
250
251 if (bytes_to_write_ == size)
252 // If write loop wasn't yet started, then start it
253 WriteData();
254 }
255
256 void SingleConnectionServer::AcceptConnection() {
257 CHECK(CalledOnValidThread());
258
259 if (client_socket_) {
260 client_socket_->Disconnect();
261 client_socket_.reset();
262 }
263
264 int accept_result = server_socket_->Accept(&client_socket_,
265 base::Bind(&SingleConnectionServer::OnAccepted, base::Unretained(this)));
266
267 if (accept_result != net::ERR_IO_PENDING)
268 base::MessageLoop::current()->PostTask(
269 FROM_HERE,
270 base::Bind(&SingleConnectionServer::OnAccepted,
271 base::Unretained(this),
272 accept_result));
273 }
274
275 void SingleConnectionServer::OnAccepted(int result) {
276 CHECK(CalledOnValidThread());
277
278 ASSERT_EQ(result, 0); // Fails if the socket is already in use.
279 parser_->Reset();
280 ReadData();
281 }
282
283 void SingleConnectionServer::ReadData() {
284 CHECK(CalledOnValidThread());
285
286 if (input_buffer_->RemainingCapacity() == 0)
287 input_buffer_->SetCapacity(input_buffer_->capacity() * 2);
288
289 int read_result = client_socket_->Read(
290 input_buffer_.get(),
291 input_buffer_->RemainingCapacity(),
292 base::Bind(&SingleConnectionServer::OnDataRead, base::Unretained(this)));
293
294 if (read_result != net::ERR_IO_PENDING)
295 OnDataRead(read_result);
296 }
297
298 void SingleConnectionServer::OnDataRead(int count) {
299 CHECK(CalledOnValidThread());
300
301 if (count <= 0) {
302 AcceptConnection();
303 return;
304 }
305
306 input_buffer_->set_offset(input_buffer_->offset() + count);
307
308 int bytes_processed;
309
310 do {
311 char* data = input_buffer_->StartOfBuffer();
312 int data_size = input_buffer_->offset();
313
314 bytes_processed = parser_->Consume(data, data_size);
315
316 if (bytes_processed) {
317 memmove(data, data + bytes_processed, data_size - bytes_processed);
318 input_buffer_->set_offset(data_size - bytes_processed);
319 }
320 } while (bytes_processed);
321
322 // Posting is needed not to enter deep recursion in case too synchronous IO
323 base::MessageLoop::current()->PostTask(
324 FROM_HERE,
325 base::Bind(&SingleConnectionServer::ReadData, base::Unretained(this)));
326 }
327
328 void SingleConnectionServer::WriteData() {
329 CHECK(CalledOnValidThread());
330
331 CHECK_GE(output_buffer_->capacity(),
332 output_buffer_->offset() + bytes_to_write_) << "Overflow";
333
334 int write_result = client_socket_->Write(
335 output_buffer_,
336 bytes_to_write_,
337 base::Bind(&SingleConnectionServer::OnDataWritten,
338 base::Unretained(this)));
339 if (write_result != net::ERR_IO_PENDING)
340 OnDataWritten(write_result);
341 }
342
343 void SingleConnectionServer::OnDataWritten(int count) {
344 CHECK(CalledOnValidThread());
345
346 if (count < 0) {
347 AcceptConnection();
348 return;
349 }
350
351 CHECK_GT(count, 0);
352 CHECK_GE(output_buffer_->capacity(),
353 output_buffer_->offset() + bytes_to_write_) << "Overflow";
354
355 bytes_to_write_ -= count;
356 output_buffer_->set_offset(output_buffer_->offset() + count);
357
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(
361 FROM_HERE,
362 base::Bind(&SingleConnectionServer::WriteData, base::Unretained(this)));
363 }
364
365
366 class MockAdbServer : SingleConnectionServer::Parser,
367 base::NonThreadSafe {
368 public:
369 MockAdbServer() {
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));
375 }
376
377 virtual ~MockAdbServer() {
378 CHECK(CalledOnValidThread());
379 }
380
381 private:
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);
390 }
391 return 0;
392 }
393
394 if (size >= kAdbMessageHeaderSize) {
395 std::string message_header(data, kAdbMessageHeaderSize);
396 int message_size;
397
398 EXPECT_TRUE(base::HexStringToInt(message_header, &message_size));
399
400 if (size >= message_size + kAdbMessageHeaderSize) {
401 std::string message_body(data + kAdbMessageHeaderSize, message_size );
402
403 ProcessCommand(message_body);
404
405 return kAdbMessageHeaderSize + message_size;
406 }
407 }
408
409 return 0;
410 }
411
412 virtual void Reset() OVERRIDE {
413 CHECK(CalledOnValidThread());
414 selected_device_ = std::string();
415 selected_socket_ = std::string();
416 }
417
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]);
425
426 std::string path(tokens[1]);
427
428 if (path == kJsonPath)
429 path = kJsonListPath;
430
431 if (selected_socket_ == "chrome_devtools_remote") {
432 if (path == kJsonVersionPath)
433 SendHTTPResponse(kSampleChromeVersion);
434 else if (path == kJsonListPath)
435 SendHTTPResponse(kSampleChromePages);
436 else
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);
443 else
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("[]");
450 else
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);
457 else
458 NOTREACHED() << "Unknown command " << request;
459 } else {
460 NOTREACHED() << "Unknown socket " << selected_socket_;
461 }
462 }
463
464 void ProcessCommand(const std::string& command) {
465 CHECK(CalledOnValidThread());
466 if (command == "host:devices") {
467 SendResponse(base::StringPrintf("%s\tdevice\n%s\toffline",
468 kSerialOnline,
469 kSerialOffline));
470 } else if (command.find(kHostTransportPrefix) == 0) {
471 selected_device_ = command.substr(strlen(kHostTransportPrefix));
472 SendResponse("");
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));
487 SendResponse("");
488 } else {
489 NOTREACHED() << "Unknown command - " << command;
490 }
491 }
492
493 void SendResponse(const std::string& response) {
494 CHECK(CalledOnValidThread());
495 std::stringstream response_stream;
496 response_stream << "OKAY";
497
498 int size = response.size();
499 if (size > 0) {
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;
504 }
505
506 server_->Send(response_stream.str());
507 }
508
509 void SendHTTPResponse(const std::string& body) {
510 CHECK(CalledOnValidThread());
511 std::string response_data(base::StringPrintf(kHttpResponse,
512 static_cast<int>(body.size()),
513 body.c_str()));
514 server_->Send(response_data);
515 }
516
517 std::string selected_device_;
518 std::string selected_socket_;
519
520 scoped_ptr<SingleConnectionServer> server_;
521 };
522
523 static MockAdbServer* mock_adb_server_ = NULL;
524
525 void StartMockAdbServerOnIOThread() {
526 CHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
527 CHECK(mock_adb_server_ == NULL);
528 mock_adb_server_ = new MockAdbServer();
529 }
530
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;
536 }
537
538 } // namespace
539
540 void StartMockAdbServer() {
541 BrowserThread::PostTaskAndReply(
542 BrowserThread::IO,
543 FROM_HERE,
544 base::Bind(&StartMockAdbServerOnIOThread),
545 base::MessageLoop::QuitClosure());
546 content::RunMessageLoop();
547 }
548
549 void StopMockAdbServer() {
550 BrowserThread::PostTaskAndReply(
551 BrowserThread::IO,
552 FROM_HERE,
553 base::Bind(&StopMockAdbServerOnIOThread),
554 base::MessageLoop::QuitClosure());
555 content::RunMessageLoop();
556 }
557
OLDNEW
« no previous file with comments | « chrome/browser/devtools/device/adb/mock_adb_server.h ('k') | chrome/browser/devtools/device/android_device_manager.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698