Android6.0蓝牙探索旅程

2023-12-20 10:18

本文主要是介绍Android6.0蓝牙探索旅程,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

废话不说,直接撸代码。
模块一:模拟手机设置界面打开蓝牙操作逐步分析。

Step1

设置界面
对应文件packages/apps/Settings/SettingsActivity.java

private static final String[] ENTRY_FRAGMENTS = {......BluetoothSettings.class.getName(),......}```

蓝牙作为众多设置的一个,也被添加到数组中了。

Step2

蓝牙设置界面这里写图片描述
对应文件ackages/apps/Settings/bluetooth/BluetoothSettings.java
public class BluetoothSettings extends DeviceListPreferenceFragment implements Indexable {
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
……….
final SettingsActivity activity = (SettingsActivity) getActivity();
mSwitchBar = activity.getSwitchBar();
mBluetoothEnabler = new BluetoothEnabler(activity, mSwitchBar);
mBluetoothEnabler.setupSwitchBar();
}

}
继承自fragment,添加了一个switchBar。嗯,接下来分析BluetoothEnabler这个文件时如何来控制蓝牙的开关的。

Step3

文件目录:packages/apps/Settings/bluetooth/BluetoothEnabler.java
`public void onSwitchChanged(Switch switchView, boolean isChecked) {

    if (isChecked &&!WirelessUtils.isRadioAllowed(mContext, Settings.Global.RADIO_BLUETOOTH)) {Toast.makeText(mContext, R.string.wifi_in_airplane_mode, Toast.LENGTH_SHORT).show();// Reset switch to offswitchView.setChecked(false);}MetricsLogger.action(mContext, MetricsLogger.ACTION_BLUETOOTH_TOGGLE, isChecked);Log.d(TAG, "mUpdateStatusOnly is " + mUpdateStatusOnly);/// M: if receive bt status changed broadcast, do not need enable/disable bt.if (mLocalAdapter != null && !mUpdateStatusOnly) {mLocalAdapter.setBluetoothEnabled(isChecked);}mSwitch.setEnabled(false);
}`

Step4

调用bluetoothAdapter的setBluetoothEnabled(isChecked)方法,
boolean success = enabled ? mAdapter.enable() : mAdapter.disable()
终于到核心类BluetoothAdapter了。
目录来了一个大的改变从packages目录到了frameworks目录。
frameworks/base/core/java/android/bluetooth/bluetoothAdapter.java

 @SystemApipublic boolean enableBLE() {if (!isBleScanAlwaysAvailable()) return false;if (isLeEnabled() == true) {if (DBG) Log.d(TAG, "enableBLE(): BT is already enabled..!");try {mManagerService.updateBleAppCount(mToken, true);} catch (RemoteException e) {Log.e(TAG, "", e);}return true;}try {if (DBG) Log.d(TAG, "Calling enableBLE");mManagerService.updateBleAppCount(mToken, true);return mManagerService.enable();} catch (RemoteException e) {Log.e(TAG, "", e);}return false;}

Step5

重点关注 return mManagerService.enable(); mManagerService的创建时在BluetoothAdapter中完成的

  public static synchronized BluetoothAdapter getDefaultAdapter() {if (sAdapter == null) {IBinder b = ServiceManager.getService(BLUETOOTH_MANAGER_SERVICE);if (b != null) {IBluetoothManager managerService = IBluetoothManager.Stub.asInterface(b);sAdapter = new BluetoothAdapter(managerService);} else {Log.e(TAG, "Bluetooth binder is null");}}return sAdapter;}/*** Use {@link #getDefaultAdapter} to get the BluetoothAdapter instance.*/BluetoothAdapter(IBluetoothManager managerService) {if (managerService == null) {throw new IllegalArgumentException("bluetooth manager service is null");}try {mService = managerService.registerAdapter(mManagerCallback);} catch (RemoteException e) {Log.e(TAG, "", e);}mManagerService = managerService;mLeScanClients = new HashMap<LeScanCallback, ScanCallback>();mToken = new Binder();}

我们可以看到,getDefaultAdapter方法和构造方法配合着使用。当获取实例时,mManagerService也实例化了。首先通过ServiceManager的getService返回一个binder类型的对象,然后获取到远程对象的接口managerService ,来进行远程调用。这样我们直接查看frameworks/base/core/java/android/bluetooth/BluetoothManagerService 的enable方法。

Step5

在这里前面最终还是调用了, sendEnableMsg(false);发送了MESSAGE_ENABLE消息,我们看看,哪个handler接收了这个消息。

  public boolean enable() {if ((Binder.getCallingUid() != Process.SYSTEM_UID) &&(!checkIfCallerIsForegroundUser())) {Log.w(TAG,"enable(): not allowed for non-active and non system user");return false;}mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,"Need BLUETOOTH ADMIN permission");if (DBG) {Log.d(TAG,"enable():  mBluetooth =" + mBluetooth +" mBinding = " + mBinding);}/// M: MoMS permission check @{if (MobileManagerUtils.isSupported()) {checkEnablePermission();return true;}/// @}synchronized(mReceiver) {mQuietEnableExternal = false;mEnableExternal = true;// waive WRITE_SECURE_SETTINGS permission checksendEnableMsg(false);}if (DBG) Log.d(TAG, "enable returning");return true;}private void sendEnableMsg(boolean quietMode) {mHandler.sendMessage(mHandler.obtainMessage(MESSAGE_ENABLE,quietMode ? 1 : 0, 0));}

Step6

BluetoothManagerService有个内部类BluetoothHandler.java,继续发消息,里面有个doBind方法,发现最终拉起一个Service,看看ServiceConnection的onServiceConected方法,发现又是发消息MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED,里面会根据AdapterService和GattService的差异区别发送,最终传一个binder对象到message中,继续看看这个消息发送的目的地,他在BluetoothHandler中,这里也是把之前的binder对象转化成调用远程服务的接口,所以最终我们要看在
AdapterService和GattService是如何处理的。

        public void handleMessage(Message msg) {...case MESSAGE_ENABLE:mHandler.removeMessages(MESSAGE_RESTART_BLUETOOTH_SERVICE);mEnable = true;handleEnable(msg.arg1 == 1);break;case MESSAGE_BLUETOOTH_SERVICE_CONNECTED:{。。。。IBinder service = (IBinder) msg.obj;synchronized(mConnection) {if (msg.arg1 == SERVICE_IBLUETOOTHGATT) {mBluetoothGatt = IBluetoothGatt.Stub.asInterface(service);onBluetoothGattServiceUp();break;} // else must be SERVICE_IBLUETOOTH//Remove timeout                      mHandler.removeMessages(MESSAGE_TIMEOUT_BIND);mBinding = false;mBluetooth = IBluetooth.Stub.asInterface(service);try {boolean enableHciSnoopLog = (Settings.Secure.getInt(mContentResolver,Settings.Secure.BLUETOOTH_HCI_LOG, 0) == 1);if (!mBluetooth.configHciSnoopLog(enableHciSnoopLog)) {Log.e(TAG,"IBluetooth.configHciSnoopLog return false");}} catch (RemoteException e) {Log.e(TAG,"Unable to call configHciSnoopLog", e);}
.....                      break;}          case MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED:{Log.e(TAG, "MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED: " + msg.arg1);synchronized(mConnection) {if (msg.arg1 == SERVICE_IBLUETOOTH) {// if service is unbinded already, do nothing and returnif (mBluetooth == null) break;mBluetooth = null;} else if (msg.arg1 == SERVICE_IBLUETOOTHGATT) {mBluetoothGatt = null;break;} else {Log.e(TAG, "Bad msg.arg1: " + msg.arg1);break;}}...}private void handleEnable(boolean quietMode) {synchronized(mConnection) {     if ((mBluetooth == null) && (!mBinding)) {Message timeoutMsg=mHandler.obtainMessage(MESSAGE_TIMEOUT_BIND);mHandler.sendMessageDelayed(timeoutMsg,TIMEOUT_BIND_MS);mConnection.setGetNameAddressOnly(false);Intent i = new Intent(IBluetooth.class.getName());if (!doBind(i, mConnection,Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT,UserHandle.CURRENT)) {}}boolean doBind(Intent intent, ServiceConnection conn, int flags, UserHandle user) {ComponentName comp = intent.resolveSystemService(mContext.getPackageManager(), 0);intent.setComponent(comp);if (comp == null || !mContext.bindServiceAsUser(intent, conn, flags, user)) {Log.e(TAG, "Fail to bind to: " + intent);return false;}return true;}private class BluetoothServiceConnection implements ServiceConnection {
。。。。。public void onServiceConnected(ComponentName className, IBinder service) {if (DBG) Log.d(TAG, "BluetoothServiceConnection: " + className.getClassName());Message msg = mHandler.obtainMessage(MESSAGE_BLUETOOTH_SERVICE_CONNECTED);// TBD if (className.getClassName().equals(IBluetooth.class.getName())) {if (className.getClassName().equals("com.android.bluetooth.btservice.AdapterService")) {msg.arg1 = SERVICE_IBLUETOOTH;// } else if (className.getClassName().equals(IBluetoothGatt.class.getName())) {} else if (className.getClassName().equals("com.android.bluetooth.gatt.GattService")) {msg.arg1 = SERVICE_IBLUETOOTHGATT;} else {Log.e(TAG, "Unknown service connected: " + className.getClassName());return;}msg.obj = service;mHandler.sendMessage(msg);}。。。。}

Step7

上面已经说到,要找AdapterService和GattService里继续追踪。接下来重点考虑AdapterService,他的路径在Packages/apps/Bluetooth/src/com/android/bluetooth/btservice/AdapterService,所以又从framework层调到了app层。从何处入手了,Step6中说了拉起服务的事,其实后面拉起服务后还会有一段代码,启动蓝牙,我们看看AdapterService的enable方法。

//Enable bluetoothtry {if (!mQuietEnable) {if(!mBluetooth.enable()) {Log.e(TAG,"IBluetooth.enable() returned false");}}else {if(!mBluetooth.enableNoAutoConnect()) {Log.e(TAG,"IBluetooth.enableNoAutoConnect() returned false");}}} catch (RemoteException e) {Log.e(TAG,"Unable to call enable()",e);}public class AdapterService extends Service {
...
public synchronized boolean enable(boolean quietMode) {enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH ADMIN permission");debugLog("enable() - Enable called with quiet mode status =  " + mQuietmode);mQuietmode = quietMode;Message m = mAdapterStateMachine.obtainMessage(AdapterState.BLE_TURN_ON);mAdapterStateMachine.sendMessage(m);return true;}...}

Step8

嗯,继续发消息,AdapterState.BLE_TURN_ON
Packages/apps/Bluetooth/src/com/android/bluetooth/btservice/AdapterState.java,里面有很多stateMachine,也有对消息的监听这里,我也有点蒙圈,不按照套路出牌,最终要调用adapterService.enableNative()的native方法,进行jni通信。

 case BLE_TURN_ON:if (isTurningOff || isBleTurningOff) {infoLog("Deferring BLE_TURN_ON request...");deferMessage(msg);}break;case BLE_STARTED://Remove start timeoutremoveMessages(BLE_START_TIMEOUT);//Enableif (!adapterService.enableNative()) {errorLog("Error while turning Bluetooth on");notifyAdapterStateChange(BluetoothAdapter.STATE_OFF);transitionTo(mOffState);} else {sendMessageDelayed(ENABLE_TIMEOUT, ENABLE_TIMEOUT_DELAY);}break;

Step9

从应用层调到了蓝牙协议栈了,我们看看它的c++层是如何操作的。
Packages/apps/Bluetooth/jni/com_android_bluetooth_btservice_AdapterService.cpp,蓝牙驱动对象sBluetoothInterface的enable方法。好吧我再也分析不下去了。

static jboolean enableNative(JNIEnv* env, jobject obj) {  ALOGV("%s:",__FUNCTION__);  jboolean result = JNI_FALSE;  if (!sBluetoothInterface) return result;  int ret = sBluetoothInterface->enable();  result = (ret == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;  return result;  }  

总的来说博通写的蓝牙模块的内容涉及了好多message信息的处理。下面一篇我会对蓝牙文件传输进行分析。

这篇关于Android6.0蓝牙探索旅程的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/515653

相关文章

pip install jupyterlab失败的原因问题及探索

《pipinstalljupyterlab失败的原因问题及探索》在学习Yolo模型时,尝试安装JupyterLab但遇到错误,错误提示缺少Rust和Cargo编译环境,因为pywinpty包需要它... 目录背景问题解决方案总结背景最近在学习Yolo模型,然后其中要下载jupyter(有点LSVmu像一个

深入探索协同过滤:从原理到推荐模块案例

文章目录 前言一、协同过滤1. 基于用户的协同过滤(UserCF)2. 基于物品的协同过滤(ItemCF)3. 相似度计算方法 二、相似度计算方法1. 欧氏距离2. 皮尔逊相关系数3. 杰卡德相似系数4. 余弦相似度 三、推荐模块案例1.基于文章的协同过滤推荐功能2.基于用户的协同过滤推荐功能 前言     在信息过载的时代,推荐系统成为连接用户与内容的桥梁。本文聚焦于

AI(文生语音)-TTS 技术线路探索学习:从拼接式参数化方法到Tacotron端到端输出

AI(文生语音)-TTS 技术线路探索学习:从拼接式参数化方法到Tacotron端到端输出 在数字化时代,文本到语音(Text-to-Speech, TTS)技术已成为人机交互的关键桥梁,无论是为视障人士提供辅助阅读,还是为智能助手注入声音的灵魂,TTS 技术都扮演着至关重要的角色。从最初的拼接式方法到参数化技术,再到现今的深度学习解决方案,TTS 技术经历了一段长足的进步。这篇文章将带您穿越时

轻松录制每一刻:探索2024年免费高清录屏应用

你不会还在用一些社交工具来录屏吧?现在的市面上有不少免费录屏的软件了。别看如软件是免费的,它的功能比起社交工具的录屏功能来说全面的多。这次我就分享几款我用过的录屏工具。 1.福晰录屏大师 链接直达:https://www.foxitsoftware.cn/REC/  这个软件的操作方式非常简单,打开软件之后从界面设计就能看出来这个软件操作的便捷性。界面的设计简单明了基本一打眼你就会轻松驾驭啦

深入探索嵌入式 Linux

摘要:本文深入探究嵌入式 Linux。首先回顾其发展历程,从早期尝试到克服诸多困难逐渐成熟。接着阐述其体系结构,涵盖硬件、内核、文件系统和应用层。开发环境方面包括交叉编译工具链、调试工具和集成开发环境。在应用领域,广泛应用于消费电子、工业控制、汽车电子和智能家居等领域。关键技术有内核裁剪与优化、设备驱动程序开发、实时性增强和电源管理等。最后展望其未来发展趋势,如与物联网融合、人工智能应用、安全性与

开放式耳机好用?平价开放式耳机推荐?四款开放式的蓝牙耳机推荐

开放式耳机好用吗?有平价些的开放式耳机推荐吗?那这两个问题的回答当然是肯定的。 首先开放式耳机好不好用取决于对耳机的需求,因为开放式耳机其实是比较适用于需要注意周围环境、需要‌长时间佩戴舒适以及需要频繁与人交流的场景中,在这些场景下使用开放式耳机的话就会比较有优势。就例如跑步骑行健身等运动的时候,能够兼得佩戴舒适度的同时,增加一定的安全性;还有在办公学习的时候,会很适合长时间佩戴,能够方便和

Android6.0以上权限申请

说明: 部分1:出自:http://jijiaxin89.com/2015/08/30/Android-s-Runtime-Permission/ android M 的名字官方刚发布不久,最终正式版即将来临! android在不断发展,最近的更新 M 非常不同,一些主要的变化例如运行时权限将有颠覆性影响。惊讶的是android社区鲜有谈论这事儿,尽管这事很重要或许在不远的将来会引

【vue3|第28期】 Vue3 + Vue Router:探索路由重定向的使用与作用

日期:2024年9月8日 作者:Commas 签名:(ง •_•)ง 积跬步以致千里,积小流以成江海…… 注释:如果您觉在这里插入代码片得有所帮助,帮忙点个赞,也可以关注我,我们一起成长;如果有不对的地方,还望各位大佬不吝赐教,谢谢^ - ^ 1.01365 = 37.7834;0.99365 = 0.0255 1.02365 = 1377.4083;0.98365 = 0.0006 说

多云架构下大模型训练的存储稳定性探索

一、多云架构与大模型训练的融合 (一)多云架构的优势与挑战 多云架构为大模型训练带来了诸多优势。首先,资源灵活性显著提高,不同的云平台可以提供不同类型的计算资源和存储服务,满足大模型训练在不同阶段的需求。例如,某些云平台可能在 GPU 计算资源上具有优势,而另一些则在存储成本或性能上表现出色,企业可以根据实际情况进行选择和组合。其次,扩展性得以增强,当大模型的规模不断扩大时,单一云平

探索Invoke:Python自动化任务的瑞士军刀

文章目录 探索Invoke:Python自动化任务的瑞士军刀背景:为何选择Invoke?`invoke`是什么?如何安装`invoke`?简单的`invoke`库函数使用方法场景应用:`invoke`在实际项目中的使用场景一:自动化测试场景二:代码格式化场景三:部署应用 常见问题与解决方案问题一:命令执行失败问题二:权限不足问题三:并发执行问题 总结 探索Invoke:P