Android GATT 连接过程源码分析

低功耗蓝牙(BLE)设备的通信基本协议是 GATT, 要操作 BLE 设备,第一步就是要连接设备,其实就是连接 BLE 设备上的 GATT service。 结合上一篇文章,我这里结合源码,分析一下 GATT 连接的流程,以及各个模块是怎么相互交互的。注意本文依据的是 Android 4.4 的源代码。

应用框架层

首先,一般应用层都是通过调用如下方法,来创建一个 GATT 连接的:

mBluetoothGatt = device.connectGatt(this, false, mGattCallback);  

这里调用了方法 connectGatt(),我们来看一下源码,代码在 /frameworks/base/core/java/android/bluetooth/BluetoothDevice.java

public BluetoothGatt connectGatt(Context context, boolean autoConnect,  
        BluetoothGattCallback callback) {
    BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
    IBluetoothManager managerService = adapter.getBluetoothManager();
    try {
        IBluetoothGatt iGatt = managerService.getBluetoothGatt();
        if (iGatt == null) {
            // BLE is not supported
            return null;
        }
        // 创建一个 BluetoothGatt 对象
        BluetoothGatt gatt = new BluetoothGatt(context, iGatt, this);
        // 发起连接
        gatt.connect(autoConnect, callback);
        return gatt;
    } catch (RemoteException e) {Log.e(TAG, "", e);}
    return null;
}

这里通过 BluetoothAdapter 获取 managerService ,这是通过 Binder 机制绑定的一个远程蓝牙管理服务,进而获得 iGatt,同样,这也是一个远程的 Binder 对象,这是一个非常关键的对象,后面会详细讲。然后调用了 BluetoothGattconnect() 方法,需要注意这里有一个参数 autoConnect, 如果为 false,则表示直接连接,true 表示自动连接,意思是等到设备可用,则会自动连接上。

接下来看 gatt.connect() 的实现,代码在/frameworks/base/core/java/android/bluetooth/BluetoothGatt.java

boolean connect(Boolean autoConnect, BluetoothGattCallback callback) {  
    if (DBG) Log.d(TAG, "connect() - device: " + mDevice.getAddress() + ", auto: " + autoConnect);
    synchronized(mStateLock) {
        // 判断当前连接状态
        if (mConnState != CONN_STATE_IDLE) {
            throw new IllegalStateException("Not idle");
        }
        mConnState = CONN_STATE_CONNECTING;
    }
    // 这里向底层注册上层的应用
    if (!registerApp(callback)) {
        synchronized(mStateLock) {
            mConnState = CONN_STATE_IDLE;
        }
        Log.e(TAG, "Failed to register callback");
        return false;
    }

    // the connection will continue after successful callback registration
    mAutoConnect = autoConnect;
    return true;
}

这里面关键的一句是 registerApp(callback),这是向底层注册 App,底层就知道有 App 在使用蓝牙,有蓝牙消息的时候,就通过回调通知上层的 App。BLE 几乎所有操作都是通过异步回调实现的,就是通过这个你自定义的 BluetoothGattCallback 来通知你的应用的。接下来我们继续看 registerApp()

private boolean registerApp(BluetoothGattCallback callback) {  
    if (DBG) Log.d(TAG, "registerApp()");
    if (mService == null) return false;

    mCallback = callback;
    UUID uuid = UUID.randomUUID();
    if (DBG) Log.d(TAG, "registerApp() - UUID=" + uuid);

    try {
        mService.registerClient(new ParcelUuid(uuid), mBluetoothGattCallback);
    } catch (RemoteException e) {
        Log.e(TAG,"",e);
        return false;
    }

    return true;
}

可以看到,这里调用了 mService.registerClient(),这里的 mService 就是第一步创建的 BluetoothGatt 对象的时候传入的 IBluetoothGatt 类型的 Binder 对象。对于这个函数的名字为什么叫 registerClient,这是因为,在 Binder 机制中,被绑定的 Service 作为称为服务端,发起绑定的一方是客户端

在继续往下看 registerClient() 这个函数之前,我们回忆一下,我们的目标是连接 BLE 设备,到这一步了,还没有看到连接动作的踪影。这是怎么回事?前面我们说过,蓝牙几乎所有的操作都是依靠回调实现,我们先来看一下这里的 mBluetoothGatt 的实现,看源代码中,这个回调对象非常大,包含所有的 Gatt 回调动作,我们这里主要看 onClientRegistered() 方法:

private final IBluetoothGattCallback mBluetoothGattCallback =  
new IBluetoothGattCallback.Stub() {  
    /**
     * Application interface registered - app is ready to go
     * @hide
     */
    public void onClientRegistered(int status, int clientIf) {
        if (DBG) Log.d(TAG, "onClientRegistered() - status=" + status
                + " clientIf=" + clientIf);
        if (VDBG) {
            synchronized(mStateLock) {
                // 这里判断状态是不是 CONN_STATE_CONNECTING,
                // 注意到前面的 `connect()` 方法中已经把 mConnState = CONN_STATE_CONNECTING;
                if (mConnState != CONN_STATE_CONNECTING) {
                    Log.e(TAG, "Bad connection state: " + mConnState);
                }
            }
        }
        mClientIf = clientIf;
        // 注册客户端失败,通知到应用的 callback
        if (status != GATT_SUCCESS) {
            mCallback.onConnectionStateChange(BluetoothGatt.this, GATT_FAILURE,
                    BluetoothProfile.STATE_DISCONNECTED);
            synchronized(mStateLock) {
                mConnState = CONN_STATE_IDLE;
            }
            return;
        }
        try {
            // 这里开始做真正的连接操作了
            mService.clientConnect(mClientIf, mDevice.getAddress(),
                    !mAutoConnect); // autoConnect is inverse of "isDirect"
        } catch (RemoteException e) {
            Log.e(TAG,"",e);
        }
    }

    ...
};

这个回调方法有两个参数 statusclientIf,前者很好理解,就是表示注册客户端是否成功。clientIf 表示从底层返回的一个 id,用来唯一标示这个客户端,接下来的所有客户端的操作请求,都需要带上这个 id。 这个回调方法中做的事情比较清晰,特别注意到 mService.clientConnect(...),这里开始调用 Service 接口开始发起连接了。

从代码中可以看到,mService 是一个很关键的对象,但是这个对象是从哪里来的呢?

应用框架和蓝牙服务的衔接: Binder

在第一段代码的分析中就提到了 iGatt 对象,从 BluetoothGatt 的构造函数可以看出,其实 mService = iGattiGattIBluetoothGatt 接口的 Binder。

我们看一下 BluetoothAdapter 是怎么获得的,BluetoothAdapter.getDefaultAdapter():

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;
}

这里是一个单例模式,通过系统API ServiceManager.getService() 获得的,这里大致逻辑就是,在系统那个启动的时候,Android 会启动一些系统服务并通过 ServiceManager 管理,具体我就不往下深究了,可以具体看一下老罗的这篇文章。这里直接给出结论,这里 Binder 对象对应的服务是 BluetoothManagerService,代码在 /frameworks/base/services/java/com/android/server/BluetoothManagerService.java

我们看一下怎么从 BluetoothManagerService 中获取到 IBluetoothGatt 的 Binder 的。注意到 BluetoothManagerService 中有一个方法 bluetoothStateChangeHandler(),冲方法名就大概可以知道这个方法是在蓝牙状态变化的时候,做一些处理的。跟踪以下这个函数的调用的地方,就能验证我们的猜想是对的。这一块和本文的关系不大,我们现在来看一下 bluetoothStateChangeHandler() 的具体实现:

private void bluetoothStateChangeHandler(int prevState, int newState) {  
    if (prevState != newState) {
        //Notify all proxy objects first of adapter state change
        if (newState == BluetoothAdapter.STATE_ON || newState == BluetoothAdapter.STATE_OFF) {
            boolean isUp = (newState==BluetoothAdapter.STATE_ON);
            sendBluetoothStateCallback(isUp);

            if (isUp) {
                // connect to GattService
                if (mContext.getPackageManager().hasSystemFeature(
                            PackageManager.FEATURE_BLUETOOTH_LE)) {
                    Intent i = new Intent(IBluetoothGatt.class.getName());
                    doBind(i, mConnection, Context.BIND_AUTO_CREATE, UserHandle.CURRENT);

                    Intent iqc = new Intent(IQBluetooth.class.getName());
                    doBind(iqc, mConnection, Context.BIND_AUTO_CREATE, UserHandle.CURRENT);
                }
            } else {
                //If Bluetooth is off, send service down event to proxy objects, and unbind
                if (!isUp && canUnbindBluetoothService()) {
                    sendBluetoothServiceDownCallback();
                    sendQBluetoothServiceDownCallback();
                    unbindAndFinish();
                }
            }
        }

        //Send broadcast message to everyone else
        Intent intent = new Intent(BluetoothAdapter.ACTION_STATE_CHANGED);
        intent.putExtra(BluetoothAdapter.EXTRA_PREVIOUS_STATE, prevState);
        intent.putExtra(BluetoothAdapter.EXTRA_STATE, newState);
        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
        intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
        if (DBG) Log.d(TAG,"Bluetooth State Change Intent: " + prevState + " -> " + newState);
        mContext.sendBroadcastAsUser(intent, UserHandle.ALL,
                BLUETOOTH_PERM);
    }
}

看到 if (isUp) 这个分支中,会绑定到以 IBluetoothGatt 的类名为 Action Name 的服务,也就是 action="android.bluetooth.IBluetoothGatt"。我们在 /packages/apps/Bluetooth 这个 App 的 AndroidManifest.xml 中找到如下的声明:

<service  
    android:process="@string/process"
    android:name = ".gatt.GattService"
    android:enabled="@bool/profile_supported_gatt">
    <intent-filter>
        <action android:name="android.bluetooth.IBluetoothGatt" />
    </intent-filter>
</service>  

我们找到了,原来是绑定到了 com.android.bluetooth.gatt.GattService 上了。如果绑定成功,会回调 mConnectiononServiceConnected(),其实现如下:

public void onServiceConnected(ComponentName className, IBinder service) {  
    Message msg = mHandler.obtainMessage(MESSAGE_BLUETOOTH_SERVICE_CONNECTED);
    ...
    } else if (className.getClassName().equals("com.android.bluetooth.gatt.GattService")) {
        msg.arg1 = SERVICE_IBLUETOOTHGATT;
    }
    ...
    msg.obj = service;
    mHandler.sendMessage(msg);
}

如果绑定的类名是 GattService,就会发送MESSAGE_BLUETOOTH_SERVICE_CONNECTED 消息给 mHandler,消息的第一个参数为 SERVICE_IBLUETOOTHGATT,我们接下来看 mHandler 怎么处理的:

@Override
public void handleMessage(Message msg) {  
    if (DBG) Log.d (TAG, "Message: " + msg.what);
    switch (msg.what) {
        ...
        case MESSAGE_BLUETOOTH_SERVICE_CONNECTED:
        {
            IBinder service = (IBinder) msg.obj;
            synchronized(mConnection) {
                if (msg.arg1 == SERVICE_IBLUETOOTHGATT) {
                    mBluetoothGatt = IBluetoothGatt.Stub.asInterface(service);
                    break;
                }
                ...
            }
        }
    }
}

最终获得 IBluetoothGatt 的 Binder,并赋值给 mBluetoothGatt,最后通过如下接口,返回给前面的 BluetoothGatt

至此,通过 Binder 机制,完成了应用框架 API 到 Service 的绑定。别忘了我们的目标:分析BLE连接的流程。通过前面的代码分析我们知道,连接的时候,先调用了 'mService.registerClient()',然后在注册成功后,调用了 mService.clientConnect() 真正发起连接。我们知道了,这个 mService 实际上就是 com.android.bluetooth.gatt.GattService。我们接下来分析这个 Service,也就到了蓝牙服务层了。

蓝牙服务

蓝牙服务的代码在 packages/app/Bluetooth,编译以后成 Bluetooth.apk,安装在 /system/app/ 目录下面,GattService 运行在 com.android.bluetooth 进程中。我们接着来看 BinderregisterClient() 接口,这个 Binder 是 GattService 的一个内部类:

private static class BluetoothGattBinder extends IBluetoothGatt.Stub implements IProfileServiceBinder {  
    public void registerClient(ParcelUuid uuid, IBluetoothGattCallback callback) {
        GattService service = getService();
        if (service == null) return;
        service.registerClient(uuid.getUuid(), callback);
    }
}

可以看到,实际上这里还是调用了 GattServiceregisterClient 方法:

void registerClient(UUID uuid, IBluetoothGattCallback callback) {  
    enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");

    if (DBG) Log.d(TAG, "registerClient() - UUID=" + uuid);
    mClientMap.add(uuid, callback);
    // 调用 native 接口
    gattClientRegisterAppNative(uuid.getLeastSignificantBits(),
            uuid.getMostSignificantBits());
}

这里首先是把 uuid 以及对应的 callback 保存到一个 mClientMap 中去,这里从名字上我们就能大概清楚这里的作用,这里的 uuid 是客户端的唯一标示, uuid 对应了客户端的回调函数 callback。接下来,调用了 gattClientRegisterAppNative() 接口向底层协议栈注册客户端,看一下函数定义:

private native void gattClientRegisterAppNative(long app_uuid_lsb, long app_uuid_msb);  

这里可以看出,实际上是客户端的标示 -- UUID 注册到底层去,UUID 是 128 bit, 正好用两个 long 型的参数表示。这个函数是 JNI 的申明,具体的实现就在对应的 C/C++ 代码中。

蓝牙服务和 HAL 的调用:JNI

上面的 gattClientRegisterAppNative() 对应的 JNI 的代码在哪里呢?通过查看 AndroidManifest.xml,我们知道 Bluetooth 的自定义 Application 是 AdapterApp,里面有这样的代码:

static {  
    if (DBG) Log.d(TAG,"Loading JNI Library");
    System.loadLibrary("bluetooth_jni");
}

这里是加载了 libbluetooth_jni.so 动态库。我们再看 jni 目录的 Android.mk,这里正好是生成 libbluetooth_jni 的编译脚本。这样我们就知道了对应的 C/C++ 代码在 com_android_bluetooth_gatt.cpp:

static JNINativeMethod sMethods[] = {  
    ...
    {"gattClientRegisterAppNative", "(JJ)V", (void *) gattClientRegisterAppNative},
    ...
}

这是注册 JNI 函数的标准方法,关于 JNI 的详细语法,可以参考这里。可以找到对应的函数实现如下:

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);
}

这里调用了 sGattIfclientregister_client() 方法,这里还是把客户端的标示 UUID 传递下去。这里的  sGattIf 是什么呢?

static const btgatt_interface_t *sGattIf = NULL;  

它是一个 btgatt_interface_t 类型的变量,sGattIf 的初始化在 initializeNative() 中,这个函数在 GattService.start() 方法中被调用了,这个函数定义如下:

static void initializeNative(JNIEnv *env, jobject object) {  
    if(btIf)
      return;
  if ( (btIf = getBluetoothInterface()) == NULL) {
      error("Bluetooth module is not loaded");
      return;
  }
    ...
  if ( (sGattIf = (btgatt_interface_t *)
        btIf->get_profile_interface(BT_PROFILE_GATT_ID)) == NULL) {
      error("Failed to get Bluetooth GATT Interface");
      return;
  }
    ...
}

注意这里首先通过 getBluetoothInterface() 获得整个底层的蓝牙接口。我们重点来关注以下 sGattIf 是怎么来的? 看到这里调用了 btIf->get_profile_interface(BT_PROFILE_GATT_ID)) 来获取 sGattIf 实例。

现在来看 btgatt_interface_t 是在哪里定义的,我们看一下这个文件 include 的头文件中,最有可能就是在 #include "hardware/bt_gatt.h",这就是 HAL 接口定义的地方。

硬件抽象层 HAL

HAL 头文件都放在 hardware/libhardware/include/hardware/,我们在这里找到了 bt_gatt.h,并找到了 btgatt_interface_t 的定义如下:

/** Represents the standard Bluetooth GATT interface. */
typedef struct {  
    /** Set to sizeof(btgatt_interface_t) */
    size_t          size;

    /**
     * Initializes the interface and provides callback routines
     */
    bt_status_t (*init)( const btgatt_callbacks_t* callbacks );

    /** Closes the interface */
    void (*cleanup)( void );

    /** Pointer to the GATT client interface methods.*/
    const btgatt_client_interface_t* client;

    /** Pointer to the GATT server interface methods.*/
    const btgatt_server_interface_t* server;
} btgatt_interface_t;

可以看到 btgatt_interface_t 有一个成员 client,类型是 btgatt_client_interface_t。 我们再来看 btgatt_client_interface_t 的定义,在 bt_gatt_client.h 中:

/** Represents the standard BT-GATT client interface. */

typedef struct {  
    /** Registers a GATT client application with the stack */
    bt_status_t (*register_client)( bt_uuid_t *uuid );

    /** Unregister a client application from the stack */
    bt_status_t (*unregister_client)(int client_if );

    /** Create a connection to a remote LE or dual-mode device */
    bt_status_t (*connect)( int client_if, const bt_bdaddr_t *bd_addr,
                         bool is_direct, int transport );

    /** Disconnect a remote device or cancel a pending connection */
    bt_status_t (*disconnect)( int client_if, const bt_bdaddr_t *bd_addr,
                    int conn_id);

        ...
} btgatt_client_interface_t;

在这里我们看到了 register_client 这个函数指针。这个结构体的定义很长,我这里只截取了本文相关的内容。这里定义了所有 GATT 客户端操作相关的接口,例如连接、扫描、获取 Gatt Service、读写 Gatt characteristic/descriptor 等等。 但是这个结构体的具体实现在什么地方呢?我们的直觉应该就在 HAL 的实现 BlueDroid 模块了。

蓝牙协议栈:BlueDroid

BlueDroid 的代码在 external/bluetooth/bluedroid。我们在这个目录下 grep 一下:

$ cd external/bluetooth/bluedroid
$ grep -nr 'btgatt_interface_t' .

我们很容易找到 btgatt_interface_t 的实现:

// btif/src/btif_gatt.c
static const btgatt_interface_t btgattInterface = {  
    sizeof(btgattInterface),

    btif_gatt_init,
    btif_gatt_cleanup,

    &btgattClientInterface,
    &btgattServerInterface,
};

然后在 btif/src/btif_gatt_client.c,找到 btgattClientInterface 具体的实现如下:

const btgatt_client_interface_t btgattClientInterface = {  
    btif_gattc_register_app,
    btif_gattc_unregister_app,
    btif_gattc_open,
    btif_gattc_close,
    ...
}

看到这里定义了一个 btgatt_client_interface_t 的实例 btgattClientInterface,内部都是函数指针,所有的函数的实现都这这个文件中能找到。其实这个变量就是前面的代码中提到的 sGattIf->client,我们下面来看看这是是怎么关联上的。 在 btif/src/btif_gatt.c 中又如下定义:

extern btgatt_client_interface_t btgattClientInterface;  
static const btgatt_interface_t btgattInterface = {  
    sizeof(btgattInterface),

    btif_gatt_init,
    btif_gatt_cleanup,

    &btgattClientInterface,
    &btgattServerInterface,
};

const btgatt_interface_t *btif_gatt_get_interface()  
{
    return &btgattInterface;
}

从代码中可以看出,btgattClientInterface 赋值给了 btgattInterfaceclient 成员(还记得前面的 btgatt_interface_t 的定义吧)。难道这里的 btgattInterface 就是 JNI 中的 sGattIf 吗? 确实是这样的,还记的前面的说的 sGattIf 的初始化,调用了如下接口:

sGattIf = (btgatt_interface_t *)btIf->get_profile_interface(BT_PROFILE_GATT_ID)  

我们来看一下 get_profile_interface() 的定义,在 btif/src/bluetooth.c 中:

static const void* get_profile_interface (const char *profile_id)  
{
    ...
    if (is_profile(profile_id, BT_PROFILE_GATT_ID))
        return btif_gatt_get_interface();
    ...
}

看到这里调用了 btif_gatt_get_interface(),实际上就是把 btgattInterface 返回赋值给了 sGattIf

到这里,变量之间的相互关系和初始化就都完全清楚了。还是不要忘记我们的目标:连接 BLE 设备。前面我们分析到了,发起 BLE 设备连接,首先是向底层协议栈注册客户端,也就是调用了 sGattIf->client->register_client(&uuid);。 现在我们知道了 register_client() 的实现就在 btif/src/btif_gatt_client.c,对应的实现如下:

static bt_status_t btif_gattc_register_app(bt_uuid_t *uuid)  
{
    CHECK_BTGATT_INIT();
    btif_gattc_cb_t btif_cb;
    memcpy(&btif_cb.uuid, uuid, sizeof(bt_uuid_t));
    return btif_transfer_context(btgattc_handle_event, BTIF_GATTC_REGISTER_APP,
                                 (char*) &btif_cb, sizeof(btif_gattc_cb_t), NULL);
}

这里的 btif_transfer_context() 是一个工具方法,代码如下:

// btif/src/btif_core.c
bt_status_t btif_transfer_context (tBTIF_CBACK *p_cback, UINT16 event, char* p_params, int param_len, tBTIF_COPY_CBACK *p_copy_cback)  
{
    tBTIF_CONTEXT_SWITCH_CBACK *p_msg;
    BTIF_TRACE_VERBOSE2("btif_transfer_context event %d, len %d", event, param_len);

    /* allocate and send message that will be executed in btif context */
    if ((p_msg = (tBTIF_CONTEXT_SWITCH_CBACK *) GKI_getbuf(sizeof(tBTIF_CONTEXT_SWITCH_CBACK) + param_len)) != NULL)
    {
        // 给 p_msg 赋值
                ...

                // 注意这里
        btif_sendmsg(p_msg);
        return BT_STATUS_SUCCESS;
    }
    else
    {
        /* let caller deal with a failed allocation */
        return BT_STATUS_NOMEM;
    }
}

这里面调用了一个很重要的方法 btif_sendmsg(...),实际上是调用了 GKI_send_msg(...),接着往下看代码就会发现,实际上就是发送一个 Event,让对应的 handler 函数去处理。 据我的理解,其实就是一个类似于 Android framework 中的 Handler,你可以提交你的 Task 到指定的线程中去运行。 这里 btif_transfer_context(...) 的作用就是把代码运行的上下文(context)转为蓝牙协议栈,这部分的代码和本文关系不大,这里就不深入讨论了。 这里的 btgattc_handle_event 相当于我们要运行的 Task, 后面就是这个 Task 运行需要的一些参数。我们接下来看 btgattc_handle_event 的实现:

// btif/src/btif_gatt_client.c
static void btgattc_handle_event(uint16_t event, char* p_param)  
{
    tBTA_GATT_STATUS           status;
    tBT_UUID                   uuid;
    ...

    btif_gattc_cb_t* p_cb = (btif_gattc_cb_t*)p_param;
    if (!p_cb) return;
    ALOGD("%s: Event %d", __FUNCTION__, event);

    switch (event)
    {
        case BTIF_GATTC_REGISTER_APP:
                        // UUID 的格式转换
            btif_to_bta_uuid(&uuid, &p_cb->uuid);
            BTA_GATTC_AppRegister(&uuid, bta_gattc_cback);
            break;
                ...
        }
}

可以看到,这个函数的参数,都是我们上面那个 btif_transfer_context(...) 传递进来的,这里 event = BTIF_GATTC_REGISTER_APP,看一下对应的 switch 分支代码。 btif_to_bta_uuid() 非常简单,这是把 UUID 的转换为 BTA 层 UUID 格式。然后真正做事的是 BTA_GATTC_AppRegister(...)

// bta/gatt/bta_gattc_api.c
void BTA_GATTC_AppRegister(tBT_UUID *p_app_uuid, tBTA_GATTC_CBACK *p_client_cb)  
{
    tBTA_GATTC_API_REG  *p_buf;

        if (bta_sys_is_register(BTA_ID_GATTC) == FALSE)
    {
        GKI_sched_lock();
                // 注册事件处理函数
        bta_sys_register(BTA_ID_GATTC, &bta_gattc_reg);
        GKI_sched_unlock();
    }

    if ((p_buf = (tBTA_GATTC_API_REG *) GKI_getbuf(sizeof(tBTA_GATTC_API_REG))) != NULL)
    {
        p_buf->hdr.event    = BTA_GATTC_API_REG_EVT;
        if (p_app_uuid != NULL)
            memcpy(&p_buf->app_uuid, p_app_uuid, sizeof(tBT_UUID));
        p_buf->p_cback      = p_client_cb;

        bta_sys_sendmsg(p_buf);
    }
    return;
}

这里首先判断 BTA_ID_GATTC 事件处理器是否注册了,如果没有注册就注册一个 bta_gattc_reg。这里表示 bta_gattc_reg 所有的 GATT 客户端事件的处理器。 可见,这个 bta_gattc_reg 是非常重要的,我们来看它的定义:

// bta/sys/bta_sys.h
/* registration structure */
typedef struct  
{
        // 事件处理函数
    tBTA_SYS_EVT_HDLR   *evt_hdlr;
        // 关闭事件处理
    tBTA_SYS_DISABLE    *disable;
} tBTA_SYS_REG;  

// bta/gatt/bta_gattc_api.c
static const tBTA_SYS_REG bta_gattc_reg =  
{
    bta_gattc_hdl_event,
    BTA_GATTC_Disable
};

这是一个结构体,其定义我也贴在上面了,成员类型都是函数指针,其函数的定义我在后面会讲。 我们先往下看,这里的代码是不是看起来有些面熟,其实和 btif_transfer_context() 的逻辑非常类似,这里也是发送一个 event 给 handler 去处理。 虽然这里调用的是 bta_sys_sendmsg(...),实际上它的实现就是调用 GKI_send_msg(...)。 分析方法类似,我们这里的 event 是 BTA_GATTC_API_REG_EVT,这个事件的处理函数就是上面的 bta_gattc_regbta_gattc_hdl_event

// bta/gatt/bta_gattc_main.c
BOOLEAN bta_gattc_hdl_event(BT_HDR *p_msg)  
{
    tBTA_GATTC_CB *p_cb = &bta_gattc_cb;
    ...
    switch (p_msg->event)
    {
        case BTA_GATTC_API_REG_EVT:
            bta_gattc_register(p_cb, (tBTA_GATTC_DATA *) p_msg);
            break;
             ...
        }
        ...
}

到这里,我们终于看到了最终的真正执行注册客户端的函数 bta_gattc_register(...) 了:

// bta/gatt/bta_gattc_act.c
void bta_gattc_register(tBTA_GATTC_CB *p_cb, tBTA_GATTC_DATA *p_data)  
{
    tBTA_GATTC               cb_data;
    UINT8                    i;
    tBT_UUID                 *p_app_uuid = &p_data->api_reg.app_uuid;
    tBTA_GATTC_INT_START_IF  *p_buf;
    tBTA_GATT_STATUS         status = BTA_GATT_NO_RESOURCES;

    APPL_TRACE_DEBUG1("bta_gattc_register state %d",p_cb->state);
    memset(&cb_data, 0, sizeof(cb_data));
    cb_data.reg_oper.status = BTA_GATT_NO_RESOURCES;

     // 检查 GATTC 模块是否开启;如果没有,就开启
     if (p_cb->state == BTA_GATTC_STATE_DISABLED)
     {
         bta_gattc_enable (p_cb);
     }

        // 这里遍历客户端列表
    for (i = 0; i < BTA_GATTC_CL_MAX; i ++)
    {
                // 检查是否被占用
        if (!p_cb->cl_rcb[i].in_use)
        {
                        // 如果没有被占用,就向 GATT 协议栈注册,并获得新的 client_if
            if ((p_app_uuid == NULL) || (p_cb->cl_rcb[i].client_if = GATT_Register(p_app_uuid, &bta_gattc_cl_cback)) == 0)
            {
                APPL_TRACE_ERROR0("Register with GATT stack failed.");
                status = BTA_GATT_ERROR;
            }
            else
            {
                                // GATT协议栈注册成功,就在 BTA 层也中保存下来,完成注册
                p_cb->cl_rcb[i].in_use = TRUE;
                p_cb->cl_rcb[i].p_cback = p_data->api_reg.p_cback;
                memcpy(&p_cb->cl_rcb[i].app_uuid, p_app_uuid, sizeof(tBT_UUID));

                /* BTA use the same client interface as BTE GATT statck */
                cb_data.reg_oper.client_if = p_cb->cl_rcb[i].client_if;

                if ((p_buf = (tBTA_GATTC_INT_START_IF *) GKI_getbuf(sizeof(tBTA_GATTC_INT_START_IF))) != NULL)
                {
                    p_buf->hdr.event    = BTA_GATTC_INT_START_IF_EVT;
                    p_buf->client_if    = p_cb->cl_rcb[i].client_if;
                                        // 注册成功,发送 BTA_GATTC_INT_START_IF_EVT 事件
                    bta_sys_sendmsg(p_buf);
                    status = BTA_GATT_OK;
                }
                else
                {
                    GATT_Deregister(p_cb->cl_rcb[i].client_if);

                    status = BTA_GATT_NO_RESOURCES;
                    memset( &p_cb->cl_rcb[i], 0 , sizeof(tBTA_GATTC_RCB));
                }
                break;
            }
        }
    }

        /* callback with register event */
    if (p_data->api_reg.p_cback)
    {
        if (p_app_uuid != NULL)
            memcpy(&(cb_data.reg_oper.app_uuid),p_app_uuid,sizeof(tBT_UUID));

        cb_data.reg_oper.status = status;
                // 通过发送 BTA_GATTC_REG_EVT 事件,把注册结果回调给上层
        (*p_data->api_reg.p_cback)(BTA_GATTC_REG_EVT,  (tBTA_GATTC *)&cb_data);
    }  
}

主要流程都在代码的注释中解释了,遍历客户端列表,向 GATT statck 注册客户端,注册成功后发送 BTA_GATTC_INT_START_IF_EVT 事件。 因为这里和前面一样,同样是调用了 bta_sys_sendmsg(...),所以处理函数是 bta_gattc_hdl_event(...),我们再来看这个分支:

// bta/gatt/bta_gattc_main.c
BOOLEAN bta_gattc_hdl_event(BT_HDR *p_msg)  
{
    tBTA_GATTC_CB *p_cb = &bta_gattc_cb;
        ...
    switch (p_msg->event)
    {
                ...
        case BTA_GATTC_INT_START_IF_EVT:
            bta_gattc_start_if(p_cb, (tBTA_GATTC_DATA *) p_msg);
            break;
                ...
        }
}

这里调用了 bta_gattc_start_if(...)

// bta/gatt/bta_gattc_act.c
void bta_gattc_start_if(tBTA_GATTC_CB *p_cb, tBTA_GATTC_DATA *p_msg)  
{
    if (bta_gattc_cl_get_regcb(p_msg->int_start_if.client_if) !=NULL )
    {
        GATT_StartIf(p_msg->int_start_if.client_if);
    }
    else
    {
        APPL_TRACE_ERROR1("Unable to start app.: Unknown interface =%d",p_msg->int_start_if.client_if );
    }
}

最终调用了 GATT_StartIf(...)

// stack/gatt/gatt_api.c
void GATT_StartIf (tGATT_IF gatt_if)  
{
    tGATT_REG   *p_reg;
    tGATT_TCB   *p_tcb;
    BD_ADDR     bda;
    UINT8       start_idx, found_idx;
    UINT16      conn_id;

    GATT_TRACE_API1 ("GATT_StartIf gatt_if=%d", gatt_if);
    if ((p_reg = gatt_get_regcb(gatt_if)) != NULL)
    {
        p_reg = &gatt_cb.cl_rcb[gatt_if - 1];
        start_idx = 0;
        while (gatt_find_the_connected_bda(start_idx, bda, &found_idx))
        {
            p_tcb = gatt_find_tcb_by_addr(bda);
            if (p_reg->app_cb.p_conn_cb && p_tcb)
            {
                conn_id = GATT_CREATE_CONN_ID(p_tcb->tcb_idx, gatt_if);
                (*p_reg->app_cb.p_conn_cb)(gatt_if, bda, conn_id, TRUE, 0);
            }
            start_idx = ++found_idx;
        }
    }
}

这个函数的主要作用是,调用刚注册的客户端 gatt_if 的连接回调函数,上报所有的设备的连接状态。

我们接着分析 bta_gattc_register(...) 函数,重点是这一行:

(*p_data->api_reg.p_cback)(BTA_GATTC_REG_EVT,  (tBTA_GATTC *)&cb_data);

这里是看起来调用了一个回调函数,这里的 (*p_data->api_reg.p_cback) 是谁,我们这里回溯以下。 回到 bta_gattc_hdl_event(...),这个 p_data 是这里传进来的 tBTA_GATTC_DATA 类型的数据,它是一个联合体(union):

// bta/gatt/bta_gattc_int.h
typedef union  
{
    BT_HDR                      hdr;
    tBTA_GATTC_API_REG          api_reg;
        ...
} tBTA_GATTC_DATA;

其中 (p_data->api_reg) 成员是一个 tBTA_GATTC_API_REG,这个类型我们在 BTA_GATTC_AppRegister(...) 函数中见过。 其实这个值就是我们在这里创建的,我们看一下 p_cback 是谁,我们在往回找到 btgattc_handle_event(...) 函数,发现就是 bta_gattc_cback:其定义如下:

// btif/src/btif_gatt_client.c
static void bta_gattc_cback(tBTA_GATTC_EVT event, tBTA_GATTC *p_data)  
{
    bt_status_t status = btif_transfer_context(btif_gattc_upstreams_evt,
                    (uint16_t) event, (void*)p_data, sizeof(tBTA_GATTC), btapp_gattc_req_data);
    ASSERTC(status == BT_STATUS_SUCCESS, "Context transfer failed!", status);
}

这里又是一个通过 "handler"  机制实现运行上下文的切换,这里来看一下事件处理函数 btif_gattc_upstreams_evt

static void btif_gattc_upstreams_evt(uint16_t event, char* p_param)  
{
    ALOGD("%s: Event %d", __FUNCTION__, event);

    tBTA_GATTC *p_data = (tBTA_GATTC*)p_param;
    switch (event)
    {
        case BTA_GATTC_REG_EVT:
        {
            bt_uuid_t app_uuid;
            bta_to_btif_uuid(&app_uuid, &p_data->reg_oper.app_uuid);
            HAL_CBACK(bt_gatt_callbacks, client->register_client_cb
                , p_data->reg_oper.status
                , p_data->reg_oper.client_if
                , &app_uuid
            );
            break;
        }
                ...
        }
        btapp_gattc_free_req_data(event, p_data);
}

因为上面传递进来的 event 是 BTA_GATTC_REG_EVT,我们就来看这个 event 的处理代码。 bta_to_btif_uuid() 和上面的 btif_to_bta_uuid() 相反,把 BTA 的 UUID 转换为 BTIF 的格式。 然后,一个宏 HAL_CBACK,其定义如下:

#define HAL_CBACK(P_CB, P_CBACK, ...)\
    if (P_CB && P_CB->P_CBACK) {            \
        BTIF_TRACE_API2("HAL %s->%s", #P_CB, #P_CBACK); \
        P_CB->P_CBACK(__VA_ARGS__);         \
    }                                       \
    else {                                  \
        ASSERTC(0, "Callback is NULL", 0);  \
    }

这里展开一下,并替换其中实际的变量:

bt_gatt_callbacks->client->register_client_cb(p_data->reg_oper.status, p_data->reg_oper.client_if, &app_uuid);  

可以看到这里其实就是一个执行回调函数的宏。

现在问题是 bt_gatt_callbacks 是从谁?我们可以看到是在这里初始化的:

static bt_status_t btif_gatt_init( const btgatt_callbacks_t* callbacks )  
{
    bt_gatt_callbacks = callbacks;

    return BT_STATUS_SUCCESS;
}

也就是初始化的时候,通过传递进来的。在分析 BlueDroid 的最开始我们已经看到了 btgattInterface 的初始化了,这里的 btif_gatt_init 函数就赋值给了它的 init 成员。 通过我们前面的分析,btgattInterface 实际上就是 JNI 层的 sGattIf 对象。我们回到 JNI 层的代码:

// /packages/apps/Bluetooth/jni/com_android_bluetooth_gatt.cpp
static void initializeNative(JNIEnv *env, jobject object) {  
        ...
    // 这里我们前面分析过
    if ( (sGattIf = (btgatt_interface_t *)
          btIf->get_profile_interface(BT_PROFILE_GATT_ID)) == NULL) {
        error("Failed to get Bluetooth GATT Interface");
        return;
    }

        // 注意这里调用初始化方法 init(...)
    bt_status_t status;
    if ( (status = sGattIf->init(&sGattCallbacks)) != BT_STATUS_SUCCESS) {
        error("Failed to initialize Bluetooth GATT, status: %d", status);
        sGattIf = NULL;
        return;
    }

    mCallbacksObj = env->NewGlobalRef(object);
}

这里调用了 sGattIf->init(...) 方法,实际上就是前面的 btif_gatt_init(...) 函数。看到这里传入的 sGattCallbacks 就是我们在 BlueDroid 层寻找的 bt_gatt_callbacks。 我们来看 sGattCallbacks 的定义:

// /packages/apps/Bluetooth/jni/com_android_bluetooth_gatt.cpp
static const btgatt_callbacks_t sGattCallbacks = {  
    sizeof(btgatt_callbacks_t),
    &sGattClientCallbacks,
    &sGattServerCallbacks
};

通过前面的分析,我们应该能很快知道 btgatt_callbacks_t 应该在 HAL 中定义的,然后 sGattClientCallbacks 就是对应的 client 成员。 在来看 sGattClientCallbacks 的定义:

// /packages/apps/Bluetooth/jni/com_android_bluetooth_gatt.cpp
static const btgatt_client_callbacks_t sGattClientCallbacks = {  
    btgattc_register_app_cb,
        ...
};

这里的 btgattc_register_app_cb 对应的就是 btgatt_client_callbacks_tregister_client_cb 成员。所以我们再来看一下那个展开的宏,这里再贴一下:

bt_gatt_callbacks->client->register_client_cb(p_data->reg_oper.status, p_data->reg_oper.client_if, &app_uuid);  

实际上就是调用了 JNI 中定义的 btgattc_register_app_cb 函数:

// /packages/apps/Bluetooth/jni/com_android_bluetooth_gatt.cpp
void btgattc_register_app_cb(int status, int clientIf, bt_uuid_t *app_uuid)  
{
    CHECK_CALLBACK_ENV
    sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onClientRegistered, status,
        clientIf, UUID_PARAMS(app_uuid));
    checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
}

这里通过 JNI 调用了函数 id 为 method_onClientRegistered 函数,

// /packages/apps/Bluetooth/jni/com_android_bluetooth_gatt.cpp
static void classInitNative(JNIEnv* env, jclass clazz) {  
    // Client callbacks
    method_onClientRegistered = env->GetMethodID(clazz, "onClientRegistered", "(IIJJ)V");
        ...
}

这里就对应了 Java class 中的 onClientRegistered(...) 方法,这里 clazz 是谁呢?

// /packages/apps/Bluetooth/jni/com_android_bluetooth_gatt.cpp
static JNINativeMethod sMethods[] = {  
    {"classInitNative", "()V", (void *) classInitNative},
        ...
}

我们在 GattService.java 中看到:

// /packages/apps/Bluetooth/src/com/android/bluetooth/gatt/GattService.java
public class GattService extends ProfileService {  
    static {
        classInitNative();
  }
}

可见,上面的 clazz 就是 GattServiceonClientRegistered 就是 GattService 的成员方法。我们在 GattService 类中找到其实现如下:

// /packages/apps/Bluetooth/src/com/android/bluetooth/gatt/GattService.java
void onClientRegistered(int status, int clientIf, long uuidLsb, long uuidMsb)  
        throws RemoteException {
    UUID uuid = new UUID(uuidMsb, uuidLsb);
    if (DBG) Log.d(TAG, "onClientRegistered() - UUID=" + uuid + ", clientIf=" + clientIf);
    ClientMap.App app = mClientMap.getByUuid(uuid);
    if (app != null) {
        app.id = clientIf;
        app.linkToDeath(new ClientDeathRecipient(clientIf));
        app.callback.onClientRegistered(status, clientIf);
    }
}

哈哈,终于回到我们熟悉的 Java 层代码。还记得我们前面的在分析调用 registerClient(...) 的时候,把上层客户端与 uuid 对应起来,保存在 mClientMap 中。 这里通过 uuid 找到对应的客户端App,然后调用对应的回调函数 app.callback.onClientRegistered(status, clientIf);。 如果你还记得前面的分析的话,应该知道这个 callback 就是 BluetoothGatt 在调用 registerApp(...) 的时候传递的 mBluetoothGattCallback,所以这里就调用了 mBluetoothGattCallback.onClientRegistered(...) 方法。 这个 onClientRegistered() 回调我们在之前就提到过,如果注册客户端完成,就会回调这里。如果成功,就会发起真正的连接请求(见第 1 节)。到这里,其实就回调了 Android framework 层了。

如果这里注册客户端成功了,回调的 status 就是 GATT_SUCCESS,在 BluetoothGatt 中就会发起连接请求 mService.clientConnect(mClientIf, mDevice.getAddress(), !mAutoConnect);。具体的流程和上面整个分析类似。 有了上面的整个分析经验,这次应该就驾轻就熟了。所以我这里也不再往下继续说了。

总结

结合文章开始的那个图,回顾一下代码整个调用过程,非常清楚印证流程:framework -> Bluetooth service -> JNI -> HAL -> BlueDroid。 整个分析下来,几乎贯穿了整个 Android 系统,尽管还有很多细节没有展开去了解,但是脉络还是很清晰的。 第一次写分析源代码的文章,不知不觉就写了这么长(其实大部分是代码),花费了很多精力,也不知道说清楚了没有。对我自己来说,还是收获不少。

Read more

Android 上的低功耗蓝牙实践

这是我在 Droidcon Beijing 2016 和 GDG Devfest 2016 上做的分享,以下是正文: Slide 01 我今天分享的主题是 Android 上低功耗蓝牙的实践。这个主题比较小众。我在过去的一年多的时间里,主要是在做低功耗蓝牙相关的开发。接触过程中发现,BLE 的开发和通常的 Android APP 的开发有点不一样,这里需要访问硬件资源,而且涉及到一些协议相关的内容,而且这方面的资料也比较少。今天我从 Android 开发者的角度,来分享一下低功耗蓝牙开发实践。 Slide 02 今天分享的内容,主要包含如下几个部分:首先对蓝牙和低功耗蓝牙做一个简单的介绍;然后介绍 Android 上对低功耗蓝牙的支持;再介绍一下在 Android 平台上可以开发哪些低功耗蓝牙应用;然后是,开发过程中,可以帮助我们调试的工具;最后,总结一下所谓的 “最佳实践”,低功耗蓝牙开发的一些小经验。 Slide

By Race604

React Native 触摸事件处理详解

触控是移动设备的核心功能,也移动应用交互的基础,Android 和 iOS 各自都有完善的触摸事件处理机制。React Native(以下简称 RN)提供了一套统一的处理方式,能够方便的处理界面中组件的触摸事件、用户手势等。本文尝试介绍 RN 中触摸事件处理。 1. RN 基本触摸组件 RN 的组件除了 Text,其他组件默认是不支持点击事件,也不能响应基本触摸事件,所以 RN 中提供了几个直接处理响应事件的组件,基本上能够满大部分的点击处理需求TouchableHighlight, TouchableNativeFeedback, TouchableOpacity 和 TouchableWithoutFeedback。因为这几个组件的功能和使用方法基本类似,只是 Touch 的反馈效果不一样,所以一般我们用 Touchable** 代替。Touchable** 有如下几个回调方法: * onPressIn:点击开始; * onPressOut:点击结束或者离开; * onPress:单击事件回调; * onLongPress:长按事件回调。 它们的基本使用方法如下,

By Race604

React Native 中 ScrollView 性能探究

1 基本使用 ScrollView 是 React Native(后面简称:RN) 中最常见的组件之一。理解 ScrollView 的原理,有利于写出高性能的 RN 应用。 ScrollView 的基本使用也非常简单,如下: <ScrollView> <Child1 /> <Child2 /> ... </ScrollView> 它和 View 组件一样,可以包含一个或者多个子组件。对子组件的布局可以是垂直或者水平的,通过属性 horizontal=true/false 来控制。甚至还默认支持“下拉”刷新操作。另外还有一个特别赞的特性,超出屏幕的 View 会自动被移除,从而节省资源和提高绘制效率。我们来看如下一个例子: class

By Race604

30 天入门 Android 开发, Google 与你一起圆梦

经常会有朋友让我推荐 Android 开发入门的教程或者视频,我一直是推荐看官方的教程。大部分人或者觉得比较迷茫,或者觉得坚持不下去。这次推荐这个《30 天入门 Android 开发》是 Google 亲自发起的免费教学,以学习小组方式,大家可以一起学习和交流。一个好的开始,是成功的一半。让 Google 工程师带领你一起进入多彩的 Android 开发大门。点击这里 报名。 Android 设备已经随处可见,你想尝试一下在 Android 设备上的开发和创新吗?快来跟随 Google 的步伐,一起学习 Android 入门课吧! Google Study Jams 活动介绍 Study Jams 是一个学习 Google 在线课程的活动。该活动由学员自主发起课程学习小组,带领小组成员入门 Android 开发,最终将

By Race604