android Bluetooth setScanMode()流程分析

/ android / 没有评论 / 859浏览

用到的代码文件

frameworks/base/core/java/:
android/bluetooth/BluetoothAdapter.java

packages/apps/Bluetooth/src/:
com/android/bluetooth/btservice/AdapterService.java
com/android/bluetooth/btservice/AdapterProperties.java

packages/apps/Bluetooth/jni/:
com_android_bluetooth_btservice_AdapterService.cpp

hardware/libhardware/include/:
hardware/bluetooth.h

system/bt/btif/src/:
bluetooth.c

代码执行流程图

bluetooth setScanMode

查看原图

蓝牙setScanMode流程分析

下面的代码是以android N(api 24)为基础。

本文基于高通(Qualcomm)平台基线。

下面进入BluetoothAdapter类的setScanMode()方法。

public boolean setScanMode(@ScanMode int mode, int duration) {
    if (getState() != STATE_ON) return false;
    try {
        mServiceLock.readLock().lock();
        if (mService != null) 
            return mService.setScanMode(mode, duration);
    } catch (RemoteException e) {
        Log.e(TAG, "", e);
    } finally {
        mServiceLock.readLock().unlock();
    }
    return false;
}

下面进入AdapterServerBinder类的setScanMode()方法。 AdapterServerBinder类是定义在AdapterService类中的内部类。

public boolean setScanMode(int mode, int duration) {
    Log.i("AdapterServiceBinder", "setScanMode()");
    if (!Utils.checkCaller()) {
        Log.w(TAG, "setScanMode()"
        + " - Not allowed for non-active user");
        return false;
    }

    //do not allow setmode when multicast is active
    A2dpService a2dpService = A2dpService.getA2dpService();
    if (a2dpService != null &&
            a2dpService.isMulticastOngoing(null)) {
        Log.w(TAG,"A2dp Multicast is Ongoing, "
            + "ignore setmode " + mode);
        mScanmode = mode;
        return false;
    }

    AdapterService service = getService();
    if (service == null) return false;
    // when scan mode is not changed during multicast, 
    // reset it last to scan mode, as we will set mode
    // to none for multicast
    mScanmode = service.getScanMode();
    Log.i(TAG,"setScanMode: prev mode: " 
        + mScanmode + " new mode: " + mode);
    return service.setScanMode(mode, duration);
}

下面进入AdapterService类的setScanMode()方法。

boolean setScanMode(int mode, int duration) {
     Log.d(TAG,"setScanMode()");
    enforceCallingOrSelfPermission(BLUETOOTH_PERM, 
        "Need BLUETOOTH permission");

    //先设置超时时间
    boolean setDiscoverableResult=
        setDiscoverableTimeout(duration);
     Log.d(TAG,"setDiscoverableResult: "
        +setDiscoverableResult);
    int newMode = convertScanModeToHal(mode);
    return mAdapterProperties.setScanMode(newMode);
}

下面进入AdapterService类的setDiscoverableTimeout()方法。

 boolean setDiscoverableTimeout(int timeout) {
     Log.d(TAG,"setDiscoverableTimeout() timeout: "
        + timeout);
    enforceCallingOrSelfPermission(BLUETOOTH_PERM, 
        "Need BLUETOOTH permission");

    return mAdapterProperties
        .setDiscoverableTimeout(timeout);
}

下面进入AdapterProperties类的setDiscoverableTimeout()方法。

boolean setDiscoverableTimeout(int timeout) {
    Log.d(TAG,"setDiscoverableTimeout()");
    synchronized (mObject) {
        return mService.setAdapterPropertyNative(
                AbstractionLayer
                  .BT_PROPERTY_ADAPTER_DISCOVERABLE_TIMEOUT,
                Utils.intToByteArray(timeout));
    }
}

下面进入AdapterService类的setAdapterPropertyNative()方法。

native boolean setAdapterPropertyNative(int type, byte[] val);

进入com_android_bluetooth_btservice_AdapterService.cpp文件的setAdapterPropertyNative()方法。

static const bt_interface_t *sBluetoothInterface = NULL;

static jboolean setAdapterPropertyNative(JNIEnv *env, 
    jobject obj, jint type, jbyteArray value) {
    ALOGE("%s:",__FUNCTION__);
    ALOGE("method %s , type %d ",
        "setAdapterPropertyNative()",type);

    jbyte *val;
    jboolean result = JNI_FALSE;
    if (!sBluetoothInterface) return result;

    val = env->GetByteArrayElements(value, NULL);

    bt_property_t prop;
    prop.type = (bt_property_type_t) type;
    prop.len = env->GetArrayLength(value);
    prop.val = val;

    int ret = sBluetoothInterface->set_adapter_property(&prop);
    env->ReleaseByteArrayElements(value, val, 0);
    result = (ret == BT_STATUS_SUCCESS) ? 
              JNI_TRUE : JNI_FALSE;

    return result;
}

结构体bt_property_t定义在Bluetooth.h中。

/** Bluetooth Adapter Property data structure */
typedef struct
{
    bt_property_type_t type;
    int len;
    void *val;
} bt_property_t;

/* Bluetooth Adapter and Remote Device property types */
bt_property_type_t是一个枚举型的数据结构,也定义在Bluetooth.h中。这个很庞大就不列出来了。

/** Represents the standard Bluetooth DM interface. */
结构体bt_interface_t也定义在Bluetooth.h中。这个结构体很庞大就不列出来了。

下面进入bluetooth.c的set_adapter_property()方法。

static int set_adapter_property(const bt_property_t *property)
{
    LOG_ERROR(LOG_TAG, "method: %s ", __func__);
    /* sanity check */
    if (interface_ready() == FALSE)
        return BT_STATUS_NOT_READY;
    /*进入这里*/
    return btif_set_adapter_property(property);
}

下面进入btif_core.c文件的btif_set_adapter_property()方法中。

bt_status_t btif_set_adapter_property(
    const bt_property_t *property)
{
    LOG_ERROR(LOG_TAG, "method %s", 
        "btif_set_adapter_property()");
    btif_storage_req_t req;
    bt_status_t status = BT_STATUS_SUCCESS;
    /* default */
    int storage_req_id = BTIF_CORE_STORAGE_NOTIFY_STATUS;
    char bd_name[BTM_MAX_LOC_BD_NAME_LEN +1];
    UINT16  name_len = 0;
    
    //E bt_btif_core: btif_set_adapter_property type: 
    //    9, len 4, 0x9eaa83f0
    LOG_ERROR(LOG_TAG, "btif_set_adapter_property type: %d, 
                      len %d, %p",
                      property->type, 
                      property->len, 
                      property->val);

    if (!btif_is_enabled()){
        LOG_ERROR(LOG_TAG, "BT_STATUS_NOT_READY");
        return BT_STATUS_NOT_READY;
    }

    //下面case中的常量定义在hardware/bluetooth.h中
    switch(property->type)
    {
        case BT_PROPERTY_BDNAME:
            {
                name_len = property->len > 
                    BTM_MAX_LOC_BD_NAME_LEN ? 
                        BTM_MAX_LOC_BD_NAME_LEN:property->len;
                memcpy(bd_name,property->val, name_len);
                bd_name[name_len] = '\0';

                BTIF_TRACE_EVENT("set property name : %s", 
                    (char *)bd_name);

                BTA_DmSetDeviceName((char *)bd_name);

                storage_req_id = BTIF_CORE_STORAGE_ADAPTER_WRITE;
            }
            break;

        case BT_PROPERTY_ADAPTER_SCAN_MODE:
            {
                LOG_ERROR(LOG_TAG,
                     "case: BT_PROPERTY_ADAPTER_SCAN_MODE");
                bt_scan_mode_t mode = 
                    *(bt_scan_mode_t*)property->val;
                tBTA_DM_DISC disc_mode;
                tBTA_DM_CONN conn_mode;

                switch(mode)
                {
                    case BT_SCAN_MODE_NONE:
                        disc_mode = BTA_DM_NON_DISC;
                        conn_mode = BTA_DM_NON_CONN;
                        break;

                    case BT_SCAN_MODE_CONNECTABLE:
                        disc_mode = BTA_DM_NON_DISC;
                        conn_mode = BTA_DM_CONN;
                        break;

                    case BT_SCAN_MODE_CONNECTABLE_DISCOVERABLE:
                        disc_mode = BTA_DM_GENERAL_DISC;
                        conn_mode = BTA_DM_CONN;
                        break;

                    default:
                        BTIF_TRACE_ERROR(
                            "invalid scan mode (0x%x)", mode);
                        return BT_STATUS_PARM_INVALID;
                }

                BTIF_TRACE_EVENT(
                    "set property scan mode : %x", mode);

                BTA_DmSetVisibility(disc_mode, conn_mode, 
                    BTA_DM_IGNORE, BTA_DM_IGNORE);

                storage_req_id = BTIF_CORE_STORAGE_ADAPTER_WRITE;
            }
            break;
         /*
          * 这次先进入这里
          */
        case BT_PROPERTY_ADAPTER_DISCOVERY_TIMEOUT:
            {
                LOG_ERROR(LOG_TAG, 
                    "case: BT_PROPERTY_ADAPTER_DISCOVERY_TIMEOUT");
                /* Nothing to do beside store the value 
                   in NV.  Java will change the SCAN_MODE property 
                   after setting timeout,if required */
                /*/system/bt/btif/include/btif_common.h*/
                storage_req_id = BTIF_CORE_STORAGE_ADAPTER_WRITE;
                //E bt_btif_core: storage_req_id: 2
                LOG_ERROR(LOG_TAG, "storage_req_id: %d",storage_req_id);
            }
            break;
        case BT_PROPERTY_BDADDR:
        case BT_PROPERTY_UUIDS:
        case BT_PROPERTY_ADAPTER_BONDED_DEVICES:
        case BT_PROPERTY_REMOTE_FRIENDLY_NAME:
            /* no write support through HAL, these properties are 
            only populated from BTA events */
            status = BT_STATUS_FAIL;
            break;
        default:
            BTIF_TRACE_ERROR(
                "btif_get_adapter_property : invalid type %d",
            property->type);
            status = BT_STATUS_FAIL;
            break;
    }

    //进入这里
    if (storage_req_id != BTIF_CORE_STORAGE_NO_ACTION)
    {
        /*
         * memset
         * void *memset (void *__s, int __c, size_t __n)
         * 将s的n个字节设置为c。
         *
         * memcpy
         * 将property的sizeof(bt_property_t)个字节拷贝到src中。
         */
        /* pass on to storage for updating local database */
        memset(&(req.write_req.bd_addr), 
                0, sizeof(bt_bdaddr_t));
        memcpy(&(req.write_req.prop), 
                property, sizeof(bt_property_t));

        return btif_transfer_context(execute_storage_request,
                    storage_req_id,
                    (char*)&req,
                    sizeof(btif_storage_req_t)+property->len,
                    btif_in_storage_request_copy_cb);
    }

    return status;

}

下面进入btif_core.c文件的btif_transfer_context()方法中。

bt_status_t btif_transfer_context (tBTIF_CBACK *p_cback, 
    UINT16 event, char* p_params, int param_len,
     tBTIF_COPY_CBACK *p_copy_cback)
{
    LOG_ERROR(LOG_TAG, "method: btif_transfer_context()");
    //内存分配构建一个与HAL层交互的消息对象
    tBTIF_CONTEXT_SWITCH_CBACK *p_msg =
        (tBTIF_CONTEXT_SWITCH_CBACK *)osi_malloc(
            sizeof(tBTIF_CONTEXT_SWITCH_CBACK) + param_len);

    //E bt_btif_core: btif_transfer_context event 2, len 24
    LOG_ERROR(LOG_TAG, "btif_transfer_context event %d, 
        len %d", event, param_len);

    /* allocate and send message that will be 
    executed in btif context */
    /* internal event */
    p_msg->hdr.event = BT_EVT_CONTEXT_SWITCH_EVT; 
    p_msg->p_cb = p_cback;
    /* callback event */
    p_msg->event = event;                         
    /* check if caller has provided a copy 
      callback to do the deep copy */
    if (p_copy_cback) {
        LOG_ERROR(LOG_TAG, "p_copy_cback true");
        /*将原来的 Request 深拷贝到一个新的 Request 中去*/
        p_copy_cback(event, p_msg->p_param, p_params);
    } else if (p_params) {
        LOG_ERROR(LOG_TAG, "p_params true");
        /* callback parameter data */
        memcpy(p_msg->p_param, p_params, param_len);  
    }

    btif_sendmsg(p_msg);

    return BT_STATUS_SUCCESS;
}

下面进入btif_core.c文件的 btif_in_storage_request_copy_cb()方法中进行深拷贝。

static void btif_in_storage_request_copy_cb(
    UINT16 event,char *p_new_buf, char *p_old_buf)
{
    LOG_ERROR(LOG_TAG, 
        "method: btif_in_storage_request_copy_cb()");
     btif_storage_req_t *new_req = (btif_storage_req_t*)p_new_buf;
     btif_storage_req_t *old_req = (btif_storage_req_t*)p_old_buf;

     BTIF_TRACE_EVENT("%s", __FUNCTION__);
     switch (event)
     {
         case BTIF_CORE_STORAGE_REMOTE_WRITE:
         case BTIF_CORE_STORAGE_ADAPTER_WRITE:
         {
             bdcpy(new_req->write_req.bd_addr.address,
                old_req->write_req.bd_addr.address);
             /* Copy the member variables one at a time */
             new_req->write_req.prop.type = 
                    old_req->write_req.prop.type;
             new_req->write_req.prop.len = 
                    old_req->write_req.prop.len;

             new_req->write_req.prop.val = 
                    (UINT8 *)(p_new_buf 
                        + sizeof(btif_storage_req_t));
             memcpy(new_req->write_req.prop.val, 
                    old_req->write_req.prop.val,
                    old_req->write_req.prop.len);
         }break;
     }
}

下面进入btif_core.c文件的 btif_sendmsg()方法中。

void btif_sendmsg(void *p_msg)
{
    LOG_ERROR(LOG_TAG, "method: btif_sendmsg() %p",p_msg);
  if (!bt_jni_workqueue_thread) {
    BTIF_TRACE_ERROR("%s: message dropped, q
        ueue not initialized or gone", __func__);
    osi_free(p_msg);
    return;
  }
    /**
      * 线程异步处理,暂不深究了
      */
    LOG_ERROR(LOG_TAG, "thread_post......");
    thread_post(bt_jni_workqueue_thread, 
              bt_jni_msg_ready, p_msg);
}

再次回到AdapterService类的setScanMode()方法。

boolean setScanMode(int mode, int duration) {
     Log.d(TAG,"setScanMode()");
    enforceCallingOrSelfPermission(BLUETOOTH_PERM, 
        "Need BLUETOOTH permission");

    //执行完了
    boolean setDiscoverableResult=
            setDiscoverableTimeout(duration);
    Log.d(TAG,"setDiscoverableResult: "
        + setDiscoverableResult);
     //现在开始执行这里
    int newMode = convertScanModeToHal(mode);
    return mAdapterProperties.setScanMode(newMode);
}

下面进入AdapterService类的convertScanModeToHal()方法。

private static int convertScanModeToHal(int mode) {
    switch (mode) {
        case BluetoothAdapter.SCAN_MODE_NONE:
            return AbstractionLayer.BT_SCAN_MODE_NONE;
        case BluetoothAdapter.SCAN_MODE_CONNECTABLE:
            return AbstractionLayer.BT_SCAN_MODE_CONNECTABLE;
        case BluetoothAdapter
                .SCAN_MODE_CONNECTABLE_DISCOVERABLE:
            return AbstractionLayer
                .BT_SCAN_MODE_CONNECTABLE_DISCOVERABLE;
    }
   // errorLog("Incorrect scan mode in convertScanModeToHal");
    return -1;
}

下面进入AdapterProperties类的setScanMode()方法。

boolean setScanMode(int scanMode) {
    synchronized (mObject) {
        return mService.setAdapterPropertyNative(
            AbstractionLayer.BT_PROPERTY_ADAPTER_SCAN_MODE,           
            Utils.intToByteArray(scanMode));
    }
}

下面进入AdapterService类的setAdapterPropertyNative()方法。

native boolean setAdapterPropertyNative(int type, byte[] val);

log输出

/*
 * 下面这部分是设置扫描时间的log
 * 封装的request发送到硬件进行交互。
 */
BluetoothAdapterService: setScanMode: prev mode: 21 new mode: 23  
BluetoothServiceJni: setAdapterPropertyNative:  
BluetoothServiceJni: setAdapterPropertyNative():  
bt_btif : method: set_adapter_property   
bt_btif_core: method btif_set_adapter_property()  
bt_btif_core: btif_set_adapter_property type: 9, len 4, 0x9eaa83f0  
bt_btif_core: case: BT_PROPERTY_ADAPTER_DISCOVERY_TIMEOUT  
bt_btif_core: storage_req_id: 2  
bt_btif_core: method: btif_transfer_context()  
bt_btif_core: btif_transfer_context event 2, len 24  
bt_btif_core: p_copy_cback true  
bt_btif_core: method: btif_in_storage_request_copy_cb()   
bt_btif_core: method: btif_sendmsg() 0x9eaa93f8  
bt_btif_core: thread_post......  
  
/*
 * 下面这部分就是设置扫描模式的log
 * 可以看见与上面设置扫描时间是一样的流程
 * 最终将封装的request发送到硬件进行交互。
 */
BluetoothServiceJni: setAdapterPropertyNative:  
BluetoothServiceJni: setAdapterPropertyNative():  
bt_btif : method: set_adapter_property   
bt_btif_core: method btif_set_adapter_property()  
bt_btif_core: btif_set_adapter_property type: 7, len 4, 0x9eaa83f0  
bt_btif_core: case: BT_PROPERTY_ADAPTER_SCAN_MODE  
bt_btif_core: method: btif_transfer_context()  
bt_btif_core: btif_transfer_context event 2, len 24  
bt_btif_core: p_copy_cback true  
bt_btif_core: method: btif_in_storage_request_copy_cb()  
bt_btif_core: method: btif_sendmsg() 0x9eaa9430  
bt_btif_core: thread_post......  

现在我们都把扫描模式和扫描时间设置了,那么怎么知道是否生效呢?
答案就是底层硬件通过jni回调的方式通知Bluetooth进程,这样就自然又回到了上层java中进行处理。

在com_android_bluetooth_btservice_AdapterService.cpp中的adapter_properties_callback()方式就是回调处理。

static void adapter_properties_callback(
    bt_status_t status, int num_properties,
    bt_property_t *properties) {
    jobjectArray props;
    jintArray types;
    jbyteArray val;
    jclass mclass;

    ALOGE("method called: adapter_properties_callback()");

    if (!checkCallbackThread()) {
       ALOGE("Callback: '%s' is not called on the correct thread",
           __FUNCTION__);
       return;
    }

    ALOGV("%s: Status is: %d, Properties: %d", __FUNCTION__, 
        status, num_properties);

    if (status != BT_STATUS_SUCCESS) {
        ALOGE("%s: Status %d is incorrect", 
            __FUNCTION__, status);
        return;
    }

    val = (jbyteArray) 
        callbackEnv->NewByteArray(num_properties);
    if (val == NULL) {
        ALOGE("%s: Error allocating byteArray", 
            __FUNCTION__);
        return;
    }

    mclass = callbackEnv->GetObjectClass(val);

    /* (BT) Initialize the jobjectArray and jintArray 
      here itself and send the initialized array pointers 
      alone to get_properties */

    props = callbackEnv->NewObjectArray(
            num_properties, mclass,NULL);
    if (props == NULL) {
        ALOGE("%s: Error allocating object Array for properties", 
            __FUNCTION__);
        return;
    }

    types = (jintArray)callbackEnv->NewIntArray(num_properties);

    if (types == NULL) {
        ALOGE("%s: Error allocating int Array for values", 
            __FUNCTION__);
        return;
    }
    // Delete the reference to val and mclass
    callbackEnv->DeleteLocalRef(mclass);
    callbackEnv->DeleteLocalRef(val);

    if (get_properties(num_properties, properties, 
            &types, &props) < 0) {
        if (props) callbackEnv->DeleteLocalRef(props);
        if (types) callbackEnv->DeleteLocalRef(types);
        return;
    }
    
    /**
      * 这里就是回调
      */ 
    if (sJniCallbacksObj) {
        callbackEnv->CallVoidMethod(sJniCallbacksObj,
        method_adapterPropertyChangedCallback, types,
        props);
    }
    checkAndClearExceptionFromCallback(callbackEnv,
         __FUNCTION__);
    callbackEnv->DeleteLocalRef(props);
    callbackEnv->DeleteLocalRef(types);
    return;

}

下面来看下这个变量“method_adapterPropertyChangedCallback”。
这个变量的赋值是在:

static void classInitNative(JNIEnv* env, jclass clazz) {
    ......
    jclass jniCallbackClass =
    env->FindClass(
        "com/android/bluetooth/btservice/JniCallbacks");
    ......
    method_adapterPropertyChangedCallback = 
        env->GetMethodID(jniCallbackClass,
        "adapterPropertyChangedCallback","([I[[B)V");
    ......

}

可以看见是调用的JniCallbacks类的adapterPropertyChangedCallback()方法。

void adapterPropertyChangedCallback(int[] types, 
        byte[][] val) {
    Log.d("JniCallbacks",
        "adapterPropertyChangedCallback()");
    mAdapterProperties
        .adapterPropertyChangedCallback(types, val);
}

下面进入AdapterProperties类中的adapterPropertyChangedCallback()方法。

void adapterPropertyChangedCallback(int[] types, 
        byte[][] values) {
    Log.d(TAG,"method called: adapterPropertyChangedCallback()");
    Intent intent;
    int type;
    byte[] val;
    for (int i = 0; i < types.length; i++) {
        val = values[i];
        type = types[i];
        infoLog("adapterPropertyChangedCallback with type:" 
            + type + " len:" + val.length);
        synchronized (mObject) {
            switch (type) {
                ......
                case AbstractionLayer
                    .BT_PROPERTY_ADAPTER_SCAN_MODE:
                    
                    int mode = Utils.byteArrayToInt(val, 0);
                    mScanMode = mService
                        .convertScanModeFromHal(mode);
                    intent = new Intent(BluetoothAdapter
                        .ACTION_SCAN_MODE_CHANGED);
                    intent.putExtra(BluetoothAdapter.EXTRA_SCAN_MODE, 
                        mScanMode);
                     /*
                      * 按照我的理解就是发这个广播会去检查当前手机系统启动的状态。
                      * 在系统BOOT阶段完成前只有在代码中注册的receiver才能接受
                      * 到这个广播
                      */
                    intent.addFlags(Intent
                        .FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
                    mService.sendBroadcast(intent, 
                        mService.BLUETOOTH_PERM);
                    debugLog("Scan Mode:" + mScanMode);
                    if (mBluetoothDisabling) {
                        mBluetoothDisabling = false;
                        mService.startBrEdrCleanup();
                    }
                    break;
                ......
                case AbstractionLayer
                    .BT_PROPERTY_ADAPTER_DISCOVERABLE_TIMEOUT:
                    
                    mDiscoverableTimeout = Utils.byteArrayToInt(val, 0);
                    debugLog("Discoverable Timeout:" 
                        + mDiscoverableTimeout);
                    break;
                ......
            }
        }
    }
}

由于我们先设置的扫描时间,所以先回调上来的是:
"case AbstractionLayer.BT_PROPERTY_ADAPTER_DISCOVERABLE_TIMEOUT";
会将底层设置生效的扫描时间值返回到上层。

然后回调的是:
“case AbstractionLayer.BT_PROPERTY_ADAPTER_SCAN_MODE:”
将当前扫描的模式返回给上层。
并且会发送广播进行通知。
"BluetoothAdapter.ACTION_SCAN_MODE_CHANGED"