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



0 0
原创粉丝点击