Introspecting Dbus

From WebOS Internals
Jump to: navigation, search

Palm/DBUS Namespaces

(these should be split up into Palm and 3rd-party lists at some point)

  • com.palm.accounts
  • com.palm.accountservices
  • com.palm.applicationManager
  • com.palm.bluetooth
  • com.palm.browserServer
  • com.palm.bus
  • com.palm.calendar
  • com.palm.certificatemanager
  • com.palm.connectionmanager
  • com.palm.contacts
  • com.palm.crotest
  • com.palm.customization
  • com.palm.dataimport
  • com.palm.deviceprofile
  • com.palm.display
  • com.palm.downloadmanager
  • com.palm.hidd
  • com.palm.keys
  • com.palm.location
  • com.palm.lunabus
  • com.palm.mail
  • com.palm.mediadb
  • com.palm.mediaevents
  • com.palm.messaging
  • com.palm.omadm
  • com.palm.pdf
  • com.palm.pimsync
  • com.palm.power
  • com.palm.provisioning
  • com.palm.preferences
  • com.palm.superlog
  • com.palm.systemmanager
  • com.palm.systemservice
  • com.palm.taskScheduler
  • com.palm.telephony
  • com.palm.update
  • com.palm.wan
  • com.palm.wifi

Python Code

Below is a Python app (shamelessly ripped from for doing some dbus introspection...

Use the link above for usage help.

#! /usr/bin/env python

import dbus, sys
from xml.dom import minidom
from optparse import OptionParser

class Signature(dbus.Signature):
	def Variant(x):
		return x
	_dbus_types = {
		"{": dbus.Dictionary,
		"(": dbus.Struct,
		"a": dbus.Array, 
		"y": dbus.Byte,
		"b": dbus.Boolean,
		"n": dbus.Int16,
		"q": dbus.UInt16,
		"i": dbus.Int32,
		"u": dbus.UInt32,
		"x": dbus.Int64,
		"t": dbus.UInt64,
		"d": dbus.Double,
		"s": dbus.String,
		"o": dbus.ObjectPath,
		"g": dbus.Signature,
		"v": Variant }
	def __iter__(self):
		return ( Signature(x) for x in dbus.Signature.__iter__(self) )
	def get_type(self):
		return self._dbus_types[self[0]]
	def container_type(self):
		if self.startswith("("): return dbus.Struct
		elif self.startswith("a{"): return dbus.Dictionary
		elif self.startswith("a"): return dbus.Array
		else: return None
	def container_content(self):
		if self.container_type() == dbus.Struct: return Signature(self[1:-1])
		elif self.container_type() == dbus.Dictionary: return Signature(self[2:-1])
		elif self.container_type() == dbus.Array: return Signature(self[1:])
		else: return None
	def tostring(self):
		if len(tuple(self)) > 1:
			return ", ".join( x.tostring() for x in self )
		t, c = self.container_type(), self.container_content()
		if t is None:
			return self.get_type().__name__
		elif t == dbus.Array:
			return c.tostring() + "[]"
			return t.__name__ + " {" + c.tostring() + "}"

class Object(object):
	class XMLChild(object):
		def __init__(self, obj, name):
			self.obj = obj = name
			self.xml = None
		def node(self):
			if not self.xml:
				for iface in self.parent().getElementsByTagName(self.tag):
					if iface.getAttribute('name') ==
						self.xml = iface
						return self.xml
			return self.xml
		def children(self, tag):
			for method in self.node().getElementsByTagName(tag):
				name = method.getAttribute('name')
				if name:
					yield name
	class Interface(XMLChild):
		tag = "interface"
		def parent(self):
			return self.obj.introspect()
		def methods(self):
			return self.children('method')
		def signals(self):
			return self.children('signal')
		def method(self, name):
			return self.obj.method(name,
		def signal(self, name):
			return self.obj.signal(name,
	class MethodSignal(XMLChild):
		class Argument:
			def __getattr__(self, x):
				return self.xml.getAttribute(x)
		def __init__(self, obj, name, iface):
			Object.XMLChild.__init__(self, obj, name)
			self.iface = iface
		def parent(self):
			return self.obj.interface(self.iface).node()
		def args(self):
			for arg in self.node().getElementsByTagName("arg"):
				argobj = Object.MethodSignal.Argument()
				argobj.xml = arg
				assert argobj.type
				argobj.signature = Signature(argobj.type)
				yield argobj
	class Method(MethodSignal):
		tag = "method"
		def inargs(self):
			for arg in self.args():
				if arg.direction == "in":
					yield arg
		def outargs(self):
			for arg in self.args():
				if arg.direction == "out":
					yield arg
	class Signal(MethodSignal):
		tag = "signal"
		def outargs(self):
			for arg in self.args():
				assert arg.direction != "out"
			return []
		def inargs(self):
			for arg in self.args():
				assert not arg.direction or arg.direction == "in"
				yield arg
	def __init__(self, bus, service, path):
		self.bus = bus
		self.service = service
		self.path = path
		self.object = None
		self.intr_data = None
		self.cached_childrens = {}
		self.cached_interfaces = {}
		self.cached_methods = {}
		self.cached_signals = {}
	def get_object(self):
		if not self.object:
			self.object = self.bus.get_object(self.service, self.path)
		return self.object
	def introspect(self):
		if not self.intr_data:
			self.intr_data = minidom.parseString(self.get_object().Introspect())
		return self.intr_data
	def children(self):
		intr_data = self.introspect()
		for node in intr_data.getElementsByTagName('node'):
			name = node.getAttribute("name")
			if node == intr_data.documentElement or not name:
				yield name
	def interfaces(self):
		for node in self.introspect().getElementsByTagName('interface'):
			name = node.getAttribute("name")
			if name:
				yield name
	def methods(self, iface):
		return self.interface(iface).methods()
	def signals(self, iface):
		return self.interface(iface).signals()
	def _cached(self, list, name, constr, *constr_args):
		if name not in list:
			list[name] = constr(*constr_args)
		return list[name]
	def child(self, name):
		if self.path == '/':
			full_name = '/' + name
			full_name = self.path + '/' + name
		return self._cached(self.cached_childrens, full_name, Object, self.bus, self.service, full_name)
	def interface(self, name):
		return self._cached(self.cached_interfaces, name, Object.Interface, self, name)
	def method(self, name, iface):
		full_name = iface + '.' + name
		return self._cached(self.cached_methods, full_name, Object.Method, self, name, iface)
	def signal(self, name, iface):
		full_name = iface + '.' + name
		return self._cached(self.cached_methods, full_name, Object.Signal, self, name, iface)

def nonempty_generator(generator):
		x = # this is not good; it loses the first thing generated by the generator
		return True
	except StopIteration:
		return False

def nonempty_iface(iface):
	if options.signals and nonempty_generator(iface.signals()):
		return True
	if nonempty_generator(iface.methods()):
		return True
	return False
def nonempty_object(obj, recursive = True):
	# Check wether an object has a method or a signal (of options.signals)
	# If recursive is True, then it will also return True if the object don't has any method nor signal but one of its child has
		for iface in obj.interfaces():
			if nonempty_iface(obj.interface(iface)):
				return  True
		if not recursive:
			return False
		for child in obj.children():
			if nonempty_object(obj.child(child)):
				return True
		return False
	except: # HACK: HAL returns a non-existent object in the list of chilren, ignore this error
		return False

opts = OptionParser()
opts.add_option("-a", "--all", help="Equivalent to -u -e -s -t", action="store_true", default=False)
opts.add_option("-c", "--completion", help="Set this ON if you are ZSH", action="store_true", default=False)
opts.add_option("-e", "--empty", help="Also show empty services/objects", action="store_true", default=False)
opts.add_option("-s", "--signals", help="Also show signals", action="store_true", default=False)
opts.add_option("-t", "--activatables", help="Also show activatables services", action="store_true", default=False)
opts.add_option("-u", "--unnamed", help="Also show unnamed services (most likely clients)", action="store_true", default=False)
opts.add_option("-y", "--system-bus", help="Work on system bus instead of session bus", action="store_true", default=False)
options, args = opts.parse_args()
if options.all:
	options.empty = options.signals = options.unnamed = options.activatables = True

if options.system_bus:
	bus = dbus.SystemBus()
	bus = dbus.SessionBus()

if len(args) == 0:
	def nonempty_service(service):
		# A service is empty if all its (registered) objects are empty
		return nonempty_object(Object(bus, service, '/'))
	def named(service):
		return not service.startswith(':')
	dbusd = Object(bus, 'org.freedesktop.DBus', '/')
	services = dbusd.get_object().ListNames(dbus_interface = 'org.freedesktop.DBus')
	if options.activatables:
		services += dbusd.get_object().ListActivatableNames(dbus_interface = 'org.freedesktop.DBus')
	if not options.unnamed: # Delete unnamed services if needed
		services = filter(named, services)
	if not options.empty: # Delete empty services if needed
		services = filter(nonempty_service, services)
	for service in services:
		print service
elif len(args) == 1:
	def obj_path(obj):
		return obj.path
	def list_objects(root_obj):
		# Return a list of objects contained in root_obj, including root_obj
		# but excluding (including root_obj) empty objects if needed
		if not options.empty and not nonempty_object(root_obj):
			# The object and its children are empty, no need to continue
			return []
		if not options.empty and not nonempty_object(root_obj, False): 
			# The object is empty but one of its children isn't, so continue
			result = []
			result = [root_obj]
		for child in root_obj.children():
		return result
	for obj in map(obj_path, list_objects(Object(bus, args[0], '/'))):
		print obj
elif len(args) == 2:
	def pprint(method, signal = False):
		def pprint_arg(arg):
			s = arg.signature
			n =
			x = s.tostring()
			if n:
				x += " " + n
			return x
		inargs = list(method.inargs())
		outargs = list(method.outargs())
		if signal:
			print " signal",
		elif len(outargs) == 0:
			print " void",
			print " " + ", ".join(map(pprint_arg, outargs)),
		print + '(' + ", ".join(map(pprint_arg, inargs)) + ')'
	obj = Object(bus, args[0], args[1])
	if options.completion:
		for ifname in obj.interfaces():
			iface = obj.interface(ifname)
			for x in iface.methods():
				print x
				print ifname + "." + x
			if options.signals:
				for x in iface.signals():
					print x
					print ifname + "." + x
		for ifname in obj.interfaces():
			iface = obj.interface(ifname)
			if not options.empty and not nonempty_iface(iface):
			print "Interface %s:" % ifname
			i = 0
			for methodname in iface.methods():
				i += 1
			if i:
			if not options.signals:
				if not i:
			j = 0
			for signalname in iface.signals():
				pprint(iface.signal(signalname), True)
				j += 1
			if j or not i:
	def indent(level):
		sys.stdout.write("  "*level)

	def print_arg(arg, name):
		def dump(data, lvl):
			if type(data) in (dbus.Struct, dbus.Array):
				print type(data).__name__
				for x in arg:
					dump(x, lvl + 1)
			elif type(data) == dbus.Dictionary:
				print type(data).__name__
				for k, v in data.iteritems():
					dump(k, lvl+1)
					print ":",
					dump(v, 0)
				print data,
		if name:
			print name,"= ",
		dump(arg, 0)

	service, path, method = args[0:3]
	obj = Object(bus, service, path)
	args = args[3:]
	if "." in method:
		iface, method = method.rsplit(".", 1)
		iface = None
			for iface in obj.interfaces():
				if method in list(obj.interface(iface).methods()):
	if options.completion:
			for i, arg in enumerate(obj.interface(iface).method(method).inargs()):
				if i == len(args):
					print arg.signature.tostring(),
	args2 = []
	for arg in args:
		if len(arg) >= 2 and arg[0] == '%':
			if arg[1] == '%':
				args2.append('%' + arg[2:])
				args2.append(eval(arg[1:], {}))
	args = args2
	ret = obj.get_object().get_dbus_method(method, iface)(*args)
		outargs = list(obj.method(method, iface).outargs())
		outargs = []
	if not isinstance(ret, tuple) or isinstance(ret, dbus.Struct):
		ret = (ret,)
	for i, arg in enumerate(ret):
		if len(outargs) > i:
			print_arg(arg, outargs[i].name)
			print_arg(arg, None)