Android 4.4.2 bluetooth解析(一)


開発プロジェクトの関係で、最近android 4に対してずっと4のbluedroidは研究を行い、ユーザー向けの応用を開発したが、実際に開発過程で出会った問題からandroid 4.4 bluedroidはまだ完璧ではありません.特に、bleが多く、ble bluetoothgattserver rolesを使用している場合です.
開発過程は実際に現在ネット上で最新のandroid 4について発見した.4 bleの紹介が少なく、自分ではあまり満足していないような気がします.だから自分でandroidを勉強したいと思っています.4 bleの皆さん参考にしてください.一部の部分はよく書けないので、指摘を歓迎します.さあ、今から始めます.
まず、Bluetoothの最初のステップは電源を入れることですが、android 4.4 Bluetoothの電源部分のコードは実際にandroid 4となっています.3違います.
android4.3 Bluetooth osはsystem/bluetoothですがandroid 4.4歩いているのはhardware/libhardwareとexternal/bluetooth/です.具体的には以下を見てください.
Bluetooth.h(hardware/libhardware/include/hardware/)---これは構造体で、主にenable関数を見ます.
typedef struct {
    /** set to sizeof(bt_interface_t) */
    size_t size;
    /**
     * Opens the interface and provides the callback routines
     * to the implemenation of this interface.
     */
    int (*init)(bt_callbacks_t* callbacks );

    /** Enable Bluetooth. */
    int (*enable)(void);

    /** Disable Bluetooth. */
    int (*disable)(void);

    /** Closes the interface. */
    void (*cleanup)(void);

    /** Get all Bluetooth Adapter properties at init */
    int (*get_adapter_properties)(void);

    /** Get Bluetooth Adapter property of 'type' */
    int (*get_adapter_property)(bt_property_type_t type);

    /** Set Bluetooth Adapter property of 'type' */
    /* Based on the type, val shall be one of
     * bt_bdaddr_t or bt_bdname_t or bt_scanmode_t etc
     */
    int (*set_adapter_property)(const bt_property_t *property);

    /** Get all Remote Device properties */
    int (*get_remote_device_properties)(bt_bdaddr_t *remote_addr);

    /** Get Remote Device property of 'type' */
    int (*get_remote_device_property)(bt_bdaddr_t *remote_addr,
                                      bt_property_type_t type);

    /** Set Remote Device property of 'type' */
    int (*set_remote_device_property)(bt_bdaddr_t *remote_addr,
                                      const bt_property_t *property);

    /** Get Remote Device's service record  for the given UUID */
    int (*get_remote_service_record)(bt_bdaddr_t *remote_addr,
                                     bt_uuid_t *uuid);

    /** Start SDP to get remote services */
    int (*get_remote_services)(bt_bdaddr_t *remote_addr);

    /** Start Discovery */
    int (*start_discovery)(void);

    /** Cancel Discovery */
    int (*cancel_discovery)(void);

    /** Create Bluetooth Bonding */
    int (*create_bond)(const bt_bdaddr_t *bd_addr);

    /** Remove Bond */
    int (*remove_bond)(const bt_bdaddr_t *bd_addr);

    /** Cancel Bond */
    int (*cancel_bond)(const bt_bdaddr_t *bd_addr);

    /** BT Legacy PinKey Reply */
    /** If accept==FALSE, then pin_len and pin_code shall be 0x0 */
    int (*pin_reply)(const bt_bdaddr_t *bd_addr, uint8_t accept,
                     uint8_t pin_len, bt_pin_code_t *pin_code);

    /** BT SSP Reply - Just Works, Numeric Comparison and Passkey
     * passkey shall be zero for BT_SSP_VARIANT_PASSKEY_COMPARISON &
     * BT_SSP_VARIANT_CONSENT
     * For BT_SSP_VARIANT_PASSKEY_ENTRY, if accept==FALSE, then passkey
     * shall be zero */
    int (*ssp_reply)(const bt_bdaddr_t *bd_addr, bt_ssp_variant_t variant,
                     uint8_t accept, uint32_t passkey);

    /** Get Bluetooth profile interface */
    const void* (*get_profile_interface) (const char *profile_id);

    /** Bluetooth Test Mode APIs - Bluetooth must be enabled for these APIs */
    /* Configure DUT Mode - Use this mode to enter/exit DUT mode */
    int (*dut_mode_configure)(uint8_t enable);

    /* Send any test HCI (vendor-specific) command to the controller. Must be in DUT Mode */
    int (*dut_mode_send)(uint16_t opcode, uint8_t *buf, uint8_t len);
    /** BLE Test Mode APIs */
    /* opcode MUST be one of: LE_Receiver_Test, LE_Transmitter_Test, LE_Test_End */
    int (*le_test_mode)(uint16_t opcode, uint8_t *buf, uint8_t len);

    /* enable or disable bluetooth HCI snoop log */
    int (*config_hci_snoop_log)(uint8_t enable);
} bt_interface_t;
構造体があれば、構造体対照の関数を探して実現します.
Bluetooth.c (external\bluetooth\bluedroid\btif\src)
const bt_interface_t* bluetooth__get_bluetooth_interface ()
{
    /* fixme -- add property to disable bt interface ? */

    return &bluetoothInterface;
}
static const bt_interface_t bluetoothInterface = {
    sizeof(bluetoothInterface),
    init,
    enable,
    disable,
    cleanup,
    get_adapter_properties,
    get_adapter_property,
    set_adapter_property,
    get_remote_device_properties,
    get_remote_device_property,
    set_remote_device_property,
    get_remote_service_record,
    get_remote_services,
    start_discovery,
    cancel_discovery,
    create_bond,
    remove_bond,
    cancel_bond,
    pin_reply,
    ssp_reply,
    get_profile_interface,
    dut_mode_configure,
    dut_mode_send,
#if BLE_INCLUDED == TRUE
    le_test_mode,
#else
    NULL,
#endif
    config_hci_snoop_log
};
enable関数が見つかりました.では、彼の実装を見てみましょう.
static int enable( void )
{
    ALOGI("enable");

    /* sanity check */
    if (interface_ready() == FALSE)
        return BT_STATUS_NOT_READY;

    return btif_enable_bluetooth();
}
次は関数実装に従って一歩一歩進んだがbtif_enable_bluetooth()は宣言関数があるので、btif_で注意してください.api.h、ここにはコードが貼られていません.続行:
Btif_core.c (\external\bluetooth\bluedroid\btif\src)
bt_status_t btif_enable_bluetooth(void)
{
    BTIF_TRACE_DEBUG0("BTIF ENABLE BLUETOOTH");


    if (btif_core_state != BTIF_CORE_STATE_DISABLED)
    {
        ALOGD("not disabled
");         return BT_STATUS_DONE;     }     btif_core_state = BTIF_CORE_STATE_ENABLING;     /* Create the GKI tasks and run them */     bte_main_enable();     return BT_STATUS_SUCCESS; }
次はbteを探しに行きますmain_Enable関数の実装:
void bte_main_enable()
{
    APPL_TRACE_DEBUG1("%s", __FUNCTION__);

    /* Initialize BTE control block */
    BTE_Init();

    lpm_enabled = FALSE;

    bte_hci_enable();

    GKI_create_task((TASKPTR)btu_task, BTU_TASK, BTE_BTU_TASK_STR,
                    (UINT16 *) ((UINT8 *)bte_btu_stack + BTE_BTU_STACK_SIZE),
                    sizeof(bte_btu_stack));

    GKI_run(0);
}
次はbte_hci_enable、もちろんいくつかの関数があります.BTE_Init()とGKI-
static void bte_hci_enable(void)
{
    APPL_TRACE_DEBUG1("%s", __FUNCTION__);

    preload_start_wait_timer();

    if (bt_hc_if)
    {
        int result = bt_hc_if->init(&hc_callbacks, btif_local_bd_addr.address);
        APPL_TRACE_EVENT1("libbt-hci init returns %d", result);

        assert(result == BT_HC_STATUS_SUCCESS);

        if (hci_logging_enabled == TRUE || hci_logging_config == TRUE)
            bt_hc_if->logging(BT_HC_LOGGING_ON, hci_logfile);

#if (defined (BT_CLEAN_TURN_ON_DISABLED) && BT_CLEAN_TURN_ON_DISABLED == TRUE)
        APPL_TRACE_DEBUG1("%s  Not Turninig Off the BT before Turninig ON", __FUNCTION__);

        /* Do not power off the chip before powering on  if BT_CLEAN_TURN_ON_DISABLED flag
         is defined and set to TRUE to avoid below mentioned issue.

         Wingray kernel driver maintains a combined  counter to keep track of
         BT-Wifi state. Invoking  set_power(BT_HC_CHIP_PWR_OFF) when the BT is already
         in OFF state causes this counter to be incorrectly decremented and results in undesired
         behavior of the chip.

         This is only a workaround and when the issue is fixed in the kernel this work around
         should be removed. */
#else
        /* toggle chip power to ensure we will reset chip in case
           a previous stack shutdown wasn't completed gracefully */
        bt_hc_if->set_power(BT_HC_CHIP_PWR_OFF);
#endif
        bt_hc_if->set_power(BT_HC_CHIP_PWR_ON);

        bt_hc_if->preload(NULL);
    }
}
ここは特に気をつけなければなりません.ここが現実ではないことに気づくからです.
static bt_hc_interface_t *bt_hc_if=NULL;
具体的な対照関係はbt_に行きますhci_lib.hファイルでbtを調べるhc_interface_t構造体の内容は、ここにも貼らない.
関数の照合でBt_が見つかりますhci_bdroid.c(android 4.4externalbluetoothbluedroidhcisrc)、ここがset_Powerの実現.
const bt_hc_interface_t *bt_hc_get_interface(void)
{
    return &bluetoothHCLibInterface;
}
static const bt_hc_interface_t bluetoothHCLibInterface = {
    sizeof(bt_hc_interface_t),
    init,
    set_power,
    lpm,
    preload,
    postload,
    transmit_buf,
    set_rxflow,
    logging,
    cleanup
};
この時点でset_を探すことができますPowerの実現:
/** Chip power control */
static void set_power(bt_hc_chip_power_state_t state)
{
    int pwr_state;

    BTHCDBG("set_power %d", state);

    /* Calling vendor-specific part */
    pwr_state = (state == BT_HC_CHIP_PWR_ON) ? BT_VND_PWR_ON : BT_VND_PWR_OFF;

    if (bt_vnd_if)
        bt_vnd_if->op(BT_VND_OP_POWER_CTRL, &pwr_state);
    else
        ALOGE("vendor lib is missing!");
}
この時また関数対照を行いますextern bt_vendor_interface_t *bt_vnd_if;でも気をつけてね
bt_vendor_interface_tの構造体はBt_vendor_lib.h (\external\bluetooth\bluedroid\hci\include)
みんなは自分で調べてもいいです.私のところにも貼っていません.
この時、Bt_でop関数の実装を探します.vendor_brcm.c (\android4.4\hardware\broadcom\libbt\src)
// Entry point of DLib
const bt_vendor_interface_t BLUETOOTH_VENDOR_LIB_INTERFACE = {
    sizeof(bt_vendor_interface_t),
    init,
    op,
    cleanup
};
static int op(bt_vendor_opcode_t opcode, void *param)
{
    int retval = 0;

    BTVNDDBG("op for %d", opcode);

    switch(opcode)
    {
        case BT_VND_OP_POWER_CTRL:
            {
                int *state = (int *) param;
                if (*state == BT_VND_PWR_OFF)
                    upio_set_bluetooth_power(UPIO_BT_POWER_OFF);
                else if (*state == BT_VND_PWR_ON)
                    upio_set_bluetooth_power(UPIO_BT_POWER_ON);
            }
            break;

        case BT_VND_OP_FW_CFG:
            {
                hw_config_start();
            }
            break;

        case BT_VND_OP_SCO_CFG:
            {
#if (SCO_CFG_INCLUDED == TRUE)
                hw_sco_config();
#else
                retval = -1;
#endif
            }
            break;

        case BT_VND_OP_USERIAL_OPEN:
            {
                int (*fd_array)[] = (int (*)[]) param;
                int fd, idx;
                fd = userial_vendor_open((tUSERIAL_CFG *) &userial_init_cfg);
                if (fd != -1)
                {
                    for (idx=0; idx < CH_MAX; idx++)
                        (*fd_array)[idx] = fd;

                    retval = 1;
                }
                /* retval contains numbers of open fd of HCI channels */
            }
            break;

        case BT_VND_OP_USERIAL_CLOSE:
            {
                userial_vendor_close();
            }
            break;

        case BT_VND_OP_GET_LPM_IDLE_TIMEOUT:
            {
                uint32_t *timeout_ms = (uint32_t *) param;
                *timeout_ms = hw_lpm_get_idle_timeout();
            }
            break;

        case BT_VND_OP_LPM_SET_MODE:
            {
                uint8_t *mode = (uint8_t *) param;
                retval = hw_lpm_enable(*mode);
            }
            break;

        case BT_VND_OP_LPM_WAKE_SET_STATE:
            {
                uint8_t *state = (uint8_t *) param;
                uint8_t wake_assert = (*state == BT_VND_LPM_WAKE_ASSERT) ? \
                                        TRUE : FALSE;

                hw_lpm_set_wake_state(wake_assert);
            }
            break;

        case BT_VND_OP_EPILOG:
            {
#if (HW_END_WITH_HCI_RESET == FALSE)
                if (bt_vendor_cbacks)
                {
                    bt_vendor_cbacks->epilog_cb(BT_VND_OP_RESULT_SUCCESS);
                }
#else
                hw_epilog_process();
#endif
            }
            break;
    }

    return retval;
}
BT_VND_OP_POWER_CTRL
        case BT_VND_OP_POWER_CTRL:
            {
                int *state = (int *) param;
                if (*state == BT_VND_PWR_OFF)
                    upio_set_bluetooth_power(UPIO_BT_POWER_OFF);
                else if (*state == BT_VND_PWR_ON)
                    upio_set_bluetooth_power(UPIO_BT_POWER_ON);
            }
            break;
upio_set_bluetooth_power(UPIO_BT_POWER_ON); :

Upio.c (android4.4\hardware\broadcom\libbt\src)

, android4.3 bluetooth.c, :

static int init_rfkill()
{
    char path[64];
    char buf[16];
    int fd, sz, id;

    if (is_rfkill_disabled())
        return -1;

    for (id = 0; ; id++)
    {
        snprintf(path, sizeof(path), "/sys/class/rfkill/rfkill%d/type", id);
        fd = open(path, O_RDONLY);
        if (fd < 0)
        {
            ALOGE("init_rfkill : open(%s) failed: %s (%d)
", \ path, strerror(errno), errno); return -1; } sz = read(fd, &buf, sizeof(buf)); close(fd); if (sz >= 9 && memcmp(buf, "bluetooth", 9) == 0) { rfkill_id = id; break; } } asprintf(&rfkill_state_path, "/sys/class/rfkill/rfkill%d/state", rfkill_id); return 0; }

int upio_set_bluetooth_power(int on)
{
    int sz;
    int fd = -1;
    int ret = -1;
    char buffer = '0';

    switch(on)
    {
        case UPIO_BT_POWER_OFF:
            buffer = '0';
            break;

        case UPIO_BT_POWER_ON:
            buffer = '1';
            break;
    }

    if (is_emulator_context())
    {
        /* if new value is same as current, return -1 */
        if (bt_emul_enable == on)
            return ret;

        UPIODBG("set_bluetooth_power [emul] %d", on);

        bt_emul_enable = on;
        return 0;
    }

    /* check if we have rfkill interface */
    if (is_rfkill_disabled())
        return 0;

    if (rfkill_id == -1)
    {
        if (init_rfkill())
            return ret;
    }

    fd = open(rfkill_state_path, O_WRONLY);

    if (fd < 0)
    {
        ALOGE("set_bluetooth_power : open(%s) for write failed: %s (%d)",
            rfkill_state_path, strerror(errno), errno);
        return ret;
    }

    sz = write(fd, &buffer, 1);

    if (sz < 0) {
        ALOGE("set_bluetooth_power : write(%s) failed: %s (%d)",
            rfkill_state_path, strerror(errno),errno);
    }
    else
        ret = 0;

    if (fd >= 0)
        close(fd);

    return ret;
}

, rfkill , kernel bluetooth sys 。

scan connect , 。