Chinaunix首页 | 论坛 | 博客
  • 博客访问: 229985
  • 博文数量: 14
  • 博客积分: 167
  • 博客等级: 入伍新兵
  • 技术积分: 274
  • 用 户 组: 普通用户
  • 注册时间: 2012-02-29 13:28
文章分类

全部博文(14)

文章存档

2014年(5)

2013年(4)

2012年(5)

我的朋友

分类: LINUX

2012-05-23 15:29:02

转载请标明出处

出错现象:
1.  图形界面点击“关于我”,没有反应;
2.  在Terminal中使用user用户执行gnome-about-me,出现以下错误信息。


  1. 点击(此处)折叠或打开

    1. zhangs@debian:~/桌面$ gnome-about-me -v
    2. (gnome-about-me:2046): libebook-WARNING **: e-book.c:2245: cannot get book from factory: Invalid source
    3. (gnome-about-me:2046): libebook-WARNING **: e-book.c:2245: cannot get book from factory: Invalid source
    4. about-me-properties-ERROR **: Invalid source
    5. aborting...
    6. Aborted


Debug 过程:
   (Debug过程中,有许多尝试性的动作,会“混淆视听”,所以这里就略去这些地方,只记录一下关键技术点。)

1.  首先查看gnome-about-me的源码;
查看gnome-about-me属于哪一个源码包,直接从源里下载其source code包,并解压缩。

  1. dpkg -S $(which gnome-about-me)
  2. gnome-control-center: /usr/bin/gnome-about-me
  3. apt-get source gnome-control-center
使用
  1. 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的代码量还是不小。
  1. Find . –name “*.c” | xargs wc –l
  2. 324054 总用量
无论如何,我们找到e-book.c,并且得到了如下的函数调用关系图:


整个代码摸索下来,得到两点有用的信息。
a)  gnome-about-me 配合 evlution-data-server的工作方式,是通过dbus来实现的。(事实上,Linux的桌面程序大多都是dbus实现。)
b)  针对此问题,基本锁定impl_BookFactory_getBoot()函数。

重点来查看impl_BookFactory_getBook():
函数中,有两处地方会报出 ”Invalid source” 的错误:
  1. if (!source)
  2. if (backend == NULL) // 亦与source有关
看得出source是函数传入的。

这个函数比较"特别",在g_signal_connect的时候,只传入两个参数。而在函数原型这里,有四个参数。如下:
  1. g_signal_connect (factory->priv->gdbus_object, "handle-get-book",
  2.                     G_CALLBACK (impl_BookFactory_getBook), factory);

  3. static gboolean
  4. impl_BookFactory_getBook (EGdbusBookFactory *object,
  5.                             GDBusMethodInvocation *invocation,
  6.                             const gchar *in_source,
  7.                             EDataBookFactory *factory)

这里就有一个此前没接触的Closure和Marshal的概念:在handle-get-book信号的g_signal_new中,调用了GSignalCMarshaller c_marshaller。
一般而言,这个函数命名,会将返回值参数表现出来,这里的函数名:
  1. 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)后,有一个:
  1. //
  2. backend_factory = e_data_book_factory_lookup_backend_factory (factory, uri);
  3. // 后接着
  4. 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参数得来的。其调用关系如下:
  1. proto = e_data_book_factory_extract_proto_from_uri (uri);
  2. uri = e_source_get_uri (source);
  3. 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是:
  1. <?xml version="1.0"?>
  2. <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
  1. p = strchr (uri, ':');
    即"file"。

而在evolution-data-server这一端,有关file的backend在hash表里的key(proto)是local,见函数 static
  1. const gchar * book_backend_file_factory_get_protocol (EBookBackendFactory *factory) {
  2.     return "local";
  3. }
这样一来两端就无法对上了,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应该如下:

  1. <?xml version="1.0"?>
  2. <source uid="1337793342.2158.0@debian" name="" uri="local:system"/>
可能是我遇到的gnome-control-cneter比较奇怪吧。

故如果系统出现这个问题,请先卸载gnome-control-center并再安装一遍试试?

============
总结 :
虽然最后的结论有点电影《阅后即焚》的味道,但在调试过程中,学习到不少东西!


阅读(2147) | 评论(1) | 转发(0) |
给主人留下些什么吧!~~

快活王怜花2012-05-28 15:45:48