-
Notifications
You must be signed in to change notification settings - Fork 21
Android Emulator Driver #437
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
8ee047b
3aacde0
96f1073
765119e
c957cd1
6fd7d41
ee8759a
b5472c4
d583165
ccb810f
53cc89c
41748ac
f9b2e5b
dd2191d
c7c0b6f
9688d26
3e90beb
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -15,6 +15,8 @@ function: | |
| Drivers that control the power state and basic operation of devices: | ||
|
|
||
| * **[Power](power.md)** (`jumpstarter-driver-power`) - Power control for devices | ||
| * **[Android](android.md)** (`jumpstarter-driver-android`) - | ||
| Android device control over ADB | ||
| * **[Raspberry Pi](raspberrypi.md)** (`jumpstarter-driver-raspberrypi`) - | ||
| Raspberry Pi hardware control | ||
| * **[Yepkit](yepkit.md)** (`jumpstarter-driver-yepkit`) - Yepkit hardware | ||
|
|
@@ -56,6 +58,16 @@ Drivers that handle media streams: | |
| * **[UStreamer](ustreamer.md)** (`jumpstarter-driver-ustreamer`) - Video | ||
| streaming functionality | ||
|
|
||
| ### Virtualization Drivers | ||
|
|
||
| Drivers for running virtual machines and systems: | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
|
|
||
| * **[QEMU](qemu.md)** (`jumpstarter-driver-qemu`) - QEMU virtualization platform | ||
| * **[Corellium](corellium.md)** (`jumpstarter-driver-corellium`) - Corellium | ||
| virtualization platform | ||
| * **[Android](android.md)** (`jumpstarter-driver-android`) - | ||
| Android Virtual Device (AVD) emulator | ||
|
|
||
| ### Debug and Programming Drivers | ||
|
|
||
| Drivers for debugging and programming devices: | ||
|
|
@@ -64,9 +76,6 @@ Drivers for debugging and programming devices: | |
| programming tools | ||
| * **[Probe-RS](probe-rs.md)** (`jumpstarter-driver-probe-rs`) - Debugging probe | ||
| support | ||
| * **[QEMU](qemu.md)** (`jumpstarter-driver-qemu`) - QEMU virtualization platform | ||
| * **[Corellium](corellium.md)** (`jumpstarter-driver-corellium`) - Corellium | ||
| virtualization platform | ||
| * **[U-Boot](uboot.md)** (`jumpstarter-driver-uboot`) - Universal Bootloader | ||
| interface | ||
|
|
||
|
|
@@ -78,6 +87,7 @@ General-purpose utility drivers: | |
|
|
||
| ```{toctree} | ||
| :hidden: | ||
| android.md | ||
| can.md | ||
| corellium.md | ||
| dutlink.md | ||
|
|
||
Large diffs are not rendered by default.
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,235 @@ | ||||||||||||||||||||||||||||||||||||||||||
| import errno | ||||||||||||||||||||||||||||||||||||||||||
| import os | ||||||||||||||||||||||||||||||||||||||||||
| import socket | ||||||||||||||||||||||||||||||||||||||||||
| import subprocess | ||||||||||||||||||||||||||||||||||||||||||
| import sys | ||||||||||||||||||||||||||||||||||||||||||
| from contextlib import contextmanager | ||||||||||||||||||||||||||||||||||||||||||
| from threading import Event | ||||||||||||||||||||||||||||||||||||||||||
| from typing import Generator | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| import adbutils | ||||||||||||||||||||||||||||||||||||||||||
| import click | ||||||||||||||||||||||||||||||||||||||||||
| from jumpstarter_driver_composite.client import CompositeClient | ||||||||||||||||||||||||||||||||||||||||||
| from jumpstarter_driver_network.adapters import TcpPortforwardAdapter | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| from jumpstarter.client import DriverClient | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| class AndroidClient(CompositeClient): | ||||||||||||||||||||||||||||||||||||||||||
| """Generic Android client for controlling Android devices/emulators.""" | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| pass | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| class AdbClientBase(DriverClient): | ||||||||||||||||||||||||||||||||||||||||||
| """ | ||||||||||||||||||||||||||||||||||||||||||
| Base class for ADB clients. This class provides a context manager to | ||||||||||||||||||||||||||||||||||||||||||
| create an ADB client and forward the ADB server address and port. | ||||||||||||||||||||||||||||||||||||||||||
| """ | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| def _check_port_in_use(self, host: str, port: int) -> bool: | ||||||||||||||||||||||||||||||||||||||||||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This function is unused.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This should also be removed after some experimentation, not reliable across platforms. |
||||||||||||||||||||||||||||||||||||||||||
| # Check if port is already bound | ||||||||||||||||||||||||||||||||||||||||||
| sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) | ||||||||||||||||||||||||||||||||||||||||||
| try: | ||||||||||||||||||||||||||||||||||||||||||
| sock.bind((host, port)) | ||||||||||||||||||||||||||||||||||||||||||
| except socket.error as e: | ||||||||||||||||||||||||||||||||||||||||||
| if e.errno == errno.EADDRINUSE: | ||||||||||||||||||||||||||||||||||||||||||
| return True | ||||||||||||||||||||||||||||||||||||||||||
| finally: | ||||||||||||||||||||||||||||||||||||||||||
| sock.close() | ||||||||||||||||||||||||||||||||||||||||||
| return False | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| @contextmanager | ||||||||||||||||||||||||||||||||||||||||||
| def forward_adb(self, host: str, port: int) -> Generator[str, None, None]: | ||||||||||||||||||||||||||||||||||||||||||
| """ | ||||||||||||||||||||||||||||||||||||||||||
| Port-forward remote ADB server to local host and port. | ||||||||||||||||||||||||||||||||||||||||||
| If the port is already bound, yields the existing address instead. | ||||||||||||||||||||||||||||||||||||||||||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not yet implemented?
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, this was an attempt to fix port issues, should be removed. |
||||||||||||||||||||||||||||||||||||||||||
| Args: | ||||||||||||||||||||||||||||||||||||||||||
| host (str): The local host to forward to. | ||||||||||||||||||||||||||||||||||||||||||
| port (int): The local port to forward to. | ||||||||||||||||||||||||||||||||||||||||||
| Yields: | ||||||||||||||||||||||||||||||||||||||||||
| str: The address of the forwarded ADB server. | ||||||||||||||||||||||||||||||||||||||||||
| """ | ||||||||||||||||||||||||||||||||||||||||||
| with TcpPortforwardAdapter( | ||||||||||||||||||||||||||||||||||||||||||
| client=self, | ||||||||||||||||||||||||||||||||||||||||||
| local_host=host, | ||||||||||||||||||||||||||||||||||||||||||
| local_port=port, | ||||||||||||||||||||||||||||||||||||||||||
| ) as addr: | ||||||||||||||||||||||||||||||||||||||||||
| yield addr | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| @contextmanager | ||||||||||||||||||||||||||||||||||||||||||
| def adb_client(self, host: str = "127.0.0.1", port: int = 5038) -> Generator[adbutils.AdbClient, None, None]: | ||||||||||||||||||||||||||||||||||||||||||
| """ | ||||||||||||||||||||||||||||||||||||||||||
| Context manager to get an `adbutils.AdbClient`. | ||||||||||||||||||||||||||||||||||||||||||
| Args: | ||||||||||||||||||||||||||||||||||||||||||
| host (str): The local host to forward to. | ||||||||||||||||||||||||||||||||||||||||||
| port (int): The local port to forward to. | ||||||||||||||||||||||||||||||||||||||||||
| Yields: | ||||||||||||||||||||||||||||||||||||||||||
| adbutils.AdbClient: The `adbutils.AdbClient` instance. | ||||||||||||||||||||||||||||||||||||||||||
| """ | ||||||||||||||||||||||||||||||||||||||||||
| with self.forward_adb(host, port) as addr: | ||||||||||||||||||||||||||||||||||||||||||
| client = adbutils.AdbClient(host=addr[0], port=int(addr[1])) | ||||||||||||||||||||||||||||||||||||||||||
| yield client | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| class AdbClient(AdbClientBase): | ||||||||||||||||||||||||||||||||||||||||||
| """ADB client for interacting with Android devices.""" | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| def cli(self): | ||||||||||||||||||||||||||||||||||||||||||
| @click.command(context_settings={"ignore_unknown_options": True}) | ||||||||||||||||||||||||||||||||||||||||||
| @click.option("host", "-H", default="127.0.0.1", show_default=True, help="Local adb host to forward to.") | ||||||||||||||||||||||||||||||||||||||||||
| @click.option("port", "-P", type=int, default=5038, show_default=True, help="Local adb port to forward to.") | ||||||||||||||||||||||||||||||||||||||||||
| @click.option("-a", is_flag=True, hidden=True) | ||||||||||||||||||||||||||||||||||||||||||
| @click.option("-d", is_flag=True, hidden=True) | ||||||||||||||||||||||||||||||||||||||||||
| @click.option("-e", is_flag=True, hidden=True) | ||||||||||||||||||||||||||||||||||||||||||
| @click.option("-L", hidden=True) | ||||||||||||||||||||||||||||||||||||||||||
| @click.option("--one-device", hidden=True) | ||||||||||||||||||||||||||||||||||||||||||
| @click.option( | ||||||||||||||||||||||||||||||||||||||||||
| "--adb", | ||||||||||||||||||||||||||||||||||||||||||
| default="adb", | ||||||||||||||||||||||||||||||||||||||||||
| show_default=True, | ||||||||||||||||||||||||||||||||||||||||||
| help="Path to the ADB executable", | ||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||
| @click.argument("args", nargs=-1) | ||||||||||||||||||||||||||||||||||||||||||
| def adb( | ||||||||||||||||||||||||||||||||||||||||||
| host: str, | ||||||||||||||||||||||||||||||||||||||||||
| port: int, | ||||||||||||||||||||||||||||||||||||||||||
| adb: str, | ||||||||||||||||||||||||||||||||||||||||||
| a: bool, | ||||||||||||||||||||||||||||||||||||||||||
| d: bool, | ||||||||||||||||||||||||||||||||||||||||||
| e: bool, | ||||||||||||||||||||||||||||||||||||||||||
| l: str, # noqa: E741 | ||||||||||||||||||||||||||||||||||||||||||
| one_device: str, | ||||||||||||||||||||||||||||||||||||||||||
| args: tuple[str, ...], | ||||||||||||||||||||||||||||||||||||||||||
| ): | ||||||||||||||||||||||||||||||||||||||||||
| """ | ||||||||||||||||||||||||||||||||||||||||||
| Run adb using a local adb binary against the remote adb server. | ||||||||||||||||||||||||||||||||||||||||||
| This command is a wrapper around the adb command-line tool. It allows you to run regular adb commands | ||||||||||||||||||||||||||||||||||||||||||
| with an automatically forwarded adb server running on your Jumpstarter exporter. | ||||||||||||||||||||||||||||||||||||||||||
| When executing this command, the exporter adb daemon is forwarded to a local port. The | ||||||||||||||||||||||||||||||||||||||||||
| adb server address and port are automatically set in the environment variables ANDROID_ADB_SERVER_ADDRESS | ||||||||||||||||||||||||||||||||||||||||||
| and ANDROID_ADB_SERVER_PORT, respectively. This configures your local adb client to communicate with the | ||||||||||||||||||||||||||||||||||||||||||
| remote adb server. | ||||||||||||||||||||||||||||||||||||||||||
| Most command line arguments and commands are passed directly to the adb CLI. However, some | ||||||||||||||||||||||||||||||||||||||||||
| arguments and commands are not supported by the Jumpstarter adb client. These options include: | ||||||||||||||||||||||||||||||||||||||||||
| -a, -d, -e, -L, --one-device. | ||||||||||||||||||||||||||||||||||||||||||
| The following adb commands are also not supported in remote adb environments: connect, disconnect, | ||||||||||||||||||||||||||||||||||||||||||
| reconnect, nodaemon, pair | ||||||||||||||||||||||||||||||||||||||||||
| When running start-server or kill-server, Jumpstarter will start or kill the adb server on the exporter. | ||||||||||||||||||||||||||||||||||||||||||
| Use the forward-adb command to forward the adb server address and port to a local port manually. | ||||||||||||||||||||||||||||||||||||||||||
| """ | ||||||||||||||||||||||||||||||||||||||||||
| # Throw exception for all unsupported arguments | ||||||||||||||||||||||||||||||||||||||||||
| if any([a, d, e, l, one_device]): | ||||||||||||||||||||||||||||||||||||||||||
| raise click.UsageError( | ||||||||||||||||||||||||||||||||||||||||||
| "ADB options -a, -d, -e, -L, and --one-device are not supported by the Jumpstarter ADB client" | ||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||
| # Check for unsupported server management commands | ||||||||||||||||||||||||||||||||||||||||||
| unsupported_commands = [ | ||||||||||||||||||||||||||||||||||||||||||
| "connect", | ||||||||||||||||||||||||||||||||||||||||||
| "disconnect", | ||||||||||||||||||||||||||||||||||||||||||
| "reconnect", | ||||||||||||||||||||||||||||||||||||||||||
| "nodaemon", | ||||||||||||||||||||||||||||||||||||||||||
| "pair", | ||||||||||||||||||||||||||||||||||||||||||
| ] | ||||||||||||||||||||||||||||||||||||||||||
| for arg in args: | ||||||||||||||||||||||||||||||||||||||||||
| if arg in unsupported_commands: | ||||||||||||||||||||||||||||||||||||||||||
| raise click.UsageError(f"The adb command '{arg}' is not supported by the Jumpstarter ADB client") | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| if "start-server" in args: | ||||||||||||||||||||||||||||||||||||||||||
| remote_port = int(self.call("start_server")) | ||||||||||||||||||||||||||||||||||||||||||
| click.echo(f"Remote adb server started on remote port exporter:{remote_port}") | ||||||||||||||||||||||||||||||||||||||||||
| return 0 | ||||||||||||||||||||||||||||||||||||||||||
| elif "kill-server" in args: | ||||||||||||||||||||||||||||||||||||||||||
| remote_port = int(self.call("kill_server")) | ||||||||||||||||||||||||||||||||||||||||||
| click.echo(f"Remote adb server killed on remote port exporter:{remote_port}") | ||||||||||||||||||||||||||||||||||||||||||
| return 0 | ||||||||||||||||||||||||||||||||||||||||||
| elif "forward-adb" in args: | ||||||||||||||||||||||||||||||||||||||||||
| # Port is available, proceed with forwarding | ||||||||||||||||||||||||||||||||||||||||||
| with self.forward_adb(host, port) as addr: | ||||||||||||||||||||||||||||||||||||||||||
| click.echo(f"Remote adb server forwarded to {addr[0]}:{addr[1]}") | ||||||||||||||||||||||||||||||||||||||||||
| Event().wait() | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| # Forward the ADB server address and port and call ADB executable with args | ||||||||||||||||||||||||||||||||||||||||||
| with self.forward_adb(host, port) as addr: | ||||||||||||||||||||||||||||||||||||||||||
| env = os.environ | { | ||||||||||||||||||||||||||||||||||||||||||
| "ANDROID_ADB_SERVER_ADDRESS": addr[0], | ||||||||||||||||||||||||||||||||||||||||||
| "ANDROID_ADB_SERVER_PORT": str(addr[1]), | ||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||
| cmd = [adb, *args] | ||||||||||||||||||||||||||||||||||||||||||
| process = subprocess.Popen(cmd, stdin=sys.stdin, stdout=sys.stdout, stderr=sys.stderr, env=env) | ||||||||||||||||||||||||||||||||||||||||||
| return process.wait() | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+162
to
+171
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Use proper subprocess management for resource cleanup. The subprocess should be managed properly to ensure cleanup even if an exception occurs. # Forward the ADB server address and port and call ADB executable with args
with self.forward_adb(host, port) as addr:
env = os.environ | {
"ANDROID_ADB_SERVER_ADDRESS": addr[0],
"ANDROID_ADB_SERVER_PORT": str(addr[1]),
}
cmd = [adb, *args]
- process = subprocess.Popen(cmd, stdin=sys.stdin, stdout=sys.stdout, stderr=sys.stderr, env=env)
- return process.wait()
+ with subprocess.Popen(cmd, stdin=sys.stdin, stdout=sys.stdout, stderr=sys.stderr, env=env) as process:
+ return process.wait()📝 Committable suggestion
Suggested change
🧰 Tools🪛 Pylint (3.3.7)[convention] 169-169: Line too long (111/100) (C0301) [refactor] 169-169: Consider using 'with' for resource-allocating operations (R1732) 🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||
| return adb | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| class ScrcpyClient(AdbClientBase): | ||||||||||||||||||||||||||||||||||||||||||
| """Scrcpy client for controlling Android devices remotely.""" | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| def cli(self): | ||||||||||||||||||||||||||||||||||||||||||
| @click.command(context_settings={"ignore_unknown_options": True}) | ||||||||||||||||||||||||||||||||||||||||||
| @click.option("host", "-H", default="127.0.0.1", show_default=True, help="Local adb host to forward to.") | ||||||||||||||||||||||||||||||||||||||||||
| @click.option("port", "-P", type=int, default=5038, show_default=True, help="Local adb port to forward to.") | ||||||||||||||||||||||||||||||||||||||||||
| @click.option( | ||||||||||||||||||||||||||||||||||||||||||
| "--scrcpy", | ||||||||||||||||||||||||||||||||||||||||||
| default="scrcpy", | ||||||||||||||||||||||||||||||||||||||||||
| show_default=True, | ||||||||||||||||||||||||||||||||||||||||||
| help="Path to the scrcpy executable", | ||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||
| @click.argument("args", nargs=-1) | ||||||||||||||||||||||||||||||||||||||||||
| def scrcpy( | ||||||||||||||||||||||||||||||||||||||||||
| host: str, | ||||||||||||||||||||||||||||||||||||||||||
| port: int, | ||||||||||||||||||||||||||||||||||||||||||
| scrcpy: str, | ||||||||||||||||||||||||||||||||||||||||||
| args: tuple[str, ...], | ||||||||||||||||||||||||||||||||||||||||||
| ): | ||||||||||||||||||||||||||||||||||||||||||
| """ | ||||||||||||||||||||||||||||||||||||||||||
| Run scrcpy using a local executable against the remote adb server. | ||||||||||||||||||||||||||||||||||||||||||
| This command is a wrapper around the scrcpy command-line tool. It allows you to run scrcpy | ||||||||||||||||||||||||||||||||||||||||||
| against a remote Android device through an ADB server tunneled via Jumpstarter. | ||||||||||||||||||||||||||||||||||||||||||
| When executing this command, the adb server address and port are forwarded to the local scrcpy executable. | ||||||||||||||||||||||||||||||||||||||||||
| The adb server socket path is set in the environment variable ADB_SERVER_SOCKET, allowing scrcpy to | ||||||||||||||||||||||||||||||||||||||||||
| communicate with the remote adb server. | ||||||||||||||||||||||||||||||||||||||||||
| Most command line arguments are passed directly to the scrcpy executable. | ||||||||||||||||||||||||||||||||||||||||||
| """ | ||||||||||||||||||||||||||||||||||||||||||
| # Unsupported scrcpy arguments that depend on direct adb server management | ||||||||||||||||||||||||||||||||||||||||||
| unsupported_args = [ | ||||||||||||||||||||||||||||||||||||||||||
| "--connect", | ||||||||||||||||||||||||||||||||||||||||||
| "-c", | ||||||||||||||||||||||||||||||||||||||||||
| "--serial", | ||||||||||||||||||||||||||||||||||||||||||
| "-s", | ||||||||||||||||||||||||||||||||||||||||||
| "--select-usb", | ||||||||||||||||||||||||||||||||||||||||||
| "--select-tcpip", | ||||||||||||||||||||||||||||||||||||||||||
| ] | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| for arg in args: | ||||||||||||||||||||||||||||||||||||||||||
| for unsupported in unsupported_args: | ||||||||||||||||||||||||||||||||||||||||||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Or print a warning and ignore the argument? Then the same scrcpy invocation can be used with or without jumpstarter.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. These arguments don't really work when using remote scrcpy which itself is also an adb wrapper 🙄. I can switch this to warnings instead. |
||||||||||||||||||||||||||||||||||||||||||
| if arg.startswith(unsupported): | ||||||||||||||||||||||||||||||||||||||||||
| raise click.UsageError( | ||||||||||||||||||||||||||||||||||||||||||
| f"Scrcpy argument '{unsupported}' is not supported by the Jumpstarter scrcpy client" | ||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| # Forward the ADB server address and port and call scrcpy executable with args | ||||||||||||||||||||||||||||||||||||||||||
| with self.forward_adb(host, port) as addr: | ||||||||||||||||||||||||||||||||||||||||||
| # Scrcpy uses ADB_SERVER_SOCKET environment variable | ||||||||||||||||||||||||||||||||||||||||||
| socket_path = f"tcp:{addr[0]}:{addr[1]}" | ||||||||||||||||||||||||||||||||||||||||||
| env = os.environ | { | ||||||||||||||||||||||||||||||||||||||||||
| "ADB_SERVER_SOCKET": socket_path, | ||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||
| cmd = [scrcpy, *args] | ||||||||||||||||||||||||||||||||||||||||||
| process = subprocess.Popen(cmd, stdin=sys.stdin, stdout=sys.stdout, stderr=sys.stderr, env=env) | ||||||||||||||||||||||||||||||||||||||||||
| return process.wait() | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+224
to
+234
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Use proper subprocess management for resource cleanup. Similar to the AdbClient, the subprocess should be properly managed. # Forward the ADB server address and port and call scrcpy executable with args
with self.forward_adb(host, port) as addr:
# Scrcpy uses ADB_SERVER_SOCKET environment variable
socket_path = f"tcp:{addr[0]}:{addr[1]}"
env = os.environ | {
"ADB_SERVER_SOCKET": socket_path,
}
cmd = [scrcpy, *args]
- process = subprocess.Popen(cmd, stdin=sys.stdin, stdout=sys.stdout, stderr=sys.stderr, env=env)
- return process.wait()
+ with subprocess.Popen(cmd, stdin=sys.stdin, stdout=sys.stdout, stderr=sys.stderr, env=env) as process:
+ return process.wait()📝 Committable suggestion
Suggested change
🧰 Tools🪛 Pylint (3.3.7)[convention] 232-232: Line too long (111/100) (C0301) [refactor] 232-232: Consider using 'with' for resource-allocating operations (R1732) 🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||
| return scrcpy | ||||||||||||||||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,13 @@ | ||
| from .adb import AdbServer | ||
| from .emulator import AndroidEmulator, AndroidEmulatorPower | ||
| from .options import AdbOptions, EmulatorOptions | ||
| from .scrcpy import Scrcpy | ||
|
|
||
| __all__ = [ | ||
| "AdbServer", | ||
| "AndroidEmulator", | ||
| "AndroidEmulatorPower", | ||
| "AdbOptions", | ||
| "EmulatorOptions", | ||
| "Scrcpy", | ||
| ] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be a symlink to
packages/jumpstarter-driver-android/README.md