原文網址:http://blog.csdn.net/u013467735/article/details/41962075java
BLE:全稱爲Bluetooth Low Energy。藍牙規範4.0最重要的一個特性就是低功耗。BLE使得藍牙設備可經過一粒鈕釦電池供電以維持續工做數年之久。很明顯,BLE使得藍牙設備在鐘錶、遠程控制、醫療保健及運動感應器等市場具備極光明的應用場景。android
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方法。app
- public boolean startLeScan(LeScanCallback callback) {
- return startLeScan(null, callback);
- }
這裏調用了一個同名的方法,dom
- 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");
-
- 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對象。ide
接下來分析下mManagerService,它是一個IBluetoothManager對象,IBluetoothManager是一個AIDL,能夠實現跨進程通訊,其在源碼中的路徑爲:/alps/frameworks/base/core/java/android/bluetooth/IBluetoothManager.aidl。下面來看看mManagerService的實例化,oop
- 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構造方法的參數傳給了它,來看看這個參數究竟是什麼?ui
- 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中this
- <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對象。spa
如今回到BluetoothAdapter的startLeScan方法中,
- IBluetoothGatt iGatt = mManagerService.getBluetoothGatt();
這裏實際就是調用BluetoothManagerService中的getBluetoothGatt方法了,咱們進去看看
- public IBluetoothGatt getBluetoothGatt() {
-
- 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);
- }
-
- if(FeatureOption.MTK_MOBILE_MANAGEMENT) {
- checkEnablePermission();
- return true;
- }
-
- synchronized(mReceiver) {
- mQuietEnableExternal = false;
- mEnableExternal = true;
-
- 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");
-
- 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()) {
-
-
-
- mConnection.setGetNameAddressOnly(false);
-
- try {
- mBluetooth.registerCallback(mBluetoothCallback);
- } catch (RemoteException re) {
- Log.e(TAG, "Unable to register BluetoothCallback",re);
- }
-
- sendBluetoothServiceUpCallback();
- }
-
-
- 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);
-
- 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 connected: " + className.getClassName());
- return;
- }
- msg.obj = service;
- mHandler.sendMessage(msg);
- }
-
- public void onServiceDisconnected(ComponentName className) {
-
- 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;
- }
-
-
- 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()) {
-
- Message getMsg = mHandler.obtainMessage(MESSAGE_GET_NAME_AND_ADDRESS);
- mHandler.sendMessage(getMsg);
- if (!mEnable) return;
- }
-
- mConnection.setGetNameAddressOnly(false);
-
- try {
- mBluetooth.registerCallback(mBluetoothCallback);
- } catch (RemoteException re) {
- Log.e(TAG, "Unable to register BluetoothCallback",re);
- }
-
- sendBluetoothServiceUpCallback();
-
-
- 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");
-
- 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搜索分析完畢!