按照慣例,我們看一下jni層,這次也沒有什麼特別的,唯一需要注意的就是一個android的iocapability的設置。
static jboolean createPairedDeviceNative(JNIEnv *env, jobject object,
jstring address, jint timeout_ms) {
LOGV("%s", __FUNCTION__);
#ifdef HAVE_BLUETOOTH
native_data_t *nat = get_native_data(env, object);
jobject eventLoop = env->GetObjectField(object, field_mEventLoop);
struct event_loop_native_data_t *eventLoopNat =
get_EventLoop_native_data(env, eventLoop);
if (nat && eventLoopNat) {
const char *c_address = env->GetStringUTFChars(address, NULL);
LOGV("... address = %s", c_address);
char *context_address = (char *)calloc(BTADDR_SIZE, sizeof(char));
//Android的io capability時displayyesno
const char *capabilities = "DisplayYesNo";
const char *agent_path = "/android/bluetooth/remote_device_agent";
strlcpy(context_address, c_address, BTADDR_SIZE); // for callback
//就是調用bluez中的CreatePairedDevice method
bool ret = dbus_func_args_async(env, nat->conn, (int)timeout_ms,
onCreatePairedDeviceResult, // callback
context_address,
eventLoopNat,
get_adapter_path(env, object),
DBUS_ADAPTER_IFACE,
"CreatePairedDevice",
DBUS_TYPE_STRING, &c_address,
DBUS_TYPE_OBJECT_PATH, &agent_path,
DBUS_TYPE_STRING, &capabilities,
DBUS_TYPE_INVALID);
env->ReleaseStringUTFChars(address, c_address);
return ret ? JNI_TRUE : JNI_FALSE;
}
#endif
return JNI_FALSE;
}
所以,很明顯,就是去調用bluez中的CreatePairedDevicemethod,去bluez中看一看吧。
5、bluez中CreatePairedDevice的分析
搜索一下就會發現createPairedDevice對應的method表如下:
{ "CreatePairedDevice", "sos", "o", create_paired_device,
G_DBUS_METHOD_FLAG_ASYNC},
我們直接分析create_paired_device這個函數:
static DBusMessage *create_paired_device(DBusConnection *conn,
DBusMessage *msg, void *data)
{
struct btd_adapter *adapter = data;
struct btd_device *device;
const gchar *address, *agent_path, *capability, *sender;
uint8_t cap;
int err;
if (dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &address,
DBUS_TYPE_OBJECT_PATH, &agent_path,
DBUS_TYPE_STRING, &capability,
DBUS_TYPE_INVALID) == FALSE)
return btd_error_invalid_args(msg);
//這個其實在上層已經check過了,這裏不過再次做一下而已
if (check_address(address) < 0)
return btd_error_invalid_args(msg);
//檢查adapter 是否up
if (!adapter->up)
return btd_error_not_ready(msg);
//檢查sender是否合法
sender = dbus_message_get_sender(msg);
if (adapter->agent &&
agent_matches(adapter->agent, sender, agent_path)) {
error("Refusing adapter agent usage as device specific one");
return btd_error_invalid_args(msg);
}
//解析iocapability,上層android那邊傳過來的是displayyesno
cap = parse_io_capability(capability);
if (cap == IO_CAPABILITY_INVALID)
return btd_error_invalid_args(msg);
//得到對應的device
device = adapter_find_device(adapter, address);
if (!device) {
device = create_device_internal(conn, adapter, address, &err);
if (!device)
return btd_error_failed(msg, strerror(-err));
}
//若不是le,則開始bonding
if (device_get_type(device) != DEVICE_TYPE_LE)
//詳細分析見5.1
return device_create_bonding(device, conn, msg,
agent_path, cap);
//下面是le的,暫時不管
err = device_browse_primary(device, conn, msg, TRUE);
if (err < 0)
return btd_error_failed(msg, strerror(-err));
return NULL;
}
5.1 device_create_bonding的分析
DBusMessage *device_create_bonding(struct btd_device *device,
DBusConnection *conn,
DBusMessage *msg,
const char *agent_path,
uint8_t capability)
{
char filename[PATH_MAX + 1];
char *str, srcaddr[18], dstaddr[18];
struct btd_adapter *adapter = device->adapter;
struct bonding_req *bonding;
bdaddr_t src;
int err;
adapter_get_address(adapter, &src);
ba2str(&src, srcaddr);
ba2str(&device->bdaddr, dstaddr);
//看device是否正在bonding
if (device->bonding)
return btd_error_in_progress(msg);
//看是否有linkkeys
/* check if a link key already exists */
create_name(filename, PATH_MAX, STORAGEDIR, srcaddr,
"linkkeys");
str = textfile_caseget(filename, dstaddr);
if (str) {
free(str);
//若是已經有linkkeys了,就不再進行下去了
return btd_error_already_exists(msg);
}
//調用hciops中的create bonding,詳細分析見5.2
err = adapter_create_bonding(adapter, &device->bdaddr, capability);
if (err < 0)
return btd_error_failed(msg, strerror(-err));
//新建一個bonding request
bonding = bonding_request_new(conn, msg, device, agent_path,
capability);
if (!bonding) {
adapter_cancel_bonding(adapter, &device->bdaddr);
return NULL;
}
//加入一個disconnect的watch,就是監聽這個connection的斷開的
bonding->listener_id = g_dbus_add_disconnect_watch(conn,
dbus_message_get_sender(msg),
create_bond_req_exit, device,
NULL);
device->bonding = bonding;
bonding->device = device;
return NULL;
}
5.2 hciops中的create_bonding分析
static int hciops_create_bonding(int index, bdaddr_t *bdaddr, uint8_t io_cap)
{
struct dev_info *dev = &devs[index];
BtIOSecLevel sec_level;
struct bt_conn *conn;
GError *err = NULL;
//得到connection,若是沒有新建一個bt_conn的結構體
conn = get_connection(dev, bdaddr);
//看是否在忙
if (conn->io != NULL)
return -EBUSY;
//賦值iocapability
conn->loc_cap = io_cap;
/* If our IO capability is NoInputNoOutput use medium security
* level (i.e. don't require MITM protection) else use high
* security level */
//android使用的是high security
if (io_cap == 0x03)
sec_level = BT_IO_SEC_MEDIUM;
else
sec_level = BT_IO_SEC_HIGH;
//建立L2RAW的connect,參數就是src,dst,sec level,詳細分析見5.3
conn->io = bt_io_connect(BT_IO_L2RAW, bonding_connect_cb, conn,
NULL, &err,
BT_IO_OPT_SOURCE_BDADDR, &dev->bdaddr,
BT_IO_OPT_DEST_BDADDR, bdaddr,
BT_IO_OPT_SEC_LEVEL, sec_level,
BT_IO_OPT_INVALID);
if (conn->io == NULL) {
error("bt_io_connect: %s", err->message);
g_error_free(err);
return -EIO;
}
//bonding初始化ok的標誌位的設置
conn->bonding_initiator = TRUE;
return 0;
}
5.3、L2RAW connection的建立分析
GIOChannel *bt_io_connect(BtIOType type, BtIOConnect connect,
gpointer user_data, GDestroyNotify destroy,
GError **gerr, BtIOOption opt1, ...)
{
GIOChannel *io;
va_list args;
struct set_opts opts;
int err, sock;
gboolean ret;
//解析得到對應的參數
va_start(args, opt1);
ret = parse_set_opts(&opts, gerr, opt1, args);
va_end(args);
if (ret == FALSE)
return NULL;
//創建io,詳細見5.4的分析
io = create_io(type, FALSE, &opts, gerr);
if (io == NULL)
return NULL;
//得到對應的socket
sock = g_io_channel_unix_get_fd(io);
switch (type) {
case BT_IO_L2RAW:
//connect,詳細見5.8
err = l2cap_connect(sock, &opts.dst, 0, opts.cid);
break;
case BT_IO_L2CAP:
err = l2cap_connect(sock, &opts.dst, opts.psm, opts.cid);
break;
case BT_IO_RFCOMM:
err = rfcomm_connect(sock, &opts.dst, opts.channel);
break;
case BT_IO_SCO:
err = sco_connect(sock, &opts.dst);
break;
default:
g_set_error(gerr, BT_IO_ERROR, BT_IO_ERROR_INVALID_ARGS,
"Unknown BtIO type %d", type);
return NULL;
}
if (err < 0) {
g_set_error(gerr, BT_IO_ERROR, BT_IO_ERROR_CONNECT_FAILED,
"connect: %s (%d)", strerror(-err), -err);
g_io_channel_unref(io);
return NULL;
}
//加入connection
connect_add(io, connect, user_data, destroy);
return io;
}
5.4 io的創建
static GIOChannel *create_io(BtIOType type, gboolean server,
struct set_opts *opts, GError **err)
{
int sock;
GIOChannel *io;
switch (type) {
//IO L2RAW是建立L2CAP的socket
case BT_IO_L2RAW:
//l2cap socket的創建,這個就是在kernel層實現的了,具體分析見5.5
sock = socket(PF_BLUETOOTH, SOCK_RAW, BTPROTO_L2CAP);
if (sock < 0) {
ERROR_FAILED(err, "socket(RAW, L2CAP)", errno);
return NULL;
}
//bind,具體分析見5.6
//server若是false,則爲0,否則要提供psm
if (l2cap_bind(sock, &opts->src, server ? opts->psm : 0,
opts->cid, err) < 0)
goto failed;
//設置一些參數,根據參數進行配置 ,具體分析見5.7
//sec level時high,force_active=1
if (!l2cap_set(sock, opts->sec_level, 0, 0, 0, -1, -1, opts->force_active,
err))
goto failed;
break;
……
//創建一個io channel
io = g_io_channel_unix_new(sock);
//當沒有ref的時候就把這個channel關閉
g_io_channel_set_close_on_unref(io, TRUE);
//io non block的
g_io_channel_set_flags(io, G_IO_FLAG_NONBLOCK, NULL);
return io;
failed:
close(sock);
return NULL;
}
所以,基本就是要建L2CAP通道了,這個過程是一個很繁瑣的過程,也是一個很核心的過程,曉東會在下一篇文章中和大家詳細分析。
若您覺得該文章對您有幫助,請在下面用鼠標輕輕按一下“頂”,哈哈~~·