blob: 4b9941147ce9808695e2b7db0baaa015b02509cd [file] [log] [blame]
Josh Gao9b6522b2018-08-07 14:31:17 -07001#!/usr/bin/env python3
Dan Albert8e1fdd72015-07-24 17:08:33 -07002#
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"""
Dan Albert8e1fdd72015-07-24 17:08:33 -070022
Spencer Low351ecd12015-10-14 17:32:44 -070023import contextlib
Spencer Low1ce06082015-09-16 20:45:53 -070024import os
Dan Albert8e1fdd72015-07-24 17:08:33 -070025import random
Luis Hector Chavez8b67c522018-04-17 19:25:33 -070026import select
Spencer Low351ecd12015-10-14 17:32:44 -070027import socket
Joshua Duong7ebc5952020-05-01 09:25:12 -070028import string
Spencer Low351ecd12015-10-14 17:32:44 -070029import struct
Dan Albert8e1fdd72015-07-24 17:08:33 -070030import subprocess
Josh Gao92cd59f2018-08-21 14:25:05 -070031import sys
Spencer Low1ce06082015-09-16 20:45:53 -070032import threading
Josh Gao902dace2018-08-10 14:44:54 -070033import time
Dan Albert8e1fdd72015-07-24 17:08:33 -070034import unittest
Josh Gao42c86722018-10-16 11:00:39 -070035import warnings
Joshua Duong13c639e2020-03-31 08:39:24 -070036from importlib import util
37from parameterized import parameterized_class
Dan Albert8e1fdd72015-07-24 17:08:33 -070038
Josh Gaoe8829c62020-02-27 14:29:38 -080039def find_open_port():
40 # Find an open port.
41 with socket.socket() as s:
42 s.bind(("localhost", 0))
43 return s.getsockname()[1]
Dan Albert8e1fdd72015-07-24 17:08:33 -070044
Luis Hector Chavez8b67c522018-04-17 19:25:33 -070045@contextlib.contextmanager
Luis Hector Chavezfbee0a92018-05-02 09:10:29 -070046def fake_adbd(protocol=socket.AF_INET, port=0):
47 """Creates a fake ADB daemon that just replies with a CNXN packet."""
Luis Hector Chavez8b67c522018-04-17 19:25:33 -070048
49 serversock = socket.socket(protocol, socket.SOCK_STREAM)
Luis Hector Chavezfbee0a92018-05-02 09:10:29 -070050 serversock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
Luis Hector Chavez8b67c522018-04-17 19:25:33 -070051 if protocol == socket.AF_INET:
Josh Gaob3610732018-08-08 13:08:08 -070052 serversock.bind(("127.0.0.1", port))
Luis Hector Chavez8b67c522018-04-17 19:25:33 -070053 else:
Josh Gaob3610732018-08-08 13:08:08 -070054 serversock.bind(("::1", port))
Luis Hector Chavez8b67c522018-04-17 19:25:33 -070055 serversock.listen(1)
56
57 # A pipe that is used to signal the thread that it should terminate.
Josh Gao676f375d2018-08-07 16:07:25 -070058 readsock, writesock = socket.socketpair()
Luis Hector Chavez8b67c522018-04-17 19:25:33 -070059
Josh Gao9b6522b2018-08-07 14:31:17 -070060 def _adb_packet(command: bytes, arg0: int, arg1: int, data: bytes) -> bytes:
Josh Gaob3610732018-08-08 13:08:08 -070061 bin_command = struct.unpack("I", command)[0]
62 buf = struct.pack("IIIIII", bin_command, arg0, arg1, len(data), 0,
Luis Hector Chavez56fe7532018-04-17 14:25:04 -070063 bin_command ^ 0xffffffff)
64 buf += data
65 return buf
66
Josh Gao9b6522b2018-08-07 14:31:17 -070067 def _handle(sock):
68 with contextlib.closing(sock) as serversock:
Josh Gao676f375d2018-08-07 16:07:25 -070069 rlist = [readsock, serversock]
Josh Gao9b6522b2018-08-07 14:31:17 -070070 cnxn_sent = {}
71 while True:
72 read_ready, _, _ = select.select(rlist, [], [])
73 for ready in read_ready:
Josh Gao676f375d2018-08-07 16:07:25 -070074 if ready == readsock:
Josh Gao9b6522b2018-08-07 14:31:17 -070075 # Closure pipe
Josh Gao9b6522b2018-08-07 14:31:17 -070076 for f in rlist:
Josh Gao676f375d2018-08-07 16:07:25 -070077 f.close()
Josh Gao9b6522b2018-08-07 14:31:17 -070078 return
79 elif ready == serversock:
80 # Server socket
81 conn, _ = ready.accept()
82 rlist.append(conn)
83 else:
84 # Client socket
85 data = ready.recv(1024)
Josh Gaob3610732018-08-08 13:08:08 -070086 if not data or data.startswith(b"OPEN"):
Josh Gao9b6522b2018-08-07 14:31:17 -070087 if ready in cnxn_sent:
88 del cnxn_sent[ready]
89 ready.shutdown(socket.SHUT_RDWR)
90 ready.close()
91 rlist.remove(ready)
92 continue
Luis Hector Chavezfbee0a92018-05-02 09:10:29 -070093 if ready in cnxn_sent:
Josh Gao9b6522b2018-08-07 14:31:17 -070094 continue
95 cnxn_sent[ready] = True
Josh Gaob3610732018-08-08 13:08:08 -070096 ready.sendall(_adb_packet(b"CNXN", 0x01000001, 1024 * 1024,
97 b"device::ro.product.name=fakeadb"))
Luis Hector Chavez8b67c522018-04-17 19:25:33 -070098
99 port = serversock.getsockname()[1]
Josh Gao9b6522b2018-08-07 14:31:17 -0700100 server_thread = threading.Thread(target=_handle, args=(serversock,))
Luis Hector Chavez8b67c522018-04-17 19:25:33 -0700101 server_thread.start()
102
103 try:
Josh Gao902dace2018-08-10 14:44:54 -0700104 yield port, writesock
Luis Hector Chavez8b67c522018-04-17 19:25:33 -0700105 finally:
Josh Gao676f375d2018-08-07 16:07:25 -0700106 writesock.close()
Luis Hector Chavez8b67c522018-04-17 19:25:33 -0700107 server_thread.join()
108
109
Luis Hector Chavez454bc7c2018-04-20 10:31:29 -0700110@contextlib.contextmanager
111def adb_connect(unittest, serial):
112 """Context manager for an ADB connection.
113
114 This automatically disconnects when done with the connection.
115 """
116
Josh Gaob3610732018-08-08 13:08:08 -0700117 output = subprocess.check_output(["adb", "connect", serial])
Josh Gao9b6522b2018-08-07 14:31:17 -0700118 unittest.assertEqual(output.strip(),
Josh Gaob3610732018-08-08 13:08:08 -0700119 "connected to {}".format(serial).encode("utf8"))
Luis Hector Chavez454bc7c2018-04-20 10:31:29 -0700120
121 try:
122 yield
123 finally:
124 # Perform best-effort disconnection. Discard the output.
Josh Gaob3610732018-08-08 13:08:08 -0700125 subprocess.Popen(["adb", "disconnect", serial],
Luis Hector Chavezfbee0a92018-05-02 09:10:29 -0700126 stdout=subprocess.PIPE,
127 stderr=subprocess.PIPE).communicate()
Luis Hector Chavez454bc7c2018-04-20 10:31:29 -0700128
129
Luis Hector Chavez32559742018-05-02 10:47:01 -0700130@contextlib.contextmanager
131def adb_server():
132 """Context manager for an ADB server.
133
Josh Gao902dace2018-08-10 14:44:54 -0700134 This creates an ADB server and returns the port it's listening on.
Luis Hector Chavez32559742018-05-02 10:47:01 -0700135 """
136
Josh Gaoe8829c62020-02-27 14:29:38 -0800137 port = find_open_port()
Luis Hector Chavez32559742018-05-02 10:47:01 -0700138 read_pipe, write_pipe = os.pipe()
Josh Gao92cd59f2018-08-21 14:25:05 -0700139
140 if sys.platform == "win32":
141 import msvcrt
142 write_handle = msvcrt.get_osfhandle(write_pipe)
143 os.set_handle_inheritable(write_handle, True)
144 reply_fd = str(write_handle)
145 else:
146 os.set_inheritable(write_pipe, True)
147 reply_fd = str(write_pipe)
148
Josh Gaob3610732018-08-08 13:08:08 -0700149 proc = subprocess.Popen(["adb", "-L", "tcp:localhost:{}".format(port),
150 "fork-server", "server",
Josh Gao92cd59f2018-08-21 14:25:05 -0700151 "--reply-fd", reply_fd], close_fds=False)
Luis Hector Chavez32559742018-05-02 10:47:01 -0700152 try:
153 os.close(write_pipe)
154 greeting = os.read(read_pipe, 1024)
Josh Gaob3610732018-08-08 13:08:08 -0700155 assert greeting == b"OK\n", repr(greeting)
Luis Hector Chavez32559742018-05-02 10:47:01 -0700156 yield port
157 finally:
158 proc.terminate()
159 proc.wait()
160
161
Luis Hector Chavezfbee0a92018-05-02 09:10:29 -0700162class CommandlineTest(unittest.TestCase):
163 """Tests for the ADB commandline."""
Dan Albert8e1fdd72015-07-24 17:08:33 -0700164
165 def test_help(self):
166 """Make sure we get _something_ out of help."""
167 out = subprocess.check_output(
Josh Gaob3610732018-08-08 13:08:08 -0700168 ["adb", "help"], stderr=subprocess.STDOUT)
Dan Albert8e1fdd72015-07-24 17:08:33 -0700169 self.assertGreater(len(out), 0)
170
171 def test_version(self):
172 """Get a version number out of the output of adb."""
Josh Gaob3610732018-08-08 13:08:08 -0700173 lines = subprocess.check_output(["adb", "version"]).splitlines()
Dan Albert8e1fdd72015-07-24 17:08:33 -0700174 version_line = lines[0]
Josh Gao9b6522b2018-08-07 14:31:17 -0700175 self.assertRegex(
Josh Gaob3610732018-08-08 13:08:08 -0700176 version_line, rb"^Android Debug Bridge version \d+\.\d+\.\d+$")
Dan Albert8e1fdd72015-07-24 17:08:33 -0700177 if len(lines) == 2:
178 # Newer versions of ADB have a second line of output for the
179 # version that includes a specific revision (git SHA).
180 revision_line = lines[1]
Josh Gao9b6522b2018-08-07 14:31:17 -0700181 self.assertRegex(
Josh Gaob3610732018-08-08 13:08:08 -0700182 revision_line, rb"^Revision [0-9a-f]{12}-android$")
Dan Albert8e1fdd72015-07-24 17:08:33 -0700183
184 def test_tcpip_error_messages(self):
Luis Hector Chavezfbee0a92018-05-02 09:10:29 -0700185 """Make sure 'adb tcpip' parsing is sane."""
Josh Gaob3610732018-08-08 13:08:08 -0700186 proc = subprocess.Popen(["adb", "tcpip"],
Josh Gao9b6522b2018-08-07 14:31:17 -0700187 stdout=subprocess.PIPE,
Luis Hector Chavezfbee0a92018-05-02 09:10:29 -0700188 stderr=subprocess.STDOUT)
189 out, _ = proc.communicate()
190 self.assertEqual(1, proc.returncode)
Josh Gaob3610732018-08-08 13:08:08 -0700191 self.assertIn(b"requires an argument", out)
Dan Albert8e1fdd72015-07-24 17:08:33 -0700192
Josh Gaob3610732018-08-08 13:08:08 -0700193 proc = subprocess.Popen(["adb", "tcpip", "foo"],
Josh Gao9b6522b2018-08-07 14:31:17 -0700194 stdout=subprocess.PIPE,
Luis Hector Chavezfbee0a92018-05-02 09:10:29 -0700195 stderr=subprocess.STDOUT)
196 out, _ = proc.communicate()
197 self.assertEqual(1, proc.returncode)
Josh Gaob3610732018-08-08 13:08:08 -0700198 self.assertIn(b"invalid port", out)
Dan Albert8e1fdd72015-07-24 17:08:33 -0700199
Luis Hector Chavezfbee0a92018-05-02 09:10:29 -0700200
201class ServerTest(unittest.TestCase):
202 """Tests for the ADB server."""
203
204 @staticmethod
205 def _read_pipe_and_set_event(pipe, event):
206 """Reads a pipe until it is closed, then sets the event."""
207 pipe.read()
Spencer Low1ce06082015-09-16 20:45:53 -0700208 event.set()
209
Spencer Low1ce06082015-09-16 20:45:53 -0700210 def test_handle_inheritance(self):
Luis Hector Chavezfbee0a92018-05-02 09:10:29 -0700211 """Test that launch_server() does not inherit handles.
212
213 launch_server() should not let the adb server inherit
214 stdin/stdout/stderr handles, which can cause callers of adb.exe to hang.
215 This test also runs fine on unix even though the impetus is an issue
216 unique to Windows.
217 """
Spencer Low1ce06082015-09-16 20:45:53 -0700218 # This test takes 5 seconds to run on Windows: if there is no adb server
219 # running on the the port used below, adb kill-server tries to make a
220 # TCP connection to a closed port and that takes 1 second on Windows;
221 # adb start-server does the same TCP connection which takes another
222 # second, and it waits 3 seconds after starting the server.
223
224 # Start adb client with redirected stdin/stdout/stderr to check if it
225 # passes those redirections to the adb server that it starts. To do
226 # this, run an instance of the adb server on a non-default port so we
227 # don't conflict with a pre-existing adb server that may already be
228 # setup with adb TCP/emulator connections. If there is a pre-existing
229 # adb server, this also tests whether multiple instances of the adb
230 # server conflict on adb.log.
231
Josh Gaoe8829c62020-02-27 14:29:38 -0800232 port = find_open_port()
Spencer Low1ce06082015-09-16 20:45:53 -0700233
234 try:
Josh Gao42c86722018-10-16 11:00:39 -0700235 # We get warnings for unclosed files for the subprocess's pipes,
236 # and it's somewhat cumbersome to close them, so just ignore this.
237 warnings.simplefilter("ignore", ResourceWarning)
238
Spencer Low1ce06082015-09-16 20:45:53 -0700239 # Run the adb client and have it start the adb server.
Josh Gaob3610732018-08-08 13:08:08 -0700240 proc = subprocess.Popen(["adb", "-P", str(port), "start-server"],
Luis Hector Chavezfbee0a92018-05-02 09:10:29 -0700241 stdin=subprocess.PIPE,
242 stdout=subprocess.PIPE,
243 stderr=subprocess.PIPE)
Spencer Low1ce06082015-09-16 20:45:53 -0700244
245 # Start threads that set events when stdout/stderr are closed.
246 stdout_event = threading.Event()
247 stdout_thread = threading.Thread(
Luis Hector Chavezfbee0a92018-05-02 09:10:29 -0700248 target=ServerTest._read_pipe_and_set_event,
249 args=(proc.stdout, stdout_event))
Spencer Low1ce06082015-09-16 20:45:53 -0700250 stdout_thread.start()
251
252 stderr_event = threading.Event()
253 stderr_thread = threading.Thread(
Luis Hector Chavezfbee0a92018-05-02 09:10:29 -0700254 target=ServerTest._read_pipe_and_set_event,
255 args=(proc.stderr, stderr_event))
Spencer Low1ce06082015-09-16 20:45:53 -0700256 stderr_thread.start()
257
258 # Wait for the adb client to finish. Once that has occurred, if
259 # stdin/stderr/stdout are still open, it must be open in the adb
260 # server.
Luis Hector Chavezfbee0a92018-05-02 09:10:29 -0700261 proc.wait()
Spencer Low1ce06082015-09-16 20:45:53 -0700262
263 # Try to write to stdin which we expect is closed. If it isn't
264 # closed, we should get an IOError. If we don't get an IOError,
265 # stdin must still be open in the adb server. The adb client is
266 # probably letting the adb server inherit stdin which would be
267 # wrong.
268 with self.assertRaises(IOError):
Josh Gaob3610732018-08-08 13:08:08 -0700269 proc.stdin.write(b"x")
Josh Gao9b6522b2018-08-07 14:31:17 -0700270 proc.stdin.flush()
Spencer Low1ce06082015-09-16 20:45:53 -0700271
272 # Wait a few seconds for stdout/stderr to be closed (in the success
273 # case, this won't wait at all). If there is a timeout, that means
274 # stdout/stderr were not closed and and they must be open in the adb
275 # server, suggesting that the adb client is letting the adb server
276 # inherit stdout/stderr which would be wrong.
277 self.assertTrue(stdout_event.wait(5), "adb stdout not closed")
278 self.assertTrue(stderr_event.wait(5), "adb stderr not closed")
Josh Gao9b6522b2018-08-07 14:31:17 -0700279 stdout_thread.join()
280 stderr_thread.join()
Spencer Low1ce06082015-09-16 20:45:53 -0700281 finally:
282 # If we started a server, kill it.
Josh Gaob3610732018-08-08 13:08:08 -0700283 subprocess.check_output(["adb", "-P", str(port), "kill-server"],
Spencer Low1ce06082015-09-16 20:45:53 -0700284 stderr=subprocess.STDOUT)
Dan Albert8e1fdd72015-07-24 17:08:33 -0700285
Callum Ryan8539cb32019-10-31 07:21:42 -0700286 @unittest.skipUnless(
287 os.name == "posix",
288 "adb doesn't yet support IPv6 on Windows",
289 )
290 def test_starts_on_ipv6_localhost(self):
291 """
292 Tests that the server can start up on ::1 and that it's accessible
293 """
Josh Gaoe8829c62020-02-27 14:29:38 -0800294
295 server_port = find_open_port()
Callum Ryan8539cb32019-10-31 07:21:42 -0700296 try:
297 subprocess.check_output(
298 ["adb", "-L", "tcp:[::1]:{}".format(server_port), "server"],
299 stderr=subprocess.STDOUT,
300 )
301 with fake_adbd() as (port, _):
302 with adb_connect(self, serial="localhost:{}".format(port)):
303 pass
304 finally:
305 # If we started a server, kill it.
306 subprocess.check_output(
307 ["adb", "-P", str(server_port), "kill-server"],
308 stderr=subprocess.STDOUT,
309 )
310
311
312
Luis Hector Chavezfbee0a92018-05-02 09:10:29 -0700313
314class EmulatorTest(unittest.TestCase):
315 """Tests for the emulator connection."""
316
Spencer Low351ecd12015-10-14 17:32:44 -0700317 def _reset_socket_on_close(self, sock):
Luis Hector Chavezfbee0a92018-05-02 09:10:29 -0700318 """Use SO_LINGER to cause TCP RST segment to be sent on socket close."""
Spencer Low351ecd12015-10-14 17:32:44 -0700319 # The linger structure is two shorts on Windows, but two ints on Unix.
Josh Gaob3610732018-08-08 13:08:08 -0700320 linger_format = "hh" if os.name == "nt" else "ii"
Spencer Low351ecd12015-10-14 17:32:44 -0700321 l_onoff = 1
322 l_linger = 0
323
324 sock.setsockopt(socket.SOL_SOCKET, socket.SO_LINGER,
325 struct.pack(linger_format, l_onoff, l_linger))
326 # Verify that we set the linger structure properly by retrieving it.
327 linger = sock.getsockopt(socket.SOL_SOCKET, socket.SO_LINGER, 16)
328 self.assertEqual((l_onoff, l_linger),
329 struct.unpack_from(linger_format, linger))
330
331 def test_emu_kill(self):
332 """Ensure that adb emu kill works.
333
334 Bug: https://code.google.com/p/android/issues/detail?id=21021
335 """
Spencer Low351ecd12015-10-14 17:32:44 -0700336 with contextlib.closing(
Luis Hector Chavezfbee0a92018-05-02 09:10:29 -0700337 socket.socket(socket.AF_INET, socket.SOCK_STREAM)) as listener:
Spencer Low351ecd12015-10-14 17:32:44 -0700338 # Use SO_REUSEADDR so subsequent runs of the test can grab the port
339 # even if it is in TIME_WAIT.
340 listener.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
Josh Gaob3610732018-08-08 13:08:08 -0700341 listener.bind(("127.0.0.1", 0))
Spencer Low351ecd12015-10-14 17:32:44 -0700342 listener.listen(4)
Josh Gaoc251ec52018-04-03 12:55:18 -0700343 port = listener.getsockname()[1]
Spencer Low351ecd12015-10-14 17:32:44 -0700344
345 # Now that listening has started, start adb emu kill, telling it to
346 # connect to our mock emulator.
Luis Hector Chavezfbee0a92018-05-02 09:10:29 -0700347 proc = subprocess.Popen(
Josh Gaob3610732018-08-08 13:08:08 -0700348 ["adb", "-s", "emulator-" + str(port), "emu", "kill"],
Spencer Low351ecd12015-10-14 17:32:44 -0700349 stderr=subprocess.STDOUT)
350
351 accepted_connection, addr = listener.accept()
352 with contextlib.closing(accepted_connection) as conn:
353 # If WSAECONNABORTED (10053) is raised by any socket calls,
354 # then adb probably isn't reading the data that we sent it.
Josh Gaob3610732018-08-08 13:08:08 -0700355 conn.sendall(("Android Console: type 'help' for a list "
356 "of commands\r\n").encode("utf8"))
357 conn.sendall(b"OK\r\n")
Spencer Low351ecd12015-10-14 17:32:44 -0700358
Luis Hector Chavezfbee0a92018-05-02 09:10:29 -0700359 with contextlib.closing(conn.makefile()) as connf:
360 line = connf.readline()
Josh Gaob3610732018-08-08 13:08:08 -0700361 if line.startswith("auth"):
Luis Hector Chavezfbee0a92018-05-02 09:10:29 -0700362 # Ignore the first auth line.
363 line = connf.readline()
Josh Gaob3610732018-08-08 13:08:08 -0700364 self.assertEqual("kill\n", line)
365 self.assertEqual("quit\n", connf.readline())
Spencer Low351ecd12015-10-14 17:32:44 -0700366
Josh Gaob3610732018-08-08 13:08:08 -0700367 conn.sendall(b"OK: killing emulator, bye bye\r\n")
Spencer Low351ecd12015-10-14 17:32:44 -0700368
369 # Use SO_LINGER to send TCP RST segment to test whether adb
370 # ignores WSAECONNRESET on Windows. This happens with the
371 # real emulator because it just calls exit() without closing
372 # the socket or calling shutdown(SD_SEND). At process
373 # termination, Windows sends a TCP RST segment for every
374 # open socket that shutdown(SD_SEND) wasn't used on.
375 self._reset_socket_on_close(conn)
376
377 # Wait for adb to finish, so we can check return code.
Luis Hector Chavezfbee0a92018-05-02 09:10:29 -0700378 proc.communicate()
Spencer Low351ecd12015-10-14 17:32:44 -0700379
380 # If this fails, adb probably isn't ignoring WSAECONNRESET when
381 # reading the response from the adb emu kill command (on Windows).
Luis Hector Chavezfbee0a92018-05-02 09:10:29 -0700382 self.assertEqual(0, proc.returncode)
383
Luis Hector Chavez32559742018-05-02 10:47:01 -0700384 def test_emulator_connect(self):
385 """Ensure that the emulator can connect.
386
387 Bug: http://b/78991667
388 """
389 with adb_server() as server_port:
Josh Gao902dace2018-08-10 14:44:54 -0700390 with fake_adbd() as (port, _):
Josh Gaob3610732018-08-08 13:08:08 -0700391 serial = "emulator-{}".format(port - 1)
Luis Hector Chavez32559742018-05-02 10:47:01 -0700392 # Ensure that the emulator is not there.
393 try:
Josh Gaob3610732018-08-08 13:08:08 -0700394 subprocess.check_output(["adb", "-P", str(server_port),
395 "-s", serial, "get-state"],
Luis Hector Chavez32559742018-05-02 10:47:01 -0700396 stderr=subprocess.STDOUT)
Josh Gaob3610732018-08-08 13:08:08 -0700397 self.fail("Device should not be available")
Luis Hector Chavez32559742018-05-02 10:47:01 -0700398 except subprocess.CalledProcessError as err:
399 self.assertEqual(
400 err.output.strip(),
Josh Gaob3610732018-08-08 13:08:08 -0700401 "error: device '{}' not found".format(serial).encode("utf8"))
Luis Hector Chavez32559742018-05-02 10:47:01 -0700402
403 # Let the ADB server know that the emulator has started.
404 with contextlib.closing(
Josh Gao9b6522b2018-08-07 14:31:17 -0700405 socket.socket(socket.AF_INET, socket.SOCK_STREAM)) as sock:
Josh Gaob3610732018-08-08 13:08:08 -0700406 sock.connect(("localhost", server_port))
407 command = "host:emulator:{}".format(port).encode("utf8")
408 sock.sendall(b"%04x%s" % (len(command), command))
Luis Hector Chavez32559742018-05-02 10:47:01 -0700409
410 # Ensure the emulator is there.
Josh Gaob3610732018-08-08 13:08:08 -0700411 subprocess.check_call(["adb", "-P", str(server_port),
412 "-s", serial, "wait-for-device"])
413 output = subprocess.check_output(["adb", "-P", str(server_port),
414 "-s", serial, "get-state"])
415 self.assertEqual(output.strip(), b"device")
Luis Hector Chavez32559742018-05-02 10:47:01 -0700416
Luis Hector Chavezfbee0a92018-05-02 09:10:29 -0700417
418class ConnectionTest(unittest.TestCase):
419 """Tests for adb connect."""
Spencer Low351ecd12015-10-14 17:32:44 -0700420
Josh Gao78cc20f2016-09-01 14:54:18 -0700421 def test_connect_ipv4_ipv6(self):
422 """Ensure that `adb connect localhost:1234` will try both IPv4 and IPv6.
423
424 Bug: http://b/30313466
425 """
Luis Hector Chavez8b67c522018-04-17 19:25:33 -0700426 for protocol in (socket.AF_INET, socket.AF_INET6):
427 try:
Josh Gao902dace2018-08-10 14:44:54 -0700428 with fake_adbd(protocol=protocol) as (port, _):
Josh Gaob3610732018-08-08 13:08:08 -0700429 serial = "localhost:{}".format(port)
Luis Hector Chavez454bc7c2018-04-20 10:31:29 -0700430 with adb_connect(self, serial):
431 pass
Luis Hector Chavez8b67c522018-04-17 19:25:33 -0700432 except socket.error:
433 print("IPv6 not available, skipping")
434 continue
Josh Gao78cc20f2016-09-01 14:54:18 -0700435
Luis Hector Chavez8b67c522018-04-17 19:25:33 -0700436 def test_already_connected(self):
Luis Hector Chavez454bc7c2018-04-20 10:31:29 -0700437 """Ensure that an already-connected device stays connected."""
438
Josh Gao902dace2018-08-10 14:44:54 -0700439 with fake_adbd() as (port, _):
Josh Gaob3610732018-08-08 13:08:08 -0700440 serial = "localhost:{}".format(port)
Luis Hector Chavez454bc7c2018-04-20 10:31:29 -0700441 with adb_connect(self, serial):
442 # b/31250450: this always returns 0 but probably shouldn't.
Josh Gaob3610732018-08-08 13:08:08 -0700443 output = subprocess.check_output(["adb", "connect", serial])
Luis Hector Chavez454bc7c2018-04-20 10:31:29 -0700444 self.assertEqual(
Josh Gao9b6522b2018-08-07 14:31:17 -0700445 output.strip(),
Josh Gaob3610732018-08-08 13:08:08 -0700446 "already connected to {}".format(serial).encode("utf8"))
Josh Gao78cc20f2016-09-01 14:54:18 -0700447
Julien Desprezfb4c1352019-02-20 09:42:49 -0800448 @unittest.skip("Currently failing b/123247844")
Luis Hector Chavez454bc7c2018-04-20 10:31:29 -0700449 def test_reconnect(self):
450 """Ensure that a disconnected device reconnects."""
Josh Gao78cc20f2016-09-01 14:54:18 -0700451
Josh Gao902dace2018-08-10 14:44:54 -0700452 with fake_adbd() as (port, _):
Josh Gaob3610732018-08-08 13:08:08 -0700453 serial = "localhost:{}".format(port)
Luis Hector Chavez454bc7c2018-04-20 10:31:29 -0700454 with adb_connect(self, serial):
Josh Gaoaa95aa02019-02-07 17:53:29 -0800455 # Wait a bit to give adb some time to connect.
456 time.sleep(0.25)
457
Josh Gaob3610732018-08-08 13:08:08 -0700458 output = subprocess.check_output(["adb", "-s", serial,
459 "get-state"])
460 self.assertEqual(output.strip(), b"device")
Josh Gaoc251ec52018-04-03 12:55:18 -0700461
Luis Hector Chavez454bc7c2018-04-20 10:31:29 -0700462 # This will fail.
Josh Gaob3610732018-08-08 13:08:08 -0700463 proc = subprocess.Popen(["adb", "-s", serial, "shell", "true"],
Luis Hector Chavezfbee0a92018-05-02 09:10:29 -0700464 stdout=subprocess.PIPE,
465 stderr=subprocess.STDOUT)
466 output, _ = proc.communicate()
Josh Gaob3610732018-08-08 13:08:08 -0700467 self.assertEqual(output.strip(), b"error: closed")
Luis Hector Chavez454bc7c2018-04-20 10:31:29 -0700468
Josh Gaob3610732018-08-08 13:08:08 -0700469 subprocess.check_call(["adb", "-s", serial, "wait-for-device"])
Luis Hector Chavez454bc7c2018-04-20 10:31:29 -0700470
Josh Gaob3610732018-08-08 13:08:08 -0700471 output = subprocess.check_output(["adb", "-s", serial,
472 "get-state"])
473 self.assertEqual(output.strip(), b"device")
Luis Hector Chavez454bc7c2018-04-20 10:31:29 -0700474
475 # Once we explicitly kick a device, it won't attempt to
476 # reconnect.
Josh Gaob3610732018-08-08 13:08:08 -0700477 output = subprocess.check_output(["adb", "disconnect", serial])
Luis Hector Chavez454bc7c2018-04-20 10:31:29 -0700478 self.assertEqual(
Josh Gao9b6522b2018-08-07 14:31:17 -0700479 output.strip(),
Josh Gaob3610732018-08-08 13:08:08 -0700480 "disconnected {}".format(serial).encode("utf8"))
Luis Hector Chavez454bc7c2018-04-20 10:31:29 -0700481 try:
Josh Gaob3610732018-08-08 13:08:08 -0700482 subprocess.check_output(["adb", "-s", serial, "get-state"],
Luis Hector Chavez454bc7c2018-04-20 10:31:29 -0700483 stderr=subprocess.STDOUT)
Josh Gaob3610732018-08-08 13:08:08 -0700484 self.fail("Device should not be available")
Luis Hector Chavezfbee0a92018-05-02 09:10:29 -0700485 except subprocess.CalledProcessError as err:
Luis Hector Chavez454bc7c2018-04-20 10:31:29 -0700486 self.assertEqual(
Luis Hector Chavezfbee0a92018-05-02 09:10:29 -0700487 err.output.strip(),
Josh Gaob3610732018-08-08 13:08:08 -0700488 "error: device '{}' not found".format(serial).encode("utf8"))
Spencer Low351ecd12015-10-14 17:32:44 -0700489
Luis Hector Chavezfbee0a92018-05-02 09:10:29 -0700490
Josh Gao902dace2018-08-10 14:44:54 -0700491class DisconnectionTest(unittest.TestCase):
492 """Tests for adb disconnect."""
493
494 def test_disconnect(self):
495 """Ensure that `adb disconnect` takes effect immediately."""
496
497 def _devices(port):
498 output = subprocess.check_output(["adb", "-P", str(port), "devices"])
499 return [x.split("\t") for x in output.decode("utf8").strip().splitlines()[1:]]
500
501 with adb_server() as server_port:
502 with fake_adbd() as (port, sock):
503 device_name = "localhost:{}".format(port)
504 output = subprocess.check_output(["adb", "-P", str(server_port),
505 "connect", device_name])
506 self.assertEqual(output.strip(),
507 "connected to {}".format(device_name).encode("utf8"))
508
509
510 self.assertEqual(_devices(server_port), [[device_name, "device"]])
511
512 # Send a deliberately malformed packet to make the device go offline.
513 packet = struct.pack("IIIIII", 0, 0, 0, 0, 0, 0)
514 sock.sendall(packet)
515
516 # Wait a bit.
517 time.sleep(0.1)
518
519 self.assertEqual(_devices(server_port), [[device_name, "offline"]])
520
521 # Disconnect the device.
522 output = subprocess.check_output(["adb", "-P", str(server_port),
523 "disconnect", device_name])
524
525 # Wait a bit.
526 time.sleep(0.1)
527
528 self.assertEqual(_devices(server_port), [])
529
530
Spencer Low8f6bdc92018-08-31 19:49:46 -0700531@unittest.skipUnless(sys.platform == "win32", "requires Windows")
532class PowerTest(unittest.TestCase):
533 def test_resume_usb_kick(self):
534 """Resuming from sleep/hibernate should kick USB devices."""
535 try:
536 usb_serial = subprocess.check_output(["adb", "-d", "get-serialno"]).strip()
537 except subprocess.CalledProcessError:
538 # If there are multiple USB devices, we don't have a way to check whether the selected
539 # device is USB.
540 raise unittest.SkipTest('requires single USB device')
541
542 try:
543 serial = subprocess.check_output(["adb", "get-serialno"]).strip()
544 except subprocess.CalledProcessError:
545 # Did you forget to select a device with $ANDROID_SERIAL?
546 raise unittest.SkipTest('requires $ANDROID_SERIAL set to a USB device')
547
548 # Test only works with USB devices because adb _power_notification_thread does not kick
549 # non-USB devices on resume event.
550 if serial != usb_serial:
551 raise unittest.SkipTest('requires USB device')
552
553 # Run an adb shell command in the background that takes a while to complete.
554 proc = subprocess.Popen(['adb', 'shell', 'sleep', '5'])
555
556 # Wait for startup of adb server's _power_notification_thread.
557 time.sleep(0.1)
558
559 # Simulate resuming from sleep/hibernation by sending Windows message.
560 import ctypes
561 from ctypes import wintypes
562 HWND_BROADCAST = 0xffff
563 WM_POWERBROADCAST = 0x218
564 PBT_APMRESUMEAUTOMATIC = 0x12
565
566 PostMessageW = ctypes.windll.user32.PostMessageW
567 PostMessageW.restype = wintypes.BOOL
568 PostMessageW.argtypes = (wintypes.HWND, wintypes.UINT, wintypes.WPARAM, wintypes.LPARAM)
569 result = PostMessageW(HWND_BROADCAST, WM_POWERBROADCAST, PBT_APMRESUMEAUTOMATIC, 0)
570 if not result:
571 raise ctypes.WinError()
572
573 # Wait for connection to adb shell to be broken by _power_notification_thread detecting the
574 # Windows message.
575 start = time.time()
576 proc.wait()
577 end = time.time()
578
579 # If the power event was detected, the adb shell command should be broken very quickly.
580 self.assertLess(end - start, 2)
581
Joshua Duong504d3932020-03-31 10:58:50 -0700582"""Use 'adb mdns check' to see if mdns discovery is available."""
583def is_adb_mdns_available():
584 with adb_server() as server_port:
585 output = subprocess.check_output(["adb", "-P", str(server_port),
586 "mdns", "check"]).strip()
587 return output.startswith(b"mdns daemon version")
588
Joshua Duong13c639e2020-03-31 08:39:24 -0700589"""Check if we have zeroconf python library installed"""
590def is_zeroconf_installed():
591 zeroconf_spec = util.find_spec("zeroconf")
592 return zeroconf_spec is not None
593
594@contextlib.contextmanager
595def zeroconf_context(ipversion):
596 from zeroconf import Zeroconf
597 """Context manager for a zeroconf instance
598
599 This creates a zeroconf instance and returns it.
600 """
601
602 try:
603 zeroconf = Zeroconf(ip_version=ipversion)
604 yield zeroconf
605 finally:
606 zeroconf.close()
607
608@contextlib.contextmanager
609def zeroconf_register_service(zeroconf_ctx, info):
610 """Context manager for a zeroconf service
611
612 Registers a service and unregisters it on cleanup. Returns the ServiceInfo
613 supplied.
614 """
615
616 try:
617 zeroconf_ctx.register_service(info)
618 yield info
619 finally:
620 zeroconf_ctx.unregister_service(info)
621
622"""Should match the service names listed in adb_mdns.h"""
623@parameterized_class(('service_name',), [
624 ("adb",),
625 ("adb-tls-connect",),
626 ("adb-tls-pairing",),
627])
Joshua Duong504d3932020-03-31 10:58:50 -0700628@unittest.skipIf(not is_adb_mdns_available(), "mdns feature not available")
629class MdnsTest(unittest.TestCase):
630 """Tests for adb mdns."""
Joshua Duong13c639e2020-03-31 08:39:24 -0700631
Joshua Duong7ebc5952020-05-01 09:25:12 -0700632 @staticmethod
633 def _mdns_services(port):
634 output = subprocess.check_output(["adb", "-P", str(port), "mdns", "services"])
635 return [x.split("\t") for x in output.decode("utf8").strip().splitlines()[1:]]
636
637 @staticmethod
638 def _devices(port):
639 output = subprocess.check_output(["adb", "-P", str(port), "devices"])
640 return [x.split("\t") for x in output.decode("utf8").strip().splitlines()[1:]]
641
642 @contextlib.contextmanager
643 def _adb_mdns_connect(self, server_port, mdns_instance, serial, should_connect):
644 """Context manager for an ADB connection.
645
646 This automatically disconnects when done with the connection.
647 """
648
649 output = subprocess.check_output(["adb", "-P", str(server_port), "connect", mdns_instance])
650 if should_connect:
651 self.assertEqual(output.strip(), "connected to {}".format(serial).encode("utf8"))
652 else:
653 self.assertTrue(output.startswith("failed to resolve host: '{}'"
654 .format(mdns_instance).encode("utf8")))
655
656 try:
657 yield
658 finally:
659 # Perform best-effort disconnection. Discard the output.
660 subprocess.Popen(["adb", "disconnect", serial],
661 stdout=subprocess.PIPE,
662 stderr=subprocess.PIPE).communicate()
663
664
Joshua Duong13c639e2020-03-31 08:39:24 -0700665 @unittest.skipIf(not is_zeroconf_installed(), "zeroconf library not installed")
666 def test_mdns_services_register_unregister(self):
667 """Ensure that `adb mdns services` correctly adds and removes a service
668 """
669 from zeroconf import IPVersion, ServiceInfo
Joshua Duong13c639e2020-03-31 08:39:24 -0700670
671 with adb_server() as server_port:
672 output = subprocess.check_output(["adb", "-P", str(server_port),
673 "mdns", "services"]).strip()
674 self.assertTrue(output.startswith(b"List of discovered mdns services"))
Joshua Duong13c639e2020-03-31 08:39:24 -0700675
676 """TODO(joshuaduong): Add ipv6 tests once we have it working in adb"""
677 """Register/Unregister a service"""
678 with zeroconf_context(IPVersion.V4Only) as zc:
679 serv_instance = "my_fake_test_service"
680 serv_type = "_" + self.service_name + "._tcp."
681 serv_ipaddr = socket.inet_aton("1.2.3.4")
682 serv_port = 12345
683 service_info = ServiceInfo(
684 serv_type + "local.",
685 name=serv_instance + "." + serv_type + "local.",
686 addresses=[serv_ipaddr],
687 port=serv_port)
Joshua Duong13c639e2020-03-31 08:39:24 -0700688 with zeroconf_register_service(zc, service_info) as info:
689 """Give adb some time to register the service"""
Joshua Duong077ac112020-04-07 15:16:42 -0700690 time.sleep(1)
Joshua Duong13c639e2020-03-31 08:39:24 -0700691 self.assertTrue(any((serv_instance in line and serv_type in line)
Joshua Duong7ebc5952020-05-01 09:25:12 -0700692 for line in MdnsTest._mdns_services(server_port)))
Joshua Duong13c639e2020-03-31 08:39:24 -0700693
694 """Give adb some time to unregister the service"""
Joshua Duong077ac112020-04-07 15:16:42 -0700695 time.sleep(1)
Joshua Duong13c639e2020-03-31 08:39:24 -0700696 self.assertFalse(any((serv_instance in line and serv_type in line)
Joshua Duong7ebc5952020-05-01 09:25:12 -0700697 for line in MdnsTest._mdns_services(server_port)))
698
699 @unittest.skipIf(not is_zeroconf_installed(), "zeroconf library not installed")
700 def test_mdns_connect(self):
701 """Ensure that `adb connect` by mdns instance name works (for non-pairing services)
702 """
703 from zeroconf import IPVersion, ServiceInfo
704
705 with adb_server() as server_port:
706 with zeroconf_context(IPVersion.V4Only) as zc:
707 serv_instance = "fakeadbd-" + ''.join(
708 random.choice(string.ascii_letters) for i in range(4))
709 serv_type = "_" + self.service_name + "._tcp."
710 serv_ipaddr = socket.inet_aton("127.0.0.1")
711 should_connect = self.service_name != "adb-tls-pairing"
712 with fake_adbd() as (port, _):
713 service_info = ServiceInfo(
714 serv_type + "local.",
715 name=serv_instance + "." + serv_type + "local.",
716 addresses=[serv_ipaddr],
717 port=port)
718 with zeroconf_register_service(zc, service_info) as info:
719 """Give adb some time to register the service"""
720 time.sleep(1)
721 self.assertTrue(any((serv_instance in line and serv_type in line)
722 for line in MdnsTest._mdns_services(server_port)))
723 full_name = '.'.join([serv_instance, serv_type])
724 with self._adb_mdns_connect(server_port, serv_instance, full_name,
725 should_connect):
726 if should_connect:
727 self.assertEqual(MdnsTest._devices(server_port),
728 [[full_name, "device"]])
729
730 """Give adb some time to unregister the service"""
731 time.sleep(1)
732 self.assertFalse(any((serv_instance in line and serv_type in line)
733 for line in MdnsTest._mdns_services(server_port)))
Spencer Low8f6bdc92018-08-31 19:49:46 -0700734
Dan Albert8e1fdd72015-07-24 17:08:33 -0700735def main():
Luis Hector Chavezfbee0a92018-05-02 09:10:29 -0700736 """Main entrypoint."""
Dan Albert8e1fdd72015-07-24 17:08:33 -0700737 random.seed(0)
Luis Hector Chavezfbee0a92018-05-02 09:10:29 -0700738 unittest.main(verbosity=3)
Dan Albert8e1fdd72015-07-24 17:08:33 -0700739
740
Josh Gaob3610732018-08-08 13:08:08 -0700741if __name__ == "__main__":
Dan Albert8e1fdd72015-07-24 17:08:33 -0700742 main()