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相關流程。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章