的startScanning(),我们分析的起点也从这里开始,起步代码如下
1. private void updateContent(int
2. if
3. preferenceScreen.removePreference(mPairedDevicesCategory);
4. if (scanState == true) {
5. false;
6. startScanning();
7. else<SPAN style="FONT-FAMILY: Arial, Helvetica, sans-serif"> ........</SPAN>
8. }
9. private void
10. if
11. getPreferenceScreen().addPreference(mAvailableDevicesCategory);
12. }
13. true);
14. }
private void updateContent(int bluetoothState, boolean scanState) {
if (numberOfPairedDevices == 0) {
preferenceScreen.removePreference(mPairedDevicesCategory);
if (scanState == true) {
mActivityStarted = false;
startScanning();
} else ........
}
private void startScanning() {
if (!mAvailableDevicesCategoryIsPresent) {
getPreferenceScreen().addPreference(mAvailableDevicesCategory);
}
mLocalAdapter.startScanning(true);
}
其实在这里蓝牙搜索和打开流程是结构上是一致的,利用LocalBluetoothAdapter.java过渡到BluetoothAdapter.java再跳转至AdapterService.java要稍微留意下的是在这个过渡中startScaning()方法变成了startDiscovery()方法,看下代码:packages/apps/Settings/src/com/android/settings/bluetooth/LocalBluetoothAdapter.java
1. void startScanning(boolean
2. if
3. if
4. // Don't scan more than frequently than SCAN_EXPIRATION_MS,
5. // unless forced
6. if
7. return;
8. }
9. // If we are playing music, don't scan unless forced.
10. A2dpProfile a2dp = mProfileManager.getA2dpProfile();
11. if (a2dp != null
12. return;
13. }
14. }
15. //这里才是我们最关注的,前面限制条件关注一下就行了
16. if
17. mLastScan = System.currentTimeMillis();
18. }
19. }
void startScanning(boolean force) {
if (!mAdapter.isDiscovering()) {
if (!force) {
// Don't scan more than frequently than SCAN_EXPIRATION_MS,
// unless forced
if (mLastScan + SCAN_EXPIRATION_MS > System.currentTimeMillis()) {
return;
}
// If we are playing music, don't scan unless forced.
A2dpProfile a2dp = mProfileManager.getA2dpProfile();
if (a2dp != null && a2dp.isA2dpPlaying()) {
return;
}
}
//这里才是我们最关注的,前面限制条件关注一下就行了
if (mAdapter.startDiscovery()) {
mLastScan = System.currentTimeMillis();
}
}
void startScanning(boolean force) {
if (!mAdapter.isDiscovering()) {
if (!force) {
// Don't scan more than frequently than SCAN_EXPIRATION_MS,
// unless forced
if (mLastScan + SCAN_EXPIRATION_MS > System.currentTimeMillis()) {
return;
}
// If we are playing music, don't scan unless forced.
A2dpProfile a2dp = mProfileManager.getA2dpProfile();
if (a2dp != null && a2dp.isA2dpPlaying()) {
return;
}
}
//这里才是我们最关注的,前面限制条件关注一下就行了
if (mAdapter.startDiscovery()) {
mLastScan = System.currentTimeMillis();
}
}
BluetoothAdapter.java的那一段,路径 /frameworks/base/core/java/android/bluetooth/BluetoothAdapter.java
1. public boolean
2. .............................
3. AdapterService service = getService();
4. if (service == null) return false;
5. return
6. }
public boolean startDiscovery() {
.............................
AdapterService service = getService();
if (service == null) return false;
return service.startDiscovery();
}
这个service代码写得很明白AdapterService,转了一圈从framework又回到packages了,
下面的代码路径自然是 :packages/apps/Bluetooth/src/com/android/bluetooth/btservice/AdapterService.java,
1. boolean
2. enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
3. "Need BLUETOOTH ADMIN permission");
4.
5. return
6. }
boolean startDiscovery() {
enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
"Need BLUETOOTH ADMIN permission");
return startDiscoveryNative();
}
和打开蓝牙根本就是一个套路,上面的流程略过一小步,很简单的不写了,下面要怎么走,估计大家也都猜到了,JNI应该出场了,
路径:/packages/apps/Bluetooth/jni/com_android_bluetooth_btservice_AdapterService.cpp
1. static
2. "%s:",__FUNCTION__);
3.
4. jboolean result = JNI_FALSE;
5. if (!sBluetoothInterface) return
6.
7. int
8. result = (ret == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
9. return
10. }
static jboolean startDiscoveryNative(JNIEnv* env, jobject obj) {
ALOGV("%s:",__FUNCTION__);
jboolean result = JNI_FALSE;
if (!sBluetoothInterface) return result;
int ret = sBluetoothInterface->start_discovery();
result = (ret == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
return result;
}
在下面要去哪?稍微要动下脑筋,不过我们在上一篇android -- 蓝牙 bluetooth (二) 打开蓝牙已经说过怎么找了,注意android.mk文件,先找头文件,再找对应的实现C文件代码。就是现在回顾下,蓝牙打开和搜索的代码流程我们都看了,跳转都是一个套路,settings界面发起,LocalBluetoothAdapter.java过渡,去framework的转转(BluetoothAdapter.java)后回到packages的AdapterService.java,再走JNI来的external。流程就是这样的,相信类似的功能跳转(比如蓝牙配对,关闭蓝牙,停止扫描这些)大家都应该熟悉了,后面再有类似的功能就写函数名一笔带过了,还有这里要注意的就是这个start_discovery()实现代码的寻找,留意mk文件就是了,不复杂。小结结束,继续看代码 路径:/external/bluetooth/bluedroid/btif/src/bluetooth.c
1. static int start_discovery(void)
2. {
3. /* sanity check */
4. if
5. return
6.
7. return
8. }
static int start_discovery(void)
{
/* sanity check */
if (interface_ready() == FALSE)
return BT_STATUS_NOT_READY;
return btif_dm_start_discovery();
}
下面代码直接跳转就可以找到,路径external/bluetooth/bluedroid/btif/src/btif_dm.c
这个代码有点多,不过里面的信息也很多,所以连注释也一起保留的贴出来了,蓝牙的搜索实现并没有像蓝牙打开那样交由vendor厂商实现,在这里已经写出来了,仔细看下那些#if和#else,都是一些查询条件的调置,#if (BLE_INCLUDED == TRUE) 这个应该就google为蓝牙4.0 LE作的准备了,也算是今年google I/O大会上宣布即将支持蓝牙4.0低能耗版一个佐证吧,对于代码里面那些字符串的含义看这里好了external/bluetooth/bluedroid/bta/include/bta_api.h,一个头文件,大部分字符串和结构体的定义都在这了,多少还有些注释。
1. bt_status_t btif_dm_start_discovery(void)
2. {
3. tBTA_DM_INQ inq_params;
4. tBTA_SERVICE_MASK services = 0;
5.
6. "%s", __FUNCTION__);
7. /* TODO: Do we need to handle multiple inquiries at the same time? */
8.
9. /* Set inquiry params and call API */
10. #if (BLE_INCLUDED == TRUE)
11. inq_params.mode = BTA_DM_GENERAL_INQUIRY|BTA_BLE_GENERAL_INQUIRY;
12. #else
13. inq_params.mode = BTA_DM_GENERAL_INQUIRY;
14. #endif
15. inq_params.duration = BTIF_DM_DEFAULT_INQ_MAX_DURATION;
16.
17. inq_params.max_resps = BTIF_DM_DEFAULT_INQ_MAX_RESULTS;
18. inq_params.report_dup = TRUE;
19.
20. inq_params.filter_type = BTA_DM_INQ_CLR;
21. /* TODO: Filter device by BDA needs to be implemented here */
22.
23. /* Will be enabled to TRUE once inquiry busy level has been received */
24. btif_dm_inquiry_in_progress = FALSE;
25. /* find nearby devices */
26. BTA_DmSearch(&inq_params, services, bte_search_devices_evt);
27.
28. return
29. }
bt_status_t btif_dm_start_discovery(void)
{
tBTA_DM_INQ inq_params;
tBTA_SERVICE_MASK services = 0;
BTIF_TRACE_EVENT1("%s", __FUNCTION__);
/* TODO: Do we need to handle multiple inquiries at the same time? */
/* Set inquiry params and call API */
#if (BLE_INCLUDED == TRUE)
inq_params.mode = BTA_DM_GENERAL_INQUIRY|BTA_BLE_GENERAL_INQUIRY;
#else
inq_params.mode = BTA_DM_GENERAL_INQUIRY;
#endif
inq_params.duration = BTIF_DM_DEFAULT_INQ_MAX_DURATION;
inq_params.max_resps = BTIF_DM_DEFAULT_INQ_MAX_RESULTS;
inq_params.report_dup = TRUE;
inq_params.filter_type = BTA_DM_INQ_CLR;
/* TODO: Filter device by BDA needs to be implemented here */
/* Will be enabled to TRUE once inquiry busy level has been received */
btif_dm_inquiry_in_progress = FALSE;
/* find nearby devices */
BTA_DmSearch(&inq_params, services, bte_search_devices_evt);
return BT_STATUS_SUCCESS;
}
BTA_DmSearch()方法是看起来是要搜索了,不过里面这个家伙bte_search_devices_evt才是真正干活的主力,所以我们先看它,在这个函数里
1. static void
2. UINT16 param_len = 0;
3.
4. if
5. sizeof(tBTA_DM_SEARCH);
6. /* Allocate buffer to hold the pointers (deep copy). The pointers will point to the end of the tBTA_DM_SEARCH */
7. switch
8. {
9. case
10. {
11. if
12. param_len += HCI_EXT_INQ_RESPONSE_LEN;
13. }
14. break;
15. ..............................
16. }
17. "%s event=%s param_len=%d", __FUNCTION__, dump_dm_search_event(event), param_len);
18.
19. /* if remote name is available in EIR, set teh flag so that stack doesnt trigger RNR */
20. if
21. p_data->inq_res.remt_name_not_required = check_eir_remote_name(p_data, NULL, NULL);
22.
23. void
24. sizeof(tBTA_DM_SEARCH)) ? search_devices_copy_cb : NULL);
25. }
static void bte_search_devices_evt(tBTA_DM_SEARCH_EVT event, tBTA_DM_SEARCH *p_data) {
UINT16 param_len = 0;
if (p_data)
param_len += sizeof(tBTA_DM_SEARCH);
/* Allocate buffer to hold the pointers (deep copy). The pointers will point to the end of the tBTA_DM_SEARCH */
switch (event)
{
case BTA_DM_INQ_RES_EVT:
{
if (p_data->inq_res.p_eir)
param_len += HCI_EXT_INQ_RESPONSE_LEN;
}
break;
..............................
}
BTIF_TRACE_DEBUG3("%s event=%s param_len=%d", __FUNCTION__, dump_dm_search_event(event), param_len);
/* if remote name is available in EIR, set teh flag so that stack doesnt trigger RNR */
if (event == BTA_DM_INQ_RES_EVT)
p_data->inq_res.remt_name_not_required = check_eir_remote_name(p_data, NULL, NULL);
btif_transfer_context (btif_dm_search_devices_evt , (UINT16) event, (void *)p_data, param_len,
(param_len > sizeof(tBTA_DM_SEARCH)) ? search_devices_copy_cb : NULL);
}
1. static void btif_dm_search_devices_evt (UINT16 event, char
2.
3. tBTA_DM_SEARCH *p_search_data;
4. "%s event=%s", __FUNCTION__, dump_dm_search_event(event));
5.
6. switch
7. {
8. case
9. {
10. p_search_data = (tBTA_DM_SEARCH *)p_param;
11. /* Remote name update */
12. if (strlen((const char
13. {
14. bt_property_t properties[1];
15. bt_bdaddr_t bdaddr;
16. bt_status_t status;
17.
18. properties[0].type = BT_PROPERTY_BDNAME;
19. properties[0].val = p_search_data->disc_res.bd_name;
20. char
21. bdcpy(bdaddr.address, p_search_data->disc_res.bd_addr);
22.
23. status = btif_storage_set_remote_device_property(&bdaddr, &properties[0]);
24. "failed to save remote device property", status);
25. HAL_CBACK(bt_hal_cbacks, remote_device_properties_cb,
26. status, &bdaddr, 1, properties);
27. }
28. /* TODO: Services? */
29. }
30. break;
static void btif_dm_search_devices_evt (UINT16 event, char *p_param)
{
tBTA_DM_SEARCH *p_search_data;
BTIF_TRACE_EVENT2("%s event=%s", __FUNCTION__, dump_dm_search_event(event));
switch (event)
{
case BTA_DM_DISC_RES_EVT:
{
p_search_data = (tBTA_DM_SEARCH *)p_param;
/* Remote name update */
if (strlen((const char *) p_search_data->disc_res.bd_name))
{
bt_property_t properties[1];
bt_bdaddr_t bdaddr;
bt_status_t status;
properties[0].type = BT_PROPERTY_BDNAME;
properties[0].val = p_search_data->disc_res.bd_name;
properties[0].len = strlen((char *)p_search_data->disc_res.bd_name);
bdcpy(bdaddr.address, p_search_data->disc_res.bd_addr);
status = btif_storage_set_remote_device_property(&bdaddr, &properties[0]);
ASSERTC(status == BT_STATUS_SUCCESS, "failed to save remote device property", status);
HAL_CBACK(bt_hal_cbacks, remote_device_properties_cb,
status, &bdaddr, 1, properties);
}
/* TODO: Services? */
}
break;
05-30 13:52:14.890 1578 2612 D bt-btif : bte_search_devices_evt event=BTA_DM_INQ_RES_EVT param_len=524
05-30 13:52:14.890 1578 2612 D bt-btif : search_devices_copy_cb: event=BTA_DM_INQ_RES_EVT
05-30 13:52:14.890 1578 2584 I bt-btif : btif_dm_search_devices_evt event=BTA_DM_INQ_RES_EVT
05-30 13:52:14.890 1578 2584 D bt-btif : btif_dm_search_devices_evt() ec:89:f5:ba:fb:03 device_type = 0x1
当然回过头我们还要看下那个BTA_DmSearch(),看它的实现,更应该是起消息发送的作用,代码在/external/bluetooth/bluedroid/bta/dm/bta_dm_api.c,这个函数具体流程并没有看多少,当工具方法看了,有时间看看还是没坏处的。
1. void
2. { tBTA_DM_API_SEARCH *p_msg;
3. if ((p_msg = (tBTA_DM_API_SEARCH *) GKI_getbuf(sizeof(tBTA_DM_API_SEARCH))) != NULL)
4. {
5. sizeof(tBTA_DM_API_SEARCH));
6.
7. p_msg->hdr.event = BTA_DM_API_SEARCH_EVT;
8. sizeof(tBTA_DM_INQ));
9. p_msg->services = services;
10. p_msg->p_cback = p_cback;
11. p_msg->rs_res = BTA_DM_RS_NONE;
12. bta_sys_sendmsg(p_msg);
13. }
14. }
void BTA_DmSearch(tBTA_DM_INQ *p_dm_inq, tBTA_SERVICE_MASK services, tBTA_DM_SEARCH_CBACK *p_cback)
{ tBTA_DM_API_SEARCH *p_msg;
if ((p_msg = (tBTA_DM_API_SEARCH *) GKI_getbuf(sizeof(tBTA_DM_API_SEARCH))) != NULL)
{
memset(p_msg, 0, sizeof(tBTA_DM_API_SEARCH));
p_msg->hdr.event = BTA_DM_API_SEARCH_EVT;
memcpy(&p_msg->inq_params, p_dm_inq, sizeof(tBTA_DM_INQ));
p_msg->services = services;
p_msg->p_cback = p_cback;
p_msg->rs_res = BTA_DM_RS_NONE;
bta_sys_sendmsg(p_msg);
}
}
1. method_deviceFoundCallback = env->GetMethodID(jniCallbackClass, "deviceFoundCallback", "([B)V");
method_deviceFoundCallback = env->GetMethodID(jniCallbackClass, "deviceFoundCallback", "([B)V");
deviceFoundCallback方法最后会来java层的/packages/apps/Bluetooth/src/com/android/bluetooth/btservice/RemoteDevices.java
1. void deviceFoundCallback(byte[] address) {
2. // The device properties are already registered - we can send the intent
3. // now
4. BluetoothDevice device = getDevice(address);
5. "deviceFoundCallback: Remote Address is:"
6. DeviceProperties deviceProp = getDeviceProperties(device);
7. if (deviceProp == null) {
8. "Device Properties is null for Device:"
9. return;
10. }
11.
12. new
13. intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device);
14. intent.putExtra(BluetoothDevice.EXTRA_CLASS,
15. new
16. intent.putExtra(BluetoothDevice.EXTRA_RSSI, deviceProp.mRssi);
17. intent.putExtra(BluetoothDevice.EXTRA_NAME, deviceProp.mName);
18.
19. mAdapterService.sendBroadcast(intent, mAdapterService.BLUETOOTH_PERM);
20. }
void deviceFoundCallback(byte[] address) {
// The device properties are already registered - we can send the intent
// now
BluetoothDevice device = getDevice(address);
debugLog("deviceFoundCallback: Remote Address is:" + device);
DeviceProperties deviceProp = getDeviceProperties(device);
if (deviceProp == null) {
errorLog("Device Properties is null for Device:" + device);
return;
}
Intent intent = new Intent(BluetoothDevice.ACTION_FOUND);
intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device);
intent.putExtra(BluetoothDevice.EXTRA_CLASS,
new BluetoothClass(Integer.valueOf(deviceProp.mBluetoothClass)));
intent.putExtra(BluetoothDevice.EXTRA_RSSI, deviceProp.mRssi);
intent.putExtra(BluetoothDevice.EXTRA_NAME, deviceProp.mName);
mAdapterService.sendBroadcast(intent, mAdapterService.BLUETOOTH_PERM);
}
1. addHandler(BluetoothDevice.ACTION_FOUND, new
2. private final BroadcastReceiver mBroadcastReceiver = new
3. @Override
4. public void
5. String action = intent.getAction();
6. BluetoothDevice device = intent
7. .getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
8.
9. Handler handler = mHandlerMap.get(action);
10. if (handler != null) {
11. handler.onReceive(context, intent, device);
12. }
13. }
14. };
addHandler(BluetoothDevice.ACTION_FOUND, new DeviceFoundHandler());
private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
BluetoothDevice device = intent
.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
Handler handler = mHandlerMap.get(action);
if (handler != null) {
handler.onReceive(context, intent, device);
}
}
};
1. private class DeviceFoundHandler implements
2. public void
3. BluetoothDevice device) {
4. ........................
5. // TODO Pick up UUID. They should be available for 2.1 devices.
6. // Skip for now, there's a bluez problem and we are not getting uuids even for 2.1.
7. CachedBluetoothDevice cachedDevice = mDeviceManager.findDevice(device);
8. if (cachedDevice == null) {
9. cachedDevice = mDeviceManager.addDevice(mLocalAdapter, mProfileManager, device);
10. "DeviceFoundHandler created new CachedBluetoothDevice: "
11. + cachedDevice);
12. // callback to UI to create Preference for new device
13. dispatchDeviceAdded(cachedDevice);
14. }
15. ......................
16. }
17. }
private class DeviceFoundHandler implements Handler {
public void onReceive(Context context, Intent intent,
BluetoothDevice device) {
........................
// TODO Pick up UUID. They should be available for 2.1 devices.
// Skip for now, there's a bluez problem and we are not getting uuids even for 2.1.
CachedBluetoothDevice cachedDevice = mDeviceManager.findDevice(device);
if (cachedDevice == null) {
cachedDevice = mDeviceManager.addDevice(mLocalAdapter, mProfileManager, device);
Log.d(TAG, "DeviceFoundHandler created new CachedBluetoothDevice: "
+ cachedDevice);
// callback to UI to create Preference for new device
dispatchDeviceAdded(cachedDevice);
}
......................
}
}
1. public void
2. if (mDevicePreferenceMap.get(cachedDevice) != null) {
3. return;
4. }
5.
6. // Prevent updates while the list shows one of the state messages
7. if (mLocalAdapter.getBluetoothState() != BluetoothAdapter.STATE_ON) return;
8.
9. if
10. createDevicePreference(cachedDevice);
11. }
12. }
public void onDeviceAdded(CachedBluetoothDevice cachedDevice) {
if (mDevicePreferenceMap.get(cachedDevice) != null) {
return;
}
// Prevent updates while the list shows one of the state messages
if (mLocalAdapter.getBluetoothState() != BluetoothAdapter.STATE_ON) return;
if (mFilter.matches(cachedDevice.getDevice())) {
createDevicePreference(cachedDevice);
}
}
1. void
2. new
3. getActivity(), cachedDevice);
4.
5. initDevicePreference(preference);
6. mDeviceListGroup.addPreference(preference);
7. mDevicePreferenceMap.put(cachedDevice, preference);
8. }
void createDevicePreference(CachedBluetoothDevice cachedDevice) {
BluetoothDevicePreference preference = new BluetoothDevicePreference(
getActivity(), cachedDevice);
initDevicePreference(preference);
mDeviceListGroup.addPreference(preference);
mDevicePreferenceMap.put(cachedDevice, preference);
}
到目前为止,包括前面的打开流程分析,还仅是针对代码流程做的分析,对于蓝牙协议方面东西还没有涉及,比如蓝牙是如何发现其它蓝牙设备,这个流程究竟是怎么工作还不是很清楚,后续会尽量关注这些问题,估计看起来就没那么容易,欢迎有经验的朋友指点一二,当然对于本文不足,欢迎拍砖讨论。分享是快乐的,谢谢!