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

作為一個程序員,咋廢話就不多說瞭,直接看代碼吧,哈哈~~

 

 

 

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

 

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *