Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> [Android源碼分析]jni層之下的配對分析

[Android源碼分析]jni層之下的配對分析

編輯:關於Android編程

?? 4、createPairedDeviceNative

按照慣例,我們看一下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;
}

 

 

 

 

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved