[Android源码分析]bluez中adapter初始化分析

作为一个程序员,咋废话就不多说了,直接看代码吧,哈哈~~

2adapter的初始化

gboolean adapter_init(struct btd_adapter *adapter)
{
	int err;

	/* adapter_ops makes sure that newly registered adapters always
	 * start off as powered */
	//置up位,为什么不放到最后在置位啊
	adapter->up = TRUE;
	//读bdaddr,这个就是得到dev的bdaddr到adapter->bdaddr
	adapter_ops->read_bdaddr(adapter->dev_id, &adapter->bdaddr);
	//和BDADDR_ANY比较一下,若是一样就是有问题啦。
	if (bacmp(&adapter->bdaddr, BDADDR_ANY) == 0) {
		error("No address available for hci%d", adapter->dev_id);
		return FALSE;
	}
	//同样的时候拷贝dev的features到adapter的features中
	err = adapter_ops->read_local_features(adapter->dev_id,
							adapter->features);
	if (err < 0) {
		error("Can't read features for hci%d: %s (%d)",
					adapter->dev_id, strerror(-err), -err);
		return FALSE;
	}
	//对应的config文件下,看是否有name,显然是没有的,所以会进入if中
	if (read_local_name(&adapter->bdaddr, adapter->name) < 0)
//adapter->name应该是null了,main_opts.name就是main.conf中的内容了,是%m。这里就是初始化adapter->name的值了。读取的是ro.product.model的值,他在buildinfo.sh定义为PRODUCT_MODEL,而PRODUCT_MODEL就是对应的base.mk中定义的,所以,我们可以在这里改变名字。就是我们见到的8825gc,具体见2-1.
		expand_name(adapter->name, MAX_NAME_LENGTH, main_opts.name,
							adapter->dev_id);
//是否支持gatt,显然目前我们并不支持
	if (main_opts.attrib_server)
		attrib_gap_set(GATT_CHARAC_DEVICE_NAME,
			(const uint8_t *) adapter->name, strlen(adapter->name));
//初始化service list,就是把开始的那些service record和adapter这边关联起来。见2-2
	sdp_init_services_list(&adapter->bdaddr);
//就是加载那些plugin的adpater driver,见2-3分析
	load_drivers(adapter);
//清除block列表
	clear_blocked(adapter);
//加载device,就是创建一系列的文件,见2-4分析
	load_devices(adapter);
	/* Set pairable mode */
	//读config文件下的pairable的值,若是没有读到就设为true,否则就是读到的值
	if (read_device_pairable(&adapter->bdaddr, &adapter->pairable) < 0)
		adapter->pairable = TRUE;

	/* retrieve the active connections: address the scenario where
	 * the are active connections before the daemon've started */
	 //得到active的connection
	load_connections(adapter);
	//initialized设为true
	adapter->initialized = TRUE;

	return TRUE;
}

2-1 expand_name分析

expand_name就是扩展名字了。这里ANDROID_EXPAND_NAME是必然会定义了的

static char *expand_name(char *dst, int size, char *str, int dev_id)
{
	register int sp, np, olen;
	char *opt, buf[10];

#ifdef ANDROID_EXPAND_NAME
	char value[PROPERTY_VALUE_MAX];
#endif
//这里当然不是null了
	if (!str || !dst)
		return NULL;

	sp = np = 0;
	while (np < size - 1 && str[sp]) {
		switch (str[sp]) {
		case '%':
			opt = NULL;

			switch (str[sp+1]) {
			case 'd':
……
//我们是%m,所以会走到这里
#ifdef ANDROID_EXPAND_NAME
			case 'b':
				property_get("ro.product.brand", value, "");
				opt = value;
			break;
//得到ro.product.model的值
			case 'm':
				property_get("ro.product.model", value, "");
				opt = value;
			break;
……
#endif

			case '%':
				dst[np++] = str[sp++];
				/* fall through */
			default:
				sp++;
				continue;
			}

			if (opt) {
				/* substitute */
	//保存到adapter.name中
				olen = strlen(opt);
				if (np + olen < size - 1)
					memcpy(dst + np, opt, olen);
				np += olen;
			}
			sp += 2;
			continue;

		case '\\':
			sp++;
			/* fall through */
		default:
			dst[np++] = str[sp++];
			break;
		}
	}
	dst[np] = '\0';
	return dst;
}


2-2 sdp_init_services_list

这个函数主要就是把开始的service record和对应的adapter关联起来

void sdp_init_services_list(bdaddr_t *device)
{
	sdp_list_t *p;

	DBG("");
//access_db就是开始那边sdp record会加入的
	for (p = access_db; p != NULL; p = p->next) {
		sdp_access_t *access = p->data;
		sdp_record_t *rec;

		if (bacmp(BDADDR_ANY, &access->device))
			continue;
	//得到对应的sdp record
		rec = sdp_record_find(access->handle);
		if (rec == NULL)
			continue;

		SDPDBG("adding record with handle %x", access->handle);
	//加入到每一个adapter中,这里其实也就是一个了
	//这里其实就是会调用adapter_service_insert函数
		manager_foreach_adapter(adapter_service_insert, rec);
	}
}
void adapter_service_insert(struct btd_adapter *adapter, void *r)
{
	sdp_record_t *rec = r;
	gboolean new_uuid;
	//看adapter services中是否已经有了该uuid
	if (sdp_list_find(adapter->services, &rec->svclass, uuid_cmp) == NULL)
		new_uuid = TRUE;
	else
		new_uuid = FALSE;
	//把这个rec加入到adapter services中
	adapter->services = sdp_list_insert_sorted(adapter->services, rec,
								record_sort);

	if (new_uuid) {
		//add uuid,新的uuid,则需要调用hciops中的add uuid
		uint8_t svc_hint = get_uuid_mask(&rec->svclass);
		//调用hciops对应的add_uuid,就是下面的hciops_add_uuid
		adapter_ops->add_uuid(adapter->dev_id, &rec->svclass, svc_hint);
	}
	//因为adapter还没有初始化完成,所以这个不会做什么,直接return而已
	adapter_emit_uuids_updated(adapter);
}
static int hciops_add_uuid(int index, uuid_t *uuid, uint8_t svc_hint)
{
	struct dev_info *dev = &devs[index];
	struct uuid_info *info;

	DBG("hci%d", index);
	//新建一个uuid info用来保存这个新的uuid
	info = g_new0(struct uuid_info, 1);
	memcpy(&info->uuid, uuid, sizeof(*uuid));
	info->svc_hint = svc_hint;
	//加入到dev->uuids列表中
	dev->uuids = g_slist_append(dev->uuids, info);

	return update_service_classes(index);
}
static int update_service_classes(int index)
{
	struct dev_info *dev = &devs[index];
	uint8_t value;
	int err;
	//uuid对应的service class集合
	value = generate_service_class(index);

	DBG("hci%d value %u", index, value);

	/* Update only the service class, keep the limited bit,
	 * major/minor class bits intact */
	dev->wanted_cod &= 0x00ffff;
	dev->wanted_cod |= (value << 16);

	/* If the cache is enabled or an existing CoD write is in progress
	 * just bail out */
	//我们这边的cached_enable是置为true的,所以,暂时就直接return了,后面等到了再分析吧
	if (dev->cache_enable || dev->pending_cod)
		return 0;
……
}


2-3 pluginadapter driver的加载

2.2.7中,我们详细分析了各个plugin的初始化,他们最后也注册了一系列的adapter_driver,这里我们就是把这些driver进行初始化。

//其实就是遍历adapter_drivers列表,然后probe driver
static void load_drivers(struct btd_adapter *adapter)
{
	GSList *l;

	for (l = adapter_drivers; l; l = l->next)
		probe_driver(adapter, l->data);
}
static void probe_driver(struct btd_adapter *adapter, gpointer user_data)
{
	struct btd_adapter_driver *driver = user_data;
	int err;
	//检查是否已经up
	if (!adapter->up)
		return;
	//检查是否有probe函数
	if (driver->probe == NULL)
		return;
	//调用对应的probe
	err = driver->probe(adapter);
	if (err < 0) {
		error("%s: %s (%d)", driver->name, strerror(-err), -err);
		return;
	}
	//加入到loaded_drivers列表中
	adapter->loaded_drivers = g_slist_prepend(adapter->loaded_drivers,
									driver);
}


2.3.7的最后,我们发现最终注册到adapter_driver列表中的有:a2dp_server_driveravrcp_server_driverinput_server_drivernetwork_server_driverhdp_adapter_driver。所以,下面我们就这些进行一下分析。我们以a2dp_server_driver为例进行分析,其它的就比较类似了,不多做解释。

a2dp_server_driverprobe函数分析

static int a2dp_server_probe(struct btd_adapter *adapter)
{
	struct audio_adapter *adp;
	//得到adapter的path
	const gchar *path = adapter_get_path(adapter);
	bdaddr_t src;
	int err;

	DBG("path %s", path);
	//创建一个audio adapter,开始肯定没有啦
	adp = audio_adapter_get(adapter);
	if (!adp)
		return -EINVAL;
//得到对应的address
	adapter_get_address(adapter, &src);
	//a2dp的注册,很大程度上需要根据config做一些不同的操作
	err = a2dp_register(connection, &src, config);
	if (err < 0)
		audio_adapter_unref(adp);

	return err;
}

int a2dp_register(DBusConnection *conn, const bdaddr_t *src, GKeyFile *config)
{
	int sbc_srcs = 1, sbc_sinks = 1;
	int mpeg12_srcs = 0, mpeg12_sinks = 0;
	gboolean source = TRUE, sink = FALSE, socket = TRUE;
	gboolean delay_reporting = FALSE;
	char *str;
	GError *err = NULL;
	int i;
	struct a2dp_server *server;

	if (!config)
		goto proceed;
//关于config,配置如下:
/*
Enable=Sink,Control
Disable=Headset,Gateway,Source
Master=false
FastConnectable=false
[A2DP]
SBCSources=1
MPEG12Sources=0
*/
	str = g_key_file_get_string(config, "General", "Enable", &err);

	if (err) {
		DBG("audio.conf: %s", err->message);
		g_clear_error(&err);
	} else {
		if (strstr(str, "Sink"))
			source = TRUE; //source是true,是反的啊~~
		if (strstr(str, "Source"))
			sink = TRUE;
		g_free(str);
	}
	str = g_key_file_get_string(config, "General", "Disable", &err);

	if (err) {
		DBG("audio.conf: %s", err->message);
		g_clear_error(&err);
	} else {
		if (strstr(str, "Sink"))
			source = FALSE;
		if (strstr(str, "Source"))
			sink = FALSE; //这个是false
		if (strstr(str, "Socket"))
			socket = FALSE; //socket没有,所以它还是true
		g_free(str);
	}
	/* Don't register any local sep if Socket is disabled */
	//socket肯定是会支持的,所以这里不会走到
	if (socket == FALSE) {
		sbc_srcs = 0;
		sbc_sinks = 0;
		mpeg12_srcs = 0;
		mpeg12_sinks = 0;
		goto proceed;
	}
	str = g_key_file_get_string(config, "A2DP", "SBCSources", &err);
	if (err) {
		DBG("audio.conf: %s", err->message);
		g_clear_error(&err);
	} else {
		sbc_srcs = atoi(str); //sbc_srcs=1
		g_free(str);
	}

	str = g_key_file_get_string(config, "A2DP", "MPEG12Sources", &err);
	if (err) {
		DBG("audio.conf: %s", err->message);
		g_clear_error(&err);
	} else {
		mpeg12_srcs = atoi(str);//MPEG12Source=0
		g_free(str);
	}

	str = g_key_file_get_string(config, "A2DP", "SBCSinks", &err);
	if (err) {
		DBG("audio.conf: %s", err->message);
		g_clear_error(&err);
	} else {
		sbc_sinks = atoi(str); //默认为1
		g_free(str);
	}
	str = g_key_file_get_string(config, "A2DP", "MPEG12Sinks", &err);
	if (err) {
		DBG("audio.conf: %s", err->message);
		g_clear_error(&err);
	} else {
		mpeg12_sinks = atoi(str); //默认为0
		g_free(str);
	}
proceed:
	//没有connection,先得到connection
	if (!connection)
		connection = dbus_connection_ref(conn);
	//找到servers中的a2dp_server
	server = find_server(servers, src);
	if (!server) {
		int av_err;
//没有,就新建一个
		server = g_new0(struct a2dp_server, 1);
		if (!server)
			return -ENOMEM;
//建一个avdpt的server,并开始一个l2cap的io监听
		av_err = avdtp_init(src, config, &server->version);
		if (av_err < 0) {
			g_free(server);
			return av_err;
		}
		//拷贝到server src中
		bacpy(&server->src, src);
		//把新建的server加入到servers中
		servers = g_slist_append(servers, server);
	}
	if (config)
		delay_reporting = g_key_file_get_boolean(config, "A2DP",
						"DelayReporting", NULL);
	//根据配置,看version,决定是1.3还是1.2
	if (delay_reporting)
		server->version = 0x0103;
	else
		server->version = 0x0102;
	//source是enable的
	server->source_enabled = source;
	if (source) {
		for (i = 0; i < sbc_srcs; i++)
			a2dp_add_sep(src, AVDTP_SEP_TYPE_SOURCE,
				A2DP_CODEC_SBC, delay_reporting, NULL, NULL);
		for (i = 0; i < mpeg12_srcs; i++)
			a2dp_add_sep(src, AVDTP_SEP_TYPE_SOURCE,
					A2DP_CODEC_MPEG12, delay_reporting,
					NULL, NULL);
	}
	//sink是没有enable的
	server->sink_enabled = sink;
	if (sink) {
		for (i = 0; i < sbc_sinks; i++)
			a2dp_add_sep(src, AVDTP_SEP_TYPE_SINK,
				A2DP_CODEC_SBC, delay_reporting, NULL, NULL);

		for (i = 0; i < mpeg12_sinks; i++)
			a2dp_add_sep(src, AVDTP_SEP_TYPE_SINK,
					A2DP_CODEC_MPEG12, delay_reporting,
					NULL, NULL);
	}

	return 0;
}
int avdtp_init(const bdaddr_t *src, GKeyFile *config, uint16_t *version)
{
	GError *err = NULL;
	gboolean tmp, master = TRUE;
	struct avdtp_server *server;
	uint16_t ver = 0x0102;

	if (!config)
		goto proceed;
	//master = false
	tmp = g_key_file_get_boolean(config, "General",
			"Master", &err);
	if (err) {
		DBG("audio.conf: %s", err->message);
		g_clear_error(&err);
	} else
		master = tmp;
	//auto_connect = true
	tmp = g_key_file_get_boolean(config, "General", "AutoConnect",
			&err);
	if (err)
		g_clear_error(&err);
	else
		auto_connect = tmp;
	//这里是没有了,所以是0102,就是V1.2,支持delayreporting就是v1.3了
	if (g_key_file_get_boolean(config, "A2DP", "DelayReporting", NULL))
		ver = 0x0103;

proceed:
	//新建avdtp的server
	server = g_new0(struct avdtp_server, 1);
	if (!server)
		return -ENOMEM;

	server->version = ver;
	//version传给调用的
	if (version)
		*version = server->version;
	//建一个l2cap的监听io
	server->io = avdtp_server_socket(src, master);
	if (!server->io) {
		g_free(server);
		return -1;
	}

	bacpy(&server->src, src);
	//加入到servers列表中

	servers = g_slist_append(servers, server);

	return 0;
}

struct a2dp_sep *a2dp_add_sep(const bdaddr_t *src, uint8_t type,
				uint8_t codec, gboolean delay_reporting,
				struct media_endpoint *endpoint, int *err)
{
	struct a2dp_server *server;
	struct a2dp_sep *sep;
	GSList **l;
	uint32_t *record_id;
	sdp_record_t *record;
	struct avdtp_sep_ind *ind;
	//找到a2dp server
	server = find_server(servers, src);
	if (server == NULL) {
		if (err)
			*err = -EINVAL;
		return NULL;
	}

	if (type == AVDTP_SEP_TYPE_SINK && !server->sink_enabled) {
		if (err)
			*err = -EPROTONOSUPPORT;
		return NULL;
	}
	//检查一下是否对应
	if (type == AVDTP_SEP_TYPE_SOURCE && !server->source_enabled) {
		if (err)
			*err = -EPROTONOSUPPORT;
		return NULL;
	}
	//初始化a2dp sep
	sep = g_new0(struct a2dp_sep, 1);
	//传入的是null
	if (endpoint) {
		ind = &endpoint_ind;
		goto proceed;
	}
	//是sbc
	ind = (codec == A2DP_CODEC_MPEG12) ? &mpeg_ind : &sbc_ind;

proceed:
	//初始化一个local sep,并把它加入到server sep列表中
	sep->lsep = avdtp_register_sep(&server->src, type,
					AVDTP_MEDIA_TYPE_AUDIO, codec,
					delay_reporting, ind, &cfm, sep);
	if (sep->lsep == NULL) {
		g_free(sep);
		if (err)
			*err = -EINVAL;
		return NULL;
	}
	//初始化a2dp的sep
	sep->server = server;
	sep->endpoint = endpoint;
	sep->codec = codec;
	sep->type = type;
	sep->delay_reporting = delay_reporting;

	if (type == AVDTP_SEP_TYPE_SOURCE) {
		l = &server->sources;
		record_id = &server->source_record_id;
	} else {
		l = &server->sinks;
		record_id = &server->sink_record_id;
	}
	//开始这个是0了
	if (*record_id != 0)
		goto add;
	//service record
	record = a2dp_record(type, server->version);
	if (!record) {
		error("Unable to allocate new service record");
		avdtp_unregister_sep(sep->lsep);
		g_free(sep);
		if (err)
			*err = -EINVAL;
		return NULL;
	}
	//把record和server相关联,这里也会有UUIDS的property change
	if (add_record_to_server(&server->src, record) < 0) {
		error("Unable to register A2DP service record");\
		sdp_record_free(record);
		avdtp_unregister_sep(sep->lsep);
		g_free(sep);
		if (err)
			*err = -EINVAL;
		return NULL;
	}
	//record id用来表示record的handle
	*record_id = record->handle;

add:
	//加入到server source的列表中
	*l = g_slist_append(*l, sep);

	if (err)
		*err = 0;
	return sep;
}


至此,a2dpprobe函数就结束了,主要就是根据配置,新建了a2dp servera2dp sep,并把对应的service record加入到了server中。

2-4 load_devices的分析

这个函数就是建立了一系列的文件,然后根据文件的内容会有一系列的函数进行对应的处理

static void load_devices(struct btd_adapter *adapter)
{
	char filename[PATH_MAX + 1];
	char srcaddr[18];
	struct adapter_keys keys = { adapter, NULL };
	int err;
	//把bt的addrees取出保存到srcaddr中
	ba2str(&adapter->bdaddr, srcaddr);
	//新建profiles文件
	create_name(filename, PATH_MAX, STORAGEDIR, srcaddr, "profiles");
	//找到对应key和value,然后调用create_stored_device_from_profiles进行处理,这里是空的,没什么好做
	textfile_foreach(filename, create_stored_device_from_profiles,
								adapter);
	//新建primary
	create_name(filename, PATH_MAX, STORAGEDIR, srcaddr, "primary");
	textfile_foreach(filename, create_stored_device_from_primary,
								adapter);
	//新建linkkeys
	create_name(filename, PATH_MAX, STORAGEDIR, srcaddr, "linkkeys");
	textfile_foreach(filename, create_stored_device_from_linkkeys, &keys);
	//调用load keys,设置dev的key和debug keys元素
	err = adapter_ops->load_keys(adapter->dev_id, keys.keys,
							main_opts.debug_keys);
	if (err < 0) {
		error("Unable to load keys to adapter_ops: %s (%d)",
							strerror(-err), -err);
		g_slist_foreach(keys.keys, (GFunc) g_free, NULL);
		g_slist_free(keys.keys);
	}
	//创建blocked
	create_name(filename, PATH_MAX, STORAGEDIR, srcaddr, "blocked");
	textfile_foreach(filename, create_stored_device_from_blocked, adapter);
	//创建types
	create_name(filename, PATH_MAX, STORAGEDIR, srcaddr, "types");
	textfile_foreach(filename, create_stored_device_from_types, adapter);
}


2.4.2.4.2 btd_adapter_get_mode的分析

总的来说还是蛮简单的,就是根据配置,设置modeon_mode,和pairable

void btd_adapter_get_mode(struct btd_adapter *adapter, uint8_t *mode,
					uint8_t *on_mode, gboolean *pairable)
{
	char str[14], address[18];

	ba2str(&adapter->bdaddr, address);

	if (mode) {
		//这里是false,所以,直接设置为main_opts.mode,就是MODE_CONNECTABLE
		if (main_opts.remember_powered == FALSE)
			*mode = main_opts.mode;
		else if (read_device_mode(address, str, sizeof(str)) == 0)
			*mode = get_mode(&adapter->bdaddr, str);
		else
			*mode = main_opts.mode;
	}

	if (on_mode) {
		//false,read config中的on mode的值,默认为MODE_CONNECTABLE
		if (main_opts.remember_powered == FALSE)
			*on_mode = get_mode(&adapter->bdaddr, "on");
		else if (read_on_mode(address, str, sizeof(str)) == 0)
			*on_mode = get_mode(&adapter->bdaddr, str);
		else
			*on_mode = main_opts.mode;
	}
	//设置为adapter的pairable
	if (pairable)
		*pairable = adapter->pairable;
}


2.4.2.4.3 start_adapter的分析

adapter的启动,这个过程同样将会涉及到很多的commandevent的交互,可以认为是打开蓝牙的第二波大规模的commandevent交互了,所幸的是,有很多的内容是和之前的是类似的。所以,我们的分析相对而言会比较轻松一点。

static void start_adapter(int index)
{
	struct dev_info *dev = &devs[index];
	uint8_t inqmode;
	uint16_t link_policy;
	//发送set event mask的cmd
	set_event_mask(index);
	//根据是否支持simple pair来决定是否write simple pairing mode的cmd
	if (dev->features[6] & LMP_SIMPLE_PAIR)
		init_ssp_mode(index);
	//看inquiry的mode,然后再决定是否write inquiry mode的cmd
	inqmode = get_inquiry_mode(index);
	if (inqmode)
		write_inq_mode(index, inqmode);
	//是否支持inquiry tx power,然后决定是否发送read inquiry response tx power level的cmd
	if (dev->features[7] & LMP_INQ_TX_PWR)
		hci_send_cmd(dev->sk, OGF_HOST_CTL,
				OCF_READ_INQ_RESPONSE_TX_POWER_LEVEL, 0, NULL);

	/* Set default link policy */
	link_policy = main_opts.link_policy;

	if (!(dev->features[0] & LMP_RSWITCH))
		link_policy &= ~HCI_LP_RSWITCH;
	if (!(dev->features[0] & LMP_HOLD))
		link_policy &= ~HCI_LP_HOLD;
	if (!(dev->features[0] & LMP_SNIFF))
		link_policy &= ~HCI_LP_SNIFF;
	if (!(dev->features[1] & LMP_PARK))
		link_policy &= ~HCI_LP_PARK;
	//发送write default link policy来设置link的策略
	link_policy = htobs(link_policy);
	hci_send_cmd(dev->sk, OGF_LINK_POLICY, OCF_WRITE_DEFAULT_LINK_POLICY,
					sizeof(link_policy), &link_policy);

	dev->current_cod = 0;
	memset(dev->eir, 0, sizeof(dev->eir));
}


log来看,在开始的时候只会发送set event maskwrite default link policycmd。这两个cmdkernel层的处理我们已经分析过了,都没有做什么,再回到bluez层,我们会发现其实也没有对这两个cmd的处理,所以,我们就不管了。继续往下分析好了。

2.4.2.4.4 btd_adapter_start的分析

初始化adaptere的一些内容,不可避免地仍然会涉及到各种commandevent的交互。主要就是两个commandwrite local namewrite device of class

void btd_adapter_start(struct btd_adapter *adapter)
{
	char address[18];
	uint8_t cls[3];
	gboolean powered;

	ba2str(&adapter->bdaddr, address);

	adapter->dev_class = 0;
	adapter->off_requested = FALSE;
	adapter->up = TRUE;
	adapter->discov_timeout = get_discoverable_timeout(address);
	adapter->pairable_timeout = get_pairable_timeout(address);
	adapter->state = STATE_IDLE;
	adapter->mode = MODE_CONNECTABLE;

	if (main_opts.le)
		adapter_ops->enable_le(adapter->dev_id);
	//通过write local name来设置controller的name
	adapter_ops->set_name(adapter->dev_id, adapter->name);
	//得到config文件中的class的值
	if (read_local_class(&adapter->bdaddr, cls) < 0) {
		//若是没有得到,就拷贝main opts中的class
		uint32_t class = htobl(main_opts.class);
		memcpy(cls, &class, 3);
	}
	//调用write class of device command来设置device class
	//但是因为cached_enable是true,所以,他并不会调用这个cmd
	//而是在后面的disable_cod_cache中调用
	btd_adapter_set_class(adapter, cls[1], cls[0]);

	powered = TRUE;
	//向上层通知powered的改变,为true了,也是property change,这个会在后面的分析中详细介绍
	emit_property_changed(connection, adapter->path,
					ADAPTER_INTERFACE, "Powered",
					DBUS_TYPE_BOOLEAN, &powered);
	//就headset中用到过,这里没有,所以直接返回了
	call_adapter_powered_callbacks(adapter, TRUE);
	//调用write class of device command来设置device class
	adapter_ops->disable_cod_cache(adapter->dev_id);

	info("Adapter %s has been enabled", adapter->path);
}


这个函数涉及到的两个cmdwrite local namewrite device of class,其中write local namecommand complete是没有什么需要做的。而write device of classbluez中是有很多操作的,我们需要详细分析一下:

1write device of classcommand complete分析:

static void write_class_complete(int index, uint8_t status)
{
	struct dev_info *dev = &devs[index];
	struct btd_adapter *adapter;

	//status非0的话说明有问题,好像开始没有介绍,这里介绍一次后面不再说了
	if (status)
		return;

	if (dev->pending_cod == 0)
		return;
	//设置当前的coditon
	dev->current_cod = dev->pending_cod;
	//把pending去除掉
	dev->pending_cod = 0;

	adapter = manager_find_adapter(&dev->bdaddr);
	//保存class到config文件中,并通知上层property change
	if (adapter)
		btd_adapter_class_changed(adapter, dev->current_cod);
	//根据ex inquiry的feature决定是否需要update
	update_ext_inquiry_response(index);
	//这里就直接return了
	if (dev->wanted_cod == dev->current_cod)
		return;
	//若不是,则需要再次进行一次class的write
	if (dev->wanted_cod & LIMITED_BIT &&
			!(dev->current_cod & LIMITED_BIT))
		hciops_set_limited_discoverable(index, TRUE);
	else if (!(dev->wanted_cod & LIMITED_BIT) &&
					(dev->current_cod & LIMITED_BIT))
		hciops_set_limited_discoverable(index, FALSE);
	else
		write_class(index, dev->wanted_cod);
}


总的来说,他就是把class的值保存到对应的config文件中,然后向上层通知了classpropertychange

2.4.2.4.5 write scan enableinquiry cancel的分析

write scan enablecommand complete处理来看,他会直接发送read scan enablecmd

case cmd_opcode_pack(OGF_HOST_CTL, OCF_WRITE_SCAN_ENABLE):
		hci_send_cmd(dev->sk, OGF_HOST_CTL, OCF_READ_SCAN_ENABLE,
								0, NULL);
		break;
inquiry cancel的command complete:
static inline void cc_inquiry_cancel(int index, uint8_t status)
{
	//status有问题,只会打印一下
	if (status) {
		error("Inquiry Cancel Failed with status 0x%02x", status);
		return;
	}
	//设置状态位DISCOV_HALTED,不过初始化就是这个,所以在打开蓝牙的时候这个命令出问题,其实是没有关系的。事实上很多controller就是不支持这个cmd,还好问题也不大。
	set_state	(index, DISCOV_HALTED);
}
下面我们顺手再分析一下read scan enable这个cmd的event处理:
static void read_scan_complete(int index, uint8_t status, void *ptr)
{
	struct btd_adapter *adapter;
	read_scan_enable_rp *rp = ptr;

	DBG("hci%d status %u", index, status);

	adapter = manager_find_adapter_by_id(index);
	if (!adapter) {
		error("Unable to find matching adapter");
		return;
	}
	//通知mode 的change
	adapter_mode_changed(adapter, rp->enable);
}
void adapter_mode_changed(struct btd_adapter *adapter, uint8_t scan_mode)
{
	const gchar *path = adapter_get_path(adapter);
	gboolean discoverable, pairable;

	DBG("old 0x%02x new 0x%02x", adapter->scan_mode, scan_mode);
	//没有变化就什么都不做
	if (adapter->scan_mode == scan_mode){
#ifdef BOARD_HAVE_BLUETOOTH_BCM
	    /*we may reset scan_mode already in btd_adapter_stop(), so comes to here*/
	    set_mode_complete(adapter);
#endif
	    return;
	}
	//这个就是把discov timeout去除掉,开始也没有,所以,这里也就没有什么
	adapter_remove_discov_timeout(adapter);

	switch (scan_mode) {
	case SCAN_DISABLED:
		adapter->mode = MODE_OFF;
		discoverable = FALSE;
		pairable = FALSE;
		break;
		//我们是0x02
	case SCAN_PAGE:
		adapter->mode = MODE_CONNECTABLE;
		discoverable = FALSE;
		pairable = adapter->pairable;
		break;
	case (SCAN_PAGE | SCAN_INQUIRY):
		adapter->mode = MODE_DISCOVERABLE;
		discoverable = TRUE;
		pairable = adapter->pairable;
		if (adapter->discov_timeout != 0)
			adapter_set_discov_timeout(adapter,
						adapter->discov_timeout);
		break;
	case SCAN_INQUIRY:
		/* Address the scenario where a low-level application like
		 * hciconfig changed the scan mode */
		if (adapter->discov_timeout != 0)
			adapter_set_discov_timeout(adapter,
						adapter->discov_timeout);

		/* ignore, this event should not be sent */
	default:
		/* ignore, reserved */
		return;
	}

	/* If page scanning gets toggled emit the Pairable property */
	//scan page的改变,需要通知上层pairable的property change
	if ((adapter->scan_mode & SCAN_PAGE) != (scan_mode & SCAN_PAGE))
		emit_property_changed(connection, adapter->path,
					ADAPTER_INTERFACE, "Pairable",
					DBUS_TYPE_BOOLEAN, &pairable);
	//这里discoverable是false
	if (!discoverable)
		adapter_set_limited_discoverable(adapter, FALSE);
	//再通知上层discoverable的property change
	emit_property_changed(connection, path,
				ADAPTER_INTERFACE, "Discoverable",
				DBUS_TYPE_BOOLEAN, &discoverable);
	//设置adapter的scan mode
	adapter->scan_mode = scan_mode;
	//设置mode完成
	set_mode_complete(adapter);
}


所以,这里最重要的就是向上面发送了两个property change,分别为:Pairable=falseDiscoverable=false

至此,enableNative的分析就全部结束了,他使用了rfkill来进行芯片的上电操作,调用了hciattach来进行各家芯片的初始化工作,通过ioctl来把hci device up,在这个过程中通过一系列的cmdresponse的交互使得对应的蓝牙controller能够进行初始化,最后使能bluetoothd初始化bluez的方方面面,总得来说内容还是很多的。他留给我们的还有几个property change的处理的悬念,这些我们会在后面的文章中再和大家来一一分析。

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值