桌面虚拟化传输协议之android spice

文章目录

  1. 1. 背景
  2. 2. SPICE 协议在android平台的应用

背景

云计算是目前计算机领域的一个热门领域,桌面虚拟化是其中的一个重要应用,即把桌面系统在服务器端虚拟化,然后通过传输协议传输数据到客户端来实现桌面虚拟化,这样的好处就在于不管用什么设备,只要通过客户端都可以访问到云端的系统,随时随地都可以在一个系统上工作。

目前有两大标准的桌面传输协议,分别是RBP和RDP。

  • RBP有一个简单的架构,即直接把虚拟机的图形数据直接传输给客户端,客户端直接显示图像,有点类似于看网络视频。这样子就对网络的要求较高,高延迟情况下效果很差,但是客户端压力比较小,因此对客户机的性能要求较低,毕竟它只负责显示图像。

RBP

  • RDP稍微复杂一点,使用的是图像局部刷新,它发送事件消息给客户端,提示需要刷新的图像区域并且提供数据,客户端根据消息数据生成图像数据显示出来。因此传输的数据量较少,适合于网络不好情况,但是缺点是客户端需要生成图像数据,对客户机有一定压力。

RDP

那么对于移动设备来说,很显然,RDP协议更适合移动设备,因为移动设备在3G,4G情况下不可能用耗费大流量的RFB协议,并且延迟比较高。而RDP协议由于传输的数据量较少,对网络条件要求不高。所以,针对于移动平台来说,RDP协议比较合适。

但是,由于RDP协议是微软的产品,受限于其证书,并不是开源产品,所以不能用于移动设备。那么,开源的类RDP协议的SPICE协议,就隆重登场了,结合我们的主题,在android平台上应用spice协议。下面,我们来介绍spice在android平台上的应用。

SPICE 协议在android平台的应用

Spice事实上并没有android版本,但是它有linux版本,而android是基于linux的,所以,我们可以通过使用NDK来交叉编译Spice库到android上使用。也就是说,我们可以通过使用JNI来调用libspice.so(通过NDK交叉编译),从而在android平台上使用Spice。

android spice

Spice服务器通过通道(Channel)来与客户端通信,其中jpeg模块是通过NDK编译好的库,使用JNI调用,把服务器发送过来图像命令转化为图像,再把图像交给android的View显示出来。

在实际使用中,需要对图像的解析过程进行优化,否则显示的延迟很大。一个解决方案是使用更快的jpeg解析库。

最后,推荐一个开源的spice安卓客户端remote-desktop-clients

以上只是对Spice工作原理的简单描述,详细介绍查看官方文档:

  • spice_for_newbies
  • spice入门(这是我根据spice官方文档翻译的中文版本)

spice源码分析之server(1)

By Yonah-潇

发表于 2015-08-19

文章目录

  1. 1. Spice简介
  2. 2. Spice server
    1. 2.1. 部分宏定义
    2. 2.2. 公共函数
    3. 2.3. VDI接口
    4. 2.4. Channel
    5. 2.5. Dispatcher
    6. 2.6. RedWorker
  3. 3. 总结

前言:本文是结合我自己阅读代码的心得总结而来,同时会忽略很多细节,只能作为阅读源码时的参考.如有错误,欢迎指正.

Spice简介

Spice是一个开源的云计算解决方案,使客户端能显示远程虚拟主机的操作界面并且使用其设备,如键盘,鼠标,声音等。Spice给用户提供了一种如同操作本地机器一样的体验,同时尽可能把密集的CPU和GPU任务在客户端上执行。Spice能在局域网和互联网间使用,而不减少用户体验。
图0

Spice的基本组成包括:

  • Spice协议
  • Spice服务器
  • Spice客户端

Spice的相关组件包括:

  • QXL设备
  • QXL驱动

其中,Spice服务器基于libspice(一个虚拟设备接口可插拔库)。VDI提供了一个通过软件组件来发布虚拟设备接口的标准方式,使得软件组件能够与虚拟设备交互。

  • 服务器使用Spice协议与客户端交互。
  • 服务器通过VDI接口与VDI主机程序(如QEMU)交互。

也就是说spice服务器处于主机与客户端中间,是整个Spice的核心所在.下面我们开始从代码层面分析spice服务器
更多资料查看本人翻译的spice新手文档Spice入门,以及官方网站

Spice server

图1
图1是spice服务器的核心架构,贯穿整个源码的组织结构.
值得一提的是,spice server是作为一个库提供给qemu使用的,编译出来就是libspice,所以代码中没有main函数.
下面我们先了解一个server源码中使用到的一些核心概念,在看源码之前推荐大家先看一遍Spice入门,否则理解代码中的某些核心概念会很吃力.

部分宏定义

  • SPICE_GNUC_DEPRECATED,其定义是#define SPICE_GNUC_DEPRECATED __attribute__((__deprecated__))表示该函数以及被弃用,在编译时会给出警告
  • SPICE_GNUC_VISIBLE,其定义是#define SPICE_GNUC_VISIBLE __attribute__ ((visibility ("default")))用于控制符号的可见性,设置为对外可见.spice作为动态链接库给qemu使用,默认隐藏函数对外部的可见性,即外部文件不能调用库里面的函数,有这个声明的函数可以被外部文件调用,即为公共函数.

公共函数

Server的公共函数主要在两个头文件中:

  • spice.h:与SpiceServer结构体相关的函数,是qemu调用spice的主要函数
  • red_dispatcher.h:与QXL设备相关的函数

对server的分析,主要围绕这三个公共函数:

  • spice_server_init:负责初始化spice_server
  • spice_server_add_interface:给server注册VDI接口
  • spice_server_add_client:处理qemu接收到的客户端连接消息

VDI接口

从图1中可以看到,VDI接口是spice server离qemu最近的一层,qemu主要是通过VDI接口来与spice交互的.
VDI接口的定义在spice.h中,结构体内部的函数指针实现都在qemu的源码里面(ui/spice-core.c)

  • SpiceCoreInterface:核心接口,用于创建,添加,取消定时和监听事件

    12345678
    SpiceTimer *(*timer_add)(SpiceTimerFunc func, void *opaque);void (*timer_start)(SpiceTimer *timer, uint32_t ms);void (*timer_cancel)(SpiceTimer *timer);void (*timer_remove)(SpiceTimer *timer);SpiceWatch *(*watch_add)(int fd, int event_mask, SpiceWatchFunc func, void *opaque);void (*watch_update_mask)(SpiceWatch *watch, int event_mask);void (*watch_remove)(SpiceWatch *watch);void (*channel_event)(int event, SpiceChannelEventInfo *info);
  • QXLInterface:QXL设备接口

    123456789101112131415161718
    void (*attache_worker)(QXLInstance *qin, QXLWorker *qxl_worker);void (*set_compression_level)(QXLInstance *qin, int level);void (*set_mm_time)(QXLInstance *qin, uint32_t mm_time);void (*get_init_info)(QXLInstance *qin, QXLDevInitInfo *info);int (*get_command)(QXLInstance *qin, struct QXLCommandExt *cmd);int (*req_cmd_notification)(QXLInstance *qin);void (*release_resource)(QXLInstance *qin, struct QXLReleaseInfoExt release_info);int (*get_cursor_command)(QXLInstance *qin, struct QXLCommandExt *cmd);int (*req_cursor_notification)(QXLInstance *qin);void (*notify_update)(QXLInstance *qin, uint32_t update_id);int (*flush_resources)(QXLInstance *qin);void (*async_complete)(QXLInstance *qin, uint64_t cookie);void (*update_area_complete)(QXLInstance *qin, uint32_t surface_id,struct QXLRect *updated_rects,uint32_t num_updated_rects);void (*set_client_capabilities)(QXLInstance *qin,uint8_t client_present,uint8_t caps[58]);/* returns 1 if the interface is supported, 0 otherwise. * if monitors_config is NULL nothing is done except reporting the * return code. */int (*client_monitors_config)(QXLInstance *qin,VDAgentMonitorsConfig *monitors_config);
  • SpiceCharDeviceInterface:字符型设备接口

    1234
    void (*state)(SpiceCharDeviceInstance *sin, int connected);int (*write)(SpiceCharDeviceInstance *sin, const uint8_t *buf, int len);int (*read)(SpiceCharDeviceInstance *sin, uint8_t *buf, int len);void (*event)(SpiceCharDeviceInstance *sin, uint8_t event);
  • SpiceKbdInterface:键盘接口

    12
    void (*push_scan_freg)(SpiceKbdInstance *sin, uint8_t frag);uint8_t (*get_leds)(SpiceKbdInstance *sin);
  • SpiceMigrateInterface:迁移接口

    12
    void (*migrate_connect_complete)(SpiceMigrateInstance *sin);void (*migrate_end_complete)(SpiceMigrateInstance *sin);
  • SpiceMouseInterface:鼠标接口

    12
    void (*motion)(SpiceMouseInstance *sin, int dx, int dy, int dz,uint32_t buttons_state);void (*buttons)(SpiceMouseInstance *sin, uint32_t buttons_state);
  • SpiceTabletInterface:触摸板接口

    1234
    void (*set_logical_size)(SpiceTabletInstance* tablet, int width, int height);void (*position)(SpiceTabletInstance* tablet, int x, int y, uint32_t buttons_state);void (*wheel)(SpiceTabletInstance* tablet, int wheel_moution, uint32_t buttons_state);void (*buttons)(SpiceTabletInstance* tablet, uint32_t buttons_state);
  • SpicePlaybackInterface:声音接口

  • SpiceRecordInterface:录音接口

Channel

从图1可以看到,VDI接口之后即是Channel(QXLInterface比较特殊,这个后面再说).
Channel的主要作用是使用对应的TCP连接传输消息给客户端,保证其传输的可靠性,其本质是通道,不同的Channel传输不同的消息.

spice中主要有六种Channel:

  • MainChannel:与客户端连接的建立和断开有关
  • InputsChannel:跟鼠标,键盘,触摸板的输入有关
  • DisplayChannel:跟图像传输有关
  • CursorChannel:跟鼠标指针的显示有关
  • PlaybackChannel:跟播放宿机的声音有关
  • RecordChannel:跟录制客户端的声音有关

这六种Channel并不是平行的关系,虽然都继承与RedChannel,但是在实现以及逻辑上的作用有很大不同,大致可以分成三类.

  • Main和Input通道被相应的处理函数控制(reds.c)
  • Display和Cursor通道被每个display工作线程使用(red_worker.c)
  • Playback和Record通道有它们各自的处理程序(snd_worker.c)

六种Channel中只有DisplayChannel和CursorChannel是单独在工作线程工作的,其他都是在qemu线程工作.

Dispatcher

图3
前面提到Channel负责传输消息,而Dispatcher则负责处理消息,并且调度Channel.
Dispatcher使用socketpair来与外界交互,例如监听事件,传输结果等.
这里存在两种Dispatcher

  • MainDispatcher:在qemu线程中监听socket事件,处理客户端连接的初始化,建立和断开等,跟MainChannel相关
  • RedDispatcher:在worker线程中监听socket事件,处理QXL设备有关的消息,跟DisplayChannel,CursorChannel相关,图3描述的就是RedDispatcher的工作流程.在图1我们看到QXLInterface与其他接口不一样,与Channel的联系中间多了一个RedDispatcher,它们在单独的Worker线程中工作,提供了QEMU与接收的图像命令处理和渲染过程的独立性

RedWorker

RedWorker可以说是server的核心,80%代码跟它有关,毕竟它负责图像渲染和传输,这是spice最难最复杂的部分,涉及图像的压缩,渲染,局部刷新等核心技术.
RedWorker在单独线程上工作,通过QXLInterface与QEMU的QXL设备直接交互,同时控制DisplayChannel,CursorChannel,并且拥有自己的poll事件驱动核心.而其他的Channel都依赖于QEMU线程.

总结

  • Spice server作为一个库给QEMU调用,用于支持Spice协议.
  • server通过使用VDI接口与QEMU交互
  • server通过使用Channel与客户端交互
  • Dispatcher用于处理消息
  • Channel用于传输消息
  • 图像在RedWorker线程中处理

以上是我分析的server源代码的核心概念,为了方便理解,描述并不全面.其中关于迁移,声音,录音等功能并没有看过,我主要关注server的工作原理,在了解它工作流程之后,就好比有了一张地图,剩下的就是一个个去探险了.
当然了,没有代码的分析就是耍流氓.这篇就当是开胃菜,之后,我会结合代码,分析server的启动流程以及工作流程.先挖个坑.

桌面虚拟化传输协议之android spice及spice源码分析之server(1)相关推荐

  1. linux虚拟化桌面协议,桌面虚拟化传输协议之android spice

    背景 云计算是目前计算机领域的一个热门领域,桌面虚拟化是其中的一个重要应用,即把桌面系统在服务器端虚拟化,然后通过传输协议传输数据到客户端来实现桌面虚拟化,这样的好处就在于不管用什么设备,只要通过客户 ...

  2. Android 11.0 Settings源码分析 - 主界面加载

    Android 11.0 Settings源码分析 - 主界面加载 本篇主要记录AndroidR Settings源码主界面加载流程,方便后续工作调试其流程. Settings代码路径: packag ...

  3. Android上百实例源码分析以及开源分析集合打包

    感谢网友banketree的收集,压缩包的内容如下: 1.360新版特性界面源代码 实现了360新版特性界面的效果,主要涉及到Qt的一些事件处理与自定义控件.但源码好像是c++. 2.aidl跨进程调 ...

  4. Android Camera 系统架构源码分析

    Android Camera 系统架构源码分析(1)---->Camera的初始化 Android Camera 系统架构源码分析(2)---->Camera的startPreview和s ...

  5. Android 系统(78)---《android framework常用api源码分析》之 app应用安装流程

    <android framework常用api源码分析>之 app应用安装流程 <android framework常用api源码分析>android生态在中国已经发展非常庞大 ...

  6. Android录音下————AudioRecord源码分析

    Android录音下----AudioRecord源码分析 文章目录 Android录音下----AudioRecord源码分析 一.概述 1.主要分析点 2.储备知识 二.getMinBufferS ...

  7. Android 8.0系统源码分析--Camera processCaptureResult结果回传源码分析

    相机,从上到下概览一下,真是太大了,上面的APP->Framework->CameraServer->CameraHAL,HAL进程中Pipeline.接各种算法的Node.再往下的 ...

  8. Android 双开沙箱 VirtualApp 源码分析(一)

    最近发现了一个非常好的开源项目,基本实现了一个 Android 上的沙箱环境,不过应用场景最多的还是应用双开. VA github: https://github.com/asLody/Virtual ...

  9. Android 双开沙箱 VirtualApp 源码分析(六)ContentProvider

    上一章:Android 双开沙箱 VirtualApp 源码分析(五)BroadcastReceiver Provider 注册 回顾前面,Activity 启动的时候会检查 Application ...

  10. Android 双开沙箱 VirtualApp 源码分析(二)

    Android 双开沙箱 VirtualApp 源码分析(二) VA 初始化 先看一下代码: VirtualCore.startup public void startup(Context conte ...

最新文章

  1. 我的Dll(动态链接库)学习笔记
  2. 自动化测试里的数据驱动和关键字驱动思路的理解
  3. 神策 2021 数据驱动大会「积分有礼」榜单今日揭晓!快来看看你排第几?
  4. 使用Java读取 “Python写入redis” 的数据踩坑记录
  5. 使用Spring Data Cassandra缓存的预备语句
  6. 《FPGA全程进阶---实战演练》第二十一章 电源常用类型:LDO和 DCDC
  7. 解决:Xshell如何修改默认的登录用户,自动跳转到密码界面
  8. Java基础篇(05):函数式编程概念和应用
  9. merry chrismas
  10. 关于线性字符串匹配的算法-----KMP的算法
  11. 中间件技术是一种计算机游戏,游戏界面中间件有哪些
  12. python 英语翻译 excel_Excel自动翻译
  13. 新萝卜家园 Ghost XP SP3 电脑城装机专用版 10.5
  14. 解决FireFox(火狐浏览器)占用资…
  15. Android apk下载与安装
  16. 设计师:设计师的知识储备之异形曲面设计 巴洛克、洛可可 设计理论(三角形构图、平衡式构图、三分法构图 、九宫格构图)之详细攻略
  17. 中层领导力:西点军校和哈佛大学共同讲授的领导力教程读书摘要
  18. fast路由器服务器未响应,迅捷(FAST)无线路由器设置好了上不了网的解决方法
  19. keep-alive 组件缓存的用法
  20. jenkins更换初始登录密码

热门文章

  1. 站内优化第一篇:页面标签对于网站SEO的重要性
  2. 机器人最新天赋符文天赋加点图_机器人天赋符文s9
  3. 香港一卡通攻略:取款省4倍手续费
  4. 赵小楼《天道》《遥远的救世主》深度解析(109)天下乌鸦一般黑,不要幻想
  5. 如何使用keepalive实现虚拟IP
  6. java公路车的气嘴_5分钟了解运动自行车常见的两种气嘴
  7. 什么是NLP,NLP主要有什么用,为什么要学自然语言处理?
  8. Python NLP 自然语言处理
  9. 用.net制作排序、分页及多条记录选择及删除的范例(不用.net内置的分页和排序机制)
  10. 用FAI制作debian自动安装盘