按照惯例,我们看一下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通道了,这个过程是一个很繁琐的过程,也是一个很核心的过程,晓东会在下一篇文章中和大家详细分析。
若您觉得该文章对您有帮助,请在下面用鼠标轻轻按一下“顶”,哈哈~~·