xref: /aosp_15_r20/external/autotest/client/cros/multimedia/multimedia_xmlrpc_server.py (revision 9c5db1993ded3edbeafc8092d69fe5de2ee02df7)
1#!/usr/bin/env python
2# Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
3# Use of this source code is governed by a BSD-style license that can be
4# found in the LICENSE file.
5
6"""XML RPC server for multimedia testing."""
7
8import argparse
9import code
10import logging
11import os
12import six.moves.xmlrpc_client
13import sys
14import traceback
15
16import common   # pylint: disable=unused-import
17from autotest_lib.client.bin import utils
18from autotest_lib.client.common_lib import logging_config
19from autotest_lib.client.cros import constants
20from autotest_lib.client.cros import upstart
21from autotest_lib.client.cros import xmlrpc_server
22from autotest_lib.client.cros.multimedia import assistant_facade
23from autotest_lib.client.cros.multimedia import audio_facade
24from autotest_lib.client.cros.multimedia import browser_facade
25from autotest_lib.client.cros.multimedia import cfm_facade
26from autotest_lib.client.cros.multimedia import display_facade
27from autotest_lib.client.cros.multimedia import facade_resource
28from autotest_lib.client.cros.multimedia import graphics_facade
29from autotest_lib.client.cros.multimedia import input_facade
30from autotest_lib.client.cros.multimedia import kiosk_facade
31from autotest_lib.client.cros.multimedia import system_facade
32from autotest_lib.client.cros.multimedia import usb_facade
33from autotest_lib.client.cros.multimedia import video_facade
34
35# Python3 required for the following:
36if sys.version_info[0] >= 3:
37    from autotest_lib.client.cros.multimedia import bluetooth_facade
38
39
40class MultimediaXmlRpcDelegate(xmlrpc_server.XmlRpcDelegate):
41    """XML RPC delegate for multimedia testing."""
42
43    def __init__(self, resource):
44        """Initializes the facade objects."""
45
46        # TODO: (crbug.com/618111) Add test driven switch for
47        # supporting arc_mode enabled or disabled. At this time
48        # if ARC build is tested, arc_mode is always enabled.
49        arc_res = None
50        if utils.get_board_property('CHROMEOS_ARC_VERSION'):
51            logging.info('Using ARC resource on ARC enabled board.')
52            from autotest_lib.client.cros.multimedia import arc_resource
53            arc_res = arc_resource.ArcResource()
54
55        self._facades = {
56                'assistant':
57                assistant_facade.AssistantFacadeLocal(resource),
58                'audio':
59                audio_facade.AudioFacadeLocal(resource,
60                                                      arc_resource=arc_res),
61                'video':
62                video_facade.VideoFacadeLocal(resource,
63                                                      arc_resource=arc_res),
64                'display':
65                display_facade.DisplayFacadeLocal(resource),
66                'system':
67                system_facade.SystemFacadeLocal(),
68                'usb':
69                usb_facade.USBFacadeLocal(),
70                'browser':
71                browser_facade.BrowserFacadeLocal(resource),
72                'input':
73                input_facade.InputFacadeLocal(),
74                'cfm_main_screen':
75                cfm_facade.CFMFacadeLocal(resource, 'hotrod'),
76                'cfm_mimo_screen':
77                cfm_facade.CFMFacadeLocal(resource, 'control'),
78                'kiosk':
79                kiosk_facade.KioskFacadeLocal(resource),
80                'graphics':
81                graphics_facade.GraphicsFacadeLocal()
82        }
83
84        # Limit some facades to python3
85        if sys.version_info[0] >= 3:
86            self._facades[
87                    'bluetooth'] = bluetooth_facade.BluezFacadeLocal()
88            self._facades['floss'] = bluetooth_facade.FlossFacadeLocal(
89            )
90
91    def __exit__(self, exception, value, traceback):
92        """Clean up the resources."""
93        self._facades['audio'].cleanup()
94
95        if 'floss' in self._facades:
96            self._facades['floss'].cleanup()
97
98    def _dispatch(self, method, params):
99        """Dispatches the method to the proper facade.
100
101        We turn off allow_dotted_names option. The method handles the dot
102        and dispatches the method to the proper native facade, like
103        DisplayFacadeLocal.
104
105        """
106        try:
107            try:
108                if '.' not in method:
109                    func = getattr(self, method)
110                else:
111                    facade_name, method_name = method.split('.', 1)
112                    if facade_name in self._facades:
113                        func = getattr(self._facades[facade_name], method_name)
114                    else:
115                        raise Exception('unknown facade: %s' % facade_name)
116            except AttributeError:
117                raise Exception('method %s not supported' % method)
118
119            logging.info('Dispatching method %s with args %s',
120                         str(func), str(params))
121            return func(*params)
122        except:
123            # TODO(ihf): Try to return meaningful stacktraces from the client.
124            return traceback.format_exc()
125
126
127def config_logging():
128    """Configs logging to be verbose and use console handler."""
129    config = logging_config.LoggingConfig()
130    config.configure_logging(use_console=True, verbose=True)
131
132
133def main():
134    """The main function, to run the XMLRPC server."""
135    parser = argparse.ArgumentParser()
136    parser.add_argument('-d', '--debug', action='store_true', required=False,
137                        help=('create a debug console with a ServerProxy "s" '
138                              'connecting to the XML RPC sever at localhost'))
139    args = parser.parse_args()
140    pid = os.getpid()
141
142    if args.debug:
143        s = six.moves.xmlrpc_client.ServerProxy('http://localhost:%d' %
144                                  constants.MULTIMEDIA_XMLRPC_SERVER_PORT,
145                                  allow_none=True)
146        code.interact(local=locals())
147    else:
148        config_logging()
149        logging.debug('multimedia_xmlrpc_server[%s] main...', pid)
150        xmlrpc_server.terminate_old(__file__)
151
152        # bind before full setup, so the error is the last thing in the log
153        server = xmlrpc_server.XmlRpcServer(
154                'localhost', constants.MULTIMEDIA_XMLRPC_SERVER_PORT)
155
156        # Restart Cras to clean up any audio activities.
157        upstart.restart_job('cras')
158
159        with facade_resource.FacadeResource() as res:
160            server.register_delegate(MultimediaXmlRpcDelegate(res))
161            server.run()
162            logging.debug('multimedia_xmlrpc_server[%s] exiting...', pid)
163        logging.debug('multimedia_xmlrpc_server[%s] done.\n', pid)
164
165
166if __name__ == '__main__':
167    main()
168