編輯:關於Android編程
按照慣例,我們看一下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; }
首先是配置文件: 活動中的代碼如下: package com.itydl.rwinrom;import jav
今天我們來接觸一下多線程下載,當然也包括斷點續傳,我們可以看到很多下載器,當開通會員的時候下載東西的速度就變得快了許多,這是為什麼呢?這就是跟今天講的多線程有關系了,其實
小編一直任務將web和android組件結合起來做應用可以事半功倍,html5一來就更有說服力了,特別是對於以前從事web開發的兄弟來說 1. webview加入布局文件
今天我們來一起學習一下緩存技術,相信大家做開發的時候都知道請求網絡數據的重要,但是有一些只用請求一次就過時性的消息比如某些新聞信息,如果我們每次進入新聞界面