| # Copyright 2014 The Chromium OS Authors. All rights reserved. |
| # Use of this source code is governed by a BSD-style license that can be |
| # found in the LICENSE file. |
| |
| import dbus |
| import logging |
| |
| from autotest_lib.client.bin import utils |
| |
| |
| DBUS_INTERFACE_OBJECT_MANAGER = 'org.freedesktop.DBus.ObjectManager' |
| DBUS_ERROR_SERVICEUNKNOWN = 'org.freedesktop.DBus.Error.ServiceUnknown' |
| |
| |
| def dbus2primitive(value): |
| """Convert values from dbus types to python types. |
| |
| @param value: dbus object to convert to a primitive. |
| |
| """ |
| if isinstance(value, dbus.Boolean): |
| return bool(value) |
| elif isinstance(value, int): |
| return int(value) |
| elif isinstance(value, dbus.UInt16): |
| return long(value) |
| elif isinstance(value, dbus.UInt32): |
| return long(value) |
| elif isinstance(value, dbus.UInt64): |
| return long(value) |
| elif isinstance(value, float): |
| return float(value) |
| elif isinstance(value, str): |
| return str(value) |
| elif isinstance(value, unicode): |
| return str(value) |
| elif isinstance(value, list): |
| return [dbus2primitive(x) for x in value] |
| elif isinstance(value, tuple): |
| return tuple([dbus2primitive(x) for x in value]) |
| elif isinstance(value, dict): |
| return dict([(dbus2primitive(k), dbus2primitive(v)) |
| for k,v in value.items()]) |
| else: |
| logging.error('Failed to convert dbus object of class: %r', |
| value.__class__.__name__) |
| return value |
| |
| |
| def get_objects_with_interface(service_name, object_manager_path, |
| dbus_interface, path_prefix=None, |
| bus=None): |
| """Get objects that have a particular interface via a property manager. |
| |
| @param service_name: string remote service exposing the object manager |
| to query (e.g. 'org.chromium.peerd'). |
| @param object_manager_path: string DBus path of object manager on remote |
| service (e.g. '/org/chromium/peerd') |
| @param dbus_interface: string interface of object we're interested in. |
| @param path_prefix: string prefix of DBus path to filter for. If not |
| None, we'll return only objects in the remote service whose |
| paths start with this prefix. |
| @param bus: dbus.Bus object, defaults to dbus.SystemBus(). Note that |
| normally, dbus.SystemBus() multiplexes a single DBus connection |
| among its instances. |
| @return dict that maps object paths to dicts of interface name to properties |
| exposed by that interface. This is similar to the structure |
| returned by org.freedesktop.DBus.ObjectManaber.GetManagedObjects(). |
| |
| """ |
| if bus is None: |
| bus = dbus.SystemBus() |
| object_manager = dbus.Interface( |
| bus.get_object(service_name, object_manager_path), |
| dbus_interface=DBUS_INTERFACE_OBJECT_MANAGER) |
| objects = dbus2primitive(object_manager.GetManagedObjects()) |
| logging.debug('Saw objects %r', objects) |
| # Filter by interface. |
| objects = [(path, interfaces) |
| for path, interfaces in objects.iteritems() |
| if dbus_interface in interfaces] |
| if path_prefix is not None: |
| objects = [(path, interfaces) |
| for path, interfaces in objects |
| if path.startswith(path_prefix)] |
| objects = dict(objects) |
| logging.debug('Filtered objects: %r', objects) |
| return objects |
| |
| def get_dbus_object(bus, service_name, object_manager_path, timeout=None): |
| """Keeps trying to get the a DBus object until a timeout expires. |
| Useful if a test should wait for a system daemon to start up. |
| |
| @param bus: dbus.Bus object. |
| @param service_name: string service to look up (e.g. 'org.chromium.peerd'). |
| @param object_manager_path: string DBus path of object manager on remote |
| service (e.g. '/org/chromium/peerd') |
| @param timeout: maximum time in seconds to wait for the bus object. |
| @return The DBus object or None if the timeout expired. |
| |
| """ |
| |
| def try_get_object(): |
| try: |
| return bus.get_object(service_name, object_manager_path) |
| except dbus.exceptions.DBusException as e: |
| # Only handle DBUS_ERROR_SERVICEUNKNOWN, which is thrown when the |
| # service is not running yet. Otherwise, rethrow. |
| if e.get_dbus_name() == DBUS_ERROR_SERVICEUNKNOWN: |
| return None |
| raise |
| |
| return utils.poll_for_condition( |
| condition=try_get_object, |
| desc='Get bus object "%s" / "%s"' % (service_name, |
| object_manager_path), |
| timeout=timeout or 0) |