1*9c5db199SXin Li# Lint as: python2, python3 2*9c5db199SXin Li# Copyright 2014 The Chromium OS Authors. All rights reserved. 3*9c5db199SXin Li# Use of this source code is governed by a BSD-style license that can be 4*9c5db199SXin Li# found in the LICENSE file. 5*9c5db199SXin Li 6*9c5db199SXin Lifrom __future__ import absolute_import 7*9c5db199SXin Lifrom __future__ import division 8*9c5db199SXin Lifrom __future__ import print_function 9*9c5db199SXin Li 10*9c5db199SXin Liimport dbus 11*9c5db199SXin Liimport logging 12*9c5db199SXin Liimport six 13*9c5db199SXin Li 14*9c5db199SXin Liimport common 15*9c5db199SXin Li 16*9c5db199SXin Lifrom autotest_lib.client.bin import utils 17*9c5db199SXin Lifrom autotest_lib.client.common_lib import seven 18*9c5db199SXin Li 19*9c5db199SXin Li 20*9c5db199SXin LiDBUS_INTERFACE_OBJECT_MANAGER = 'org.freedesktop.DBus.ObjectManager' 21*9c5db199SXin LiDBUS_ERROR_SERVICEUNKNOWN = 'org.freedesktop.DBus.Error.ServiceUnknown' 22*9c5db199SXin Li 23*9c5db199SXin Li 24*9c5db199SXin Lidef dbus2primitive(value): 25*9c5db199SXin Li """Convert values from dbus types to python types. 26*9c5db199SXin Li 27*9c5db199SXin Li @param value: dbus object to convert to a primitive. 28*9c5db199SXin Li 29*9c5db199SXin Li """ 30*9c5db199SXin Li if isinstance(value, dbus.Boolean): 31*9c5db199SXin Li return bool(value) 32*9c5db199SXin Li elif isinstance(value, int): 33*9c5db199SXin Li return int(value) 34*9c5db199SXin Li elif isinstance(value, dbus.UInt16): 35*9c5db199SXin Li return seven.ensure_long(value) 36*9c5db199SXin Li elif isinstance(value, dbus.UInt32): 37*9c5db199SXin Li return seven.ensure_long(value) 38*9c5db199SXin Li elif isinstance(value, dbus.UInt64): 39*9c5db199SXin Li return seven.ensure_long(value) 40*9c5db199SXin Li elif isinstance(value, float): 41*9c5db199SXin Li return float(value) 42*9c5db199SXin Li elif isinstance(value, str): 43*9c5db199SXin Li return str(value) 44*9c5db199SXin Li elif isinstance(value, six.text_type): 45*9c5db199SXin Li return str(value.encode('utf-8')) 46*9c5db199SXin Li elif isinstance(value, list): 47*9c5db199SXin Li return [dbus2primitive(x) for x in value] 48*9c5db199SXin Li elif isinstance(value, tuple): 49*9c5db199SXin Li return tuple([dbus2primitive(x) for x in value]) 50*9c5db199SXin Li elif isinstance(value, dict): 51*9c5db199SXin Li return dict([(dbus2primitive(k), dbus2primitive(v)) 52*9c5db199SXin Li for k, v in value.items()]) 53*9c5db199SXin Li else: 54*9c5db199SXin Li logging.error('Failed to convert dbus object of class: %r', 55*9c5db199SXin Li value.__class__.__name__) 56*9c5db199SXin Li return value 57*9c5db199SXin Li 58*9c5db199SXin Li 59*9c5db199SXin Lidef get_objects_with_interface(service_name, object_manager_path, 60*9c5db199SXin Li dbus_interface, path_prefix=None, 61*9c5db199SXin Li bus=None): 62*9c5db199SXin Li """Get objects that have a particular interface via a property manager. 63*9c5db199SXin Li 64*9c5db199SXin Li @param service_name: string remote service exposing the object manager 65*9c5db199SXin Li to query (e.g. 'org.chromium.peerd'). 66*9c5db199SXin Li @param object_manager_path: string DBus path of object manager on remote 67*9c5db199SXin Li service (e.g. '/org/chromium/peerd') 68*9c5db199SXin Li @param dbus_interface: string interface of object we're interested in. 69*9c5db199SXin Li @param path_prefix: string prefix of DBus path to filter for. If not 70*9c5db199SXin Li None, we'll return only objects in the remote service whose 71*9c5db199SXin Li paths start with this prefix. 72*9c5db199SXin Li @param bus: dbus.Bus object, defaults to dbus.SystemBus(). Note that 73*9c5db199SXin Li normally, dbus.SystemBus() multiplexes a single DBus connection 74*9c5db199SXin Li among its instances. 75*9c5db199SXin Li @return dict that maps object paths to dicts of interface name to properties 76*9c5db199SXin Li exposed by that interface. This is similar to the structure 77*9c5db199SXin Li returned by org.freedesktop.DBus.ObjectManaber.GetManagedObjects(). 78*9c5db199SXin Li 79*9c5db199SXin Li """ 80*9c5db199SXin Li if bus is None: 81*9c5db199SXin Li bus = dbus.SystemBus() 82*9c5db199SXin Li object_manager = dbus.Interface( 83*9c5db199SXin Li bus.get_object(service_name, object_manager_path), 84*9c5db199SXin Li dbus_interface=DBUS_INTERFACE_OBJECT_MANAGER) 85*9c5db199SXin Li objects = dbus2primitive(object_manager.GetManagedObjects()) 86*9c5db199SXin Li logging.debug('Saw objects %r', objects) 87*9c5db199SXin Li # Filter by interface. 88*9c5db199SXin Li objects = [(path, interfaces) 89*9c5db199SXin Li for path, interfaces in six.iteritems(objects) 90*9c5db199SXin Li if dbus_interface in interfaces] 91*9c5db199SXin Li if path_prefix is not None: 92*9c5db199SXin Li objects = [(path, interfaces) 93*9c5db199SXin Li for path, interfaces in objects 94*9c5db199SXin Li if path.startswith(path_prefix)] 95*9c5db199SXin Li objects = dict(objects) 96*9c5db199SXin Li logging.debug('Filtered objects: %r', objects) 97*9c5db199SXin Li return objects 98*9c5db199SXin Li 99*9c5db199SXin Lidef get_dbus_object(bus, service_name, object_manager_path, timeout=None): 100*9c5db199SXin Li """Keeps trying to get the a DBus object until a timeout expires. 101*9c5db199SXin Li Useful if a test should wait for a system daemon to start up. 102*9c5db199SXin Li 103*9c5db199SXin Li @param bus: dbus.Bus object. 104*9c5db199SXin Li @param service_name: string service to look up (e.g. 'org.chromium.peerd'). 105*9c5db199SXin Li @param object_manager_path: string DBus path of object manager on remote 106*9c5db199SXin Li service (e.g. '/org/chromium/peerd') 107*9c5db199SXin Li @param timeout: maximum time in seconds to wait for the bus object. 108*9c5db199SXin Li @return The DBus object or None if the timeout expired. 109*9c5db199SXin Li 110*9c5db199SXin Li """ 111*9c5db199SXin Li 112*9c5db199SXin Li def try_get_object(): 113*9c5db199SXin Li try: 114*9c5db199SXin Li return bus.get_object(service_name, object_manager_path) 115*9c5db199SXin Li except dbus.exceptions.DBusException as e: 116*9c5db199SXin Li # Only handle DBUS_ERROR_SERVICEUNKNOWN, which is thrown when the 117*9c5db199SXin Li # service is not running yet. Otherwise, rethrow. 118*9c5db199SXin Li if e.get_dbus_name() == DBUS_ERROR_SERVICEUNKNOWN: 119*9c5db199SXin Li return None 120*9c5db199SXin Li raise 121*9c5db199SXin Li 122*9c5db199SXin Li return utils.poll_for_condition( 123*9c5db199SXin Li condition=try_get_object, 124*9c5db199SXin Li desc='Get bus object "%s" / "%s"' % (service_name, 125*9c5db199SXin Li object_manager_path), 126*9c5db199SXin Li timeout=timeout or 0) 127