[Android源碼分析]bluez internal event的處理

在上面2.1中是hci dev的註冊和up,2.3中有bluez的初始化,這兩者是有一個交集的,那就是說bluez初始化後會監聽hci dev的一些event,主要有HCI_DEV_REG和HCI_DEV_UP兩個比較重要,那本集就是主要分析這兩個event帶來的影響。

 

         從上面的分析中,我們已經知道,這兩個event的處理函數是io_stack_event:

 

[cpp]  

static gboolean io_stack_event(GIOChannel *chan, GIOCondition cond,  

                                gpointer data)  

{  

    unsigned char buf[HCI_MAX_FRAME_SIZE], *ptr;  

    evt_stack_internal *si;  

    evt_si_device *sd;  

    hci_event_hdr *eh;  

    int type, fd;  

    ssize_t len;  

  

    ptr = buf;  

  

    fd = g_io_channel_unix_get_fd(chan);  

    //讀取event的內容  

    len = read(fd, buf, sizeof(buf));  

    if (len < 0) {  

        if (errno == EAGAIN)  

            return TRUE;  

  

        error("Read from control socket failed: %s (%d)",  

                        strerror(errno), errno);  

        return FALSE;  

    }  

  

    type = *ptr++;  

  

    if (type != HCI_EVENT_PKT)  

        return TRUE;  

  

    eh = (hci_event_hdr *) ptr;  

//判斷是否是internal的event  

    if (eh->evt != EVT_STACK_INTERNAL)  

        return TRUE;  

  

    ptr += HCI_EVENT_HDR_SIZE;  

  

    si = (evt_stack_internal *) ptr;  

    switch (si->type) {  

    case EVT_SI_DEVICE:  

        sd = (void *) &si->data;  

    //event的處理  

        device_event(sd->event, sd->dev_id);  

        break;  

    }  

  

    return TRUE;  

}  

static void device_event(int event, int index)  

{  

    switch (event) {  

    //device register後的操作,詳細見2.4.1  

    case HCI_DEV_REG:  

        info("HCI dev %d registered", index);  

        init_device(index, FALSE);  

        break;  

    //unreg,不做詳細分析  

    case HCI_DEV_UNREG:  

        info("HCI dev %d unregistered", index);  

        stop_hci_dev(index);  

        if (devs[index].registered)  

            btd_manager_unregister_adapter(index);  

        break;  

    //device up的操作,詳細分析見2.4.2  

    case HCI_DEV_UP:  

        info("HCI dev %d up", index);  

        devs[index].up = TRUE;  

        device_devup_setup(index);  

        break;  

    //Down的操作  

    case HCI_DEV_DOWN:  

        info("HCI dev %d down", index);  

        devs[index].up = FALSE;  

        devs[index].pending_cod = 0;  

        devs[index].cache_enable = TRUE;  

        if (!devs[index].pending) {  

            struct btd_adapter *adapter;  

  

            adapter = manager_find_adapter_by_id(index);  

            if (adapter)  

                btd_adapter_stop(adapter);  

  

            init_pending(index);  

        }  

        break;  

    }  

}  

 

 

 

2.4.1 device register後的bluez的操作分析

 

         這個函數是bluez收到底層hci dev registe的消息之後的操作。事實上,因為init_known_adapters的存在,這裡可能都沒有走到。不過,在上面init_known_adapters中我們也沒有分析這個函數,這裡我們分析一下吧,反正這個函數終歸是要走的。

 

[cpp]  

static struct dev_info *init_device(int index, gboolean already_up)  

{  

    struct dev_info *dev;  

    struct hci_dev_req dr;  

    int dd;  

    pid_t pid;  

  

    DBG("hci%d", index);  

    //open hci device  

    //其實就是建一個hci對應的socket,並bind,返回的dd就是socket的句柄  

    dd = hci_open_dev(index);  

    if (dd < 0) {  

        error("Unable to open hci%d: %s (%d)", index,  

                        strerror(errno), errno);  

        return NULL;  

    }  

    //max_dev默認為0,申請對應的空間  

    if (index > max_dev) {  

        max_dev = index;  

        devs = g_realloc(devs, sizeof(devs[0]) * (max_dev + 1));  

    }  

    //初始化devcie的info,見2.4.1.1  

    dev = init_dev_info(index, dd, FALSE, already_up);  

    //設置device的pending位,把dev->pending的bdaddr,version,features和name都置位  

    init_pending(index);  

    //開始hci device,這裡會對一系列的event進行監聽,具體見2.4.1.2  

    start_hci_dev(index);  

    //已經up瞭,就不需要做什麼瞭  

/* Avoid forking if nothing else has to be done */  

    if (already_up)  

        return dev;  

  

    /* Do initialization in the separate process */  

//fork一個進程出來繼續,子進程繼續下去,父進程這裡直接返回device  

    pid = fork();  

    switch (pid) {  

        case 0:  

        //註冊一個子進程退出時調用的函數  

            atexit(at_child_exit);  

            break;  

        //fork出錯,直接返回device,註意這裡沒有break  

        case -1:  

            error("Fork failed. Can't init device hci%d: %s (%d)",  

                    index, strerror(errno), errno);  

        default:  

        //父進程直接返回device  

            DBG("child %d forked", pid);  

            return dev;  

    }  

    memset(&dr, 0, sizeof(dr));  

    dr.dev_id = index;  

//根據配置的link mode來進行設置,默認的link policy(7)是不支持park的,支持sniff,roleswitch和hold  

    /* Set link mode */  

    dr.dev_opt = main_opts.link_mode;  

    if (ioctl(dd, HCISETLINKMODE, (unsigned long) &dr) < 0)  

        error("Can't set link mode on hci%d: %s (%d)",  

                        index, strerror(errno), errno);  

    //這裡會再次up,其實之前在bluetoothd啟動之前的enable_native中已經up過瞭,所以這裡應該沒有什麼瞭  

    /* Start HCI device */  

    if (ioctl(dd, HCIDEVUP, index) < 0 && errno != EALREADY) {  

        error("Can't init device hci%d: %s (%d)",  

                    index, strerror(errno), errno);  

        goto fail;  

    }  

  

    hci_close_dev(dd);  

    exit(0);  

  

fail:  

    hci_close_dev(dd);  

    exit(1);  

}  

 

 

 

至此,device register在bluez和kernel中的所有操作就都完成瞭。

 

 

 

2.4.1.1 device info的初始化

 

[cpp]  

         static struct dev_info *init_dev_info(int index, int sk, gboolean registered,  

  

                                                                 gboolean already_up)  

  

{  

  

         struct dev_info *dev = &devs[index];  

  

         //初始化wie0  

  

         memset(dev, 0, sizeof(*dev));  

  

   

  

         dev->id = index; //id就是0,就是hci0  

  

         dev->sk = sk;    //和剛剛建立的socket綁定  

  

         dev->cache_enable = TRUE;    //cache enable置位true  

  

         dev->registered = registered; //registered為false  

  

         dev->already_up = already_up;       //already up是傳入的值,這裡理論上應該是false  

  

         dev->io_capability = 0x03; /* No Input No Output */ //no input no output  

  

         dev->discov_state = DISCOV_HALTED; //初始化discovery的state為DISCOV_HALTED,這個狀態的轉變我們在inquiry的時候再詳細分析  

  

   

  

         return dev;  

  

}  

 

 

 

2.4.1.2  hci device的start

 

         這個函數說白瞭就是對一系列的event進行監聽,這也是我們後期能夠對event處理的關鍵前提所在。

 

 

 

[cpp]  

static void start_hci_dev(int index)  

{  

    struct dev_info *dev = &devs[index];  

    GIOChannel *chan = dev->io;  

    GIOCondition cond;  

    struct hci_filter flt;  

  

    if (chan)  

        return;  

  

    info("Listening for HCI events on hci%d", index);  

    //對下面一系列的event進行處理  

    /* Set filter */  

    hci_filter_clear(&flt);  

    hci_filter_set_ptype(HCI_EVENT_PKT, &flt);  

    hci_filter_set_event(EVT_CMD_STATUS, &flt);  

    hci_filter_set_event(EVT_CMD_COMPLETE, &flt);  

    hci_filter_set_event(EVT_PIN_CODE_REQ, &flt);  

    hci_filter_set_event(EVT_LINK_KEY_REQ, &flt);  

    hci_filter_set_event(EVT_LINK_KEY_NOTIFY, &flt);  

    hci_filter_set_event(EVT_RETURN_LINK_KEYS, &flt);  

    hci_filter_set_event(EVT_IO_CAPABILITY_REQUEST, &flt);  

    hci_filter_set_event(EVT_IO_CAPABILITY_RESPONSE, &flt);  

    hci_filter_set_event(EVT_USER_CONFIRM_REQUEST, &flt);  

    hci_filter_set_event(EVT_USER_PASSKEY_REQUEST, &flt);  

    hci_filter_set_event(EVT_REMOTE_OOB_DATA_REQUEST, &flt);  

    hci_filter_set_event(EVT_USER_PASSKEY_NOTIFY, &flt);  

    hci_filter_set_event(EVT_KEYPRESS_NOTIFY, &flt);  

    hci_filter_set_event(EVT_SIMPLE_PAIRING_COMPLETE, &flt);  

    hci_filter_set_event(EVT_AUTH_COMPLETE, &flt);  

    hci_filter_set_event(EVT_REMOTE_NAME_REQ_COMPLETE, &flt);  

    hci_filter_set_event(EVT_READ_REMOTE_VERSION_COMPLETE, &flt);  

    hci_filter_set_event(EVT_READ_REMOTE_FEATURES_COMPLETE, &flt);  

    hci_filter_set_event(EVT_REMOTE_HOST_FEATURES_NOTIFY, &flt);  

    hci_filter_set_event(EVT_INQUIRY_COMPLETE, &flt);  

    hci_filter_set_event(EVT_INQUIRY_RESULT, &flt);  

    hci_filter_set_event(EVT_INQUIRY_RESULT_WITH_RSSI, &flt);  

    hci_filter_set_event(EVT_EXTENDED_INQUIRY_RESULT, &flt);  

    hci_filter_set_event(EVT_CONN_REQUEST, &flt);  

    hci_filter_set_event(EVT_CONN_COMPLETE, &flt);  

    hci_filter_set_event(EVT_DISCONN_COMPLETE, &flt);  

    hci_filter_set_event(EVT_LE_META_EVENT, &flt);  

    if (setsockopt(dev->sk, SOL_HCI, HCI_FILTER, &flt, sizeof(flt)) < 0) {  

        error("Can't set filter on hci%d: %s (%d)",  

                        index, strerror(errno), errno);  

        return;  

    }  

    //處理的函數是io_security_event。所以,後期的一系列event上來之後,我們在這裡還需要進行一次處理,其實上文中的up過程中的event,是不需要再走這邊的,因為在up的時候bluetoothd還沒有啟動,這裡肯定是還沒有註冊瞭  

    chan = g_io_channel_unix_new(dev->sk);  

    cond = G_IO_IN | G_IO_NVAL | G_IO_HUP | G_IO_ERR;  

    dev->watch_id = g_io_add_watch_full(chan, G_PRIORITY_LOW, cond,  

                        io_security_event,  

                        GINT_TO_POINTER(index), NULL);  

    dev->io = chan;  

    dev->pin_length = 0;  

  

}  

 

 

 

2.4.2 device up後的bluez的操作分析

 

         這個函數device up之後bluez的需要進行的各種操作。

 

[cpp]  

static void device_devup_setup(int index)  

{  

    struct dev_info *dev = &devs[index];  

    struct hci_dev_info di;  

    read_stored_link_key_cp cp;  

  

    DBG("hci%d", index);  

    //得到kernel中的device info,並初始化到di中  

    if (hci_devinfo(index, &di) < 0)  

        return;  

    //檢查是否是bredr或者device_raw被置位  

    if (ignore_device(&di))  

        return;  

    //拷貝kernel中的bdaddr和features  

    bacpy(&dev->bdaddr, &di.bdaddr);  

    memcpy(dev->features, di.features, 8);  

  

    /* Set page timeout */  

    if ((main_opts.flags & (1 << HCID_SET_PAGETO))) {  

        write_page_timeout_cp cp;  

  

        cp.timeout = htobs(main_opts.pageto);  

        //這裡會發送write page timeout的cmd,所以,我們要修改page timeout,就可以通過修改main_opts.pageto來實現,他是可以通過main.conf修改來得到的  

        hci_send_cmd(dev->sk, OGF_HOST_CTL, OCF_WRITE_PAGE_TIMEOUT,  

                    WRITE_PAGE_TIMEOUT_CP_SIZE, &cp);  

    }  

    bacpy(&cp.bdaddr, BDADDR_ANY);  

    cp.read_all = 1;  

    //發送read stored link key的cmd  

    hci_send_cmd(dev->sk, OGF_HOST_CTL, OCF_READ_STORED_LINK_KEY,  

                    READ_STORED_LINK_KEY_CP_SIZE, &cp);  

    //若是沒有pending的內容,就init_adapter瞭。  

    //我們從上面的分析中知道,這裡是有一個pending version的,所以這裡先不急,我們來分析一下上面共3個cmd,他們的response所帶來的影響。分別是read local version information和write page timeout以及read stored link key。  

    if (!dev->pending)  

        init_adapter(index);  

}  

 

 

 

2.4.2.1 read local version information的response的影響。

 

         kernel中這個event的影響我們已經分析,不再累述。我們隻分析bluez這裡的處理:

 

他的處理在io_security_event中的command complete中有分析:

 

[cpp]  

case cmd_opcode_pack(OGF_INFO_PARAM, OCF_READ_LOCAL_VERSION):  

        ptr += sizeof(evt_cmd_complete);  

        read_local_version_complete(index, ptr);  

        break;  

所以就是read_local_version_complete這個函數瞭:

 

[cpp] 

static void read_local_version_complete(int index,  

                const read_local_version_rp *rp)  

{  

    struct dev_info *dev = &devs[index];  

  

    if (rp->status)  

        return;  

    //得到device的一些信息  

    dev->ver.manufacturer = btohs(bt_get_unaligned(&rp->manufacturer));  

    dev->ver.hci_ver = rp->hci_ver;  

    dev->ver.hci_rev = btohs(bt_get_unaligned(&rp->hci_rev));  

    dev->ver.lmp_ver = rp->lmp_ver;  

    dev->ver.lmp_subver = btohs(bt_get_unaligned(&rp->lmp_subver));  

    //若是沒有設置pending位,則直接return  

    if (!dev->pending)  

        return;  

    //否則,就把pending version的位清空  

    hci_clear_bit(PENDING_VERSION, &dev->pending);  

  

    DBG("Got version for hci%d", index);  

    //沒有其他pending瞭,且up瞭,就需要init adapter瞭,所以,我們終歸是要走到init_adapter的。所以這個函數的分析見2.3.2.4  

    if (!dev->pending && dev->up)  

        init_adapter(index);  

}  

 

 

 

2.4.2.2 write page timeout的response的分析

 

         依然是command complete,我們會發現,其實我們什麼都沒有做。包括kernel中也沒有做。

 

2.4.2.3 read stored link key的response的分析

 

         這個和2.4.2.2是一樣的。所以什麼都沒有做。

 

 

 

2.4.2.4 init_adapter函數的分析

 

         這個函數就是adapter的初始化瞭

 

[cpp]  

static gboolean init_adapter(int index)  

{   //得到對應device的info  

    struct dev_info *dev = &devs[index];  

    struct btd_adapter *adapter = NULL;  

    gboolean existing_adapter = dev->registered;  

    uint8_t mode, on_mode;  

    gboolean pairable, discoverable;  

    //從上面我們知道dev->registered是false,所以會走if中的resister,就是還沒有註冊過,就先register,否則就是find,意味著已經註冊過瞭  

    if (!dev->registered) {  

        //見下面的2.4.2.4.1  

        adapter = btd_manager_register_adapter(index);  

        if (adapter)  

            dev->registered = TRUE;  

    } else {  

        adapter = manager_find_adapter(&dev->bdaddr);  

        /* FIXME: manager_find_adapter should return a new ref */  

        btd_adapter_ref(adapter);  

    }  

    //沒有創建成功,就直接return false瞭  

    if (adapter == NULL)  

        return FALSE;  

    //設置mode,on_mode以及pairable的值,見2.4.2.4.2  

    btd_adapter_get_mode(adapter, &mode, &on_mode, &pairable);  

//這個地方是false,所以不會進這個if  

    if (existing_adapter)  

        mode = on_mode;  

//不是mode off,所以,不會進  

    if (mode == MODE_OFF) {  

        hciops_power_off(index);  

        goto done;  

    }  

    //這個就是通過一系列的cmd來啟動adapter瞭,詳細見2.4.2.4.3  

    start_adapter(index);  

    //繼續start adapter,詳細分析2.4.2.4.4  

    btd_adapter_start(adapter);  

    //因為我們這裡目前的mode是connectable,所以,discoverable是0  

    discoverable = (mode == MODE_DISCOVERABLE);  

    //write scan enable,然後mode是scan_page就是2  

    hciops_set_discoverable(index, discoverable);  

    //設置pairable的值  

    hciops_set_pairable(index, pairable);  

    //這裡就是發送inquiry cancel的command  

    if (dev->already_up)  

        hciops_stop_inquiry(index);  

    //以上一共有兩個cmd,分別是write scan enable,inquiry cancel。這兩個cmd的event的分析見2.4.2.4.5  

done:  

    btd_adapter_unref(adapter);  

    return TRUE;  

發佈留言

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