Home | History | Annotate | Download | only in adb
      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