Android 4.4 Bluetooth学习之一

限于喜欢 提交于 2019-12-02 18:01:40

一、写在前面的话
近来由于项目需求需要搞蓝牙这一块,之前在上家公司带LC(本地连接)组时也做过一点蓝牙,在Android系统中也解过一些bug,但是不够系统,现在正好比较系统的学习蓝牙。

二、蓝牙的协议框架
                     A2dp  Handset  opp Hid Health Pan Map  Dun...
                                       |  |     |...
                                  CORE Stack Specification
                                          |
                                 Host Controller Interface
                                          |
                                        chip

三、Android 4.4(Kitkat)上蓝牙的启动流程

1.服务启动
系统启动时在SystemServer中注册蓝牙服务管理BluetoothManagerService服务:

            if (SystemProperties.get("ro.kernel.qemu").equals("1")) {
                Slog.i(TAG, "No Bluetooh Service (emulator)");
            } else if (factoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL) {
                Slog.i(TAG, "No Bluetooth Service (factory test)");
            } else if (!context.getPackageManager().hasSystemFeature
                       (PackageManager.FEATURE_BLUETOOTH)) {
                Slog.i(TAG, "No Bluetooth Service (Bluetooth Hardware Not Present)");
            } else if (disableBluetooth) {
                Slog.i(TAG, "Bluetooth Service disabled by config");
            } else {
                Slog.i(TAG, "Bluetooth Manager Service");
                bluetooth = new BluetoothManagerService(context);
                ServiceManager.addService(BluetoothAdapter.BLUETOOTH_MANAGER_SERVICE, bluetooth);
            }

其它进程通过binder机制调用该服务,该服务属于综合服务管理类,包括AdapterService的启动、蓝牙适配器Adapter的管理等。

2.蓝牙启动模式

在4.4上蓝牙的启动模式分两种:QuietEnableMode和普通从“设置”里打开两种方式,前一中方式主要是为了NFC的Handover功能——在传递媒体大文件时nfc会打开蓝牙传送。

3.蓝牙关键服务启动和回调处理

下面就以在“设置”中打开为例描述下蓝牙的启动流程:

1)蓝牙所有的profiles位于上层代码中/packages/apps/Bluetooth目录下,常用的几个profiles包括A2dp、HeadSet、Opp、Hid、Pan等,并且Android 4.4上蓝牙协议栈采用的是BRCM和Google共同开发的bluedroid;

2)启动流程涉及代码结构Settings -> Bluetooth -> framework -> bluedroid -> hci -> chip,启动过程是先启动AdapterService并初始化bluedroid,然后启动所有的profile service(A2dpService、HeadsetService等),
成功加载所支持的profiles后使能bluedroid给蓝牙上电,蓝牙上电成功后回bluedroid回调类com_android_bluetooth_btservice_AdapterService.cpp的接口static void adapter_state_change_callback(bt_state_t status),通过JNI回调通知AdapterStateMachine更新Adapter状态,并且通知注册到AdapterService上回调:
void updateAdapterState(int prevState, int newState){
        if (mCallbacks !=null) {
            int n=mCallbacks.beginBroadcast();
            Log.d(TAG,"Broadcasting updateAdapterState() to " + n + " receivers.");
            for (int i=0; i <n;i++) {
                try {
                    mCallbacks.getBroadcastItem(i).onBluetoothStateChange(prevState,newState);
                }  catch (RemoteException e) {
                    Log.e(TAG, "Unable to call onBluetoothStateChange() on callback #" + i, e);
                }
            }
            mCallbacks.finishBroadcast();
        }
    }

mCallbacks该回调是BluetoothManagerService在成功bind到AdapterService时注册的回调mBluetoothCallback:
case MESSAGE_BLUETOOTH_SERVICE_CONNECTED:
                {
                    if (DBG) Log.d(TAG,"MESSAGE_BLUETOOTH_SERVICE_CONNECTED: " + msg.arg1);

                    mIsBluetoothServiceConnected = true;

                    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); //注册Adapter状态变更的callback
                        } catch (RemoteException re) {
                            Log.e(TAG, "Unable to register BluetoothCallback",re);
                        }
...

而BluetoothManagerService注册该callback的目的是通知系统所有支持的profiles蓝牙的开启状态,用于更新每个profile和对应profile服务的bind,如通知BluetoothHeadset bind到HeadsetService上,通过binder机制获取HeadsetService的句柄进行相关操作:
BluetoothHeadset.java
final private IBluetoothStateChangeCallback mBluetoothStateChangeCallback =
            new IBluetoothStateChangeCallback.Stub() {
                public void onBluetoothStateChange(boolean up) {
                    if (DBG) Log.d(TAG, "onBluetoothStateChange: up=" + up);
                    if (!up) {
                        if (VDBG) Log.d(TAG,"Unbinding service...");
                        synchronized (mConnection) {
                            try {
                                mService = null;
                                mContext.unbindService(mConnection);
                            } catch (Exception re) {
                                Log.e(TAG,"",re);
                            }
                        }
                    } else {
                        synchronized (mConnection) {
                            try {
                                if (mService == null) {
                                    if (VDBG) Log.d(TAG,"Binding service...");
                                    doBind();//绑定到HeadsetService
                                }
                            } catch (Exception re) {
                                Log.e(TAG,"",re);
                            }
                        }
                    }
                }
        };

那么既然profile要去bind到对应的service上,这些profile对应的Sercice又是什么时候注册的呢?
这个很关键,其实在我们使能蓝牙过程中,AdapaterStateMachine处于OffState状态,处理 msg.what == USER_TURN_ON
case USER_TURN_ON:
                   if (DBG) Log.d(TAG,"CURRENT_STATE=OFF, MESSAGE = USER_TURN_ON");
                   notifyAdapterStateChange(BluetoothAdapter.STATE_TURNING_ON);
                   mPendingCommandState.setTurningOn(true);
                   transitionTo(mPendingCommandState);
                   sendMessageDelayed(START_TIMEOUT, START_TIMEOUT_DELAY);
                   adapterService.processStart();//启动系统支持的所有profiles的services

对应调用AdapterService的接口:

    void processStart() {
        if (DBG) debugLog("processStart()");
        Class[] supportedProfileServices = Config.getSupportedProfiles();
        //Initialize data objects
        for (int i=0; i < supportedProfileServices.length;i++) {
            mProfileServicesState.put(supportedProfileServices[i].getName(),BluetoothAdapter.STATE_OFF);
        }
        mRemoteDevices = new RemoteDevices(mPowerManager, this);
        mAdapterProperties.init(mRemoteDevices);

        if (DBG) {debugLog("processStart(): Make Bond State Machine");}
        mBondStateMachine = BondStateMachine.make(this, mAdapterProperties, mRemoteDevices);

        mJniCallbacks.init(mBondStateMachine,mRemoteDevices);

        //FIXME: Set static instance here???
        setAdapterService(this);

        //Start profile services
        if (!mProfilesStarted && supportedProfileServices.length >0) {
            //Startup all profile services
            setProfileServiceState(supportedProfileServices,BluetoothAdapter.STATE_ON);
        }else {
            if (DBG) {debugLog("processStart(): Profile Services alreay started");}
            mAdapterStateMachine.sendMessage(mAdapterStateMachine.obtainMessage(AdapterState.STARTED));
        }
    }

以上就是profiles对应服务的注册。

3)BluetoothManagerService中处理两个callback:一个是来自BluetoothAdapter实例化时注册的回调mManagerCallback并添加到BluetoothManagerService类private final RemoteCallbackList<IBluetoothManagerCallback> mCallbacks中,该callback主要用于当BluetoothManagerService成功bind到AdapterService时BluetoothDevice获取AdapterService的句柄(BluetoothDevice获取的过程也是向BluetoothAdapter注册回调的机制);另一个来自于各个profile实现类如BluetoothHeadset注册的callback添加到BluetoothManagerService类private final RemoteCallbackList<IBluetoothStateChangeCallback> mStateChangeCallbacks中,用户通知每个profile adapter状态的变化如TURNING_ON、TURN_ON、TURNING_OFF、TURN_OFF等;


4)Bluetooth中采用的回调机的地方太多,从Settings中显示部分就多处采用回调来更新UI显示,如BluetoothSettings父类DeviceListPreferenceFragment在onResume()时向LocalBluetoothEventManager中注册callback:
@Override
    public void onResume() {
        super.onResume();
        if (mLocalManager == null) return;

        mLocalManager.setForegroundActivity(getActivity());
        mLocalManager.getEventManager().registerCallback(this);//注册回调

        updateProgressUi(mLocalAdapter.isDiscovering());
    }

不仅如此,在JNI和bluedroid的通信中也采用的时回调机制,如com_android_bluetooth_btservice_AdapterService.cpp类在初始化bluedroid时:
static bool initNative(JNIEnv* env, jobject obj) {
    ALOGV("%s:",__FUNCTION__);

    sJniCallbacksObj = env->NewGlobalRef(env->GetObjectField(obj, sJniCallbacksField));

    if (sBluetoothInterface) {
        int ret = sBluetoothInterface->init(&sBluetoothCallbacks);//初始化回调接口
        if (ret != BT_STATUS_SUCCESS) {
            ALOGE("Error while setting the callbacks \n");
            sBluetoothInterface = NULL;
            return JNI_FALSE;
        }
        if ( (sBluetoothSocketInterface = (btsock_interface_t *)
                  sBluetoothInterface->get_profile_interface(BT_PROFILE_SOCKETS_ID)) == NULL) {
                ALOGE("Error getting socket interface");
        }

        if ( (sBluetoothMceInterface = (btmce_interface_t *)
                  sBluetoothInterface->get_profile_interface(BT_PROFILE_MAP_CLIENT_ID)) == NULL) {
                ALOGE("Error getting mapclient interface");
        } else {
            if ( (sBluetoothMceInterface->init(&sBluetoothMceCallbacks)) != BT_STATUS_SUCCESS) {
                ALOGE("Failed to initialize Bluetooth MCE");
                sBluetoothMceInterface = NULL;
            }
        }

        return JNI_TRUE;
    }
    return JNI_FALSE;
}

初次看code时可能会感觉很绕,怎么会那么多回调呀?习惯了就好,这貌似时BRCM代码风格。

4.蓝牙关键类管理流程

                                                    —— A2dpProfile      < ———— >          BluetoothA2dp       <————>       A2dpService     <—————>    A2dpStateMachine   <————>  
                                                   |        (注册Listener监听profile的连接状态)          (bind到A2dpService)             (采用状态机管理)                 (jni机制)
                                                     com_android_bluetooth_a2dp <————> blueDroid <————> HCI
                                                   |...
                      —— LocalBluetoothProfile <——>|
                     |    (管理所有的profiles)      |
                     |                              —— HidProfile      < ———— >          BluetoothHid       <————>       HidService   <—————> com_android_bluetooth_hid <————> blueDroid <————> HCI
                     |                                    (注册Listener监听profile的连接状态)         (bind到HidService)               (jni机制)
                     |                                                                                                                                              —— AdapterStateMachine
LocalBluetoothManager|—— LocalBluetoothApater      <——>     BluetoothAdapter   <————>   BluetoothManagerService <————>          AdapterService           < ————> |                 均通过JniCallback回调
(上层本地蓝牙管理类)|      (本地Adpater)     (调用远端的实现)                (开启/关闭)   (蓝牙远端服务管理类)          (负责开启/关闭及其它profile服务的管理)        —— BondStateMachine
                     |
                     |
                      —— BluetoothEventManager               <————>                 CachedBluetoothDeviceManager
                                            (注册广播监听蓝牙状态变更、蓝牙设备状态)


四、小结
本来想采用UML画出流程图以备后查,无奈时间紧张、手头没有环境,唉做项目的人真心悲催啊!待续...

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!