termux使用proot构建ubuntu20.04(非proot-distro),并搭建.net10的开发编译环境
具体操作步骤如下:
下载
ubuntu-base-20.04.5-base-arm64.tar
地址
https://cdimage.ubuntu.com/ubuntu-base/releases/focal/release/
通过WinScp拷贝到android 的termux目录下(/data/data/com.termux/files/home)
解压到目标目录
tar --numeric-owner -zxvf ubuntu-base-20.04.5-base-arm64.tar.gz -C ubuntu2004/ubuntu-fs/
构建proot启动脚本
#---------------------------------------------------------------------------------------
#!/data/data/com.termux/files/usr/bin/bash
cd $(dirname $0)
## 取消可能导致冲突的环境变量
unset LD_PRELOAD
command="proot"
command+=" --link2symlink"
command+=" -0"
command+=" -r ubuntu-fs"
## 挂载基础系统目录
command+=" -b /dev"
command+=" -b /proc"
command+=" -b /sys"
command+=" -b ubuntu-fs/tmp:/dev/shm"
## 挂载手机存储(移除引起路径冲突的全局根目录 / 挂载)
command+=" -b /data/data/com.termux"
command+=" -b /sdcard"
command+=" -b /storage"
## 设置运行环境与标准的 Ubuntu 20.04 环境变量
command+=" -w /root"
command+=" /usr/bin/env -i"
command+=" HOME=/root"
command+=" PATH=/usr/local/sbin:/usr/local/bin:/bin:/usr/bin:/sbin:/usr/sbin:/usr/games:/usr/local/games"
command+=" TERM=$TERM"
command+=" LANG=C.UTF-8"
command+=" /bin/bash --login"
# 支持外部命令直接输入执行
com="$@"
if [ -z "$1" ];then
exec $command
else
$command -c "$com"
fi
#---------------------------------------------------------------------------------------------------------------------------
给予权限
sudo chmod +x start_chroot.sh
sudo ./start_chroot.sh
登录后group id报错信息解决
echo "aid_inet:x:3003:root" >> /etc/group
echo "aid_everybody:x:9997:root" >> /etc/group
echo "aid_u0_a362:x:20362:root" >> /etc/group
echo "aid_u0_a362_cache:x:50362:root" >> /etc/group
登录后环境配置
apt update
apt upgrade
apt install busybox
apt install nano
apt install net-tools
apt install iputils-ping
(dotnet 依赖环境)
apt install -y build-essential
apt install -y libicu66
apt install wget
遇到不能联网,执行下面命令来指定dns
echo "nameserver 223.5.5.5" > /etc/resolv.conf
下载SDK
wget https://builds.dotnet.microsoft.com/dotnet/Sdk/10.0.301/dotnet-sdk-10.0.301-linux-arm64.tar.gz
mkdir -p $HOME/dotnet && tar zxf dotnet-sdk-10.0.301-linux-arm64.tar.gz -C $HOME/dotnet
增加环境变量
export DOTNET_ROOT=$HOME/dotnet
export PATH=$PATH:$HOME/dotnet
# proot下需要额外加入这行,解决GC堆内存限制
export DOTNET_GCHeapHardLimit=1C0000000
#建议proot下加入如下环境,解决该环境下Socket对外联网工作异常的问题(依然需要root)
export DOTNET_SYSTEM_NET_SOCKETS_INLINE_COMPLETIONS=0
#建议proot下添加下面的代码,避免后台编译VBCSCompiler进程不能退出的问题
alias exit='pkill -9 -f VBCSCompiler; pkill -9 -P $$; builtin exit'
关于网络配置解释(export DOTNET_SYSTEM_NET_SOCKETS_INLINE_COMPLETIONS=0):
在 Linux 系统上,.NET 为了实现极高的并发网络吞吐量,其 System.Net.Sockets 核心库默认开启了 Inline Completions(内联完成) 机制。
- 开启时(.NET 默认行为): 当 Socket 发生 I/O 事件时,.NET 会通过底层的 epoll 线程池直接在当前 I/O 线程中“就地(Inline)”触发并回调 C# 代码中的 Task 状态机。这减少了线程上下文切换(Thread Context Switch)的开销。
- 在 PRoot 中为什么会挂: PRoot 依靠 ptrace 来拦截和翻译每一次网络系统调用。当 .NET 的多个高性能 I/O 线程在非常底层的级别同时尝试内联触发事件,并疯狂交织进行 epoll_wait、setsockopt 时,PRoot 的用户态仿真层(模拟内核)无力应对如此高并发且复杂的底层调用同步,导致线程锁死、系统调用被 PRoot 挂起,或者因时序混乱被 Android 内核误判为非法越权。
- 关闭后(设置=0): .NET 会被迫放弃这个极限网络优化。所有的 Socket 事件完成通知不再“内联”执行,而是乖乖地被扔回 .NET 全局的 ThreadPool(普通线程池) 中,由独立的标准工作线程去排队调度。
微软文档:
DOTNET_SYSTEM_NET_SOCKETS_*
This section highlights two System.Net.Sockets environment variables:
- DOTNET_SYSTEM_NET_SOCKETS_INLINE_COMPLETIONS
- DOTNET_SYSTEM_NET_SOCKETS_THREAD_COUNT
DOTNET_SYSTEM_NET_SOCKETS_INLINE_COMPLETIONS (default disabled) allows socket continuations to run on the event thread instead of being dispatched to the ThreadPool, potentially enhancing performance but risking IO thread blockage. [1]
DOTNET_SYSTEM_NET_SOCKETS_THREAD_COUNT allows overriding default, high-load optimized thread calculations (30 x64 / 8 Arm64 per engine) for scenarios with extreme request volumes. [1]
- If INLINE_COMPLETIONS is 1, Environment.ProcessorCount is used.
- Otherwise, it defaults to 8 for Arm/Arm64, or 30 for others, determined by RuntimeInformation.ProcessArchitecture. [1]
另外.net 编译程序能正常联网的前提,需要使用sudo启动脚本,没有管理员权限,在联网或安装时,都可能遇到问题,这也是直接用脚本构建proot的原因。
测试
dotnet --version
安装SVN
apt install -y subversion
拉取代码,编译测试
安装ubuntu24.04时,libicu可以选择libicu74(libicu-dev太大)
另外尝试了下,proot-distro也可以加sudo 去启动,解决.net 程序的对外网络连接的问题。
proot-distro的安装后的文件系统路径比较难找,这里附带下:
/data/data/com.termux/files/usr/var/lib/proot-distro/containers/debian
路径比较难找,这也是为嘛要用脚本构建的原因,编译后程序直接rootfs中找。
浙公网安备 33010602011771号