【转】Android4.4(MT8685)源码蓝牙解析--BLE搜索

时间:2023-03-08 17:24:52

原文网址:http://blog.****.net/u013467735/article/details/41962075

BLE:全称为Bluetooth Low Energy。蓝牙规范4.0最重要的一个特性就是低功耗。BLE使得蓝牙设备可通过一粒纽扣电池供电以维持续工作数年之久。很明显,BLE使得蓝牙设备在钟表、远程控制、医疗保健及运动感应器等市场具有极光明的应用场景。

Google从Android 4.3开始添加了对蓝牙4.0的支持。本文一个demo为入口分析 BLE 搜索的流程。

  1. package com.dy.ble;
  2. import android.annotation.SuppressLint;
  3. import android.app.Activity;
  4. import android.bluetooth.BluetoothAdapter;
  5. import android.bluetooth.BluetoothDevice;
  6. import android.os.Bundle;
  7. import android.util.Log;
  8. import android.view.View;
  9. import android.view.View.OnClickListener;
  10. import android.widget.Button;
  11. public class MainActivity extends Activity {
  12. private static final String TAG = "BLE";
  13. private Button scanBtn;
  14. private BluetoothAdapter bluetoothAdapter;
  15. @Override
  16. protected void onCreate(Bundle savedInstanceState) {
  17. super.onCreate(savedInstanceState);
  18. setContentView(R.layout.main);
  19. bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
  20. if(!bluetoothAdapter.isEnabled()){
  21. bluetoothAdapter.enable();
  22. }
  23. scanBtn = (Button) this.findViewById(R.id.btn_scan);
  24. scanBtn.setOnClickListener(new OnClickListener(){
  25. @SuppressLint("NewApi")
  26. @Override
  27. public void onClick(View arg0) {
  28. if(bluetoothAdapter.isEnabled()){
  29. bluetoothAdapter.startLeScan(callback);
  30. }
  31. }
  32. });
  33. }
  34. @SuppressLint("NewApi")
  35. private BluetoothAdapter.LeScanCallback callback = new BluetoothAdapter.LeScanCallback(){
  36. @Override
  37. public void onLeScan(BluetoothDevice device, int rssi, byte[] scanRecord) {
  38. Log.d(TAG, "onLeScan device = " + device + ",rssi = " + rssi + "scanRecord = " + scanRecord);
  39. }
  40. };
  41. }

点击按钮就会开始扫描,扫描到设备时,就会触发onLeScan这个回调方法,并且可以从参数中获取扫描到的蓝牙设备信息。下面分析BluetoothAdapter中的startLeScan方法。

  1. public boolean startLeScan(LeScanCallback callback) {
  2. return startLeScan(null, callback);
  3. }

这里调用了一个同名的方法,

  1. public boolean startLeScan(UUID[] serviceUuids, LeScanCallback callback) {
  2. if (DBG) Log.d(TAG, "startLeScan(): " + serviceUuids);
  3. if (callback == null) {
  4. if (DBG) Log.e(TAG, "startLeScan: null callback");
  5. return false;
  6. }
  7. synchronized(mLeScanClients) {
  8. if (mLeScanClients.containsKey(callback)) {
  9. if (DBG) Log.e(TAG, "LE Scan has already started");
  10. return false;
  11. }
  12. try {
  13. IBluetoothGatt iGatt = mManagerService.getBluetoothGatt();
  14. if (iGatt == null) {
  15. if (DBG) Log.e("BluetoothAdapterReceiver", "iGatt == null");
  16. // BLE is not supported
  17. return false;
  18. }
  19. UUID uuid = UUID.randomUUID();
  20. GattCallbackWrapper wrapper = new GattCallbackWrapper(this, callback, serviceUuids);
  21. iGatt.registerClient(new ParcelUuid(uuid), wrapper);
  22. if (wrapper.scanStarted()) {
  23. if (DBG) Log.e("BluetoothAdapterReceiver", "wrapper.scanStarted()==true");
  24. mLeScanClients.put(callback, wrapper);
  25. return true;
  26. }
  27. } catch (RemoteException e) {
  28. Log.e(TAG,"",e);
  29. }
  30. }
  31. return false;
  32. }

这个方法需要BLUETOOTH_ADMIN权限,第一个参数是各种蓝牙服务的UUID数组,UUID是“Universally Unique Identifier”的简称,通用唯一识别码的意思。对于蓝牙设备,每个服务都有通用、独立、唯一的UUID与之对应。也就是说,在同一时间、同一地点,不可能有两个相同的UUID标识的不同服务。第二个参数是前面传进来的LeScanCallback对象。

接下来分析下mManagerService,它是一个IBluetoothManager对象,IBluetoothManager是一个AIDL,可以实现跨进程通信,其在源码中的路径为:/alps/frameworks/base/core/java/android/bluetooth/IBluetoothManager.aidl。下面来看看mManagerService的实例化,

  1. BluetoothAdapter(IBluetoothManager managerService) {
  2. if (managerService == null) {
  3. throw new IllegalArgumentException("bluetooth manager service is null");
  4. }
  5. try {
  6. mService = managerService.registerAdapter(mManagerCallback);
  7. } catch (RemoteException e) {Log.e(TAG, "", e);}
  8. mManagerService = managerService;
  9. mLeScanClients = new HashMap<LeScanCallback, GattCallbackWrapper>();
  10. }

直接将BluetoothAdapter构造方法的参数传给了它,来看看这个参数到底是什么?

  1. public static synchronized BluetoothAdapter getDefaultAdapter() {
  2. if (sAdapter == null) {
  3. IBinder b = ServiceManager.getService(BLUETOOTH_MANAGER_SERVICE);
  4. if (b != null) {
  5. IBluetoothManager managerService = IBluetoothManager.Stub.asInterface(b);
  6. sAdapter = new BluetoothAdapter(managerService);
  7. } else {
  8. Log.e(TAG, "Bluetooth binder is null");
  9. }
  10. }
  11. return sAdapter;
  12. }

首先通过Binder机制获取了BLUETOOTH_MANAGER_SERVICE服务的IBinder对象,这个服务是在系统启动的时候添加进去的,在SystemServer.java中

  1. <pre name="code" class="java"> bluetooth = new BluetoothManagerService(context);
  2. ServiceManager.addService(BluetoothAdapter.BLUETOOTH_MANAGER_SERVICE, bluetooth);

这里实际就是实例化了一个BluetoothManagerService对象,然后把这个对象通过Binder保存在BLUETOOTH_MANAGER_SERVICE服务中。最后把这个IBinder对象转化为IBluetoothManager对象。所以managerService实际就是一个BluetoothManagerService对象。

现在回到BluetoothAdapter的startLeScan方法中,

  1. IBluetoothGatt iGatt = mManagerService.getBluetoothGatt();

这里实际就是调用BluetoothManagerService中的getBluetoothGatt方法了,我们进去看看

  1. public IBluetoothGatt getBluetoothGatt() {
  2. // sync protection
  3. return mBluetoothGatt;
  4. }

这里直接返回一个IBluetoothGatt对象,那我们就来看看这个对象时在哪里得到的呢?其实通过对代码的研究发现, 这个对象是在蓝牙开启的时候得到的!

  1. public boolean enable() {
  2. if ((Binder.getCallingUid() != Process.SYSTEM_UID) &&
  3. (!checkIfCallerIsForegroundUser())) {
  4. Log.w(TAG,"enable(): not allowed for non-active and non system user");
  5. return false;
  6. }
  7. mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
  8. "Need BLUETOOTH ADMIN permission");
  9. if (DBG) {
  10. Log.d(TAG,"enable():  mBluetooth =" + mBluetooth +
  11. " mBinding = " + mBinding);
  12. }
  13. /// M: MoMS permission check @{
  14. if(FeatureOption.MTK_MOBILE_MANAGEMENT) {
  15. checkEnablePermission();
  16. return true;
  17. }
  18. /// @}
  19. synchronized(mReceiver) {
  20. mQuietEnableExternal = false;
  21. mEnableExternal = true;
  22. // waive WRITE_SECURE_SETTINGS permission check
  23. long callingIdentity = Binder.clearCallingIdentity();
  24. persistBluetoothSetting(BLUETOOTH_ON_BLUETOOTH);
  25. Binder.restoreCallingIdentity(callingIdentity);
  26. sendEnableMsg(false);
  27. }
  28. return true;
  29. }

这是开启蓝牙的代码,sendEnableMsg(false);这里看来要发送一个消息,

  1. private void sendEnableMsg(boolean quietMode) {
  2. mHandler.sendMessage(mHandler.obtainMessage(MESSAGE_ENABLE,
  3. quietMode ? 1 : 0, 0));
  4. }

果然,看看在哪里接收了

  1. @Override
  2. public void handleMessage(Message msg) {
  3. if (DBG) Log.d (TAG, "Message: " + msg.what);
  4. switch (msg.what) {
  5. <span style="white-space:pre">    </span>    case MESSAGE_ENABLE:
  6. if (DBG) {
  7. Log.d(TAG, "MESSAGE_ENABLE: mBluetooth = " + mBluetooth);
  8. }
  9. mHandler.removeMessages(MESSAGE_RESTART_BLUETOOTH_SERVICE);
  10. mEnable = true;
  11. handleEnable(msg.arg1 == 1);
  12. break;
  1. <span style="white-space:pre">        </span>}
  2. }

进入handleEnable方法看看

  1. private void handleEnable(boolean quietMode) {
  2. mQuietEnable = quietMode;
  3. synchronized(mConnection) {
  4. if (DBG) Log.d(TAG, "handleEnable: mBluetooth = " + mBluetooth +
  5. ", mBinding = " + mBinding + "quietMode = " + quietMode);
  6. if ((mBluetooth == null) && (!mBinding)) {
  7. if (DBG) Log.d(TAG, "Bind AdapterService");
  8. //Start bind timeout and bind
  9. Message timeoutMsg=mHandler.obtainMessage(MESSAGE_TIMEOUT_BIND);
  10. mHandler.sendMessageDelayed(timeoutMsg,TIMEOUT_BIND_MS);
  11. mConnection.setGetNameAddressOnly(false);
  12. Intent i = new Intent(IBluetooth.class.getName());
  13. if (!doBind(i, mConnection,Context.BIND_AUTO_CREATE, UserHandle.CURRENT)) {
  14. mHandler.removeMessages(MESSAGE_TIMEOUT_BIND);
  15. Log.e(TAG, "Fail to bind to: " + IBluetooth.class.getName());
  16. } else {
  17. mBinding = true;
  18. }
  19. } else if (mBluetooth != null) {
  20. if (mConnection.isGetNameAddressOnly()) {
  21. // if GetNameAddressOnly is set, we can clear this flag,
  22. // so the service won't be unbind
  23. // after name and address are saved
  24. mConnection.setGetNameAddressOnly(false);
  25. //Register callback object
  26. try {
  27. mBluetooth.registerCallback(mBluetoothCallback);
  28. } catch (RemoteException re) {
  29. Log.e(TAG, "Unable to register BluetoothCallback",re);
  30. }
  31. //Inform BluetoothAdapter instances that service is up
  32. sendBluetoothServiceUpCallback();
  33. }
  34. //Enable bluetooth
  35. try {
  36. if (!mQuietEnable) {
  37. if(!mBluetooth.enable()) {
  38. Log.e(TAG,"IBluetooth.enable() returned false");
  39. }
  40. }
  41. else {
  42. if(!mBluetooth.enableNoAutoConnect()) {
  43. Log.e(TAG,"IBluetooth.enableNoAutoConnect() returned false");
  44. }
  45. }
  46. } catch (RemoteException e) {
  47. Log.e(TAG,"Unable to call enable()",e);
  48. }
  49. }
  50. }
  51. }

这里会调用doBinder方法来绑定服务,

  1. boolean doBind(Intent intent, ServiceConnection conn, int flags, UserHandle user) {
  2. ComponentName comp = intent.resolveSystemService(mContext.getPackageManager(), 0);
  3. intent.setComponent(comp);
  4. if (comp == null || !mContext.bindServiceAsUser(intent, conn, flags, user)) {
  5. Log.e(TAG, "Fail to bind to: " + intent);
  6. return false;
  7. }
  8. return true;
  9. }

这个conn就是mConnection,那么mConnection是什么呢?

  1. private BluetoothServiceConnection mConnection = new BluetoothServiceConnection();
  1. private class BluetoothServiceConnection implements ServiceConnection {
  2. private boolean mGetNameAddressOnly;
  3. public void setGetNameAddressOnly(boolean getOnly) {
  4. mGetNameAddressOnly = getOnly;
  5. }
  6. public boolean isGetNameAddressOnly() {
  7. return mGetNameAddressOnly;
  8. }
  9. public void onServiceConnected(ComponentName className, IBinder service) {
  10. if (DBG) Log.d(TAG, "BluetoothServiceConnection: " + className.getClassName());
  11. Message msg = mHandler.obtainMessage(MESSAGE_BLUETOOTH_SERVICE_CONNECTED);
  12. // TBD if (className.getClassName().equals(IBluetooth.class.getName())) {
  13. if (className.getClassName().equals("com.android.bluetooth.btservice.AdapterService")) {
  14. msg.arg1 = SERVICE_IBLUETOOTH;
  15. // } else if (className.getClassName().equals(IBluetoothGatt.class.getName())) {
  16. } else if (className.getClassName().equals("com.android.bluetooth.gatt.GattService")) {
  17. msg.arg1 = SERVICE_IBLUETOOTHGATT;
  18. } else {
  19. Log.e(TAG, "Unknown service connected: " + className.getClassName());
  20. return;
  21. }
  22. msg.obj = service;
  23. mHandler.sendMessage(msg);
  24. }
  25. public void onServiceDisconnected(ComponentName className) {
  26. // Called if we unexpected disconnected.
  27. if (DBG) Log.d(TAG, "BluetoothServiceConnection, disconnected: " +
  28. className.getClassName());
  29. Message msg = mHandler.obtainMessage(MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED);
  30. if (className.getClassName().equals("com.android.bluetooth.btservice.AdapterService")) {
  31. msg.arg1 = SERVICE_IBLUETOOTH;
  32. } else if (className.getClassName().equals("com.android.bluetooth.gatt.GattService")) {
  33. msg.arg1 = SERVICE_IBLUETOOTHGATT;
  34. } else {
  35. Log.e(TAG, "Unknown service disconnected: " + className.getClassName());
  36. return;
  37. }
  38. mHandler.sendMessage(msg);
  39. }
  40. }

现在我们就知道原来这个mConnection是一个绑定服务的连接对象,所以现在BluetoothManagerService绑定了一个IBluetooth的AIDL服务,这时onServiceConnected方法会执行,并且会发送一个MESSAGE_BLUETOOTH_SERVICE_CONNECTED消息,来看接收消息的地方

  1. case MESSAGE_BLUETOOTH_SERVICE_CONNECTED:
  2. {
  3. if (DBG) Log.d(TAG,"MESSAGE_BLUETOOTH_SERVICE_CONNECTED: " + msg.arg1);
  4. IBinder service = (IBinder) msg.obj;
  5. synchronized(mConnection) {
  6. if (msg.arg1 == SERVICE_IBLUETOOTHGATT) {
  7. mBluetoothGatt = IBluetoothGatt.Stub.asInterface(service);
  8. break;
  9. } // else must be SERVICE_IBLUETOOTH
  10. //Remove timeout
  11. mHandler.removeMessages(MESSAGE_TIMEOUT_BIND);
  12. mBinding = false;
  13. mBluetooth = IBluetooth.Stub.asInterface(service);
  14. try {
  15. boolean enableHciSnoopLog = (Settings.Secure.getInt(mContentResolver,
  16. Settings.Secure.BLUETOOTH_HCI_LOG, 0) == 1);
  17. if (!mBluetooth.configHciSnoopLog(enableHciSnoopLog)) {
  18. Log.e(TAG,"IBluetooth.configHciSnoopLog return false");
  19. }
  20. } catch (RemoteException e) {
  21. Log.e(TAG,"Unable to call configHciSnoopLog", e);
  22. }
  23. if (mConnection.isGetNameAddressOnly()) {
  24. //Request GET NAME AND ADDRESS
  25. Message getMsg = mHandler.obtainMessage(MESSAGE_GET_NAME_AND_ADDRESS);
  26. mHandler.sendMessage(getMsg);
  27. if (!mEnable) return;
  28. }
  29. mConnection.setGetNameAddressOnly(false);
  30. //Register callback object
  31. try {
  32. mBluetooth.registerCallback(mBluetoothCallback);
  33. } catch (RemoteException re) {
  34. Log.e(TAG, "Unable to register BluetoothCallback",re);
  35. }
  36. //Inform BluetoothAdapter instances that service is up
  37. sendBluetoothServiceUpCallback();
  38. //Do enable request
  39. try {
  40. if (mQuietEnable == false) {
  41. if(!mBluetooth.enable()) {
  42. Log.e(TAG,"IBluetooth.enable() returned false");
  43. }
  44. }
  45. else
  46. {
  47. if(!mBluetooth.enableNoAutoConnect()) {
  48. Log.e(TAG,"IBluetooth.enableNoAutoConnect() returned false");
  49. }
  50. }
  51. } catch (RemoteException e) {
  52. Log.e(TAG,"Unable to call enable()",e);
  53. }
  54. }
  55. if (!mEnable) {
  56. waitForOnOff(true, false);
  57. handleDisable();
  58. waitForOnOff(false, false);
  59. }
  60. break;
  61. }

当msg的参数1为SERVICE_IBLUETOOTHGATT时,实例化mBluetoothGatt对象,至此我们就可以得到mBluetoothGatt。

再一次回到BluetoothAdapter的startLeScan方法中,

  1. public boolean startLeScan(UUID[] serviceUuids, LeScanCallback callback) {
  2. if (DBG) Log.d(TAG, "startLeScan(): " + serviceUuids);
  3. if (callback == null) {
  4. if (DBG) Log.e(TAG, "startLeScan: null callback");
  5. return false;
  6. }
  7. synchronized(mLeScanClients) {
  8. if (mLeScanClients.containsKey(callback)) {
  9. if (DBG) Log.e(TAG, "LE Scan has already started");
  10. return false;
  11. }
  12. try {
  13. IBluetoothGatt iGatt = mManagerService.getBluetoothGatt();
  14. if (iGatt == null) {
  15. if (DBG) Log.e("BluetoothAdapterReceiver", "iGatt == null");
  16. // BLE is not supported
  17. return false;
  18. }
  19. UUID uuid = UUID.randomUUID();
  20. GattCallbackWrapper wrapper = new GattCallbackWrapper(this, callback, serviceUuids);
  21. iGatt.registerClient(new ParcelUuid(uuid), wrapper);
  22. if (wrapper.scanStarted()) {
  23. if (DBG) Log.e("BluetoothAdapterReceiver", "wrapper.scanStarted()==true");
  24. mLeScanClients.put(callback, wrapper);
  25. return true;
  26. }
  27. } catch (RemoteException e) {
  28. Log.e(TAG,"",e);
  29. }
  30. }
  31. return false;
  32. }

接着创建了一个GattCallbackWrapper对象,这是个BluetoothAdapter的内部类,主要用于获取回调信息,然后iGatt注册一个client,由BluetoothManagerService中的分析可知,iGatt实际是一个GattService内部类BluetoothGattBinder的对象

  1. public void registerClient(ParcelUuid uuid, IBluetoothGattCallback callback) {
  2. GattService service = getService();
  3. if (service == null) return;
  4. service.registerClient(uuid.getUuid(), callback);
  5. }

这里还是调用GattService的registerClient方法

  1. void registerClient(UUID uuid, IBluetoothGattCallback callback) {
  2. enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
  3. if (DBG) Log.d(TAG, "registerClient() - UUID=" + uuid);
  4. mClientMap.add(uuid, callback);
  5. gattClientRegisterAppNative(uuid.getLeastSignificantBits(),
  6. uuid.getMostSignificantBits());
  7. }

这里面调用了本地方法,对应的JNI文件是Com_android_bluetooth_gatt.cpp,

  1. static void gattClientRegisterAppNative(JNIEnv* env, jobject object,
  2. jlong app_uuid_lsb, jlong app_uuid_msb )
  3. {
  4. bt_uuid_t uuid;
  5. if (!sGattIf) return;
  6. set_uuid(uuid.uu, app_uuid_msb, app_uuid_lsb);
  7. sGattIf->client->register_client(&uuid);
  8. }

分析到这里其实差不多了,因为这里系统会调用MTK提供的蓝牙库来实现搜索,源码我们无法看到。

至此,蓝牙BLE搜索分析完毕!