http://blog.csdn.net/lansefeiyang08/article/details/46505921
上周花了两天时间简单试了一下android L BLE Peripheral和Central角色的应用开发。基本功能也差不多可以实现,那接下来我们就要來看一下系统里,android L是如何加入Peripheral角色,工作原理到底是什么样子的,SDK里的接口怎么用才能实现我们想要的功能,android协议里对一些BLE参数设定是什么,下面我们來一下看一下。
关于Peripheral角色的实现,我会按照应用开发的流程來讲解,简单讲就是从启动到工作,系统里的GATT是如何完成Peripheral的。此篇文章可能不是应用开发工程师关注的,但是对于和真正的BLE外设联调,有些功能了解一下还是很有帮助的。当然后面我会继续更新Central角色的实现,对所有人都会有帮助,因为BLE外设的流行,手机Central角色遇到的问题也会越多,想了解原理的让你也会越多,敬请期待。好了,我们继续Peripheral的工作。
可能有人会有疑惑,为什么我开始写博客是从Peripheral开始而不是应用更广泛的Central。其实我的想法很简单,知己知彼,百战不殆。想深入了解Central,最好还是先了解它的搭档Peripheral,虽然android系统很少用到,但是既然Android L更新了,那就肯定有他亮点和用处。好了我们正式开始了解整个流程。还是和以前一样,代码+解析架构。由于牵扯的东西比较多,为了减少每篇篇幅,我计划分两次來完成。
对于蓝牙标准的东西,比如检查是否支持蓝牙、是否支持BLE我就不讲了,因为不管是传统蓝牙还是BLE,其实都是一样的。那我们就从获得BluetoothAdapter开始。
如果你开发过SPP,那么你应该会熟悉如下代码:
<span style="font-size:14px;"> // Get local Bluetooth adapter
mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();</span>
那现在就有一点改变了,BLE获得的BluetoothAdapter并不用BluetoothAdapter里的方法,而是用了如下代码:
<span style="font-size:14px;"> final BluetoothManager mBluetoothManager = (BluetoothManager) getSystemService(BLUETOOTH_SERVICE);
mBluetoothAdapter = mBluetoothManager.getAdapter();</span>
你可能会有疑惑,为什么会有如此差别呢?实际上BluetoothManager这个类是专门为GATT和GATT SERVER服务的,最终通过BluetoothManager获得的mBluetoothAdapter最终也是调用了BluetoothAdapter里的getDefaultAdapter。好吧,你应该发现了,实际上这两个类是一样的,但是BluetoothManager类里方法还是比较好用,一个是getConnectionState(BluetoothDevice device, int profile)用来获得远端BLE设备的连接状态;另外一种是getConnectedDevices(int profile)用来获得某种profile的已连接设备;还有一个可能会用到的是openGattServer(Context context,BluetoothGattServerCallback callback),此方法在android L之前就已经存在,且更新了Advertiser接口也并没有弃用,说明此方法肯定有它的作用(Nordic开发的BLE应用,是用OpenGattServer启动这个BLE应用的,此做法的好处暂时不详,不过我猜是为了使用Find Me功能,如果有人知道,可以告诉我。
获得了关键的bluetoothadapter,剩下來就是要实例化BluetoothLeAdvertiser:
<span style="font-size:14px;">mBluetoothLeAdvertiser = mBluetoothAdapter.getBluetoothLeAdvertiser();</span>
让我们看看Adapter里getBluetoothLeAdvertiser到底做了什么:
<span style="font-size:14px;"> public BluetoothLeAdvertiser getBluetoothLeAdvertiser() {
if (getState() != STATE_ON) {
return null;
}
if (!isMultipleAdvertisementSupported()) {
return null;
}
synchronized(mLock) {
if (sBluetoothLeAdvertiser == null) {
sBluetoothLeAdvertiser = new BluetoothLeAdvertiser(mManagerService);
}
}
return sBluetoothLeAdvertiser;
}</span>
你可以看到,实际上就做了两件事,一件事是判断蓝牙有没有打开,判断支持不支持BLE Advertise模式,这两种情况失败都会返回null,所以如果你在开发应用时,一定要先把蓝牙是否打开判断了,如果再执行这段代码返回null,那就是你本地设备不支持BLE Advertise了;第二件事是实例化了BluetoothLeAdvertiser,最后返回实例化的对象。接下来我们继续往下看:
<span style="font-size:14px;"> public BluetoothLeAdvertiser(IBluetoothManager bluetoothManager) {
mBluetoothManager = bluetoothManager;
mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
mHandler = new Handler(Looper.getMainLooper());
}</span>
这里是实例化代码,你会看到为了拿到BluetoothAdapter,代码里又执行了一遍此类。可能有些人会有疑问,这样执行多遍,不会拿到的BluetoothAdapter会不会不是同一个呀,实际上是这样的,google默认只支持一个BlueoothAdapter,所以你执行多遍获得也是你本地唯一的Adapter。
实例化结束了,发现这个都没有跑到系统里去。那我们继续往下看应用开发流程。
接下来是要实例化AdvertiseSettings喝AdvertiseData两个类,这两个类都是在准备最后一步广播所需要的参数,也没有真正的走进蓝牙协议里,所以我们就直接看最后一步广播:
<span style="font-size:14px;">mBluetoothLeAdvertiser.startAdvertising(createAdvSettings(true, 0), createAdvertiseData(), mAdvertiseCallback);</span>
上一篇的文章已经把应用代码贴出来了,所以我们还是沿用之前的代码,我们来看看startAdvertising到底干了什么:
<span style="font-size:14px;"> public void startAdvertising(AdvertiseSettings settings,
AdvertiseData advertiseData, final AdvertiseCallback callback) {
startAdvertising(settings, advertiseData, null, callback);
}</span>
发现它调用了自己类的另一个startAdvertising方法,并且多了一个参数scanResponse:
<span style="font-size:14px;"> public void startAdvertising(AdvertiseSettings settings,
AdvertiseData advertiseData, AdvertiseData scanResponse,
final AdvertiseCallback callback) {
synchronized (mLeAdvertisers) {
BluetoothLeUtils.checkAdapterStateOn(mBluetoothAdapter);
if (callback == null) {
throw new IllegalArgumentException("callback cannot be null");
}
if (!mBluetoothAdapter.isMultipleAdvertisementSupported()) {
postStartFailure(callback,
AdvertiseCallback.ADVERTISE_FAILED_FEATURE_UNSUPPORTED);
return;
}
if (totalBytes(advertiseData) > MAX_ADVERTISING_DATA_BYTES ||
totalBytes(scanResponse) > MAX_ADVERTISING_DATA_BYTES) {
postStartFailure(callback, AdvertiseCallback.ADVERTISE_FAILED_DATA_TOO_LARGE);
return;
}
if (mLeAdvertisers.containsKey(callback)) {
postStartFailure(callback, AdvertiseCallback.ADVERTISE_FAILED_ALREADY_STARTED);
return;
}
IBluetoothGatt gatt;
try {
gatt = mBluetoothManager.getBluetoothGatt();
} catch (RemoteException e) {
Log.e(TAG, "Failed to get Bluetooth gatt - ", e);
postStartFailure(callback, AdvertiseCallback.ADVERTISE_FAILED_INTERNAL_ERROR);
return;
}
AdvertiseCallbackWrapper wrapper = new AdvertiseCallbackWrapper(callback, advertiseData,
scanResponse, settings, gatt);
wrapper.startRegisteration();
}
}</span>
这里需要注意几个点:
(1)你必须实例化一个回调函数
(2)广播最大数据字节数:当前广播的最大数据字节数是31Bytes
(3)获得了gatt的接口
(4)实例化AdvertiseCallbackWraper,调用startRegisteration方法。
那我们现在依次看这几个关键点:
(1)回调函数AdvertiseCallback,此回调类会收到两个回调方法onStartSuccess(AdvertiseSettings settingsInEffect)和onStartFailure(int errorCode),由于上一次应用篇已经讲了,这里就不过多的讲述了。
(2)最大字节数没有什么好讲的,大家注意这些细节就好
(3)gatt接口,这里我们需要注意一下mBluetoothManager的定义:
<span style="font-size:14px;"> private final IBluetoothManager mBluetoothManager;</span>
那我们看看IBluetoothManager的实现:
<span style="font-size:14px;">/**
* System private API for talking with the Bluetooth service.
*
* {@hide}
*/
interface IBluetoothManager
{
……
IBluetoothGatt getBluetoothGatt();
……
}
</span>
原来它关联了IBluetoothGatt,那我们继续去追踪IBluetoothGatt,里面的接口都是Gatt的隐藏接口,他会在(4)中被用到:
<span style="font-size:14px;">/**
* API for interacting with BLE / GATT
* @hide
*/
interface IBluetoothGatt {
List<BluetoothDevice> getDevicesMatchingConnectionStates(in int[] states);
void startScan(in int appIf, in boolean isServer, in ScanSettings settings, in List<ScanFilter> filters, in List scanStorages);
void stopScan(in int appIf, in boolean isServer);
void flushPendingBatchResults(in int appIf, in boolean isServer);
void startMultiAdvertising(in int appIf, in AdvertiseData advertiseData, in AdvertiseData scanResponse,
in AdvertiseSettings settings);
void stopMultiAdvertising(in int appIf);
void registerClient(in ParcelUuid appId, in IBluetoothGattCallback callback);
void unregisterClient(in int clientIf);
void clientConnect(in int clientIf, in String address, in boolean isDirect, in int transport);
void clientDisconnect(in int clientIf, in String address);
void refreshDevice(in int clientIf, in String address);
void discoverServices(in int clientIf, in String address);
void readCharacteristic(in int clientIf, in String address, in int srvcType, in int srvcInstanceId, in ParcelUuid srvcId,
in int charInstanceId, in ParcelUuid charId, in int authReq);
void writeCharacteristic(in int clientIf, in String address, in int srvcType, in int srvcInstanceId, in ParcelUuid srvcId,
in int charInstanceId, in ParcelUuid charId, in int writeType, in int authReq, in byte[] value);
void readDescriptor(in int clientIf, in String address, in int srvcType, in int srvcInstanceId, in ParcelUuid srvcId,
in int charInstanceId, in ParcelUuid charId, in int descrInstanceId, in ParcelUuid descrUuid, in int authReq);
void writeDescriptor(in int clientIf, in String address, in int srvcType, in int srvcInstanceId, in ParcelUuid srvcId,
in int charInstanceId, in ParcelUuid charId, in int descrInstanceId, in ParcelUuid descrId,
in int writeType, in int authReq, in byte[] value);
void registerForNotification(in int clientIf, in String address, in int srvcType, in int srvcInstanceId, in ParcelUuid srvcId,
in int charInstanceId, in ParcelUuid charId, in boolean enable);
void beginReliableWrite(in int clientIf, in String address);
void endReliableWrite(in int clientIf, in String address, in boolean execute);
void readRemoteRssi(in int clientIf, in String address);
void configureMTU(in int clientIf, in String address, in int mtu);
void connectionParameterUpdate(in int clientIf, in String address, in int connectionPriority);
void registerServer(in ParcelUuid appId, in IBluetoothGattServerCallback callback);
void unregisterServer(in int serverIf);
void serverConnect(in int servertIf, in String address, in boolean isDirect, in int transport);
void serverDisconnect(in int serverIf, in String address);
void beginServiceDeclaration(in int serverIf, in int srvcType, in int srvcInstanceId, in int minHandles,
in ParcelUuid srvcId, boolean advertisePreferred);
void addIncludedService(in int serverIf, in int srvcType, in int srvcInstanceId, in ParcelUuid srvcId);
void addCharacteristic(in int serverIf, in ParcelUuid charId, in int properties, in int permissions);
void addDescriptor(in int serverIf, in ParcelUuid descId, in int permissions);
void endServiceDeclaration(in int serverIf);
void removeService(in int serverIf, in int srvcType, in int srvcInstanceId, in ParcelUuid srvcId);
void clearServices(in int serverIf);
void sendResponse(in int serverIf, in String address, in int requestId, in int status, in int offset, in byte[] value);
void sendNotification(in int serverIf, in String address, in int srvcType, in int srvcInstanceId, in ParcelUuid srvcId,
in int charInstanceId, in ParcelUuid charId, in boolean confirm, in byte[] value);
}
</span>
(4)那我们就看看最后一步到底是做了什么,设备就开始广播了呢?实例化了AdvertiseCallbackWrapper:
<span style="font-size:14px;"> public AdvertiseCallbackWrapper(AdvertiseCallback advertiseCallback,
AdvertiseData advertiseData, AdvertiseData scanResponse,
AdvertiseSettings settings,
IBluetoothGatt bluetoothGatt) {
mAdvertiseCallback = advertiseCallback;
mAdvertisement = advertiseData;
mScanResponse = scanResponse;
mSettings = settings;
mBluetoothGatt = bluetoothGatt;
mClientIf = 0;
}</span>
这里注意两点,第一点是mClientIf,这里的值大家在调试的时候要了解: // mClientIf 0: not registered
// -1: scan stopped
// >0: registered and scan started
第二个是mBluetoothGatt,这里的接口来源实际就是调用了IBluetoothGatt的所有接口。
实例化完了之后就是调用startRegisteration(),实现代码如下:
<span style="font-size:14px;"> public void startRegisteration() {
synchronized (this) {
if (mClientIf == -1) return;
try {
UUID uuid = UUID.randomUUID();
mBluetoothGatt.registerClient(new ParcelUuid(uuid), this);
wait(LE_CALLBACK_TIMEOUT_MILLIS);
} catch (InterruptedException | RemoteException e) {
Log.e(TAG, "Failed to start registeration", e);
}
if (mClientIf > 0 && mIsAdvertising) {
mLeAdvertisers.put(mAdvertiseCallback, this);
} else if (mClientIf <= 0) {
// Post internal error if registration failed.
postStartFailure(mAdvertiseCallback,
AdvertiseCallback.ADVERTISE_FAILED_INTERNAL_ERROR);
} else {
// Unregister application if it's already registered but advertise failed.
try {
mBluetoothGatt.unregisterClient(mClientIf);
mClientIf = -1;
} catch (RemoteException e) {
Log.e(TAG, "remote exception when unregistering", e);
}
}
}
}</span>
这里实际就是真正的去启动BLE工作了。首先去调用了registerClient:
<span style="font-size:14px;"> public void registerClient(ParcelUuid uuid, IBluetoothGattCallback callback) {
GattService service = getService();
if (service == null) return;
service.registerClient(uuid.getUuid(), callback);
}</span>
然后又去调用了自己内部的registerClient函数:
<span style="font-size:14px;"> void registerClient(UUID uuid, IBluetoothGattCallback callback) {
enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
if (DBG) Log.d(TAG, "registerClient() - UUID=" + uuid);
mClientMap.add(uuid, callback);
gattClientRegisterAppNative(uuid.getLeastSignificantBits(),
uuid.getMostSignificantBits());
}</span>
看到这里的函数,你应该就了解马上就要进入JNI了, gattClientRegisterAppNative对应的就是JNI文件里的 {"gattClientRegisterAppNative", "(JJ)V", (void *) gattClientRegisterAppNative},下面我们来看一下gattClientRegisterAppNative的实现是怎样的:
<span style="font-size:14px;">static void gattClientRegisterAppNative(JNIEnv* env, jobject object,
jlong app_uuid_lsb, jlong app_uuid_msb )
{
bt_uuid_t uuid;
if (!sGattIf) return;
set_uuid(uuid.uu, app_uuid_msb, app_uuid_lsb);
sGattIf->client->register_client(&uuid);
}</span>
看到这里的C++代码,也就意味着马上就要进入协议栈。要找到register_client函数,那我们必须先去找sGattIf。
sGattIf定义如下:
<span style="font-size:14px;">static const btgatt_interface_t *sGattIf = NULL;</span>
btgatt_interface_t的定义如下:
<span style="font-size:14px;">/** Represents the standard Bluetooth GATT interface. */
typedef struct {
/** Set to sizeof(btgatt_interface_t) */
size_t size;
/**
* Initializes the interface and provides callback routines
*/
bt_status_t (*init)( const btgatt_callbacks_t* callbacks );
/** Closes the interface */
void (*cleanup)( void );
/** Pointer to the GATT client interface methods.*/
const btgatt_client_interface_t* client;
/** Pointer to the GATT server interface methods.*/
const btgatt_server_interface_t* server;
} btgatt_interface_t;</span>
看到这里,第二个成员变量我们也知道是啥了,但是我们还需要继续追踪,去继续看btgatt_client_interface_t是如何定义的,
<span style="font-size:14px;">typedef struct {
/** Registers a GATT client application with the stack */
bt_status_t (*register_client)( bt_uuid_t *uuid );
/** Unregister a client application from the stack */
bt_status_t (*unregister_client)(int client_if );
/** Start or stop LE device scanning */
bt_status_t (*scan)( bool start );
/** Create a connection to a remote LE or dual-mode device */
bt_status_t (*connect)( int client_if, const bt_bdaddr_t *bd_addr,
bool is_direct, int transport );
/** Disconnect a remote device or cancel a pending connection */
bt_status_t (*disconnect)( int client_if, const bt_bdaddr_t *bd_addr,
int conn_id);
/** Start or stop advertisements to listen for incoming connections */
bt_status_t (*listen)(int client_if, bool start);
/** Clear the attribute cache for a given device */
bt_status_t (*refresh)( int client_if, const bt_bdaddr_t *bd_addr );
/**
* Enumerate all GATT services on a connected device.
* Optionally, the results can be filtered for a given UUID.
*/
bt_status_t (*search_service)(int conn_id, bt_uuid_t *filter_uuid );
/**
* Enumerate included services for a given service.
* Set start_incl_srvc_id to NULL to get the first included service.
*/
bt_status_t (*get_included_service)( int conn_id, btgatt_srvc_id_t *srvc_id,
btgatt_srvc_id_t *start_incl_srvc_id);
/**
* Enumerate characteristics for a given service.
* Set start_char_id to NULL to get the first characteristic.
*/
bt_status_t (*get_characteristic)( int conn_id,
btgatt_srvc_id_t *srvc_id, btgatt_gatt_id_t *start_char_id);
/**
* Enumerate descriptors for a given characteristic.
* Set start_descr_id to NULL to get the first descriptor.
*/
bt_status_t (*get_descriptor)( int conn_id,
btgatt_srvc_id_t *srvc_id, btgatt_gatt_id_t *char_id,
btgatt_gatt_id_t *start_descr_id);
/** Read a characteristic on a remote device */
bt_status_t (*read_characteristic)( int conn_id,
btgatt_srvc_id_t *srvc_id, btgatt_gatt_id_t *char_id,
int auth_req );
/** Write a remote characteristic */
bt_status_t (*write_characteristic)(int conn_id,
btgatt_srvc_id_t *srvc_id, btgatt_gatt_id_t *char_id,
int write_type, int len, int auth_req,
char* p_value);
/** Read the descriptor for a given characteristic */
bt_status_t (*read_descriptor)(int conn_id,
btgatt_srvc_id_t *srvc_id, btgatt_gatt_id_t *char_id,
btgatt_gatt_id_t *descr_id, int auth_req);
/** Write a remote descriptor for a given characteristic */
bt_status_t (*write_descriptor)( int conn_id,
btgatt_srvc_id_t *srvc_id, btgatt_gatt_id_t *char_id,
btgatt_gatt_id_t *descr_id, int write_type, int len,
int auth_req, char* p_value);
/** Execute a prepared write operation */
bt_status_t (*execute_write)(int conn_id, int execute);
/**
* Register to receive notifications or indications for a given
* characteristic
*/
bt_status_t (*register_for_notification)( int client_if,
const bt_bdaddr_t *bd_addr, btgatt_srvc_id_t *srvc_id,
btgatt_gatt_id_t *char_id);
/** Deregister a previous request for notifications/indications */
bt_status_t (*deregister_for_notification)( int client_if,
const bt_bdaddr_t *bd_addr, btgatt_srvc_id_t *srvc_id,
btgatt_gatt_id_t *char_id);
/** Request RSSI for a given remote device */
bt_status_t (*read_remote_rssi)( int client_if, const bt_bdaddr_t *bd_addr);
/** Setup scan filter params */
bt_status_t (*scan_filter_param_setup)(int client_if, int action, int filt_index, int feat_seln,
int list_logic_type, int filt_logic_type, int rssi_high_thres,
int rssi_low_thres, int dely_mode, int found_timeout,
int lost_timeout, int found_timeout_cnt);
/** Configure a scan filter condition */
bt_status_t (*scan_filter_add_remove)(int client_if, int action, int filt_type,
int filt_index, int company_id,
int company_id_mask, const bt_uuid_t *p_uuid,
const bt_uuid_t *p_uuid_mask, const bt_bdaddr_t *bd_addr,
char addr_type, int data_len, char* p_data, int mask_len,
char* p_mask);
/** Clear all scan filter conditions for specific filter index*/
bt_status_t (*scan_filter_clear)(int client_if, int filt_index);
/** Enable / disable scan filter feature*/
bt_status_t (*scan_filter_enable)(int client_if, bool enable);
/** Determine the type of the remote device (LE, BR/EDR, Dual-mode) */
int (*get_device_type)( const bt_bdaddr_t *bd_addr );
/** Set the advertising data or scan response data */
bt_status_t (*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);
/** Configure the MTU for a given connection */
bt_status_t (*configure_mtu)(int conn_id, int mtu);
/** Request a connection parameter update */
bt_status_t (*conn_parameter_update)(const bt_bdaddr_t *bd_addr, int min_interval,
int max_interval, int latency, int timeout);
/** Sets the LE scan interval and window in units of N*0.625 msec */
bt_status_t (*set_scan_parameters)(int scan_interval, int scan_window);
/* Setup the parameters as per spec, user manual specified values and enable multi ADV */
bt_status_t (*multi_adv_enable)(int client_if, int min_interval,int max_interval,int adv_type,
int chnl_map, int tx_power, int timeout_s);
/* Update the parameters as per spec, user manual specified values and restart multi ADV */
bt_status_t (*multi_adv_update)(int client_if, int min_interval,int max_interval,int adv_type,
int chnl_map, int tx_power, int timeout_s);
/* Setup the data for the specified instance */
bt_status_t (*multi_adv_set_inst_data)(int client_if, bool set_scan_rsp, bool include_name,
bool incl_txpower, int appearance, int manufacturer_len,
char* manufacturer_data, int service_data_len,
char* service_data, int service_uuid_len, char* service_uuid);
/* Disable the multi adv instance */
bt_status_t (*multi_adv_disable)(int client_if);
/* Configure the batchscan storage */
bt_status_t (*batchscan_cfg_storage)(int client_if, int batch_scan_full_max,
int batch_scan_trunc_max, int batch_scan_notify_threshold);
/* Enable batchscan */
bt_status_t (*batchscan_enb_batch_scan)(int client_if, int scan_mode,
int scan_interval, int scan_window, int addr_type, int discard_rule);
/* Disable batchscan */
bt_status_t (*batchscan_dis_batch_scan)(int client_if);
/* Read out batchscan reports */
bt_status_t (*batchscan_read_reports)(int client_if, int scan_mode);
/** Test mode interface */
bt_status_t (*test_command)( int command, btgatt_test_params_t* params);
} btgatt_client_interface_t;</span>
我们终于找到我们要调用的函数了,但是我们发现并不是直接实现了此函数,而是做了一下映射:
<span style="font-size:14px;">const btgatt_client_interface_t btgattClientInterface = {
btif_gattc_register_app,
btif_gattc_unregister_app,
btif_gattc_scan,
btif_gattc_open,
btif_gattc_close,
btif_gattc_listen,
btif_gattc_refresh,
btif_gattc_search_service,
btif_gattc_get_included_service,
btif_gattc_get_characteristic,
btif_gattc_get_descriptor,
btif_gattc_read_char,
btif_gattc_write_char,
btif_gattc_read_char_descr,
btif_gattc_write_char_descr,
btif_gattc_execute_write,
btif_gattc_reg_for_notification,
btif_gattc_dereg_for_notification,
btif_gattc_read_remote_rssi,
btif_gattc_scan_filter_param_setup,
btif_gattc_scan_filter_add_remove,
btif_gattc_scan_filter_clear,
btif_gattc_scan_filter_enable,
btif_gattc_get_device_type,
btif_gattc_set_adv_data,
btif_gattc_configure_mtu,
btif_gattc_conn_parameter_update,
btif_gattc_set_scan_parameters,
btif_gattc_multi_adv_enable,
btif_gattc_multi_adv_update,
btif_gattc_multi_adv_setdata,
btif_gattc_multi_adv_disable,
btif_gattc_cfg_storage,
btif_gattc_enb_batch_scan,
btif_gattc_dis_batch_scan,
btif_gattc_read_batch_scan_reports,
btif_gattc_test_command
};</span>
ok,终于发现在协议栈里,已经不是原来的名字,换了一个马甲,那我们看看它到底做了什么:
<span style="font-size:14px;">static bt_status_t btif_gattc_register_app(bt_uuid_t *uuid)
{
CHECK_BTGATT_INIT();
btif_gattc_cb_t btif_cb;
memcpy(&btif_cb.uuid, uuid, sizeof(bt_uuid_t));
return btif_transfer_context(btgattc_handle_event, BTIF_GATTC_REGISTER_APP,
(char*) &btif_cb, sizeof(btif_gattc_cb_t), NULL);
}</span>
看到这里你肯定会觉得似曾相识了,因为前面有一篇帖子已经讲过了一些。主要还是btgattc_handle_event的实现和BTIF_GATTC_REGISTER_APP:
<span style="font-size:14px;">static void btgattc_handle_event(uint16_t event, char* p_param)
{
……
switch (event)
{
case BTIF_GATTC_REGISTER_APP:
btif_to_bta_uuid(&uuid, &p_cb->uuid);
btif_gattc_incr_app_count();
BTA_GATTC_AppRegister(&uuid, bta_gattc_cback);
break;
……
</span>
接下来就有点梳理代码了,大家不要失去耐心,看这些并不是没用,对你肯定有好处。好了,我们继续,后面主要就是BTA_GATTC_AppRegister和 bta_gattc_cback了:
<span style="font-size:14px;">void BTA_GATTC_AppRegister(tBT_UUID *p_app_uuid, tBTA_GATTC_CBACK *p_client_cb)
{
tBTA_GATTC_API_REG *p_buf;
if (bta_sys_is_register(BTA_ID_GATTC) == FALSE)
{
bta_sys_register(BTA_ID_GATTC, &bta_gattc_reg);
}
if ((p_buf = (tBTA_GATTC_API_REG *) GKI_getbuf(sizeof(tBTA_GATTC_API_REG))) != NULL)
{
p_buf->hdr.event = BTA_GATTC_API_REG_EVT;
if (p_app_uuid != NULL)
memcpy(&p_buf->app_uuid, p_app_uuid, sizeof(tBT_UUID));
p_buf->p_cback = p_client_cb;
bta_sys_sendmsg(p_buf);
}
return;
}
</span>
通过bta_sys_register函数注册了bta_gatt_reg结构体中定义的客户端主事件处理函数bta_gattc_hdl_event;然后设置event为BTA_GATTC_API_REG_EVT,触发bta_gattc_hdl_event函数:
<span style="font-size:14px;">static const tBTA_SYS_REG bta_gattc_reg =
{
bta_gattc_hdl_event,
BTA_GATTC_Disable
};</span>
<span style="font-size:14px;">BOOLEAN bta_gattc_hdl_event(BT_HDR *p_msg)
{
……
switch (p_msg->event)
{
……
case BTA_GATTC_API_REG_EVT:
bta_gattc_register(p_cb, (tBTA_GATTC_DATA *) p_msg);
break;
……
</span>
接下來就是bta对它的处理实现了:
<span style="font-size:14px;">void bta_gattc_register(tBTA_GATTC_CB *p_cb, tBTA_GATTC_DATA *p_data)
{
tBTA_GATTC cb_data;
UINT8 i;
tBT_UUID *p_app_uuid = &p_data->api_reg.app_uuid;
tBTA_GATTC_INT_START_IF *p_buf;
tBTA_GATT_STATUS status = BTA_GATT_NO_RESOURCES;
APPL_TRACE_DEBUG("bta_gattc_register state %d",p_cb->state);
memset(&cb_data, 0, sizeof(cb_data));
cb_data.reg_oper.status = BTA_GATT_NO_RESOURCES;
/* check if GATTC module is already enabled . Else enable */
if (p_cb->state == BTA_GATTC_STATE_DISABLED)
{
bta_gattc_enable (p_cb);
}
/* todo need to check duplicate uuid */
for (i = 0; i < BTA_GATTC_CL_MAX; i ++)
{
if (!p_cb->cl_rcb[i].in_use)
{
if ((p_app_uuid == NULL) || (p_cb->cl_rcb[i].client_if = GATT_Register(p_app_uuid, &bta_gattc_cl_cback)) == 0)
{
APPL_TRACE_ERROR("Register with GATT stack failed.");
status = BTA_GATT_ERROR;
}
else
{
p_cb->cl_rcb[i].in_use = TRUE;
p_cb->cl_rcb[i].p_cback = p_data->api_reg.p_cback;
memcpy(&p_cb->cl_rcb[i].app_uuid, p_app_uuid, sizeof(tBT_UUID));
/* BTA use the same client interface as BTE GATT statck */
cb_data.reg_oper.client_if = p_cb->cl_rcb[i].client_if;
if ((p_buf = (tBTA_GATTC_INT_START_IF *) GKI_getbuf(sizeof(tBTA_GATTC_INT_START_IF))) != NULL)
{
p_buf->hdr.event = BTA_GATTC_INT_START_IF_EVT;
p_buf->client_if = p_cb->cl_rcb[i].client_if;
bta_sys_sendmsg(p_buf);
status = BTA_GATT_OK;
}
else
{
GATT_Deregister(p_cb->cl_rcb[i].client_if);
status = BTA_GATT_NO_RESOURCES;
memset( &p_cb->cl_rcb[i], 0 , sizeof(tBTA_GATTC_RCB));
}
break;
}
}
}
/* callback with register event */
if (p_data->api_reg.p_cback)
{
if (p_app_uuid != NULL)
memcpy(&(cb_data.reg_oper.app_uuid),p_app_uuid,sizeof(tBT_UUID));
cb_data.reg_oper.status = status;
(*p_data->api_reg.p_cback)(BTA_GATTC_REG_EVT, (tBTA_GATTC *)&cb_data);
}
}</span>
到这里了,基本上已经到了GKI库了,那里面的东西我就不写了,不过那里面和协议关系不是很大了。这里面最后还有一个event的回调BTA_GATTC_REG_EVT了。那么接下来就是要讲回调了。
那我们就重点來解析一下bta_gattc_cback这个回调,先来看看它的实现:
<span style="font-size:14px;">static void bta_gattc_cback(tBTA_GATTC_EVT event, tBTA_GATTC *p_data)
{
bt_status_t status = btif_transfer_context(btif_gattc_upstreams_evt,
(uint16_t) event, (void*) p_data, sizeof(tBTA_GATTC), btapp_gattc_req_data);
ASSERTC(status == BT_STATUS_SUCCESS, "Context transfer failed!", status);
}</span>
这里我们主要是关注两个地方,一个是btif_gattc_upstreams_evt另一个就是btapp_gattc_req_data.
btapp_gattc_req_data的实现很简单:
<span style="font-size:14px;">static void btapp_gattc_req_data(UINT16 event, char *p_dest, char *p_src)
{
tBTA_GATTC *p_dest_data = (tBTA_GATTC*) p_dest;
tBTA_GATTC *p_src_data = (tBTA_GATTC*) p_src;
if (!p_src_data || !p_dest_data)
return;
// Copy basic structure first
memcpy(p_dest_data, p_src_data, sizeof(tBTA_GATTC));
// Allocate buffer for request data if necessary
switch (event)
{
case BTA_GATTC_READ_CHAR_EVT:
case BTA_GATTC_READ_DESCR_EVT:
if (p_src_data->read.p_value != NULL)
{
p_dest_data->read.p_value = GKI_getbuf(sizeof(tBTA_GATT_READ_VAL));
if (p_dest_data->read.p_value != NULL)
{
memcpy(p_dest_data->read.p_value, p_src_data->read.p_value,
sizeof(tBTA_GATT_READ_VAL));
// Allocate buffer for att value if necessary
if (get_uuid16(&p_src_data->read.descr_type.uuid) != GATT_UUID_CHAR_AGG_FORMAT
&& p_src_data->read.p_value->unformat.len > 0
&& p_src_data->read.p_value->unformat.p_value != NULL)
{
p_dest_data->read.p_value->unformat.p_value =
GKI_getbuf(p_src_data->read.p_value->unformat.len);
if (p_dest_data->read.p_value->unformat.p_value != NULL)
{
memcpy(p_dest_data->read.p_value->unformat.p_value,
p_src_data->read.p_value->unformat.p_value,
p_src_data->read.p_value->unformat.len);
}
}
}
}
else
{
BTIF_TRACE_WARNING("%s :Src read.p_value ptr is NULL for event 0x%x",
__FUNCTION__, event);
p_dest_data->read.p_value = NULL;
}
break;
default:
break;
}
}
</span>
下面來看看btif_gattc_upstreams_evt的实现:
<span style="font-size:14px;">static void btif_gattc_upstreams_evt(uint16_t event, char* p_param)
{
BTIF_TRACE_EVENT("%s: Event %d", __FUNCTION__, event);
tBTA_GATTC *p_data = (tBTA_GATTC*) p_param;
switch (event)
{
case BTA_GATTC_REG_EVT:
{
bt_uuid_t app_uuid;
bta_to_btif_uuid(&app_uuid, &p_data->reg_oper.app_uuid);
HAL_CBACK(bt_gatt_callbacks, client->register_client_cb
, p_data->reg_oper.status
, p_data->reg_oper.client_if
, &app_uuid
);
break;
……
}</span>
那你肯定会问,为什么是BTA_GATTC_REG_EVT这个事件呢,因为我们在bta_gattc_register做了伏笔,参数是它传过去的。在这里又做了一个很重要的事情注册了client callback.我们先来看一下bt_gatt_callbacks:
<span style="font-size:14px;">const btgatt_callbacks_t *bt_gatt_callbacks = NULL;</span>
看来我们真正要找的是btgatt_callbacks_t
,那我们继续追它:
<span style="font-size:14px;">/** BT-GATT callbacks */
typedef struct {
/** Set to sizeof(btgatt_callbacks_t) */
size_t size;
/** GATT Client callbacks */
const btgatt_client_callbacks_t* client;
/** GATT Server callbacks */
const btgatt_server_callbacks_t* server;
} btgatt_callbacks_t;</span>
接下来就要去解析register_client_cb了,我们知道client指向的是btgatt_client_callbacks_t结构体,它对应的是:
typedef struct {
register_client_callback register_client_cb;
scan_result_callback scan_result_cb;
connect_callback open_cb;
disconnect_callback close_cb;
……
到这里既有点绕了,因为需要回到JNI去寻找,但是由于前面我已经讲过(android4.4.2 bluetooth解析(二)),为了减少篇幅我就不重复了,直接找到对应的函数:
static const btgatt_client_callbacks_t sGattClientCallbacks = {
btgattc_register_app_cb,
btgattc_scan_result_cb,
btgattc_open_cb,
btgattc_close_cb,
……
void btgattc_register_app_cb(int status, int clientIf, bt_uuid_t *app_uuid)
{
CHECK_CALLBACK_ENV
sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onClientRegistered, status,
clientIf, UUID_PARAMS(app_uuid));
checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
}
到这里我们已经看到method_onClientRegistered了:
static jmethodID method_onClientRegistered;
下一步就会进入Java层,到达回调service:
void onClientRegistered(int status, int clientIf, long uuidLsb, long uuidMsb)
throws RemoteException {
UUID uuid = new UUID(uuidMsb, uuidLsb);
if (DBG) Log.d(TAG, "onClientRegistered() - UUID=" + uuid + ", clientIf=" + clientIf);
ClientMap.App app = mClientMap.getByUuid(uuid);
if (app != null) {
if (status == 0) {
app.id = clientIf;
app.linkToDeath(new ClientDeathRecipient(clientIf));
} else {
mClientMap.remove(uuid);
}
app.callback.onClientRegistered(status, clientIf);
}
}
这终于回到了BluetoothLeAdvertiser类了:
/**
* Application interface registered - app is ready to go
*/
@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();
}
}
到这里你可以看到已经走了一个来回了,当然这是在应用第一次启动,或者之前并没有注册过ble应用设备时才会这样,不然他会跳过register_app这一步动作的。看到这里你会感觉好复杂呀,实际上,这一直是在准备工作,真正的广播还没开始呢。不过为了文章篇幅我会在第二篇文章继续看看mBluetoothGatt.startMultiAdvertising(mClientIf, mAdvertisement, mScanResponse, mSettings);是怎么工作的。
下一篇文章即将更新,敬请期待。