【转】Android4.4(MT8685)源码蓝牙解析--BLE搜索
原文网址:http://blog.csdn.net/u013467735/article/details/41962075
BLE:全称为Bluetooth Low Energy。蓝牙规范4.0最重要的一个特性就是低功耗。BLE使得蓝牙设备可通过一粒纽扣电池供电以维持续工作数年之久。很明显,BLE使得蓝牙设备在钟表、远程控制、医疗保健及运动感应器等市场具有极光明的应用场景。
Google从Android 4.3开始添加了对蓝牙4.0的支持。本文一个demo为入口分析 BLE 搜索的流程。
- package com.dy.ble;
- import android.annotation.SuppressLint;
- import android.app.Activity;
- import android.bluetooth.BluetoothAdapter;
- import android.bluetooth.BluetoothDevice;
- import android.os.Bundle;
- import android.util.Log;
- import android.view.View;
- import android.view.View.OnClickListener;
- import android.widget.Button;
- public class MainActivity extends Activity {
- private static final String TAG = "BLE";
- private Button scanBtn;
- private BluetoothAdapter bluetoothAdapter;
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.main);
- bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
- if(!bluetoothAdapter.isEnabled()){
- bluetoothAdapter.enable();
- }
- scanBtn = (Button) this.findViewById(R.id.btn_scan);
- scanBtn.setOnClickListener(new OnClickListener(){
- @SuppressLint("NewApi")
- @Override
- public void onClick(View arg0) {
- if(bluetoothAdapter.isEnabled()){
- bluetoothAdapter.startLeScan(callback);
- }
- }
- });
- }
- @SuppressLint("NewApi")
- private BluetoothAdapter.LeScanCallback callback = new BluetoothAdapter.LeScanCallback(){
- @Override
- public void onLeScan(BluetoothDevice device, int rssi, byte[] scanRecord) {
- Log.d(TAG, "onLeScan device = " + device + ",rssi = " + rssi + "scanRecord = " + scanRecord);
- }
- };
- }
点击按钮就会开始扫描,扫描到设备时,就会触发onLeScan这个回调方法,并且可以从参数中获取扫描到的蓝牙设备信息。下面分析BluetoothAdapter中的startLeScan方法。
- public boolean startLeScan(LeScanCallback callback) {
- return startLeScan(null, callback);
- }
这里调用了一个同名的方法,
- public boolean startLeScan(UUID[] serviceUuids, LeScanCallback callback) {
- if (DBG) Log.d(TAG, "startLeScan(): " + serviceUuids);
- if (callback == null) {
- if (DBG) Log.e(TAG, "startLeScan: null callback");
- return false;
- }
- synchronized(mLeScanClients) {
- if (mLeScanClients.containsKey(callback)) {
- if (DBG) Log.e(TAG, "LE Scan has already started");
- return false;
- }
- try {
- IBluetoothGatt iGatt = mManagerService.getBluetoothGatt();
- if (iGatt == null) {
- if (DBG) Log.e("BluetoothAdapterReceiver", "iGatt == null");
- // BLE is not supported
- return false;
- }
- UUID uuid = UUID.randomUUID();
- GattCallbackWrapper wrapper = new GattCallbackWrapper(this, callback, serviceUuids);
- iGatt.registerClient(new ParcelUuid(uuid), wrapper);
- if (wrapper.scanStarted()) {
- if (DBG) Log.e("BluetoothAdapterReceiver", "wrapper.scanStarted()==true");
- mLeScanClients.put(callback, wrapper);
- return true;
- }
- } catch (RemoteException e) {
- Log.e(TAG,"",e);
- }
- }
- return false;
- }
这个方法需要BLUETOOTH_ADMIN权限,第一个参数是各种蓝牙服务的UUID数组,UUID是“Universally Unique Identifier”的简称,通用唯一识别码的意思。对于蓝牙设备,每个服务都有通用、独立、唯一的UUID与之对应。也就是说,在同一时间、同一地点,不可能有两个相同的UUID标识的不同服务。第二个参数是前面传进来的LeScanCallback对象。
接下来分析下mManagerService,它是一个IBluetoothManager对象,IBluetoothManager是一个AIDL,可以实现跨进程通信,其在源码中的路径为:/alps/frameworks/base/core/java/android/bluetooth/IBluetoothManager.aidl。下面来看看mManagerService的实例化,
- 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, GattCallbackWrapper>();
- }
直接将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;
- }
首先通过Binder机制获取了BLUETOOTH_MANAGER_SERVICE服务的IBinder对象,这个服务是在系统启动的时候添加进去的,在SystemServer.java中
- <pre name="code" class="java"> bluetooth = new BluetoothManagerService(context);
- ServiceManager.addService(BluetoothAdapter.BLUETOOTH_MANAGER_SERVICE, bluetooth);
这里实际就是实例化了一个BluetoothManagerService对象,然后把这个对象通过Binder保存在BLUETOOTH_MANAGER_SERVICE服务中。最后把这个IBinder对象转化为IBluetoothManager对象。所以managerService实际就是一个BluetoothManagerService对象。
现在回到BluetoothAdapter的startLeScan方法中,
- IBluetoothGatt iGatt = mManagerService.getBluetoothGatt();
这里实际就是调用BluetoothManagerService中的getBluetoothGatt方法了,我们进去看看
- public IBluetoothGatt getBluetoothGatt() {
- // sync protection
- return mBluetoothGatt;
- }
这里直接返回一个IBluetoothGatt对象,那我们就来看看这个对象时在哪里得到的呢?其实通过对代码的研究发现, 这个对象是在蓝牙开启的时候得到的!
- 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(FeatureOption.MTK_MOBILE_MANAGEMENT) {
- checkEnablePermission();
- return true;
- }
- /// @}
- synchronized(mReceiver) {
- mQuietEnableExternal = false;
- mEnableExternal = true;
- // waive WRITE_SECURE_SETTINGS permission check
- long callingIdentity = Binder.clearCallingIdentity();
- persistBluetoothSetting(BLUETOOTH_ON_BLUETOOTH);
- Binder.restoreCallingIdentity(callingIdentity);
- sendEnableMsg(false);
- }
- return true;
- }
这是开启蓝牙的代码,sendEnableMsg(false);这里看来要发送一个消息,
- private void sendEnableMsg(boolean quietMode) {
- mHandler.sendMessage(mHandler.obtainMessage(MESSAGE_ENABLE,
- quietMode ? 1 : 0, 0));
- }
果然,看看在哪里接收了
- @Override
- public void handleMessage(Message msg) {
- if (DBG) Log.d (TAG, "Message: " + msg.what);
- switch (msg.what) {
- <span style="white-space:pre"> </span> case MESSAGE_ENABLE:
- if (DBG) {
- Log.d(TAG, "MESSAGE_ENABLE: mBluetooth = " + mBluetooth);
- }
- mHandler.removeMessages(MESSAGE_RESTART_BLUETOOTH_SERVICE);
- mEnable = true;
- handleEnable(msg.arg1 == 1);
- break;
- <span style="white-space:pre"> </span>}
- }
进入handleEnable方法看看
- private void handleEnable(boolean quietMode) {
- mQuietEnable = quietMode;
- synchronized(mConnection) {
- if (DBG) Log.d(TAG, "handleEnable: mBluetooth = " + mBluetooth +
- ", mBinding = " + mBinding + "quietMode = " + quietMode);
- if ((mBluetooth == null) && (!mBinding)) {
- if (DBG) Log.d(TAG, "Bind AdapterService");
- //Start bind timeout and bind
- 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, UserHandle.CURRENT)) {
- mHandler.removeMessages(MESSAGE_TIMEOUT_BIND);
- Log.e(TAG, "Fail to bind to: " + IBluetooth.class.getName());
- } else {
- mBinding = true;
- }
- } else if (mBluetooth != null) {
- if (mConnection.isGetNameAddressOnly()) {
- // if GetNameAddressOnly is set, we can clear this flag,
- // so the service won't be unbind
- // after name and address are saved
- mConnection.setGetNameAddressOnly(false);
- //Register callback object
- try {
- mBluetooth.registerCallback(mBluetoothCallback);
- } catch (RemoteException re) {
- Log.e(TAG, "Unable to register BluetoothCallback",re);
- }
- //Inform BluetoothAdapter instances that service is up
- sendBluetoothServiceUpCallback();
- }
- //Enable bluetooth
- try {
- 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);
- }
- }
- }
- }
这里会调用doBinder方法来绑定服务,
- 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;
- }
这个conn就是mConnection,那么mConnection是什么呢?
- private BluetoothServiceConnection mConnection = new BluetoothServiceConnection();
- private class BluetoothServiceConnection implements ServiceConnection {
- private boolean mGetNameAddressOnly;
- public void setGetNameAddressOnly(boolean getOnly) {
- mGetNameAddressOnly = getOnly;
- }
- public boolean isGetNameAddressOnly() {
- return mGetNameAddressOnly;
- }
- 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);
- }
- public void onServiceDisconnected(ComponentName className) {
- // Called if we unexpected disconnected.
- if (DBG) Log.d(TAG, "BluetoothServiceConnection, disconnected: " +
- className.getClassName());
- Message msg = mHandler.obtainMessage(MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED);
- if (className.getClassName().equals("com.android.bluetooth.btservice.AdapterService")) {
- msg.arg1 = SERVICE_IBLUETOOTH;
- } else if (className.getClassName().equals("com.android.bluetooth.gatt.GattService")) {
- msg.arg1 = SERVICE_IBLUETOOTHGATT;
- } else {
- Log.e(TAG, "Unknown service disconnected: " + className.getClassName());
- return;
- }
- mHandler.sendMessage(msg);
- }
- }
现在我们就知道原来这个mConnection是一个绑定服务的连接对象,所以现在BluetoothManagerService绑定了一个IBluetooth的AIDL服务,这时onServiceConnected方法会执行,并且会发送一个MESSAGE_BLUETOOTH_SERVICE_CONNECTED消息,来看接收消息的地方
- case MESSAGE_BLUETOOTH_SERVICE_CONNECTED:
- {
- if (DBG) Log.d(TAG,"MESSAGE_BLUETOOTH_SERVICE_CONNECTED: " + msg.arg1);
- IBinder service = (IBinder) msg.obj;
- synchronized(mConnection) {
- if (msg.arg1 == SERVICE_IBLUETOOTHGATT) {
- mBluetoothGatt = IBluetoothGatt.Stub.asInterface(service);
- 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);
- }
- if (mConnection.isGetNameAddressOnly()) {
- //Request GET NAME AND ADDRESS
- Message getMsg = mHandler.obtainMessage(MESSAGE_GET_NAME_AND_ADDRESS);
- mHandler.sendMessage(getMsg);
- if (!mEnable) return;
- }
- mConnection.setGetNameAddressOnly(false);
- //Register callback object
- try {
- mBluetooth.registerCallback(mBluetoothCallback);
- } catch (RemoteException re) {
- Log.e(TAG, "Unable to register BluetoothCallback",re);
- }
- //Inform BluetoothAdapter instances that service is up
- sendBluetoothServiceUpCallback();
- //Do enable request
- try {
- if (mQuietEnable == false) {
- 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);
- }
- }
- if (!mEnable) {
- waitForOnOff(true, false);
- handleDisable();
- waitForOnOff(false, false);
- }
- break;
- }
当msg的参数1为SERVICE_IBLUETOOTHGATT时,实例化mBluetoothGatt对象,至此我们就可以得到mBluetoothGatt。
再一次回到BluetoothAdapter的startLeScan方法中,
- public boolean startLeScan(UUID[] serviceUuids, LeScanCallback callback) {
- if (DBG) Log.d(TAG, "startLeScan(): " + serviceUuids);
- if (callback == null) {
- if (DBG) Log.e(TAG, "startLeScan: null callback");
- return false;
- }
- synchronized(mLeScanClients) {
- if (mLeScanClients.containsKey(callback)) {
- if (DBG) Log.e(TAG, "LE Scan has already started");
- return false;
- }
- try {
- IBluetoothGatt iGatt = mManagerService.getBluetoothGatt();
- if (iGatt == null) {
- if (DBG) Log.e("BluetoothAdapterReceiver", "iGatt == null");
- // BLE is not supported
- return false;
- }
- UUID uuid = UUID.randomUUID();
- GattCallbackWrapper wrapper = new GattCallbackWrapper(this, callback, serviceUuids);
- iGatt.registerClient(new ParcelUuid(uuid), wrapper);
- if (wrapper.scanStarted()) {
- if (DBG) Log.e("BluetoothAdapterReceiver", "wrapper.scanStarted()==true");
- mLeScanClients.put(callback, wrapper);
- return true;
- }
- } catch (RemoteException e) {
- Log.e(TAG,"",e);
- }
- }
- return false;
- }
接着创建了一个GattCallbackWrapper对象,这是个BluetoothAdapter的内部类,主要用于获取回调信息,然后iGatt注册一个client,由BluetoothManagerService中的分析可知,iGatt实际是一个GattService内部类BluetoothGattBinder的对象
- public void registerClient(ParcelUuid uuid, IBluetoothGattCallback callback) {
- GattService service = getService();
- if (service == null) return;
- service.registerClient(uuid.getUuid(), callback);
- }
这里还是调用GattService的registerClient方法
- 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());
- }
这里面调用了本地方法,对应的JNI文件是Com_android_bluetooth_gatt.cpp,
- 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);
- }
分析到这里其实差不多了,因为这里系统会调用MTK提供的蓝牙库来实现搜索,源码我们无法看到。
至此,蓝牙BLE搜索分析完毕!
【转】Android4.4(MT8685)源码蓝牙解析--BLE搜索的更多相关文章
- Android4.2.2源码目录结构分析
撰写不易,转载请注明出处:http://blog.csdn.net/jscese/article/details/40897277#t17 导读: 关于的Android目录分析,网上有很多资料,在此不 ...
- iOS开发之Masonry框架源码深度解析
Masonry是iOS在控件布局中经常使用的一个轻量级框架,Masonry让NSLayoutConstraint使用起来更为简洁.Masonry简化了NSLayoutConstraint的使用方式,让 ...
- Retrofit源码设计模式解析(下)
本文将接着<Retrofit源码设计模式解析(上)>,继续分享以下设计模式在Retrofit中的应用: 适配器模式 策略模式 观察者模式 单例模式 原型模式 享元模式 一.适配器模式 在上 ...
- 源码深度解析SpringMvc请求运行机制(转)
源码深度解析SpringMvc请求运行机制 本文依赖的是springmvc4.0.5.RELEASE,通过源码深度解析了解springMvc的请求运行机制.通过源码我们可以知道从客户端发送一个URL请 ...
- SpringMVC 源码深度解析<context:component-scan>(扫描和注冊的注解Bean)
我们在SpringMVC开发项目中,有的用注解和XML配置Bean,这两种都各有自己的优势,数据源配置比較经经常使用XML配置.控制层依赖的service比較经经常使用注解等(在部署时比較不会改变的) ...
- 英蓓特Mars board的android4.0.3源码编译过程
英蓓特Mars board的android4.0.3源码编译过程 作者:StephenZhu(大桥++) 2013年8月22日 若要转载,请注明出处 一.编译环境搭建及要点: 1. 虚拟机软件virt ...
- Ubuntu12.04编译Android4.0.1源码全过程-----附wubi安装ubuntu编译android源码硬盘空间不够的问题解决
昨晚在编译源码,make一段时间之后报错如下: # A fatal error has been detected by the Java Runtime Environment: # # SIGSE ...
- Android 图片加载框架Glide4.0源码完全解析(二)
写在之前 上一篇博文写的是Android 图片加载框架Glide4.0源码完全解析(一),主要分析了Glide4.0源码中的with方法和load方法,原本打算是一起发布的,但是由于into方法复杂性 ...
- Masonry框架源码深度解析
Masonry是iOS在控件布局中经常使用的一个轻量级框架,Masonry让NSLayoutConstraint使用起来更为简洁.Masonry简化了NSLayoutConstraint的使用方式,让 ...
随机推荐
- OC加强-day03
#program mark - 0_18 分类的使用注意 [掌握] 1.分类的作用 作用:讲一个类分为多个模块,将相似功能的方法写在同一个模块中,方便我们后面代码的维护 "强调 1.分类中只 ...
- 切换到mint了,纪念一下
- sql server 数据库正在使用该文件的解决办法
今天在帮朋友还原数据库时遇到了一个问题.朋友用的是sql server 2008数据库,本身有一个数据库,他在修改程序的时候,想修改数据库的内容.但是又不想在原数据库中修改.想备份还原出一个数据库然后 ...
- [转载]5分钟了解Mockito
原文链接: http://liuzhijun.iteye.com/blog/1512780/ 5分钟了解Mockito 博客分类: Open SourceJava 一.什么是mock测试,什么是moc ...
- javascript笔记之正则表达式
1.在js正则表达式特殊的需要转义的字符有: ^ $ . * + ? = ! : | \ / ( ) [ ] { } 但实际应用中,还要根据实际情况来判断,以上字符可能不需要转义,也可能不止以上字符 ...
- 精通 Oracle+Python,第 1 部分:查询最佳应践
原文链接:http://www.oracle.com/technetwork/cn/articles/dsl/mastering-oracle-python-1391323-zhs.html 在 Py ...
- Python全栈开发之 Mysql (一)
一: 1.什么是数据库? 数据库(Database)是按照数据结构来组织.存储和管理数据的仓库别说我们在写程序的时候创建的database就是一个数据库 2.什么是 MySQL.Oracle.SQLi ...
- PHP、JSP、.NET各自的真正优势是什么
PHP的优势在于, 跨平台, 极易部署, 易维护, 为Web而生, 开源社区强大, 文档丰富.至于说3足鼎立, 谈不上, 全球前100万的sites中, 70%是PHP. JSP和Asp..net 也 ...
- STM32之系统滴答定时器
一.SysTick(系统滴答定时器)概述 操作系统需要一个滴答定时器周期性产生中断,以产生系统运行的节拍.在中断服务程序里,基于优先级调度的操作系统会根据进程优先级切换任务,基于时间片轮转系统会根据时 ...
- load-store/register-memory/register-plus-memory比较
在理解ARM的load-store架构时,我在百度上搜索了很长时间,但是始终找不到一篇像样的中文文章.最后,在用谷歌搜索的英文网站上终于找到了一些蛛丝马迹.让我们先看一下一篇英文资料. Process ...