• 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_v2
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
82    client = snippet_client_v2.SnippetClientV2(package=package, ad=self._device)
83    client.initialize()
84    self._snippet_clients[name] = client
85
86  def remove_snippet_client(self, name):
87    """Removes a snippet client from management.
88
89    Args:
90      name: string, the name of the snippet client to remove.
91
92    Raises:
93      Error: if no snippet client is managed under the specified name.
94    """
95    if name not in self._snippet_clients:
96      raise Error(self._device, MISSING_SNIPPET_CLIENT_MSG % name)
97    client = self._snippet_clients.pop(name)
98    client.stop()
99
100  def start(self):
101    """Starts all the snippet clients under management."""
102    for client in self._snippet_clients.values():
103      if not client.is_alive:
104        self._device.log.debug('Starting SnippetClient<%s>.', client.package)
105        client.initialize()
106      else:
107        self._device.log.debug(
108            'Not startng SnippetClient<%s> because it is already alive.',
109            client.package)
110
111  def stop(self):
112    """Stops all the snippet clients under management."""
113    for client in self._snippet_clients.values():
114      if client.is_alive:
115        self._device.log.debug('Stopping SnippetClient<%s>.', client.package)
116        client.stop()
117      else:
118        self._device.log.debug(
119            'Not stopping SnippetClient<%s> because it is not alive.',
120            client.package)
121
122  def pause(self):
123    """Pauses all the snippet clients under management.
124
125    This clears the host port of a client because a new port will be
126    allocated in `resume`.
127    """
128    for client in self._snippet_clients.values():
129      self._device.log.debug('Pausing SnippetClient<%s>.', client.package)
130      client.close_connection()
131
132  def resume(self):
133    """Resumes all paused snippet clients."""
134    for client in self._snippet_clients.values():
135      if not client.is_alive:
136        self._device.log.debug('Resuming SnippetClient<%s>.', client.package)
137        client.restore_server_connection()
138      else:
139        self._device.log.debug('Not resuming SnippetClient<%s>.',
140                               client.package)
141
142  def __getattr__(self, name):
143    client = self.get_snippet_client(name)
144    if client:
145      return client
146    return self.__getattribute__(name)
147