美文网首页
Android之Bluetooth配对

Android之Bluetooth配对

作者: 锄禾豆 | 来源:发表于2022-02-22 10:01 被阅读0次

    前言

    我们关注蓝牙建立连接的过程
    1.通信的建立一定是异步的过程,自然涉及回调
    2.如果有回调,一定有一处代码进行分发处理
    
    apk -- jni -- hal 
    apk的监听一定来自jni,我们关注jni的注册
    

    解读JniCallbacks

    /*
     * Copyright (C) 2012-2014 The Android Open Source Project
     *
     * Licensed under the Apache License, Version 2.0 (the "License");
     * you may not use this file except in compliance with the License.
     * You may obtain a copy of the License at
     *
     *      http://www.apache.org/licenses/LICENSE-2.0
     *
     * Unless required by applicable law or agreed to in writing, software
     * distributed under the License is distributed on an "AS IS" BASIS,
     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     * See the License for the specific language governing permissions and
     * limitations under the License.
     */
    
    package com.android.bluetooth.btservice;
    
    import android.util.Log;
    
    final class JniCallbacks {
    
        private RemoteDevices mRemoteDevices;
        private AdapterProperties mAdapterProperties;
        private AdapterState mAdapterStateMachine;
        private BondStateMachine mBondStateMachine;
    
        JniCallbacks(AdapterState adapterStateMachine,AdapterProperties adapterProperties) {
            mAdapterStateMachine = adapterStateMachine;
            mAdapterProperties = adapterProperties;
        }
    
        void init(BondStateMachine bondStateMachine, RemoteDevices remoteDevices) {
            mRemoteDevices = remoteDevices;
            mBondStateMachine = bondStateMachine;
        }
    
        void cleanup() {
            mRemoteDevices = null;
            mAdapterProperties = null;
            mAdapterStateMachine = null;
            mBondStateMachine = null;
        }
    
        @Override
        public Object clone() throws CloneNotSupportedException {
            throw new CloneNotSupportedException();
        }
    
        void sspRequestCallback(byte[] address, byte[] name, int cod, int pairingVariant,
                int passkey) {//蓝牙芯片通知配对确认
            mBondStateMachine.sspRequestCallback(address, name, cod, pairingVariant,
                passkey);
        }
        void devicePropertyChangedCallback(byte[] address, int[] types, byte[][] val) {//用于记录蓝牙设备的数据,主要涉及的类为RemoteDevices.DeviceProperties。例如蓝牙地址 蓝牙uuid
            mRemoteDevices.devicePropertyChangedCallback(address, types, val);
        }
    
        void deviceFoundCallback(byte[] address) {//扫描设备的回调
            mRemoteDevices.deviceFoundCallback(address);
        }
    
        void pinRequestCallback(byte[] address, byte[] name, int cod, boolean min16Digits) {
            mBondStateMachine.pinRequestCallback(address, name, cod, min16Digits);
        }
    
        void bondStateChangeCallback(int status, byte[] address, int newState) {//配对状态更改
            mBondStateMachine.bondStateChangeCallback(status, address, newState);
        }
    
        void aclStateChangeCallback(int status, byte[] address, int newState) {//配置的设备状态更改,例如远程设备关闭了蓝牙,会通知出来,具体的时间是多久?
            mRemoteDevices.aclStateChangeCallback(status, address, newState);
        }
    
        void stateChangeCallback(int status) {//本设备的蓝牙打开和关闭通知
            mAdapterStateMachine.stateChangeCallback(status);
        }
    
        void discoveryStateChangeCallback(int state) {//扫描开始和扫描结束,开始是1 结束是0
            mAdapterProperties.discoveryStateChangeCallback(state);
        }
    
        void adapterPropertyChangedCallback(int[] types, byte[][] val) {//不是很清楚用来做什么
            mAdapterProperties.adapterPropertyChangedCallback(types, val);
        }
    
    }
    
    

    场景:配对建立连接过程

    设备端:
    UI端点击配对 -- 系统服务 -- Bluetooth.apk -- jni -- hal ---->  接受方
    
    
    接受方:
    接受方 -- 发送pin指令进行配对 --> 设备端
    
    设备端
    设备端收到指令hal -- jni -- Bluetooth.apk -- UI端接受点击确认
    JniCallbacks.sspRequestCallback 接收到回调之后,进行事件分发
    

    案例:蓝牙配对连接
    注:
    配对的前提,设备已知,代码分析要从设备信息出发

    1.UI调用方法
    BluetoothDevice.createBond

        public boolean createBond() {
            ······
            try {
                return sService.createBond(this, TRANSPORT_AUTO);//sService为Bluetooth.apk中的服务
            } catch (RemoteException e) {Log.e(TAG, "", e);}
            return false;
        }
        注:
        sService的获取来自系统服务BluetoothManagerService
    

    2.蓝牙app及jni
    1)AdapterService.AdapterServiceBinder.createBond

    AdapterService.AdapterServiceBinder.createBond --> AdapterService.createBond
    
         boolean createBond(BluetoothDevice device, int transport, OobData oobData) {
            ······
            // Pairing is unreliable while scanning, so cancel discovery
            // Note, remove this when native stack improves
            cancelDiscoveryNative();//注意配对的时候需要取消扫描
    
            Message msg = mBondStateMachine.obtainMessage(BondStateMachine.CREATE_BOND);
            msg.obj = device;
            msg.arg1 = transport;
    
            if (oobData != null) {
                Bundle oobDataBundle = new Bundle();
                oobDataBundle.putParcelable(BondStateMachine.OOBDATA, oobData);
                msg.setData(oobDataBundle);
            }
            mBondStateMachine.sendMessage(msg);//mBondStateMachine为状态机。要熟悉状态机的运用
            return true;
        }
    

    2)BondStateMachine.StableState接受来自消息CREATE_BOND

    mBondStateMachine的默认状态为mStableState
        private BondStateMachine(AdapterService service,
                AdapterProperties prop, RemoteDevices remoteDevices) {
            super("BondStateMachine:");
            addState(mStableState);
            addState(mPendingCommandState);
            ······
            setInitialState(mStableState);
        }
        
        private class StableState extends State {
            ······
            @Override
            public boolean processMessage(Message msg) {
                ·······
                switch(msg.what) {
                  ·······
                  case CREATE_BOND:
                      OobData oobData = null;
                      if (msg.getData() != null)
                          oobData = msg.getData().getParcelable(OOBDATA);
    
                      createBond(dev, msg.arg1, oobData, true);
                      break;
                  ······
                }
                ······
            }
        }
        
        private boolean createBond(BluetoothDevice dev, int transport, OobData oobData,
                                   boolean transition) {
            if (dev.getBondState() == BluetoothDevice.BOND_NONE) {
                infoLog("Bond address is:" + dev);
                byte[] addr = Utils.getBytesFromAddress(dev.getAddress());
                boolean result;
                if (oobData != null) {
                    result = mAdapterService.createBondOutOfBandNative(addr, transport, oobData);
                } else {
                    result = mAdapterService.createBondNative(addr, transport);//调用jni进行通信
                }
    
                if (!result) {
                    sendIntent(dev, BluetoothDevice.BOND_NONE,
                               BluetoothDevice.UNBOND_REASON_REMOVED);
                    return false;
                } else if (transition) {
                    transitionTo(mPendingCommandState);//同步把状态切换成带处理状态(mPendingCommandState)
                }
                return true;
            }
            return false;
        }
    

    3)AdapterService.createBondNative

    /*package*/ native boolean createBondNative(byte[] address, int transport);
    
    com_android_bluetooth_btservice_AdapterService.cpp
    static jboolean createBondNative(JNIEnv* env, jobject obj, jbyteArray address, jint transport) {
        ALOGV("%s:",__FUNCTION__);
    
        jbyte *addr;
        jboolean result = JNI_FALSE;
    
        if (!sBluetoothInterface) return result;
    
        addr = env->GetByteArrayElements(address, NULL);
        if (addr == NULL) {
            jniThrowIOException(env, EINVAL);
            return result;
        }
    
        int ret = sBluetoothInterface->create_bond((bt_bdaddr_t *)addr, transport);//通过jni调进蓝牙协议栈中
        env->ReleaseByteArrayElements(address, addr, 0);
        result = (ret == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
    
        return result;
    }
    
    这里是没有对应的回调传给jni,那自然是jni主动被调用,这样才能把配对的状态告知app
    

    3.蓝牙协议栈--省略

    4.Bluetooth.apk接收回调
    1)关注JniCallbacks接收回调的地方

        void bondStateChangeCallback(int status, byte[] address, int newState) {//配对状态更改
            mBondStateMachine.bondStateChangeCallback(status, address, newState);
        }
        
        void sspRequestCallback(byte[] address, byte[] name, int cod, int pairingVariant,
                int passkey) {//蓝牙芯片通知配对确认
            mBondStateMachine.sspRequestCallback(address, name, cod, pairingVariant,
                passkey);
        }
    

    2)BondStateMachine
    a)关注配对状态的回调

        void bondStateChangeCallback(int status, byte[] address, int newState) {
            ······
            Message msg = obtainMessage(BONDING_STATE_CHANGE);//状态机目前处于mPendingCommandState
            msg.obj = device;
    
            if (newState == BOND_STATE_BONDED)
                msg.arg1 = BluetoothDevice.BOND_BONDED;
            else if (newState == BOND_STATE_BONDING)
                msg.arg1 = BluetoothDevice.BOND_BONDING;
            else
                msg.arg1 = BluetoothDevice.BOND_NONE;
            msg.arg2 = status;
    
            sendMessage(msg);
        }
        
        private class PendingCommandState extends State {
            ······
            @Override
            public boolean processMessage(Message msg) {
                ······
                switch (msg.what) {
                    ······
                    case BONDING_STATE_CHANGE:
                        int newState = msg.arg1;
                        int reason = getUnbondReasonFromHALCode(msg.arg2);
                        sendIntent(dev, newState, reason);//发送广播出去
                        ······
                        break;
                    ······
                }
                ······
            }
        }
        
        private void sendIntent(BluetoothDevice device, int newState, int reason) {
            DeviceProperties devProp = mRemoteDevices.getDeviceProperties(device);
            int oldState = BluetoothDevice.BOND_NONE;
            if (devProp != null) {
                oldState = devProp.getBondState();
            }
            if (oldState == newState) return;
            mAdapterProperties.onBondStateChanged(device, newState);
    
            Intent intent = new Intent(BluetoothDevice.ACTION_BOND_STATE_CHANGED);//关注广播
            intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device);
            intent.putExtra(BluetoothDevice.EXTRA_BOND_STATE, newState);
            intent.putExtra(BluetoothDevice.EXTRA_PREVIOUS_BOND_STATE, oldState);
            if (newState == BluetoothDevice.BOND_NONE)
                intent.putExtra(BluetoothDevice.EXTRA_REASON, reason);
            mAdapterService.sendBroadcastAsUser(intent, UserHandle.ALL,
                    AdapterService.BLUETOOTH_PERM);
            infoLog("Bond State Change Intent:" + device + " OldState: " + oldState
                    + " NewState: " + newState);
        }
        
        总结:
        针对配对的状态,其他应用关注广播:BluetoothDevice.ACTION_BOND_STATE_CHANGED
    

    b)关注配置过程确认pin码

        void sspRequestCallback(byte[] address, byte[] name, int cod, int pairingVariant,
                int passkey) {
            ······
            Message msg = obtainMessage(SSP_REQUEST);//状态机目前处于mPendingCommandState
            msg.obj = device;
            if(displayPasskey)
                msg.arg1 = passkey;
            msg.arg2 = variant;
            sendMessage(msg);
        }
        
        private class PendingCommandState extends State {
            ······
            @Override
            public boolean processMessage(Message msg) {
                ······
                switch (msg.what) {
                    ······
                    case SSP_REQUEST:
                        int passkey = msg.arg1;
                        int variant = msg.arg2;
                        sendDisplayPinIntent(devProp.getAddress(), passkey, variant);//发送广播
                        break;
                    ······
                }
                ······
            }
        }
        
        private void sendDisplayPinIntent(byte[] address, int pin, int variant) {
            Intent intent = new Intent(BluetoothDevice.ACTION_PAIRING_REQUEST);//关注此广播
            intent.putExtra(BluetoothDevice.EXTRA_DEVICE, mRemoteDevices.getDevice(address));
            if (pin != 0) {
                intent.putExtra(BluetoothDevice.EXTRA_PAIRING_KEY, pin);
            }
            intent.putExtra(BluetoothDevice.EXTRA_PAIRING_VARIANT, variant);
            intent.setFlags(Intent.FLAG_RECEIVER_FOREGROUND);
            mAdapterService.sendOrderedBroadcast(intent, mAdapterService.BLUETOOTH_ADMIN_PERM);
        }
        
        总结:
        针对配对过程获取pin码,其他应用关注广播:BluetoothDevice.ACTION_PAIRING_REQUEST
        
    

    参考学习

    https://www.jianshu.com/p/a150d55e29ca
    https://blog.csdn.net/WHB20081815/article/details/88653177
    

    相关文章

      网友评论

          本文标题:Android之Bluetooth配对

          本文链接:https://www.haomeiwen.com/subject/hqgqkrtx.html