作为一个程序员,咋废话就不多说了,直接看代码吧,哈哈~~
2)adapter的初始化
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 plugin的adapter 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_driver,avrcp_server_driver,input_server_driver,network_server_driver,hdp_adapter_driver。所以,下面我们就这些进行一下分析。我们以a2dp_server_driver为例进行分析,其它的就比较类似了,不多做解释。
a2dp_server_driver的probe函数分析
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的分析
这个函数就是建立了一系列的文件,然后根据文件的内容会有一系列的函数进行对应的处理
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。
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交互了,所幸的是,有很多的内容是和之前的是类似的。所以,我们的分析相对而言会比较轻松一点。
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。
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分析:
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。
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
至此,enableNative的分析就全部结束了,他使用了rfkill来进行芯片的上电操作,调用了hciattach来进行各家芯片的初始化工作,通过ioctl来把hci device up,在这个过程中通过一系列的cmd和response的交互使得对应的蓝牙controller能够进行初始化,最后使能bluetoothd初始化bluez的方方面面,总得来说内容还是很多的。他留给我们的还有几个property change的处理的悬念,这些我们会在后面的文章中再和大家来一一分析。
若您觉得该文章对您有帮助,请在下面用鼠标轻轻按一下“顶”,哈哈~~·