Android4.4(MT8685)源码蓝牙解析–BLE搜索

  • Post author:
  • Post category:其他




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搜索分析完毕!




版权声明:本文为u013467735原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。