• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Copyright 2018 Google Inc.
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7#     http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14"""Module for the snippet management service."""
15from mobly.controllers.android_device_lib import errors
16from mobly.controllers.android_device_lib import snippet_client
17from mobly.controllers.android_device_lib.services import base_service
18
19MISSING_SNIPPET_CLIENT_MSG = 'No snippet client is registered with name "%s".'
20
21
22class Error(errors.ServiceError):
23  """Root error type for snippet management service."""
24  SERVICE_TYPE = 'SnippetManagementService'
25
26
27class SnippetManagementService(base_service.BaseService):
28  """Management service of snippet clients.
29
30  This service manages all the snippet clients associated with an Android
31  device.
32  """
33
34  def __init__(self, device, configs=None):
35    del configs  # Unused param.
36    self._device = device
37    self._is_alive = False
38    self._snippet_clients = {}
39    super().__init__(device)
40
41  @property
42  def is_alive(self):
43    """True if any client is running, False otherwise."""
44    return any([client.is_alive for client in self._snippet_clients.values()])
45
46  def get_snippet_client(self, name):
47    """Gets the snippet client managed under a given name.
48
49    Args:
50      name: string, the name of the snippet client under management.
51
52    Returns:
53      SnippetClient.
54    """
55    if name in self._snippet_clients:
56      return self._snippet_clients[name]
57
58  def add_snippet_client(self, name, package):
59    """Adds a snippet client to the management.
60
61    Args:
62      name: string, the attribute name to which to attach the snippet
63        client. E.g. `name='maps'` attaches the snippet client to
64        `ad.maps`.
65      package: string, the package name of the snippet apk to connect to.
66
67    Raises:
68      Error, if a duplicated name or package is passed in.
69    """
70    # Should not load snippet with the same name more than once.
71    if name in self._snippet_clients:
72      raise Error(
73          self, 'Name "%s" is already registered with package "%s", it cannot '
74          'be used again.' % (name, self._snippet_clients[name].client.package))
75    # Should not load the same snippet package more than once.
76    for snippet_name, client in self._snippet_clients.items():
77      if package == client.package:
78        raise Error(
79            self, 'Snippet package "%s" has already been loaded under name'
80            ' "%s".' % (package, snippet_name))
81    client = snippet_client.SnippetClient(package=package, ad=self._device)
82    client.start_app_and_connect()
83    self._snippet_clients[name] = client
84
85  def remove_snippet_client(self, name):
86    """Removes a snippet client from management.
87
88    Args:
89      name: string, the name of the snippet client to remove.
90
91    Raises:
92      Error: if no snippet client is managed under the specified name.
93    """
94    if name not in self._snippet_clients:
95      raise Error(self._device, MISSING_SNIPPET_CLIENT_MSG % name)
96    client = self._snippet_clients.pop(name)
97    client.stop_app()
98
99  def start(self):
100    """Starts all the snippet clients under management."""
101    for client in self._snippet_clients.values():
102      if not client.is_alive:
103        self._device.log.debug('Starting SnippetClient<%s>.', client.package)
104        client.start_app_and_connect()
105      else:
106        self._device.log.debug(
107            'Not startng SnippetClient<%s> because it is already alive.',
108            client.package)
109
110  def stop(self):
111    """Stops all the snippet clients under management."""
112    for client in self._snippet_clients.values():
113      if client.is_alive:
114        self._device.log.debug('Stopping SnippetClient<%s>.', client.package)
115        client.stop_app()
116      else:
117        self._device.log.debug(
118            'Not stopping SnippetClient<%s> because it is not alive.',
119            client.package)
120
121  def pause(self):
122    """Pauses all the snippet clients under management.
123
124    This clears the host port of a client because a new port will be
125    allocated in `resume`.
126    """
127    for client in self._snippet_clients.values():
128      self._device.log.debug('Pausing SnippetClient<%s>.', client.package)
129      client.disconnect()
130
131  def resume(self):
132    """Resumes all paused snippet clients."""
133    for client in self._snippet_clients.values():
134      if not client.is_alive:
135        self._device.log.debug('Resuming SnippetClient<%s>.', client.package)
136        client.restore_app_connection()
137      else:
138        self._device.log.debug('Not resuming SnippetClient<%s>.',
139                               client.package)
140
141  def __getattr__(self, name):
142    client = self.get_snippet_client(name)
143    if client:
144      return client
145    return self.__getattribute__(name)
146