zoukankan      html  css  js  c++  java
  • [置顶] [Android源码分析]inquiry result引起的上层变化分析

    在上一篇文章中,我们详细分析了android是如何解析蓝牙反馈上来的搜索到的设备信息,本文将会继续分析这些信息到了上层之后是如何处理。

    8inquiry result引起的上层变化

                    我们知道inquiry result引起的上层变化是通过向上层回报device foundsignal来实现的。在jni层收到这个signal之后,会调用java层的onDeviceFound接口,这个地方为什么会调用我就不详细解释了,看了我之前的文章,这个地方应该是轻车熟路了。直接分析onDeviceFound函数:


     private void onDeviceFound(String address, String[] properties) {
            if (properties == null) {
                Log.e(TAG, "ERROR: Remote device properties are null");
                return;
            }
            //把address和对应的properties保存
            addDevice(address, properties);
    }
        private void addDevice(String address, String[] properties) {
            BluetoothDeviceProperties deviceProperties =
                    mBluetoothService.getDeviceProperties();
            //保存address和对应的properties
            deviceProperties.addProperties(address, properties);
            //得到rssi,class,name
            String rssi = deviceProperties.getProperty(address, "RSSI");
            String classValue = deviceProperties.getProperty(address, "Class");
            String name = deviceProperties.getProperty(address, "Name");
            short rssiValue;
            // For incoming connections, we don't get the RSSI value. Use a default of MIN_VALUE.
            // If we accept the pairing, we will automatically show it at the top of the list.
            if (rssi != null) {
                rssiValue = (short)Integer.valueOf(rssi).intValue();
            } else {
            //得到short的最小值
                rssiValue = Short.MIN_VALUE;
            }
            if (classValue != null) {
            //有clasevalue我们会产生action_found的broadcast
                Intent intent = new Intent(BluetoothDevice.ACTION_FOUND);
                intent.putExtra(BluetoothDevice.EXTRA_DEVICE, mAdapter.getRemoteDevice(address));
                intent.putExtra(BluetoothDevice.EXTRA_CLASS,
                        new BluetoothClass(Integer.valueOf(classValue)));
                intent.putExtra(BluetoothDevice.EXTRA_RSSI, rssiValue);
                intent.putExtra(BluetoothDevice.EXTRA_NAME, name);
    
                mContext.sendBroadcast(intent, BLUETOOTH_PERM);
            } else {
            //对于不知道class的设备,我们并不会上报
                log ("ClassValue: " + classValue + " for remote device: " + address + " is null");
            }
    }
    

    很明显,一般而言,会把这些信息通过action_foundbroadcast回报到上层的app,供对应的app使用。我们去settings中看看吧,这个broadcast该如何处理啊,呵呵~~

        在settings中对这个broadcast的处理就只有一个:

    addHandler(BluetoothDevice.ACTION_FOUND, new DeviceFoundHandler());

    所以,我们直接去看DeviceFoundHandler是怎么实现的:

    //device found的处理
        private class DeviceFoundHandler implements Handler {
            public void onReceive(Context context, Intent intent,
                    BluetoothDevice device) {
                    //得到rssi,class,name
                short rssi = intent.getShortExtra(BluetoothDevice.EXTRA_RSSI, Short.MIN_VALUE);
                BluetoothClass btClass = intent.getParcelableExtra(BluetoothDevice.EXTRA_CLASS);
                String name = intent.getStringExtra(BluetoothDevice.EXTRA_NAME);
                // TODO Pick up UUID. They should be available for 2.1 devices.
                // Skip for now, there's a bluez problem and we are not getting uuids even for 2.1.
                    //cachedDevice中是否有对应的设备
                CachedBluetoothDevice cachedDevice = mDeviceManager.findDevice(device);
                if (cachedDevice == null) {
                    //若是没有,则把device加进去
                    cachedDevice = mDeviceManager.addDevice(mLocalAdapter, mProfileManager, device);
                    Log.d(TAG, "DeviceFoundHandler created new CachedBluetoothDevice: "
                            + cachedDevice);
                    // callback to UI to create Preference for new device
                    //创建对应的preference
                    dispatchDeviceAdded(cachedDevice);
                }
                    //设置cached device的属性,并显示出来
                cachedDevice.setRssi(rssi);
                cachedDevice.setBtClass(btClass);
                cachedDevice.setName(name);
                cachedDevice.setVisible(true);
            }
        }
    

    所以,这里就是在ui上显示对应的搜索到的内容了。

    到这里,我们就完成从点击搜索到开始显示第一个搜索到的设备之间的流程的分析。下面就是接着搜索到的设备的显示,这个操作是雷同的,直到搜索结束。底层表示搜索结束的eventinquiry complete,收到这个event表示我们的搜索就结束了,那么上层对这个event是如何处理的呢?我们继续分析。


    9inquiry complete event的处理

                    在分析inquirycomplete之前,我们同样来看一下spec中是如何定义这个event的:



    看起来很简单啊,就返回了一个status的参数,这个参数若是为0就表示success,若是不为0则根据返回值有各种返回错误码。在core spec中类似只返回statusevent还是蛮多的,后面遇到的话我就只提一下,不会再截图了哦,大家可以自己去看具体的spec

        具体的inquiry complete event的处理如下:

    static inline void inquiry_complete_evt(int index, uint8_t status)
    {
            int adapter_type;
            struct btd_adapter *adapter;
    
            //inquiry失败
            if (status) {
                    error("Inquiry Failed with status 0x%02x", status);
                    return;
            }
    
            //找到对应的adapter
            adapter = manager_find_adapter_by_id(index);
            if (!adapter) {
                    error("No matching adapter found");
                    return;
            }
    
            //得到对应的type,le or bredr
            adapter_type = get_adapter_type(index);
    
            if (adapter_type == BR_EDR_LE &&
                                            adapter_has_discov_sessions(adapter)) {
                    //LE我们忽略
                    int err = hciops_start_scanning(index, TIMEOUT_BR_LE_SCAN);
                    if (err < 0)
                            set_state(index, DISCOV_HALTED);
            } else {
                    //bredr设置state位halted
                    set_state(index, DISCOV_HALTED);
            }
    }
    

    9.1 设置stateDISCOV_HALTED

        这个state的设置代码如下:

      switch (dev->discov_state) {
            case DISCOV_HALTED:
                    //得到adapter的state
                    if (adapter_get_state(adapter) == STATE_SUSPENDED)
                            return;
    
                    //resolv name是否enable,并且有discov的session
                    if (is_resolvname_enabled() &&
                                            adapter_has_discov_sessions(adapter))
                            //resolve name
                            adapter_set_state(adapter, STATE_RESOLVNAME);
                    else
                            //否则就直接设为idle了
                            adapter_set_state(adapter, STATE_IDLE);
                    break;
    这里其实就是去进行resolve name:
            case STATE_RESOLVNAME:
                    resolve_names(adapter);
                    break;
    

    9.2 resolve name的分析

    static inline void resolve_names(struct btd_adapter *adapter)
    {
            int err;
    
            //这个必须先设置adapter的state才行
            if (adapter->state != STATE_RESOLVNAME)
                    return;
    
            err = adapter_resolve_names(adapter);
            //err < 0是表示有错误,这里设为idle,没有错误的情况下,这里是不会走到idle的哦
            if (err < 0)
                    adapter_set_state(adapter, STATE_IDLE);
    }
    
    int adapter_resolve_names(struct btd_adapter *adapter)
    {
            struct remote_dev_info *dev, match;
            int err;
    
            /* Do not attempt to resolve more names if on suspended state */
            if (adapter->state == STATE_SUSPENDED)
                    return 0;
    
            memset(&match, 0, sizeof(struct remote_dev_info));
            bacpy(&match.bdaddr, BDADDR_ANY);
            match.name_status = NAME_REQUIRED;
    
            //遍历found device中name_required的设备
            dev = adapter_search_found_devices(adapter, &match);
            if (!dev)
                    return -ENODATA;
    
            /* send at least one request or return failed if the list is empty */
            do {
                    /* flag to indicate the current remote name requested */
                    dev->name_status = NAME_REQUESTED;
    
                    //这个应该就是发送remote name request了
                    err = adapter_ops->resolve_name(adapter->dev_id, &dev->bdaddr);
    
                    //成功直接返回
                    if (!err)
                            break;
    
                    error("Unable to send HCI remote name req: %s (%d)",
                                                    strerror(errno), errno);
    
                    /* if failed, request the next element */
                    /* remove the element from the list */
                    //faile,就直接把这个设备从found device中remove掉
                    adapter_remove_found_device(adapter, &dev->bdaddr);
    
                    /* get the next element */
                    //找下一个name request的设备
                    dev = adapter_search_found_devices(adapter, &match);
            } while (dev);
    
            return err;
    }
    

    Hciopsresolve name的实现:

    static int hciops_resolve_name(int index, bdaddr_t *bdaddr)
    {
            struct dev_info *dev = &devs[index];
            remote_name_req_cp cp;
            char addr[18];
    
            ba2str(bdaddr, addr);
            DBG("hci%d dba %s", index, addr);
    
            memset(&cp, 0, sizeof(cp));
            bacpy(&cp.bdaddr, bdaddr);
            cp.pscan_rep_mode = 0x02;
    
                    //remote name request command的发送
            if (hci_send_cmd(dev->sk, OGF_LINK_CTL, OCF_REMOTE_NAME_REQ,
                                            REMOTE_NAME_REQ_CP_SIZE, &cp) < 0)
                    return -errno;
    
            return 0;
    }
    

    所以,在收到inquiry compleevent之后,我们并没有立即通知上层结束扫描,而是在继续地发送remote name requestcommand去继续得到设备的名字。而此时,上层根本不知道有这些东西在,它还是老老实实地转着圈圈等待搜索的结束。



    若您觉得该文章对您有帮助,请在下面用鼠标轻轻按一下“顶”,哈哈~~·



  • 相关阅读:
    判断用户 是用的电脑还是手机 判断 是安卓还是IOS
    特殊符号
    如何在 ajax 外拿到 ajax 的数据???和ajax的参数
    事件(只有事件 没有其他)
    c3 新特性
    jquery 操作属性[选择器为主]
    按字母排序,sql语句查询法
    ubuntu12.04安装lamp的简单lamp
    Ubuntu 下傻瓜式安装配置lamp环境
    万能HTML编辑框 CuteEditor 使用详解
  • 原文地址:https://www.cnblogs.com/fuhaots2009/p/3473069.html
Copyright © 2011-2022 走看看