ZT 4.3 android bluetooth hfp分析
4.3 android bluetooth hfp分析
所有程序执行的代码都是有入口的,在这里我们暂时分析一种情景,蓝牙打开着,蓝牙耳机连接。
在设置界面点击蓝牙耳机操作:
packages/apps/Settings/src/com/android/settings/bluetooth/BluetoothDevicePreference.java
- void onClicked() {
- int bondState = mCachedDevice.getBondState();
- if (mCachedDevice.isConnected()) {
- askDisconnect();
- } else if (bondState == BluetoothDevice.BOND_BONDED) { //已经配对,但是未连接
- <span style="color:#ff0000;">mCachedDevice.connect(true);</span>
- } else if (bondState == BluetoothDevice.BOND_NONE) { //没有配对
- <span style="color:#ff0000;">pair();</span>
- }
- }
mCachedDevice.connect(true);方法会直接调用CachedBluetoothDevice.java的connect的方法。
packages/apps/Settings/src/com/android/settings/bluetooth/CachedBluetoothDevice.java
- void connect(boolean connectAllProfiles) {
- if (!ensurePaired()) { //配对处理暂时不关注
- return;
- }
- mConnectAttempted = SystemClock.elapsedRealtime();
- connectWithoutResettingTimer(connectAllProfiles);
- }
代码执行到connectWithoutResettingTimer,注释就不粘贴了。
- private void connectWithoutResettingTimer(boolean connectAllProfiles) {
- ......
- // Reset the only-show-one-error-dialog tracking variable
- mIsConnectingErrorPossible = true;
- int preferredProfiles = 0;
- for (LocalBluetoothProfile profile : mProfiles) {
- if (connectAllProfiles ? profile.isConnectable() : profile.isAutoConnectable()) {
- if (profile.isPreferred(mDevice)) {
- ++preferredProfiles;
- connectInt(profile);
- }
- }
- }
- if (DEBUG) Log.d(TAG, "Preferred profiles = " + preferredProfiles);
- if (preferredProfiles == 0) {
- connectAutoConnectableProfiles();
- }
- }
不同的协议实现类,继承于LocalBluetoothProfile,以HeadsetProfile为例。
- synchronized void connectInt(LocalBluetoothProfile profile) {
- if (!ensurePaired()) {
- return;
- }
- if (<span style="color:#ff0000;">profile.connect(mDevice)</span>) {
- if (Utils.D) {
- Log.d(TAG, "Command sent successfully:CONNECT " + describe(profile));
- }
- return;
- }
- Log.i(TAG, "Failed to connect " + profile.toString() + " to " + mName);
- }
这个方法中,profile.connnect(),直接调用 HeadsetProfile的connnect(),其实headset/handsfree 是共用同一个service。
packages/apps/Settings/src/com/android/settings/bluetooth/HeadsetProfile.java
- public boolean connect(BluetoothDevice device) {
- if (mService == null) return false;
- List<BluetoothDevice> sinks = mService.getConnectedDevices();
- if (sinks != null) {//断开所有连接
- for (BluetoothDevice sink : sinks) {
- mService.disconnect(sink);
- }
- }
- return mService.connect(device);
- }
mService.connect 直接进入framwork层,调用Bluetooth Headset server的api。
frameworks/base/core/java/android/bluetooth/BluetoothHeadset.java
- public boolean connect(BluetoothDevice device) {
- if (DBG) log("connect(" + device + ")");
- if (mService != null && isEnabled() &&
- isValidDevice(device)) {
- try {
- return mService.connect(device);
- } catch (RemoteException e) {
- Log.e(TAG, Log.getStackTraceString(new Throwable()));
- return false;
- }
- }
- if (mService == null) Log.w(TAG, "Proxy not attached to service");
- return false;
- }
framework 中转了一下,利用Binder机制再次进入Bluetooth模块。
frameworks/base/core/java/android/bluetooth/IBluetoothHeadset.aidl,实现类是
packages/apps/Bluetooth/src/com/android/bluetooth/hfp/HeadsetService.java
注意顺序:Setting->framewrok->Bluetooth
- public boolean connect(BluetoothDevice device) {
- HeadsetService service = getService();
- if (service == null) return false;
- return service.connect(device);
- }
IBluetoothHeadset.Sub仅仅是一个连接,什么都不做直接进入HeadsetService.java的connect 方法。
- public boolean connect(BluetoothDevice device) {
- enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
- "Need BLUETOOTH ADMIN permission");
- if (getPriority(device) == BluetoothProfile.PRIORITY_OFF) {
- return false;
- }
- int connectionState = mStateMachine.getConnectionState(device);
- if (connectionState == BluetoothProfile.STATE_CONNECTED ||
- connectionState == BluetoothProfile.STATE_CONNECTING) {
- return false;
- }
- mStateMachine.sendMessage(HeadsetStateMachine.CONNECT, device);//万恶的状态机开始工作
- return true;
- }
很讨厌android状态机,感觉把java搞成了非面向对象,进入状态机代码实现:
packages/apps/Bluetooth/src/com/android/bluetooth/hfp/HeadsetStateMachine.java
记住当前为 未连接状态,所以应该进入 Disconnected的状态,Disconnected的processMessage方法中:
- switch(message.what) {
- case CONNECT:
- BluetoothDevice device = (BluetoothDevice) message.obj;
- broadcastConnectionState(device, BluetoothProfile.STATE_CONNECTING,
- BluetoothProfile.STATE_DISCONNECTED);
- if (!<span style="color:#ff0000;">connectHfpNative(getByteAddress(device)) </span>) {
- broadcastConnectionState(device, BluetoothProfile.STATE_DISCONNECTED,
- BluetoothProfile.STATE_CONNECTING);
- break;
- }
- synchronized (HeadsetStateMachine.this) {
- mTargetDevice = device;
- transitionTo(mPending);
- }
connectHfpNative 连接,jni 方法 简单了。
packages\apps\bluetooth\jni\Com_android_bluetooth_hfp.cpp
- {"connectHfpNative", "([B)Z", (void *) connectHfpNative},
- static jboolean connectHfpNative(JNIEnv *env, jobject object, jbyteArray address) {
- jbyte *addr;
- bt_status_t status;
- ALOGI("%s: sBluetoothHfpInterface: %p", __FUNCTION__, sBluetoothHfpInterface);
- if (!sBluetoothHfpInterface) return JNI_FALSE;
- addr = env->GetByteArrayElements(address, NULL);
- if (!addr) {
- jniThrowIOException(env, EINVAL);
- return JNI_FALSE;
- }
- <span style="color:#ff0000;">if ((status = sBluetoothHfpInterface->connect((bt_bdaddr_t *)addr)) != BT_STATUS_SUCCESS) {</span>
- ALOGE("Failed HF connection, status: %d", status);
- }
- env->ReleaseByteArrayElements(address, addr, 0);
- return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
关键函数是sBluetoothHfpInterface->connect((bt_bdaddr_t *)addr), connect定义在 hardware/libhardware/include/hardware/bt_hf.h,
但是实现却在:external/bluetooth/bluedroid/btif/src/btif_hf.c 中实现
- #include <hardware/bt_hf.h>
- static bt_status_t connect( bt_bdaddr_t *bd_addr )
- {
- CHECK_BTHF_INIT();
- return btif_queue_connect(UUID_SERVCLASS_AG_HANDSFREE, bd_addr, connect_int);
- }
看定义,直接连接handsfree
#define UUID_SERVCLASS_AG_HANDSFREE 0X111F /* Handsfree profile */
btif_queue_connect的定义在下面文件中定义
external/bluetooth/bluedroid/btif/src/btif_profile_queue.c
进入bt_status_t btif_queue_connect看定义:
- bt_status_t btif_queue_connect(uint16_t uuid, const bt_bdaddr_t *bda,
- btif_connect_cb_t *connect_cb)
- {
- connect_node_t node;
- memset(&node, 0, sizeof(connect_node_t));
- memcpy(&(node.bda), bda, sizeof(bt_bdaddr_t));
- node.uuid = uuid;
- node.p_cb = connect_cb;
- return btif_transfer_context(queue_int_handle_evt, BTIF_QUEUE_CONNECT_EVT,
- (char*)&node, sizeof(connect_node_t), NULL);
- }
btif_transfer_context定义在如下文件中
external/bluetooth/bluedroid/btif/src/btif_core.c
btif_transfer_context内容就不粘贴了,里面发送消息,调用
external/bluetooth/bluedroid/gki/common/gki_buffer.c
- void GKI_send_msg (UINT8 task_id, UINT8 mbox, void *msg)
GKI_send_msg发送一条GKI信息到BTA,GKI_send_msg有三个参数,第一个参数是线程id,也作为task id, 通过bta_sys_init获得,第二个参数是mailbox id,第三个是上一步封装好的p_msg
首先对p_msg进一步封装成event,通过链表存到mailbox
id对应的任务队列中,调用external/bluetooth/bluedroid/gki/ulinux/gki_ulinux.c
:: GKI_send_event
ZT 4.3 android bluetooth hfp分析的更多相关文章
- 【转】Android bluetooth介绍(三): 蓝牙扫描(scan)设备分析
原文网址:http://blog.csdn.net/xubin341719/article/details/38584469 关键词:蓝牙blueZ A2DP.SINK.sink_connect.s ...
- Android bluetooth介绍(四): a2dp connect流程分析
关键词:蓝牙blueZ A2DP.SINK.sink_connect.sink_disconnect.sink_suspend.sink_resume.sink_is_connected.sink_ ...
- Android bluetooth介绍(三): 蓝牙扫描(scan)设备分析
关键词:蓝牙blueZ A2DP.SINK.sink_connect.sink_disconnect.sink_suspend.sink_resume.sink_is_connected.sink_ ...
- Android源码分析(六)-----蓝牙Bluetooth源码目录分析
一 :Bluetooth 的设置应用 packages\apps\Settings\src\com\android\settings\bluetooth* 蓝牙设置应用及设置参数,蓝牙状态,蓝牙设备等 ...
- ZT Android Debuggerd的分析及使用方法
Android Debuggerd的分析及使用方法 分类: 移动开发 android framework 2012-12-28 12:00 983人阅读 评论(0) 收藏 举报 目录(?)[+] An ...
- android4.3 Bluetooth(le)分析之startLeScan分析
BluetoothAdapter.java中有low enery(le)的一些方法,android提供了这些方法,但源码中并未找到这些方法的调用之处.本文档主要分析这类方法的执行流程,来了解下le到底 ...
- 【转】Android bluetooth介绍(二): android blueZ蓝牙代码架构及其uart 到rfcomm流程
原文网址:http://blog.sina.com.cn/s/blog_602c72c50102uzoj.html 关键词:蓝牙blueZ UART HCI_UART H4 HCI L2CAP ...
- Android BLE与终端通信(二)——Android Bluetooth基础科普以及搜索蓝牙设备显示列表
Android BLE与终端通信(二)--Android Bluetooth基础搜索蓝牙设备显示列表 摘要 第一篇算是个热身,这一片开始来写些硬菜了,这篇就是实际和蓝牙打交道了,所以要用到真机调试哟, ...
- Android Bluetooth模块学习笔记
一.蓝牙基础知识 1.蓝牙( Bluetooth )是一种无线技术标准,可实现固定设备.移动设备和楼宇个人域网之间的短距离数据交换.蓝牙基于设备低成本的收发器芯片,传输距离近.低功耗. 2.微波频段: ...
随机推荐
- [转]微信小程序之购物数量加减 —— 微信小程序实战商城系列(3)
本文转自:http://blog.csdn.net/michael_ouyang/article/details/70194144 我们在购买宝贝的时候,购物的数量,经常是我们需要使用的,如下所示: ...
- MySQL7:性能优化
性能优化 优化MySQL数据库是数据库管理员和数据库开发人员的必备技能.MySQL优化,一方面是找出系统的瓶颈,提高MySQL数据库的整体性能:一方面需要合理的结构设计和参数调整,以提高用户操作响应的 ...
- 序列化模块2 pickle
import pickle # dump的结果是bytes,dump用的f文件句柄需要以wb的形式打开,load所用的f是'rb'模式# 支持几乎所有对象的序列化# 对于对象的序列化需要这个对象对应的 ...
- python3中的新式类mro查看和C3算法原理
两个公式 L(object) = [object] L(子类(父类1, 父类2)) = [子类] + merge(L(父类1), L(父类2) , [父类1, 父类2])注意 + 代表合并列表 mer ...
- web百度地图离线开发
公司现在做的一个项目本来用的是google离线地图,但是发现谷歌的地图数据很久没更新数据了,中国的城市发展这么快,好多地方地图和现实都对不上了. 发现百度地图数据更新挺快的(呵呵,毕竟是国产的吗),最 ...
- 【vue】vue的路由权限管理
前言: 最近闲来无事浏览各种博客,看到了一个关于路由权限的管理,觉得很有用,针对那个博客,准备自己写一个demo. 实现: 路由大致分为用户路由<特定用户才能浏览>和基本路由<所有用 ...
- EJB JBOSS的安装
下载地址:http://www.jboss.org/jbossas/downloads 下载JBoss 4.2.3-->解压 启动:bin-->run.bat 管理后台:www.local ...
- 请求包含(Include)和请求转发(Forward)
定义 请求包含是指将另一个Servlet的请求处理流程包含进来. 请求转发是指将请求转发给别的Servlet处理. 实现 实现请求包含和请求转发,可以使用HttpServletRequest的getR ...
- Eclipse 校验取消
eclipse Multiple annotations found at this line错误,eclipse开发过程中,一些XML配置文件会报错,但是这些其实不是错,飘红的原因是因为eclips ...
- 11.Spring——JDBC框架
1.DBC 框架概述 2.Spring JDBC 示例 3.Spring 中 SQL 的存储过程 1.DBC 框架概述 在使用普通的 JDBC 数据库时,就会很麻烦的写不必要的代码来处理异常,打开和关 ...