OLD | NEW |
---|---|
(Empty) | |
1 // Copyright (c) 2013 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/strings/string_number_conversions.h" | |
6 #include "chrome/browser/devtools/android_device.h" | |
7 #include "chrome/browser/ui/browser.h" | |
8 #include "chrome/test/base/in_process_browser_test.h" | |
9 #include "content/public/browser/browser_thread.h" | |
10 #include "content/public/test/browser_test.h" | |
11 #include "content/public/test/test_utils.h" | |
12 #include "net/base/host_port_pair.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/base/net_log.h" | |
17 #include "net/socket/stream_socket.h" | |
18 #include "net/socket/tcp_server_socket.h" | |
19 | |
20 using namespace net; | |
21 | |
22 static const char kDeviceModelCommand[] = "shell:getprop ro.product.model"; | |
23 static const char kDeviceModel[] = "Nexus 8"; | |
24 | |
25 static const int kBufferSize = 16*1024; | |
26 static const int kAdbPort = 5037; | |
27 | |
28 static const int kAdbMessageHeaderSize = 4; | |
29 | |
30 class AdbClientSocketTest : public InProcessBrowserTest { | |
31 public: | |
32 AdbClientSocketTest() { | |
33 input_buffer_ = new net::GrowableIOBuffer(); | |
34 input_buffer_->SetCapacity(kBufferSize); | |
35 | |
36 output_buffer_ = new net::GrowableIOBuffer(); | |
37 | |
38 } | |
39 | |
40 void InitServerSocket() { | |
41 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO)); | |
42 | |
43 IPAddressNumber address; | |
44 ParseIPLiteralToNumber("127.0.0.1", &address); | |
45 | |
46 IPEndPoint endpoint(address, kAdbPort); | |
47 | |
48 server_socket_.reset(new TCPServerSocket(NULL, NetLog::Source())); | |
49 server_socket_->Listen(endpoint, 2); | |
50 AcceptConnection(); | |
51 | |
52 content::BrowserThread::PostTask( | |
53 content::BrowserThread::UI, FROM_HERE, | |
54 base::Bind(&AdbClientSocketTest::StartTest, | |
55 base::Unretained(this))); | |
56 } | |
57 | |
58 private: | |
59 void StartTest() { | |
60 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); | |
61 | |
62 adb_thread_ = RefCountedAdbThread::GetInstance(); | |
63 | |
64 adb_provider_ = AndroidDeviceProvider::GetAdbDeviceProvider(); | |
65 adb_provider_->QueryDevices( | |
66 base::Bind(&AdbClientSocketTest::AdbDevicesReceived, | |
67 base::Unretained(this))); | |
68 } | |
69 | |
70 void AdbDevicesReceived( | |
71 const AndroidDeviceProvider::AndroidDevices& received_devices) { | |
72 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); | |
73 #if defined(DEBUG_DEVTOOLS) | |
74 // Mock device is added | |
75 ASSERT_EQ(2U, received_devices.size()); | |
76 #else | |
77 ASSERT_EQ(1U, received_devices.size()); | |
78 #endif | |
79 android_device_ = received_devices.back(); | |
80 ASSERT_EQ(android_device_->serial(), "1498B321301A00A"); | |
Vladislav Kaznacheev
2013/10/25 15:18:19
lets test "offline" device as well
this will proba
Dmitry Zvorygin
2013/10/28 14:00:16
Done.
| |
81 ASSERT_TRUE(android_device_->is_connected()); | |
82 | |
Vladislav Kaznacheev
2013/10/25 15:18:19
extra blank line
Dmitry Zvorygin
2013/10/28 14:00:16
Done.
| |
83 | |
84 adb_thread_->message_loop()->PostTask( | |
85 FROM_HERE, | |
86 base::Bind(&AndroidDevice::RunCommand, | |
87 android_device_, | |
88 kDeviceModelCommand, | |
89 base::Bind(&AdbClientSocketTest::AdbDeviceModelReceived, | |
90 base::Unretained(this)))); | |
91 } | |
92 | |
93 void AdbDeviceModelReceived(int result_code, const std::string& model) { | |
94 DCHECK_EQ(adb_thread_->message_loop(), base::MessageLoop::current()); | |
95 ASSERT_EQ(result_code, 0); | |
96 ASSERT_EQ(model, kDeviceModel); | |
97 EndTest(); | |
98 } | |
99 | |
100 void EndTest() { | |
101 content::BrowserThread::PostTask( | |
102 content::BrowserThread::IO, FROM_HERE, | |
103 base::Bind(&AdbClientSocketTest::ShutDownSockets, | |
104 base::Unretained(this))); | |
105 } | |
106 | |
107 void ShutDownSockets() { | |
108 server_socket_.reset(); | |
109 | |
110 if (client_socket_) { | |
111 client_socket_->Disconnect(); | |
112 client_socket_.reset(); | |
113 } | |
114 | |
115 content::BrowserThread::PostTask( | |
116 content::BrowserThread::UI, FROM_HERE, | |
117 base::Bind(&content::MessageLoopRunner::Quit, runner)); | |
118 } | |
119 | |
120 // Adb server implementation | |
Vladislav Kaznacheev
2013/10/25 15:18:19
Please extract a separate class for the server. Yo
Dmitry Zvorygin
2013/10/28 14:00:16
Done.
| |
121 | |
122 void AcceptConnection() { | |
123 if (client_socket_) { | |
124 client_socket_->Disconnect(); | |
125 client_socket_.reset(); | |
126 } | |
127 | |
128 int accept_result = server_socket_->Accept(&client_socket_, | |
129 base::Bind(&AdbClientSocketTest::OnAccepted, base::Unretained(this))); | |
130 if (accept_result != ERR_IO_PENDING) | |
131 OnAccepted(accept_result); | |
132 } | |
133 | |
134 void OnAccepted(int result) { | |
135 ASSERT_EQ(result, 0); | |
136 ReadData(); | |
137 } | |
138 | |
139 void ReadData() { | |
140 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO)); | |
141 | |
142 int read_result = client_socket_->Read( | |
143 input_buffer_.get(), | |
144 input_buffer_->RemainingCapacity(), | |
145 base::Bind(&AdbClientSocketTest::OnDataRead, base::Unretained(this))); | |
146 | |
147 if (read_result != ERR_IO_PENDING) | |
148 OnDataRead(read_result); | |
149 } | |
150 | |
151 void OnDataRead(int count) { | |
152 if (count <= 0) { | |
153 AcceptConnection(); | |
154 return; | |
155 } | |
156 | |
157 input_buffer_->set_offset(input_buffer_->offset() + count); | |
158 | |
159 if (!TryProcessCommand()) { | |
160 // Posting is needed not to enter deep recursion in case too synchronous | |
161 // replies. | |
162 content::BrowserThread::PostTask( content::BrowserThread::IO, FROM_HERE, | |
163 base::Bind(&AdbClientSocketTest::ReadData, base::Unretained(this))); | |
164 } | |
165 } | |
166 | |
167 void WriteData() { | |
168 ASSERT_NE(output_buffer_->offset(), output_buffer_->capacity()); | |
169 int write_result = client_socket_->Write( | |
170 output_buffer_, | |
171 output_buffer_->capacity() - output_buffer_->offset(), | |
172 base::Bind(&AdbClientSocketTest::OnDataWritten, | |
173 base::Unretained(this))); | |
174 if (write_result != ERR_IO_PENDING) | |
175 OnDataWritten(write_result); | |
176 } | |
177 | |
178 void OnDataWritten(int count) { | |
179 if (count < 0) { | |
180 AcceptConnection(); | |
181 return; | |
182 } | |
183 | |
184 ASSERT_TRUE(count > 0); | |
185 ASSERT_TRUE(output_buffer_->offset() + count <= output_buffer_->capacity()); | |
186 | |
187 output_buffer_->set_offset(output_buffer_->offset() + count); | |
188 if (output_buffer_->offset() != output_buffer_->capacity()) | |
189 WriteData(); | |
190 else if (!TryProcessCommand()) | |
191 ReadData(); | |
192 } | |
193 | |
194 bool TryProcessCommand() { | |
195 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO)); | |
196 char* data = input_buffer_->StartOfBuffer(); | |
197 int data_size = input_buffer_->offset(); | |
198 | |
199 if (data_size >= kAdbMessageHeaderSize) { | |
200 std::string message_header(data, kAdbMessageHeaderSize); | |
201 int message_size; | |
202 | |
203 EXPECT_TRUE(base::HexStringToInt(message_header, &message_size)); | |
204 | |
205 if (data_size >= message_size + kAdbMessageHeaderSize) { | |
206 std::string message_body(data + kAdbMessageHeaderSize, message_size ); | |
207 | |
208 memmove(data, data + message_size, | |
209 data_size - message_size - kAdbMessageHeaderSize); | |
210 input_buffer_->set_offset( | |
211 data_size - message_size - kAdbMessageHeaderSize); | |
212 | |
213 ProcessCommand(message_body); | |
214 | |
215 return true; | |
216 } | |
217 } | |
218 | |
219 return false; | |
220 } | |
221 | |
222 void ProcessCommand(const std::string& command) { | |
223 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO)); | |
224 | |
225 if (command == "host:devices") { | |
226 SendResponse("1498B321301A00A\tdevice"); | |
227 } else if (command == "host:transport:1498B321301A00A") { | |
228 SendResponse(""); | |
229 } else if (command == kDeviceModelCommand) { | |
230 SendResponse(kDeviceModel); | |
231 } else { | |
232 NOTREACHED() << "Unknown command - " << command; | |
233 } | |
234 } | |
235 | |
236 void SendResponse(const std::string& response) { | |
237 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO)); | |
238 | |
239 std::stringstream response_stream; | |
240 response_stream << "OKAY"; | |
241 | |
242 int size = response.size(); | |
243 if (size > 0) { | |
244 static const char kHexChars[] = "0123456789ABCDEF"; | |
245 for (int i = 3; i >= 0; i--) | |
246 response_stream << kHexChars[ (size >> 4*i) & 0x0f ]; | |
247 response_stream << response; | |
248 } | |
249 | |
250 std::string response_data = response_stream.str(); | |
251 | |
252 output_buffer_->SetCapacity(response_data.size()); | |
253 output_buffer_->set_offset(0); | |
254 mempcpy(output_buffer_->StartOfBuffer(), response_data.c_str(), | |
255 response_data.size()); | |
256 WriteData(); | |
257 } | |
258 | |
259 public: | |
260 scoped_refptr<content::MessageLoopRunner> runner; | |
261 | |
262 private: | |
263 scoped_refptr<RefCountedAdbThread> adb_thread_; | |
264 scoped_refptr<AndroidDeviceProvider> adb_provider_; | |
265 scoped_refptr<AndroidDevice> android_device_; | |
266 scoped_ptr<TCPServerSocket> server_socket_; | |
267 scoped_ptr<StreamSocket> client_socket_; | |
268 scoped_refptr<net::GrowableIOBuffer> input_buffer_; | |
269 scoped_refptr<net::GrowableIOBuffer> output_buffer_; | |
270 }; | |
271 | |
272 IN_PROC_BROWSER_TEST_F(AdbClientSocketTest, TestAdbClientSocket) { | |
273 runner = new content::MessageLoopRunner; | |
274 | |
275 content::BrowserThread::PostTask( | |
276 content::BrowserThread::IO, FROM_HERE, | |
277 base::Bind(&AdbClientSocketTest::InitServerSocket, | |
278 base::Unretained(this))); | |
279 | |
280 runner->Run(); | |
281 } | |
OLD | NEW |