[android源码分析]bluez启动过程中的各种plugin的初始化(一)--__bluetooth_builtin数组所耍的花样
在bluez启动过程中,各种插件的初始化尤为重要,没有这些插件,很多功能将无法实现。
2.3.5 plugin的初始化
插件的初始化,是什么的干活,其实还是很重要的,我们来看看吧。
gboolean plugin_init(GKeyFile *config, const char *enable, const char *disable)
{
GSList *list;
GDir *dir;
const gchar *file;
char **conf_disabled, **cli_disabled, **cli_enabled;
unsigned int i;
/* Make a call to BtIO API so its symbols got resolved before the
* plugins are loaded. */
//不知道这里调了干嘛
bt_io_error_quark();
//有config文件,会去解析General中的DisablePlugins,我们其实可以看到它是没有的
if (config)
conf_disabled = g_key_file_get_string_list(config, "General",
"DisablePlugins",
NULL, NULL);
else
conf_disabled = NULL;
//这个enable是null,所以忽略
if (enable)
cli_enabled = g_strsplit_set(enable, ", ", -1);
else
cli_enabled = NULL;
//disable也是null,忽略
if (disable)
cli_disabled = g_strsplit_set(disable, ", ", -1);
else
cli_disabled = NULL;
DBG("Loading builtin plugins");
//这里是遍历__bluetooth_builtin数组了,__bluetooth_builtin数组这里有必要详细解释一下,见2.3.5.1
for (i = 0; __bluetooth_builtin[i]; i++) {
//enable_plugin因为conf_disabled,cli_enabled,cli_disabled均为null,所以什么都没有做,直接return true了
if (!enable_plugin(__bluetooth_builtin[i]->name, conf_disabled,
cli_enabled, cli_disabled))
continue;
//下面就是加入plugin了,这里又会发生些什么好玩的东西呢,我们看2.3.5.2
add_plugin(NULL, __bluetooth_builtin[i]);
}
//看是否有PLUGINDIR,从Android.mk中可以发现:
/*-DPLUGINDIR=\"/system/lib/bluez-plugin\*/
//PLUGINDI就是/system/lib/bluez-plugin这个目录,所以,我们这里要继续往下看了
if (strlen(PLUGINDIR) == 0)
goto start;
DBG("Loading plugins %s", PLUGINDIR);
//打开这个路径
dir = g_dir_open(PLUGINDIR, 0, NULL);
if (!dir)
goto start;
//打开这个文件夹,并去除每个文件的名字
while ((file = g_dir_read_name(dir)) != NULL) {
struct bluetooth_plugin_desc *desc;
void *handle;
gchar *filename;
//以lib开头,或者不以.so结尾,我们都认为是有问题的,直接跳出
if (g_str_has_prefix(file, "lib") == TRUE ||
g_str_has_suffix(file, ".so") == FALSE)
continue;
//filename就是该文件的包含目录的完整文件名
filename = g_build_filename(PLUGINDIR, file, NULL);
//打开这个动态库
handle = dlopen(filename, RTLD_NOW);
if (handle == NULL) {
error("Can't load plugin %s: %s", filename,
dlerror());
g_free(filename);
continue;
}
g_free(filename);
//找到bluetooth_plugin_desc
desc = dlsym(handle, "bluetooth_plugin_desc");
if (desc == NULL) {
error("Can't load plugin description: %s", dlerror());
dlclose(handle);
continue;
}
//使能,什么都不做,和上面一样
if (!enable_plugin(desc->name, conf_disabled,
cli_enabled, cli_disabled)) {
dlclose(handle);
continue;
}
//加到plugin中去,最终plugin中包含hciops, audio,health,input,network
if (add_plugin(handle, desc) == FALSE)
dlclose(handle);
}
start:
for (list = plugins; list; list = list->next) {
struct bluetooth_plugin *plugin = list->data;
//调用对应的plugin的init函数,以hciops为例进行分析,详细见2.3.5.3
if (plugin->desc->init() < 0) {
error("Failed to init %s plugin", plugin->desc->name);
continue;
}
//把active置位true
plugin->active = TRUE;
}
g_strfreev(conf_disabled);
g_strfreev(cli_enabled);
g_strfreev(cli_disabled);
return TRUE;
}
2.3.5.1 __bluetooth_builtin数组所耍的花样
呵呵,这个数组我看了有一会了,为什么呢?因为他里面用了一些我们所谓的奇淫技巧,这样的代码用起来是蛮方便的,可是等别人去阅读的时候就是个悲剧啊。
首先,很简单,我们去搜索一下,立即就能发现这个数组的定义:
extern struct bluetooth_plugin_desc __bluetooth_builtin_hciops;
static struct bluetooth_plugin_desc *__bluetooth_builtin[] = {
&__bluetooth_builtin_hciops,
NULL };
简单吧,里面就只有一个元素:&__bluetooth_builtin_hciops,这个元素是extern的,肯定就是在别的地方定义啦,于是去搜索一下呗,奶奶个熊的,你发现搜索不到这个东西,没有&__bluetooth_builtin_hciops啊,要崩溃了吧,哈哈。
在某一个月黑风高的夜晚,我咬着铅笔头,冥思苦想这个问题,突然间,我发现这个hciops好熟悉,bluez里面有这个文件啊,就决定去这个文件里面看看,在不起眼的最后一行,发现了如下语句:
BLUETOOTH_PLUGIN_DEFINE(hciops, VERSION,
BLUETOOTH_PLUGIN_PRIORITY_LOW, hciops_init, hciops_exit)
plugin的define,嗯?有点意思,赶快去看看。于是跳转到这个BLUETOOTH_PLUGIN_DEFINE定义的地方:
//在Android.mk中,这个define是有的,所以,就看上面的,不看else了
#ifdef BLUETOOTH_PLUGIN_BUILTIN
//于是根据这个定义,把上面的宏替代之后就是:
/*
struct bluetooth_plugin_desc __bluetooth_builtin_hciops = {
hciops, VERSION, BLUETOOTH_PLUGIN_PRIORITY_LOW, hciops_init, hciops_exit
};
*/
//哈哈,众里寻他千百度啊,简单吧~~嘻嘻。。
#define BLUETOOTH_PLUGIN_DEFINE(name, version, priority, init, exit) \
struct bluetooth_plugin_desc __bluetooth_builtin_ ## name = { \
#name, version, priority, init, exit \
};
#else
#define BLUETOOTH_PLUGIN_DEFINE(name, version, priority, init, exit) \
extern struct bluetooth_plugin_desc bluetooth_plugin_desc \
__attribute__ ((visibility("default"))); \
struct bluetooth_plugin_desc bluetooth_plugin_desc = { \
#name, version, priority, init, exit \
};
#endif
额外资讯:
大家继续往后面看会发现,android加载别的plugin的方法是遍历system/lib/bluez-plugin目录下的动态库,从而进行加载的,然后在原生bluez中则不是这样实现的。因为实现的方法实在不错,所以这里也简单介绍一下:
就在我开开心心地以为我自己很牛x的时候,打印了一下__bluetooth_builtin数组,突然发现它里面不止一个hicops,然后赶紧偷偷搜索了一下BLUETOOTH_PLUGIN_DEFINE,发现它出来了竟然有近十个,啊~~这些东东都是什么时候加进去的啊?
继续来搜索__bluetooth_builtin,这次把非c文件也搜索了下,我坚信肯定是makefile或者什么别的文件在捣乱。呵呵,果然,找到了src下面的genbuiltin文件,我们来看一下写的什么:
#!/bin/sh
for i in $*
do
echo "extern struct bluetooth_plugin_desc __bluetooth_builtin_$i;"
done
echo
echo "static struct bluetooth_plugin_desc *__bluetooth_builtin[] = {"
for i in $*
do
echo " &__bluetooth_builtin_$i,"
done
echo " NULL"
echo "};"
#从这个文件就可以看出来个大概了,看样子,他们把__bluetooth_builtin_**别的东西都加入到了*__bluetooth_builtin这个数组中去了。考虑到这个文件是一个shell的文件,$*就是所有传入的参数了,我们去看调用他的地方吧,所以,我们继续搜索一下genbuiltin。哈哈,果然找到了,藏得还蛮深的嘛,小样:
在Makefile.am文件中:
//第一行就是要编译的文件
src/builtin.h: src/genbuiltin $(builtin_sources)
//这个就是输入到$@文件中,就是builtin.h中,所以,我们后面看到的builtin文件其实是已经改变过的,至于builtin_modules就是根据各种宏定义来取舍的,具体大家自己去分析了,我就不再多说了
$(AM_V_GEN)$(srcdir)/src/genbuiltin $(builtin_modules) > $@
至此,__bluetooth_builtin数组就分析完成了,哎~,奇淫技巧,呵呵~~
若您觉得该文章对您有帮助,请在下面用鼠标轻轻按一下“顶”,哈哈~~·