展会信息港展会大全

[Android源码分析]bluez中adapter初始化分析
来源:互联网   发布日期:2015-10-02 16:16:49   浏览:3041次  

导读:作为一个程序员,咋废话就不多说了,直接看代码吧,哈哈~~2)adapter的初始化[cpp] gboolean adapter_init(struct btd_adap...

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

2)adapter的初始化

[cpp]

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是必然会定义了的

[cpp]

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关联起来

[cpp]

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 plugin的adapter driver的加载

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

[cpp]

//其实就是遍历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_driver,avrcp_server_driver,input_server_driver,network_server_driver,hdp_adapter_driver。所以,下面我们就这些进行一下分析。我们以a2dp_server_driver为例进行分析,其它的就比较类似了,不多做解释。

a2dp_server_driver的probe函数分析

[cpp]

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;

}

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

2-4 load_devices的分析

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

[cpp]

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的分析

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

[cpp]

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

[cpp]

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 mask和write default link policy的cmd。这两个cmd在kernel层的处理我们已经分析过了,都没有做什么,再回到bluez层,我们会发现其实也没有对这两个cmd的处理,所以,我们就不管了。继续往下分析好了。

2.4.2.4.4 btd_adapter_start的分析

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

[cpp]

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);

}

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

1)write device of class的command complete分析:

[cpp]

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文件中,然后向上层通知了class的property的change。

2.4.2.4.5 write scan enable,inquiry cancel的分析

从write scan enable的command complete处理来看,他会直接发送read scan enable的cmd。

[cpp]

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=false和Discoverable=false

赞助本站

人工智能实验室

相关热词: android开发 教程

相关内容
AiLab云推荐
展开

热门栏目HotCates

Copyright © 2010-2024 AiLab Team. 人工智能实验室 版权所有    关于我们 | 联系我们 | 广告服务 | 公司动态 | 免责声明 | 隐私条款 | 工作机会 | 展会港