connectGatt(1/4):从frameworks到bt-JNI

  • Android启动时会运行com.android.bluetooth,后者一启动便会加载由<aosp>/system/bt编译出的BLE HAL模块libbluetooth.so。
  • 针对ROC-RK3588S-PC,BLE HAL模块源码位在<aosp>/systrem/bt,没在<aosp>/hardward。
图1 connectGatt

一、connectGatt“顶层”逻辑

要操作BLE设备,第一步就是要连接设备,其实就是连接BLE设备上的GATT service。这里结合源码,分析GATT连接流程,以及各个模块是怎么相互交互。

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

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

这里调用了方法connectGatt(),我们来看一下源码。

<aosp>/frameworks/base/core/java/android/bluetooth/BluetoothDevice.java
------
    public BluetoothGatt connectGatt(Context context, boolean autoConnect,
            BluetoothGattCallback callback, int transport,
            boolean opportunistic, int phy, Handler handler) {
        BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
        // managerService是Binder代理对象,它对应的本地对象是个叫BLUETOOTH_MANAGER_SERVICE("bluetooth_manager")的Binder组件,
        // 整系统只有一个,即所有app共用一个BluetoothAdapter本地对象。
        IBluetoothManager managerService = adapter.getBluetoothManager();
        try {
            IBluetoothGatt iGatt = managerService.getBluetoothGatt();
            if (iGatt == null) {
                // BLE is not supported
                return null;
            }
            // 创建一个 BluetoothGatt 对象
            BluetoothGatt gatt = new BluetoothGatt(
                    iGatt, this, transport, opportunistic, phy, mAttributionSource);
            // 发起连接
            gatt.connect(autoConnect, callback, handler);
            return gatt;
        } catch (RemoteException e) {
            Log.e(TAG, "", e);
        }
        return null;
    }

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

接下来看gatt.connect()的实现。

<aosp>/frameworks/base/core/java/android/bluetooth/BluetoothGatt.java
------
    boolean connect(Boolean autoConnect, BluetoothGattCallback callback,
            Handler handler) {
        synchronized (mStateLock) {
            // 判断当前连接状态
            if (mConnState != CONN_STATE_IDLE) {
                throw new IllegalStateException("Not idle");
            }
            mConnState = CONN_STATE_CONNECTING;
        }

        mAutoConnect = autoConnect;
        // 这里向底层注册上层的应用
        if (!registerApp(callback, handler)) {
            synchronized (mStateLock) {
                mConnState = CONN_STATE_IDLE;
            }
            Log.e(TAG, "Failed to register callback");
            return false;
        }

        // The connection will continue in the onClientRegistered callback
        return true;
    }

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

<aosp>/frameworks/base/core/java/android/bluetooth/BluetoothGatt.java
------
    private boolean registerApp(BluetoothGattCallback callback, Handler handler) {
        return registerApp(callback, handler, false);
    }

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

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

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

        return true;
    }

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

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

<aosp>/frameworks/base/core/java/android/bluetooth/BluetoothGatt.java
------
    private final IBluetoothGattCallback mBluetoothGattCallback =
            new IBluetoothGattCallback.Stub() {
                /**
                 * Application interface registered - app is ready to go
                 * @hide
                 */
                @Override
                @SuppressLint("AndroidFrameworkRequiresPermission")
                public void onClientRegistered(int status, int clientIf) {
                    mClientIf = clientIf;
                    if (status != GATT_SUCCESS) {
                        // 注册客户端失败,通知到应用的callback
                        runOrQueueCallback(new Runnable() {
                            @Override
                            public void run() {
                                final BluetoothGattCallback callback = mCallback;
                                if (callback != null) {
                                    callback.onConnectionStateChange(BluetoothGatt.this,
                                            GATT_FAILURE,
                                            BluetoothProfile.STATE_DISCONNECTED);
                                }
                            }
                        });

                        synchronized (mStateLock) {
                            mConnState = CONN_STATE_IDLE;
                        }
                        return;
                    }
                    try {
                        // 这里开始做真正的连接操作了
                        mService.clientConnect(mClientIf, mDevice.getAddress(),
                                !mAutoConnect, mTransport, mOpportunistic,
                                mPhy, mAttributionSource); // autoConnect is inverse of "isDirect"
                    } catch (RemoteException e) {
                        Log.e(TAG, "", e);
                    }
                }

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

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

 

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

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

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

<aosp>/frameworks/base/core/java/android/bluetooth/BluetoothAdapter.java
------
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,代码在 <aosp>/frameworks/base/services/java/com/android/server/BluetoothManagerService.java。

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

<aosp>/frameworks/base/services/java/com/android/server/BluetoothManagerService.java
------
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 intermediate_off = (prevState == BluetoothAdapter.STATE_TURNING_OFF
         && newState == BluetoothAdapter.STATE_BLE_ON);
      if (newState == BluetoothAdapter.STATE_OFF) {
          ...
      } else if (!intermediate_off) {
        // connect to GattService
        if (mBluetoothGatt != null) {
          if (DBG) Slog.d(TAG, "Calling BluetoothGattServiceUp");
          onBluetoothGattServiceUp();
        } else { 
          // if (mContext.getPackageManager().hasSystemFeature(
          //        PackageManager.FEATURE_BLUETOOTH_LE)) {
          Intent i = new Intent(IBluetoothGatt.class.getName());
          doBind(i, mConnection, Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT, UserHandle.CURRENT);
        }
        sendBleStateChanged(prevState, newState);
        // Don't broadcase this as std intent
        isStandardBroadcast = false;
      } else {
          ...
      }
    }
  }
}

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

<aosp>/packages/apps/Bluetooth/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>

doBind原来是绑定到了com.android.bluetooth.gatt.GattService。如果绑定成功,会回调mConnection的 onServiceConnected(),其实现如下:

<aosp>\frameworks\base\services\core\java\com\android\server\BluetoothManagerService.java
------
private class BluetoothServiceConnection implements ServiceConnection {
  public void onServiceConnected(ComponentName className, IBinder service) {  
    String name = componentName.getClassName();
    Message msg = mHandler.obtainMessage(MESSAGE_BLUETOOTH_SERVICE_CONNECTED);
    ...
    if (name.equals("com.android.bluetooth.btservice.AdapterService")) {
      msg.arg1 = SERVICE_IBLUETOOTH;
    } else if (name.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怎么处理的:

<aosp>/frameworks/base\services/core/java/com/android/server/BluetoothManagerService.java
------
private class BluetoothHandler extends Handler {
  @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;
        mBluetoothLock.writeLock().lock();
        if (msg.arg1 == SERVICE_IBLUETOOTHGATT) {
          mBluetoothGatt = IBluetoothGatt.Stub.asInterface(service);
          onBluetoothGattServiceUp();
          break;
        }
        ...
      }
    }
  }
}

最终获得 IBluetoothGatt 的 Binder代理对象,并赋值给mBluetoothGatt,最后通过getBluetoothGatt,返回给前面的BluetoothGatt。

<aosp>/frameworks/base\services/core/java/com/android/server/BluetoothManagerService.java
------
public IBluetoothGatt getBluetoothGatt() {
    // sync protection
    return mBluetoothGatt;
}

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

 

三、蓝牙服务:com.android.bluetooth.gatt.GattService

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

<aosp>/packages/apps/Bluetooth/src/com/android/bluetooth/gatt/GattService.java
------
    private static class BluetoothGattBinder extends IBluetoothGatt.Stub
            implements IProfileServiceBinder {
        public void registerClient(ParcelUuid uuid, IBluetoothGattCallback callback,
                boolean eatt_support, AttributionSource attributionSource) {
            GattService service = getService();
            if (service == null) {
                return;
            }
            service.registerClient(uuid.getUuid(), callback, eatt_support, attributionSource);
        }

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

<aosp>/packages/apps/Bluetooth/src/com/android/bluetooth/gatt/GattService.java
------
    void registerClient(UUID uuid, IBluetoothGattCallback callback, boolean eatt_support,
            AttributionSource attributionSource) {
        if (!Utils.checkConnectPermissionForDataDelivery(
                this, attributionSource, "GattService registerClient")) {
            return;
        }

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

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

private native void gattClientRegisterAppNative(long appUuidLsb, long appUuidMsb, boolean eatt_support);

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

 

四、蓝牙服务和HAL的调用:JNI

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

<aosp>/packages/apps/Bluetooth/src/com/android/bluetooth/btservice/AdapterApp.java
------
public class AdapterApp extends Application {
  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。

<aosp>/packages/apps/Bluetooth/jni/com_android_bluetooth_gatt.cpp
------
static JNINativeMethod sMethods[] = {
    ...
    {"gattClientRegisterAppNative", "(JJZ)V",
     (void*)gattClientRegisterAppNative},
    ...
};

这是注册JN 函数的标准方法,也是在该cpp,可以找到对应的函数实现。

static void gattClientRegisterAppNative(JNIEnv* env, jobject object,
                                        jlong app_uuid_lsb, jlong app_uuid_msb,
                                        jboolean eatt_support) {
  if (!sGattIf) return;
  Uuid uuid = from_java_uuid(app_uuid_msb, app_uuid_lsb);
  sGattIf->client->register_client(uuid, eatt_support);
}

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

static const btgatt_interface_t *sGattIf = NULL;

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

<aosp>/packages/apps/Bluetooth/jni/com_android_bluetooth_gatt.cpp
------
static const btgatt_interface_t* sGattIf = NULL;
static const bt_interface_t* btIf;

static void initializeNative(JNIEnv* env, jobject object) {
  if (btIf) return;

  btIf = getBluetoothInterface();
  ...

  sGattIf =
      (btgatt_interface_t*)btIf->get_profile_interface(BT_PROFILE_GATT_ID);
  if (sGattIf == NULL) {
    error("Failed to get Bluetooth GATT Interface");
    return;
  }

  ...
}

通过以上代码,能知道sGattIf来自btIf,btIf是个指向bt_interface_t结构的指针,值来自getBluetoothInterface()。getBluetoothInterface简单返回一个全局变量sBluetoothInterface,而赋值sBluetoothInterface发生在classInitNative。

<aosp>/packages/apps/Bluetooth/jni/com_android_bluetooth_btservice_AdapterService.cpp
------
static const bt_interface_t* sBluetoothInterface = NULL;

const bt_interface_t* getBluetoothInterface() { return sBluetoothInterface; }

static void classInitNative(JNIEnv* env, jclass clazz) {
  ...

  if (hal_util_load_bt_library((bt_interface_t const**)&sBluetoothInterface)) {
    ALOGE("No Bluetooth Library found");
  }
}

com.android.bluetooth在构造“.btservice.AdapterService”这个service时会调用classInitNative,进而给sBluetoothInterface赋值。这个赋值时机发生在Android启动时的初始化阶段。给sBluetoothInterface赋值的函数是hal_util_load_bt_library。

<aosp>/packages/apps/Bluetooth/jni/com_android_bluetooth_btservice_AdapterService.cpp
------
int hal_util_load_bt_library(const bt_interface_t** interface) {
  const char* sym = BLUETOOTH_INTERFACE_STRING;
  bt_interface_t* itf = nullptr;

  // The library name is not set by default, so the preset library name is used.
  void* handle = dlopen("libbluetooth.so", RTLD_NOW);
  if (!handle) {
    const char* err_str = dlerror();
    ALOGE("%s: failed to load Bluetooth library, error=%s", __func__,
          err_str ? err_str : "error unknown");
    goto error;
  }

  // Get the address of the bt_interface_t.
  itf = (bt_interface_t*)dlsym(handle, sym);
  if (!itf) {
    ALOGE("%s: failed to load symbol from Bluetooth library %s", __func__, sym);
    goto error;
  }

  // Success.
  ALOGI("%s: loaded Bluetooth library successfully", __func__);
  *interface = itf;
  return 0;

error:
  *interface = NULL;
  if (handle) dlclose(handle);

  return -EINVAL;
}

HAL模块会被编译成一个*.so。一般来说,HAL模块为让它人使用,需要向外export一个和struct hw_module_t相关的变量,使用者则调用hw_get_module得到这个变量。但是,bt_interface_t在定义上和hw_module_t没关系,但逻辑上差不多。

  1. 蓝牙HAL模块被编译成libbluetooth.so。依协议,libbluetooth.so必须向外EXPORT_SYMBOL一个bt_interface_t类型全局变量。
  2. (hal_util_load_bt_library)dlopen打开libbluetooth.so
  3. (hal_util_load_bt_library)用dlsym得到libbluetooth.so中那个bt_interface_t类型的变量,并让itf指向这个变量,也就是sBluetoothInterface。

已经知道libbluetooth.so必须向外EXPORT_SYMBOL一个bt_interface_t类型全局变量,那这变量是什么。

<aosp>/system/bt/btif/src/bluetooth.cc
------
EXPORT_SYMBOL bt_interface_t bluetoothInterface = {
    sizeof(bluetoothInterface),
    init,
    enable,
    disable,
    cleanup,
    ...
    get_profile_interface,  // get_profile_interface
    ...
};

JNI中的sBluetoothInterface就是这个libbluetooth.so中的bluetoothInterface全局变量,为得到sGattIf,JNI调用btIf->get_profile_interface(BT_PROFILE_GATT_ID))。

<aosp>/system/bt/btif/src/bluetooth.c
------
static const void* get_profile_interface(const char* profile_id) {
  LOG_INFO("%s: id = %s", __func__, profile_id);

  ......
  // BT_PROFILE_GATT_ID是个宏,它的值是字符串:gatt
  if (is_profile(profile_id, BT_PROFILE_GATT_ID))
    return btif_gatt_get_interface();

  return NULL;
}

<aosp>/system/bt/btif/src/btif_gatt.cc
------
static btgatt_interface_t btgattInterface = {
    .size = sizeof(btgattInterface),

    .init = btif_gatt_init,
    .cleanup = btif_gatt_cleanup,

    .client = &btgattClientInterface,
    .server = &btgattServerInterface,
    .scanner = nullptr,    // filled in btif_gatt_get_interface
    .advertiser = nullptr  // filled in btif_gatt_get_interface
};

const btgatt_interface_t* btif_gatt_get_interface() {
  btgattInterface.scanner = get_ble_scanner_instance();
  btgattInterface.advertiser = get_ble_advertiser_instance();
  return &btgattInterface;
}

然后在btif_gatt_client.c,找到btgattClientInterface具体的实现。

<aosp>/system/bt/btif/src/btif_gatt_client.cc
------
const btgatt_client_interface_t btgattClientInterface = {
    btif_gattc_register_app,   // => register_client
    btif_gattc_unregister_app, // => unregister_client
    btif_gattc_open,           // => connect
    btif_gattc_close,          // => disconnect
    ...
};

于是可得出结论,针对JNI层中的“sGattIf->client->register_client(&uuid)”,sGattIf对应着HAL中的btgattInterface,sGattIf->client对应着btgattClientInterface结构,register_client是该结构中的btif_gattc_register_app字段,当然,它的类型是函数。

全部评论: 0

    写评论: