diff options
Diffstat (limited to 'mobly/controllers/android_device_lib')
3 files changed, 52 insertions, 6 deletions
diff --git a/mobly/controllers/android_device_lib/services/logcat.py b/mobly/controllers/android_device_lib/services/logcat.py index cbd8e95..37a8454 100644 --- a/mobly/controllers/android_device_lib/services/logcat.py +++ b/mobly/controllers/android_device_lib/services/logcat.py @@ -201,6 +201,10 @@ class Logcat(base_service.BaseService): The collection runs in a separate subprocess and saves logs in a file. """ + if self._ad.is_bootloader: + self._ad.log.warning( + 'Skip starting logcat because the device is in fastboot mode.') + return self._assert_not_running() if self._config.clear_log: self.clear_adb_log() diff --git a/mobly/controllers/android_device_lib/services/snippet_management_service.py b/mobly/controllers/android_device_lib/services/snippet_management_service.py index fae60e2..05e8cda 100644 --- a/mobly/controllers/android_device_lib/services/snippet_management_service.py +++ b/mobly/controllers/android_device_lib/services/snippet_management_service.py @@ -55,7 +55,7 @@ class SnippetManagementService(base_service.BaseService): if name in self._snippet_clients: return self._snippet_clients[name] - def add_snippet_client(self, name, package): + def add_snippet_client(self, name, package, config=None): """Adds a snippet client to the management. Args: @@ -63,6 +63,9 @@ class SnippetManagementService(base_service.BaseService): client. E.g. `name='maps'` attaches the snippet client to `ad.maps`. package: string, the package name of the snippet apk to connect to. + config: snippet_client_v2.Config, the configuration object for + controlling the snippet behaviors. See the docstring of the `Config` + class for supported configurations. Raises: Error, if a duplicated name or package is passed in. @@ -79,7 +82,9 @@ class SnippetManagementService(base_service.BaseService): self, 'Snippet package "%s" has already been loaded under name' ' "%s".' % (package, snippet_name)) - client = snippet_client_v2.SnippetClientV2(package=package, ad=self._device) + client = snippet_client_v2.SnippetClientV2( + package=package, ad=self._device, config=config, + ) client.initialize() self._snippet_clients[name] = client diff --git a/mobly/controllers/android_device_lib/snippet_client_v2.py b/mobly/controllers/android_device_lib/snippet_client_v2.py index 3adfde5..f7494c2 100644 --- a/mobly/controllers/android_device_lib/snippet_client_v2.py +++ b/mobly/controllers/android_device_lib/snippet_client_v2.py @@ -13,10 +13,12 @@ # limitations under the License. """Snippet Client V2 for Interacting with Snippet Server on Android Device.""" +import dataclasses import enum import json import re import socket +from typing import Dict from mobly import utils from mobly.controllers.android_device_lib import adb @@ -30,8 +32,8 @@ _INSTRUMENTATION_RUNNER_PACKAGE = 'com.google.android.mobly.snippet.SnippetRunne # The command template to start the snippet server _LAUNCH_CMD = ( - '{shell_cmd} am instrument {user} -w -e action start {snippet_package}/' - f'{_INSTRUMENTATION_RUNNER_PACKAGE}') + '{shell_cmd} am instrument {user} -w -e action start {instrument_options} ' + f'{{snippet_package}}/{_INSTRUMENTATION_RUNNER_PACKAGE}') # The command template to stop the snippet server _STOP_CMD = ('am instrument {user} -w -e action stop {snippet_package}/' @@ -76,6 +78,23 @@ _SOCKET_READ_TIMEOUT = 60 * 10 _CALLBACK_DEFAULT_TIMEOUT_SEC = 60 * 2 +@dataclasses.dataclass +class Config: + """A configuration class. + + Attributes: + am_instrument_options: The Android am instrument options used for + controlling the `onCreate` process of the app under test. Note that this + should only be used for controlling the app launch process, options for + other purposes may not take effect and you should use snippet RPCs. This + is because Mobly snippet runner changes the subsequent instrumentation + process. + """ + + am_instrument_options: Dict[str, str] = dataclasses.field( + default_factory=dict) + + class ConnectionHandshakeCommand(enum.Enum): """Commands to send to the server when sending the handshake request. @@ -109,12 +128,14 @@ class SnippetClientV2(client_base.ClientBase): the connection to the server is made successfully. """ - def __init__(self, package, ad): + def __init__(self, package, ad, config=None): """Initializes the instance of Snippet Client V2. Args: package: str, see base class. ad: AndroidDevice, the android device object associated with this client. + config: Config, the configuration object. See the docstring of the + `Config` class for supported configurations. """ super().__init__(package=package, device=ad) self.host_port = None @@ -126,6 +147,7 @@ class SnippetClientV2(client_base.ClientBase): self._client = None # keep it to prevent close errors on connect failure self._conn = None self._event_client = None + self._config = config or Config() @property def user_id(self): @@ -231,9 +253,11 @@ class SnippetClientV2(client_base.ClientBase): self.log.debug('Snippet server for package %s is using protocol %d.%d', self.package, _PROTOCOL_MAJOR_VERSION, _PROTOCOL_MINOR_VERSION) + option_str = self._get_instrument_options_str() cmd = _LAUNCH_CMD.format(shell_cmd=persists_shell_cmd, user=self._get_user_command_string(), - snippet_package=self.package) + snippet_package=self.package, + instrument_options=option_str) self._proc = self._run_adb_cmd(cmd) # Check protocol version and get the device port @@ -272,6 +296,19 @@ class SnippetClientV2(client_base.ClientBase): _SETSID_COMMAND, _NOHUP_COMMAND) return '' + def _get_instrument_options_str(self): + self.log.debug( + 'Got am instrument options in snippet client for package %s: %s', + self.package, + self._config.am_instrument_options, + ) + if not self._config.am_instrument_options: + return '' + + return ' '.join( + f'-e {k} {v}' for k, v in self._config.am_instrument_options.items() + ) + def _get_user_command_string(self): """Gets the appropriate command argument for specifying device user ID. |