1. 前言
目前国产化系统浪潮下,适配鸿蒙是中国软件大势所趋,.net作为最适合开发客户端语言之一,适配鸿蒙系统(harmonyos next)是目前.net开发者最关心的事情。我目前业余时间正在移植avalonia到harmonyos,去年在.net conf cn上分享过,目前又取得一点进展,所以本文把所有问题进行整合与大家进行分享。
2. 项目状态
目前.net可以成功在harmonyos next上运行。
avalonia移植项目在真机上也可以运行,本文主要探讨.net适配相关工作。
3. 运行时
自harmonyos 5.0.0(12)起,禁止匿名内存申请可执行权限,除系统内置的javascript引擎外,其他虚拟机不能使用jit功能,所以无法将coreclr接入到鸿蒙系统中,而最新版的mono虽然支持解释执行,但是由于性能问题也不会接入mono到鸿蒙系统,最终只能选择接入nativeaot运行时。
4. nativeaot
支撑鸿蒙可以接入nativeaot的原理是鸿蒙系统兼容libc是musl的linux系统的动态库(.so)。而.net的rid支持linux-musl-arm64/linux-musl-x64,所以理论上可以将.net程序编译为原生的linux动态库(.so),然后在鸿蒙的原生项目中,通过dlopen以及dlsym等函数调用c#中的入口函数。
而c#调用鸿蒙api则通过p/invoke调用鸿蒙的ndk,而arkui的typescript api则通过ndk中的napi调用。
具体做法可以参考我正在做的avalonia移植项目: https://github.com/openharmony-net/openharmony.avalonia
5. 已知问题
5.1 syscall限制 (已解决)
鸿蒙系统使用了seccomp限制危险的syscall调用。标准posix下,如果系统不支持某个syscall则返回错误码,而seccomp非常激进,如果调用了非法的sycall则直接杀掉进程。.net的运行时初始化时,会调用__nr_get_mempolicy系统调用对numa支持进行检查,而这个系统调用不在鸿蒙的seccomp白名单中,所以导致直接宕机。
鸿蒙系统中seccomp的系统调用白名单如下:https://gitee.com/openharmony/startup_init/blob/master/services/modules/seccomp/seccomp_policy/app.seccomp.policy
其实安卓中也有类似的限制,.net的nativeaot之所以能在安卓平台下运行是因为.net中对安卓进行了特殊处理,而在鸿蒙平台我们使用的是linux平台的代码,所以没有对这些系统调用进行处理。
解决办法则是自行修改代码,将numa的函数全部修改为空函数。
5.2 mmap申请虚拟内存过大(已解决)
解决上个问题后,.net运行时初始化依然不能成功,导致程序崩溃,经过排查发现是gc初始化时会申请256g左右的虚拟内存,导致mmap返回out of memory错误。
解决办法1:设置环境变量“dotnet_gcheaphardlimit”,将虚拟内存申请控制在约180g以下即可。
解决办法2:修改源代码,将use_regions宏关掉。
5.3 icu,openssl等第三方库缺失(已解决)
解决方案1:从alpine上偷包 ,因为alpine的libc是musl,所以理论上alpine的库在鸿蒙上大部分都能使用。
阿里云alpine软件包镜像地址:
arm64架构:https://mirrors.aliyun.com/alpine/edge/main/aarch64/amd64架构:https://mirrors.aliyun.com/alpine/edge/main/x86_64/
解决方案2:如果该库有cmake项目,则可以通过鸿蒙的cmake工具链编译。
5.4 icu初始化失败(已解决)
鸿蒙的icu配置文件路径与默认路径不同,需要调用修改环境变量api,将icu_data修改为/system/usr/ohos_icu
且鸿蒙平台上libicu的大版本是72,要使用这个版本的库。
5.5 nativeaot如何跨平台编译 (windows平台已解决)
nativeaot众所周知不支持跨平台编译,而我的方案需要发布到linux-musl平台,所以无法在windows上发布,影响开发效率。
解决方案:在项目中引入项目https://github.com/openharmony-net/publishaotcross
5.6 无法调用marshal.getdelegateforfunctionpointer
相关函数
marshal.getdelegateforfunctionpointer的实现依赖动态生成汇编,而harmonyos不支持动态生成汇编代码执行(jit),使用该函数会导致崩溃。
解决方案: 使用函数指针直接调用。
6. 如何修改nativeaot代码
前文中提到部分问题的解决方案是修改源码,具体操作步骤如下:
修改完代码,执行以下命令进行编译(linux平台下,需要有编译环境):
./build.sh --subset clr.aot --configuration release -arch arm64 --cross |
编译成功后,打开目录 运行时/artifacts/bin/coreclr/linux.arm64.release/aotsdk
,将这里所有的替换到自己电脑nuget的缓存目录, 例如c:\users\用户名\.nuget\packages\runtime.linux-musl-arm64.microsoft.dotnet.ilcompiler\dotnet版本\sdk
7.相关链接
https://github.com/dotnet/runtime/issues/110074
https://github.com/dotnet/runtime/issues/111649
到此这篇关于.net适配harmonyos进展的文章就介绍到这了,更多相关.net适配harmonyos内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!
发表评论