Christopher Wiley | 1f89fd2 | 2013-12-19 15:02:45 -0800 | [diff] [blame] | 1 | # Copyright (c) 2013 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 collections |
| 6 | import dbus |
| 7 | import dbus.mainloop.glib |
| 8 | import gobject |
Christopher Wiley | 1f89fd2 | 2013-12-19 15:02:45 -0800 | [diff] [blame] | 9 | import time |
| 10 | |
Christopher Wiley | 10fe277 | 2014-10-13 09:21:23 -0700 | [diff] [blame] | 11 | from autotest_lib.client.cros import dbus_util |
| 12 | |
Christopher Wiley | 1f89fd2 | 2013-12-19 15:02:45 -0800 | [diff] [blame] | 13 | |
| 14 | class ShillProxyError(Exception): |
Ben Chan | dd49275 | 2018-01-30 15:53:18 -0800 | [diff] [blame] | 15 | """Exceptions raised by ShillProxy and its children.""" |
Christopher Wiley | 1f89fd2 | 2013-12-19 15:02:45 -0800 | [diff] [blame] | 16 | pass |
| 17 | |
| 18 | |
Ben Chan | dd49275 | 2018-01-30 15:53:18 -0800 | [diff] [blame] | 19 | class ShillProxyTimeoutError(ShillProxyError): |
| 20 | """Timeout exception raised by ShillProxy and its children.""" |
| 21 | def __init__(self, desc): |
| 22 | super(ShillProxyTimeoutError, self).__init__( |
| 23 | 'Timed out waiting for condition %s.' % desc) |
| 24 | |
| 25 | |
Christopher Wiley | 1f89fd2 | 2013-12-19 15:02:45 -0800 | [diff] [blame] | 26 | class ShillProxy(object): |
| 27 | """A wrapper around a DBus proxy for shill.""" |
| 28 | |
| 29 | # Core DBus error names |
| 30 | DBUS_ERROR_UNKNOWN_OBJECT = 'org.freedesktop.DBus.Error.UnknownObject' |
| 31 | # Shill error names |
Thieu Le | 98327a4 | 2014-08-21 18:11:41 -0700 | [diff] [blame] | 32 | ERROR_ALREADY_CONNECTED = 'org.chromium.flimflam.Error.AlreadyConnected' |
Christopher Wiley | 1f89fd2 | 2013-12-19 15:02:45 -0800 | [diff] [blame] | 33 | ERROR_FAILURE = 'org.chromium.flimflam.Error.Failure' |
Thieu Le | 98327a4 | 2014-08-21 18:11:41 -0700 | [diff] [blame] | 34 | ERROR_INCORRECT_PIN = 'org.chromium.flimflam.Error.IncorrectPin' |
Thieu Le | e3b3fcf | 2014-09-08 13:56:15 -0700 | [diff] [blame] | 35 | ERROR_IN_PROGRESS = 'org.chromium.flimflam.Error.InProgress' |
Thieu Le | 98327a4 | 2014-08-21 18:11:41 -0700 | [diff] [blame] | 36 | ERROR_NOT_CONNECTED = 'org.chromium.flimflam.Error.NotConnected' |
| 37 | ERROR_NOT_SUPPORTED = 'org.chromium.flimflam.Error.NotSupported' |
| 38 | ERROR_PIN_BLOCKED = 'org.chromium.flimflam.Error.PinBlocked' |
| 39 | |
Christopher Wiley | 1f89fd2 | 2013-12-19 15:02:45 -0800 | [diff] [blame] | 40 | |
| 41 | DBUS_INTERFACE = 'org.chromium.flimflam' |
| 42 | DBUS_SERVICE_UNKNOWN = 'org.freedesktop.DBus.Error.ServiceUnknown' |
| 43 | DBUS_TYPE_DEVICE = 'org.chromium.flimflam.Device' |
| 44 | DBUS_TYPE_IPCONFIG = 'org.chromium.flimflam.IPConfig' |
| 45 | DBUS_TYPE_MANAGER = 'org.chromium.flimflam.Manager' |
| 46 | DBUS_TYPE_PROFILE = 'org.chromium.flimflam.Profile' |
| 47 | DBUS_TYPE_SERVICE = 'org.chromium.flimflam.Service' |
| 48 | |
| 49 | ENTRY_FIELD_NAME = 'Name' |
Christopher Wiley | 7195702 | 2014-01-08 09:43:38 -0800 | [diff] [blame] | 50 | ENTRY_FIELD_TYPE = 'Type' |
Christopher Wiley | 1f89fd2 | 2013-12-19 15:02:45 -0800 | [diff] [blame] | 51 | |
| 52 | MANAGER_PROPERTY_ACTIVE_PROFILE = 'ActiveProfile' |
| 53 | MANAGER_PROPERTY_DEVICES = 'Devices' |
Thieu Le | 996e0a0 | 2014-09-15 12:36:08 -0700 | [diff] [blame] | 54 | MANAGER_PROPERTY_NO_AUTOCONNECT_TECHNOLOGIES = 'NoAutoConnectTechnologies' |
Ben Chan | b24e46a | 2018-01-18 15:49:53 -0800 | [diff] [blame] | 55 | MANAGER_PROPERTY_ENABLED_TECHNOLOGIES = 'EnabledTechnologies' |
| 56 | MANAGER_PROPERTY_PROHIBITED_TECHNOLOGIES = 'ProhibitedTechnologies' |
Brian Norris | e93b4ba | 2018-01-26 17:10:19 -0800 | [diff] [blame] | 57 | MANAGER_PROPERTY_UNINITIALIZED_TECHNOLOGIES = 'UninitializedTechnologies' |
Christopher Wiley | 1f89fd2 | 2013-12-19 15:02:45 -0800 | [diff] [blame] | 58 | MANAGER_PROPERTY_PROFILES = 'Profiles' |
| 59 | MANAGER_PROPERTY_SERVICES = 'Services' |
Brian Norris | 3a1cb2a | 2019-08-08 13:35:28 -0700 | [diff] [blame] | 60 | MANAGER_PROPERTY_DEFAULT_SERVICE = 'DefaultService' |
Christopher Wiley | 1f89fd2 | 2013-12-19 15:02:45 -0800 | [diff] [blame] | 61 | MANAGER_PROPERTY_ALL_SERVICES = 'ServiceCompleteList' |
Rebecca Silberstein | eea6966 | 2016-03-03 21:39:21 -0800 | [diff] [blame] | 62 | MANAGER_PROPERTY_DHCPPROPERTY_HOSTNAME = 'DHCPProperty.Hostname' |
| 63 | MANAGER_PROPERTY_DHCPPROPERTY_VENDORCLASS = 'DHCPProperty.VendorClass' |
Matthew Wang | 371e0f5 | 2018-11-15 14:45:07 -0800 | [diff] [blame] | 64 | MANAGER_PROPERTY_WIFI_GLOBAL_FT_ENABLED = 'WiFi.GlobalFTEnabled' |
Rebecca Silberstein | eea6966 | 2016-03-03 21:39:21 -0800 | [diff] [blame] | 65 | |
| 66 | MANAGER_OPTIONAL_PROPERTY_MAP = { |
| 67 | MANAGER_PROPERTY_DHCPPROPERTY_HOSTNAME: dbus.String, |
Matthew Wang | 371e0f5 | 2018-11-15 14:45:07 -0800 | [diff] [blame] | 68 | MANAGER_PROPERTY_DHCPPROPERTY_VENDORCLASS: dbus.String, |
| 69 | MANAGER_PROPERTY_WIFI_GLOBAL_FT_ENABLED: dbus.Boolean |
Rebecca Silberstein | eea6966 | 2016-03-03 21:39:21 -0800 | [diff] [blame] | 70 | } |
Christopher Wiley | 1f89fd2 | 2013-12-19 15:02:45 -0800 | [diff] [blame] | 71 | |
| 72 | PROFILE_PROPERTY_ENTRIES = 'Entries' |
| 73 | PROFILE_PROPERTY_NAME = 'Name' |
| 74 | |
| 75 | OBJECT_TYPE_PROPERTY_MAP = { |
| 76 | 'Device': ( DBUS_TYPE_DEVICE, MANAGER_PROPERTY_DEVICES ), |
| 77 | 'Profile': ( DBUS_TYPE_PROFILE, MANAGER_PROPERTY_PROFILES ), |
| 78 | 'Service': ( DBUS_TYPE_SERVICE, MANAGER_PROPERTY_SERVICES ), |
| 79 | 'AnyService': ( DBUS_TYPE_SERVICE, MANAGER_PROPERTY_ALL_SERVICES ) |
| 80 | } |
| 81 | |
Ben Chan | 927c9b0 | 2018-01-30 14:47:28 -0800 | [diff] [blame] | 82 | DEVICE_ENUMERATION_TIMEOUT = 30 |
Thieu Le | e3b3fcf | 2014-09-08 13:56:15 -0700 | [diff] [blame] | 83 | DEVICE_ENABLE_DISABLE_TIMEOUT = 60 |
Christopher Wiley | 1f89fd2 | 2013-12-19 15:02:45 -0800 | [diff] [blame] | 84 | SERVICE_DISCONNECT_TIMEOUT = 5 |
| 85 | |
| 86 | SERVICE_PROPERTY_AUTOCONNECT = 'AutoConnect' |
| 87 | SERVICE_PROPERTY_DEVICE = 'Device' |
| 88 | SERVICE_PROPERTY_GUID = 'GUID' |
| 89 | SERVICE_PROPERTY_HEX_SSID = 'WiFi.HexSSID' |
| 90 | SERVICE_PROPERTY_HIDDEN = 'WiFi.HiddenSSID' |
| 91 | SERVICE_PROPERTY_MODE = 'Mode' |
| 92 | SERVICE_PROPERTY_NAME = 'Name' |
| 93 | SERVICE_PROPERTY_PASSPHRASE = 'Passphrase' |
| 94 | SERVICE_PROPERTY_PROFILE = 'Profile' |
| 95 | SERVICE_PROPERTY_SAVE_CREDENTIALS = 'SaveCredentials' |
Matthew Wang | 1667e5c | 2018-02-27 17:32:59 -0800 | [diff] [blame] | 96 | SERVICE_PROPERTY_FT_ENABLED = 'WiFi.FTEnabled' |
mukesh agrawal | 9fe0e25 | 2014-12-12 17:45:38 -0800 | [diff] [blame] | 97 | # Unless you really care whether a network is WPA (TSN) vs. WPA-2 |
| 98 | # (RSN), you should use SERVICE_PROPERTY_SECURITY_CLASS. |
| 99 | SERVICE_PROPERTY_SECURITY_RAW = 'Security' |
| 100 | SERVICE_PROPERTY_SECURITY_CLASS = 'SecurityClass' |
Christopher Wiley | 1f89fd2 | 2013-12-19 15:02:45 -0800 | [diff] [blame] | 101 | SERVICE_PROPERTY_SSID = 'SSID' |
| 102 | SERVICE_PROPERTY_STRENGTH = 'Strength' |
| 103 | SERVICE_PROPERTY_STATE = 'State' |
Alex Khouderchah | c742410 | 2019-08-06 14:34:57 -0700 | [diff] [blame] | 104 | SERVICE_PROPERTY_STATIC_IP_CONFIG = 'StaticIPConfig' |
Christopher Wiley | 1f89fd2 | 2013-12-19 15:02:45 -0800 | [diff] [blame] | 105 | SERVICE_PROPERTY_TYPE = 'Type' |
| 106 | |
Peter Qiu | af68323 | 2015-08-11 16:47:57 -0700 | [diff] [blame] | 107 | # EAP related properties. |
| 108 | SERVICE_PROPERTY_EAP_EAP = 'EAP.EAP' |
| 109 | SERVICE_PROPERTY_EAP_INNER_EAP = 'EAP.InnerEAP' |
| 110 | SERVICE_PROPERTY_EAP_IDENTITY = 'EAP.Identity' |
| 111 | SERVICE_PROPERTY_EAP_PASSWORD = 'EAP.Password' |
| 112 | SERVICE_PROPERTY_EAP_CA_CERT_PEM = 'EAP.CACertPEM' |
Matthew Wang | 1667e5c | 2018-02-27 17:32:59 -0800 | [diff] [blame] | 113 | SERVICE_PROPERTY_CLIENT_CERT_ID = 'EAP.CertID' |
| 114 | SERVICE_PROPERTY_EAP_KEY_MGMT = 'EAP.KeyMgmt' |
| 115 | SERVICE_PROPERTY_EAP_PIN = 'EAP.PIN' |
| 116 | SERVICE_PROPERTY_PRIVATE_KEY_ID = 'EAP.KeyID' |
| 117 | SERVICE_PROPERTY_USE_SYSTEM_CAS = 'EAP.UseSystemCAs' |
Peter Qiu | af68323 | 2015-08-11 16:47:57 -0700 | [diff] [blame] | 118 | |
Ningyuan Wang | c326ddf | 2015-09-22 16:03:40 -0700 | [diff] [blame] | 119 | # OpenVPN related properties. |
| 120 | SERVICE_PROPERTY_OPENVPN_CA_CERT_PEM = 'OpenVPN.CACertPEM' |
| 121 | SERVICE_PROPERTY_OPENVPN_PASSWORD = 'OpenVPN.Password' |
| 122 | SERVICE_PROPERTY_OPENVPN_PKCS11_ID = 'OpenVPN.Pkcs11.ID' |
| 123 | SERVICE_PROPERTY_OPENVPN_PKCS11_PIN = 'OpenVPN.Pkcs11.PIN' |
| 124 | SERVICE_PROPERTY_OPENVPN_PROVIDER_HOST = 'Provider.Host' |
| 125 | SERVICE_PROPERTY_OPENVPN_PROVIDER_TYPE = 'Provider.Type' |
| 126 | SERVICE_PROPERTY_OPENVPN_REMOTE_CERT_EKU = 'OpenVPN.RemoteCertEKU' |
| 127 | SERVICE_PROPERTY_OPENVPN_USER = 'OpenVPN.User' |
| 128 | SERVICE_PROPERTY_OPENVPN_VERB = 'OpenVPN.Verb' |
| 129 | SERVICE_PROPERTY_OPENVPN_VERIFY_HASH = 'OpenVPN.VerifyHash' |
| 130 | SERVICE_PROPERTY_OPENVPN_VERIFY_X509_NAME = 'OpenVPN.VerifyX509Name' |
| 131 | SERVICE_PROPERTY_OPENVPN_VERIFY_X509_TYPE = 'OpenVPN.VerifyX509Type' |
Ningyuan Wang | c326ddf | 2015-09-22 16:03:40 -0700 | [diff] [blame] | 132 | |
| 133 | # L2TP VPN related properties. |
| 134 | SERVICE_PROPERTY_L2TP_CA_CERT_PEM = 'L2TPIPsec.CACertPEM' |
| 135 | SERVICE_PROPERTY_L2TP_CLIENT_CERT_ID = 'L2TPIPsec.ClientCertID' |
| 136 | SERVICE_PROPERTY_L2TP_CLIENT_CERT_SLOT = 'L2TPIPsec.ClientCertSlot' |
| 137 | SERVICE_PROPERTY_L2TP_PASSWORD = 'L2TPIPsec.Password' |
| 138 | SERVICE_PROPERTY_L2TP_PIN = 'L2TPIPsec.PIN' |
| 139 | SERVICE_PROPERTY_L2TP_PSK = 'L2TPIPsec.PSK' |
| 140 | SERVICE_PROPERTY_L2TP_USER = 'L2TPIPsec.User' |
| 141 | SERVICE_PROPERTY_L2TP_XAUTH_PASSWORD = 'L2TPIPsec.XauthPassword' |
| 142 | SERVICE_PROPERTY_L2TP_XAUTH_USER = 'L2TPIPsec.XauthUser' |
| 143 | |
Alex Khouderchah | c742410 | 2019-08-06 14:34:57 -0700 | [diff] [blame] | 144 | # Mapping of service property to (dbus-type, additional kwargs). |
Peter Qiu | af68323 | 2015-08-11 16:47:57 -0700 | [diff] [blame] | 145 | SERVICE_PROPERTY_MAP = { |
Alex Khouderchah | c742410 | 2019-08-06 14:34:57 -0700 | [diff] [blame] | 146 | SERVICE_PROPERTY_AUTOCONNECT: (dbus.Boolean, {}), |
| 147 | SERVICE_PROPERTY_DEVICE: (dbus.ObjectPath, {}), |
| 148 | SERVICE_PROPERTY_GUID: (dbus.String, {}), |
| 149 | SERVICE_PROPERTY_HEX_SSID: (dbus.String, {}), |
| 150 | SERVICE_PROPERTY_HIDDEN: (dbus.Boolean, {}), |
| 151 | SERVICE_PROPERTY_MODE: (dbus.String, {}), |
| 152 | SERVICE_PROPERTY_NAME: (dbus.String, {}), |
| 153 | SERVICE_PROPERTY_PASSPHRASE: (dbus.String, {}), |
| 154 | SERVICE_PROPERTY_PROFILE: (dbus.ObjectPath, {}), |
| 155 | SERVICE_PROPERTY_SAVE_CREDENTIALS: (dbus.Boolean, {}), |
| 156 | SERVICE_PROPERTY_SECURITY_RAW: (dbus.String, {}), |
| 157 | SERVICE_PROPERTY_SECURITY_CLASS: (dbus.String, {}), |
| 158 | SERVICE_PROPERTY_SSID: (dbus.String, {}), |
| 159 | SERVICE_PROPERTY_STRENGTH: (dbus.Byte, {}), |
| 160 | SERVICE_PROPERTY_STATE: (dbus.String, {}), |
| 161 | SERVICE_PROPERTY_TYPE: (dbus.String, {}), |
| 162 | SERVICE_PROPERTY_FT_ENABLED: (dbus.Boolean, {}), |
| 163 | SERVICE_PROPERTY_STATIC_IP_CONFIG: (dbus.Dictionary, |
| 164 | {'signature' : 'sv'}), |
Peter Qiu | af68323 | 2015-08-11 16:47:57 -0700 | [diff] [blame] | 165 | |
Alex Khouderchah | c742410 | 2019-08-06 14:34:57 -0700 | [diff] [blame] | 166 | SERVICE_PROPERTY_EAP_EAP: (dbus.String, {}), |
| 167 | SERVICE_PROPERTY_EAP_INNER_EAP: (dbus.String, {}), |
| 168 | SERVICE_PROPERTY_EAP_IDENTITY: (dbus.String, {}), |
| 169 | SERVICE_PROPERTY_EAP_PASSWORD: (dbus.String, {}), |
| 170 | SERVICE_PROPERTY_EAP_CA_CERT_PEM: (dbus.Array, {}), |
| 171 | SERVICE_PROPERTY_CLIENT_CERT_ID: (dbus.String, {}), |
| 172 | SERVICE_PROPERTY_EAP_KEY_MGMT: (dbus.String, {}), |
| 173 | SERVICE_PROPERTY_EAP_PIN: (dbus.String, {}), |
| 174 | SERVICE_PROPERTY_PRIVATE_KEY_ID: (dbus.String, {}), |
| 175 | SERVICE_PROPERTY_USE_SYSTEM_CAS: (dbus.Boolean, {}), |
Ningyuan Wang | c326ddf | 2015-09-22 16:03:40 -0700 | [diff] [blame] | 176 | |
Alex Khouderchah | c742410 | 2019-08-06 14:34:57 -0700 | [diff] [blame] | 177 | SERVICE_PROPERTY_OPENVPN_CA_CERT_PEM: (dbus.Array, {}), |
| 178 | SERVICE_PROPERTY_OPENVPN_PASSWORD: (dbus.String, {}), |
| 179 | SERVICE_PROPERTY_OPENVPN_PKCS11_ID: (dbus.String, {}), |
| 180 | SERVICE_PROPERTY_OPENVPN_PKCS11_PIN: (dbus.String, {}), |
| 181 | SERVICE_PROPERTY_OPENVPN_PROVIDER_HOST: (dbus.String, {}), |
| 182 | SERVICE_PROPERTY_OPENVPN_PROVIDER_TYPE: (dbus.String, {}), |
| 183 | SERVICE_PROPERTY_OPENVPN_REMOTE_CERT_EKU: (dbus.String, {}), |
| 184 | SERVICE_PROPERTY_OPENVPN_USER: (dbus.String, {}), |
| 185 | SERVICE_PROPERTY_OPENVPN_VERB: (dbus.String, {}), |
| 186 | SERVICE_PROPERTY_OPENVPN_VERIFY_HASH: (dbus.String, {}), |
| 187 | SERVICE_PROPERTY_OPENVPN_VERIFY_X509_NAME: (dbus.String, {}), |
| 188 | SERVICE_PROPERTY_OPENVPN_VERIFY_X509_TYPE: (dbus.String, {}), |
Ningyuan Wang | c326ddf | 2015-09-22 16:03:40 -0700 | [diff] [blame] | 189 | |
Alex Khouderchah | c742410 | 2019-08-06 14:34:57 -0700 | [diff] [blame] | 190 | SERVICE_PROPERTY_L2TP_CA_CERT_PEM: (dbus.Array, {}), |
| 191 | SERVICE_PROPERTY_L2TP_CLIENT_CERT_ID: (dbus.String, {}), |
| 192 | SERVICE_PROPERTY_L2TP_CLIENT_CERT_SLOT: (dbus.String, {}), |
| 193 | SERVICE_PROPERTY_L2TP_PASSWORD: (dbus.String, {}), |
| 194 | SERVICE_PROPERTY_L2TP_PIN: (dbus.String, {}), |
| 195 | SERVICE_PROPERTY_L2TP_PSK: (dbus.String, {}), |
| 196 | SERVICE_PROPERTY_L2TP_USER: (dbus.String, {}), |
| 197 | SERVICE_PROPERTY_L2TP_XAUTH_PASSWORD: (dbus.String, {}), |
| 198 | SERVICE_PROPERTY_L2TP_XAUTH_USER: (dbus.String, {}) |
Peter Qiu | af68323 | 2015-08-11 16:47:57 -0700 | [diff] [blame] | 199 | } |
| 200 | |
Brian Norris | 3380b22 | 2019-05-23 14:04:12 -0700 | [diff] [blame] | 201 | SERVICE_CONNECTED_STATES = ['portal', 'no-connectivity', 'redirect-found', |
| 202 | 'portal-suspected', 'online', 'ready'] |
Christopher Wiley | 1f89fd2 | 2013-12-19 15:02:45 -0800 | [diff] [blame] | 203 | SUPPORTED_WIFI_STATION_TYPES = {'managed': 'managed', |
| 204 | 'ibss': 'adhoc', |
| 205 | None: 'managed'} |
| 206 | |
| 207 | DEVICE_PROPERTY_ADDRESS = 'Address' |
| 208 | DEVICE_PROPERTY_EAP_AUTHENTICATION_COMPLETED = 'EapAuthenticationCompleted' |
| 209 | DEVICE_PROPERTY_EAP_AUTHENTICATOR_DETECTED = 'EapAuthenticatorDetected' |
| 210 | DEVICE_PROPERTY_IP_CONFIG = 'IpConfig' |
| 211 | DEVICE_PROPERTY_INTERFACE = 'Interface' |
| 212 | DEVICE_PROPERTY_NAME = 'Name' |
| 213 | DEVICE_PROPERTY_POWERED = 'Powered' |
| 214 | DEVICE_PROPERTY_RECEIVE_BYTE_COUNT = 'ReceiveByteCount' |
| 215 | DEVICE_PROPERTY_SCANNING = 'Scanning' |
| 216 | DEVICE_PROPERTY_TRANSMIT_BYTE_COUNT = 'TransmitByteCount' |
| 217 | DEVICE_PROPERTY_TYPE = 'Type' |
| 218 | |
| 219 | TECHNOLOGY_CELLULAR = 'cellular' |
| 220 | TECHNOLOGY_ETHERNET = 'ethernet' |
| 221 | TECHNOLOGY_VPN = 'vpn' |
| 222 | TECHNOLOGY_WIFI = 'wifi' |
Christopher Wiley | 1f89fd2 | 2013-12-19 15:02:45 -0800 | [diff] [blame] | 223 | |
Thieu Le | 75f8368 | 2014-09-23 18:03:14 -0700 | [diff] [blame] | 224 | VALUE_POWERED_ON = True |
| 225 | VALUE_POWERED_OFF = False |
Christopher Wiley | 1f89fd2 | 2013-12-19 15:02:45 -0800 | [diff] [blame] | 226 | |
| 227 | POLLING_INTERVAL_SECONDS = 0.2 |
| 228 | |
| 229 | # Default log level used in connectivity tests. |
| 230 | LOG_LEVEL_FOR_TEST = -4 |
| 231 | |
| 232 | # Default log scopes used in connectivity tests. |
| 233 | LOG_SCOPES_FOR_TEST_COMMON = [ |
| 234 | 'connection', |
| 235 | 'dbus', |
| 236 | 'device', |
| 237 | 'link', |
| 238 | 'manager', |
| 239 | 'portal', |
| 240 | 'service' |
| 241 | ] |
| 242 | |
| 243 | # Default log scopes used in connectivity tests for specific technologies. |
| 244 | LOG_SCOPES_FOR_TEST = { |
| 245 | TECHNOLOGY_CELLULAR: LOG_SCOPES_FOR_TEST_COMMON + ['cellular'], |
| 246 | TECHNOLOGY_ETHERNET: LOG_SCOPES_FOR_TEST_COMMON + ['ethernet'], |
| 247 | TECHNOLOGY_VPN: LOG_SCOPES_FOR_TEST_COMMON + ['vpn'], |
| 248 | TECHNOLOGY_WIFI: LOG_SCOPES_FOR_TEST_COMMON + ['wifi'], |
Christopher Wiley | 1f89fd2 | 2013-12-19 15:02:45 -0800 | [diff] [blame] | 249 | } |
| 250 | |
| 251 | UNKNOWN_METHOD = 'org.freedesktop.DBus.Error.UnknownMethod' |
| 252 | |
| 253 | |
| 254 | @staticmethod |
| 255 | def str2dbus(dbus_class, value): |
| 256 | """Typecast string property values to dbus types. |
| 257 | |
| 258 | This mostly makes it easy to special case Boolean constructors |
| 259 | to interpret strings like 'false' and '0' as False. |
| 260 | |
| 261 | @param dbus_class: DBus class object. |
| 262 | @param value: value to pass to constructor. |
| 263 | |
| 264 | """ |
| 265 | if isinstance(dbus_class, dbus.Boolean): |
| 266 | return dbus_class(value.lower() in ('true','1')) |
| 267 | else: |
| 268 | return dbus_class(value) |
| 269 | |
| 270 | |
Peter Qiu | af68323 | 2015-08-11 16:47:57 -0700 | [diff] [blame] | 271 | @staticmethod |
| 272 | def service_properties_to_dbus_types(in_dict): |
| 273 | """Convert service properties to dbus types. |
| 274 | |
| 275 | @param in_dict: Dictionary containing service properties. |
| 276 | @return DBus variant dictionary containing service properties. |
| 277 | |
| 278 | """ |
| 279 | dbus_dict = {} |
| 280 | for key, value in in_dict.iteritems(): |
| 281 | if key not in ShillProxy.SERVICE_PROPERTY_MAP: |
| 282 | raise ShillProxyError('Unsupported property %s' % (key)) |
Alex Khouderchah | c742410 | 2019-08-06 14:34:57 -0700 | [diff] [blame] | 283 | (dbus_type, kwargs) = ShillProxy.SERVICE_PROPERTY_MAP[key] |
| 284 | dbus_dict[key] = dbus_type(value, variant_level=1, **kwargs) |
Peter Qiu | af68323 | 2015-08-11 16:47:57 -0700 | [diff] [blame] | 285 | return dbus_dict |
| 286 | |
| 287 | |
Christopher Wiley | 1f89fd2 | 2013-12-19 15:02:45 -0800 | [diff] [blame] | 288 | @classmethod |
| 289 | def dbus2primitive(cls, value): |
| 290 | """Typecast values from dbus types to python types. |
| 291 | |
| 292 | @param value: dbus object to convert to a primitive. |
| 293 | |
| 294 | """ |
Christopher Wiley | 10fe277 | 2014-10-13 09:21:23 -0700 | [diff] [blame] | 295 | return dbus_util.dbus2primitive(value) |
Christopher Wiley | 1f89fd2 | 2013-12-19 15:02:45 -0800 | [diff] [blame] | 296 | |
| 297 | |
| 298 | @staticmethod |
| 299 | def get_dbus_property(interface, property_key): |
| 300 | """get property on a dbus Interface |
| 301 | |
| 302 | @param interface dbus Interface to receive new setting |
| 303 | @param property_key string name of property on interface |
| 304 | @return python typed object representing property value or None |
| 305 | |
| 306 | """ |
| 307 | properties = interface.GetProperties(utf8_strings=True) |
| 308 | if property_key in properties: |
| 309 | return ShillProxy.dbus2primitive(properties[property_key]) |
| 310 | else: |
| 311 | return None |
| 312 | |
| 313 | |
| 314 | @staticmethod |
| 315 | def set_dbus_property(interface, property_key, value): |
| 316 | """set property on a dbus Interface |
| 317 | |
| 318 | @param interface dbus Interface to receive new setting |
| 319 | @param property_key string name of property on interface |
| 320 | @param value string value to set for property on interface from string |
| 321 | |
| 322 | """ |
| 323 | properties = interface.GetProperties(utf8_strings=True) |
| 324 | if property_key not in properties: |
| 325 | raise ShillProxyError('No property %s found in %s' % |
| 326 | (property_key, interface.object_path)) |
| 327 | else: |
| 328 | dbus_class = properties[property_key].__class__ |
| 329 | interface.SetProperty(property_key, |
| 330 | ShillProxy.str2dbus(dbus_class, value)) |
| 331 | |
| 332 | |
Rebecca Silberstein | eea6966 | 2016-03-03 21:39:21 -0800 | [diff] [blame] | 333 | @staticmethod |
| 334 | def set_optional_dbus_property(interface, property_key, value): |
| 335 | """set an optional property on a dbus Interface. |
| 336 | |
| 337 | This method can be used for properties that are optionally listed |
| 338 | in the profile. It skips the initial check of the property |
| 339 | being in the interface.GetProperties list. |
| 340 | |
| 341 | @param interface dbus Interface to receive new setting |
| 342 | @param property_key string name of property on interface |
| 343 | @param value string value to set for property on interface from string |
| 344 | |
| 345 | """ |
| 346 | if property_key not in ShillProxy.MANAGER_OPTIONAL_PROPERTY_MAP: |
| 347 | raise ShillProxyError('Unsupported property %s' % |
| 348 | (property_key)) |
| 349 | else: |
| 350 | dbus_class = ShillProxy.MANAGER_OPTIONAL_PROPERTY_MAP[property_key] |
| 351 | interface.SetProperty(property_key, |
| 352 | ShillProxy.str2dbus(dbus_class, value)) |
| 353 | |
| 354 | |
Christopher Wiley | 1f89fd2 | 2013-12-19 15:02:45 -0800 | [diff] [blame] | 355 | @classmethod |
Thieu Le | 16f7eeb | 2014-08-26 18:31:17 -0700 | [diff] [blame] | 356 | def get_proxy(cls, bus=None, timeout_seconds=10): |
Christopher Wiley | 1f89fd2 | 2013-12-19 15:02:45 -0800 | [diff] [blame] | 357 | """Create a Proxy, retrying if necessary. |
| 358 | |
| 359 | This method creates a proxy object of the required subclass of |
| 360 | ShillProxy. A call to SomeSubclassOfShillProxy.get_proxy() will return |
| 361 | an object of type SomeSubclassOfShillProxy. |
| 362 | |
| 363 | Connects to shill over D-Bus. If shill is not yet running, |
| 364 | retry until it is, or until |timeout_seconds| expires. |
| 365 | |
| 366 | After connecting to shill, this method will verify that shill |
| 367 | is answering RPCs. No timeout is applied to the test RPC, so |
| 368 | this method _may_ block indefinitely. |
| 369 | |
Thieu Le | 16f7eeb | 2014-08-26 18:31:17 -0700 | [diff] [blame] | 370 | @param bus D-Bus bus to use, or specify None and this object will |
| 371 | create a mainloop and bus. |
Christopher Wiley | 1f89fd2 | 2013-12-19 15:02:45 -0800 | [diff] [blame] | 372 | @param timeout_seconds float number of seconds to try connecting |
| 373 | A value <= 0 will cause the method to return immediately, |
| 374 | without trying to connect. |
| 375 | @return a ShillProxy instance if we connected, or None otherwise |
| 376 | |
| 377 | """ |
| 378 | end_time = time.time() + timeout_seconds |
| 379 | connection = None |
| 380 | while connection is None and time.time() < end_time: |
| 381 | try: |
| 382 | # We create instance of class on which this classmethod was |
| 383 | # called. This way, calling SubclassOfShillProxy.get_proxy() |
| 384 | # will get a proxy of the right type. |
Thieu Le | 16f7eeb | 2014-08-26 18:31:17 -0700 | [diff] [blame] | 385 | connection = cls(bus=bus) |
Christopher Wiley | 1f89fd2 | 2013-12-19 15:02:45 -0800 | [diff] [blame] | 386 | except dbus.exceptions.DBusException as e: |
| 387 | if e.get_dbus_name() != ShillProxy.DBUS_SERVICE_UNKNOWN: |
| 388 | raise ShillProxyError('Error connecting to shill') |
| 389 | else: |
| 390 | # Wait a moment before retrying |
| 391 | time.sleep(ShillProxy.POLLING_INTERVAL_SECONDS) |
| 392 | |
| 393 | if connection is None: |
| 394 | return None |
| 395 | |
| 396 | # Although shill is connected to D-Bus at this point, it may |
| 397 | # not have completed initialization just yet. Call into shill, |
| 398 | # and wait for the response, to make sure that it is truly up |
| 399 | # and running. (Shill will not service D-Bus requests until |
| 400 | # initialization is complete.) |
| 401 | connection.get_profiles() |
| 402 | return connection |
| 403 | |
| 404 | |
| 405 | def __init__(self, bus=None): |
| 406 | if bus is None: |
| 407 | dbus.mainloop.glib.DBusGMainLoop(set_as_default=True) |
| 408 | bus = dbus.SystemBus() |
| 409 | self._bus = bus |
| 410 | self._manager = self.get_dbus_object(self.DBUS_TYPE_MANAGER, '/') |
| 411 | |
| 412 | |
| 413 | def configure_service_by_guid(self, guid, properties={}): |
| 414 | """Configure a service identified by its GUID. |
| 415 | |
| 416 | @param guid string unique identifier of service. |
| 417 | @param properties dictionary of service property:value pairs. |
| 418 | |
| 419 | """ |
| 420 | config = properties.copy() |
| 421 | config[self.SERVICE_PROPERTY_GUID] = guid |
Peter Qiu | af68323 | 2015-08-11 16:47:57 -0700 | [diff] [blame] | 422 | self.configure_service(config) |
| 423 | |
| 424 | |
| 425 | def configure_service(self, config): |
| 426 | """Configure a service with given properties. |
| 427 | |
| 428 | @param config dictionary of service property:value pairs. |
Alex Khouderchah | e385f2a | 2020-02-04 12:13:59 -0800 | [diff] [blame^] | 429 | @return DBus object interface representing configured Service. |
Peter Qiu | af68323 | 2015-08-11 16:47:57 -0700 | [diff] [blame] | 430 | |
| 431 | """ |
| 432 | # Convert configuration values to dbus variant typed values. |
| 433 | dbus_config = ShillProxy.service_properties_to_dbus_types(config) |
Alex Khouderchah | e385f2a | 2020-02-04 12:13:59 -0800 | [diff] [blame^] | 434 | path = self.manager.ConfigureService(dbus_config) |
| 435 | return self.get_dbus_object(self.DBUS_TYPE_SERVICE, path) |
Christopher Wiley | 1f89fd2 | 2013-12-19 15:02:45 -0800 | [diff] [blame] | 436 | |
| 437 | |
Matthew Wang | ac6bbe9 | 2019-02-13 18:25:49 -0800 | [diff] [blame] | 438 | def configure_service_for_profile(self, path, config): |
| 439 | """Configure a service in the given profile with given properties. |
| 440 | |
| 441 | @param path string path of profile for which service should be |
| 442 | configured. |
| 443 | @param config dictionary of service property:value pairs. |
| 444 | |
| 445 | """ |
| 446 | # Convert configuration values to dbus variant typed values. |
| 447 | dbus_config = ShillProxy.service_properties_to_dbus_types(config) |
| 448 | self.manager.ConfigureServiceForProfile(dbus.ObjectPath(path), |
| 449 | dbus_config) |
| 450 | |
| 451 | |
Christopher Wiley | 1f89fd2 | 2013-12-19 15:02:45 -0800 | [diff] [blame] | 452 | def set_logging(self, level, scopes): |
| 453 | """Set the logging in shill to the specified |level| and |scopes|. |
| 454 | |
| 455 | @param level int log level to set to in shill. |
| 456 | @param scopes list of strings of log scopes to set to in shill. |
| 457 | |
| 458 | """ |
| 459 | self.manager.SetDebugLevel(level) |
| 460 | self.manager.SetDebugTags('+'.join(scopes)) |
| 461 | |
| 462 | |
| 463 | def set_logging_for_test(self, technology): |
| 464 | """Set the logging in shill for a test of the specified |technology|. |
| 465 | |
| 466 | Set the log level to |LOG_LEVEL_FOR_TEST| and the log scopes to the |
| 467 | ones defined in |LOG_SCOPES_FOR_TEST| for |technology|. If |technology| |
| 468 | is not found in |LOG_SCOPES_FOR_TEST|, the log scopes are set to |
| 469 | |LOG_SCOPES_FOR_TEST_COMMON|. |
| 470 | |
| 471 | @param technology string representing the technology type of a test |
| 472 | that the logging in shill is to be customized for. |
| 473 | |
| 474 | """ |
| 475 | scopes = self.LOG_SCOPES_FOR_TEST.get(technology, |
| 476 | self.LOG_SCOPES_FOR_TEST_COMMON) |
| 477 | self.set_logging(self.LOG_LEVEL_FOR_TEST, scopes) |
| 478 | |
| 479 | |
| 480 | def wait_for_property_in(self, dbus_object, property_name, |
| 481 | expected_values, timeout_seconds): |
| 482 | """Wait till a property is in a list of expected values. |
| 483 | |
| 484 | Block until the property |property_name| in |dbus_object| is in |
| 485 | |expected_values|, or |timeout_seconds|. |
| 486 | |
| 487 | @param dbus_object DBus proxy object as returned by |
| 488 | self.get_dbus_object. |
| 489 | @param property_name string property key in dbus_object. |
| 490 | @param expected_values iterable set of values to return successfully |
| 491 | upon seeing. |
| 492 | @param timeout_seconds float number of seconds to return if we haven't |
| 493 | seen the appropriate property value in time. |
| 494 | @return tuple(successful, final_value, duration) |
| 495 | where successful is True iff we saw one of |expected_values| for |
| 496 | |property_name|, final_value is the member of |expected_values| we |
| 497 | saw, and duration is how long we waited to see that value. |
| 498 | |
| 499 | """ |
| 500 | start_time = time.time() |
| 501 | duration = lambda: time.time() - start_time |
Christopher Wiley | 1f89fd2 | 2013-12-19 15:02:45 -0800 | [diff] [blame] | 502 | |
| 503 | update_queue = collections.deque() |
| 504 | signal_receiver = lambda key, value: update_queue.append((key, value)) |
| 505 | receiver_ref = self._bus.add_signal_receiver( |
| 506 | signal_receiver, |
| 507 | signal_name='PropertyChanged', |
| 508 | dbus_interface=dbus_object.dbus_interface, |
| 509 | path=dbus_object.object_path) |
Christopher Wiley | 1f89fd2 | 2013-12-19 15:02:45 -0800 | [diff] [blame] | 510 | try: |
Thieu Le | c28759c | 2014-03-13 13:16:02 -0700 | [diff] [blame] | 511 | # Check to make sure we're not already in a target state. |
| 512 | try: |
| 513 | properties = self.dbus2primitive( |
| 514 | dbus_object.GetProperties(utf8_strings=True)) |
| 515 | last_value = properties.get(property_name, '(no value found)') |
| 516 | if last_value in expected_values: |
| 517 | return True, last_value, duration() |
| 518 | |
| 519 | except dbus.exceptions.DBusException: |
| 520 | return False, '(object reference became invalid)', duration() |
| 521 | |
| 522 | context = gobject.MainLoop().get_context() |
Christopher Wiley | 1f89fd2 | 2013-12-19 15:02:45 -0800 | [diff] [blame] | 523 | while duration() < timeout_seconds: |
Thieu Le | 2da53e2 | 2014-09-24 12:51:19 -0700 | [diff] [blame] | 524 | # Dispatch all pending events. |
Christopher Wiley | 1f89fd2 | 2013-12-19 15:02:45 -0800 | [diff] [blame] | 525 | while context.iteration(False): |
Thieu Le | 2da53e2 | 2014-09-24 12:51:19 -0700 | [diff] [blame] | 526 | pass |
Christopher Wiley | 1f89fd2 | 2013-12-19 15:02:45 -0800 | [diff] [blame] | 527 | |
| 528 | while update_queue: |
Thieu Le | 37c4d7d | 2014-09-08 18:00:01 -0700 | [diff] [blame] | 529 | updated_property, value = map(self.dbus2primitive, |
| 530 | update_queue.popleft()) |
Christopher Wiley | 1f89fd2 | 2013-12-19 15:02:45 -0800 | [diff] [blame] | 531 | if property_name != updated_property: |
| 532 | continue |
| 533 | |
Thieu Le | 37c4d7d | 2014-09-08 18:00:01 -0700 | [diff] [blame] | 534 | last_value = value |
Christopher Wiley | 1f89fd2 | 2013-12-19 15:02:45 -0800 | [diff] [blame] | 535 | if not last_value in expected_values: |
| 536 | continue |
| 537 | |
| 538 | return True, last_value, duration() |
| 539 | |
| 540 | time.sleep(0.2) # Give that CPU a break. CPUs love breaks. |
| 541 | finally: |
| 542 | receiver_ref.remove() |
| 543 | |
| 544 | return False, last_value, duration() |
| 545 | |
| 546 | |
| 547 | @property |
| 548 | def manager(self): |
| 549 | """ @return DBus proxy object representing the shill Manager. """ |
| 550 | return self._manager |
| 551 | |
| 552 | |
| 553 | def get_active_profile(self): |
| 554 | """Get the active profile in shill. |
| 555 | |
| 556 | @return dbus object representing the active profile. |
| 557 | |
| 558 | """ |
| 559 | properties = self.manager.GetProperties(utf8_strings=True) |
| 560 | return self.get_dbus_object( |
| 561 | self.DBUS_TYPE_PROFILE, |
| 562 | properties[self.MANAGER_PROPERTY_ACTIVE_PROFILE]) |
| 563 | |
| 564 | |
| 565 | def get_dbus_object(self, type_str, path): |
| 566 | """Return the DBus object of type |type_str| at |path| in shill. |
| 567 | |
| 568 | @param type_str string (e.g. self.DBUS_TYPE_SERVICE). |
| 569 | @param path path to object in shill (e.g. '/service/12'). |
| 570 | @return DBus proxy object. |
| 571 | |
| 572 | """ |
| 573 | return dbus.Interface( |
Eric Caruso | 3e49371 | 2019-09-06 15:58:54 -0700 | [diff] [blame] | 574 | self._bus.get_object(self.DBUS_INTERFACE, path, |
| 575 | introspect=False), |
Christopher Wiley | 1f89fd2 | 2013-12-19 15:02:45 -0800 | [diff] [blame] | 576 | type_str) |
| 577 | |
| 578 | |
| 579 | def get_devices(self): |
| 580 | """Return the list of devices as dbus Interface objects""" |
| 581 | properties = self.manager.GetProperties(utf8_strings=True) |
| 582 | return [self.get_dbus_object(self.DBUS_TYPE_DEVICE, path) |
| 583 | for path in properties[self.MANAGER_PROPERTY_DEVICES]] |
| 584 | |
| 585 | |
| 586 | def get_profiles(self): |
| 587 | """Return the list of profiles as dbus Interface objects""" |
| 588 | properties = self.manager.GetProperties(utf8_strings=True) |
| 589 | return [self.get_dbus_object(self.DBUS_TYPE_PROFILE, path) |
| 590 | for path in properties[self.MANAGER_PROPERTY_PROFILES]] |
| 591 | |
| 592 | |
| 593 | def get_service(self, params): |
| 594 | """ |
| 595 | Get the shill service that matches |params|. |
| 596 | |
| 597 | @param params dict of strings understood by shill to describe |
| 598 | a service. |
| 599 | @return DBus object interface representing a service. |
| 600 | |
| 601 | """ |
Ningyuan Wang | c326ddf | 2015-09-22 16:03:40 -0700 | [diff] [blame] | 602 | dbus_params = self.service_properties_to_dbus_types(params) |
| 603 | path = self.manager.GetService(dbus_params) |
Christopher Wiley | 1f89fd2 | 2013-12-19 15:02:45 -0800 | [diff] [blame] | 604 | return self.get_dbus_object(self.DBUS_TYPE_SERVICE, path) |
| 605 | |
| 606 | |
| 607 | def get_service_for_device(self, device): |
| 608 | """Attempt to find a service that manages |device|. |
| 609 | |
| 610 | @param device a dbus object interface representing a device. |
| 611 | @return Dbus object interface representing a service if found. None |
| 612 | otherwise. |
| 613 | |
| 614 | """ |
| 615 | properties = self.manager.GetProperties(utf8_strings=True) |
| 616 | all_services = properties.get(self.MANAGER_PROPERTY_ALL_SERVICES, |
| 617 | None) |
| 618 | if not all_services: |
| 619 | return None |
| 620 | |
| 621 | for service_path in all_services: |
| 622 | service = self.get_dbus_object(self.DBUS_TYPE_SERVICE, |
| 623 | service_path) |
| 624 | properties = service.GetProperties(utf8_strings=True) |
| 625 | device_path = properties.get(self.SERVICE_PROPERTY_DEVICE, None) |
| 626 | if device_path == device.object_path: |
| 627 | return service |
| 628 | |
| 629 | return None |
| 630 | |
| 631 | |
| 632 | def find_object(self, object_type, properties): |
| 633 | """Find a shill object with the specified type and properties. |
| 634 | |
| 635 | Return the first shill object of |object_type| whose properties match |
| 636 | all that of |properties|. |
| 637 | |
| 638 | @param object_type string representing the type of object to be |
| 639 | returned. Valid values are those object types defined in |
| 640 | |OBJECT_TYPE_PROPERTY_MAP|. |
| 641 | @param properties dict of strings understood by shill to describe |
| 642 | a service. |
| 643 | @return DBus object interface representing the object found or None |
| 644 | if no matching object is found. |
| 645 | |
| 646 | """ |
| 647 | if object_type not in self.OBJECT_TYPE_PROPERTY_MAP: |
| 648 | return None |
| 649 | |
| 650 | dbus_type, manager_property = self.OBJECT_TYPE_PROPERTY_MAP[object_type] |
| 651 | manager_properties = self.manager.GetProperties(utf8_strings=True) |
| 652 | for path in manager_properties[manager_property]: |
| 653 | try: |
| 654 | test_object = self.get_dbus_object(dbus_type, path) |
| 655 | object_properties = test_object.GetProperties(utf8_strings=True) |
| 656 | for name, value in properties.iteritems(): |
| 657 | if (name not in object_properties or |
| 658 | self.dbus2primitive(object_properties[name]) != value): |
| 659 | break |
| 660 | else: |
| 661 | return test_object |
| 662 | |
| 663 | except dbus.exceptions.DBusException, e: |
| 664 | # This could happen if for instance, you're enumerating services |
| 665 | # and test_object was removed in shill between the call to get |
| 666 | # the manager properties and the call to get the service |
| 667 | # properties. This causes failed method invocations. |
| 668 | continue |
| 669 | return None |
| 670 | |
| 671 | |
| 672 | def find_matching_service(self, properties): |
| 673 | """Find a service object that matches the given properties. |
| 674 | |
| 675 | This re-implements the manager DBus method FindMatchingService. |
| 676 | The advantage of doing this here is that FindMatchingServices does |
| 677 | not exist on older images, which will cause tests to fail. |
| 678 | |
| 679 | @param properties dict of strings understood by shill to describe |
| 680 | a service. |
| 681 | |
| 682 | """ |
| 683 | return self.find_object('Service', properties) |
Thieu Le | 8803872 | 2014-09-18 18:18:39 -0700 | [diff] [blame] | 684 | |
| 685 | |
| 686 | def connect_service_synchronous(self, service, timeout_seconds): |
| 687 | """Connect a service and wait for its state to become connected. |
| 688 | |
| 689 | @param service DBus service object to connect. |
| 690 | @param timeout_seconds number of seconds to wait for service to go |
| 691 | enter a connected state. |
| 692 | @return True if the service connected successfully. |
| 693 | |
| 694 | """ |
| 695 | try: |
| 696 | service.Connect() |
| 697 | except dbus.exceptions.DBusException as e: |
Thieu Le | 5e6acf2 | 2014-10-14 17:34:23 -0700 | [diff] [blame] | 698 | if e.get_dbus_name() != self.ERROR_ALREADY_CONNECTED: |
Thieu Le | 8803872 | 2014-09-18 18:18:39 -0700 | [diff] [blame] | 699 | raise e |
| 700 | success, _, _ = self.wait_for_property_in( |
| 701 | service, self.SERVICE_PROPERTY_STATE, |
| 702 | self.SERVICE_CONNECTED_STATES, |
| 703 | timeout_seconds=timeout_seconds) |
| 704 | return success |
| 705 | |
| 706 | |
| 707 | def disconnect_service_synchronous(self, service, timeout_seconds): |
| 708 | """Disconnect a service and wait for its state to go idle. |
| 709 | |
| 710 | @param service DBus service object to disconnect. |
| 711 | @param timeout_seconds number of seconds to wait for service to go idle. |
| 712 | @return True if the service disconnected successfully. |
| 713 | |
| 714 | """ |
| 715 | try: |
| 716 | service.Disconnect() |
| 717 | except dbus.exceptions.DBusException as e: |
Thieu Le | 5e6acf2 | 2014-10-14 17:34:23 -0700 | [diff] [blame] | 718 | if e.get_dbus_name() not in [self.ERROR_IN_PROGRESS, |
Thieu Le | 8803872 | 2014-09-18 18:18:39 -0700 | [diff] [blame] | 719 | self.ERROR_NOT_CONNECTED]: |
| 720 | raise e |
| 721 | success, _, _ = self.wait_for_property_in( |
| 722 | service, self.SERVICE_PROPERTY_STATE, ['idle'], |
| 723 | timeout_seconds=timeout_seconds) |
| 724 | return success |
Brian Norris | 3a1cb2a | 2019-08-08 13:35:28 -0700 | [diff] [blame] | 725 | |
| 726 | |
| 727 | def get_default_interface_name(self): |
| 728 | """Retrieve the name of the default interface. |
| 729 | |
| 730 | Default interface is determined via the Manager's default service. |
| 731 | |
| 732 | @return Device name string, or None. |
| 733 | """ |
| 734 | service_path = self.get_dbus_property(self.manager, |
| 735 | self.MANAGER_PROPERTY_DEFAULT_SERVICE) |
| 736 | if not service_path: |
| 737 | return None |
| 738 | service = self.get_dbus_object(self.DBUS_TYPE_SERVICE, service_path) |
| 739 | device_path = self.get_dbus_property(service, |
| 740 | self.SERVICE_PROPERTY_DEVICE) |
| 741 | if not device_path: |
| 742 | return None |
| 743 | device = self.get_dbus_object(self.DBUS_TYPE_DEVICE, device_path) |
| 744 | return self.get_dbus_property(device, self.DEVICE_PROPERTY_INTERFACE) |