我想在freerunner(一个开源linux手机)上查看fso(openmoko的诸多软件版本之一)的dbus信息。但fso的 python没有gtk模块,跑不了d-feet。在上一讲我介绍了d-feet的基本思路:用 “org.freedesktop.DBus.ListNames”枚举消息总线上的连接,用 “org.freedesktop.DBus.Introspectable.Introspect” 从"/"开始遍历连接的对象树。上一讲我们手工查看了两个连接,那么我们能不能写一个程序自动遍历连接的对象树,输出指定连接的所有对象的所有接口的所有 方法和信号?
当然可以,为此我写了一个叫dteeth的python脚本。不过在介绍这个脚本前,让我们先看看dbus的数据类型。
dbus用xml描述接口,例如:
<?xml version="1.0" encoding="UTF-8" ?> <node name="/org/freesmartphone/GSM/Device"> <interface name="org.freesmartphone.GSM.SMS"> <method name="SendMessage"> <arg name="number" type="s"/> <arg name="contents" type="s"/> <arg name="featuremap" type="a{sv}"/> <arg type="i" direction="out"/> </method> <signal name="IncomingMessage"> <arg name="address" type="s"/> <arg name="contents" type="s"/> <arg name="features" type="a{sv}"/> </signal> </interface> </node>
其实前两讲已经看过很多例子了。node就是接口中的对象,node可以包含node,构成对象树。 dbus的接口描述文件统一采用utf-8编码。我相信读者很容易理解这个接口描述文件。我只想解释一下描述参数数据类型的type域。 dbus的数据类型是由"s"或"a{sv}"这样的类型签名(Type Signatures)定义的。类型签名中可以使用以下标记:
a | ARRAY 数组 |
b | BOOLEAN 布尔值 |
d | DOUBLE IEEE 754双精度浮点数 |
g | SIGNATURE 类型签名 |
i | INT32 32位有符号整数 |
n | INT16 16位有符号整数 |
o | OBJECT_PATH 对象路径 |
q | UINT16 16位无符号整数 |
s | STRING 零结尾的UTF-8字符串 |
t | UINT64 64位无符号整数 |
u | UINT32 32位无符号整数 |
v | VARIANT 可以放任意数据类型的容器,数据中包含类型信息。例如glib中的GValue。 |
x | INT64 64位有符号整数 |
y | BYTE 8位无符号整数 |
() | 定义结构时使用。例如"(i(ii))" |
{} | 定义键-值对时使用。例如"a{us}" |
a表示数组,数组元素的类型由a后面的标记决定。例如:
在以后的例子中,我们会亲手实现上面这个xml描述的接口,包括服务器和客户程序。到时候,读者会对dbus的数据类型有更直观的认识。
可以从这里 下载dteeth的源代码。其中包含两个python脚本:dteeth.py和_introspect_parser.py。 dteeth.py是我写的。_introspect_parser.py是个开源模块,可以分析Introspect返回的xml数据。
dteeth用法如下:
$ ./dteeth.py -h Usage: dteeth [--system] <name of a connection on the bus >
默认连接session总线,除非你加上--system。可以一次指定同一消息总线的多个连接。先在PC上试一试:
$ ./dteeth.py org.fmddlmyy.Test org.fmddlmyy.Test /TestObj org.fmddlmyy.Test.Basic methods Add( in i arg0 , in i arg1 , out i ret ) org.freedesktop.DBus.Introspectable methods Introspect( out s data ) org.freedesktop.DBus.Properties methods Set( in s interface , in s propname , in v value ) GetAll( in s interface , out a{sv} props ) Get( in s interface , in s propname , out v value )
我也在fso版本的freerunner手机上运行了一下,得到了org.freesmartphone.ogsmd的所有对象的所有的接口的所有方法和信号:
org.freesmartphone.ogsmd /org/freedesktop/Gypsy org.freedesktop.Gypsy.Time signals TimeChanged( i time ) methods GetTime( out i ) org.freedesktop.DBus.Introspectable methods Introspect( out s ) org.freedesktop.Gypsy.Device signals FixStatusChanged( i fixstatus ) ConnectionStatusChanged( b constatus ) methods GetConnectionStatus( out b ) Stop( ) Start( ) GetFixStatus( out i ) org.freedesktop.Gypsy.Course signals CourseChanged( i fields , i tstamp , d speed , d heading , d climb ) methods GetCourse( out i , out i , out d , out d , out d ) org.freedesktop.Gypsy.Position signals PositionChanged( i fields , i tstamp , d lat , d lon , d alt ) methods GetPosition( out i , out i , out d , out d , out d ) org.freedesktop.Gypsy.Accuracy signals AccuracyChanged( i fields , d pdop , d hdop , d vdop ) methods GetAccuracy( out i , out d , out d , out d ) org.freesmartphone.Resource methods Enable( ) Disable( ) Suspend( ) Resume( ) org.freedesktop.Gypsy.Satellite signals SatellitesChanged( a(ubuuu) satellites ) methods GetSatellites( out a(ubuuu) ) org.freesmartphone.GPS.UBX signals DebugPacket( s clid , i length , aa{sv} data ) methods SendDebugPacket( in s clid , in i length , in aa{sv} data ) GetDebugFilter( in s clid , out b ) SetDebugFilter( in s clid , in b state ) org.freedesktop.Gypsy.Server methods Create( in s device , out o ) Shutdown( in o path ) /org/freesmartphone/Device/Audio org.freedesktop.DBus.Introspectable methods Introspect( out s ) org.freesmartphone.Device.Audio signals SoundStatus( s name , s status , a{sv} properties ) Scenario( s scenario , s reason ) methods SetScenario( in s name ) GetInfo( out s ) GetAvailableScenarios( out as ) PushScenario( in s name ) GetScenario( out s ) PullScenario( out s ) StopSound( in s name ) StopAllSounds( ) PlaySound( in s name ) StoreScenario( in s name ) /org/freesmartphone/Device/Display/pcf50633_bl org.freedesktop.DBus.Introspectable methods Introspect( out s ) org.freesmartphone.Device.Display methods SetBrightness( in i brightness ) GetName( out s ) SetBacklightPower( in b power ) GetBrightness( out i ) GetBacklightPower( out b ) /org/freesmartphone/Device/IdleNotifier/0 org.freedesktop.DBus.Introspectable methods Introspect( out s ) org.freesmartphone.Device.IdleNotifier signals State( s state ) methods SetState( in s state ) GetState( out s ) SetTimeout( in s state , in i timeout ) GetTimeouts( out a{si} ) /org/freesmartphone/Device/Info org.freedesktop.DBus.Introspectable methods Introspect( out s ) org.freesmartphone.Device.Info methods GetCpuInfo( out a{sv} ) /org/freesmartphone/Device/Input org.freesmartphone.Device.Input signals Event( s name , s action , i seconds ) org.freedesktop.DBus.Introspectable methods Introspect( out s ) /org/freesmartphone/Device/LED/gta02_aux_red org.freedesktop.DBus.Introspectable methods Introspect( out s ) org.freesmartphone.Device.LED methods SetBrightness( in i brightness ) GetName( out s ) SetBlinking( in i delay_on , in i delay_off ) /org/freesmartphone/Device/LED/gta02_power_blue org.freedesktop.DBus.Introspectable methods Introspect( out s ) org.freesmartphone.Device.LED methods SetBrightness( in i brightness ) GetName( out s ) SetBlinking( in i delay_on , in i delay_off ) /org/freesmartphone/Device/LED/gta02_power_orange org.freedesktop.DBus.Introspectable methods Introspect( out s ) org.freesmartphone.Device.LED methods SetBrightness( in i brightness ) GetName( out s ) SetBlinking( in i delay_on , in i delay_off ) /org/freesmartphone/Device/LED/neo1973_vibrator org.freedesktop.DBus.Introspectable methods Introspect( out s ) org.freesmartphone.Device.LED methods SetBrightness( in i brightness ) GetName( out s ) SetBlinking( in i delay_on , in i delay_off ) /org/freesmartphone/Device/PowerControl/Bluetooth org.freesmartphone.Device.PowerControl signals Power( s device , b power ) methods Reset( ) GetName( out s ) SetPower( in b power ) GetPower( out b ) org.freedesktop.DBus.Introspectable methods Introspect( out s ) org.freesmartphone.Resource methods Resume( ) Enable( ) Disable( ) Suspend( ) /org/freesmartphone/Device/PowerControl/UsbHost org.freesmartphone.Device.PowerControl signals Power( s device , b power ) methods Reset( ) GetName( out s ) SetPower( in b power ) GetPower( out b ) org.freedesktop.DBus.Introspectable methods Introspect( out s ) /org/freesmartphone/Device/PowerControl/WiFi org.freesmartphone.Device.PowerControl signals Power( s device , b power ) methods Reset( ) GetName( out s ) SetPower( in b power ) GetPower( out b ) org.freedesktop.DBus.Introspectable methods Introspect( out s ) org.freesmartphone.Resource methods Resume( ) Enable( ) Disable( ) Suspend( ) /org/freesmartphone/Device/PowerSupply/apm org.freedesktop.DBus.Introspectable methods Introspect( out s ) org.freesmartphone.Device.PowerSupply methods GetName( out s ) GetEnergyPercentage( out i ) GetOnBattery( out b ) GetInfo( out a{sv} ) /org/freesmartphone/Device/PowerSupply/bat org.freedesktop.DBus.Introspectable methods Introspect( out s ) org.freesmartphone.Device.PowerSupply signals PowerStatus( s status ) Capacity( i percent ) methods GetEnergyPercentage( out i ) GetInfo( out a{sv} ) IsPresent( out b ) GetName( out s ) GetCapacity( out i ) GetPowerStatus( out s ) /org/freesmartphone/Device/RealTimeClock/rtc0 org.freedesktop.DBus.Introspectable methods Introspect( out s ) org.freesmartphone.Device.RealTimeClock methods GetWakeupReason( out s ) SetCurrentTime( in s t ) Suspend( ) GetWakeupTime( out s ) GetName( out s ) GetCurrentTime( out s ) SetWakeupTime( in s t ) /org/freesmartphone/Events org.freedesktop.DBus.Introspectable methods Introspect( out s ) org.freesmartphone.Events methods AddRule( in s rule_str ) TriggerTest( in s name , in b value ) /org/freesmartphone/Framework org.freedesktop.DBus.Introspectable methods Introspect( out s ) org.freesmartphone.Framework methods GetDebugLevel( in s logger , out s ) GetDebugDestination( out s , out s ) ListDebugLoggers( out as ) ListObjectsInSubsystem( in s subsystem , out as ) SetDebugDestination( in s category , in s destination ) SetDebugLevel( in s logger , in s levelname ) ListObjectsByInterface( in s interface , out ao ) ListSubsystems( out as ) /org/freesmartphone/GSM/Device org.freesmartphone.GSM.Call signals CallStatus( i index , s status , a{sv} properties ) methods Activate( in i index ) Emergency( in s number ) SendDtmf( in s tones ) ReleaseHeld( ) HoldActive( ) ReleaseAll( ) Initiate( in s number , in s type_ , out i ) ListCalls( out a(isa{sv}) ) Transfer( in s number ) Release( in i index ) ActivateConference( in i index ) org.freesmartphone.GSM.Debug methods DebugInjectString( in s channel , in s string ) DebugCommand( in s command , out as ) DebugEcho( in s echo , out s ) DebugListChannels( out as ) org.freedesktop.DBus.Introspectable methods Introspect( out s ) org.freesmartphone.GSM.Device methods CancelCommand( ) GetInfo( out a{sv} ) GetAntennaPower( out b ) SetSimBuffersSms( in b sim_buffers_sms ) GetFeatures( out a{sv} ) SetAntennaPower( in b power ) GetSimBuffersSms( out b ) org.freesmartphone.GSM.SMS signals IncomingMessage( s address , s text , a{sv} features ) methods SendMessage( in s number , in s contents , in a{sv} featuremap , out i ) org.freesmartphone.GSM.SIM signals ReadyStatus( b status ) MemoryFull( ) AuthStatus( s status ) IncomingStoredMessage( i index ) methods RetrievePhonebook( in s category , out a(iss) ) SendAuthCode( in s code ) ChangeAuthCode( in s old_pin , in s new_pin ) SendGenericSimCommand( in s command , out s ) ListPhonebooks( out as ) SetServiceCenterNumber( in s number ) GetHomeZones( out a(siii) ) RetrieveEntry( in s category , in i index , out s , out s ) DeleteMessage( in i index ) SendRestrictedSimCommand( in i command , in i fileid , in i p1 , in i p2 , in i p3 , in s data , out i , out i , out s ) GetMessagebookInfo( out a{sv} ) GetSimReady( out b ) GetPhonebookInfo( in s category , out a{sv} ) GetSimInfo( out a{sv} ) SendStoredMessage( in i index , out i ) SetAuthCodeRequired( in b required , in s pin ) GetAuthStatus( out s ) StoreMessage( in s number , in s contents , in a{sv} featuremap , out i ) GetAuthCodeRequired( out b ) RetrieveMessage( in i index , out s , out s , out s , out a{sv} ) StoreEntry( in s category , in i index , in s name , in s number ) Unlock( in s puk , in s new_pin ) GetServiceCenterNumber( out s ) RetrieveMessagebook( in s category , out a(isssa{sv}) ) DeleteEntry( in s category , in i index ) org.freesmartphone.GSM.Network signals Status( a{sv} status ) SignalStrength( i strength ) IncomingUssd( s mode , s message ) methods EnableCallForwarding( in s reason , in s class_ , in s number , in i timeout ) ListProviders( out a(isss) ) GetCallForwarding( in s reason , out a{sv} ) Unregister( ) SetCallingIdentification( in s status ) Register( ) SendUssdRequest( in s request ) DisableCallForwarding( in s reason , in s class_ ) GetSignalStrength( out i ) GetCallingIdentification( out s ) RegisterWithProvider( in i operator_code ) GetNetworkCountryCode( out s ) GetStatus( out a{sv} ) org.freesmartphone.Resource methods Enable( ) Disable( ) Suspend( ) Resume( ) org.freesmartphone.GSM.CB signals IncomingCellBroadcast( i channel , s data ) methods GetCellBroadcastSubscriptions( out s ) SetCellBroadcastSubscriptions( in s channels ) org.freesmartphone.GSM.PDP signals ContextStatus( i index , s status , a{sv} properties ) methods SetCurrentGprsClass( in s class_ ) ActivateContext( in s apn , in s user , in s password ) DeactivateContext( ) ListAvailableGprsClasses( out as ) GetContextStatus( out s ) GetCurrentGprsClass( out s ) /org/freesmartphone/GSM/Server org.freedesktop.DBus.Introspectable methods Introspect( out s ) org.freesmartphone.GSM.HZ signals HomeZoneStatus( s zone ) methods GetHomeZoneStatus( out s ) GetKnownHomeZones( out as ) /org/freesmartphone/PIM/Contacts org.freedesktop.DBus.Introspectable methods Introspect( out s ) org.freesmartphone.PIM.Contacts methods Query( in a{sv} query , out s ) Add( in a{sv} contact_data , out s ) GetSingleContactSingleField( in a{sv} query , in s field_name , out s ) org.freesmartphone.PIM.Contact methods GetContent( out a{sv} ) GetMultipleFields( in s field_list , out a{sv} ) /org/freesmartphone/PIM/Contacts/Queries org.freedesktop.DBus.Introspectable methods Introspect( out s ) org.freesmartphone.PIM.ContactQuery methods GetContactPath( out s ) Skip( in i num_entries ) Dispose( ) GetResult( out a{sv} ) GetResultCount( out i ) Rewind( ) GetMultipleResults( in i num_entries , out aa{sv} ) /org/freesmartphone/PIM/Messages org.freedesktop.DBus.Introspectable methods Introspect( out s ) org.freesmartphone.PIM.Messages signals NewMessage( s message_URI ) methods GetSingleMessageSingleField( in a{sv} query , in s field_name , out s ) Query( in a{sv} query , out s ) Add( in a{sv} message_data , out s ) GetFolderURIFromName( in s folder_name , out s ) GetFolderNames( out as ) org.freesmartphone.PIM.Message methods GetContent( out a{sv} ) MoveToFolder( in s new_folder_name ) GetMultipleFields( in s field_list , out a{sv} ) /org/freesmartphone/PIM/Messages/Folders org.freedesktop.DBus.Introspectable methods Introspect( out s ) org.freesmartphone.PIM.Messages signals NewMessage( s message_URI ) methods GetSingleMessageSingleField( in a{sv} query , in s field_name , out s ) Query( in a{sv} query , out s ) Add( in a{sv} message_data , out s ) GetFolderURIFromName( in s folder_name , out s ) GetFolderNames( out as ) org.freesmartphone.PIM.Message methods GetContent( out a{sv} ) MoveToFolder( in s new_folder_name ) GetMultipleFields( in s field_list , out a{sv} ) /org/freesmartphone/PIM/Messages/Folders/0 org.freesmartphone.PIM.MessageFolder signals MessageMoved( s message_uri , s new_folder_name ) methods GetMessageCount( out i ) GetMessageURIs( in i first_message_id , in i message_count , out as ) org.freedesktop.DBus.Introspectable methods Introspect( out s ) /org/freesmartphone/PIM/Messages/Folders/1 org.freesmartphone.PIM.MessageFolder signals MessageMoved( s message_uri , s new_folder_name ) methods GetMessageCount( out i ) GetMessageURIs( in i first_message_id , in i message_count , out as ) org.freedesktop.DBus.Introspectable methods Introspect( out s ) /org/freesmartphone/PIM/Messages/Queries org.freedesktop.DBus.Introspectable methods Introspect( out s ) org.freesmartphone.PIM.MessageQuery methods Skip( in i num_entries ) Dispose( ) GetResult( out a{sv} ) GetResultCount( out i ) Rewind( ) GetMultipleResults( in i num_entries , out a{ia{sv}} ) GetMessageURI( out s ) /org/freesmartphone/PIM/Sources org.freesmartphone.PIM.Sources methods GetEntryCount( out i ) InitAllEntries( ) org.freedesktop.DBus.Introspectable methods Introspect( out s ) org.freesmartphone.PIM.Source methods GetSupportedPIMDomains( out as ) GetName( out s ) GetStatus( out s ) /org/freesmartphone/Phone org.freedesktop.DBus.Introspectable methods Introspect( out s ) org.freesmartphone.Phone signals Incoming( o call ) methods InitProtocols( out as ) CreateCall( in s number , in s protocol , in b force , out o ) /org/freesmartphone/Preferences org.freesmartphone.Preferences methods GetProfiles( out as ) GetService( in s name , out o ) GetServices( out as ) SetProfile( in s profile ) GetProfile( out s ) org.freedesktop.DBus.Introspectable methods Introspect( out s ) /org/freesmartphone/Preferences/rules org.freedesktop.DBus.Introspectable methods Introspect( out s ) org.freesmartphone.Preferences.Service signals Notify( s key , v value ) methods GetType( in s key , out s ) SetValue( in s key , in v value ) GetKeys( out as ) IsProfilable( in s key , out b ) GetValue( in s key , out v ) /org/freesmartphone/Time org.freedesktop.DBus.Introspectable methods Introspect( out s ) org.freesmartphone.Time signals Minute( i year , i mon , i day , i hour , i min , i sec , i wday , i yday , i isdst ) methods GetLocalTime( in i seconds , out i , out i , out i , out i , out i , out i , out i , out i , out i ) /org/freesmartphone/Time/Alarm org.freedesktop.DBus.Introspectable methods Introspect( out s ) org.freesmartphone.Time.Alarm methods ClearAlarm( in s busname ) SetAlarm( in s busname , in i timestamp ) /org/freesmartphone/Usage org.freesmartphone.Usage signals ResourceAvailable( s resourcename , b state ) ResourceChanged( s resourcename , b state , a{sv} attributes ) methods ReleaseResource( in s resourcename ) Suspend( ) GetResourceState( in s resourcename , out b ) SetResourcePolicy( in s resourcename , in s policy ) GetResourcePolicy( in s resourcename , out s ) GetResourceUsers( in s resourcename , out as ) ListResources( out as ) RegisterResource( in s resourcename , in o path ) RequestResource( in s resourcename ) org.freedesktop.DBus.Introspectable methods Introspect( out s )
下面是dteeth的源代码:
$ cat -n dteeth.py 1 #!/usr/bin/env python 2 # -*- coding: utf-8 -*- 3 4 import dbus 5 import _introspect_parser 6 import getopt, sys 7 8 MARGIN_WIDTH = 4 9 ONE_MARGIN = ' ' * MARGIN_WIDTH 10 11 # signal是个元组,它有一个元素,是一个列表。列表的元素是signal的参数 12 # 列表的每个元素都是字典。它有两个元素,键值分别是'type'和'name' 13 def show_signal(name, signal, margin): 14 print margin+name+'(', 15 args = signal[0] 16 for i, arg in enumerate(args): 17 if i > 0: 18 print ',', 19 if arg['name']: 20 print '%s %s' % (arg['type'], arg['name']), 21 else: 22 print '%s' % arg['type'], 23 print ')' 24 25 # method是个元组,它有两个元素,都是列表。前一个列表的元素是输入参数,后一个列表的元素是输出参数 26 def show_method(name, method, margin): 27 print margin+name+'(', 28 # 输入参数 29 args = method[0] 30 in_num = len(args) 31 out_num = len(method[1]) 32 for i, arg in enumerate(args): 33 if i > 0: 34 print ',', 35 if arg['name']: 36 print 'in %s %s' % (arg['type'], arg['name']), 37 else: 38 print 'in %s' % arg['type'], 39 # 输出参数 40 if (in_num > 0) and (out_num > 0) : 41 print ',', 42 args = method[1] 43 for i, arg in enumerate(args): 44 if i > 0: 45 print ',', 46 if arg['name']: 47 print 'out %s %s' % (arg['type'], arg['name']), 48 else: 49 print 'out %s' % arg['type'], 50 print ')' 51 52 def show_property(name, property, margin): 53 print margin+name 54 print margin, 55 print property 56 57 # interfaces是个字典,它有三个元素,键值分别是'signals'、'methods'和'properties' 58 def show_iface(name, iface, margin): 59 print margin + name 60 margin += ONE_MARGIN 61 signals=iface['signals'] 62 l = len(signals) 63 if l > 0: 64 print margin+'signals' 65 for node in signals: 66 show_signal(node, signals[node], margin+ONE_MARGIN) 67 68 methods=iface['methods'] 69 l = len(methods) 70 if l > 0: 71 print margin+'methods' 72 for node in methods: 73 show_method(node, methods[node], margin+ONE_MARGIN) 74 75 properties=iface['properties'] 76 l = len(properties) 77 if l > 0: 78 print margin+'properties' 79 for node in properties: 80 show_property(node, properties[node], margin+ONE_MARGIN) 81 82 def show_obj(bus, name, obj_name, margin): 83 obj=bus.get_object(name, obj_name) 84 iface=dbus.Interface(obj, 'org.freedesktop.DBus.Introspectable') 85 xml=iface.Introspect(); 86 data = _introspect_parser.process_introspection_data(xml) 87 88 # data是个字典,它有两个元素,键值分别是'child_nodes'和'interfaces' 89 if len(data['interfaces']) > 0: 90 print margin + obj_name 91 92 for node in data['interfaces']: 93 iface=data['interfaces'][node] 94 show_iface(node, iface, margin+ONE_MARGIN) 95 96 for node in data['child_nodes']: 97 if obj_name == '/': 98 show_obj(bus, name, '/' + node, margin) 99 else: 100 show_obj(bus, name, obj_name + '/' + node, margin) 101 102 def show_connection(bus, name, margin): 103 print margin + name 104 show_obj(bus, name, '/', margin+ONE_MARGIN) 105 106 def usage(): 107 print "Usage: dteeth [--system] " 108 109 def main(): 110 try: 111 opts, args = getopt.getopt(sys.argv[1:], "h", ["help", "system"]) 112 except getopt.GetoptError, err: 113 # print help information and exit: 114 print str(err) # will print something like "option -a not recognized" 115 usage() 116 sys.exit(2) 117 118 if len(args) == 0: 119 usage() 120 sys.exit(2) 121 122 use_system = False 123 for o, a in opts: 124 if o in ("-h", "--help"): 125 usage() 126 sys.exit() 127 if o == "--system": 128 use_system = True 129 else: 130 assert False, "unhandled option" 131 132 if use_system: 133 bus=dbus.SystemBus() 134 else: 135 bus=dbus.SessionBus() 136 137 for arg in args: 138 show_connection(bus, arg, "") 139 140 if __name__ == "__main__": 141 main()
dteeth是我写的第一个超过10行的python脚本。对于熟悉python的读者,dteeth应该是很简单的。不过我还是简单解释一下dteeth的主要逻辑。
main函数分析命令行,对命令行上指定的每个连接调用show_connection函数。 show_connection在打印连接名后调用show_obj从根对象"/"开始遍历连接的对象树。
show_obj对输入对象调用Introspect方法,返回的xml数据交由_introspect_parser处理。 _introspect_parser会从xml数据中分出inerface和node。 show_obj对inerface调用show_iface显示。 show_obj对node会递归调用show_obj,实现对象树的遍历。
_introspect_parser.process_introspection_data函数分析Introspect方法返回的xml数据。为了了解_introspect_parser的输出格式,我们可以写个小脚本:
$ cat ti.py #!/usr/bin/env python import dbus import _introspect_parser bus=dbus.SessionBus() obj=bus.get_object('org.freesmartphone.ogsmd', '/org/freesmartphone/GSM/Device') iface=dbus.Interface(obj, 'org.freedesktop.DBus.Introspectable') xml=iface.Introspect(); data = _introspect_parser.process_introspection_data(xml) print data
可以用这个脚本直接打印process_introspection_data返回的数据。下面是整理后的输出:
{ 'interfaces': { u'org.freedesktop.DBus.Introspectable': { 'signals': {}, 'methods': { u'Introspect': ( [], [{'type': u's', 'name': u'data'}] ) }, 'properties': {} }, u'org.freedesktop.DBus.Properties': { 'signals': {}, 'methods': { u'Set': ( [{'type': u's', 'name': u'interface'}, {'type': u's', 'name': u'propname'}, {'type': u'v', 'name': u'value'}], [] ), u'GetAll': ( [{'type': u's', 'name': u'interface'}], [{'type': u'a{sv}', 'name': u'props'}] ), u'Get': ( [{'type': u's', 'name': u'interface'}, {'type': u's', 'name': u'propname'}], [{'type': u'v', 'name': u'value'}] ) }, 'properties': {} }, u'org.freesmartphone.GSM.SMS': { 'signals': { u'IncomingMessage': ( [{'type': u's', 'name': None}, {'type': u's', 'name': None}, {'type': u'a{sv}', 'name': None}], ) }, 'methods': { u'SendMessage': ( [{'type': u's', 'name': u'number'}, {'type': u's', 'name': u'contents'}, {'type': u'a{sv}', 'name': u'featuremap'}], [{'type': u'i', 'name': u'arg3'}] ) }, 'properties': {} } }, 'child_nodes': [] }
所有字符串前面都有前缀u,表示这些字符串都是Unicode编码。在python中,字典用{},元组用(),列表用[]。从括号我们就能看出数据格式。
我们看到process_introspection_data返回返回一个字典。这个字典有两个映射。一个映射的键值是"interfaces",另一个映射的键值是"child_nodes"。
映射"child_nodes"的值是一个列表,列出所有子节点的名称。
映射"interfaces"的值还是一个字典。这个字典的每个映射的键值是一个接口名称。每个映射的值类型还是字典, 这个字典有3个映射,映射的键值分别是'signals'、'methods'和'properties',映射的值类型都是字典。
'signals'对应字典的每个键值是一个信号名称。每个映射的值类型是元组。这个元组只有一个元素,类型是列表, 即信号的参数列表。
参数列表的元素类型是字典。这个字典有2个映射,映射的键值分别是'type'和'name'。'type'是参数类型,'name'是参数名称。 映射的值类型都是字符串。
'methods'对应字典的每个键值是一个方法名称。每个映射的值类型是元组。这个元组有两个元素,类型是列表, 分别是方法的输入参数列表和输出参数列表。参数列表的元素类型和信号的参数列表相同。
我看到'properties'映射都是空的,就没有研究。
简单介绍一下与dteeth有关的python语法。
python用缩进来区分语句所属的代码块,从类定义、函数到for、if的代码块都是用缩进来去区分的。没有缩进的代码块是脚本的主体代码。一个 脚本文件也被称作一个模块。不管模块被直接运行还是被其它模块导入,主体代码都会在载入时被执行。例如dteeth的主体代码只有两句:
140 if __name__ == "__main__": 141 main()
__xxx__这样的标志符通常是python的系统变量。如果模块被导入,__name__的值是模块的名字。如果模块被直接执行,__name__的值是"__main__"。我们通常在模块被直接执行时,调用主函数或模块的测试函数。
python脚本的起始行通常是:/p>
1 #!/usr/bin/env python
env是一个可以修改环境变量并执行程序的工具,它可以自动在系统路径中搜索要执行的程序。 python脚本文件必须以0A为换行符,默认仅支持ASCII字符。如果要写中文注释(显然是不提倡的),可以在起始行后用以下语句将文件指定为utf-8编码:
2 # -*- coding: utf-8 -*-
这时,文件必须被保存为没有BOM的utf-8编码文件。
列表类似于C的数组,列表元素用[]包括。元组是不可变的列表,元组元素用()包括。元组的元素个数和类型在创建后就不能改变了。元组中基本类型的值是不能改变的,但如果元组的一个元素是列表,我们可以改变列表内容,即我们可以改变元组中可变元素的内容。例如:
>>> a=(1,2,['abc']) >>> a[2]='def' Traceback (most recent call last): File "", line 1, in TypeError: 'tuple' object does not support item assignment >>> a[2][0]='def' >>> a (1, 2, ['def'])
字典是键-值对的集合,字典元素用{}包括。
本文介绍了一个叫作dteeth的python脚本。这个脚本逻辑很简单,读者可以根据需要修改或扩充。讲了这么多dbus,我们还没有接触C代码。下一讲,我们讨论dbus的C实例。