blob: ddd3ff0417a86e18f94aaa1dfa2ce3622cce60cf [file] [log] [blame]
Dan Albert8e1fdd72015-07-24 17:08:33 -07001#!/usr/bin/env python
2#
3# Copyright (C) 2015 The Android Open Source Project
4#
5# Licensed under the Apache License, Version 2.0 (the "License");
6# you may not use this file except in compliance with the License.
7# You may obtain a copy of the License at
8#
9# http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS,
13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14# See the License for the specific language governing permissions and
15# limitations under the License.
16#
17"""Tests for the adb program itself.
18
19This differs from things in test_device.py in that there is no API for these
20things. Most of these tests involve specific error messages or the help text.
21"""
22from __future__ import print_function
23
Luis Hector Chavez8b67c522018-04-17 19:25:33 -070024import binascii
Spencer Low351ecd12015-10-14 17:32:44 -070025import contextlib
Spencer Low1ce06082015-09-16 20:45:53 -070026import os
Dan Albert8e1fdd72015-07-24 17:08:33 -070027import random
Luis Hector Chavez8b67c522018-04-17 19:25:33 -070028import select
Spencer Low351ecd12015-10-14 17:32:44 -070029import socket
30import struct
Dan Albert8e1fdd72015-07-24 17:08:33 -070031import subprocess
Spencer Low1ce06082015-09-16 20:45:53 -070032import threading
Dan Albert8e1fdd72015-07-24 17:08:33 -070033import unittest
34
35import adb
36
37
Luis Hector Chavez8b67c522018-04-17 19:25:33 -070038@contextlib.contextmanager
Luis Hector Chavezfbee0a92018-05-02 09:10:29 -070039def fake_adbd(protocol=socket.AF_INET, port=0):
40 """Creates a fake ADB daemon that just replies with a CNXN packet."""
Luis Hector Chavez8b67c522018-04-17 19:25:33 -070041
42 serversock = socket.socket(protocol, socket.SOCK_STREAM)
Luis Hector Chavezfbee0a92018-05-02 09:10:29 -070043 serversock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
Luis Hector Chavez8b67c522018-04-17 19:25:33 -070044 if protocol == socket.AF_INET:
45 serversock.bind(('127.0.0.1', port))
46 else:
47 serversock.bind(('::1', port))
48 serversock.listen(1)
49
50 # A pipe that is used to signal the thread that it should terminate.
51 readpipe, writepipe = os.pipe()
52
Luis Hector Chavez56fe7532018-04-17 14:25:04 -070053 def _adb_packet(command, arg0, arg1, data):
54 bin_command = struct.unpack('I', command)[0]
55 buf = struct.pack('IIIIII', bin_command, arg0, arg1, len(data), 0,
56 bin_command ^ 0xffffffff)
57 buf += data
58 return buf
59
Luis Hector Chavez8b67c522018-04-17 19:25:33 -070060 def _handle():
61 rlist = [readpipe, serversock]
Luis Hector Chavez56fe7532018-04-17 14:25:04 -070062 cnxn_sent = {}
Luis Hector Chavez8b67c522018-04-17 19:25:33 -070063 while True:
Luis Hector Chavezfbee0a92018-05-02 09:10:29 -070064 read_ready, _, _ = select.select(rlist, [], [])
65 for ready in read_ready:
66 if ready == readpipe:
Luis Hector Chavez8b67c522018-04-17 19:25:33 -070067 # Closure pipe
Luis Hector Chavezfbee0a92018-05-02 09:10:29 -070068 os.close(ready)
Luis Hector Chavez8b67c522018-04-17 19:25:33 -070069 serversock.shutdown(socket.SHUT_RDWR)
70 serversock.close()
71 return
Luis Hector Chavezfbee0a92018-05-02 09:10:29 -070072 elif ready == serversock:
Luis Hector Chavez8b67c522018-04-17 19:25:33 -070073 # Server socket
Luis Hector Chavezfbee0a92018-05-02 09:10:29 -070074 conn, _ = ready.accept()
Luis Hector Chavez8b67c522018-04-17 19:25:33 -070075 rlist.append(conn)
76 else:
77 # Client socket
Luis Hector Chavezfbee0a92018-05-02 09:10:29 -070078 data = ready.recv(1024)
Luis Hector Chavez454bc7c2018-04-20 10:31:29 -070079 if not data or data.startswith('OPEN'):
Luis Hector Chavezfbee0a92018-05-02 09:10:29 -070080 if ready in cnxn_sent:
81 del cnxn_sent[ready]
82 ready.shutdown(socket.SHUT_RDWR)
83 ready.close()
84 rlist.remove(ready)
Luis Hector Chavez56fe7532018-04-17 14:25:04 -070085 continue
Luis Hector Chavezfbee0a92018-05-02 09:10:29 -070086 if ready in cnxn_sent:
Luis Hector Chavez56fe7532018-04-17 14:25:04 -070087 continue
Luis Hector Chavezfbee0a92018-05-02 09:10:29 -070088 cnxn_sent[ready] = True
89 ready.sendall(_adb_packet('CNXN', 0x01000001, 1024 * 1024,
90 'device::ro.product.name=fakeadb'))
Luis Hector Chavez8b67c522018-04-17 19:25:33 -070091
92 port = serversock.getsockname()[1]
93 server_thread = threading.Thread(target=_handle)
94 server_thread.start()
95
96 try:
97 yield port
98 finally:
99 os.close(writepipe)
100 server_thread.join()
101
102
Luis Hector Chavez454bc7c2018-04-20 10:31:29 -0700103@contextlib.contextmanager
104def adb_connect(unittest, serial):
105 """Context manager for an ADB connection.
106
107 This automatically disconnects when done with the connection.
108 """
109
110 output = subprocess.check_output(['adb', 'connect', serial])
111 unittest.assertEqual(output.strip(), 'connected to {}'.format(serial))
112
113 try:
114 yield
115 finally:
116 # Perform best-effort disconnection. Discard the output.
Luis Hector Chavezfbee0a92018-05-02 09:10:29 -0700117 subprocess.Popen(['adb', 'disconnect', serial],
118 stdout=subprocess.PIPE,
119 stderr=subprocess.PIPE).communicate()
Luis Hector Chavez454bc7c2018-04-20 10:31:29 -0700120
121
Luis Hector Chavez32559742018-05-02 10:47:01 -0700122@contextlib.contextmanager
123def adb_server():
124 """Context manager for an ADB server.
125
126 This creates an ADB server and returns the port it's listening on.
127 """
128
129 port = 5038
130 # Kill any existing server on this non-default port.
131 subprocess.check_output(['adb', '-P', str(port), 'kill-server'],
132 stderr=subprocess.STDOUT)
133 read_pipe, write_pipe = os.pipe()
134 proc = subprocess.Popen(['adb', '-L', 'tcp:localhost:{}'.format(port),
135 'fork-server', 'server',
136 '--reply-fd', str(write_pipe)])
137 try:
138 os.close(write_pipe)
139 greeting = os.read(read_pipe, 1024)
140 assert greeting == 'OK\n', repr(greeting)
141 yield port
142 finally:
143 proc.terminate()
144 proc.wait()
145
146
Luis Hector Chavezfbee0a92018-05-02 09:10:29 -0700147class CommandlineTest(unittest.TestCase):
148 """Tests for the ADB commandline."""
Dan Albert8e1fdd72015-07-24 17:08:33 -0700149
150 def test_help(self):
151 """Make sure we get _something_ out of help."""
152 out = subprocess.check_output(
153 ['adb', 'help'], stderr=subprocess.STDOUT)
154 self.assertGreater(len(out), 0)
155
156 def test_version(self):
157 """Get a version number out of the output of adb."""
158 lines = subprocess.check_output(['adb', 'version']).splitlines()
159 version_line = lines[0]
160 self.assertRegexpMatches(
161 version_line, r'^Android Debug Bridge version \d+\.\d+\.\d+$')
162 if len(lines) == 2:
163 # Newer versions of ADB have a second line of output for the
164 # version that includes a specific revision (git SHA).
165 revision_line = lines[1]
166 self.assertRegexpMatches(
167 revision_line, r'^Revision [0-9a-f]{12}-android$')
168
169 def test_tcpip_error_messages(self):
Luis Hector Chavezfbee0a92018-05-02 09:10:29 -0700170 """Make sure 'adb tcpip' parsing is sane."""
171 proc = subprocess.Popen(['adb', 'tcpip'], stdout=subprocess.PIPE,
172 stderr=subprocess.STDOUT)
173 out, _ = proc.communicate()
174 self.assertEqual(1, proc.returncode)
Elliott Hughese1632982017-08-23 15:42:28 -0700175 self.assertIn('requires an argument', out)
Dan Albert8e1fdd72015-07-24 17:08:33 -0700176
Luis Hector Chavezfbee0a92018-05-02 09:10:29 -0700177 proc = subprocess.Popen(['adb', 'tcpip', 'foo'], stdout=subprocess.PIPE,
178 stderr=subprocess.STDOUT)
179 out, _ = proc.communicate()
180 self.assertEqual(1, proc.returncode)
Elliott Hughese1632982017-08-23 15:42:28 -0700181 self.assertIn('invalid port', out)
Dan Albert8e1fdd72015-07-24 17:08:33 -0700182
Luis Hector Chavezfbee0a92018-05-02 09:10:29 -0700183
184class ServerTest(unittest.TestCase):
185 """Tests for the ADB server."""
186
187 @staticmethod
188 def _read_pipe_and_set_event(pipe, event):
189 """Reads a pipe until it is closed, then sets the event."""
190 pipe.read()
Spencer Low1ce06082015-09-16 20:45:53 -0700191 event.set()
192
Spencer Low1ce06082015-09-16 20:45:53 -0700193 def test_handle_inheritance(self):
Luis Hector Chavezfbee0a92018-05-02 09:10:29 -0700194 """Test that launch_server() does not inherit handles.
195
196 launch_server() should not let the adb server inherit
197 stdin/stdout/stderr handles, which can cause callers of adb.exe to hang.
198 This test also runs fine on unix even though the impetus is an issue
199 unique to Windows.
200 """
Spencer Low1ce06082015-09-16 20:45:53 -0700201 # This test takes 5 seconds to run on Windows: if there is no adb server
202 # running on the the port used below, adb kill-server tries to make a
203 # TCP connection to a closed port and that takes 1 second on Windows;
204 # adb start-server does the same TCP connection which takes another
205 # second, and it waits 3 seconds after starting the server.
206
207 # Start adb client with redirected stdin/stdout/stderr to check if it
208 # passes those redirections to the adb server that it starts. To do
209 # this, run an instance of the adb server on a non-default port so we
210 # don't conflict with a pre-existing adb server that may already be
211 # setup with adb TCP/emulator connections. If there is a pre-existing
212 # adb server, this also tests whether multiple instances of the adb
213 # server conflict on adb.log.
214
215 port = 5038
216 # Kill any existing server on this non-default port.
217 subprocess.check_output(['adb', '-P', str(port), 'kill-server'],
218 stderr=subprocess.STDOUT)
219
220 try:
221 # Run the adb client and have it start the adb server.
Luis Hector Chavezfbee0a92018-05-02 09:10:29 -0700222 proc = subprocess.Popen(['adb', '-P', str(port), 'start-server'],
223 stdin=subprocess.PIPE,
224 stdout=subprocess.PIPE,
225 stderr=subprocess.PIPE)
Spencer Low1ce06082015-09-16 20:45:53 -0700226
227 # Start threads that set events when stdout/stderr are closed.
228 stdout_event = threading.Event()
229 stdout_thread = threading.Thread(
Luis Hector Chavezfbee0a92018-05-02 09:10:29 -0700230 target=ServerTest._read_pipe_and_set_event,
231 args=(proc.stdout, stdout_event))
Spencer Low1ce06082015-09-16 20:45:53 -0700232 stdout_thread.daemon = True
233 stdout_thread.start()
234
235 stderr_event = threading.Event()
236 stderr_thread = threading.Thread(
Luis Hector Chavezfbee0a92018-05-02 09:10:29 -0700237 target=ServerTest._read_pipe_and_set_event,
238 args=(proc.stderr, stderr_event))
Spencer Low1ce06082015-09-16 20:45:53 -0700239 stderr_thread.daemon = True
240 stderr_thread.start()
241
242 # Wait for the adb client to finish. Once that has occurred, if
243 # stdin/stderr/stdout are still open, it must be open in the adb
244 # server.
Luis Hector Chavezfbee0a92018-05-02 09:10:29 -0700245 proc.wait()
Spencer Low1ce06082015-09-16 20:45:53 -0700246
247 # Try to write to stdin which we expect is closed. If it isn't
248 # closed, we should get an IOError. If we don't get an IOError,
249 # stdin must still be open in the adb server. The adb client is
250 # probably letting the adb server inherit stdin which would be
251 # wrong.
252 with self.assertRaises(IOError):
Luis Hector Chavezfbee0a92018-05-02 09:10:29 -0700253 proc.stdin.write('x')
Spencer Low1ce06082015-09-16 20:45:53 -0700254
255 # Wait a few seconds for stdout/stderr to be closed (in the success
256 # case, this won't wait at all). If there is a timeout, that means
257 # stdout/stderr were not closed and and they must be open in the adb
258 # server, suggesting that the adb client is letting the adb server
259 # inherit stdout/stderr which would be wrong.
260 self.assertTrue(stdout_event.wait(5), "adb stdout not closed")
261 self.assertTrue(stderr_event.wait(5), "adb stderr not closed")
262 finally:
263 # If we started a server, kill it.
264 subprocess.check_output(['adb', '-P', str(port), 'kill-server'],
265 stderr=subprocess.STDOUT)
Dan Albert8e1fdd72015-07-24 17:08:33 -0700266
Luis Hector Chavezfbee0a92018-05-02 09:10:29 -0700267
268class EmulatorTest(unittest.TestCase):
269 """Tests for the emulator connection."""
270
Spencer Low351ecd12015-10-14 17:32:44 -0700271 def _reset_socket_on_close(self, sock):
Luis Hector Chavezfbee0a92018-05-02 09:10:29 -0700272 """Use SO_LINGER to cause TCP RST segment to be sent on socket close."""
Spencer Low351ecd12015-10-14 17:32:44 -0700273 # The linger structure is two shorts on Windows, but two ints on Unix.
274 linger_format = 'hh' if os.name == 'nt' else 'ii'
275 l_onoff = 1
276 l_linger = 0
277
278 sock.setsockopt(socket.SOL_SOCKET, socket.SO_LINGER,
279 struct.pack(linger_format, l_onoff, l_linger))
280 # Verify that we set the linger structure properly by retrieving it.
281 linger = sock.getsockopt(socket.SOL_SOCKET, socket.SO_LINGER, 16)
282 self.assertEqual((l_onoff, l_linger),
283 struct.unpack_from(linger_format, linger))
284
285 def test_emu_kill(self):
286 """Ensure that adb emu kill works.
287
288 Bug: https://code.google.com/p/android/issues/detail?id=21021
289 """
Spencer Low351ecd12015-10-14 17:32:44 -0700290 with contextlib.closing(
Luis Hector Chavezfbee0a92018-05-02 09:10:29 -0700291 socket.socket(socket.AF_INET, socket.SOCK_STREAM)) as listener:
Spencer Low351ecd12015-10-14 17:32:44 -0700292 # Use SO_REUSEADDR so subsequent runs of the test can grab the port
293 # even if it is in TIME_WAIT.
294 listener.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
Josh Gaoc251ec52018-04-03 12:55:18 -0700295 listener.bind(('127.0.0.1', 0))
Spencer Low351ecd12015-10-14 17:32:44 -0700296 listener.listen(4)
Josh Gaoc251ec52018-04-03 12:55:18 -0700297 port = listener.getsockname()[1]
Spencer Low351ecd12015-10-14 17:32:44 -0700298
299 # Now that listening has started, start adb emu kill, telling it to
300 # connect to our mock emulator.
Luis Hector Chavezfbee0a92018-05-02 09:10:29 -0700301 proc = subprocess.Popen(
Spencer Low351ecd12015-10-14 17:32:44 -0700302 ['adb', '-s', 'emulator-' + str(port), 'emu', 'kill'],
303 stderr=subprocess.STDOUT)
304
305 accepted_connection, addr = listener.accept()
306 with contextlib.closing(accepted_connection) as conn:
307 # If WSAECONNABORTED (10053) is raised by any socket calls,
308 # then adb probably isn't reading the data that we sent it.
309 conn.sendall('Android Console: type \'help\' for a list ' +
Luis Hector Chavezfbee0a92018-05-02 09:10:29 -0700310 'of commands\r\n')
Spencer Low351ecd12015-10-14 17:32:44 -0700311 conn.sendall('OK\r\n')
312
Luis Hector Chavezfbee0a92018-05-02 09:10:29 -0700313 with contextlib.closing(conn.makefile()) as connf:
314 line = connf.readline()
315 if line.startswith('auth'):
316 # Ignore the first auth line.
317 line = connf.readline()
318 self.assertEqual('kill\n', line)
319 self.assertEqual('quit\n', connf.readline())
Spencer Low351ecd12015-10-14 17:32:44 -0700320
321 conn.sendall('OK: killing emulator, bye bye\r\n')
322
323 # Use SO_LINGER to send TCP RST segment to test whether adb
324 # ignores WSAECONNRESET on Windows. This happens with the
325 # real emulator because it just calls exit() without closing
326 # the socket or calling shutdown(SD_SEND). At process
327 # termination, Windows sends a TCP RST segment for every
328 # open socket that shutdown(SD_SEND) wasn't used on.
329 self._reset_socket_on_close(conn)
330
331 # Wait for adb to finish, so we can check return code.
Luis Hector Chavezfbee0a92018-05-02 09:10:29 -0700332 proc.communicate()
Spencer Low351ecd12015-10-14 17:32:44 -0700333
334 # If this fails, adb probably isn't ignoring WSAECONNRESET when
335 # reading the response from the adb emu kill command (on Windows).
Luis Hector Chavezfbee0a92018-05-02 09:10:29 -0700336 self.assertEqual(0, proc.returncode)
337
Luis Hector Chavez32559742018-05-02 10:47:01 -0700338 def test_emulator_connect(self):
339 """Ensure that the emulator can connect.
340
341 Bug: http://b/78991667
342 """
343 with adb_server() as server_port:
344 with fake_adbd() as port:
345 serial = 'emulator-{}'.format(port - 1)
346 # Ensure that the emulator is not there.
347 try:
348 subprocess.check_output(['adb', '-P', str(server_port),
349 '-s', serial, 'get-state'],
350 stderr=subprocess.STDOUT)
351 self.fail('Device should not be available')
352 except subprocess.CalledProcessError as err:
353 self.assertEqual(
354 err.output.strip(),
355 'error: device \'{}\' not found'.format(serial))
356
357 # Let the ADB server know that the emulator has started.
358 with contextlib.closing(
359 socket.socket(socket.AF_INET, socket.SOCK_STREAM)) as sock:
360 sock.connect(('localhost', server_port))
361 command = 'host:emulator:{}'.format(port)
362 sock.sendall('%04x%s' % (len(command), command))
363
364 # Ensure the emulator is there.
365 subprocess.check_call(['adb', '-P', str(server_port),
366 '-s', serial, 'wait-for-device'])
367 output = subprocess.check_output(['adb', '-P', str(server_port),
368 '-s', serial, 'get-state'])
369 self.assertEqual(output.strip(), 'device')
370
Luis Hector Chavezfbee0a92018-05-02 09:10:29 -0700371
372class ConnectionTest(unittest.TestCase):
373 """Tests for adb connect."""
Spencer Low351ecd12015-10-14 17:32:44 -0700374
Josh Gao78cc20f2016-09-01 14:54:18 -0700375 def test_connect_ipv4_ipv6(self):
376 """Ensure that `adb connect localhost:1234` will try both IPv4 and IPv6.
377
378 Bug: http://b/30313466
379 """
Luis Hector Chavez8b67c522018-04-17 19:25:33 -0700380 for protocol in (socket.AF_INET, socket.AF_INET6):
381 try:
Luis Hector Chavezfbee0a92018-05-02 09:10:29 -0700382 with fake_adbd(protocol=protocol) as port:
Luis Hector Chavez454bc7c2018-04-20 10:31:29 -0700383 serial = 'localhost:{}'.format(port)
384 with adb_connect(self, serial):
385 pass
Luis Hector Chavez8b67c522018-04-17 19:25:33 -0700386 except socket.error:
387 print("IPv6 not available, skipping")
388 continue
Josh Gao78cc20f2016-09-01 14:54:18 -0700389
Luis Hector Chavez8b67c522018-04-17 19:25:33 -0700390 def test_already_connected(self):
Luis Hector Chavez454bc7c2018-04-20 10:31:29 -0700391 """Ensure that an already-connected device stays connected."""
392
Luis Hector Chavezfbee0a92018-05-02 09:10:29 -0700393 with fake_adbd() as port:
Luis Hector Chavez454bc7c2018-04-20 10:31:29 -0700394 serial = 'localhost:{}'.format(port)
395 with adb_connect(self, serial):
396 # b/31250450: this always returns 0 but probably shouldn't.
397 output = subprocess.check_output(['adb', 'connect', serial])
398 self.assertEqual(
399 output.strip(), 'already connected to {}'.format(serial))
Josh Gao78cc20f2016-09-01 14:54:18 -0700400
Luis Hector Chavez454bc7c2018-04-20 10:31:29 -0700401 def test_reconnect(self):
402 """Ensure that a disconnected device reconnects."""
Josh Gao78cc20f2016-09-01 14:54:18 -0700403
Luis Hector Chavezfbee0a92018-05-02 09:10:29 -0700404 with fake_adbd() as port:
Luis Hector Chavez454bc7c2018-04-20 10:31:29 -0700405 serial = 'localhost:{}'.format(port)
406 with adb_connect(self, serial):
407 output = subprocess.check_output(['adb', '-s', serial,
408 'get-state'])
409 self.assertEqual(output.strip(), 'device')
Josh Gaoc251ec52018-04-03 12:55:18 -0700410
Luis Hector Chavez454bc7c2018-04-20 10:31:29 -0700411 # This will fail.
Luis Hector Chavezfbee0a92018-05-02 09:10:29 -0700412 proc = subprocess.Popen(['adb', '-s', serial, 'shell', 'true'],
413 stdout=subprocess.PIPE,
414 stderr=subprocess.STDOUT)
415 output, _ = proc.communicate()
Luis Hector Chavez454bc7c2018-04-20 10:31:29 -0700416 self.assertEqual(output.strip(), 'error: closed')
417
418 subprocess.check_call(['adb', '-s', serial, 'wait-for-device'])
419
420 output = subprocess.check_output(['adb', '-s', serial,
421 'get-state'])
422 self.assertEqual(output.strip(), 'device')
423
424 # Once we explicitly kick a device, it won't attempt to
425 # reconnect.
426 output = subprocess.check_output(['adb', 'disconnect', serial])
427 self.assertEqual(
428 output.strip(), 'disconnected {}'.format(serial))
429 try:
430 subprocess.check_output(['adb', '-s', serial, 'get-state'],
431 stderr=subprocess.STDOUT)
432 self.fail('Device should not be available')
Luis Hector Chavezfbee0a92018-05-02 09:10:29 -0700433 except subprocess.CalledProcessError as err:
Luis Hector Chavez454bc7c2018-04-20 10:31:29 -0700434 self.assertEqual(
Luis Hector Chavezfbee0a92018-05-02 09:10:29 -0700435 err.output.strip(),
Luis Hector Chavez454bc7c2018-04-20 10:31:29 -0700436 'error: device \'{}\' not found'.format(serial))
Spencer Low351ecd12015-10-14 17:32:44 -0700437
Luis Hector Chavezfbee0a92018-05-02 09:10:29 -0700438
Dan Albert8e1fdd72015-07-24 17:08:33 -0700439def main():
Luis Hector Chavezfbee0a92018-05-02 09:10:29 -0700440 """Main entrypoint."""
Dan Albert8e1fdd72015-07-24 17:08:33 -0700441 random.seed(0)
Luis Hector Chavezfbee0a92018-05-02 09:10:29 -0700442 unittest.main(verbosity=3)
Dan Albert8e1fdd72015-07-24 17:08:33 -0700443
444
445if __name__ == '__main__':
446 main()