droidvm软件开发手册v1.0 名词约定: ================================================================= 宿主系统——安卓 虚拟系统——由运行于安卓中的droidvm虚拟出来的ubuntu系统 虚拟电脑(droidvm) 简介 ================================================================= droidvm 由 闭源的 droidvm apk 和 开源的linux-installer-for-droidvm 两个项目组成 droidvm 的这两个项目分别使用不同的许可协议,具体如下: 1. 闭源的 droidvm apk 项目: 安卓包名为: com.zzvm 由柳州正卓软件有限公司开发,柳州正卓软件有限公司对这个项目的全部内容保留所有权利 发布为一个apk安装包 2. 开源的 linux-installer-for-droidvm 项目: 由柳州正卓软件有限公司开发,这个项目使用MIT许可协议 项目托管地址:https://gitee.com/yelam2022/linux-installer-for-droidvm 发布为一个zip压缩包 proot简介 ================================================================= 不需要root权限的chroot工具。 用proot启动其它程序时,可以指定一个文件夹,来做为被启动程序的根目录(/) 其它基于namespaces原理的类似工具:unshare, lxc, lxd 需要root权限的类似工具:chroot 虚拟系统的限制: ================================================================= 受安卓权限系统的限制,虚拟系统也有如下限制: 1). 单个apk应用的进程数不能超过30个(可在开发者模式下解除此限制) 2). netstat 之类的需要高权限的、跟内核有关的指令无法运行 3). 如果需要在模拟器中访问SD卡内的文件,则apk的存储权限要在安卓系统中授予 4). 无法使用<1024的端口号, lsmod之类的指令没权限使用 5). 无法使用shmem,安卓认为shmem不安全,但可以使用mmap映射文件 6). 没有systemd 7). 无法查看cpu使用率,但可以通过手机的开发者选项查看(adb shell "top") 8). 虚拟机内文件系统的权限无法隔离 9). 无法运行.netcore 用户系统: ================================================================= 虚拟系统中的所有用户 都 对应于app在安卓系统中的uid app在安卓系统中的uid: $APP_ANDROID_UID $APP_ANDROID_USERNAME 不论在虚拟系统中如何su, uid 如何变, 进程都始终对于 $APP_ANDROID_UID 也就是文件系统的权限无法按虚拟系统中的用户进行隔离, 不能真正做到切换用户,毕竟不是qemu,bochs之类的真正的虚拟机. 好在这些都可以接受,而且效率比纯虚拟机要快多了. 综上,文件系统无法基于用户进行权限隔离,虚拟系统中的sandbox不可用。 模拟器的图形显示环境: ================================================================= Xvfb 做 x11-server jwm 做 窗口管理器 pcmanfm 做 虚拟桌面和文件管理器 若需安装xfce4,请先卸载jwm,不然xfce4可能会起不来, 指令如下: sudo apt remove -y jwm sudo apt install -y --no-install-recommends xfce4 然后运行指令: echo "1" > ${app_home}/app_boot_config/cfg_use_xfce4.txt 最后重启APP. 附: echo "0" > ${app_home}/app_boot_config/cfg_use_xfce4.txt # 不启动xfce4 测试对比发现,同样是在桌面上拖动窗口,xfce4 比 JWM 更顺畅。 但进程也多了几个。 通过adb shell解除安卓对应用最大可用进程数的限制(手机重启后得重新解除) ================================================================= adb.exe shell dumpsys activity settings | grep max_phantom_processes adb.exe shell device_config set_sync_disabled_for_tests persistent adb.exe shell device_config put activity_manager max_phantom_processes 512 adb.exe shell dumpsys activity settings | grep max_phantom_processes shell入口文件: ================================================================= ${app_home}/droidvm_main.sh 此脚本由安卓端应用中的C代码调用, 关联的pty可以查看${APP_STDIO_NAME}环境变量 安卓端应用通过生成三个sh文件, 对虚拟系统提供环境变量: ================================================================= ${app_home}/droidvm_vars_setup.sh 用户选择的安装选项[0,1,2] ${app_home}/droidvm_vars.sh 最关键的数据 ${app_home}/droidvm_fbwh.sh 当前显示器的分辨率 (支持手机原屏显示、外接显示、webcontrol显示) 查看其它环境变量 set|grep APP 查看屏幕分辨率 set|grep SCREEN 安装脚本文件: ================================================================= 所在目录: ${app_home}/default_setup_scripts/ 1). setup_droid_console_only.sh 2). setup_linux_console_only.sh 3). setup_linux_fullx11.sh 三个文件分别处理三个安装选项[0,1,2] 0 => 仅安卓控制台 1 => ubuntu,不带图形界面 2 => ubuntu,以及图形界面 自启动文件: ================================================================= 所在目录: ${tools_dir}/ 1). vm_onstarted.sh 不建议改动 2). vm_onXstarted.sh 不建议改动 3). vm_onZerogo.sh 可以改动 vm_onstarted.sh 是刚进入系统时由root用户的.bashrc调用的 vm_onXstarted.sh 是x11环境启动完了以后,由startvm.sh调用的 vm_onZerogo.sh 是最后被调用的自启动脚本,用来告诉app系统已经启动完成了,并且调用用户设置的启动代码 完整的启动流程: ================================================================= 安卓端应用 -> ${app_home}/droidvm_main.sh -> ${app_home}/droidvm_bootup.sh -> ${tools_dir}/setup_linux.sh -> ${tools_dir}/startvm.sh ${tools_dir}/vm_onstarted.sh -> #客选启动项 ${tools_dir}/vm_startx.sh ${tools_dir}/vm_onXstarted.sh -> ${tools_dir}/vm_onZerogo.sh 宿主系统和虚拟系统之间的目录共享: ================================================================= 通过使用proot软件的-b参数,安卓系统可以与虚拟系统共享指定的文件目录 默认已将宿主端的: ${app_home} 映射为虚拟系统中的 ${app_home} /system/fonts/ 映射为虚拟系统中的 /usr/share/fonts/truetype/droid ${app_home}/ipc目录 ================================================================= control 安卓端应用通过这个管道文件,把触屏事件传给虚拟系统 notify 虚拟端系统通过这个管道文件,向应用告知自己的运行状态 screenupdated 虚拟端系统通过这个管道文件,向应用通知桌面已重绘 Xvfb_screen0 虚拟端系统通过这个mmapfile,向应用提供只读的framebuffer ${vmCpuArchId} ${vmGraphicsx} 两个环境变量代表安装时用户所选择的项目 ================================================================= vmCpuArchId 代表用户选装的CPU架构: 0: arm64 1: amd64 vmGraphicsx 代表用户选装的CPU架构: 0: 不装图形显示界面 1: 安装图形显示界面 ubuntu 22.10 rootfs 中的3D支持: ================================================================= apt仓库默认选用mesa 22.2.5(opengl) mesa22.2.5已支持这两种 GALLIUM_DRIVER llvmpipe - cpu指令实现的gl绘图 virpipe - virgl 其中 virgl 架构走socket, 分srv和client,效率非常低. 在安卓上安装 glmark2.apk 在此模拟器中安装 glmark2 对这两种方式的跑分结果进行对比 发现virgl仅能发挥出原生gl库约10%的性能, 但仍比 llvmpipe 要快一点点, 而且 adb shell top发现CPU使用率也低很多 virgl c/s 通信用的socket文件: ================================================================= /tmp/.virgl_test 这个socket文件由运行于安卓端的 virglrenderer 创建, 经查阅源码,发现监听端口号为1 模拟器中的mesa gl 库,加载时会检查GALLIUM_DRIVER环境变量 若为virpipe,则通过 /tmp/.virgl_test 这个socket文件所绑定的信息, 去连接 virgl 的 server 端。 ubuntu 22.10 rootfs 中对wine的支持: ================================================================= wine能够在多种兼容POSIX接口的操作系统上运行同CPU架构的windows程序。 通过 sudo apt install wine 指令 ubuntu-arm64 能安装 wine-arm64, 然后能运行windows-arm64的程序 ubuntu-amd64 能安装 wine-amd64, 然后能运行windows-amd64的程序 若想在 ubuntu-arm64 里面安装 wine-amd64,则需要安装box64 若想在 ubuntu-arm64 里面安装 wine-x86, 则需要安装box86, 以及启用multi-arch 虚拟电脑已内置box和wine的安装脚本 box86/64是个只能运行于linux-arm64中的程序, 不过,借助box86/64,可以在linux-arm64系统中, 运行linux-i386/amd64架构的linux程序 -- 比如wine-amd64 我们编译了box86/64,并按照他们建议的方法安装跨CPU架构的wine,但发现都有问题。 经多次测试,我们仍不能解决跨CPU架构运行wine的问题。 所以我们建议不要直接使用wine,而是使用其它基于wine开发的更易安装的wine前端工具。 比如: playonlinux, Bottles, wine助手 与box类似的软件有: qemu-user exagear FEX 的FEXInterpreter https://github.com/FEX-Emu/FEX FEX和qemu-user以及box86类似 FEX原生支持rootfs, 无需使用chroot # 启动wine文件浏览器 wine explorer # 启动wine虚拟桌面 wine explorer /desktop=shell,${RECOMMEND_SCREEN_WIDTH}x${RECOMMEND_SCREEN_HEIGHT}