blob: a32d8757d978f45c9e0b5468c2faedbf274f07bb [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 )
Elliott Hughes0bab0262021-03-03 16:23:05 +0000289 def 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
292 """
Josh Gaoe9fdf4a2020-02-27 14:29:38 -0800293
294 server_port = find_open_port()
Callum Ryan04efea32019-10-31 07:21:42 -0700295 try:
296 subprocess.check_output(
297 ["adb", "-L", "tcp:[::1]:{}".format(server_port), "server"],
298 stderr=subprocess.STDOUT,
299 )
300 with fake_adbd() as (port, _):
301 with adb_connect(self, serial="localhost:{}".format(port)):
302 pass
303 finally:
304 # If we started a server, kill it.
305 subprocess.check_output(
306 ["adb", "-P", str(server_port), "kill-server"],
307 stderr=subprocess.STDOUT,
308 )
309
310
311
Luis Hector Chavez947b2132018-05-02 09:10:29 -0700312
313class EmulatorTest(unittest.TestCase):
314 """Tests for the emulator connection."""
315
Spencer Lowcc4a4b12015-10-14 17:32:44 -0700316 def _reset_socket_on_close(self, sock):
Luis Hector Chavez947b2132018-05-02 09:10:29 -0700317 """Use SO_LINGER to cause TCP RST segment to be sent on socket close."""
Spencer Lowcc4a4b12015-10-14 17:32:44 -0700318 # The linger structure is two shorts on Windows, but two ints on Unix.
Josh Gao4db70c52018-08-08 13:08:08 -0700319 linger_format = "hh" if os.name == "nt" else "ii"
Spencer Lowcc4a4b12015-10-14 17:32:44 -0700320 l_onoff = 1
321 l_linger = 0
322
323 sock.setsockopt(socket.SOL_SOCKET, socket.SO_LINGER,
324 struct.pack(linger_format, l_onoff, l_linger))
325 # Verify that we set the linger structure properly by retrieving it.
326 linger = sock.getsockopt(socket.SOL_SOCKET, socket.SO_LINGER, 16)
327 self.assertEqual((l_onoff, l_linger),
328 struct.unpack_from(linger_format, linger))
329
330 def test_emu_kill(self):
331 """Ensure that adb emu kill works.
332
333 Bug: https://code.google.com/p/android/issues/detail?id=21021
334 """
Spencer Lowcc4a4b12015-10-14 17:32:44 -0700335 with contextlib.closing(
Luis Hector Chavez947b2132018-05-02 09:10:29 -0700336 socket.socket(socket.AF_INET, socket.SOCK_STREAM)) as listener:
Spencer Lowcc4a4b12015-10-14 17:32:44 -0700337 # Use SO_REUSEADDR so subsequent runs of the test can grab the port
338 # even if it is in TIME_WAIT.
339 listener.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
Josh Gao4db70c52018-08-08 13:08:08 -0700340 listener.bind(("127.0.0.1", 0))
Spencer Lowcc4a4b12015-10-14 17:32:44 -0700341 listener.listen(4)
Josh Gao13781e82018-04-03 12:55:18 -0700342 port = listener.getsockname()[1]
Spencer Lowcc4a4b12015-10-14 17:32:44 -0700343
344 # Now that listening has started, start adb emu kill, telling it to
345 # connect to our mock emulator.
Luis Hector Chavez947b2132018-05-02 09:10:29 -0700346 proc = subprocess.Popen(
Josh Gao4db70c52018-08-08 13:08:08 -0700347 ["adb", "-s", "emulator-" + str(port), "emu", "kill"],
Spencer Lowcc4a4b12015-10-14 17:32:44 -0700348 stderr=subprocess.STDOUT)
349
350 accepted_connection, addr = listener.accept()
351 with contextlib.closing(accepted_connection) as conn:
352 # If WSAECONNABORTED (10053) is raised by any socket calls,
353 # then adb probably isn't reading the data that we sent it.
Josh Gao4db70c52018-08-08 13:08:08 -0700354 conn.sendall(("Android Console: type 'help' for a list "
355 "of commands\r\n").encode("utf8"))
356 conn.sendall(b"OK\r\n")
Spencer Lowcc4a4b12015-10-14 17:32:44 -0700357
Luis Hector Chavez947b2132018-05-02 09:10:29 -0700358 with contextlib.closing(conn.makefile()) as connf:
359 line = connf.readline()
Josh Gao4db70c52018-08-08 13:08:08 -0700360 if line.startswith("auth"):
Luis Hector Chavez947b2132018-05-02 09:10:29 -0700361 # Ignore the first auth line.
362 line = connf.readline()
Josh Gao4db70c52018-08-08 13:08:08 -0700363 self.assertEqual("kill\n", line)
364 self.assertEqual("quit\n", connf.readline())
Spencer Lowcc4a4b12015-10-14 17:32:44 -0700365
Josh Gao4db70c52018-08-08 13:08:08 -0700366 conn.sendall(b"OK: killing emulator, bye bye\r\n")
Spencer Lowcc4a4b12015-10-14 17:32:44 -0700367
368 # Use SO_LINGER to send TCP RST segment to test whether adb
369 # ignores WSAECONNRESET on Windows. This happens with the
370 # real emulator because it just calls exit() without closing
371 # the socket or calling shutdown(SD_SEND). At process
372 # termination, Windows sends a TCP RST segment for every
373 # open socket that shutdown(SD_SEND) wasn't used on.
374 self._reset_socket_on_close(conn)
375
376 # Wait for adb to finish, so we can check return code.
Luis Hector Chavez947b2132018-05-02 09:10:29 -0700377 proc.communicate()
Spencer Lowcc4a4b12015-10-14 17:32:44 -0700378
379 # If this fails, adb probably isn't ignoring WSAECONNRESET when
380 # reading the response from the adb emu kill command (on Windows).
Luis Hector Chavez947b2132018-05-02 09:10:29 -0700381 self.assertEqual(0, proc.returncode)
382
Luis Hector Chaveza452f0e2018-05-02 10:47:01 -0700383 def test_emulator_connect(self):
384 """Ensure that the emulator can connect.
385
386 Bug: http://b/78991667
387 """
388 with adb_server() as server_port:
Josh Gao13cb8c02018-08-10 14:44:54 -0700389 with fake_adbd() as (port, _):
Josh Gao4db70c52018-08-08 13:08:08 -0700390 serial = "emulator-{}".format(port - 1)
Luis Hector Chaveza452f0e2018-05-02 10:47:01 -0700391 # Ensure that the emulator is not there.
392 try:
Josh Gao4db70c52018-08-08 13:08:08 -0700393 subprocess.check_output(["adb", "-P", str(server_port),
394 "-s", serial, "get-state"],
Luis Hector Chaveza452f0e2018-05-02 10:47:01 -0700395 stderr=subprocess.STDOUT)
Josh Gao4db70c52018-08-08 13:08:08 -0700396 self.fail("Device should not be available")
Luis Hector Chaveza452f0e2018-05-02 10:47:01 -0700397 except subprocess.CalledProcessError as err:
398 self.assertEqual(
399 err.output.strip(),
Josh Gao4db70c52018-08-08 13:08:08 -0700400 "error: device '{}' not found".format(serial).encode("utf8"))
Luis Hector Chaveza452f0e2018-05-02 10:47:01 -0700401
402 # Let the ADB server know that the emulator has started.
403 with contextlib.closing(
Josh Gaob1df00e2018-08-07 14:31:17 -0700404 socket.socket(socket.AF_INET, socket.SOCK_STREAM)) as sock:
Josh Gao4db70c52018-08-08 13:08:08 -0700405 sock.connect(("localhost", server_port))
406 command = "host:emulator:{}".format(port).encode("utf8")
407 sock.sendall(b"%04x%s" % (len(command), command))
Luis Hector Chaveza452f0e2018-05-02 10:47:01 -0700408
409 # Ensure the emulator is there.
Josh Gao4db70c52018-08-08 13:08:08 -0700410 subprocess.check_call(["adb", "-P", str(server_port),
411 "-s", serial, "wait-for-device"])
412 output = subprocess.check_output(["adb", "-P", str(server_port),
413 "-s", serial, "get-state"])
414 self.assertEqual(output.strip(), b"device")
Luis Hector Chaveza452f0e2018-05-02 10:47:01 -0700415
Luis Hector Chavez947b2132018-05-02 09:10:29 -0700416
417class ConnectionTest(unittest.TestCase):
418 """Tests for adb connect."""
Spencer Lowcc4a4b12015-10-14 17:32:44 -0700419
Josh Gao50bde8d2016-09-01 14:54:18 -0700420 def test_connect_ipv4_ipv6(self):
421 """Ensure that `adb connect localhost:1234` will try both IPv4 and IPv6.
422
423 Bug: http://b/30313466
424 """
Luis Hector Chavezbf8a7222018-04-17 19:25:33 -0700425 for protocol in (socket.AF_INET, socket.AF_INET6):
426 try:
Josh Gao13cb8c02018-08-10 14:44:54 -0700427 with fake_adbd(protocol=protocol) as (port, _):
Josh Gao4db70c52018-08-08 13:08:08 -0700428 serial = "localhost:{}".format(port)
Luis Hector Chavez0aeda102018-04-20 10:31:29 -0700429 with adb_connect(self, serial):
430 pass
Luis Hector Chavezbf8a7222018-04-17 19:25:33 -0700431 except socket.error:
432 print("IPv6 not available, skipping")
433 continue
Josh Gao50bde8d2016-09-01 14:54:18 -0700434
Luis Hector Chavezbf8a7222018-04-17 19:25:33 -0700435 def test_already_connected(self):
Luis Hector Chavez0aeda102018-04-20 10:31:29 -0700436 """Ensure that an already-connected device stays connected."""
437
Josh Gao13cb8c02018-08-10 14:44:54 -0700438 with fake_adbd() as (port, _):
Josh Gao4db70c52018-08-08 13:08:08 -0700439 serial = "localhost:{}".format(port)
Luis Hector Chavez0aeda102018-04-20 10:31:29 -0700440 with adb_connect(self, serial):
441 # b/31250450: this always returns 0 but probably shouldn't.
Josh Gao4db70c52018-08-08 13:08:08 -0700442 output = subprocess.check_output(["adb", "connect", serial])
Luis Hector Chavez0aeda102018-04-20 10:31:29 -0700443 self.assertEqual(
Josh Gaob1df00e2018-08-07 14:31:17 -0700444 output.strip(),
Josh Gao4db70c52018-08-08 13:08:08 -0700445 "already connected to {}".format(serial).encode("utf8"))
Josh Gao50bde8d2016-09-01 14:54:18 -0700446
Julien Desprez0e8a0a02019-02-20 09:42:49 -0800447 @unittest.skip("Currently failing b/123247844")
Luis Hector Chavez0aeda102018-04-20 10:31:29 -0700448 def test_reconnect(self):
449 """Ensure that a disconnected device reconnects."""
Josh Gao50bde8d2016-09-01 14:54:18 -0700450
Josh Gao13cb8c02018-08-10 14:44:54 -0700451 with fake_adbd() as (port, _):
Josh Gao4db70c52018-08-08 13:08:08 -0700452 serial = "localhost:{}".format(port)
Luis Hector Chavez0aeda102018-04-20 10:31:29 -0700453 with adb_connect(self, serial):
Josh Gao2645b0a2019-02-07 17:53:29 -0800454 # Wait a bit to give adb some time to connect.
455 time.sleep(0.25)
456
Josh Gao4db70c52018-08-08 13:08:08 -0700457 output = subprocess.check_output(["adb", "-s", serial,
458 "get-state"])
459 self.assertEqual(output.strip(), b"device")
Josh Gao13781e82018-04-03 12:55:18 -0700460
Luis Hector Chavez0aeda102018-04-20 10:31:29 -0700461 # This will fail.
Josh Gao4db70c52018-08-08 13:08:08 -0700462 proc = subprocess.Popen(["adb", "-s", serial, "shell", "true"],
Luis Hector Chavez947b2132018-05-02 09:10:29 -0700463 stdout=subprocess.PIPE,
464 stderr=subprocess.STDOUT)
465 output, _ = proc.communicate()
Josh Gao4db70c52018-08-08 13:08:08 -0700466 self.assertEqual(output.strip(), b"error: closed")
Luis Hector Chavez0aeda102018-04-20 10:31:29 -0700467
Josh Gao4db70c52018-08-08 13:08:08 -0700468 subprocess.check_call(["adb", "-s", serial, "wait-for-device"])
Luis Hector Chavez0aeda102018-04-20 10:31:29 -0700469
Josh Gao4db70c52018-08-08 13:08:08 -0700470 output = subprocess.check_output(["adb", "-s", serial,
471 "get-state"])
472 self.assertEqual(output.strip(), b"device")
Luis Hector Chavez0aeda102018-04-20 10:31:29 -0700473
474 # Once we explicitly kick a device, it won't attempt to
475 # reconnect.
Josh Gao4db70c52018-08-08 13:08:08 -0700476 output = subprocess.check_output(["adb", "disconnect", serial])
Luis Hector Chavez0aeda102018-04-20 10:31:29 -0700477 self.assertEqual(
Josh Gaob1df00e2018-08-07 14:31:17 -0700478 output.strip(),
Josh Gao4db70c52018-08-08 13:08:08 -0700479 "disconnected {}".format(serial).encode("utf8"))
Luis Hector Chavez0aeda102018-04-20 10:31:29 -0700480 try:
Josh Gao4db70c52018-08-08 13:08:08 -0700481 subprocess.check_output(["adb", "-s", serial, "get-state"],
Luis Hector Chavez0aeda102018-04-20 10:31:29 -0700482 stderr=subprocess.STDOUT)
Josh Gao4db70c52018-08-08 13:08:08 -0700483 self.fail("Device should not be available")
Luis Hector Chavez947b2132018-05-02 09:10:29 -0700484 except subprocess.CalledProcessError as err:
Luis Hector Chavez0aeda102018-04-20 10:31:29 -0700485 self.assertEqual(
Luis Hector Chavez947b2132018-05-02 09:10:29 -0700486 err.output.strip(),
Josh Gao4db70c52018-08-08 13:08:08 -0700487 "error: device '{}' not found".format(serial).encode("utf8"))
Spencer Lowcc4a4b12015-10-14 17:32:44 -0700488
Luis Hector Chavez947b2132018-05-02 09:10:29 -0700489
Josh Gao13cb8c02018-08-10 14:44:54 -0700490class DisconnectionTest(unittest.TestCase):
491 """Tests for adb disconnect."""
492
493 def test_disconnect(self):
494 """Ensure that `adb disconnect` takes effect immediately."""
495
496 def _devices(port):
497 output = subprocess.check_output(["adb", "-P", str(port), "devices"])
498 return [x.split("\t") for x in output.decode("utf8").strip().splitlines()[1:]]
499
500 with adb_server() as server_port:
501 with fake_adbd() as (port, sock):
502 device_name = "localhost:{}".format(port)
503 output = subprocess.check_output(["adb", "-P", str(server_port),
504 "connect", device_name])
505 self.assertEqual(output.strip(),
506 "connected to {}".format(device_name).encode("utf8"))
507
508
509 self.assertEqual(_devices(server_port), [[device_name, "device"]])
510
511 # Send a deliberately malformed packet to make the device go offline.
512 packet = struct.pack("IIIIII", 0, 0, 0, 0, 0, 0)
513 sock.sendall(packet)
514
515 # Wait a bit.
516 time.sleep(0.1)
517
518 self.assertEqual(_devices(server_port), [[device_name, "offline"]])
519
520 # Disconnect the device.
521 output = subprocess.check_output(["adb", "-P", str(server_port),
522 "disconnect", device_name])
523
524 # Wait a bit.
525 time.sleep(0.1)
526
527 self.assertEqual(_devices(server_port), [])
528
529
Spencer Lowebd8d322018-08-31 19:49:46 -0700530@unittest.skipUnless(sys.platform == "win32", "requires Windows")
531class PowerTest(unittest.TestCase):
532 def test_resume_usb_kick(self):
533 """Resuming from sleep/hibernate should kick USB devices."""
534 try:
535 usb_serial = subprocess.check_output(["adb", "-d", "get-serialno"]).strip()
536 except subprocess.CalledProcessError:
537 # If there are multiple USB devices, we don't have a way to check whether the selected
538 # device is USB.
539 raise unittest.SkipTest('requires single USB device')
540
541 try:
542 serial = subprocess.check_output(["adb", "get-serialno"]).strip()
543 except subprocess.CalledProcessError:
544 # Did you forget to select a device with $ANDROID_SERIAL?
545 raise unittest.SkipTest('requires $ANDROID_SERIAL set to a USB device')
546
547 # Test only works with USB devices because adb _power_notification_thread does not kick
548 # non-USB devices on resume event.
549 if serial != usb_serial:
550 raise unittest.SkipTest('requires USB device')
551
552 # Run an adb shell command in the background that takes a while to complete.
553 proc = subprocess.Popen(['adb', 'shell', 'sleep', '5'])
554
555 # Wait for startup of adb server's _power_notification_thread.
556 time.sleep(0.1)
557
558 # Simulate resuming from sleep/hibernation by sending Windows message.
559 import ctypes
560 from ctypes import wintypes
561 HWND_BROADCAST = 0xffff
562 WM_POWERBROADCAST = 0x218
563 PBT_APMRESUMEAUTOMATIC = 0x12
564
565 PostMessageW = ctypes.windll.user32.PostMessageW
566 PostMessageW.restype = wintypes.BOOL
567 PostMessageW.argtypes = (wintypes.HWND, wintypes.UINT, wintypes.WPARAM, wintypes.LPARAM)
568 result = PostMessageW(HWND_BROADCAST, WM_POWERBROADCAST, PBT_APMRESUMEAUTOMATIC, 0)
569 if not result:
570 raise ctypes.WinError()
571
572 # Wait for connection to adb shell to be broken by _power_notification_thread detecting the
573 # Windows message.
574 start = time.time()
575 proc.wait()
576 end = time.time()
577
578 # If the power event was detected, the adb shell command should be broken very quickly.
579 self.assertLess(end - start, 2)
580
Joshua Duonge22e1612020-03-31 10:58:50 -0700581"""Use 'adb mdns check' to see if mdns discovery is available."""
582def is_adb_mdns_available():
583 with adb_server() as server_port:
584 output = subprocess.check_output(["adb", "-P", str(server_port),
585 "mdns", "check"]).strip()
586 return output.startswith(b"mdns daemon version")
587
Joshua Duong5f63d112020-03-31 08:39:24 -0700588"""Check if we have zeroconf python library installed"""
589def is_zeroconf_installed():
590 zeroconf_spec = util.find_spec("zeroconf")
591 return zeroconf_spec is not None
592
593@contextlib.contextmanager
594def zeroconf_context(ipversion):
595 from zeroconf import Zeroconf
596 """Context manager for a zeroconf instance
597
598 This creates a zeroconf instance and returns it.
599 """
600
601 try:
602 zeroconf = Zeroconf(ip_version=ipversion)
603 yield zeroconf
604 finally:
605 zeroconf.close()
606
607@contextlib.contextmanager
608def zeroconf_register_service(zeroconf_ctx, info):
609 """Context manager for a zeroconf service
610
611 Registers a service and unregisters it on cleanup. Returns the ServiceInfo
612 supplied.
613 """
614
615 try:
616 zeroconf_ctx.register_service(info)
617 yield info
618 finally:
619 zeroconf_ctx.unregister_service(info)
620
Joshua Duongda537072020-06-29 16:27:03 -0700621@contextlib.contextmanager
622def zeroconf_register_services(zeroconf_ctx, infos):
623 """Context manager for multiple zeroconf services
624
625 Registers all services given and unregisters all on cleanup. Returns the ServiceInfo
626 list supplied.
627 """
628
629 try:
630 for info in infos:
631 zeroconf_ctx.register_service(info)
632 yield infos
633 finally:
634 for info in infos:
635 zeroconf_ctx.unregister_service(info)
636
Joshua Duong5f63d112020-03-31 08:39:24 -0700637"""Should match the service names listed in adb_mdns.h"""
Josh Gao5ece8e42020-06-02 13:14:45 -0700638class MdnsTest:
Joshua Duonge22e1612020-03-31 10:58:50 -0700639 """Tests for adb mdns."""
Joshua Duongda537072020-06-29 16:27:03 -0700640 @staticmethod
641 def _mdns_services(port):
642 output = subprocess.check_output(["adb", "-P", str(port), "mdns", "services"])
643 return [x.split("\t") for x in output.decode("utf8").strip().splitlines()[1:]]
644
645 @staticmethod
646 def _devices(port):
647 output = subprocess.check_output(["adb", "-P", str(port), "devices"])
648 return [x.split("\t") for x in output.decode("utf8").strip().splitlines()[1:]]
649
Joshua Duong5f63d112020-03-31 08:39:24 -0700650
Josh Gao5ece8e42020-06-02 13:14:45 -0700651 class Base(unittest.TestCase):
Josh Gao5ece8e42020-06-02 13:14:45 -0700652 @contextlib.contextmanager
653 def _adb_mdns_connect(self, server_port, mdns_instance, serial, should_connect):
654 """Context manager for an ADB connection.
Joshua Duong7ea62d82020-05-01 09:25:12 -0700655
Josh Gao5ece8e42020-06-02 13:14:45 -0700656 This automatically disconnects when done with the connection.
657 """
Joshua Duong7ea62d82020-05-01 09:25:12 -0700658
Josh Gao5ece8e42020-06-02 13:14:45 -0700659 output = subprocess.check_output(["adb", "-P", str(server_port), "connect", mdns_instance])
660 if should_connect:
661 self.assertEqual(output.strip(), "connected to {}".format(serial).encode("utf8"))
662 else:
663 self.assertTrue(output.startswith("failed to resolve host: '{}'"
664 .format(mdns_instance).encode("utf8")))
Joshua Duong7ea62d82020-05-01 09:25:12 -0700665
Josh Gao5ece8e42020-06-02 13:14:45 -0700666 try:
667 yield
668 finally:
669 # Perform best-effort disconnection. Discard the output.
670 subprocess.Popen(["adb", "disconnect", serial],
671 stdout=subprocess.PIPE,
672 stderr=subprocess.PIPE).communicate()
Joshua Duong7ea62d82020-05-01 09:25:12 -0700673
674
Josh Gao5ece8e42020-06-02 13:14:45 -0700675 @unittest.skipIf(not is_zeroconf_installed(), "zeroconf library not installed")
676 def test_mdns_services_register_unregister(self):
677 """Ensure that `adb mdns services` correctly adds and removes a service
678 """
679 from zeroconf import IPVersion, ServiceInfo
Joshua Duong5f63d112020-03-31 08:39:24 -0700680
Josh Gao5ece8e42020-06-02 13:14:45 -0700681 with adb_server() as server_port:
682 output = subprocess.check_output(["adb", "-P", str(server_port),
683 "mdns", "services"]).strip()
684 self.assertTrue(output.startswith(b"List of discovered mdns services"))
Joshua Duong5f63d112020-03-31 08:39:24 -0700685
Josh Gao5ece8e42020-06-02 13:14:45 -0700686 """TODO(joshuaduong): Add ipv6 tests once we have it working in adb"""
687 """Register/Unregister a service"""
688 with zeroconf_context(IPVersion.V4Only) as zc:
689 serv_instance = "my_fake_test_service"
690 serv_type = "_" + self.service_name + "._tcp."
691 serv_ipaddr = socket.inet_aton("1.2.3.4")
692 serv_port = 12345
Joshua Duong7ea62d82020-05-01 09:25:12 -0700693 service_info = ServiceInfo(
694 serv_type + "local.",
695 name=serv_instance + "." + serv_type + "local.",
696 addresses=[serv_ipaddr],
Josh Gao5ece8e42020-06-02 13:14:45 -0700697 port=serv_port)
Joshua Duong7ea62d82020-05-01 09:25:12 -0700698 with zeroconf_register_service(zc, service_info) as info:
699 """Give adb some time to register the service"""
700 time.sleep(1)
701 self.assertTrue(any((serv_instance in line and serv_type in line)
702 for line in MdnsTest._mdns_services(server_port)))
Joshua Duong7ea62d82020-05-01 09:25:12 -0700703
704 """Give adb some time to unregister the service"""
705 time.sleep(1)
706 self.assertFalse(any((serv_instance in line and serv_type in line)
707 for line in MdnsTest._mdns_services(server_port)))
Spencer Lowebd8d322018-08-31 19:49:46 -0700708
Josh Gao5ece8e42020-06-02 13:14:45 -0700709 @unittest.skipIf(not is_zeroconf_installed(), "zeroconf library not installed")
Joshua Duongda537072020-06-29 16:27:03 -0700710 def test_mdns_services_register_unregister_multiple(self):
711 """Ensure that `adb mdns services` correctly adds and removes multiple services
712 """
713 from zeroconf import IPVersion, ServiceInfo
714
715 with adb_server() as server_port:
716 output = subprocess.check_output(["adb", "-P", str(server_port),
717 "mdns", "services"]).strip()
718 self.assertTrue(output.startswith(b"List of discovered mdns services"))
719
720 """TODO(joshuaduong): Add ipv6 tests once we have it working in adb"""
721 """Register/Unregister a service"""
722 with zeroconf_context(IPVersion.V4Only) as zc:
723 srvs = {
724 'mdns_name': ["testservice0", "testservice1", "testservice2"],
725 'mdns_type': "_" + self.service_name + "._tcp.",
726 'ipaddr': [
727 socket.inet_aton("192.168.0.1"),
728 socket.inet_aton("10.0.0.255"),
729 socket.inet_aton("172.16.1.100")],
730 'port': [10000, 20000, 65535]}
731 srv_infos = []
732 for i in range(len(srvs['mdns_name'])):
733 srv_infos.append(ServiceInfo(
734 srvs['mdns_type'] + "local.",
735 name=srvs['mdns_name'][i] + "." + srvs['mdns_type'] + "local.",
736 addresses=[srvs['ipaddr'][i]],
737 port=srvs['port'][i]))
738
739 """ Register all devices, then unregister"""
740 with zeroconf_register_services(zc, srv_infos) as infos:
741 """Give adb some time to register the service"""
742 time.sleep(1)
743 for i in range(len(srvs['mdns_name'])):
744 self.assertTrue(any((srvs['mdns_name'][i] in line and srvs['mdns_type'] in line)
745 for line in MdnsTest._mdns_services(server_port)))
746
747 """Give adb some time to unregister the service"""
748 time.sleep(1)
749 for i in range(len(srvs['mdns_name'])):
750 self.assertFalse(any((srvs['mdns_name'][i] in line and srvs['mdns_type'] in line)
751 for line in MdnsTest._mdns_services(server_port)))
752
753 @unittest.skipIf(not is_zeroconf_installed(), "zeroconf library not installed")
Josh Gao5ece8e42020-06-02 13:14:45 -0700754 def test_mdns_connect(self):
755 """Ensure that `adb connect` by mdns instance name works (for non-pairing services)
756 """
757 from zeroconf import IPVersion, ServiceInfo
758
759 with adb_server() as server_port:
760 with zeroconf_context(IPVersion.V4Only) as zc:
761 serv_instance = "fakeadbd-" + ''.join(
762 random.choice(string.ascii_letters) for i in range(4))
763 serv_type = "_" + self.service_name + "._tcp."
764 serv_ipaddr = socket.inet_aton("127.0.0.1")
765 should_connect = self.service_name != "adb-tls-pairing"
766 with fake_adbd() as (port, _):
767 service_info = ServiceInfo(
768 serv_type + "local.",
769 name=serv_instance + "." + serv_type + "local.",
770 addresses=[serv_ipaddr],
771 port=port)
772 with zeroconf_register_service(zc, service_info) as info:
773 """Give adb some time to register the service"""
774 time.sleep(1)
775 self.assertTrue(any((serv_instance in line and serv_type in line)
776 for line in MdnsTest._mdns_services(server_port)))
777 full_name = '.'.join([serv_instance, serv_type])
778 with self._adb_mdns_connect(server_port, serv_instance, full_name,
779 should_connect):
780 if should_connect:
781 self.assertEqual(MdnsTest._devices(server_port),
782 [[full_name, "device"]])
783
784 """Give adb some time to unregister the service"""
785 time.sleep(1)
786 self.assertFalse(any((serv_instance in line and serv_type in line)
787 for line in MdnsTest._mdns_services(server_port)))
788
789
790@unittest.skipIf(not is_adb_mdns_available(), "mdns feature not available")
791class MdnsTestAdb(MdnsTest.Base):
792 service_name = "adb"
793
794
795@unittest.skipIf(not is_adb_mdns_available(), "mdns feature not available")
796class MdnsTestAdbTlsConnect(MdnsTest.Base):
797 service_name = "adb-tls-connect"
798
799
800@unittest.skipIf(not is_adb_mdns_available(), "mdns feature not available")
801class MdnsTestAdbTlsPairing(MdnsTest.Base):
802 service_name = "adb-tls-pairing"
803
804
Dan Alberta4169f92015-07-24 17:08:33 -0700805def main():
Luis Hector Chavez947b2132018-05-02 09:10:29 -0700806 """Main entrypoint."""
Dan Alberta4169f92015-07-24 17:08:33 -0700807 random.seed(0)
Luis Hector Chavez947b2132018-05-02 09:10:29 -0700808 unittest.main(verbosity=3)
Dan Alberta4169f92015-07-24 17:08:33 -0700809
810
Josh Gao4db70c52018-08-08 13:08:08 -0700811if __name__ == "__main__":
Dan Alberta4169f92015-07-24 17:08:33 -0700812 main()