我想在freerunner(一个开源linux手机)上查看fso(openmoko的诸多软件版本之一)的dbus信息。但fso的 python没有gtk模块,跑不了d-feet。在上一讲我介绍了d-feet的基本思路:用 “org.freedesktop.DBus.ListNames”枚举消息总线上的连接,用 “org.freedesktop.DBus.Introspectable.Introspect” 从"/"开始遍历连接的对象树。上一讲我们手工查看了两个连接,那么我们能不能写一个程序自动遍历连接的对象树,输出指定连接的所有对象的所有接口的所有 方法和信号?
当然可以,为此我写了一个叫dteeth的python脚本。不过在介绍这个脚本前,让我们先看看dbus的数据类型。
1、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后面的标记决定。例如:
- "as"是字符串数组。
- 数组"a(i(ii))"的元素是一个结构。用括号将成员的类型括起来就表示结构了,结构可以嵌套。
- 数组"a{sv}"的元素是一个键-值对。"{sv}"表示键类型是字符串,值类型是VARIANT。
在以后的例子中,我们会亲手实现上面这个xml描述的接口,包括服务器和客户程序。到时候,读者会对dbus的数据类型有更直观的认识。
2、dteeth
2.1、运行dteeth
可以从这里 下载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 )
2.2、源代码
下面是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的主要逻辑。
2.3、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,实现对象树的遍历。
2.4、_introspect_parser的输出格式
_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'映射都是空的,就没有研究。
-
3、python基础
简单介绍一下与dteeth有关的python语法。
3.1、代码块和缩进
python用缩进来区分语句所属的代码块,从类定义、函数到for、if的代码块都是用缩进来去区分的。没有缩进的代码块是脚本的主体代码。一个 脚本文件也被称作一个模块。不管模块被直接运行还是被其它模块导入,主体代码都会在载入时被执行。例如dteeth的主体代码只有两句:
140 if __name__ == "__main__":
141 main()
__xxx__这样的标志符通常是python的系统变量。如果模块被导入,__name__的值是模块的名字。如果模块被直接执行,__name__的值是"__main__"。我们通常在模块被直接执行时,调用主函数或模块的测试函数。
3.2、脚本文件格式
python脚本的起始行通常是:/p>
1 #!/usr/bin/env python
env是一个可以修改环境变量并执行程序的工具,它可以自动在系统路径中搜索要执行的程序。 python脚本文件必须以0A为换行符,默认仅支持ASCII字符。如果要写中文注释(显然是不提倡的),可以在起始行后用以下语句将文件指定为utf-8编码:
2 # -*- coding: utf-8 -*-
这时,文件必须被保存为没有BOM的utf-8编码文件。
3.3、列表、元组和字典
列表类似于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'])
字典是键-值对的集合,字典元素用{}包括。
4、结束语
本文介绍了一个叫作dteeth的python脚本。这个脚本逻辑很简单,读者可以根据需要修改或扩充。讲了这么多dbus,我们还没有接触C代码。下一讲,我们讨论dbus的C实例。