| Index: chrome/browser/devtools/device/adb/adb_client_socket_browsertest.cc
|
| diff --git a/chrome/browser/devtools/device/adb/adb_client_socket_browsertest.cc b/chrome/browser/devtools/device/adb/adb_client_socket_browsertest.cc
|
| index 219219da75a36860f6512cadff41e549390f688a..5a4fa93fccd650cbe2fb6d5f206f991106548dad 100644
|
| --- a/chrome/browser/devtools/device/adb/adb_client_socket_browsertest.cc
|
| +++ b/chrome/browser/devtools/device/adb/adb_client_socket_browsertest.cc
|
| @@ -2,421 +2,127 @@
|
| // Use of this source code is governed by a BSD-style license that can be
|
| // found in the LICENSE file.
|
|
|
| -#include "base/strings/string_number_conversions.h"
|
| +#include "chrome/browser/devtools/device/adb/mock_adb_server.h"
|
| #include "chrome/browser/devtools/device/devtools_android_bridge.h"
|
| +#include "chrome/browser/devtools/devtools_target_impl.h"
|
| #include "chrome/browser/ui/browser.h"
|
| #include "chrome/test/base/in_process_browser_test.h"
|
| #include "content/public/browser/browser_thread.h"
|
| -#include "content/public/test/browser_test.h"
|
| #include "content/public/test/test_utils.h"
|
| -#include "net/base/host_port_pair.h"
|
| -#include "net/base/io_buffer.h"
|
| -#include "net/base/ip_endpoint.h"
|
| -#include "net/base/net_errors.h"
|
| -#include "net/base/net_log.h"
|
| -#include "net/socket/stream_socket.h"
|
| -#include "net/socket/tcp_server_socket.h"
|
|
|
| -const char kOpenedUnixSocketsCommand[] = "shell:cat /proc/net/unix";
|
| -const char kDeviceModelCommand[] = "shell:getprop ro.product.model";
|
| -const char kDumpsysCommand[] = "shell:dumpsys window policy";
|
| -const char kListProcessesCommand[] = "shell:ps";
|
| -const char kInstalledChromePackagesCommand[] = "shell:pm list packages";
|
| -const char kDeviceModel[] = "Nexus 8";
|
| +using content::BrowserThread;
|
|
|
| -const char kSampleOpenedUnixSocketsWithoutBrowsers[] =
|
| - "Num RefCount Protocol Flags Type St Inode Path\n"
|
| - "00000000: 00000004 00000000"
|
| - " 00000000 0002 01 3328 /dev/socket/wpa_wlan0\n"
|
| - "00000000: 00000002 00000000"
|
| - " 00010000 0001 01 5394 /dev/socket/vold\n";
|
| -
|
| -const char kSampleDumpsys[] =
|
| - "WINDOW MANAGER POLICY STATE (dumpsys window policy)\r\n"
|
| - " mStable=(0,50)-(720,1184)\r\n";
|
| -
|
| -const char kSampleListProcesses[] =
|
| - "USER PID PPID VSIZE RSS WCHAN PC NAME\n"
|
| - "root 1 0 688 508 ffffffff 00000000 S /init\n";
|
| -
|
| -const char kSampleListPackages[] = "package:com.example.app";
|
| -
|
| -static const int kBufferSize = 16*1024;
|
| -static const int kAdbPort = 5037;
|
| -
|
| -static const int kAdbMessageHeaderSize = 4;
|
| -
|
| -// This is single connection server which listens on specified port and
|
| -// simplifies asynchronous IO.
|
| -// To write custom server, extend this class and implement TryProcessData
|
| -// method which is invoked everytime data arrives. In case of successful data
|
| -// processing(e.g. enough data collected already to parse client reply/request)
|
| -// return amount of bytes processed to throw them away from buffer
|
| -// To send data, SendData method should be used. This method is non-blocking
|
| -// and appends data to be sent to internal buffer.
|
| -// Since all calls are non-blocking and no callbacks are given, internal
|
| -// overflows may occur in case too heavy traffic.
|
| -// In case of heavy traffic performance may suffer because of memcpy calls.
|
| -class SingleConnectionServer {
|
| - public:
|
| - SingleConnectionServer(net::IPEndPoint endpoint, int buffer_size);
|
| - virtual ~SingleConnectionServer();
|
| -
|
| - protected:
|
| - virtual int TryProcessData(const char* data, int size) = 0;
|
| - void SendData(const char* data, int size);
|
| -
|
| -private:
|
| - void AcceptConnection();
|
| - void OnAccepted(int result);
|
| -
|
| - void ReadData();
|
| - void OnDataRead(int count);
|
| -
|
| - void WriteData();
|
| - void OnDataWritten(int count);
|
| -
|
| -private:
|
| - int bytes_to_write_;
|
| - scoped_ptr<net::TCPServerSocket> server_socket_;
|
| - scoped_ptr<net::StreamSocket> client_socket_;
|
| - scoped_refptr<net::GrowableIOBuffer> input_buffer_;
|
| - scoped_refptr<net::GrowableIOBuffer> output_buffer_;
|
| -
|
| - DISALLOW_COPY_AND_ASSIGN(SingleConnectionServer);
|
| -};
|
| -
|
| -SingleConnectionServer::SingleConnectionServer(net::IPEndPoint endpoint,
|
| - int buffer_size)
|
| - : bytes_to_write_(0) {
|
| - CHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
|
| -
|
| - input_buffer_ = new net::GrowableIOBuffer();
|
| - input_buffer_->SetCapacity(buffer_size);
|
| -
|
| - output_buffer_ = new net::GrowableIOBuffer();
|
| -
|
| - server_socket_.reset(new net::TCPServerSocket(NULL, net::NetLog::Source()));
|
| - server_socket_->Listen(endpoint, 1);
|
| -
|
| - AcceptConnection();
|
| -}
|
| -
|
| -SingleConnectionServer::~SingleConnectionServer() {
|
| - CHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
|
| -
|
| - server_socket_.reset();
|
| -
|
| - if (client_socket_) {
|
| - client_socket_->Disconnect();
|
| - client_socket_.reset();
|
| - }
|
| +static scoped_refptr<DevToolsAndroidBridge::RemoteBrowser>
|
| +FindBrowserByDisplayName(DevToolsAndroidBridge::RemoteBrowsers browsers,
|
| + const std::string& name) {
|
| + for (DevToolsAndroidBridge::RemoteBrowsers::iterator it = browsers.begin();
|
| + it != browsers.end(); ++it)
|
| + if ((*it)->display_name() == name)
|
| + return *it;
|
| + return NULL;
|
| }
|
|
|
| -void SingleConnectionServer::SendData(const char* data, int size) {
|
| - CHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
|
| -
|
| - if ((output_buffer_->offset() + bytes_to_write_ + size) >
|
| - output_buffer_->capacity()) {
|
| - // If not enough space without relocation
|
| - if (output_buffer_->capacity() < (bytes_to_write_ + size)) {
|
| - // If even buffer is not enough
|
| - int new_size = std::max(output_buffer_->capacity() * 2, size * 2);
|
| - output_buffer_->SetCapacity(new_size);
|
| - }
|
| - memmove(output_buffer_->StartOfBuffer(),
|
| - output_buffer_->data(),
|
| - bytes_to_write_);
|
| - output_buffer_->set_offset(0);
|
| - }
|
| -
|
| - memcpy(output_buffer_->data() + bytes_to_write_, data, size);
|
| - bytes_to_write_ += size;
|
| -
|
| - if (bytes_to_write_ == size)
|
| - // If write loop wasn't yet started, then start it
|
| - WriteData();
|
| -}
|
| -
|
| -void SingleConnectionServer::AcceptConnection() {
|
| - if (client_socket_) {
|
| - client_socket_->Disconnect();
|
| - client_socket_.reset();
|
| - }
|
| -
|
| - int accept_result = server_socket_->Accept(&client_socket_,
|
| - base::Bind(&SingleConnectionServer::OnAccepted, base::Unretained(this)));
|
| -
|
| - if (accept_result != net::ERR_IO_PENDING)
|
| - content::BrowserThread::PostTask(
|
| - content::BrowserThread::IO,
|
| - FROM_HERE,
|
| - base::Bind(&SingleConnectionServer::OnAccepted,
|
| - base::Unretained(this),
|
| - accept_result));
|
| -}
|
| -
|
| -void SingleConnectionServer::OnAccepted(int result) {
|
| - ASSERT_EQ(result, 0); // Fails if the socket is already in use.
|
| - ReadData();
|
| -}
|
| -
|
| -void SingleConnectionServer::ReadData() {
|
| - CHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
|
| -
|
| - if (input_buffer_->RemainingCapacity() == 0)
|
| - input_buffer_->SetCapacity(input_buffer_->capacity() * 2);
|
| -
|
| - int read_result = client_socket_->Read(
|
| - input_buffer_.get(),
|
| - input_buffer_->RemainingCapacity(),
|
| - base::Bind(&SingleConnectionServer::OnDataRead, base::Unretained(this)));
|
| -
|
| - if (read_result != net::ERR_IO_PENDING)
|
| - OnDataRead(read_result);
|
| -}
|
| -
|
| -void SingleConnectionServer::OnDataRead(int count) {
|
| - if (count <= 0) {
|
| - AcceptConnection();
|
| - return;
|
| - }
|
| -
|
| - input_buffer_->set_offset(input_buffer_->offset() + count);
|
| -
|
| - int bytes_processed;
|
| -
|
| - do {
|
| - char* data = input_buffer_->StartOfBuffer();
|
| - int data_size = input_buffer_->offset();
|
| -
|
| - bytes_processed = TryProcessData(data, data_size);
|
| -
|
| - if (bytes_processed) {
|
| - memmove(data, data + bytes_processed, data_size - bytes_processed);
|
| - input_buffer_->set_offset( data_size - bytes_processed);
|
| - }
|
| - } while (bytes_processed);
|
| -
|
| - // Posting is needed not to enter deep recursion in case too synchronous IO
|
| - content::BrowserThread::PostTask(content::BrowserThread::IO, FROM_HERE,
|
| - base::Bind(&SingleConnectionServer::ReadData, base::Unretained(this)));
|
| -}
|
| -
|
| -void SingleConnectionServer::WriteData() {
|
| - CHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
|
| - CHECK_GE(output_buffer_->capacity(),
|
| - output_buffer_->offset() + bytes_to_write_) << "Overflow";
|
| -
|
| - int write_result = client_socket_->Write(
|
| - output_buffer_,
|
| - bytes_to_write_,
|
| - base::Bind(&SingleConnectionServer::OnDataWritten,
|
| - base::Unretained(this)));
|
| - if (write_result != net::ERR_IO_PENDING)
|
| - OnDataWritten(write_result);
|
| -}
|
| -
|
| -void SingleConnectionServer::OnDataWritten(int count) {
|
| - CHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
|
| - if (count < 0) {
|
| - AcceptConnection();
|
| - return;
|
| - }
|
| -
|
| - CHECK_GT(count, 0);
|
| - CHECK_GE(output_buffer_->capacity(),
|
| - output_buffer_->offset() + bytes_to_write_) << "Overflow";
|
| -
|
| - bytes_to_write_ -= count;
|
| - output_buffer_->set_offset(output_buffer_->offset() + count);
|
| -
|
| - if (bytes_to_write_ != 0)
|
| - // Posting is needed not to enter deep recursion in case too synchronous IO
|
| - content::BrowserThread::PostTask(content::BrowserThread::IO, FROM_HERE,
|
| - base::Bind(&SingleConnectionServer::WriteData, base::Unretained(this)));
|
| -}
|
| -
|
| -
|
| -class MockAdbServer: public SingleConnectionServer {
|
| - public:
|
| - MockAdbServer(net::IPEndPoint endpoint, int buffer_size)
|
| - : SingleConnectionServer(endpoint, buffer_size)
|
| - {}
|
| -
|
| - virtual ~MockAdbServer() {}
|
| -
|
| - private:
|
| - virtual int TryProcessData(const char* data, int size) OVERRIDE {
|
| - CHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
|
| -
|
| - if (size >= kAdbMessageHeaderSize) {
|
| - std::string message_header(data, kAdbMessageHeaderSize);
|
| - int message_size;
|
| -
|
| - EXPECT_TRUE(base::HexStringToInt(message_header, &message_size));
|
| -
|
| - if (size >= message_size + kAdbMessageHeaderSize) {
|
| - std::string message_body(data + kAdbMessageHeaderSize, message_size );
|
| -
|
| - ProcessCommand(message_body);
|
| -
|
| - return kAdbMessageHeaderSize + message_size;
|
| - }
|
| - }
|
| -
|
| - return 0;
|
| - }
|
| -
|
| - void ProcessCommand(const std::string& command) {
|
| - CHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
|
| -
|
| - if (command == "host:devices") {
|
| - SendResponse("01498B321301A00A\tdevice\n01498B2B0D01300E\toffline");
|
| - } else if (command == "host:transport:01498B321301A00A") {
|
| - SendResponse("");
|
| - } else if (command == kDeviceModelCommand) {
|
| - SendResponse(kDeviceModel);
|
| - } else if (command == kOpenedUnixSocketsCommand) {
|
| - SendResponse(kSampleOpenedUnixSocketsWithoutBrowsers);
|
| - } else if (command == kDumpsysCommand) {
|
| - SendResponse(kSampleDumpsys);
|
| - } else if (command == kListProcessesCommand) {
|
| - SendResponse(kSampleListProcesses);
|
| - } else if (command == kInstalledChromePackagesCommand) {
|
| - SendResponse(kSampleListPackages);
|
| - } else {
|
| - NOTREACHED() << "Unknown command - " << command;
|
| - }
|
| - }
|
| -
|
| - void SendResponse(const std::string& response) {
|
| - DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
|
| -
|
| - std::stringstream response_stream;
|
| - response_stream << "OKAY";
|
| -
|
| - int size = response.size();
|
| - if (size > 0) {
|
| - static const char kHexChars[] = "0123456789ABCDEF";
|
| - for (int i = 3; i >= 0; i--)
|
| - response_stream << kHexChars[ (size >> 4*i) & 0x0f ];
|
| - response_stream << response;
|
| - }
|
| -
|
| - std::string response_data = response_stream.str();
|
| - SendData(response_data.c_str(), response_data.size());
|
| - }
|
| -};
|
| -
|
| class AdbClientSocketTest : public InProcessBrowserTest,
|
| public DevToolsAndroidBridge::DeviceListListener {
|
|
|
| -public:
|
| + public:
|
| void StartTest() {
|
| - DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
|
| -
|
| - content::BrowserThread::PostTaskAndReply(
|
| - content::BrowserThread::IO,
|
| - FROM_HERE,
|
| - base::Bind(&AdbClientSocketTest::StartMockAdbServer,
|
| - base::Unretained(this)),
|
| - base::Bind(&AdbClientSocketTest::AddListener,
|
| - base::Unretained(this)));
|
| + Profile* profile = browser()->profile();
|
| + android_bridge_ = DevToolsAndroidBridge::Factory::GetForProfile(profile);
|
| + AndroidDeviceManager::DeviceProviders device_providers;
|
| + device_providers.push_back(AndroidDeviceManager::GetAdbDeviceProvider());
|
| + android_bridge_->set_device_providers_for_test(device_providers);
|
| + android_bridge_->AddDeviceListListener(this);
|
| }
|
|
|
| virtual void DeviceListChanged(
|
| const DevToolsAndroidBridge::RemoteDevices& devices) OVERRIDE {
|
| - DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
|
| - android_bridge_->RemoveDeviceListListener(this);
|
| devices_ = devices;
|
| - EndTest();
|
| + android_bridge_->RemoveDeviceListListener(this);
|
| + base::MessageLoop::current()->Quit();
|
| }
|
|
|
| void CheckDevices() {
|
| ASSERT_EQ(2U, devices_.size());
|
|
|
| - scoped_refptr<DevToolsAndroidBridge::RemoteDevice> online_device_;
|
| - scoped_refptr<DevToolsAndroidBridge::RemoteDevice> offline_device_;
|
| + scoped_refptr<DevToolsAndroidBridge::RemoteDevice> connected =
|
| + devices_[0]->is_connected() ? devices_[0] : devices_[1];
|
|
|
| - for (DevToolsAndroidBridge::RemoteDevices::const_iterator it =
|
| - devices_.begin(); it != devices_.end(); ++it) {
|
| - if ((*it)->serial() == "01498B321301A00A")
|
| - online_device_ = *it;
|
| - else if ((*it)->serial() == "01498B2B0D01300E")
|
| - offline_device_ = *it;
|
| - }
|
| + scoped_refptr<DevToolsAndroidBridge::RemoteDevice> not_connected =
|
| + devices_[0]->is_connected() ? devices_[1] : devices_[0];
|
|
|
| - ASSERT_EQ(online_device_->serial(), "01498B321301A00A");
|
| - ASSERT_TRUE(online_device_->is_connected());
|
| - ASSERT_FALSE(offline_device_->is_connected());
|
| + ASSERT_TRUE(connected->is_connected());
|
| + ASSERT_FALSE(not_connected->is_connected());
|
|
|
| - ASSERT_EQ(online_device_->model(), kDeviceModel);
|
| - ASSERT_EQ(online_device_->browsers().size(), 0U);
|
| - ASSERT_EQ(online_device_->screen_size(), gfx::Size(720, 1184));
|
| - }
|
| + ASSERT_EQ(720, connected->screen_size().width());
|
| + ASSERT_EQ(1184, connected->screen_size().height());
|
|
|
| -private:
|
| - void EndTest() {
|
| - DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
|
| - android_bridge_ = NULL;
|
| + ASSERT_EQ("01498B321301A00A", connected->serial());
|
| + ASSERT_EQ("Nexus 6", connected->model());
|
|
|
| - content::BrowserThread::PostTaskAndReply(
|
| - content::BrowserThread::IO,
|
| - FROM_HERE,
|
| - base::Bind(&AdbClientSocketTest::StopMockAdbServer,
|
| - base::Unretained(this)),
|
| - base::Bind(&AdbClientSocketTest::StopMessageLoop,
|
| - base::Unretained(this)));
|
| - }
|
| + ASSERT_EQ("01498B2B0D01300E", not_connected->serial());
|
| + ASSERT_EQ("Offline", not_connected->model());
|
|
|
| - void StartMockAdbServer() {
|
| - DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
|
| - net::IPAddressNumber address;
|
| - net::ParseIPLiteralToNumber("127.0.0.1", &address);
|
| - net::IPEndPoint endpoint(address, kAdbPort);
|
| + const DevToolsAndroidBridge::RemoteBrowsers& browsers =
|
| + connected->browsers();
|
| + ASSERT_EQ(4U, browsers.size());
|
|
|
| - adb_server_.reset(new MockAdbServer(endpoint, kBufferSize));
|
| - }
|
| + scoped_refptr<DevToolsAndroidBridge::RemoteBrowser> chrome =
|
| + FindBrowserByDisplayName(browsers, "Chrome");
|
| + ASSERT_TRUE(chrome);
|
|
|
| - void StopMockAdbServer() {
|
| - DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
|
| - adb_server_.reset();
|
| - }
|
| + scoped_refptr<DevToolsAndroidBridge::RemoteBrowser> chrome_beta =
|
| + FindBrowserByDisplayName(browsers, "Chrome Beta");
|
| + ASSERT_TRUE(chrome_beta);
|
|
|
| - void StopMessageLoop() {
|
| - DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
|
| - runner->Quit();
|
| - }
|
| + scoped_refptr<DevToolsAndroidBridge::RemoteBrowser> chromium =
|
| + FindBrowserByDisplayName(browsers, "Chromium");
|
| + ASSERT_FALSE(chromium);
|
|
|
| - void AddListener() {
|
| - DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
|
| - android_bridge_ = DevToolsAndroidBridge::Factory::GetForProfile(
|
| - browser()->profile());
|
| + scoped_refptr<DevToolsAndroidBridge::RemoteBrowser> webview =
|
| + FindBrowserByDisplayName(browsers, "WebView in com.sample.feed");
|
| + ASSERT_TRUE(webview);
|
|
|
| - AndroidDeviceManager::DeviceProviders device_providers;
|
| - device_providers.push_back(AndroidDeviceManager::GetAdbDeviceProvider());
|
| + scoped_refptr<DevToolsAndroidBridge::RemoteBrowser> noprocess =
|
| + FindBrowserByDisplayName(browsers, "Noprocess");
|
| + ASSERT_TRUE(noprocess);
|
|
|
| - android_bridge_->set_device_providers_for_test(device_providers);
|
| - android_bridge_->AddDeviceListListener(this);
|
| - }
|
| + ASSERT_EQ("32.0.1679.0", chrome->version());
|
| + ASSERT_EQ("31.0.1599.0", chrome_beta->version());
|
| + ASSERT_EQ("4.0", webview->version());
|
| +
|
| + std::vector<DevToolsTargetImpl*> chrome_pages =
|
| + chrome->CreatePageTargets();
|
| + std::vector<DevToolsTargetImpl*> chrome_beta_pages =
|
| + chrome_beta->CreatePageTargets();
|
| + std::vector<DevToolsTargetImpl*> webview_pages =
|
| + webview->CreatePageTargets();
|
| +
|
| + ASSERT_EQ(1U, chrome_pages.size());
|
| + ASSERT_EQ(0U, chrome_beta_pages.size());
|
| + ASSERT_EQ(2U, webview_pages.size());
|
| +
|
| + // Check that we have non-empty description for webview pages.
|
| + ASSERT_EQ(0U, chrome_pages[0]->GetDescription().size());
|
| + ASSERT_NE(0U, webview_pages[0]->GetDescription().size());
|
| + ASSERT_NE(0U, webview_pages[1]->GetDescription().size());
|
|
|
| -public:
|
| - scoped_refptr<content::MessageLoopRunner> runner;
|
| + ASSERT_EQ(GURL("http://www.chromium.org/"), chrome_pages[0]->GetUrl());
|
| + ASSERT_EQ("The Chromium Projects", chrome_pages[0]->GetTitle());
|
|
|
| -private:
|
| - scoped_ptr<MockAdbServer> adb_server_;
|
| + STLDeleteElements(&chrome_pages);
|
| + STLDeleteElements(&webview_pages);
|
| + }
|
| +
|
| + private:
|
| scoped_refptr<DevToolsAndroidBridge> android_bridge_;
|
| DevToolsAndroidBridge::RemoteDevices devices_;
|
| };
|
|
|
| IN_PROC_BROWSER_TEST_F(AdbClientSocketTest, TestAdbClientSocket) {
|
| - CHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
|
| - runner = new content::MessageLoopRunner;
|
| -
|
| + StartMockAdbServer();
|
| StartTest();
|
| -
|
| - runner->Run();
|
| -
|
| + content::RunMessageLoop();
|
| CheckDevices();
|
| + StopMockAdbServer();
|
| }
|
|
|