当前位置: 代码迷 >> Android >> android5.0(Lollipop) BLE Peripheral深入了解系统篇之提高篇
  详细解决方案

android5.0(Lollipop) BLE Peripheral深入了解系统篇之提高篇

热度:215   发布时间:2016-04-28 00:20:58.0
android5.0(Lollipop) BLE Peripheral深入理解系统篇之提高篇

转载请表明出处:http://blog.csdn.net/lansefeiyang08/article/details/46545215

上一篇文章讲到了广播之前系统需要进行的准备工作,那接下来我们就来真正的启动广播。

首先还是先看一下上一篇文章结束的地方:

        @Override        public void onClientRegistered(int status, int clientIf) {            Log.d(TAG, "onClientRegistered() - status=" + status + " clientIf=" + clientIf);            synchronized (this) {                if (status == BluetoothGatt.GATT_SUCCESS) {                    mClientIf = clientIf;                    try {                        mBluetoothGatt.startMultiAdvertising(mClientIf, mAdvertisement,                                mScanResponse, mSettings);                        return;                    } catch (RemoteException e) {                        Log.e(TAG, "failed to start advertising", e);                    }                }                // Registration failed.                mClientIf = -1;                notifyAll();            }        }
现在让我们继续追踪mBluetoothGatt.startMultiAdvertising,但是我们发现mBluetoothGatt是通过AIDL來定义的:

<span style="font-size:14px;">private final IBluetoothGatt mBluetoothGatt;</span>
到这里,我们就不去看IBluetoothGatt的内容了,因为都是一些接口函数,我们比较关心的是IBluetoothGatt是谁的接口呢,在android如果遇到这种情况,我们肯定要去找service了,那我们现在基本可以确定,我们找的是GattService了,那我们去验证一下,到底是不是这样的:

private static class BluetoothGattBinder extends IBluetoothGatt.Stub implements IProfileServiceBinder 
看到这里我们应该可以确认tartMultiAdvertising的实现是在这里,那我们找一下它的实现:

        @Override        public void startMultiAdvertising(int clientIf, AdvertiseData advertiseData,                AdvertiseData scanResponse, AdvertiseSettings settings) {            GattService service = getService();            if (service == null) return;            service.startMultiAdvertising(clientIf, advertiseData, scanResponse, settings);        }
终于找到它的实现了,它却有用了GattService自己内部的实现,那我们继续看一下:

    void startMultiAdvertising(int clientIf, AdvertiseData advertiseData,            AdvertiseData scanResponse, AdvertiseSettings settings) {        enforceAdminPermission();        mAdvertiseManager.startAdvertising(new AdvertiseClient(clientIf, settings, advertiseData,                scanResponse));    }
到这里,我们有可以比较顺利的追踪了,那我们继续看一下AdvertiserManager是怎样定义它的:

    void startAdvertising(AdvertiseClient client) {        if (client == null) {            return;        }        Message message = new Message();        message.what = MSG_START_ADVERTISING;        message.obj = client;        mHandler.sendMessage(message);    }
到这里,发现竟然只是发了一个handler message,那我们就去看看这个handler是怎么处理
        @Override        public void handleMessage(Message msg) {            logd("message : " + msg.what);            AdvertiseClient client = (AdvertiseClient) msg.obj;            switch (msg.what) {                case MSG_START_ADVERTISING:                    handleStartAdvertising(client);                    break;                case MSG_STOP_ADVERTISING:                    handleStopAdvertising(client);                    break;                default:                    // Shouldn't happen.                    Log.e(TAG, "recieve an unknown message : " + msg.what);                    break;            }        }
        private void handleStartAdvertising(AdvertiseClient client) {            Utils.enforceAdminPermission(mService);            int clientIf = client.clientIf;            if (mAdvertiseClients.contains(clientIf)) {                postCallback(clientIf, AdvertiseCallback.ADVERTISE_FAILED_ALREADY_STARTED);                return;            }            if (mAdvertiseClients.size() >= maxAdvertiseInstances()) {                postCallback(clientIf,                        AdvertiseCallback.ADVERTISE_FAILED_TOO_MANY_ADVERTISERS);                return;            }            if (!mAdvertiseNative.startAdverising(client)) {                postCallback(clientIf, AdvertiseCallback.ADVERTISE_FAILED_INTERNAL_ERROR);                return;            }            mAdvertiseClients.add(client);            postCallback(clientIf, AdvertiseCallback.ADVERTISE_SUCCESS);        }
到这里了,我们也看到了关键函数mAdvertiseNative.startAdvertising函数:

        boolean startAdverising(AdvertiseClient client) {            if (!mAdapterService.isMultiAdvertisementSupported() &&                    !mAdapterService.isPeripheralModeSupported()) {                return false;            }            if (mAdapterService.isMultiAdvertisementSupported()) {                return startMultiAdvertising(client);            }            return startSingleAdvertising(client);        }
这里我们就选择任意一个函数就讲解,就选择startSingleAdvertising来讲好了:

        boolean startSingleAdvertising(AdvertiseClient client) {            logd("starting single advertising");            resetCountDownLatch();            enableAdvertising(client);            if (!waitForCallback()) {                return false;            }            setAdvertisingData(client, client.advertiseData, false);            return true;        }
这里面有两个关键点,一个是使能Advertising,另一个是设置AdvertisingData要发的数据。我们先来看一下enableAdvertising:

        private void enableAdvertising(AdvertiseClient client) {            int clientIf = client.clientIf;            int minAdvertiseUnit = (int) getAdvertisingIntervalUnit(client.settings);            int maxAdvertiseUnit = minAdvertiseUnit + ADVERTISING_INTERVAL_DELTA_UNIT;            int advertiseEventType = getAdvertisingEventType(client);            int txPowerLevel = getTxPowerLevel(client.settings);            int advertiseTimeoutSeconds = (int) TimeUnit.MILLISECONDS.toSeconds(                    client.settings.getTimeout());            if (mAdapterService.isMultiAdvertisementSupported()) {                Log.i(TAG, "gattClientEnableAdvNative(" + clientIf + ",...);");                gattClientEnableAdvNative(                        clientIf,                        minAdvertiseUnit, maxAdvertiseUnit,                        advertiseEventType,                        ADVERTISING_CHANNEL_ALL,                        txPowerLevel,                        advertiseTimeoutSeconds);            } else {                Log.i(TAG, "gattAdvertiseNative(" + client.clientIf + ",true);");                gattAdvertiseNative(client.clientIf, true);            }        }
这里面主要是在设置一些参数,比如最大广播间隔设置的是10ms+设置的最小间隔,TxPower的级别等等。这里面对于多广播和单广播调用的底层是不一样的。我们这里看看单广播gattAdvertiseNative(client.clientIf, true);实现如下:

static void gattAdvertiseNative(JNIEnv *env, jobject object,        jint client_if, jboolean start){    if (!sGattIf) return;    sGattIf->client->listen(client_if, start);}
这里的映射关系我就不再介绍了,上一篇文章已经都介绍一次了,我们这里直接看看listen函数:

static bt_status_t btif_gattc_listen(int client_if, bool start){    CHECK_BTGATT_INIT();    btif_gattc_cb_t btif_cb;    btif_cb.client_if = (uint8_t) client_if;    btif_cb.start = start ? 1 : 0;    return btif_transfer_context(btgattc_handle_event, BTIF_GATTC_LISTEN,                                 (char*) &btif_cb, sizeof(btif_gattc_cb_t), NULL);}
直接看实现:
static void btgattc_handle_event(uint16_t event, char* p_param){     ……    switch (event)    {case BTIF_GATTC_LISTEN:#if (defined(BLE_PERIPHERAL_MODE_SUPPORT) && (BLE_PERIPHERAL_MODE_SUPPORT == TRUE))            BTA_GATTC_Listen(p_cb->client_if, p_cb->start, NULL);#else            BTA_GATTC_Broadcast(p_cb->client_if, p_cb->start);#endif            break;          ……
目前我用的设备BLE_PERIPHERAL_MODE_SUPPORT是true,所以我们进入BTA_GATTC_Listen:

void BTA_GATTC_Listen(tBTA_GATTC_IF client_if, BOOLEAN start, BD_ADDR_PTR target_bda){    tBTA_GATTC_API_LISTEN  *p_buf;    if ((p_buf = (tBTA_GATTC_API_LISTEN *) GKI_getbuf((UINT16)(sizeof(tBTA_GATTC_API_LISTEN) + BD_ADDR_LEN))) != NULL)    {        p_buf->hdr.event = BTA_GATTC_API_LISTEN_EVT;        p_buf->client_if = client_if;        p_buf->start = start;        if (target_bda)        {            p_buf->remote_bda = (UINT8*)(p_buf + 1);            memcpy(p_buf->remote_bda, target_bda, BD_ADDR_LEN);        }        else            p_buf->remote_bda = NULL;        bta_sys_sendmsg(p_buf);    }    return;}
这里是开始进入广播且监听一个client设备的连接请求。这里要注意一下event时间,这个时间会被触发:

BOOLEAN bta_gattc_hdl_event(BT_HDR *p_msg){      ……      case BTA_GATTC_API_LISTEN_EVT:            bta_gattc_listen(p_cb, (tBTA_GATTC_DATA *) p_msg);            break;      ……
void bta_gattc_listen(tBTA_GATTC_CB *p_cb, tBTA_GATTC_DATA * p_msg){    tBTA_GATTC_RCB      *p_clreg = bta_gattc_cl_get_regcb(p_msg->api_listen.client_if);    tBTA_GATTC          cb_data;    UNUSED(p_cb);    cb_data.reg_oper.status = BTA_GATT_ERROR;    cb_data.reg_oper.client_if = p_msg->api_listen.client_if;    if (p_clreg == NULL)    {        APPL_TRACE_ERROR("bta_gattc_listen failed, unknown client_if: %d",                            p_msg->api_listen.client_if);        return;    }    /* mark bg conn record */    if (bta_gattc_mark_bg_conn(p_msg->api_listen.client_if,                               (BD_ADDR_PTR) p_msg->api_listen.remote_bda,                               p_msg->api_listen.start,                               TRUE))    {        if (!GATT_Listen(p_msg->api_listen.client_if,                         p_msg->api_listen.start,                         p_msg->api_listen.remote_bda))        {            APPL_TRACE_ERROR("Listen failure");            (*p_clreg->p_cback)(BTA_GATTC_LISTEN_EVT, &cb_data);        }        else        {            cb_data.status = BTA_GATT_OK;            (*p_clreg->p_cback)(BTA_GATTC_LISTEN_EVT, &cb_data);            if (p_msg->api_listen.start)            {                /* if listen to a specific target */                if (p_msg->api_listen.remote_bda != NULL)                {                    /* if is a connected remote device */                    if (L2CA_GetBleConnRole(p_msg->api_listen.remote_bda) == HCI_ROLE_SLAVE &&                        bta_gattc_find_clcb_by_cif(p_msg->api_listen.client_if,                                                   p_msg->api_listen.remote_bda,                                                   BTA_GATT_TRANSPORT_LE) == NULL)                    {                        bta_gattc_init_clcb_conn(p_msg->api_listen.client_if,                                                p_msg->api_listen.remote_bda);                    }                }                /* if listen to all */                else                {                    APPL_TRACE_ERROR("Listen For All now");                    /* go through all connected device and send                    callback for all connected slave connection */                    bta_gattc_process_listen_all(p_msg->api_listen.client_if);                }            }        }    }}
到这里,剩下的全是连接相关,我自己都有点绕,所以暂时就不讲解了。这块后期再补上。

 <span style="font-size:14px;">       private void setAdvertisingData(AdvertiseClient client, AdvertiseData data,                boolean isScanResponse) {            if (data == null) {                return;            }            boolean includeName = data.getIncludeDeviceName();            boolean includeTxPower = data.getIncludeTxPowerLevel();            int appearance = 0;            byte[] manufacturerData = getManufacturerData(data);            byte[] serviceData = getServiceData(data);            byte[] serviceUuids;            if (data.getServiceUuids() == null) {                serviceUuids = new byte[0];            } else {                ByteBuffer advertisingUuidBytes = ByteBuffer.allocate(                        data.getServiceUuids().size() * 16)                        .order(ByteOrder.LITTLE_ENDIAN);                for (ParcelUuid parcelUuid : data.getServiceUuids()) {                    UUID uuid = parcelUuid.getUuid();                    // Least significant bits first as the advertising UUID should be in                    // little-endian.                    advertisingUuidBytes.putLong(uuid.getLeastSignificantBits())                            .putLong(uuid.getMostSignificantBits());                }                serviceUuids = advertisingUuidBytes.array();            }            if (mAdapterService.isMultiAdvertisementSupported()) {                Log.i(TAG, "gattClientSetAdvDataNative(" + client.clientIf + ",...);");                gattClientSetAdvDataNative(client.clientIf, isScanResponse, includeName,                        includeTxPower, appearance,                        manufacturerData, serviceData, serviceUuids);            } else {                Log.i(TAG, "gattSetAdvDataNative(" + client.clientIf + ",...);");                gattSetAdvDataNative(client.clientIf, isScanResponse, includeName,                        includeTxPower, 0, 0, appearance,                        manufacturerData, serviceData, serviceUuids);            }        }</span>
<span style="font-size:14px;">static void gattSetAdvDataNative(JNIEnv *env, jobject object, jint client_if,        jboolean setScanRsp, jboolean inclName, jboolean inclTxPower, jint minInterval,        jint maxInterval, jint appearance, jbyteArray manufacturerData, jbyteArray serviceData,        jbyteArray serviceUuid){    if (!sGattIf) return;    jbyte* arr_data = env->GetByteArrayElements(manufacturerData, NULL);    uint16_t arr_len = (uint16_t) env->GetArrayLength(manufacturerData);    jbyte* service_data = env->GetByteArrayElements(serviceData, NULL);    uint16_t service_data_len = (uint16_t) env->GetArrayLength(serviceData);    jbyte* service_uuid = env->GetByteArrayElements(serviceUuid, NULL);    uint16_t service_uuid_len = (uint16_t) env->GetArrayLength(serviceUuid);    sGattIf->client->set_adv_data(client_if, setScanRsp, inclName, inclTxPower,        minInterval, maxInterval, appearance, arr_len, (char*)arr_data,        service_data_len, (char*)service_data, service_uuid_len,        (char*)service_uuid);    env->ReleaseByteArrayElements(manufacturerData, arr_data, JNI_ABORT);    env->ReleaseByteArrayElements(serviceData, service_data, JNI_ABORT);    env->ReleaseByteArrayElements(serviceUuid, service_uuid, JNI_ABORT);}</span>
那我们就来主要看看set_adv_data函数:

static bt_status_t btif_gattc_set_adv_data(int client_if, bool set_scan_rsp, bool include_name,                bool include_txpower, int min_interval, int max_interval, int appearance,                uint16_t manufacturer_len, char* manufacturer_data,                uint16_t service_data_len, char* service_data,                uint16_t service_uuid_len, char* service_uuid){    CHECK_BTGATT_INIT();    bt_status_t status =0;    btif_adv_data_t adv_data;    btif_gattc_adv_data_packager(client_if, set_scan_rsp, include_name,        include_txpower, min_interval, max_interval, appearance, manufacturer_len,        manufacturer_data, service_data_len, service_data, service_uuid_len, service_uuid,        &adv_data);    status = btif_transfer_context(btgattc_handle_event, BTIF_GATTC_SET_ADV_DATA,                       (char*) &adv_data, sizeof(btif_adv_data_t), NULL);    if (NULL != adv_data.p_service_data)        GKI_freebuf(adv_data.p_service_data);    if (NULL != adv_data.p_service_uuid)        GKI_freebuf(adv_data.p_service_uuid);    if (NULL != adv_data.p_manufacturer_data)        GKI_freebuf(adv_data.p_manufacturer_data);    return status;}
其中btif_gattc_adv_data_packager直接到了GKI,所以我们来看一下btgattc_handle_event触发的event事件:

        case BTIF_GATTC_SET_ADV_DATA:        {            btif_adv_data_t *p_adv_data = (btif_adv_data_t*) p_param;            int cbindex = CLNT_IF_IDX;            if (cbindex >= 0 && NULL != p_adv_data)            {                btgatt_multi_adv_common_data *p_multi_adv_data_cb = btif_obtain_multi_adv_data_cb();                if (!btif_gattc_copy_datacb(cbindex, p_adv_data, false))                    return;                if (!p_adv_data->set_scan_rsp)                {                    BTA_DmBleSetAdvConfig(p_multi_adv_data_cb->inst_cb[cbindex].mask,                        &p_multi_adv_data_cb->inst_cb[cbindex].data, bta_gattc_set_adv_data_cback);                }                else                {                    BTA_DmBleSetScanRsp(p_multi_adv_data_cb->inst_cb[cbindex].mask,                        &p_multi_adv_data_cb->inst_cb[cbindex].data, bta_gattc_set_adv_data_cback);                }                break;            }        }
这里我们主要是走了BTA_DmBleSetAdvConfig:

void BTA_DmBleSetAdvConfig (tBTA_BLE_AD_MASK data_mask, tBTA_BLE_ADV_DATA *p_adv_cfg,                            tBTA_SET_ADV_DATA_CMPL_CBACK *p_adv_data_cback){    tBTA_DM_API_SET_ADV_CONFIG  *p_msg;    if ((p_msg = (tBTA_DM_API_SET_ADV_CONFIG *)        GKI_getbuf(sizeof(tBTA_DM_API_SET_ADV_CONFIG))) != NULL)    {        p_msg->hdr.event = BTA_DM_API_BLE_SET_ADV_CONFIG_EVT;        p_msg->data_mask = data_mask;        p_msg->p_adv_data_cback = p_adv_data_cback;        p_msg->p_adv_cfg = p_adv_cfg;        bta_sys_sendmsg(p_msg);    }}
这里实际会走到
void bta_dm_ble_set_adv_config (tBTA_DM_MSG *p_data){    tBTA_STATUS status = BTA_FAILURE;    if (BTM_BleWriteAdvData(p_data->ble_set_adv_data.data_mask,                        (tBTM_BLE_ADV_DATA *)p_data->ble_set_adv_data.p_adv_cfg) == BTM_SUCCESS)    {        status = BTA_SUCCESS;    }    if (p_data->ble_set_adv_data.p_adv_data_cback)        (*p_data->ble_set_adv_data.p_adv_data_cback)(status);}
tBTM_STATUS BTM_BleWriteAdvData(tBTM_BLE_AD_MASK data_mask, tBTM_BLE_ADV_DATA *p_data){    tBTM_BLE_LOCAL_ADV_DATA *p_cb_data = &btm_cb.ble_ctr_cb.inq_var.adv_data;    UINT8  *p;    tBTM_BLE_AD_MASK   mask = data_mask;    BTM_TRACE_EVENT ("BTM_BleWriteAdvData ");    if (!HCI_LE_HOST_SUPPORTED(btm_cb.devcb.local_lmp_features[HCI_EXT_FEATURES_PAGE_1]))        return BTM_ILLEGAL_VALUE;    memset(p_cb_data, 0, sizeof(tBTM_BLE_LOCAL_ADV_DATA));    p = p_cb_data->ad_data;    p_cb_data->data_mask = data_mask;    p_cb_data->p_flags = btm_ble_build_adv_data(&mask, &p, p_data);    p_cb_data->p_pad = p;    if (mask != 0)    {        BTM_TRACE_ERROR("Partial data write into ADV");    }    p_cb_data->data_mask &= ~mask;    if (btsnd_hcic_ble_set_adv_data((UINT8)(p_cb_data->p_pad - p_cb_data->ad_data),                                    p_cb_data->ad_data))        return BTM_SUCCESS;    else        return BTM_NO_RESOURCES;}
BOOLEAN btsnd_hcic_ble_set_adv_data (UINT8 data_len, UINT8 *p_data){    BT_HDR *p;    UINT8 *pp;    if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_BLE_WRITE_ADV_DATA + 1)) == NULL)        return (FALSE);    pp = (UINT8 *)(p + 1);    p->len    = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_BLE_WRITE_ADV_DATA + 1;    p->offset = 0;    UINT16_TO_STREAM (pp, HCI_BLE_WRITE_ADV_DATA);    UINT8_TO_STREAM  (pp, HCIC_PARAM_SIZE_BLE_WRITE_ADV_DATA + 1);    memset(pp, 0, HCIC_PARAM_SIZE_BLE_WRITE_ADV_DATA);    if (p_data != NULL && data_len > 0)    {        if (data_len > HCIC_PARAM_SIZE_BLE_WRITE_ADV_DATA)            data_len = HCIC_PARAM_SIZE_BLE_WRITE_ADV_DATA;        UINT8_TO_STREAM (pp, data_len);        ARRAY_TO_STREAM (pp, p_data, data_len);    }    btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID,  p);    return (TRUE);}
后面已经直接在btu通信了,我们也就不深入了。

所以步骤跑完,在callback就会获得onSuccess中。

广播就结束了,后面我会继续更新Central相关流程。


  相关解决方案