[android源码分析]bluetoothd service的启动的总体流程分析

本篇文章将会从总体流程上解释一下每一个函数的意义,具体的每一个函数的解释将是一个很长的过程,后面的文章中我将会针对每一个有意义的函数来具体分析。

在具体分析bluetoothdservice的启动之前,我们先来看一下bluetoothd service究竟是什么,他同样定义在init.rc中:

servicebluetoothd /system/bin/bluetoothd -n

所以,很清楚,他就是执行bluetoothd这个应用。那么bluetoothd是由哪个文件编译出来的呢,搜索一下就会在bluez下面的src中的Android.mk发现其踪迹:

#
# bluetoothd
#

include $(CLEAR_VARS)

LOCAL_SHARED_LIBRARIES := \
	libbluetoothd

LOCAL_MODULE:=bluetoothd

所以,很清楚了,我们就在src目录下面看一下了,作为一个应用程序,第一个映入我们眼帘的肯定就是main了,正好下面有一个main.c,然后里面还有一个main函数,哈哈,你懂的:

int main(int argc, char *argv[])
{
	GOptionContext *context;
	GError *err = NULL;
	struct sigaction sa;
	uint16_t mtu = 0;
	GKeyFile *config;
//这个函数就是用来设置uid和capability的,他主要是使得该应用在访问kernel的时候能够有权限
//从注册可以看到,说目前的android init rc并不支持权限的赋予,所以只能出此下策,毫无疑问,我们需要走到这个ifdef中
//当然我们也可以从理论上去check一下,在Android.mk中是有这个宏的define的
#ifdef ANDROID_SET_AID_AND_CAP
	/* Unfortunately Android's init.rc does not yet support applying
	 * capabilities. So we must do it in-process. */
	void *android_set_aid_and_cap(void);
	//这个就是设置uid为AID_BLUETOOTH,
	//设置capbility为CAP_NET_RAW| CAP_NET_ADMIN| CAP_NET_BIND_SERVICE
	android_set_aid_and_cap();
#endif
	//默认的初始化,详细分析见2.2.1
	init_defaults();
//既然我们上面已经想法设法得到权限了,这里就必然不会再把权限释放了。
//这个ifdef是不会进去了
#ifdef HAVE_CAPNG
	/* Drop capabilities */
	capng_clear(CAPNG_SELECT_BOTH);
	capng_updatev(CAPNG_ADD, CAPNG_EFFECTIVE | CAPNG_PERMITTED,
					CAP_NET_BIND_SERVICE, CAP_NET_ADMIN,
						CAP_NET_RAW, CAP_IPC_LOCK, -1);
	capng_apply(CAPNG_SELECT_BOTH);
#endif
	//这里是解析命令项
	//使用的是glib命令行解析库
	context = g_option_context_new(NULL);
	//就是根据options定义的内容,自动解析到对应的变量中了
	//详细见2.2.2
	g_option_context_add_main_entries(context, options, NULL);

	if (g_option_context_parse(context, &argc, &argv, &err) == FALSE) {
		if (err != NULL) {
			g_printerr("%s\n", err->message);
			g_error_free(err);
		} else
			g_printerr("An unknown error occurred\n");
		exit(1);
	}

	g_option_context_free(context);
	//下面就是根据上面解析得到的值来看是否需要做一些对应的操作
	//从init rc中,我们可以看到只有一个-n的参数,但是,我们看是G_OPTION_FLAG_REVERS,猜猜看吧,是的,就是反转的意思,所以option_detach还是false,其它的就都可以忽略了
	if (option_version == TRUE) {
		printf("%s\n", VERSION);
		exit(0);
	}

	if (option_udev == TRUE) {
		int err;

		option_detach = TRUE;
		err = connect_dbus();
		if (err < 0) {
			if (err == -EALREADY)
				exit(0);
			exit(1);
		}
	}
	//后台运行,这里也就不去
	if (option_detach == TRUE && option_udev == FALSE) {
		if (daemon(0, 0)) {
			perror("Can't start daemon");
			exit(1);
		}
	}
	//重新设置权限
	umask(0077);
	//bt log的初始化,这里就不关心了,android中若想打印log需要重新修改
	__btd_log_init(option_debug, option_detach);
	//设置一个signal的处理函数,不一一看了,关系不大
	memset(&sa, 0, sizeof(sa));
	sa.sa_flags = SA_NOCLDSTOP;
	sa.sa_handler = sig_term;
	sigaction(SIGTERM, &sa, NULL);
	sigaction(SIGINT,  &sa, NULL);

	sa.sa_handler = sig_debug;
	sigaction(SIGUSR2, &sa, NULL);

	sa.sa_handler = SIG_IGN;
	sigaction(SIGPIPE, &sa, NULL);
	//加载配置文件
	config = load_config(CONFIGDIR "/main.conf");
	//解析配置文件,这里就是根据main.conf中的配置进行相应的设置
	//详细分析见2.2.3
	parse_config(config);
	//这里就是初始化dbus
	agent_init();

	if (option_udev == FALSE) {
		//连接dbus
		if (connect_dbus() < 0) {
			error("Unable to get on D-Bus");
			exit(1);
		}
	} else {
		if (daemon(0, 0)) {
			perror("Can't start daemon");
			exit(1);
		}
	}
	//启动sdp server,详细分析见2.2.4
	start_sdp_server(mtu, main_opts.deviceid, SDP_SERVER_COMPAT);
	//在main.conf中attrib_server=false,所以这里就不进入了
	if (main_opts.attrib_server) {
		if (attrib_server_init() < 0)
			error("Can't initialize attribute server");
	}
	/* Loading plugins has to be done after D-Bus has been setup since
	 * the plugins might wanna expose some paths on the bus. However the
	 * best order of how to init various subsystems of the Bluetooth
	 * daemon needs to be re-worked. */
//从注释来看,plugins的加载最好是在D-Bus已经建立完成的基础上。
//他们也认为这个地方做好再重写一下,我们就先将就着看看吧
//这里的option_plugin和option_noplugin都是null,因为我们的bluetoothd中并没有他们的参数
//包含了hciops,audio,input,network,health
//具体参见2.2.5中
	plugin_init(config, option_plugin, option_noplugin);
	//创建主循环
	event_loop = g_main_loop_new(NULL, FALSE);
	//adapter的ops的建立,详细分析见2.2.6
	if (adapter_ops_setup() < 0) {
		error("adapter_ops_setup failed");
		exit(1);
	}
	//会根据remember_powered参数来决定是否需要做什么,我们这里是是false,所以,没有做什么,直接ruturn。
	rfkill_init();

	DBG("Entering main loop");
	//进入主循环,就卡在这边了。
	//对主循环的影响都在上面的那些signal的处理函数中,我们可以理解,没有什么异常就会卡在这边了,知道蓝牙关闭才会退出了
	g_main_loop_run(event_loop);
	//之后的内容就不再详细分析了
	……
}


若您觉得该文章对您有帮助,请在下面用鼠标轻轻按一下“顶”,哈哈~~·

### Android 14 蓝牙功能的源码解析 #### 源码结构概述 Android 的蓝牙架构分为多个层次,每一层负责不同的职责。具体来说: - **应用层**:提供给开发者使用的 API 接口以及基于这些接口开发的应用程序[^3]。 - **Framework 层**:这一层主要包含了 Android 系统向应用程序暴露出来的蓝牙相关接口。它允许上层应用通过标准的方式访问底层硬件资源。 - **Bluetooth Service 层**:实现了各个蓝牙配置文件(Profile) 和适配器(Adapter),并提供了服务端的功能实现。此层还支持通过 AIDL (Android Interface Definition Language) 方式与其他组件交互调用和接收回调消息。 - **Bluedroid 协议栈**:这是整个蓝牙系统的最下层部分,直接处理蓝牙协议的具体细节。在此之上构建了所有高级别的特性和服务。值得注意的是,在 Bluedroid 中仅实现了 A2DP Source 角色;而在其他一些平台如 BlueZ,则同时支持 Source 和 Sink 双重角色[^2]。 对于 Android 14 版本而言,其蓝牙模块仍然遵循上述分层设计原则,并且继续优化和完善现有功能。为了更好地理解 Android 14 的蓝牙工作原理及其内部机制,可以从以下几个方面入手分析源代码: #### 启动过程中的初始化操作 当设备开机启动时,系统会加载必要的驱动程序来使能蓝牙芯片,并完成基本设置。这部分逻辑通常位于 `init.rc` 文件中定义的服务脚本里。一旦完成了初步设定之后,就会触发 Bluetooth HAL(Hardware Abstraction Layer) 来进一步初始化蓝牙子系统[^1]。 ```bash service bluetooth /system/bin/bluetoothd \ --noplugin=a2dp,audio_policy \ --enable-bt-sco-for-media-audio=true ``` 这段命令展示了如何在 init 配置文件中指定要运行的服务及其参数选项。 #### 主要类与方法介绍 在整个框架内有几个核心类扮演着重要角色,比如 `BluetoothAdapter`, 它作为连接到物理蓝牙控制器的主要入口点;还有像 `BluetoothManagerService` 这样的服务类用于管理不同类型的蓝牙连接状态变化事件监听等业务逻辑。 另外,在 Bluedroid 实现层面也存在许多关键函数用来控制具体的通信流程,例如 `a2dp_source_init()` 函数就是专门针对 A2DP 数据传输路径所做的准备工作之一。 #### 日志调试工具利用 最后但同样重要的一步是在实际开发过程中充分利用日志记录功能来进行问题排查。确保能够编译默认演示项目并将固件烧录至目标板卡(如 ESP32),同时也能够在终端界面上获取详细的调试信息输出[^4]。 ```cpp #include "esp_log.h" #define LOG_TAG "BT_DEBUG" ESP_LOGI(LOG_TAG, "Initializing Bluetooth..."); // 更多的日志打印语句... ``` 以上便是关于 Android 14 蓝牙功能的一个大致源码剖析方向指引。当然这只是冰山一角,更深入的学习还需要读者亲自去探索官方文档和技术论坛上的资料。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值