xref: /aosp_15_r20/external/autotest/client/cros/networking/apmanager_proxy.py (revision 9c5db1993ded3edbeafc8092d69fe5de2ee02df7)
1# Lint as: python2, python3
2# Copyright 2014 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
6from __future__ import absolute_import
7from __future__ import division
8from __future__ import print_function
9
10import dbus
11import dbus.mainloop.glib
12import six
13import time
14
15from autotest_lib.client.common_lib.cros.network import apmanager_constants
16from autotest_lib.client.cros import dbus_util
17
18
19class ApmanagerProxyError(Exception):
20    """Exceptions raised by ApmanagerProxy and it's children."""
21    pass
22
23
24class ApmanagerProxy(object):
25    """A wrapper around a DBus proxy for apmanager."""
26
27    # Core DBus error names
28    DBUS_ERROR_UNKNOWN_OBJECT = 'org.freedesktop.DBus.Error.UnknownObject'
29    DBUS_ERROR_SERVICE_UNKNOWN = 'org.freedesktop.DBus.Error.ServiceUnknown'
30    DBUS_ERROR_UNKNOWN_METHOD = 'org.freedesktop.DBus.Error.UnknownMethod'
31
32    # apmanager Service and Interface names.
33    DBUS_SERVICE = 'org.chromium.apmanager'
34    DBUS_PROPERTY_INTERFACE = 'org.freedesktop.DBus.Properties'
35    DBUS_CONFIG_INTERFACE = 'org.chromium.apmanager.Config'
36    DBUS_SERVICE_INTERFACE = 'org.chromium.apmanager.Service'
37    DBUS_MANAGER_INTERFACE = 'org.chromium.apmanager.Manager'
38    DBUS_MANAGER_PATH = '/org/chromium/apmanager/Manager'
39
40    # AP Service property keys
41    SERVICE_PROPERTY_CONFIG = 'Config'
42
43    # Mapping for property to dbus type function.
44    CONFIG_PROPERTY_DBUS_TYPE_MAPPING = {
45            apmanager_constants.CONFIG_BRIDGE_INTERFACE: dbus.String,
46            apmanager_constants.CONFIG_CHANNEL: dbus.UInt16,
47            apmanager_constants.CONFIG_HIDDEN_NETWORK: dbus.Boolean,
48            apmanager_constants.CONFIG_HW_MODE: dbus.String,
49            apmanager_constants.CONFIG_INTERFACE_NAME: dbus.String,
50            apmanager_constants.CONFIG_OPERATION_MODE: dbus.String,
51            apmanager_constants.CONFIG_PASSPHRASE: dbus.String,
52            apmanager_constants.CONFIG_SECURITY_MODE: dbus.String,
53            apmanager_constants.CONFIG_SERVER_ADDRESS_INDEX: dbus.UInt16,
54            apmanager_constants.CONFIG_SSID: dbus.String}
55
56    POLLING_INTERVAL_SECONDS = 0.2
57
58
59    def __init__(self, bus=None, timeout_seconds=10):
60        if bus is None:
61            dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
62            bus = dbus.SystemBus()
63        self._bus = bus
64        self._manager = None
65        self._connect_to_dbus(timeout_seconds)
66
67
68    def _connect_to_dbus(self, timeout_seconds):
69        """Connect to apmanager over DBus and initialize the DBus object for
70           org.chromium.apmanager.Manager interface.
71
72        If apmanager is not yet running, retry until it is, or until
73        |timeout_seconds| expires.
74
75        @param timeout_seconds float number of seconds to wait for connecting
76               to apmanager's DBus service.
77
78        """
79        end_time = time.time() + timeout_seconds
80        while self._manager is None and time.time() < end_time:
81            try:
82                self._manager = \
83                        self._get_dbus_object(self.DBUS_MANAGER_INTERFACE,
84                                              self.DBUS_MANAGER_PATH)
85            except dbus.exceptions.DBusException as e:
86                if (e.get_dbus_name() !=
87                    ApmanagerProxy.DBUS_ERROR_SERVICE_UNKNOWN):
88                    raise ApmanagerProxyError('Error connecting to apmanager')
89                else:
90                    # Wait a moment before retrying
91                    time.sleep(ApmanagerProxy.POLLING_INTERVAL_SECONDS)
92        if self._manager is None:
93            raise ApmanagerProxyError('Timeout connecting to apmanager')
94
95
96    def _get_dbus_object(self, interface_name, path):
97        """Return the DBus object of interface |interface_name| at |path| in
98           apmanager DBUS service.
99
100        @param interface_name string (e.g. self.DBUS_SERVICE_INTERFACE).
101        @param path path to object in apmanager (e.g. '/manager/services/1').
102        @return DBus proxy object.
103
104        """
105        return dbus.Interface(
106                self._bus.get_object(self.DBUS_SERVICE, path),
107                interface_name)
108
109
110    def _get_dbus_property(self, dbus_object, interface_name, property_key):
111        """get property on a dbus Interface
112
113        @param dbus_object DBus object to read property from
114        @param interface_name string name of the interface
115        @param property_key string name of property on interface
116        @return python typed object representing property value or None
117
118        """
119        # Get the property interface for the given DBus object.
120        property_interface = self._get_dbus_object(
121                self.DBUS_PROPERTY_INTERFACE,
122                dbus_object.object_path)
123        # Invoke Get method on the property interface.
124        try:
125            value = dbus_util.dbus2primitive(
126                    property_interface.Get(dbus.String(interface_name),
127                                           dbus.String(property_key)));
128        except dbus.exceptions.DBusException as e:
129            raise ApmanagerProxyError(
130                    'Failed to get property %s on interface %s' %
131                    (property_key, interface_name))
132        return value
133
134
135    def _set_dbus_property(self,
136                           dbus_object,
137                           interface_name,
138                           property_key,
139                           value):
140        """set property on a dbus Interface
141
142        @param dbus_object DBus object to set property on
143        @param interface_name string name of the interface
144        @param property_key string name of property on interface
145        @param value dbus_type value to set for property
146
147        """
148        # Get the property interface for the given DBus object.
149        property_interface = self._get_dbus_object(
150                self.DBUS_PROPERTY_INTERFACE,
151                dbus_object.object_path)
152        # Invoke Set method on the property interface.
153        try:
154            property_interface.Set(dbus.String(interface_name),
155                                   dbus.String(property_key),
156                                   value);
157        except dbus.exceptions.DBusException as e:
158            raise ApmanagerProxyError(
159                    'Failed to set property %s on interface %s' %
160                    (property_key, interface_name))
161
162
163    # TODO(zqiu): add more optional parameters for setting additional
164    # service configurations.
165    def start_service(self, config_params):
166        """Create/start an AP service with provided configurations.
167
168        @param config_params dictionary of configuration parameters.
169        @return string object path of the newly created service.
170
171        """
172        service = self._get_dbus_object(
173                self.DBUS_SERVICE_INTERFACE,
174                dbus_util.dbus2primitive(self._manager.CreateService()))
175        # Get configuration object for the service.
176        service_config = self._get_dbus_object(
177                self.DBUS_CONFIG_INTERFACE,
178                self._get_dbus_property(service,
179                                        self.DBUS_SERVICE_INTERFACE,
180                                        self.SERVICE_PROPERTY_CONFIG))
181        # Set configuration properties.
182        for name, value in six.iteritems(config_params):
183            if name in self.CONFIG_PROPERTY_DBUS_TYPE_MAPPING:
184                func = self.CONFIG_PROPERTY_DBUS_TYPE_MAPPING[name]
185                self._set_dbus_property(service_config,
186                                        self.DBUS_CONFIG_INTERFACE,
187                                        name,
188                                        func(value, variant_level=1))
189            else:
190                raise ApmanagerProxyError('Unknown configuration parameter [%s]'
191                                          % name)
192
193        # Start AP service.
194        service.Start()
195        return service.object_path
196
197
198    def terminate_service(self, service_path):
199        """ Terminate and remove the AP service |service|.
200
201        @param service_path string object path of the service.
202
203        """
204        self._manager.RemoveService(dbus.ObjectPath(service_path))
205