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