[Android源碼分析]bluez internal event的處理

在上面2.1中是hci dev的註冊和up2.3中有bluez的初始化,這兩者是有一個交集的,那就是說bluez初始化後會監聽hci dev的一些event,主要有HCI_DEV_REGHCI_DEV_UP兩個比較重要,那本集就是主要分析這兩個event帶來的影響。

         從上面的分析中,我們已經知道,這兩個event的處理函數是io_stack_event

static gboolean io_stack_event(GIOChannel *chan, GIOCondition cond,
								gpointer data)
{
	unsigned char buf[HCI_MAX_FRAME_SIZE], *ptr;
	evt_stack_internal *si;
	evt_si_device *sd;
	hci_event_hdr *eh;
	int type, fd;
	ssize_t len;

	ptr = buf;

	fd = g_io_channel_unix_get_fd(chan);
	//讀取event的內容
	len = read(fd, buf, sizeof(buf));
	if (len < 0) {
		if (errno == EAGAIN)
			return TRUE;

		error("Read from control socket failed: %s (%d)",
						strerror(errno), errno);
		return FALSE;
	}

	type = *ptr++;

	if (type != HCI_EVENT_PKT)
		return TRUE;

	eh = (hci_event_hdr *) ptr;
//判斷是否是internal的event
	if (eh->evt != EVT_STACK_INTERNAL)
		return TRUE;

	ptr += HCI_EVENT_HDR_SIZE;

	si = (evt_stack_internal *) ptr;
	switch (si->type) {
	case EVT_SI_DEVICE:
		sd = (void *) &si->data;
	//event的處理
		device_event(sd->event, sd->dev_id);
		break;
	}

	return TRUE;
}
static void device_event(int event, int index)
{
	switch (event) {
	//device register後的操作,詳細見2.4.1
	case HCI_DEV_REG:
		info("HCI dev %d registered", index);
		init_device(index, FALSE);
		break;
	//unreg,不做詳細分析
	case HCI_DEV_UNREG:
		info("HCI dev %d unregistered", index);
		stop_hci_dev(index);
		if (devs[index].registered)
			btd_manager_unregister_adapter(index);
		break;
	//device up的操作,詳細分析見2.4.2
	case HCI_DEV_UP:
		info("HCI dev %d up", index);
		devs[index].up = TRUE;
		device_devup_setup(index);
		break;
	//Down的操作
	case HCI_DEV_DOWN:
		info("HCI dev %d down", index);
		devs[index].up = FALSE;
		devs[index].pending_cod = 0;
		devs[index].cache_enable = TRUE;
		if (!devs[index].pending) {
			struct btd_adapter *adapter;

			adapter = manager_find_adapter_by_id(index);
			if (adapter)
				btd_adapter_stop(adapter);

			init_pending(index);
		}
		break;
	}
}


 

2.4.1 device register後的bluez的操作分析

         這個函數是bluez收到底層hci dev registe的消息之後的操作。事實上,因爲init_known_adapters的存在,這裏可能都沒有走到。不過,在上面init_known_adapters中我們也沒有分析這個函數,這裏我們分析一下吧,反正這個函數終歸是要走的。

static struct dev_info *init_device(int index, gboolean already_up)
{
	struct dev_info *dev;
	struct hci_dev_req dr;
	int dd;
	pid_t pid;

	DBG("hci%d", index);
	//open hci device
	//其實就是建一個hci對應的socket,並bind,返回的dd就是socket的句柄
	dd = hci_open_dev(index);
	if (dd < 0) {
		error("Unable to open hci%d: %s (%d)", index,
						strerror(errno), errno);
		return NULL;
	}
	//max_dev默認爲0,申請對應的空間
	if (index > max_dev) {
		max_dev = index;
		devs = g_realloc(devs, sizeof(devs[0]) * (max_dev + 1));
	}
	//初始化devcie的info,見2.4.1.1
	dev = init_dev_info(index, dd, FALSE, already_up);
	//設置device的pending位,把dev->pending的bdaddr,version,features和name都置位
	init_pending(index);
	//開始hci device,這裏會對一系列的event進行監聽,具體見2.4.1.2
	start_hci_dev(index);
	//已經up了,就不需要做什麼了
/* Avoid forking if nothing else has to be done */
	if (already_up)
		return dev;

	/* Do initialization in the separate process */
//fork一個進程出來繼續,子進程繼續下去,父進程這裏直接返回device
	pid = fork();
	switch (pid) {
		case 0:
		//註冊一個子進程退出時調用的函數
			atexit(at_child_exit);
			break;
		//fork出錯,直接返回device,注意這裏沒有break
		case -1:
			error("Fork failed. Can't init device hci%d: %s (%d)",
					index, strerror(errno), errno);
		default:
		//父進程直接返回device
			DBG("child %d forked", pid);
			return dev;
	}
	memset(&dr, 0, sizeof(dr));
	dr.dev_id = index;
//根據配置的link mode來進行設置,默認的link policy(7)是不支持park的,支持sniff,roleswitch和hold
	/* Set link mode */
	dr.dev_opt = main_opts.link_mode;
	if (ioctl(dd, HCISETLINKMODE, (unsigned long) &dr) < 0)
		error("Can't set link mode on hci%d: %s (%d)",
						index, strerror(errno), errno);
	//這裏會再次up,其實之前在bluetoothd啓動之前的enable_native中已經up過了,所以這裏應該沒有什麼了
	/* Start HCI device */
	if (ioctl(dd, HCIDEVUP, index) < 0 && errno != EALREADY) {
		error("Can't init device hci%d: %s (%d)",
					index, strerror(errno), errno);
		goto fail;
	}

	hci_close_dev(dd);
	exit(0);

fail:
	hci_close_dev(dd);
	exit(1);
}


 

至此,device registerbluezkernel中的所有操作就都完成了。

 

2.4.1.1 device info的初始化

         static struct dev_info *init_dev_info(int index, int sk, gboolean registered,

                                                                 gboolean already_up)

{

         struct dev_info *dev = &devs[index];

         //初始化wie0

         memset(dev, 0, sizeof(*dev));

 

         dev->id = index; //id就是0,就是hci0

         dev->sk = sk;    //和剛剛建立的socket綁定

         dev->cache_enable = TRUE;    //cache enable置位true

         dev->registered = registered; //registered爲false

         dev->already_up = already_up;       //already up是傳入的值,這裏理論上應該是false

         dev->io_capability = 0x03; /* No Input No Output */ //no input no output

         dev->discov_state = DISCOV_HALTED; //初始化discovery的state爲DISCOV_HALTED,這個狀態的轉變我們在inquiry的時候再詳細分析

 

         return dev;

}


 

2.4.1.2  hci devicestart

         這個函數說白了就是對一系列的event進行監聽,這也是我們後期能夠對event處理的關鍵前提所在。

 

static void start_hci_dev(int index)
{
	struct dev_info *dev = &devs[index];
	GIOChannel *chan = dev->io;
	GIOCondition cond;
	struct hci_filter flt;

	if (chan)
		return;

	info("Listening for HCI events on hci%d", index);
	//對下面一系列的event進行處理
	/* Set filter */
	hci_filter_clear(&flt);
	hci_filter_set_ptype(HCI_EVENT_PKT, &flt);
	hci_filter_set_event(EVT_CMD_STATUS, &flt);
	hci_filter_set_event(EVT_CMD_COMPLETE, &flt);
	hci_filter_set_event(EVT_PIN_CODE_REQ, &flt);
	hci_filter_set_event(EVT_LINK_KEY_REQ, &flt);
	hci_filter_set_event(EVT_LINK_KEY_NOTIFY, &flt);
	hci_filter_set_event(EVT_RETURN_LINK_KEYS, &flt);
	hci_filter_set_event(EVT_IO_CAPABILITY_REQUEST, &flt);
	hci_filter_set_event(EVT_IO_CAPABILITY_RESPONSE, &flt);
	hci_filter_set_event(EVT_USER_CONFIRM_REQUEST, &flt);
	hci_filter_set_event(EVT_USER_PASSKEY_REQUEST, &flt);
	hci_filter_set_event(EVT_REMOTE_OOB_DATA_REQUEST, &flt);
	hci_filter_set_event(EVT_USER_PASSKEY_NOTIFY, &flt);
	hci_filter_set_event(EVT_KEYPRESS_NOTIFY, &flt);
	hci_filter_set_event(EVT_SIMPLE_PAIRING_COMPLETE, &flt);
	hci_filter_set_event(EVT_AUTH_COMPLETE, &flt);
	hci_filter_set_event(EVT_REMOTE_NAME_REQ_COMPLETE, &flt);
	hci_filter_set_event(EVT_READ_REMOTE_VERSION_COMPLETE, &flt);
	hci_filter_set_event(EVT_READ_REMOTE_FEATURES_COMPLETE, &flt);
	hci_filter_set_event(EVT_REMOTE_HOST_FEATURES_NOTIFY, &flt);
	hci_filter_set_event(EVT_INQUIRY_COMPLETE, &flt);
	hci_filter_set_event(EVT_INQUIRY_RESULT, &flt);
	hci_filter_set_event(EVT_INQUIRY_RESULT_WITH_RSSI, &flt);
	hci_filter_set_event(EVT_EXTENDED_INQUIRY_RESULT, &flt);
	hci_filter_set_event(EVT_CONN_REQUEST, &flt);
	hci_filter_set_event(EVT_CONN_COMPLETE, &flt);
	hci_filter_set_event(EVT_DISCONN_COMPLETE, &flt);
	hci_filter_set_event(EVT_LE_META_EVENT, &flt);
	if (setsockopt(dev->sk, SOL_HCI, HCI_FILTER, &flt, sizeof(flt)) < 0) {
		error("Can't set filter on hci%d: %s (%d)",
						index, strerror(errno), errno);
		return;
	}
	//處理的函數是io_security_event。所以,後期的一系列event上來之後,我們在這裏還需要進行一次處理,其實上文中的up過程中的event,是不需要再走這邊的,因爲在up的時候bluetoothd還沒有啓動,這裏肯定是還沒有註冊了
	chan = g_io_channel_unix_new(dev->sk);
	cond = G_IO_IN | G_IO_NVAL | G_IO_HUP | G_IO_ERR;
	dev->watch_id = g_io_add_watch_full(chan, G_PRIORITY_LOW, cond,
						io_security_event,
						GINT_TO_POINTER(index), NULL);
	dev->io = chan;
	dev->pin_length = 0;

}


 

2.4.2 device up後的bluez的操作分析

         這個函數device up之後bluez的需要進行的各種操作。

static void device_devup_setup(int index)
{
	struct dev_info *dev = &devs[index];
	struct hci_dev_info di;
	read_stored_link_key_cp cp;

	DBG("hci%d", index);
	//得到kernel中的device info,並初始化到di中
	if (hci_devinfo(index, &di) < 0)
		return;
	//檢查是否是bredr或者device_raw被置位
	if (ignore_device(&di))
		return;
	//拷貝kernel中的bdaddr和features
	bacpy(&dev->bdaddr, &di.bdaddr);
	memcpy(dev->features, di.features, 8);

	/* Set page timeout */
	if ((main_opts.flags & (1 << HCID_SET_PAGETO))) {
		write_page_timeout_cp cp;

		cp.timeout = htobs(main_opts.pageto);
		//這裏會發送write page timeout的cmd,所以,我們要修改page timeout,就可以通過修改main_opts.pageto來實現,他是可以通過main.conf修改來得到的
		hci_send_cmd(dev->sk, OGF_HOST_CTL, OCF_WRITE_PAGE_TIMEOUT,
					WRITE_PAGE_TIMEOUT_CP_SIZE, &cp);
	}
	bacpy(&cp.bdaddr, BDADDR_ANY);
	cp.read_all = 1;
	//發送read stored link key的cmd
	hci_send_cmd(dev->sk, OGF_HOST_CTL, OCF_READ_STORED_LINK_KEY,
					READ_STORED_LINK_KEY_CP_SIZE, &cp);
	//若是沒有pending的內容,就init_adapter了。
	//我們從上面的分析中知道,這裏是有一個pending version的,所以這裏先不急,我們來分析一下上面共3個cmd,他們的response所帶來的影響。分別是read local version information和write page timeout以及read stored link key。
	if (!dev->pending)
		init_adapter(index);
}


 

2.4.2.1 read local version informationresponse的影響。

         kernel中這個event的影響我們已經分析,不再累述。我們只分析bluez這裏的處理:

他的處理在io_security_event中的command complete中有分析:

case cmd_opcode_pack(OGF_INFO_PARAM, OCF_READ_LOCAL_VERSION):
		ptr += sizeof(evt_cmd_complete);
		read_local_version_complete(index, ptr);
		break;

所以就是read_local_version_complete這個函數了:

static void read_local_version_complete(int index,
				const read_local_version_rp *rp)
{
	struct dev_info *dev = &devs[index];

	if (rp->status)
		return;
	//得到device的一些信息
	dev->ver.manufacturer = btohs(bt_get_unaligned(&rp->manufacturer));
	dev->ver.hci_ver = rp->hci_ver;
	dev->ver.hci_rev = btohs(bt_get_unaligned(&rp->hci_rev));
	dev->ver.lmp_ver = rp->lmp_ver;
	dev->ver.lmp_subver = btohs(bt_get_unaligned(&rp->lmp_subver));
	//若是沒有設置pending位,則直接return
	if (!dev->pending)
		return;
	//否則,就把pending version的位清空
	hci_clear_bit(PENDING_VERSION, &dev->pending);

	DBG("Got version for hci%d", index);
	//沒有其他pending了,且up了,就需要init adapter了,所以,我們終歸是要走到init_adapter的。所以這個函數的分析見2.3.2.4
	if (!dev->pending && dev->up)
		init_adapter(index);
}


 

2.4.2.2 write page timeoutresponse的分析

         依然是command complete,我們會發現,其實我們什麼都沒有做。包括kernel中也沒有做。

2.4.2.3 read stored link keyresponse的分析

         這個和2.4.2.2是一樣的。所以什麼都沒有做。

 

2.4.2.4 init_adapter函數的分析

         這個函數就是adapter的初始化了

static gboolean init_adapter(int index)
{	//得到對應device的info
	struct dev_info *dev = &devs[index];
	struct btd_adapter *adapter = NULL;
	gboolean existing_adapter = dev->registered;
	uint8_t mode, on_mode;
	gboolean pairable, discoverable;
	//從上面我們知道dev->registered是false,所以會走if中的resister,就是還沒有註冊過,就先register,否則就是find,意味着已經註冊過了
	if (!dev->registered) {
		//見下面的2.4.2.4.1
		adapter = btd_manager_register_adapter(index);
		if (adapter)
			dev->registered = TRUE;
	} else {
		adapter = manager_find_adapter(&dev->bdaddr);
		/* FIXME: manager_find_adapter should return a new ref */
		btd_adapter_ref(adapter);
	}
	//沒有創建成功,就直接return false了
	if (adapter == NULL)
		return FALSE;
	//設置mode,on_mode以及pairable的值,見2.4.2.4.2
	btd_adapter_get_mode(adapter, &mode, &on_mode, &pairable);
//這個地方是false,所以不會進這個if
	if (existing_adapter)
		mode = on_mode;
//不是mode off,所以,不會進
	if (mode == MODE_OFF) {
		hciops_power_off(index);
		goto done;
	}
	//這個就是通過一系列的cmd來啓動adapter了,詳細見2.4.2.4.3
	start_adapter(index);
	//繼續start adapter,詳細分析2.4.2.4.4
	btd_adapter_start(adapter);
	//因爲我們這裏目前的mode是connectable,所以,discoverable是0
	discoverable = (mode == MODE_DISCOVERABLE);
	//write scan enable,然後mode是scan_page就是2
	hciops_set_discoverable(index, discoverable);
	//設置pairable的值
	hciops_set_pairable(index, pairable);
	//這裏就是發送inquiry cancel的command
	if (dev->already_up)
		hciops_stop_inquiry(index);
	//以上一共有兩個cmd,分別是write scan enable,inquiry cancel。這兩個cmd的event的分析見2.4.2.4.5
done:
	btd_adapter_unref(adapter);
	return TRUE;
}

 

若您覺得該文章對您有幫助,請在下面用鼠標輕輕按一下“頂”,哈哈~~·

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章