blob: 8f31a536667ee1439c83c1af97f4f36af44c6077 [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 Chavezfbee0a92018-05-02 09:10:29 -0700122class CommandlineTest(unittest.TestCase):
123 """Tests for the ADB commandline."""
Dan Albert8e1fdd72015-07-24 17:08:33 -0700124
125 def test_help(self):
126 """Make sure we get _something_ out of help."""
127 out = subprocess.check_output(
128 ['adb', 'help'], stderr=subprocess.STDOUT)
129 self.assertGreater(len(out), 0)
130
131 def test_version(self):
132 """Get a version number out of the output of adb."""
133 lines = subprocess.check_output(['adb', 'version']).splitlines()
134 version_line = lines[0]
135 self.assertRegexpMatches(
136 version_line, r'^Android Debug Bridge version \d+\.\d+\.\d+$')
137 if len(lines) == 2:
138 # Newer versions of ADB have a second line of output for the
139 # version that includes a specific revision (git SHA).
140 revision_line = lines[1]
141 self.assertRegexpMatches(
142 revision_line, r'^Revision [0-9a-f]{12}-android$')
143
144 def test_tcpip_error_messages(self):
Luis Hector Chavezfbee0a92018-05-02 09:10:29 -0700145 """Make sure 'adb tcpip' parsing is sane."""
146 proc = subprocess.Popen(['adb', 'tcpip'], stdout=subprocess.PIPE,
147 stderr=subprocess.STDOUT)
148 out, _ = proc.communicate()
149 self.assertEqual(1, proc.returncode)
Elliott Hughese1632982017-08-23 15:42:28 -0700150 self.assertIn('requires an argument', out)
Dan Albert8e1fdd72015-07-24 17:08:33 -0700151
Luis Hector Chavezfbee0a92018-05-02 09:10:29 -0700152 proc = subprocess.Popen(['adb', 'tcpip', 'foo'], stdout=subprocess.PIPE,
153 stderr=subprocess.STDOUT)
154 out, _ = proc.communicate()
155 self.assertEqual(1, proc.returncode)
Elliott Hughese1632982017-08-23 15:42:28 -0700156 self.assertIn('invalid port', out)
Dan Albert8e1fdd72015-07-24 17:08:33 -0700157
Luis Hector Chavezfbee0a92018-05-02 09:10:29 -0700158
159class ServerTest(unittest.TestCase):
160 """Tests for the ADB server."""
161
162 @staticmethod
163 def _read_pipe_and_set_event(pipe, event):
164 """Reads a pipe until it is closed, then sets the event."""
165 pipe.read()
Spencer Low1ce06082015-09-16 20:45:53 -0700166 event.set()
167
Spencer Low1ce06082015-09-16 20:45:53 -0700168 def test_handle_inheritance(self):
Luis Hector Chavezfbee0a92018-05-02 09:10:29 -0700169 """Test that launch_server() does not inherit handles.
170
171 launch_server() should not let the adb server inherit
172 stdin/stdout/stderr handles, which can cause callers of adb.exe to hang.
173 This test also runs fine on unix even though the impetus is an issue
174 unique to Windows.
175 """
Spencer Low1ce06082015-09-16 20:45:53 -0700176 # This test takes 5 seconds to run on Windows: if there is no adb server
177 # running on the the port used below, adb kill-server tries to make a
178 # TCP connection to a closed port and that takes 1 second on Windows;
179 # adb start-server does the same TCP connection which takes another
180 # second, and it waits 3 seconds after starting the server.
181
182 # Start adb client with redirected stdin/stdout/stderr to check if it
183 # passes those redirections to the adb server that it starts. To do
184 # this, run an instance of the adb server on a non-default port so we
185 # don't conflict with a pre-existing adb server that may already be
186 # setup with adb TCP/emulator connections. If there is a pre-existing
187 # adb server, this also tests whether multiple instances of the adb
188 # server conflict on adb.log.
189
190 port = 5038
191 # Kill any existing server on this non-default port.
192 subprocess.check_output(['adb', '-P', str(port), 'kill-server'],
193 stderr=subprocess.STDOUT)
194
195 try:
196 # Run the adb client and have it start the adb server.
Luis Hector Chavezfbee0a92018-05-02 09:10:29 -0700197 proc = subprocess.Popen(['adb', '-P', str(port), 'start-server'],
198 stdin=subprocess.PIPE,
199 stdout=subprocess.PIPE,
200 stderr=subprocess.PIPE)
Spencer Low1ce06082015-09-16 20:45:53 -0700201
202 # Start threads that set events when stdout/stderr are closed.
203 stdout_event = threading.Event()
204 stdout_thread = threading.Thread(
Luis Hector Chavezfbee0a92018-05-02 09:10:29 -0700205 target=ServerTest._read_pipe_and_set_event,
206 args=(proc.stdout, stdout_event))
Spencer Low1ce06082015-09-16 20:45:53 -0700207 stdout_thread.daemon = True
208 stdout_thread.start()
209
210 stderr_event = threading.Event()
211 stderr_thread = threading.Thread(
Luis Hector Chavezfbee0a92018-05-02 09:10:29 -0700212 target=ServerTest._read_pipe_and_set_event,
213 args=(proc.stderr, stderr_event))
Spencer Low1ce06082015-09-16 20:45:53 -0700214 stderr_thread.daemon = True
215 stderr_thread.start()
216
217 # Wait for the adb client to finish. Once that has occurred, if
218 # stdin/stderr/stdout are still open, it must be open in the adb
219 # server.
Luis Hector Chavezfbee0a92018-05-02 09:10:29 -0700220 proc.wait()
Spencer Low1ce06082015-09-16 20:45:53 -0700221
222 # Try to write to stdin which we expect is closed. If it isn't
223 # closed, we should get an IOError. If we don't get an IOError,
224 # stdin must still be open in the adb server. The adb client is
225 # probably letting the adb server inherit stdin which would be
226 # wrong.
227 with self.assertRaises(IOError):
Luis Hector Chavezfbee0a92018-05-02 09:10:29 -0700228 proc.stdin.write('x')
Spencer Low1ce06082015-09-16 20:45:53 -0700229
230 # Wait a few seconds for stdout/stderr to be closed (in the success
231 # case, this won't wait at all). If there is a timeout, that means
232 # stdout/stderr were not closed and and they must be open in the adb
233 # server, suggesting that the adb client is letting the adb server
234 # inherit stdout/stderr which would be wrong.
235 self.assertTrue(stdout_event.wait(5), "adb stdout not closed")
236 self.assertTrue(stderr_event.wait(5), "adb stderr not closed")
237 finally:
238 # If we started a server, kill it.
239 subprocess.check_output(['adb', '-P', str(port), 'kill-server'],
240 stderr=subprocess.STDOUT)
Dan Albert8e1fdd72015-07-24 17:08:33 -0700241
Luis Hector Chavezfbee0a92018-05-02 09:10:29 -0700242
243class EmulatorTest(unittest.TestCase):
244 """Tests for the emulator connection."""
245
Spencer Low351ecd12015-10-14 17:32:44 -0700246 def _reset_socket_on_close(self, sock):
Luis Hector Chavezfbee0a92018-05-02 09:10:29 -0700247 """Use SO_LINGER to cause TCP RST segment to be sent on socket close."""
Spencer Low351ecd12015-10-14 17:32:44 -0700248 # The linger structure is two shorts on Windows, but two ints on Unix.
249 linger_format = 'hh' if os.name == 'nt' else 'ii'
250 l_onoff = 1
251 l_linger = 0
252
253 sock.setsockopt(socket.SOL_SOCKET, socket.SO_LINGER,
254 struct.pack(linger_format, l_onoff, l_linger))
255 # Verify that we set the linger structure properly by retrieving it.
256 linger = sock.getsockopt(socket.SOL_SOCKET, socket.SO_LINGER, 16)
257 self.assertEqual((l_onoff, l_linger),
258 struct.unpack_from(linger_format, linger))
259
260 def test_emu_kill(self):
261 """Ensure that adb emu kill works.
262
263 Bug: https://code.google.com/p/android/issues/detail?id=21021
264 """
Spencer Low351ecd12015-10-14 17:32:44 -0700265 with contextlib.closing(
Luis Hector Chavezfbee0a92018-05-02 09:10:29 -0700266 socket.socket(socket.AF_INET, socket.SOCK_STREAM)) as listener:
Spencer Low351ecd12015-10-14 17:32:44 -0700267 # Use SO_REUSEADDR so subsequent runs of the test can grab the port
268 # even if it is in TIME_WAIT.
269 listener.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
Josh Gaoc251ec52018-04-03 12:55:18 -0700270 listener.bind(('127.0.0.1', 0))
Spencer Low351ecd12015-10-14 17:32:44 -0700271 listener.listen(4)
Josh Gaoc251ec52018-04-03 12:55:18 -0700272 port = listener.getsockname()[1]
Spencer Low351ecd12015-10-14 17:32:44 -0700273
274 # Now that listening has started, start adb emu kill, telling it to
275 # connect to our mock emulator.
Luis Hector Chavezfbee0a92018-05-02 09:10:29 -0700276 proc = subprocess.Popen(
Spencer Low351ecd12015-10-14 17:32:44 -0700277 ['adb', '-s', 'emulator-' + str(port), 'emu', 'kill'],
278 stderr=subprocess.STDOUT)
279
280 accepted_connection, addr = listener.accept()
281 with contextlib.closing(accepted_connection) as conn:
282 # If WSAECONNABORTED (10053) is raised by any socket calls,
283 # then adb probably isn't reading the data that we sent it.
284 conn.sendall('Android Console: type \'help\' for a list ' +
Luis Hector Chavezfbee0a92018-05-02 09:10:29 -0700285 'of commands\r\n')
Spencer Low351ecd12015-10-14 17:32:44 -0700286 conn.sendall('OK\r\n')
287
Luis Hector Chavezfbee0a92018-05-02 09:10:29 -0700288 with contextlib.closing(conn.makefile()) as connf:
289 line = connf.readline()
290 if line.startswith('auth'):
291 # Ignore the first auth line.
292 line = connf.readline()
293 self.assertEqual('kill\n', line)
294 self.assertEqual('quit\n', connf.readline())
Spencer Low351ecd12015-10-14 17:32:44 -0700295
296 conn.sendall('OK: killing emulator, bye bye\r\n')
297
298 # Use SO_LINGER to send TCP RST segment to test whether adb
299 # ignores WSAECONNRESET on Windows. This happens with the
300 # real emulator because it just calls exit() without closing
301 # the socket or calling shutdown(SD_SEND). At process
302 # termination, Windows sends a TCP RST segment for every
303 # open socket that shutdown(SD_SEND) wasn't used on.
304 self._reset_socket_on_close(conn)
305
306 # Wait for adb to finish, so we can check return code.
Luis Hector Chavezfbee0a92018-05-02 09:10:29 -0700307 proc.communicate()
Spencer Low351ecd12015-10-14 17:32:44 -0700308
309 # If this fails, adb probably isn't ignoring WSAECONNRESET when
310 # reading the response from the adb emu kill command (on Windows).
Luis Hector Chavezfbee0a92018-05-02 09:10:29 -0700311 self.assertEqual(0, proc.returncode)
312
313
314class ConnectionTest(unittest.TestCase):
315 """Tests for adb connect."""
Spencer Low351ecd12015-10-14 17:32:44 -0700316
Josh Gao78cc20f2016-09-01 14:54:18 -0700317 def test_connect_ipv4_ipv6(self):
318 """Ensure that `adb connect localhost:1234` will try both IPv4 and IPv6.
319
320 Bug: http://b/30313466
321 """
Luis Hector Chavez8b67c522018-04-17 19:25:33 -0700322 for protocol in (socket.AF_INET, socket.AF_INET6):
323 try:
Luis Hector Chavezfbee0a92018-05-02 09:10:29 -0700324 with fake_adbd(protocol=protocol) as port:
Luis Hector Chavez454bc7c2018-04-20 10:31:29 -0700325 serial = 'localhost:{}'.format(port)
326 with adb_connect(self, serial):
327 pass
Luis Hector Chavez8b67c522018-04-17 19:25:33 -0700328 except socket.error:
329 print("IPv6 not available, skipping")
330 continue
Josh Gao78cc20f2016-09-01 14:54:18 -0700331
Luis Hector Chavez8b67c522018-04-17 19:25:33 -0700332 def test_already_connected(self):
Luis Hector Chavez454bc7c2018-04-20 10:31:29 -0700333 """Ensure that an already-connected device stays connected."""
334
Luis Hector Chavezfbee0a92018-05-02 09:10:29 -0700335 with fake_adbd() as port:
Luis Hector Chavez454bc7c2018-04-20 10:31:29 -0700336 serial = 'localhost:{}'.format(port)
337 with adb_connect(self, serial):
338 # b/31250450: this always returns 0 but probably shouldn't.
339 output = subprocess.check_output(['adb', 'connect', serial])
340 self.assertEqual(
341 output.strip(), 'already connected to {}'.format(serial))
Josh Gao78cc20f2016-09-01 14:54:18 -0700342
Luis Hector Chavez454bc7c2018-04-20 10:31:29 -0700343 def test_reconnect(self):
344 """Ensure that a disconnected device reconnects."""
Josh Gao78cc20f2016-09-01 14:54:18 -0700345
Luis Hector Chavezfbee0a92018-05-02 09:10:29 -0700346 with fake_adbd() as port:
Luis Hector Chavez454bc7c2018-04-20 10:31:29 -0700347 serial = 'localhost:{}'.format(port)
348 with adb_connect(self, serial):
349 output = subprocess.check_output(['adb', '-s', serial,
350 'get-state'])
351 self.assertEqual(output.strip(), 'device')
Josh Gaoc251ec52018-04-03 12:55:18 -0700352
Luis Hector Chavez454bc7c2018-04-20 10:31:29 -0700353 # This will fail.
Luis Hector Chavezfbee0a92018-05-02 09:10:29 -0700354 proc = subprocess.Popen(['adb', '-s', serial, 'shell', 'true'],
355 stdout=subprocess.PIPE,
356 stderr=subprocess.STDOUT)
357 output, _ = proc.communicate()
Luis Hector Chavez454bc7c2018-04-20 10:31:29 -0700358 self.assertEqual(output.strip(), 'error: closed')
359
360 subprocess.check_call(['adb', '-s', serial, 'wait-for-device'])
361
362 output = subprocess.check_output(['adb', '-s', serial,
363 'get-state'])
364 self.assertEqual(output.strip(), 'device')
365
366 # Once we explicitly kick a device, it won't attempt to
367 # reconnect.
368 output = subprocess.check_output(['adb', 'disconnect', serial])
369 self.assertEqual(
370 output.strip(), 'disconnected {}'.format(serial))
371 try:
372 subprocess.check_output(['adb', '-s', serial, 'get-state'],
373 stderr=subprocess.STDOUT)
374 self.fail('Device should not be available')
Luis Hector Chavezfbee0a92018-05-02 09:10:29 -0700375 except subprocess.CalledProcessError as err:
Luis Hector Chavez454bc7c2018-04-20 10:31:29 -0700376 self.assertEqual(
Luis Hector Chavezfbee0a92018-05-02 09:10:29 -0700377 err.output.strip(),
Luis Hector Chavez454bc7c2018-04-20 10:31:29 -0700378 'error: device \'{}\' not found'.format(serial))
Spencer Low351ecd12015-10-14 17:32:44 -0700379
Luis Hector Chavezfbee0a92018-05-02 09:10:29 -0700380
Dan Albert8e1fdd72015-07-24 17:08:33 -0700381def main():
Luis Hector Chavezfbee0a92018-05-02 09:10:29 -0700382 """Main entrypoint."""
Dan Albert8e1fdd72015-07-24 17:08:33 -0700383 random.seed(0)
Luis Hector Chavezfbee0a92018-05-02 09:10:29 -0700384 unittest.main(verbosity=3)
Dan Albert8e1fdd72015-07-24 17:08:33 -0700385
386
387if __name__ == '__main__':
388 main()