From 2e1e927cafc08752e1b3603f67e5809e5e2b541a Mon Sep 17 00:00:00 2001 From: Tony Li Date: Mon, 13 Jul 2026 13:12:22 -0700 Subject: [PATCH] Update Configuration & ADB Controller for Pathlib Compatibility PiperOrigin-RevId: 947204216 --- android_env/components/adb_controller.py | 2 +- android_env/components/config_classes.py | 9 ++--- .../simulators/emulator/emulator_launcher.py | 29 +++++++++------ android_env/loader.py | 27 ++++++++------ android_env/loader_test.py | 36 +++++++++++-------- 5 files changed, 62 insertions(+), 41 deletions(-) diff --git a/android_env/components/adb_controller.py b/android_env/components/adb_controller.py index 8273757..314aca5 100644 --- a/android_env/components/adb_controller.py +++ b/android_env/components/adb_controller.py @@ -61,7 +61,7 @@ def command_prefix(self, include_device_name: bool = True) -> list[str]: # port explicitly. adb_port_args = ['-P', str(self._config.adb_server_port)] command_prefix = [ - self._config.adb_path, + os.fspath(self._config.adb_path), *adb_port_args, ] if include_device_name: diff --git a/android_env/components/config_classes.py b/android_env/components/config_classes.py index a1792dc..90a008f 100644 --- a/android_env/components/config_classes.py +++ b/android_env/components/config_classes.py @@ -17,6 +17,7 @@ import dataclasses import enum +import pathlib @dataclasses.dataclass @@ -113,7 +114,7 @@ class EmulatorLauncherConfig: # Path to the KVM device. kvm_device: str = '/dev/kvm' # Path to directory which will hold temporary files. - tmp_dir: str = '/tmp/android_env/simulator/' + tmp_dir: pathlib.Path | None = pathlib.Path('/tmp/android_env/simulator/') # GPU mode override. # Please see # https://developer.android.com/studio/run/emulator-acceleration#accel-graphics. @@ -155,7 +156,7 @@ class EmulatorConfig(SimulatorConfig): ) # Path to file which holds emulator logs. If not provided, it will be # determined by the EmulatorLauncher. - logfile_path: str = '' + logfile_path: pathlib.Path | None = None # The number of times to try launching the emulator before rebooting (reboot # on the n+1-st try). launch_n_times_without_reboot: int = 1 @@ -195,7 +196,7 @@ class TaskConfig: """Base config class for loading tasks.""" # The directory for temporary task-related resources. - tmp_dir: str = '' + tmp_dir: pathlib.Path | None = None @dataclasses.dataclass @@ -203,7 +204,7 @@ class FilesystemTaskConfig(TaskConfig): """Config for protobuf files stored in the local filesystem.""" # Filesystem path to `.binarypb` or `.textproto` protobuf Task. - path: str = '' + path: pathlib.Path | None = None @dataclasses.dataclass diff --git a/android_env/components/simulators/emulator/emulator_launcher.py b/android_env/components/simulators/emulator/emulator_launcher.py index 8958c58..85de152 100644 --- a/android_env/components/simulators/emulator/emulator_launcher.py +++ b/android_env/components/simulators/emulator/emulator_launcher.py @@ -17,6 +17,7 @@ import glob import os +import pathlib import subprocess import tempfile @@ -43,6 +44,7 @@ def __init__( # Create directory for tmp files. # Note: this will be deleted once EmulatorLauncher instance is cleaned up. + assert config.tmp_dir is not None os.makedirs(config.tmp_dir, exist_ok=True) self._local_tmp_dir_handle = tempfile.TemporaryDirectory( dir=config.tmp_dir, prefix='simulator_instance_' @@ -57,26 +59,31 @@ def logfile_path(self) -> str: def launch_emulator_process(self) -> None: """Launches the emulator.""" - logging.info('Booting new emulator: %s', self._config.emulator_path) + emulator_path = self._config.emulator_path + if not emulator_path: + raise ValueError('emulator_path must be set.') + + logging.info('Booting new emulator: %s', emulator_path) # Set necessary environment variables. - base_lib_dir = self._config.emulator_path[:-8] + 'lib64/' + emu_dir = emulator_path.parent + base_lib_dir = os.fspath(emu_dir / 'lib64') + '/' ld_library_path = ':'.join([ - base_lib_dir + 'x11/', base_lib_dir + 'qt/lib/', - base_lib_dir + 'gles_swiftshader/', base_lib_dir + base_lib_dir + 'x11/', + base_lib_dir + 'qt/lib/', + base_lib_dir + 'gles_swiftshader/', + base_lib_dir, ]) extra_env_vars = { 'ANDROID_HOME': '', - 'ANDROID_SDK_ROOT': self._config.android_sdk_root, - 'ANDROID_AVD_HOME': self._config.android_avd_home, + 'ANDROID_SDK_ROOT': os.fspath(self._config.android_sdk_root or ''), + 'ANDROID_AVD_HOME': os.fspath(self._config.android_avd_home or ''), 'ANDROID_EMULATOR_KVM_DEVICE': self._config.kvm_device, 'ANDROID_ADB_SERVER_PORT': str( self._adb_controller_config.adb_server_port ), 'LD_LIBRARY_PATH': ld_library_path, - 'QT_XKB_CONFIG_ROOT': str( - self._config.emulator_path[:-8] + 'qt_config/' - ), + 'QT_XKB_CONFIG_ROOT': os.fspath(emu_dir / 'qt_config') + '/', 'ANDROID_EMU_ENABLE_CRASH_REPORTING': '1', 'SHOW_PERF_STATS': str(1 if self._config.show_perf_stats else 0), } @@ -114,9 +121,9 @@ def launch_emulator_process(self) -> None: ) command = ( [ - self._config.emulator_path, + os.fspath(emulator_path), '-adb-path', - self._adb_controller_config.adb_path, + os.fspath(self._adb_controller_config.adb_path), '-gpu', self._config.gpu_mode, '-no-audio', diff --git a/android_env/loader.py b/android_env/loader.py index aac854d..c636e48 100644 --- a/android_env/loader.py +++ b/android_env/loader.py @@ -16,6 +16,7 @@ """Function for loading AndroidEnv.""" import os +import pathlib from absl import logging from android_env import environment @@ -36,6 +37,7 @@ def _load_task(task_config: config_classes.TaskConfig) -> task_pb2.Task: task = task_pb2.Task() match task_config: case config_classes.FilesystemTaskConfig(): + assert task_config.path is not None with open(task_config.path, 'r') as proto_file: text_format.Parse(proto_file.read(), task) case _: @@ -79,15 +81,18 @@ def _process_emulator_launcher_config( # Expand the user directory if specified. launcher_config = emulator_config.emulator_launcher - launcher_config.android_avd_home = os.path.expanduser( - launcher_config.android_avd_home - ) - launcher_config.android_sdk_root = os.path.expanduser( - launcher_config.android_sdk_root - ) - launcher_config.emulator_path = os.path.expanduser( - launcher_config.emulator_path - ) - emulator_config.adb_controller.adb_path = os.path.expanduser( - emulator_config.adb_controller.adb_path + if launcher_config.android_avd_home is not None: + launcher_config.android_avd_home = pathlib.Path( + os.path.expanduser(launcher_config.android_avd_home) + ) + if launcher_config.android_sdk_root is not None: + launcher_config.android_sdk_root = pathlib.Path( + os.path.expanduser(launcher_config.android_sdk_root) + ) + if launcher_config.emulator_path is not None: + launcher_config.emulator_path = pathlib.Path( + os.path.expanduser(launcher_config.emulator_path) + ) + emulator_config.adb_controller.adb_path = pathlib.Path( + os.path.expanduser(emulator_config.adb_controller.adb_path) ) diff --git a/android_env/loader_test.py b/android_env/loader_test.py index 6a56c9f..57e4151 100644 --- a/android_env/loader_test.py +++ b/android_env/loader_test.py @@ -14,7 +14,7 @@ # limitations under the License. import builtins -import os +import pathlib from typing import cast from unittest import mock @@ -53,17 +53,19 @@ def test_load_emulator( mock_open.return_value.__enter__ = mock_open mock_open.return_value.read.return_value = '' config = config_classes.AndroidEnvConfig( - task=config_classes.FilesystemTaskConfig(path='some/path/'), + task=config_classes.FilesystemTaskConfig( + path=pathlib.Path('some/path/') + ), simulator=config_classes.EmulatorConfig( emulator_launcher=config_classes.EmulatorLauncherConfig( avd_name='my_avd', - android_avd_home='~/.android/avd', - android_sdk_root='~/Android/Sdk', - emulator_path='~/Android/Sdk/emulator/emulator', + android_avd_home=pathlib.Path('~/.android/avd'), + android_sdk_root=pathlib.Path('~/Android/Sdk'), + emulator_path=pathlib.Path('~/Android/Sdk/emulator/emulator'), run_headless=False, ), adb_controller=config_classes.AdbControllerConfig( - adb_path='~/Android/Sdk/platform-tools/adb', + adb_path=pathlib.Path('~/Android/Sdk/platform-tools/adb'), ), ), ) @@ -79,16 +81,18 @@ def test_load_emulator( config=config_classes.EmulatorConfig( emulator_launcher=config_classes.EmulatorLauncherConfig( avd_name='my_avd', - android_avd_home=os.path.expanduser('~/.android/avd'), - android_sdk_root=os.path.expanduser('~/Android/Sdk'), - emulator_path=os.path.expanduser( + android_avd_home=pathlib.Path('~/.android/avd').expanduser(), + android_sdk_root=pathlib.Path('~/Android/Sdk').expanduser(), + emulator_path=pathlib.Path( '~/Android/Sdk/emulator/emulator' - ), + ).expanduser(), run_headless=False, gpu_mode='swangle_indirect', ), adb_controller=config_classes.AdbControllerConfig( - adb_path=os.path.expanduser('~/Android/Sdk/platform-tools/adb'), + adb_path=pathlib.Path( + '~/Android/Sdk/platform-tools/adb' + ).expanduser(), adb_server_port=5037, ), ) @@ -118,7 +122,9 @@ def test_load_fake_simulator( mock_open.return_value.__enter__ = mock_open mock_open.return_value.read.return_value = '' config = config_classes.AndroidEnvConfig( - task=config_classes.FilesystemTaskConfig(path='some/path/'), + task=config_classes.FilesystemTaskConfig( + path=pathlib.Path('some/path/') + ), simulator=config_classes.FakeSimulatorConfig( screen_dimensions=(1234, 5678) ), @@ -159,13 +165,15 @@ def test_task( max_episode_sec: 0 ''' config = config_classes.AndroidEnvConfig( - task=config_classes.FilesystemTaskConfig(path='some/path/'), + task=config_classes.FilesystemTaskConfig( + path=pathlib.Path('some/path/') + ), simulator=config_classes.EmulatorConfig( emulator_launcher=config_classes.EmulatorLauncherConfig( avd_name='my_avd' ), adb_controller=config_classes.AdbControllerConfig( - adb_path='~/Android/Sdk/platform-tools/adb', + adb_path=pathlib.Path('~/Android/Sdk/platform-tools/adb'), ), ), )