Android4.4(MT8685)源码蓝牙解析--BLE搜索
来源:互联网 发布:owncloud9 php 编辑:程序博客网 时间:2024/05/16 04:54
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;@Overrideprotected 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")@Overridepublic void onClick(View arg0) {if(bluetoothAdapter.isEnabled()){bluetoothAdapter.startLeScan(callback);}}});}@SuppressLint("NewApi")private BluetoothAdapter.LeScanCallback callback = new BluetoothAdapter.LeScanCallback(){@Overridepublic 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.4(MT8685)源码蓝牙解析--搜索
- Android4.4(MT8685)源码蓝牙解析--概述
- Android4.4(MT8685)源码蓝牙解析--配对
- Android4.4(MT8685)源码蓝牙解析--连接
- Android4.4(MT8685)源码WIFI--初始化1
- Android4.4(MT8685)源码WIFI--初始化2
- Android4.4(MT8685)源码WIFI--扫描和连接
- Android4.3 蓝牙BLE初步
- Android4.3 蓝牙BLE初步
- Android4.3 蓝牙BLE初步
- Android4.3 蓝牙BLE初步
- Android4.3 蓝牙BLE初步
- Android4.3 蓝牙BLE初步
- Android4.3 蓝牙BLE初步
- Android4.3 蓝牙BLE初步
- Android4.3 蓝牙BLE初步
- Android4.3 蓝牙BLE初步
- python正则表达式
- 构建CF卡Linux系统的几个常见难题
- hdu2614 Beat 简单dfs
- Mahout0.9 ——hadoop2.2.0编译与安装
- MySQL read_log_event(): 'Found invalid event in binary log'
- Android4.4(MT8685)源码蓝牙解析--BLE搜索
- win64使用openssl生成ca证书
- 第16周项目5-编程处理C++代码(判断主函数个数)
- mybatis实战教程(mybatis in action)之四:实现关联数据的查询
- [JAVA]POI(Apache POI)各Jar包的作用
- 典型相关分析(Canonical Correlation Analysis, CCA)
- jquery跨域请求解决方案(都是从网上找的,本人未加验证)
- [黑马程序员][C语言]预处理指令
- EAX、ECX、EDX、EBX寄存器的作用