转载请标明出处
出错现象:
1. 图形界面点击“关于我”,没有反应;
2. 在Terminal中使用user用户执行gnome-about-me,出现以下错误信息。
-
-
zhangs@debian:~/桌面$ gnome-about-me -v
-
(gnome-about-me:2046): libebook-WARNING **: e-book.c:2245: cannot get book from factory: Invalid source
-
(gnome-about-me:2046): libebook-WARNING **: e-book.c:2245: cannot get book from factory: Invalid source
-
about-me-properties-ERROR **: Invalid source
-
aborting...
-
Aborted
-
Debug 过程:
(Debug过程中,有许多尝试性的动作,会“混淆视听”,所以这里就略去这些地方,只记录一下关键技术点。)
1. 首先查看gnome-about-me的源码;
查看gnome-about-me属于哪一个源码包,直接从源里下载其source code包,并解压缩。
-
dpkg -S $(which gnome-about-me)
-
gnome-control-center: /usr/bin/gnome-about-me
-
apt-get source gnome-control-center
使用
-
dpkg-source -x gnome-control-center_2.32.0-0ubuntu2.dsc解压缩(apt-get source会帮忙做掉)
dpkg-source 包含在dpkg-dev工具包内,需要安装dpkg-dev。
(事实过程中,gnome-about-me的代码,没有看出端倪。根据出错的提示信息,下载了e-book.c的相关代码,即evolution-data-server,步骤基本同上。)
2. 追查evolution-data-server的代码;
evolution-data-server的代码量还是不小。
-
Find . –name “*.c” | xargs wc –l
-
324054 总用量
无论如何,我们找到e-book.c,并且得到了如下的函数调用关系图:
整个代码摸索下来,得到两点有用的信息。
a) gnome-about-me 配合 evlution-data-server的工作方式,是通过dbus来实现的。(事实上,Linux的桌面程序大多都是dbus实现。)
b) 针对此问题,基本锁定impl_BookFactory_getBoot()函数。
重点来查看impl_BookFactory_getBook():
函数中,有两处地方会报出 ”Invalid source” 的错误:
-
if (!source)
-
if (backend == NULL) // 亦与source有关
看得出source是函数传入的。
这个函数比较"特别",在g_signal_connect的时候,只传入两个参数。而在函数原型这里,有四个参数。如下:
-
g_signal_connect (factory->priv->gdbus_object, "handle-get-book",
-
G_CALLBACK (impl_BookFactory_getBook), factory);
-
-
static gboolean
-
impl_BookFactory_getBook (EGdbusBookFactory *object,
-
GDBusMethodInvocation *invocation,
-
const gchar *in_source,
-
EDataBookFactory *factory)
这里就有一个此前没接触的Closure和Marshal的概念:在handle-get-book信号的g_signal_new中,调用了GSignalCMarshaller c_marshaller。
一般而言,这个函数命名,会将返回值参数表现出来,这里的函数名:
-
void _e_gdbus_gdbus_cclosure_marshaller_BOOLEAN__OBJECT_STRING()
(我的理解,marshal是通过闭包Closure用来指定g_signal_new新建出来的信号的callback的函数原型(参数、返回值等),不是很深刻。)
所以,现在看起来,impl_BookFactory_getBook()的参数,是g_signal_emit的时候传入的,但是在handle_method_call的参数如何传入,没追出来,所以采取最直接的加printf语句的方式。
编译的时候,遇到些问题。
可以使用autoconf等工具包,debian系的也可以使用dpkg-buildpackage 和 apt-get build-dep来解决配置和依赖的问题,比较傻瓜化,还有一些依赖关系可能需要手动解决。
打印出来发现,是因为backend出问题导致gnome-about-me出错。
在if (backend == NULL)后,有一个:
-
// 先
-
backend_factory = e_data_book_factory_lookup_backend_factory (factory, uri);
-
// 后接着
-
backend = e_book_backend_factory_new_backend (backend_factory)
的动作,即重新得到一个backend_factory并再生成backend。
根据打印信息,evolution-data-server在factory注册backend的时候(e_data_book_factory_register_backends (factory))有一个proto的概念,proto作为hash表的一个key值,对应着某个backend(这个地方其实不是很了解)。在几个backend中,有一个关于file的EBookBackendFileFactory。
Backend的hash表中的key(proto)最终是从impl_BookFactory_getBook()的const gchar *in_source参数得来的。其调用关系如下:
-
proto = e_data_book_factory_extract_proto_from_uri (uri);
-
uri = e_source_get_uri (source);
-
source = e_source_new_from_standalone_xml (in_source);
整个过程的总结:
gnome-about-me提供了一个in_source,evolution-data-server根据这个in_source提供backend,而且evolution-data-server有一些鲁棒性的设置,在backend出错时有一些补救措施。
这里关键值的打印出来如下:
in_source是:
-
<?xml version="1.0"?>
-
<source uid="1337793487.2176.0@debian" name="" uri="file:///home/zhangs/.evolution/addressbook/local/system"/>
source是个结构,没打印出来,是中间形态。
uri是source->priv->absolute_uri,
即 "file:///home/zhangs/.evolution/addressbook/local/system";
proto是
即"file"。
而在evolution-data-server这一端,有关file的backend在hash表里的key(proto)是local,见函数 static
-
const gchar * book_backend_file_factory_get_protocol (EBookBackendFactory *factory) {
-
return "local";
-
}
这样一来两端就无法对上了,gnome-about-me端提出的proto申请时file协议,而evolution-data-server端提供的是local协议。导致gnome-about-me执行出错。
针对此,有两种策略,修改服务端或者客户端。
我们再去查evoluton-data-server的源码,发现这个问题在2.xx.xx版本根本就没修复,即维护者不认为这是个bug,故修改服务端不是很妥当。
第二步,修改客户端,编译gnome-about-me。
事实上,gnome-about-me调用了evolutio-data-server的接口,本身将请求写死为"local:system"。正常的in_source应该如下:
-
<?xml version="1.0"?>
-
<source uid="1337793342.2158.0@debian" name="" uri="local:system"/>
可能是我遇到的gnome-control-cneter比较奇怪吧。
故如果系统出现这个问题,请先卸载gnome-control-center并再安装一遍试试?
============
总结 :
虽然最后的结论有点电影《阅后即焚》的味道,但在调试过程中,学习到不少东西!
阅读(2147) | 评论(1) | 转发(0) |