blob: 64278dc75d7250630b70c848daee440af7ea213d [file] [log] [blame]
Josh Gaob1df00e2018-08-07 14:31:17 -07001#!/usr/bin/env python3
Dan Alberta4169f92015-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 Alberta4169f92015-07-24 17:08:33 -070022
Spencer Lowcc4a4b12015-10-14 17:32:44 -070023import contextlib
Spencer Low9a999242015-09-16 20:45:53 -070024import os
Dan Alberta4169f92015-07-24 17:08:33 -070025import random
Luis Hector Chavezbf8a7222018-04-17 19:25:33 -070026import select
Spencer Lowcc4a4b12015-10-14 17:32:44 -070027import socket
Joshua Duong7ea62d82020-05-01 09:25:12 -070028import string
Spencer Lowcc4a4b12015-10-14 17:32:44 -070029import struct
Dan Alberta4169f92015-07-24 17:08:33 -070030import subprocess
Josh Gao6d7b9652018-08-21 14:25:05 -070031import sys
Spencer Low9a999242015-09-16 20:45:53 -070032import threading
Josh Gao13cb8c02018-08-10 14:44:54 -070033import time
Dan Alberta4169f92015-07-24 17:08:33 -070034import unittest
Josh Gaobe294912018-10-16 11:00:39 -070035import warnings
Joshua Duong5f63d112020-03-31 08:39:24 -070036from importlib import util
Dan Alberta4169f92015-07-24 17:08:33 -070037
Josh Gaoe9fdf4a2020-02-27 14:29:38 -080038def find_open_port():
39 # Find an open port.
40 with socket.socket() as s:
41 s.bind(("localhost", 0))
42 return s.getsockname()[1]
Dan Alberta4169f92015-07-24 17:08:33 -070043
Luis Hector Chavezbf8a7222018-04-17 19:25:33 -070044@contextlib.contextmanager
Luis Hector Chavez947b2132018-05-02 09:10:29 -070045def fake_adbd(protocol=socket.AF_INET, port=0):
46 """Creates a fake ADB daemon that just replies with a CNXN packet."""
Luis Hector Chavezbf8a7222018-04-17 19:25:33 -070047
48 serversock = socket.socket(protocol, socket.SOCK_STREAM)
Luis Hector Chavez947b2132018-05-02 09:10:29 -070049 serversock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
Luis Hector Chavezbf8a7222018-04-17 19:25:33 -070050 if protocol == socket.AF_INET:
Josh Gao4db70c52018-08-08 13:08:08 -070051 serversock.bind(("127.0.0.1", port))
Luis Hector Chavezbf8a7222018-04-17 19:25:33 -070052 else:
Josh Gao4db70c52018-08-08 13:08:08 -070053 serversock.bind(("::1", port))
Luis Hector Chavezbf8a7222018-04-17 19:25:33 -070054 serversock.listen(1)
55
56 # A pipe that is used to signal the thread that it should terminate.
Josh Gao6afbf792018-08-07 16:07:25 -070057 readsock, writesock = socket.socketpair()
Luis Hector Chavezbf8a7222018-04-17 19:25:33 -070058
Josh Gaob1df00e2018-08-07 14:31:17 -070059 def _adb_packet(command: bytes, arg0: int, arg1: int, data: bytes) -> bytes:
Josh Gao4db70c52018-08-08 13:08:08 -070060 bin_command = struct.unpack("I", command)[0]
61 buf = struct.pack("IIIIII", bin_command, arg0, arg1, len(data), 0,
Luis Hector Chavezda74b902018-04-17 14:25:04 -070062 bin_command ^ 0xffffffff)
63 buf += data
64 return buf
65
Josh Gaob1df00e2018-08-07 14:31:17 -070066 def _handle(sock):
67 with contextlib.closing(sock) as serversock:
Josh Gao6afbf792018-08-07 16:07:25 -070068 rlist = [readsock, serversock]
Josh Gaob1df00e2018-08-07 14:31:17 -070069 cnxn_sent = {}
70 while True:
71 read_ready, _, _ = select.select(rlist, [], [])
72 for ready in read_ready:
Josh Gao6afbf792018-08-07 16:07:25 -070073 if ready == readsock:
Josh Gaob1df00e2018-08-07 14:31:17 -070074 # Closure pipe
Josh Gaob1df00e2018-08-07 14:31:17 -070075 for f in rlist:
Josh Gao6afbf792018-08-07 16:07:25 -070076 f.close()
Josh Gaob1df00e2018-08-07 14:31:17 -070077 return
78 elif ready == serversock:
79 # Server socket
80 conn, _ = ready.accept()
81 rlist.append(conn)
82 else:
83 # Client socket
84 data = ready.recv(1024)
Josh Gao4db70c52018-08-08 13:08:08 -070085 if not data or data.startswith(b"OPEN"):
Josh Gaob1df00e2018-08-07 14:31:17 -070086 if ready in cnxn_sent:
87 del cnxn_sent[ready]
88 ready.shutdown(socket.SHUT_RDWR)
89 ready.close()
90 rlist.remove(ready)
91 continue
Luis Hector Chavez947b2132018-05-02 09:10:29 -070092 if ready in cnxn_sent:
Josh Gaob1df00e2018-08-07 14:31:17 -070093 continue
94 cnxn_sent[ready] = True
Josh Gao4db70c52018-08-08 13:08:08 -070095 ready.sendall(_adb_packet(b"CNXN", 0x01000001, 1024 * 1024,
96 b"device::ro.product.name=fakeadb"))
Luis Hector Chavezbf8a7222018-04-17 19:25:33 -070097
98 port = serversock.getsockname()[1]
Josh Gaob1df00e2018-08-07 14:31:17 -070099 server_thread = threading.Thread(target=_handle, args=(serversock,))
Luis Hector Chavezbf8a7222018-04-17 19:25:33 -0700100 server_thread.start()
101
102 try:
Josh Gao13cb8c02018-08-10 14:44:54 -0700103 yield port, writesock
Luis Hector Chavezbf8a7222018-04-17 19:25:33 -0700104 finally:
Josh Gao6afbf792018-08-07 16:07:25 -0700105 writesock.close()
Luis Hector Chavezbf8a7222018-04-17 19:25:33 -0700106 server_thread.join()
107
108
Luis Hector Chavez0aeda102018-04-20 10:31:29 -0700109@contextlib.contextmanager
110def adb_connect(unittest, serial):
111 """Context manager for an ADB connection.
112
113 This automatically disconnects when done with the connection.
114 """
115
Josh Gao4db70c52018-08-08 13:08:08 -0700116 output = subprocess.check_output(["adb", "connect", serial])
Josh Gaob1df00e2018-08-07 14:31:17 -0700117 unittest.assertEqual(output.strip(),
Josh Gao4db70c52018-08-08 13:08:08 -0700118 "connected to {}".format(serial).encode("utf8"))
Luis Hector Chavez0aeda102018-04-20 10:31:29 -0700119
120 try:
121 yield
122 finally:
123 # Perform best-effort disconnection. Discard the output.
Josh Gao4db70c52018-08-08 13:08:08 -0700124 subprocess.Popen(["adb", "disconnect", serial],
Luis Hector Chavez947b2132018-05-02 09:10:29 -0700125 stdout=subprocess.PIPE,
126 stderr=subprocess.PIPE).communicate()
Luis Hector Chavez0aeda102018-04-20 10:31:29 -0700127
128
Luis Hector Chaveza452f0e2018-05-02 10:47:01 -0700129@contextlib.contextmanager
130def adb_server():
131 """Context manager for an ADB server.
132
Josh Gao13cb8c02018-08-10 14:44:54 -0700133 This creates an ADB server and returns the port it's listening on.
Luis Hector Chaveza452f0e2018-05-02 10:47:01 -0700134 """
135
Josh Gaoe9fdf4a2020-02-27 14:29:38 -0800136 port = find_open_port()
Luis Hector Chaveza452f0e2018-05-02 10:47:01 -0700137 read_pipe, write_pipe = os.pipe()
Josh Gao6d7b9652018-08-21 14:25:05 -0700138
139 if sys.platform == "win32":
140 import msvcrt
141 write_handle = msvcrt.get_osfhandle(write_pipe)
142 os.set_handle_inheritable(write_handle, True)
143 reply_fd = str(write_handle)
144 else:
145 os.set_inheritable(write_pipe, True)
146 reply_fd = str(write_pipe)
147
Josh Gao4db70c52018-08-08 13:08:08 -0700148 proc = subprocess.Popen(["adb", "-L", "tcp:localhost:{}".format(port),
149 "fork-server", "server",
Josh Gao6d7b9652018-08-21 14:25:05 -0700150 "--reply-fd", reply_fd], close_fds=False)
Luis Hector Chaveza452f0e2018-05-02 10:47:01 -0700151 try:
152 os.close(write_pipe)
153 greeting = os.read(read_pipe, 1024)
Josh Gao4db70c52018-08-08 13:08:08 -0700154 assert greeting == b"OK\n", repr(greeting)
Luis Hector Chaveza452f0e2018-05-02 10:47:01 -0700155 yield port
156 finally:
157 proc.terminate()
158 proc.wait()
159
160
Luis Hector Chavez947b2132018-05-02 09:10:29 -0700161class CommandlineTest(unittest.TestCase):
162 """Tests for the ADB commandline."""
Dan Alberta4169f92015-07-24 17:08:33 -0700163
164 def test_help(self):
165 """Make sure we get _something_ out of help."""
166 out = subprocess.check_output(
Josh Gao4db70c52018-08-08 13:08:08 -0700167 ["adb", "help"], stderr=subprocess.STDOUT)
Dan Alberta4169f92015-07-24 17:08:33 -0700168 self.assertGreater(len(out), 0)
169
170 def test_version(self):
171 """Get a version number out of the output of adb."""
Josh Gao4db70c52018-08-08 13:08:08 -0700172 lines = subprocess.check_output(["adb", "version"]).splitlines()
Dan Alberta4169f92015-07-24 17:08:33 -0700173 version_line = lines[0]
Josh Gaob1df00e2018-08-07 14:31:17 -0700174 self.assertRegex(
Josh Gao4db70c52018-08-08 13:08:08 -0700175 version_line, rb"^Android Debug Bridge version \d+\.\d+\.\d+$")
Dan Alberta4169f92015-07-24 17:08:33 -0700176 if len(lines) == 2:
177 # Newer versions of ADB have a second line of output for the
178 # version that includes a specific revision (git SHA).
179 revision_line = lines[1]
Josh Gaob1df00e2018-08-07 14:31:17 -0700180 self.assertRegex(
Josh Gao4db70c52018-08-08 13:08:08 -0700181 revision_line, rb"^Revision [0-9a-f]{12}-android$")
Dan Alberta4169f92015-07-24 17:08:33 -0700182
183 def test_tcpip_error_messages(self):
Luis Hector Chavez947b2132018-05-02 09:10:29 -0700184 """Make sure 'adb tcpip' parsing is sane."""
Josh Gao4db70c52018-08-08 13:08:08 -0700185 proc = subprocess.Popen(["adb", "tcpip"],
Josh Gaob1df00e2018-08-07 14:31:17 -0700186 stdout=subprocess.PIPE,
Luis Hector Chavez947b2132018-05-02 09:10:29 -0700187 stderr=subprocess.STDOUT)
188 out, _ = proc.communicate()
189 self.assertEqual(1, proc.returncode)
Josh Gao4db70c52018-08-08 13:08:08 -0700190 self.assertIn(b"requires an argument", out)
Dan Alberta4169f92015-07-24 17:08:33 -0700191
Josh Gao4db70c52018-08-08 13:08:08 -0700192 proc = subprocess.Popen(["adb", "tcpip", "foo"],
Josh Gaob1df00e2018-08-07 14:31:17 -0700193 stdout=subprocess.PIPE,
Luis Hector Chavez947b2132018-05-02 09:10:29 -0700194 stderr=subprocess.STDOUT)
195 out, _ = proc.communicate()
196 self.assertEqual(1, proc.returncode)
Josh Gao4db70c52018-08-08 13:08:08 -0700197 self.assertIn(b"invalid port", out)
Dan Alberta4169f92015-07-24 17:08:33 -0700198
Luis Hector Chavez947b2132018-05-02 09:10:29 -0700199
200class ServerTest(unittest.TestCase):
201 """Tests for the ADB server."""
202
203 @staticmethod
204 def _read_pipe_and_set_event(pipe, event):
205 """Reads a pipe until it is closed, then sets the event."""
206 pipe.read()
Spencer Low9a999242015-09-16 20:45:53 -0700207 event.set()
208
Spencer Low9a999242015-09-16 20:45:53 -0700209 def test_handle_inheritance(self):
Luis Hector Chavez947b2132018-05-02 09:10:29 -0700210 """Test that launch_server() does not inherit handles.
211
212 launch_server() should not let the adb server inherit
213 stdin/stdout/stderr handles, which can cause callers of adb.exe to hang.
214 This test also runs fine on unix even though the impetus is an issue
215 unique to Windows.
216 """
Spencer Low9a999242015-09-16 20:45:53 -0700217 # This test takes 5 seconds to run on Windows: if there is no adb server
218 # running on the the port used below, adb kill-server tries to make a
219 # TCP connection to a closed port and that takes 1 second on Windows;
220 # adb start-server does the same TCP connection which takes another
221 # second, and it waits 3 seconds after starting the server.
222
223 # Start adb client with redirected stdin/stdout/stderr to check if it
224 # passes those redirections to the adb server that it starts. To do
225 # this, run an instance of the adb server on a non-default port so we
226 # don't conflict with a pre-existing adb server that may already be
227 # setup with adb TCP/emulator connections. If there is a pre-existing
228 # adb server, this also tests whether multiple instances of the adb
229 # server conflict on adb.log.
230
Josh Gaoe9fdf4a2020-02-27 14:29:38 -0800231 port = find_open_port()
Spencer Low9a999242015-09-16 20:45:53 -0700232
233 try:
Josh Gaobe294912018-10-16 11:00:39 -0700234 # We get warnings for unclosed files for the subprocess's pipes,
235 # and it's somewhat cumbersome to close them, so just ignore this.
236 warnings.simplefilter("ignore", ResourceWarning)
237
Spencer Low9a999242015-09-16 20:45:53 -0700238 # Run the adb client and have it start the adb server.
Josh Gao4db70c52018-08-08 13:08:08 -0700239 proc = subprocess.Popen(["adb", "-P", str(port), "start-server"],
Luis Hector Chavez947b2132018-05-02 09:10:29 -0700240 stdin=subprocess.PIPE,
241 stdout=subprocess.PIPE,
242 stderr=subprocess.PIPE)
Spencer Low9a999242015-09-16 20:45:53 -0700243
244 # Start threads that set events when stdout/stderr are closed.
245 stdout_event = threading.Event()
246 stdout_thread = threading.Thread(
Luis Hector Chavez947b2132018-05-02 09:10:29 -0700247 target=ServerTest._read_pipe_and_set_event,
248 args=(proc.stdout, stdout_event))
Spencer Low9a999242015-09-16 20:45:53 -0700249 stdout_thread.start()
250
251 stderr_event = threading.Event()
252 stderr_thread = threading.Thread(
Luis Hector Chavez947b2132018-05-02 09:10:29 -0700253 target=ServerTest._read_pipe_and_set_event,
254 args=(proc.stderr, stderr_event))
Spencer Low9a999242015-09-16 20:45:53 -0700255 stderr_thread.start()
256
257 # Wait for the adb client to finish. Once that has occurred, if
258 # stdin/stderr/stdout are still open, it must be open in the adb
259 # server.
Luis Hector Chavez947b2132018-05-02 09:10:29 -0700260 proc.wait()
Spencer Low9a999242015-09-16 20:45:53 -0700261
262 # Try to write to stdin which we expect is closed. If it isn't
263 # closed, we should get an IOError. If we don't get an IOError,
264 # stdin must still be open in the adb server. The adb client is
265 # probably letting the adb server inherit stdin which would be
266 # wrong.
267 with self.assertRaises(IOError):
Josh Gao4db70c52018-08-08 13:08:08 -0700268 proc.stdin.write(b"x")
Josh Gaob1df00e2018-08-07 14:31:17 -0700269 proc.stdin.flush()
Spencer Low9a999242015-09-16 20:45:53 -0700270
271 # Wait a few seconds for stdout/stderr to be closed (in the success
272 # case, this won't wait at all). If there is a timeout, that means
273 # stdout/stderr were not closed and and they must be open in the adb
274 # server, suggesting that the adb client is letting the adb server
275 # inherit stdout/stderr which would be wrong.
276 self.assertTrue(stdout_event.wait(5), "adb stdout not closed")
277 self.assertTrue(stderr_event.wait(5), "adb stderr not closed")
Josh Gaob1df00e2018-08-07 14:31:17 -0700278 stdout_thread.join()
279 stderr_thread.join()
Spencer Low9a999242015-09-16 20:45:53 -0700280 finally:
281 # If we started a server, kill it.
Josh Gao4db70c52018-08-08 13:08:08 -0700282 subprocess.check_output(["adb", "-P", str(port), "kill-server"],
Spencer Low9a999242015-09-16 20:45:53 -0700283 stderr=subprocess.STDOUT)
Dan Alberta4169f92015-07-24 17:08:33 -0700284
Callum Ryan04efea32019-10-31 07:21:42 -0700285 @unittest.skipUnless(
286 os.name == "posix",
287 "adb doesn't yet support IPv6 on Windows",
288 )
Josh Gao4658efe2021-02-01 18:11:49 -0800289 def disabled_test_starts_on_ipv6_localhost(self):
Callum Ryan04efea32019-10-31 07:21:42 -0700290 """
291 Tests that the server can start up on ::1 and that it's accessible
Josh Gao4658efe2021-02-01 18:11:49 -0800292
293 Disabled due to b/178980410
Callum Ryan04efea32019-10-31 07:21:42 -0700294 """
Josh Gaoe9fdf4a2020-02-27 14:29:38 -0800295
296 server_port = find_open_port()
Callum Ryan04efea32019-10-31 07:21:42 -0700297 try:
298 subprocess.check_output(
299 ["adb", "-L", "tcp:[::1]:{}".format(server_port), "server"],
300 stderr=subprocess.STDOUT,
301 )
302 with fake_adbd() as (port, _):
303 with adb_connect(self, serial="localhost:{}".format(port)):
304 pass
305 finally:
306 # If we started a server, kill it.
307 subprocess.check_output(
308 ["adb", "-P", str(server_port), "kill-server"],
309 stderr=subprocess.STDOUT,
310 )
311
312
313
Luis Hector Chavez947b2132018-05-02 09:10:29 -0700314
315class EmulatorTest(unittest.TestCase):
316 """Tests for the emulator connection."""
317
Spencer Lowcc4a4b12015-10-14 17:32:44 -0700318 def _reset_socket_on_close(self, sock):
Luis Hector Chavez947b2132018-05-02 09:10:29 -0700319 """Use SO_LINGER to cause TCP RST segment to be sent on socket close."""
Spencer Lowcc4a4b12015-10-14 17:32:44 -0700320 # The linger structure is two shorts on Windows, but two ints on Unix.
Josh Gao4db70c52018-08-08 13:08:08 -0700321 linger_format = "hh" if os.name == "nt" else "ii"
Spencer Lowcc4a4b12015-10-14 17:32:44 -0700322 l_onoff = 1
323 l_linger = 0
324
325 sock.setsockopt(socket.SOL_SOCKET, socket.SO_LINGER,
326 struct.pack(linger_format, l_onoff, l_linger))
327 # Verify that we set the linger structure properly by retrieving it.
328 linger = sock.getsockopt(socket.SOL_SOCKET, socket.SO_LINGER, 16)
329 self.assertEqual((l_onoff, l_linger),
330 struct.unpack_from(linger_format, linger))
331
332 def test_emu_kill(self):
333 """Ensure that adb emu kill works.
334
335 Bug: https://code.google.com/p/android/issues/detail?id=21021
336 """
Spencer Lowcc4a4b12015-10-14 17:32:44 -0700337 with contextlib.closing(
Luis Hector Chavez947b2132018-05-02 09:10:29 -0700338 socket.socket(socket.AF_INET, socket.SOCK_STREAM)) as listener:
Spencer Lowcc4a4b12015-10-14 17:32:44 -0700339 # Use SO_REUSEADDR so subsequent runs of the test can grab the port
340 # even if it is in TIME_WAIT.
341 listener.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
Josh Gao4db70c52018-08-08 13:08:08 -0700342 listener.bind(("127.0.0.1", 0))
Spencer Lowcc4a4b12015-10-14 17:32:44 -0700343 listener.listen(4)
Josh Gao13781e82018-04-03 12:55:18 -0700344 port = listener.getsockname()[1]
Spencer Lowcc4a4b12015-10-14 17:32:44 -0700345
346 # Now that listening has started, start adb emu kill, telling it to
347 # connect to our mock emulator.
Luis Hector Chavez947b2132018-05-02 09:10:29 -0700348 proc = subprocess.Popen(
Josh Gao4db70c52018-08-08 13:08:08 -0700349 ["adb", "-s", "emulator-" + str(port), "emu", "kill"],
Spencer Lowcc4a4b12015-10-14 17:32:44 -0700350 stderr=subprocess.STDOUT)
351
352 accepted_connection, addr = listener.accept()
353 with contextlib.closing(accepted_connection) as conn:
354 # If WSAECONNABORTED (10053) is raised by any socket calls,
355 # then adb probably isn't reading the data that we sent it.
Josh Gao4db70c52018-08-08 13:08:08 -0700356 conn.sendall(("Android Console: type 'help' for a list "
357 "of commands\r\n").encode("utf8"))
358 conn.sendall(b"OK\r\n")
Spencer Lowcc4a4b12015-10-14 17:32:44 -0700359
Luis Hector Chavez947b2132018-05-02 09:10:29 -0700360 with contextlib.closing(conn.makefile()) as connf:
361 line = connf.readline()
Josh Gao4db70c52018-08-08 13:08:08 -0700362 if line.startswith("auth"):
Luis Hector Chavez947b2132018-05-02 09:10:29 -0700363 # Ignore the first auth line.
364 line = connf.readline()
Josh Gao4db70c52018-08-08 13:08:08 -0700365 self.assertEqual("kill\n", line)
366 self.assertEqual("quit\n", connf.readline())
Spencer Lowcc4a4b12015-10-14 17:32:44 -0700367
Josh Gao4db70c52018-08-08 13:08:08 -0700368 conn.sendall(b"OK: killing emulator, bye bye\r\n")
Spencer Lowcc4a4b12015-10-14 17:32:44 -0700369
370 # Use SO_LINGER to send TCP RST segment to test whether adb
371 # ignores WSAECONNRESET on Windows. This happens with the
372 # real emulator because it just calls exit() without closing
373 # the socket or calling shutdown(SD_SEND). At process
374 # termination, Windows sends a TCP RST segment for every
375 # open socket that shutdown(SD_SEND) wasn't used on.
376 self._reset_socket_on_close(conn)
377
378 # Wait for adb to finish, so we can check return code.
Luis Hector Chavez947b2132018-05-02 09:10:29 -0700379 proc.communicate()
Spencer Lowcc4a4b12015-10-14 17:32:44 -0700380
381 # If this fails, adb probably isn't ignoring WSAECONNRESET when
382 # reading the response from the adb emu kill command (on Windows).
Luis Hector Chavez947b2132018-05-02 09:10:29 -0700383 self.assertEqual(0, proc.returncode)
384
Luis Hector Chaveza452f0e2018-05-02 10:47:01 -0700385 def test_emulator_connect(self):
386 """Ensure that the emulator can connect.
387
388 Bug: http://b/78991667
389 """
390 with adb_server() as server_port:
Josh Gao13cb8c02018-08-10 14:44:54 -0700391 with fake_adbd() as (port, _):
Josh Gao4db70c52018-08-08 13:08:08 -0700392 serial = "emulator-{}".format(port - 1)
Luis Hector Chaveza452f0e2018-05-02 10:47:01 -0700393 # Ensure that the emulator is not there.
394 try:
Josh Gao4db70c52018-08-08 13:08:08 -0700395 subprocess.check_output(["adb", "-P", str(server_port),
396 "-s", serial, "get-state"],
Luis Hector Chaveza452f0e2018-05-02 10:47:01 -0700397 stderr=subprocess.STDOUT)
Josh Gao4db70c52018-08-08 13:08:08 -0700398 self.fail("Device should not be available")
Luis Hector Chaveza452f0e2018-05-02 10:47:01 -0700399 except subprocess.CalledProcessError as err:
400 self.assertEqual(
401 err.output.strip(),
Josh Gao4db70c52018-08-08 13:08:08 -0700402 "error: device '{}' not found".format(serial).encode("utf8"))
Luis Hector Chaveza452f0e2018-05-02 10:47:01 -0700403
404 # Let the ADB server know that the emulator has started.
405 with contextlib.closing(
Josh Gaob1df00e2018-08-07 14:31:17 -0700406 socket.socket(socket.AF_INET, socket.SOCK_STREAM)) as sock:
Josh Gao4db70c52018-08-08 13:08:08 -0700407 sock.connect(("localhost", server_port))
408 command = "host:emulator:{}".format(port).encode("utf8")
409 sock.sendall(b"%04x%s" % (len(command), command))
Luis Hector Chaveza452f0e2018-05-02 10:47:01 -0700410
411 # Ensure the emulator is there.
Josh Gao4db70c52018-08-08 13:08:08 -0700412 subprocess.check_call(["adb", "-P", str(server_port),
413 "-s", serial, "wait-for-device"])
414 output = subprocess.check_output(["adb", "-P", str(server_port),
415 "-s", serial, "get-state"])
416 self.assertEqual(output.strip(), b"device")
Luis Hector Chaveza452f0e2018-05-02 10:47:01 -0700417
Luis Hector Chavez947b2132018-05-02 09:10:29 -0700418
419class ConnectionTest(unittest.TestCase):
420 """Tests for adb connect."""
Spencer Lowcc4a4b12015-10-14 17:32:44 -0700421
Josh Gao50bde8d2016-09-01 14:54:18 -0700422 def test_connect_ipv4_ipv6(self):
423 """Ensure that `adb connect localhost:1234` will try both IPv4 and IPv6.
424
425 Bug: http://b/30313466
426 """
Luis Hector Chavezbf8a7222018-04-17 19:25:33 -0700427 for protocol in (socket.AF_INET, socket.AF_INET6):
428 try:
Josh Gao13cb8c02018-08-10 14:44:54 -0700429 with fake_adbd(protocol=protocol) as (port, _):
Josh Gao4db70c52018-08-08 13:08:08 -0700430 serial = "localhost:{}".format(port)
Luis Hector Chavez0aeda102018-04-20 10:31:29 -0700431 with adb_connect(self, serial):
432 pass
Luis Hector Chavezbf8a7222018-04-17 19:25:33 -0700433 except socket.error:
434 print("IPv6 not available, skipping")
435 continue
Josh Gao50bde8d2016-09-01 14:54:18 -0700436
Luis Hector Chavezbf8a7222018-04-17 19:25:33 -0700437 def test_already_connected(self):
Luis Hector Chavez0aeda102018-04-20 10:31:29 -0700438 """Ensure that an already-connected device stays connected."""
439
Josh Gao13cb8c02018-08-10 14:44:54 -0700440 with fake_adbd() as (port, _):
Josh Gao4db70c52018-08-08 13:08:08 -0700441 serial = "localhost:{}".format(port)
Luis Hector Chavez0aeda102018-04-20 10:31:29 -0700442 with adb_connect(self, serial):
443 # b/31250450: this always returns 0 but probably shouldn't.
Josh Gao4db70c52018-08-08 13:08:08 -0700444 output = subprocess.check_output(["adb", "connect", serial])
Luis Hector Chavez0aeda102018-04-20 10:31:29 -0700445 self.assertEqual(
Josh Gaob1df00e2018-08-07 14:31:17 -0700446 output.strip(),
Josh Gao4db70c52018-08-08 13:08:08 -0700447 "already connected to {}".format(serial).encode("utf8"))
Josh Gao50bde8d2016-09-01 14:54:18 -0700448
Julien Desprez0e8a0a02019-02-20 09:42:49 -0800449 @unittest.skip("Currently failing b/123247844")
Luis Hector Chavez0aeda102018-04-20 10:31:29 -0700450 def test_reconnect(self):
451 """Ensure that a disconnected device reconnects."""
Josh Gao50bde8d2016-09-01 14:54:18 -0700452
Josh Gao13cb8c02018-08-10 14:44:54 -0700453 with fake_adbd() as (port, _):
Josh Gao4db70c52018-08-08 13:08:08 -0700454 serial = "localhost:{}".format(port)
Luis Hector Chavez0aeda102018-04-20 10:31:29 -0700455 with adb_connect(self, serial):
Josh Gao2645b0a2019-02-07 17:53:29 -0800456 # Wait a bit to give adb some time to connect.
457 time.sleep(0.25)
458
Josh Gao4db70c52018-08-08 13:08:08 -0700459 output = subprocess.check_output(["adb", "-s", serial,
460 "get-state"])
461 self.assertEqual(output.strip(), b"device")
Josh Gao13781e82018-04-03 12:55:18 -0700462
Luis Hector Chavez0aeda102018-04-20 10:31:29 -0700463 # This will fail.
Josh Gao4db70c52018-08-08 13:08:08 -0700464 proc = subprocess.Popen(["adb", "-s", serial, "shell", "true"],
Luis Hector Chavez947b2132018-05-02 09:10:29 -0700465 stdout=subprocess.PIPE,
466 stderr=subprocess.STDOUT)
467 output, _ = proc.communicate()
Josh Gao4db70c52018-08-08 13:08:08 -0700468 self.assertEqual(output.strip(), b"error: closed")
Luis Hector Chavez0aeda102018-04-20 10:31:29 -0700469
Josh Gao4db70c52018-08-08 13:08:08 -0700470 subprocess.check_call(["adb", "-s", serial, "wait-for-device"])
Luis Hector Chavez0aeda102018-04-20 10:31:29 -0700471
Josh Gao4db70c52018-08-08 13:08:08 -0700472 output = subprocess.check_output(["adb", "-s", serial,
473 "get-state"])
474 self.assertEqual(output.strip(), b"device")
Luis Hector Chavez0aeda102018-04-20 10:31:29 -0700475
476 # Once we explicitly kick a device, it won't attempt to
477 # reconnect.
Josh Gao4db70c52018-08-08 13:08:08 -0700478 output = subprocess.check_output(["adb", "disconnect", serial])
Luis Hector Chavez0aeda102018-04-20 10:31:29 -0700479 self.assertEqual(
Josh Gaob1df00e2018-08-07 14:31:17 -0700480 output.strip(),
Josh Gao4db70c52018-08-08 13:08:08 -0700481 "disconnected {}".format(serial).encode("utf8"))
Luis Hector Chavez0aeda102018-04-20 10:31:29 -0700482 try:
Josh Gao4db70c52018-08-08 13:08:08 -0700483 subprocess.check_output(["adb", "-s", serial, "get-state"],
Luis Hector Chavez0aeda102018-04-20 10:31:29 -0700484 stderr=subprocess.STDOUT)
Josh Gao4db70c52018-08-08 13:08:08 -0700485 self.fail("Device should not be available")
Luis Hector Chavez947b2132018-05-02 09:10:29 -0700486 except subprocess.CalledProcessError as err:
Luis Hector Chavez0aeda102018-04-20 10:31:29 -0700487 self.assertEqual(
Luis Hector Chavez947b2132018-05-02 09:10:29 -0700488 err.output.strip(),
Josh Gao4db70c52018-08-08 13:08:08 -0700489 "error: device '{}' not found".format(serial).encode("utf8"))
Spencer Lowcc4a4b12015-10-14 17:32:44 -0700490
Luis Hector Chavez947b2132018-05-02 09:10:29 -0700491
Josh Gao13cb8c02018-08-10 14:44:54 -0700492class DisconnectionTest(unittest.TestCase):
493 """Tests for adb disconnect."""
494
495 def test_disconnect(self):
496 """Ensure that `adb disconnect` takes effect immediately."""
497
498 def _devices(port):
499 output = subprocess.check_output(["adb", "-P", str(port), "devices"])
500 return [x.split("\t") for x in output.decode("utf8").strip().splitlines()[1:]]
501
502 with adb_server() as server_port:
503 with fake_adbd() as (port, sock):
504 device_name = "localhost:{}".format(port)
505 output = subprocess.check_output(["adb", "-P", str(server_port),
506 "connect", device_name])
507 self.assertEqual(output.strip(),
508 "connected to {}".format(device_name).encode("utf8"))
509
510
511 self.assertEqual(_devices(server_port), [[device_name, "device"]])
512
513 # Send a deliberately malformed packet to make the device go offline.
514 packet = struct.pack("IIIIII", 0, 0, 0, 0, 0, 0)
515 sock.sendall(packet)
516
517 # Wait a bit.
518 time.sleep(0.1)
519
520 self.assertEqual(_devices(server_port), [[device_name, "offline"]])
521
522 # Disconnect the device.
523 output = subprocess.check_output(["adb", "-P", str(server_port),
524 "disconnect", device_name])
525
526 # Wait a bit.
527 time.sleep(0.1)
528
529 self.assertEqual(_devices(server_port), [])
530
531
Spencer Lowebd8d322018-08-31 19:49:46 -0700532@unittest.skipUnless(sys.platform == "win32", "requires Windows")
533class PowerTest(unittest.TestCase):
534 def test_resume_usb_kick(self):
535 """Resuming from sleep/hibernate should kick USB devices."""
536 try:
537 usb_serial = subprocess.check_output(["adb", "-d", "get-serialno"]).strip()
538 except subprocess.CalledProcessError:
539 # If there are multiple USB devices, we don't have a way to check whether the selected
540 # device is USB.
541 raise unittest.SkipTest('requires single USB device')
542
543 try:
544 serial = subprocess.check_output(["adb", "get-serialno"]).strip()
545 except subprocess.CalledProcessError:
546 # Did you forget to select a device with $ANDROID_SERIAL?
547 raise unittest.SkipTest('requires $ANDROID_SERIAL set to a USB device')
548
549 # Test only works with USB devices because adb _power_notification_thread does not kick
550 # non-USB devices on resume event.
551 if serial != usb_serial:
552 raise unittest.SkipTest('requires USB device')
553
554 # Run an adb shell command in the background that takes a while to complete.
555 proc = subprocess.Popen(['adb', 'shell', 'sleep', '5'])
556
557 # Wait for startup of adb server's _power_notification_thread.
558 time.sleep(0.1)
559
560 # Simulate resuming from sleep/hibernation by sending Windows message.
561 import ctypes
562 from ctypes import wintypes
563 HWND_BROADCAST = 0xffff
564 WM_POWERBROADCAST = 0x218
565 PBT_APMRESUMEAUTOMATIC = 0x12
566
567 PostMessageW = ctypes.windll.user32.PostMessageW
568 PostMessageW.restype = wintypes.BOOL
569 PostMessageW.argtypes = (wintypes.HWND, wintypes.UINT, wintypes.WPARAM, wintypes.LPARAM)
570 result = PostMessageW(HWND_BROADCAST, WM_POWERBROADCAST, PBT_APMRESUMEAUTOMATIC, 0)
571 if not result:
572 raise ctypes.WinError()
573
574 # Wait for connection to adb shell to be broken by _power_notification_thread detecting the
575 # Windows message.
576 start = time.time()
577 proc.wait()
578 end = time.time()
579
580 # If the power event was detected, the adb shell command should be broken very quickly.
581 self.assertLess(end - start, 2)
582
Joshua Duonge22e1612020-03-31 10:58:50 -0700583"""Use 'adb mdns check' to see if mdns discovery is available."""
584def is_adb_mdns_available():
585 with adb_server() as server_port:
586 output = subprocess.check_output(["adb", "-P", str(server_port),
587 "mdns", "check"]).strip()
588 return output.startswith(b"mdns daemon version")
589
Joshua Duong5f63d112020-03-31 08:39:24 -0700590"""Check if we have zeroconf python library installed"""
591def is_zeroconf_installed():
592 zeroconf_spec = util.find_spec("zeroconf")
593 return zeroconf_spec is not None
594
595@contextlib.contextmanager
596def zeroconf_context(ipversion):
597 from zeroconf import Zeroconf
598 """Context manager for a zeroconf instance
599
600 This creates a zeroconf instance and returns it.
601 """
602
603 try:
604 zeroconf = Zeroconf(ip_version=ipversion)
605 yield zeroconf
606 finally:
607 zeroconf.close()
608
609@contextlib.contextmanager
610def zeroconf_register_service(zeroconf_ctx, info):
611 """Context manager for a zeroconf service
612
613 Registers a service and unregisters it on cleanup. Returns the ServiceInfo
614 supplied.
615 """
616
617 try:
618 zeroconf_ctx.register_service(info)
619 yield info
620 finally:
621 zeroconf_ctx.unregister_service(info)
622
Joshua Duongda537072020-06-29 16:27:03 -0700623@contextlib.contextmanager
624def zeroconf_register_services(zeroconf_ctx, infos):
625 """Context manager for multiple zeroconf services
626
627 Registers all services given and unregisters all on cleanup. Returns the ServiceInfo
628 list supplied.
629 """
630
631 try:
632 for info in infos:
633 zeroconf_ctx.register_service(info)
634 yield infos
635 finally:
636 for info in infos:
637 zeroconf_ctx.unregister_service(info)
638
Joshua Duong5f63d112020-03-31 08:39:24 -0700639"""Should match the service names listed in adb_mdns.h"""
Josh Gao5ece8e42020-06-02 13:14:45 -0700640class MdnsTest:
Joshua Duonge22e1612020-03-31 10:58:50 -0700641 """Tests for adb mdns."""
Joshua Duongda537072020-06-29 16:27:03 -0700642 @staticmethod
643 def _mdns_services(port):
644 output = subprocess.check_output(["adb", "-P", str(port), "mdns", "services"])
645 return [x.split("\t") for x in output.decode("utf8").strip().splitlines()[1:]]
646
647 @staticmethod
648 def _devices(port):
649 output = subprocess.check_output(["adb", "-P", str(port), "devices"])
650 return [x.split("\t") for x in output.decode("utf8").strip().splitlines()[1:]]
651
Joshua Duong5f63d112020-03-31 08:39:24 -0700652
Josh Gao5ece8e42020-06-02 13:14:45 -0700653 class Base(unittest.TestCase):
Josh Gao5ece8e42020-06-02 13:14:45 -0700654 @contextlib.contextmanager
655 def _adb_mdns_connect(self, server_port, mdns_instance, serial, should_connect):
656 """Context manager for an ADB connection.
Joshua Duong7ea62d82020-05-01 09:25:12 -0700657
Josh Gao5ece8e42020-06-02 13:14:45 -0700658 This automatically disconnects when done with the connection.
659 """
Joshua Duong7ea62d82020-05-01 09:25:12 -0700660
Josh Gao5ece8e42020-06-02 13:14:45 -0700661 output = subprocess.check_output(["adb", "-P", str(server_port), "connect", mdns_instance])
662 if should_connect:
663 self.assertEqual(output.strip(), "connected to {}".format(serial).encode("utf8"))
664 else:
665 self.assertTrue(output.startswith("failed to resolve host: '{}'"
666 .format(mdns_instance).encode("utf8")))
Joshua Duong7ea62d82020-05-01 09:25:12 -0700667
Josh Gao5ece8e42020-06-02 13:14:45 -0700668 try:
669 yield
670 finally:
671 # Perform best-effort disconnection. Discard the output.
672 subprocess.Popen(["adb", "disconnect", serial],
673 stdout=subprocess.PIPE,
674 stderr=subprocess.PIPE).communicate()
Joshua Duong7ea62d82020-05-01 09:25:12 -0700675
676
Josh Gao5ece8e42020-06-02 13:14:45 -0700677 @unittest.skipIf(not is_zeroconf_installed(), "zeroconf library not installed")
678 def test_mdns_services_register_unregister(self):
679 """Ensure that `adb mdns services` correctly adds and removes a service
680 """
681 from zeroconf import IPVersion, ServiceInfo
Joshua Duong5f63d112020-03-31 08:39:24 -0700682
Josh Gao5ece8e42020-06-02 13:14:45 -0700683 with adb_server() as server_port:
684 output = subprocess.check_output(["adb", "-P", str(server_port),
685 "mdns", "services"]).strip()
686 self.assertTrue(output.startswith(b"List of discovered mdns services"))
Joshua Duong5f63d112020-03-31 08:39:24 -0700687
Josh Gao5ece8e42020-06-02 13:14:45 -0700688 """TODO(joshuaduong): Add ipv6 tests once we have it working in adb"""
689 """Register/Unregister a service"""
690 with zeroconf_context(IPVersion.V4Only) as zc:
691 serv_instance = "my_fake_test_service"
692 serv_type = "_" + self.service_name + "._tcp."
693 serv_ipaddr = socket.inet_aton("1.2.3.4")
694 serv_port = 12345
Joshua Duong7ea62d82020-05-01 09:25:12 -0700695 service_info = ServiceInfo(
696 serv_type + "local.",
697 name=serv_instance + "." + serv_type + "local.",
698 addresses=[serv_ipaddr],
Josh Gao5ece8e42020-06-02 13:14:45 -0700699 port=serv_port)
Joshua Duong7ea62d82020-05-01 09:25:12 -0700700 with zeroconf_register_service(zc, service_info) as info:
701 """Give adb some time to register the service"""
702 time.sleep(1)
703 self.assertTrue(any((serv_instance in line and serv_type in line)
704 for line in MdnsTest._mdns_services(server_port)))
Joshua Duong7ea62d82020-05-01 09:25:12 -0700705
706 """Give adb some time to unregister the service"""
707 time.sleep(1)
708 self.assertFalse(any((serv_instance in line and serv_type in line)
709 for line in MdnsTest._mdns_services(server_port)))
Spencer Lowebd8d322018-08-31 19:49:46 -0700710
Josh Gao5ece8e42020-06-02 13:14:45 -0700711 @unittest.skipIf(not is_zeroconf_installed(), "zeroconf library not installed")
Joshua Duongda537072020-06-29 16:27:03 -0700712 def test_mdns_services_register_unregister_multiple(self):
713 """Ensure that `adb mdns services` correctly adds and removes multiple services
714 """
715 from zeroconf import IPVersion, ServiceInfo
716
717 with adb_server() as server_port:
718 output = subprocess.check_output(["adb", "-P", str(server_port),
719 "mdns", "services"]).strip()
720 self.assertTrue(output.startswith(b"List of discovered mdns services"))
721
722 """TODO(joshuaduong): Add ipv6 tests once we have it working in adb"""
723 """Register/Unregister a service"""
724 with zeroconf_context(IPVersion.V4Only) as zc:
725 srvs = {
726 'mdns_name': ["testservice0", "testservice1", "testservice2"],
727 'mdns_type': "_" + self.service_name + "._tcp.",
728 'ipaddr': [
729 socket.inet_aton("192.168.0.1"),
730 socket.inet_aton("10.0.0.255"),
731 socket.inet_aton("172.16.1.100")],
732 'port': [10000, 20000, 65535]}
733 srv_infos = []
734 for i in range(len(srvs['mdns_name'])):
735 srv_infos.append(ServiceInfo(
736 srvs['mdns_type'] + "local.",
737 name=srvs['mdns_name'][i] + "." + srvs['mdns_type'] + "local.",
738 addresses=[srvs['ipaddr'][i]],
739 port=srvs['port'][i]))
740
741 """ Register all devices, then unregister"""
742 with zeroconf_register_services(zc, srv_infos) as infos:
743 """Give adb some time to register the service"""
744 time.sleep(1)
745 for i in range(len(srvs['mdns_name'])):
746 self.assertTrue(any((srvs['mdns_name'][i] in line and srvs['mdns_type'] in line)
747 for line in MdnsTest._mdns_services(server_port)))
748
749 """Give adb some time to unregister the service"""
750 time.sleep(1)
751 for i in range(len(srvs['mdns_name'])):
752 self.assertFalse(any((srvs['mdns_name'][i] in line and srvs['mdns_type'] in line)
753 for line in MdnsTest._mdns_services(server_port)))
754
755 @unittest.skipIf(not is_zeroconf_installed(), "zeroconf library not installed")
Josh Gao5ece8e42020-06-02 13:14:45 -0700756 def test_mdns_connect(self):
757 """Ensure that `adb connect` by mdns instance name works (for non-pairing services)
758 """
759 from zeroconf import IPVersion, ServiceInfo
760
761 with adb_server() as server_port:
762 with zeroconf_context(IPVersion.V4Only) as zc:
763 serv_instance = "fakeadbd-" + ''.join(
764 random.choice(string.ascii_letters) for i in range(4))
765 serv_type = "_" + self.service_name + "._tcp."
766 serv_ipaddr = socket.inet_aton("127.0.0.1")
767 should_connect = self.service_name != "adb-tls-pairing"
768 with fake_adbd() as (port, _):
769 service_info = ServiceInfo(
770 serv_type + "local.",
771 name=serv_instance + "." + serv_type + "local.",
772 addresses=[serv_ipaddr],
773 port=port)
774 with zeroconf_register_service(zc, service_info) as info:
775 """Give adb some time to register the service"""
776 time.sleep(1)
777 self.assertTrue(any((serv_instance in line and serv_type in line)
778 for line in MdnsTest._mdns_services(server_port)))
779 full_name = '.'.join([serv_instance, serv_type])
780 with self._adb_mdns_connect(server_port, serv_instance, full_name,
781 should_connect):
782 if should_connect:
783 self.assertEqual(MdnsTest._devices(server_port),
784 [[full_name, "device"]])
785
786 """Give adb some time to unregister the service"""
787 time.sleep(1)
788 self.assertFalse(any((serv_instance in line and serv_type in line)
789 for line in MdnsTest._mdns_services(server_port)))
790
791
792@unittest.skipIf(not is_adb_mdns_available(), "mdns feature not available")
793class MdnsTestAdb(MdnsTest.Base):
794 service_name = "adb"
795
796
797@unittest.skipIf(not is_adb_mdns_available(), "mdns feature not available")
798class MdnsTestAdbTlsConnect(MdnsTest.Base):
799 service_name = "adb-tls-connect"
800
801
802@unittest.skipIf(not is_adb_mdns_available(), "mdns feature not available")
803class MdnsTestAdbTlsPairing(MdnsTest.Base):
804 service_name = "adb-tls-pairing"
805
806
Dan Alberta4169f92015-07-24 17:08:33 -0700807def main():
Luis Hector Chavez947b2132018-05-02 09:10:29 -0700808 """Main entrypoint."""
Dan Alberta4169f92015-07-24 17:08:33 -0700809 random.seed(0)
Luis Hector Chavez947b2132018-05-02 09:10:29 -0700810 unittest.main(verbosity=3)
Dan Alberta4169f92015-07-24 17:08:33 -0700811
812
Josh Gao4db70c52018-08-08 13:08:08 -0700813if __name__ == "__main__":
Dan Alberta4169f92015-07-24 17:08:33 -0700814 main()