spice-gtk是里面有一个spicy的测试工具,可以直接用来远程连接虚拟机代替remote-viewer,但是spicy远程连接的虚拟机却不能自动加载插入的usb设备,下面简单解析一下spice-gtk中关于usb的代码.
usb-device-manager.c
下面是usb-device-manager.c中几个重要的函数调用:spice_usb_device_manager_initable_init初始化了一个回调函数spice_usb_device_manager_hotplug_cb当检测到usb接入和拔出的时候就会调用这个回调函数,之后再调用spice_usb_device_manager_hotplug_idle_cb里面又调用了下面这两个函数spice_usb_device_manager_add_dev和spice_usb_device_manager_remove_dev一个是插一个是拔。
usb-device-manager.c这个文件和spice-session是关联的,session启动的时候起来一个spice-channel,其实就是usb-device-manager.c(这个类似一个channel-display.c)里面的,里面有一个spice_usb_device_manager_add_dev这个函数就是channel检测到有usb之后执行的任务。函数里面有一个判断 if (priv->auto_connect)如果这个执行,就会自动连接usb的,如果不执行那就需要在上面的input的menu菜单里面点击usb设置选择usb以后才能重定向usb spice_usb_device_manager_add_dev最后发射:
g_signal_emit(self, signals[DEVICE_ADDED], 0, device);信号传输给usb-deivce-widget.c里面
其实我们考虑auto_connect变量是哪边给赋值的呢,只要我们从根源给这个变量设置成ture其实就不需要上述操作了,根据我的寻找在spice-gtk-session.c里面的spice_gtk_session_set_property会设置此变量,在case PROP_AUTO_USBREDIR时,将s->auto_usbredir_enable写死为true即可。
usb-device-widget.c
在这个里面收到信号的时候就会在这个widget类中添加这个usb的界面按钮,spicy窗口上面有一个input菜单栏,点击之后会出现一个选择usb设备的窗口,如果说上文不执行auto_connect那就需要你点击按钮以后才会将usb重定向,如果上文执行auto_connect,那就直接给你按钮按下去了,自动重定向连接usb。
虚拟机重新连接的时候不能直接重定向所有的usb设备
上述操作仅仅在虚拟机正常连接spice之后才能进行,虚拟机在刚连接的时候如果u盘是插着的,那么这个u盘是不会被重定向到虚拟机里面的,需要重新插拔一下,因为spice_usb_device_manager_add_dev执行的时候auto_connect还没被赋值,或者说即使auto_connect被强制赋值成true,usb重定向的时候也会因为某些错误而失败。最终将usb重定向到虚拟机中的函数是spice_usb_device_manager_connect_device_async。
实现连接虚拟机时自动重定向已经插着的usb
上文说到usb在插着的时候连接虚拟机是不会被重定向的,需要重新插拔,那么怎样去实现自动识别呢?在这个地方我自己实现了一个spice_usb_device_manager_connect_device_async的包装,在spicy.c中包装了一个函数想办法去调用usb-device-manager.c中的spice_usb_device_manager_connect_device_async实现自动连接usb。在spice_usb_device_manager_add_dev中有这样一行代码g_ptr_array_add(priv->devices, device);是指将刚检测到的usb设备存储到devices这个数组中以供后面的使用,usb-device-widget.c中的界面启动的时候界面上就会列举已经插着的u盘让你去选择连接,其实这边列举的时候就是讲devices里面的usb设备读取出来的。我们在usb-device-manager.c中实现了下面的代码:
void spice_usb_device_manager_connect_all_usb_device(SpiceUsbDeviceManager *self)
{
SpiceUsbDeviceManagerPrivate *priv = self->priv;
guint i;
for (i = 0; i < priv->devices->len; i++) {
SpiceUsbDevice *device = g_ptr_array_index(priv->devices, i);
spice_usb_device_manager_connect_device_async(self,
device, NULL,
spice_usb_device_manager_auto_connect_cb,
spice_usb_device_ref(device));
}
printf("device num = %d\n", (int)i);
}
这里实现了将devices里面的所有usb设备都进行重定向,spice_usb_device_manager_connect_device_async重定向的根本函数,那应该在哪里调用呢?我们写的这个函数在调用的时候需要在所有资源都初始化完成之后才能调用成功,在spic-session.c中加上这么一个函数:
void spice_session_connect_all_usb_device(SpiceSession *session)
{
SpiceUsbDeviceManager *manager = spice_usb_device_manager_get(session, NULL);
if (manager)
spice_usb_device_manager_connect_all_usb_device(manager);
}
之后再在spicy.c中这样调用:
spice_session_connect_all_usb_device(conn->session);//连接所有usb
但是关键问题是这行代码到底放在spicy.c中的哪个地方呢?
connection_connect里面不行调用的时候devices还是空的;g_message("main channel: opened");这个后面,也不行,提示usb重定向失败,应该还是某些资源没初始化完成;只有放在全屏按钮触发的函数里面才会生效,所以之后usb到底在开机后多久才能自己连上呢?才能调用重定向usb的操作呢??还是有待研究!
请阅读《spice-gtk之usb相关代码(2)》: