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 550