Add new certificateProvider extension API.
[chromium-blink-merge.git] / chrome / browser / devtools / device / adb / mock_adb_server.cc
blob70e9a0cf9c0f8527e3b5e41e59cdfb0df3416e43
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 "chrome/browser/devtools/device/adb/mock_adb_server.h"
7 #include "base/location.h"
8 #include "base/memory/weak_ptr.h"
9 #include "base/single_thread_task_runner.h"
10 #include "base/strings/string_number_conversions.h"
11 #include "base/strings/string_split.h"
12 #include "base/strings/string_util.h"
13 #include "base/strings/stringprintf.h"
14 #include "base/thread_task_runner_handle.h"
15 #include "base/threading/non_thread_safe.h"
16 #include "content/public/browser/browser_thread.h"
17 #include "content/public/test/browser_test.h"
18 #include "content/public/test/test_utils.h"
19 #include "net/base/io_buffer.h"
20 #include "net/base/ip_endpoint.h"
21 #include "net/base/net_errors.h"
22 #include "net/socket/stream_socket.h"
23 #include "net/socket/tcp_server_socket.h"
25 using content::BrowserThread;
27 namespace {
29 const char kHostTransportPrefix[] = "host:transport:";
30 const char kLocalAbstractPrefix[] = "localabstract:";
32 const char kShellPrefix[] = "shell:";
33 const char kOpenedUnixSocketsCommand[] = "cat /proc/net/unix";
34 const char kDeviceModelCommand[] = "getprop ro.product.model";
35 const char kDumpsysCommand[] = "dumpsys window policy";
36 const char kListProcessesCommand[] = "ps";
37 const char kListUsersCommand[] = "dumpsys user";
38 const char kEchoCommandPrefix[] = "echo ";
40 const char kSerialOnline[] = "01498B321301A00A";
41 const char kSerialOffline[] = "01498B2B0D01300E";
42 const char kDeviceModel[] = "Nexus 6";
44 const char kJsonVersionPath[] = "/json/version";
45 const char kJsonPath[] = "/json";
46 const char kJsonListPath[] = "/json/list";
48 const char kHttpRequestTerminator[] = "\r\n\r\n";
50 const char kHttpResponse[] =
51 "HTTP/1.1 200 OK\r\n"
52 "Content-Length:%d\r\n"
53 "Content-Type:application/json; charset=UTF-8\r\n\r\n%s";
55 const char kSampleOpenedUnixSockets[] =
56 "Num RefCount Protocol Flags Type St Inode Path\n"
57 "00000000: 00000004 00000000"
58 " 00000000 0002 01 3328 /dev/socket/wpa_wlan0\n"
59 "00000000: 00000002 00000000"
60 " 00010000 0001 01 5394 /dev/socket/vold\n"
61 "00000000: 00000002 00000000"
62 " 00010000 0001 01 11810 @webview_devtools_remote_2425\n"
63 "00000000: 00000002 00000000"
64 " 00010000 0001 01 20893 @chrome_devtools_remote\n"
65 "00000000: 00000002 00000000"
66 " 00010000 0001 01 20894 @chrome_devtools_remote_1002\n"
67 "00000000: 00000002 00000000"
68 " 00010000 0001 01 20895 @noprocess_devtools_remote\n";
70 const char kSampleListProcesses[] =
71 "USER PID PPID VSIZE RSS WCHAN PC NAME\n"
72 "root 1 0 688 508 ffffffff 00000000 S /init\r\n"
73 "u0_a75 2425 123 933736 193024 ffffffff 00000000 S com.sample.feed\r\n"
74 "nfc 741 123 706448 26316 ffffffff 00000000 S com.android.nfc\r\n"
75 "u0_a76 1001 124 111111 222222 ffffffff 00000000 S com.android.chrome\r\n"
76 "u10_a77 1002 125 111111 222222 ffffffff 00000000 S com.chrome.beta\r\n"
77 "u0_a78 1003 126 111111 222222 ffffffff 00000000 S com.noprocess.app\r\n";
79 const char kSampleDumpsys[] =
80 "WINDOW MANAGER POLICY STATE (dumpsys window policy)\r\n"
81 " mSafeMode=false mSystemReady=true mSystemBooted=true\r\n"
82 " mStable=(0,50)-(720,1184)\r\n" // Only mStable parameter is parsed
83 " mForceStatusBar=false mForceStatusBarFromKeyguard=false\r\n";
85 const char kSampleListUsers[] =
86 "Users:\r\n"
87 " UserInfo{0:Test User:13} serialNo=0\r\n"
88 " Created: <unknown>\r\n"
89 " Last logged in: +17m18s871ms ago\r\n"
90 " UserInfo{10:Test User : 2:10} serialNo=10\r\n"
91 " Created: +3d4h35m1s139ms ago\r\n"
92 " Last logged in: +17m26s287ms ago\r\n";
94 char kSampleChromeVersion[] = "{\n"
95 " \"Browser\": \"Chrome/32.0.1679.0\",\n"
96 " \"Protocol-Version\": \"1.0\",\n"
97 " \"User-Agent\": \"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 "
98 "(KHTML, like Gecko) Chrome/32.0.1679.0 Safari/537.36\",\n"
99 " \"WebKit-Version\": \"537.36 (@160162)\"\n"
100 "}";
102 char kSampleChromeBetaVersion[] = "{\n"
103 " \"Browser\": \"Chrome/31.0.1599.0\",\n"
104 " \"Protocol-Version\": \"1.0\",\n"
105 " \"User-Agent\": \"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 "
106 "(KHTML, like Gecko) Chrome/32.0.1679.0 Safari/537.36\",\n"
107 " \"WebKit-Version\": \"537.36 (@160162)\"\n"
108 "}";
110 char kSampleWebViewVersion[] = "{\n"
111 " \"Browser\": \"Version/4.0\",\n"
112 " \"Protocol-Version\": \"1.0\",\n"
113 " \"User-Agent\": \"Mozilla/5.0 (Linux; Android 4.3; Build/KRS74B) "
114 "AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Safari/537.36\",\n"
115 " \"WebKit-Version\": \"537.36 (@157588)\"\n"
116 "}";
118 char kSampleChromePages[] = "[ {\n"
119 " \"description\": \"\",\n"
120 " \"devtoolsFrontendUrl\": \"/devtools/devtools.html?"
121 "ws=/devtools/page/0\",\n"
122 " \"id\": \"0\",\n"
123 " \"title\": \"The Chromium Projects\",\n"
124 " \"type\": \"page\",\n"
125 " \"url\": \"http://www.chromium.org/\",\n"
126 " \"webSocketDebuggerUrl\": \""
127 "ws:///devtools/page/0\"\n"
128 "} ]";
130 char kSampleChromeBetaPages[] = "[ {\n"
131 " \"description\": \"\",\n"
132 " \"devtoolsFrontendUrl\": \"/devtools/devtools.html?"
133 "ws=/devtools/page/0\",\n"
134 " \"id\": \"0\",\n"
135 " \"title\": \"The Chromium Projects\",\n"
136 " \"type\": \"page\",\n"
137 " \"url\": \"http://www.chromium.org/\",\n"
138 " \"webSocketDebuggerUrl\": \""
139 "ws:///devtools/page/0\"\n"
140 "} ]";
142 char kSampleWebViewPages[] = "[ {\n"
143 " \"description\": \"{\\\"attached\\\":false,\\\"empty\\\":false,"
144 "\\\"height\\\":1173,\\\"screenX\\\":0,\\\"screenY\\\":0,"
145 "\\\"visible\\\":true,\\\"width\\\":800}\",\n"
146 " \"devtoolsFrontendUrl\": \"http://chrome-devtools-frontend.appspot.com/"
147 "serve_rev/@157588/devtools.html?ws="
148 "/devtools/page/3E962D4D-B676-182D-3BE8-FAE7CE224DE7\",\n"
149 " \"faviconUrl\": \"http://chromium.org/favicon.ico\",\n"
150 " \"id\": \"3E962D4D-B676-182D-3BE8-FAE7CE224DE7\",\n"
151 " \"thumbnailUrl\": \"/thumb/3E962D4D-B676-182D-3BE8-FAE7CE224DE7\",\n"
152 " \"title\": \"Blink - The Chromium Projects\",\n"
153 " \"type\": \"page\",\n"
154 " \"url\": \"http://www.chromium.org/blink\",\n"
155 " \"webSocketDebuggerUrl\": \"ws:///devtools/"
156 "page/3E962D4D-B676-182D-3BE8-FAE7CE224DE7\"\n"
157 "}, {\n"
158 " \"description\": \"{\\\"attached\\\":true,\\\"empty\\\":true,"
159 "\\\"screenX\\\":0,\\\"screenY\\\":33,\\\"visible\\\":false}\",\n"
160 " \"devtoolsFrontendUrl\": \"http://chrome-devtools-frontend.appspot.com/"
161 "serve_rev/@157588/devtools.html?ws="
162 "/devtools/page/44681551-ADFD-2411-076B-3AB14C1C60E2\",\n"
163 " \"faviconUrl\": \"\",\n"
164 " \"id\": \"44681551-ADFD-2411-076B-3AB14C1C60E2\",\n"
165 " \"thumbnailUrl\": \"/thumb/44681551-ADFD-2411-076B-3AB14C1C60E2\",\n"
166 " \"title\": \"More Activity\",\n"
167 " \"type\": \"page\",\n"
168 " \"url\": \"about:blank\",\n"
169 " \"webSocketDebuggerUrl\": \"ws:///devtools/page/"
170 "44681551-ADFD-2411-076B-3AB14C1C60E2\"\n"
171 "}]";
173 static const int kBufferSize = 16*1024;
174 static const uint16 kAdbPort = 5037;
176 static const int kAdbMessageHeaderSize = 4;
178 class SimpleHttpServer : base::NonThreadSafe {
179 public:
180 class Parser {
181 public:
182 virtual int Consume(const char* data, int size) = 0;
183 virtual ~Parser() {}
186 using SendCallback = base::Callback<void(const std::string&)>;
187 using ParserFactory = base::Callback<Parser*(const SendCallback&)>;
189 SimpleHttpServer(const ParserFactory& factory, net::IPEndPoint endpoint);
190 virtual ~SimpleHttpServer();
192 private:
193 class Connection : base::NonThreadSafe {
194 public:
195 Connection(net::StreamSocket* socket, const ParserFactory& factory);
196 virtual ~Connection();
198 private:
199 void Send(const std::string& message);
200 void ReadData();
201 void OnDataRead(int count);
202 void WriteData();
203 void OnDataWritten(int count);
205 scoped_ptr<net::StreamSocket> socket_;
206 scoped_ptr<Parser> parser_;
207 scoped_refptr<net::GrowableIOBuffer> input_buffer_;
208 scoped_refptr<net::GrowableIOBuffer> output_buffer_;
209 int bytes_to_write_;
210 bool read_closed_;
211 base::WeakPtrFactory<Connection> weak_factory_;
213 DISALLOW_COPY_AND_ASSIGN(Connection);
216 void AcceptConnection();
217 void OnAccepted(int result);
219 ParserFactory factory_;
220 scoped_ptr<net::TCPServerSocket> socket_;
221 scoped_ptr<net::StreamSocket> client_socket_;
222 base::WeakPtrFactory<SimpleHttpServer> weak_factory_;
224 DISALLOW_COPY_AND_ASSIGN(SimpleHttpServer);
227 SimpleHttpServer::SimpleHttpServer(const ParserFactory& factory,
228 net::IPEndPoint endpoint)
229 : factory_(factory),
230 socket_(new net::TCPServerSocket(nullptr, net::NetLog::Source())),
231 weak_factory_(this) {
232 socket_->Listen(endpoint, 5);
233 AcceptConnection();
236 SimpleHttpServer::~SimpleHttpServer() {
239 SimpleHttpServer::Connection::Connection(net::StreamSocket* socket,
240 const ParserFactory& factory)
241 : socket_(socket),
242 parser_(factory.Run(base::Bind(&Connection::Send,
243 base::Unretained(this)))),
244 input_buffer_(new net::GrowableIOBuffer()),
245 output_buffer_(new net::GrowableIOBuffer()),
246 bytes_to_write_(0),
247 read_closed_(false),
248 weak_factory_(this) {
249 input_buffer_->SetCapacity(kBufferSize);
250 ReadData();
253 SimpleHttpServer::Connection::~Connection() {
256 void SimpleHttpServer::Connection::Send(const std::string& message) {
257 CHECK(CalledOnValidThread());
258 const char* data = message.c_str();
259 int size = message.size();
261 if ((output_buffer_->offset() + bytes_to_write_ + size) >
262 output_buffer_->capacity()) {
263 // If not enough space without relocation
264 if (output_buffer_->capacity() < (bytes_to_write_ + size)) {
265 // If even buffer is not enough
266 int new_size = std::max(output_buffer_->capacity() * 2, size * 2);
267 output_buffer_->SetCapacity(new_size);
269 memmove(output_buffer_->StartOfBuffer(),
270 output_buffer_->data(),
271 bytes_to_write_);
272 output_buffer_->set_offset(0);
275 memcpy(output_buffer_->data() + bytes_to_write_, data, size);
276 bytes_to_write_ += size;
278 if (bytes_to_write_ == size)
279 // If write loop wasn't yet started, then start it
280 WriteData();
283 void SimpleHttpServer::Connection::ReadData() {
284 CHECK(CalledOnValidThread());
286 if (input_buffer_->RemainingCapacity() == 0)
287 input_buffer_->SetCapacity(input_buffer_->capacity() * 2);
289 int read_result = socket_->Read(
290 input_buffer_.get(),
291 input_buffer_->RemainingCapacity(),
292 base::Bind(&Connection::OnDataRead, base::Unretained(this)));
294 if (read_result != net::ERR_IO_PENDING)
295 OnDataRead(read_result);
298 void SimpleHttpServer::Connection::OnDataRead(int count) {
299 CHECK(CalledOnValidThread());
300 if (count <= 0) {
301 if (bytes_to_write_ == 0)
302 delete this;
303 else
304 read_closed_ = true;
305 return;
307 input_buffer_->set_offset(input_buffer_->offset() + count);
308 int bytes_processed;
310 do {
311 char* data = input_buffer_->StartOfBuffer();
312 int data_size = input_buffer_->offset();
313 bytes_processed = parser_->Consume(data, data_size);
315 if (bytes_processed) {
316 memmove(data, data + bytes_processed, data_size - bytes_processed);
317 input_buffer_->set_offset(data_size - bytes_processed);
319 } while (bytes_processed);
320 // Posting to avoid deep recursion in case of synchronous IO
321 base::ThreadTaskRunnerHandle::Get()->PostTask(
322 FROM_HERE, base::Bind(&Connection::ReadData, weak_factory_.GetWeakPtr()));
325 void SimpleHttpServer::Connection::WriteData() {
326 CHECK(CalledOnValidThread());
327 CHECK_GE(output_buffer_->capacity(),
328 output_buffer_->offset() + bytes_to_write_) << "Overflow";
330 int write_result = socket_->Write(
331 output_buffer_.get(),
332 bytes_to_write_,
333 base::Bind(&Connection::OnDataWritten, base::Unretained(this)));
335 if (write_result != net::ERR_IO_PENDING)
336 OnDataWritten(write_result);
339 void SimpleHttpServer::Connection::OnDataWritten(int count) {
340 CHECK(CalledOnValidThread());
341 if (count < 0) {
342 delete this;
343 return;
345 CHECK_GT(count, 0);
346 CHECK_GE(output_buffer_->capacity(),
347 output_buffer_->offset() + bytes_to_write_) << "Overflow";
349 bytes_to_write_ -= count;
350 output_buffer_->set_offset(output_buffer_->offset() + count);
352 if (bytes_to_write_ != 0)
353 // Posting to avoid deep recursion in case of synchronous IO
354 base::ThreadTaskRunnerHandle::Get()->PostTask(
355 FROM_HERE,
356 base::Bind(&Connection::WriteData, weak_factory_.GetWeakPtr()));
357 else if (read_closed_)
358 delete this;
361 void SimpleHttpServer::AcceptConnection() {
362 CHECK(CalledOnValidThread());
364 int accept_result = socket_->Accept(&client_socket_,
365 base::Bind(&SimpleHttpServer::OnAccepted, base::Unretained(this)));
367 if (accept_result != net::ERR_IO_PENDING)
368 base::ThreadTaskRunnerHandle::Get()->PostTask(
369 FROM_HERE, base::Bind(&SimpleHttpServer::OnAccepted,
370 weak_factory_.GetWeakPtr(), accept_result));
373 void SimpleHttpServer::OnAccepted(int result) {
374 CHECK(CalledOnValidThread());
375 ASSERT_EQ(result, 0); // Fails if the socket is already in use.
376 new Connection(client_socket_.release(), factory_);
377 AcceptConnection();
380 class AdbParser : public SimpleHttpServer::Parser,
381 public base::NonThreadSafe,
382 public MockAndroidConnection::Delegate {
383 public:
384 static Parser* Create(FlushMode flush_mode,
385 const SimpleHttpServer::SendCallback& callback) {
386 return new AdbParser(flush_mode, callback);
389 ~AdbParser() override {}
390 private:
391 explicit AdbParser(FlushMode flush_mode,
392 const SimpleHttpServer::SendCallback& callback)
393 : flush_mode_(flush_mode),
394 callback_(callback) {
397 int Consume(const char* data, int size) override {
398 CHECK(CalledOnValidThread());
399 if (mock_connection_) {
400 mock_connection_->Receive(std::string(data, size));
401 return size;
403 if (size >= kAdbMessageHeaderSize) {
404 std::string message_header(data, kAdbMessageHeaderSize);
405 int message_size;
407 EXPECT_TRUE(base::HexStringToInt(message_header, &message_size));
409 if (size >= message_size + kAdbMessageHeaderSize) {
410 std::string message_body(data + kAdbMessageHeaderSize, message_size);
411 ProcessCommand(message_body);
412 return kAdbMessageHeaderSize + message_size;
415 return 0;
418 void ProcessCommand(const std::string& command) {
419 CHECK(CalledOnValidThread());
420 if (command == "host:devices") {
421 SendSuccess(base::StringPrintf("%s\tdevice\n%s\toffline",
422 kSerialOnline,
423 kSerialOffline));
424 } else if (command.find(kHostTransportPrefix) == 0) {
425 serial_ = command.substr(strlen(kHostTransportPrefix));
426 SendSuccess(std::string());
427 } else if (serial_ != kSerialOnline) {
428 Send("FAIL", "device offline (x)");
429 } else {
430 mock_connection_ = make_scoped_ptr(
431 new MockAndroidConnection(this, serial_, command));
435 void SendSuccess(const std::string& response) override {
436 Send("OKAY", response);
439 void SendRaw(const std::string& data) override {
440 callback_.Run(data);
443 void Send(const std::string& status, const std::string& response) {
444 CHECK(CalledOnValidThread());
445 CHECK_EQ(4U, status.size());
446 std::string buffer = status;
447 if (flush_mode_ == FlushWithoutSize) {
448 callback_.Run(buffer);
449 buffer = std::string();
452 int size = response.size();
453 if (size > 0) {
454 static const char kHexChars[] = "0123456789ABCDEF";
455 for (int i = 3; i >= 0; i--)
456 buffer += kHexChars[ (size >> 4*i) & 0x0f ];
457 if (flush_mode_ == FlushWithSize) {
458 callback_.Run(buffer);
459 buffer = std::string();
461 buffer += response;
462 callback_.Run(buffer);
463 } else if (flush_mode_ != FlushWithoutSize) {
464 callback_.Run(buffer);
468 FlushMode flush_mode_;
469 SimpleHttpServer::SendCallback callback_;
470 std::string serial_;
471 scoped_ptr<MockAndroidConnection> mock_connection_;
474 static SimpleHttpServer* mock_adb_server_ = NULL;
476 void StartMockAdbServerOnIOThread(FlushMode flush_mode) {
477 CHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
478 CHECK(mock_adb_server_ == NULL);
479 net::IPAddressNumber address;
480 net::ParseIPLiteralToNumber("127.0.0.1", &address);
481 net::IPEndPoint endpoint(address, kAdbPort);
482 mock_adb_server_ = new SimpleHttpServer(
483 base::Bind(&AdbParser::Create, flush_mode), endpoint);
486 void StopMockAdbServerOnIOThread() {
487 CHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
488 CHECK(mock_adb_server_ != NULL);
489 delete mock_adb_server_;
490 mock_adb_server_ = NULL;
493 } // namespace
495 MockAndroidConnection::MockAndroidConnection(
496 Delegate* delegate,
497 const std::string& serial,
498 const std::string& command)
499 : delegate_(delegate),
500 serial_(serial) {
501 ProcessCommand(command);
504 MockAndroidConnection::~MockAndroidConnection() {
507 void MockAndroidConnection::Receive(const std::string& data) {
508 request_ += data;
509 size_t request_end_pos = data.find(kHttpRequestTerminator);
510 if (request_end_pos == std::string::npos)
511 return;
513 std::string request(request_.substr(0, request_end_pos));
514 std::vector<std::string> tokens =
515 base::SplitString(request, " ", base::KEEP_WHITESPACE,
516 base::SPLIT_WANT_NONEMPTY);
517 CHECK_EQ(3U, tokens.size());
518 CHECK_EQ("GET", tokens[0]);
519 CHECK_EQ("HTTP/1.1", tokens[2]);
521 std::string path(tokens[1]);
522 if (path == kJsonPath)
523 path = kJsonListPath;
525 if (socket_name_ == "chrome_devtools_remote") {
526 if (path == kJsonVersionPath)
527 SendHTTPResponse(kSampleChromeVersion);
528 else if (path == kJsonListPath)
529 SendHTTPResponse(kSampleChromePages);
530 else
531 NOTREACHED() << "Unknown command " << request;
532 } else if (socket_name_ == "chrome_devtools_remote_1002") {
533 if (path == kJsonVersionPath)
534 SendHTTPResponse(kSampleChromeBetaVersion);
535 else if (path == kJsonListPath)
536 SendHTTPResponse(kSampleChromeBetaPages);
537 else
538 NOTREACHED() << "Unknown command " << request;
539 } else if (socket_name_.find("noprocess_devtools_remote") == 0) {
540 if (path == kJsonVersionPath)
541 SendHTTPResponse("{}");
542 else if (path == kJsonListPath)
543 SendHTTPResponse("[]");
544 else
545 NOTREACHED() << "Unknown command " << request;
546 } else if (socket_name_ == "webview_devtools_remote_2425") {
547 if (path == kJsonVersionPath)
548 SendHTTPResponse(kSampleWebViewVersion);
549 else if (path == kJsonListPath)
550 SendHTTPResponse(kSampleWebViewPages);
551 else
552 NOTREACHED() << "Unknown command " << request;
553 } else {
554 NOTREACHED() << "Unknown socket " << socket_name_;
558 void MockAndroidConnection::ProcessCommand(const std::string& command) {
559 if (command.find(kLocalAbstractPrefix) == 0) {
560 socket_name_ = command.substr(strlen(kLocalAbstractPrefix));
561 delegate_->SendSuccess(std::string());
562 } else {
563 if (command.find(kShellPrefix) == 0) {
564 std::string result;
565 for (const auto& line :
566 base::SplitString(command.substr(strlen(kShellPrefix)), "\n",
567 base::KEEP_WHITESPACE,
568 base::SPLIT_WANT_NONEMPTY)) {
569 if (line == kDeviceModelCommand) {
570 result += kDeviceModel;
571 result += "\r\n";
572 } else if (line == kOpenedUnixSocketsCommand) {
573 result += kSampleOpenedUnixSockets;
574 } else if (line == kDumpsysCommand) {
575 result += kSampleDumpsys;
576 } else if (line == kListProcessesCommand) {
577 result += kSampleListProcesses;
578 } else if (line == kListUsersCommand) {
579 result += kSampleListUsers;
580 } else if (line.find(kEchoCommandPrefix) == 0) {
581 result += line.substr(strlen(kEchoCommandPrefix));
582 result += "\r\n";
583 } else {
584 NOTREACHED() << "Unknown shell command - " << command;
587 delegate_->SendSuccess(result);
588 } else {
589 NOTREACHED() << "Unknown command - " << command;
591 delegate_->Close();
595 void MockAndroidConnection::SendHTTPResponse(const std::string& body) {
596 std::string response_data(base::StringPrintf(kHttpResponse,
597 static_cast<int>(body.size()),
598 body.c_str()));
599 delegate_->SendRaw(response_data);
602 void StartMockAdbServer(FlushMode flush_mode) {
603 BrowserThread::PostTaskAndReply(
604 BrowserThread::IO,
605 FROM_HERE,
606 base::Bind(&StartMockAdbServerOnIOThread, flush_mode),
607 base::MessageLoop::QuitClosure());
608 content::RunMessageLoop();
611 void StopMockAdbServer() {
612 BrowserThread::PostTaskAndReply(
613 BrowserThread::IO,
614 FROM_HERE,
615 base::Bind(&StopMockAdbServerOnIOThread),
616 base::MessageLoop::QuitClosure());
617 content::RunMessageLoop();