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