赞
踩
云将东游,过扶摇之枝,而适遭鸿蒙。—《庄子·在宥》
OpenHarmony是由开放原子开源基金会(OpenAtom Foundation)孵化及运营的开源项目,目标是面向全场景、全连接、全智能时代、基于开源的方式,搭建一个智能终端设备操作系统的框架和平台,促进万物互联产业的繁荣发展。最近在学习OpenHarmony源代码,个人认为学习有三个阶段,分别是看、实操、写(归纳总结),本着追求学习的终极目标,因此有了这篇文章。
OpenHarmony编译框架是基于模块化的,从大到小依次划分为产品、子系统集(或领域)、子系统、部件、模块、特性。这种模块化的树状编译框架,非常方便根据目标产品硬件资源的大小进行灵活的裁剪,从而实现“统一OS,弹性部署”的目标。
产品是基于解决方案为基于开发板的完整产品,主要包含产品对OS的适配、部件拼装配置、启动配置和文件系统配置等。build.sh编译的时候通过–product-name编译选项指定;hb编译的时候通过hb set进行设置。
#适用于标准(即L2或standard)系统编译
./build.sh --product-name rk3568 --ccache
#适用于小型(即L1或small)和轻量(即L0或mini)系统编译
cd build #进入源码下build目录
hb set #执行hb set命令,选择对应的产品名称
hb build #执行hb build命令,进行编译
OpenHarmony技术架构中有四大子系统集:“系统基本能力子系统集”、“基础软件服务子系统集”、“增强软件服务子系统集”、“硬件服务子系统集”。四大子系统不会直接出现在编译选项或者参数中,而是有对应的一级源代码文件夹:“系统基本能力子系统集”对应源码foundation文件夹;“基础软件服务子系统集”和“硬件服务子系统集”对应源码base文件夹;“增强软件服务子系统集”对应源码domains文件夹。
. ├── applications //应用程序 ├── arkcompiler //ark编译器 ├── base //“基础软件服务子系统集”和“硬件服务子系统集” ├── build //编译目录 ├── build.py -> build/lite/build.py //软链接 ├── build.sh -> build/build_scripts/build.sh //软链接,标准系统编译入口 ├── commonlibrary //通用库 ├── developtools //开发工具 ├── device //芯片相关 ├── docs //文档md文件目录 ├── drivers //驱动文件 ├── foundation //“系统基本能力子系统集” ├── ide //ide ├── interface //接口 ├── kernel //内核,liteos-m,liteos-a,linux,uniproton ├── napi_generator //native api相关 ├── prebuilts //编译工具路径 ├── productdefine //产品定义 ├── qemu-run -> vendor/ohemu/common/qemu-run //qemu模拟器运行脚本 ├── test //测试用例 ├── third_party //三方库 └── vendor //产品
子系统是一个逻辑概念,它具体由对应的部件构成。在多设备部署场景下,支持根据实际需求裁剪某些非必要的子系统或部件。在build/subsystem_config.json中定义。
{ "arkui": { "path": "foundation/arkui", //子系统源码路径 "name": "arkui" //子系统名称 }, "ai": { "path": "foundation/ai", "name": "ai" }, "distributeddatamgr": { "path": "foundation/distributeddatamgr", "name": "distributeddatamgr" }, "security": { "path": "base/security", "name": "security" }, "startup": { "path": "base/startup", "name": "startup" }, "hiviewdfx": { "path": "base/hiviewdfx", "name": "hiviewdfx" }, "kernel": { "path": "kernel", "name": "kernel" }, "thirdparty": { "path": "third_party", "name": "thirdparty" } ... }
部件对子系统的进一步拆分,可复用的软件单元,它包含源码、配置文件、资源文件和编译脚本;能独立构建,以二进制方式集成,具备独立验证能力的二进制单元。部件由对应源码文件夹下的bundle.json文件进行定义。以napi部件为例foundation/arkui/napi/bundle.json
{ "name": "@ohos/napi", "description": "Node-API (formerly N-API) is an API for build native Addons", "version": "3.1", "license": "Apache 2.0", "publishAs": "code-segment", "segment": { "destPath": "foundation/arkui/napi" }, "dirs": {}, "scripts": {}, "component": { "name": "napi", //部件名称 "subsystem": "arkui", //所属子系统 "syscap": [ "SystemCapability.ArkUI.ArkUI.Napi", "SystemCapability.ArkUI.ArkUI.Libuv" ], "features": ["napi_enable_container_scope"], //部件特性 "adapted_system_type": [ "standard" ], "rom": "5120KB", //部件rom大小 "ram": "10240KB",//部件ram大小 "deps": { //部件依赖 "components": [ //部件依赖的部件 "hiviewdfx_hilog_native", "hilog" ], "third_party": [//部件依赖的三方库 "jerryscript", "libuv", "node", "bounds_checking_function", "v8" ] }, "build": { "group_type": { "base_group": [ "//foundation/arkui/napi:napi_packages", "//foundation/arkui/napi:napi_packages_ndk" ], "fwk_group": [], "service_group": [] }, "inner_kits": [//部件对外暴露的接口,用于其它部件或者模块进行引用 { "header": { "header_base": "//foundation/arkui/napi/interfaces/kits", "header_files": [ "napi/native_api.h" ] }, "name": "//foundation/arkui/napi:ace_napi" }, { "header": { "header_base": "//foundation/arkui/napi/interfaces/inner_api", "header_files": [ "napi/native_common.h", "napi/native_node_api.h" ] }, "name": "//foundation/arkui/napi:ace_napi" }, { "header": { "header_base": "//foundation/arkui/ace_engine/frameworks/core/common/", "header_files": [ "container_scope.h" ] }, "name": "//foundation/arkui/napi:ace_container_scope" } ], "test": [ "//foundation/arkui/napi:napi_packages_test", "//foundation/arkui/napi/sample/native_module_systemtest:systemtest", "//foundation/arkui/napi/test/unittest:unittest" ] } } }
模块就是编译子系统的一个编译目标,部件也可以是编译目标。模块属于哪个部件,在gn文件中由part_name指定。
ohos_shared_library("ace_napi") { //ace_napi为模块名,同时也是编译目标
deps = [ ":ace_napi_static" ] //模块的依赖,被依赖的对象即使没有被subsystem显式包含,也会被编译
public_configs = [ ":ace_napi_config" ] //模块配置参数,比如cflag
if (!is_cross_platform_build) {
public_deps = [ "//third_party/libuv:uv" ]
}
subsystem_name = "arkui" //模块所属部件所属子系统名称
part_name = "napi" //模块所属部件名称,一个模块只能属于一个部件
}
特性是部件用于体现不同产品之间的差异。通常不同特性可以定义不同编译宏或者代码,从而影响到源代码中define的特性。
vender/hihope/rk3568_mini_system/config.json
{
"subsystem": "communication",
"components": [
{ "component": "ipc", "features":[] },
{ "component": "dsoftbus", "features":["dsoftbus_get_devicename=false"] }
]
},
foundation/communication/dsoftbus/bundle.json
{ "name": "@openharmony/dsoftbus", "version": "3.1.0", "description": "dsoftbus", ... "component": { "name": "dsoftbus", "subsystem": "communication", "adapted_system_type": [ "mini", "small", "standard" ], "features": [ "dsoftbus_feature_conn_p2p", "dsoftbus_feature_disc_ble", "dsoftbus_feature_conn_br", "dsoftbus_feature_conn_ble", "dsoftbus_feature_lnn_net", "dsoftbus_feature_trans_udp_stream", "dsoftbus_feature_trans_udp_file", "dsoftbus_get_devicename", "dsoftbus_feature_product_config_path", "dsoftbus_feature_ifname_prefix", "dsoftbus_feature_lnn_wifiservice_dependence", "dsoftbus_standard_feature_dfinder_support_multi_nif", "dsoftbus_feature_protocol_newip" ], },
foundation/communication/dsoftbus/core/adapter/core_adapter.gni
if (dsoftbus_get_devicename == false) {//特性取值不同,影响编译不同代码
bus_center_core_adapter_src += [ "$dsoftbus_root_path/core/adapter/bus_center/src/lnn_settingdata_event_monitor_virtual.cpp" ]
bus_center_core_adapter_inc +=[ "$dsoftbus_root_path/core/adapter/bus_center/include" ]
bus_center_core_adapter_deps += []
} else {
bus_center_core_adapter_src += ["$dsoftbus_root_path/core/adapter/bus_center/src/lnn_settingdata_event_monitor.cpp","$dsoftbus_root_path/core/adapter/bus_center/src/lnn_ohos_account.cpp",]
bus_center_core_adapter_inc += ["$dsoftbus_root_path/adapter/common/bus_center/include","$dsoftbus_root_path/core/adapter/bus_center/include","//foundation/distributeddatamgr/relational_store/interfaces/inner_api/rdb/include","//foundation/distributeddatamgr/relational_store/interfaces/inner_api/dataability/include","//base/account/os_account/interfaces/innerkits/ohosaccount/native/include/",]
bus_center_core_adapter_deps += ["${ability_base_path}:want","${ability_base_path}:zuri","${ability_runtime_inner_api_path}/dataobs_manager:dataobs_manager","${ability_runtime_path}/frameworks/native/ability/native:abilitykit_native","//base/account/os_account/frameworks/ohosaccount/native:libaccountkits","//base/account/os_account/frameworks/osaccount/native:os_account_innerkits","//foundation/distributeddatamgr/data_share/interfaces/inner_api:datashare_consumer","//foundation/distributeddatamgr/data_share/interfaces/inner_api/common:datashare_common","//foundation/distributeddatamgr/relational_store/interfaces/inner_api/dataability:native_dataability","//foundation/distributeddatamgr/relational_store/interfaces/inner_api/rdb:native_rdb",]
}
SysCap,全称 SystemCapability,即系统能力,指操作系统中每一个相对独立的特性,如蓝牙,WIFI,NFC,摄像头等,都是系统能力之一。每个系统能力对应多个 API,随着目标设备是否支持该系统能力共同存在或消失,也会随着 DevEco Studio 一起提供给开发者做联想。
一个产品(product) 可以包含 1~n个子系统(subsystem),一个子系统可以包含1~n个部件(component),一个部件可以包含1~n个模块(module),不同产品的中的相同部件可以编译不同的特性(feature),子系统集(domain)在源代码一级根目录有体现。
OpenHarmony构建工具由shell脚本、python脚本、gn、ninjia、clang/llvm等构成。GN is “Generate Ninja” 一个用来生成.ninja 的工具,直接编写.ninja文件难度较大,且非常乏味。Ninja 原意是忍者的意思,它是一个专注于速度的小型构建工具,利用gn生成的.ninja文件作为输入。clang/llvm执行真正的编译和链接工作,clang负责编译前端,llvm负责编译优化和后端(通常编译工具分前端、优化、后端)。 GN的语法相对比较简单,有点面向对象编程语言的思想;Ninja号称比make编译速度更快,推测原因make编译过程有大量的延时变量和预置变量,需要在编译过程进行推导其值,因此需要消耗大量cpu资源进行计算,形如$@,$^,$<,$*,$?
。补充一点:每个.c 和.c++文件是独立编译的,编译过程彼此之间并不进行通信,因此可进行并行编译。编译和链接过程及常见的问题如何解决,后续单独出一期,此处先挖个坑。Ninja 手册 - https://ninja-build.org/manual.html
GN 手册- https://gitee.com/hxdlj/gn-docs/blob/master/gn_reference.md
Openharmony完整的编译构建流程主要可以分成以下五个大阶段:Preloder、Loader、GN、Ninja、Post build。Preloader和Loader阶段主要是执行python脚本preloader.py和loader.py,Preloader阶段根据vendor仓的产品配置config.json文件对产品配置进行解析,并将解析结果输出到out/preloader/{product_name}目录下;Loader阶段进行部件化配置的加载,将部件的编译gn文件,并将解析结果输出到out/{product_name}/build_configs文件夹下。GN阶段以.gn和.gni文件作为输入,通过GN工具生成.ninja文件,输出到out/{product_name}/obj目录下。Ninja阶段以.ninja文件作为输入,通过Ninja工具生调用clang/llvm编译工具链编译生成目标,如静态库out/{product_name}/obj目录下,共享库out/{product_name}/ {part_name}目录下,可执行程序。又可以分为10个小阶段:prebuild、preload、load、pre_target_generate、target_generate、post_target_generate、pre_target_compilation、target_compilation、post_target_compilation、post_build。
hb/modules/interface/build_module_interface.py
def run(self): try: self._prebuild() self._preload() self._load() self._pre_target_generate() self._target_generate() self._post_target_generate() self._pre_target_compilation() self._target_compilation() except OHOSException as exception: raise exception else: self._post_target_compilation() finally: self._post_build()
存储中的镜像(如flash或emmc)一般由芯片厂家提供的烧录工具或者产线生产过程通过专用编程器写入相应分区。OpenHarmony编译完成后镜像img文件所在的目录out/{product_name}/package/phone/image。镜像img文件一般由打包工具按照一定的规则将输入文件夹(含文件夹目录层级)和文件夹下所有文件(如库文件、可执行文件、配置文件、启动脚本文件)整体打包而成,打包过程需要考虑文件系统格式,在产品启动过程中会使用mount进行挂载,因此需要考虑文件夹和文件的层级关系及文件夹、库文件、可执行文件、配置文件、启动脚本文件的权限。这些文件夹、文件从何而来?文件夹直接在宿主机采用mkdir创建,库文件、可执行文件编译完成以后直接copy到对应文件夹中,其它配置或者脚本也是提前准备或者编译过程生成,然后copy到对应文件夹中。
生成镜像格式
packages/phone/images# file boot_linux.img chip_prod.img MiniLoaderAll.bin ramdisk.img resource.img sys_prod.img system.img uboot.img updater.img userdata.img vendor.img
boot_linux.img: Linux rev 0.0 ext2 filesystem data, UUID=00000000-0000-0000-0000-000000000000
chip_prod.img: Linux rev 1.0 ext2 filesystem data, UUID=9972d61c-2903-4218-b280-c0bc5228266d (extents) (64bit) (large files) (huge files)
MiniLoaderAll.bin: data
ramdisk.img: gzip compressed data, was "ramdisk.img", last modified: Tue Dec 26 06:16:21 2023, from Unix, original size modulo 2^32 4331520
resource.img: data
sys_prod.img: Linux rev 1.0 ext2 filesystem data, UUID=0a2da78c-c4ab-44a7-b1c8-8383098758e4 (extents) (64bit) (large files) (huge files)
system.img: Linux rev 1.0 ext2 filesystem data, UUID=a2757491-4407-4139-aa26-4cac86a28ec0 (extents) (64bit) (large files) (huge files)
uboot.img: Device Tree Blob version 17, size=2560, boot CPU=0, string block size=197, DT structure block size=1964
updater.img: gzip compressed data, was "updater.img", last modified: Tue Dec 26 06:16:21 2023, from Unix, original size modulo 2^32 18057216
userdata.img: F2FS filesystem, UUID=cf1dd758-c179-4876-9518-54ee72d3f9e9, volume name "/data"
vendor.img: Linux rev 1.0 ext2 filesystem data, UUID=21ef10b2-6522-4980-bc55-79a54d4a8d0f (extents) (64bit) (large files) (huge files)
对boot_linux.img进行解包
/out/rk3568/packages/phone/images# mkdir boot_linux
/out/rk3568/packages/phone/images# mount -o loop boot_linux.img boot_linux
/out/rk3568/packages/phone/images# cd boot_linux
/out/rk3568/packages/phone/images/boot_linux# ls -al
total 8708
drwxr-xr-x 4 root root 4096 12月 16 13:57 .
drwxr-xr-x 3 root root 4096 12月 27 10:51 ..
drwxr-xr-x 2 root root 4096 12月 16 13:57 extlinux
-rwxr-xr-x 1 root root 2764854 12月 16 13:57 logo.bmp
-rwxr-xr-x 1 root root 2764854 12月 16 13:57 logo_kernel.bmp
drwx------ 2 root root 3354624 12月 16 13:57 lost+found
对system.img进行解包
/out/rk3568/packages/phone/images# mkdir system /out/rk3568/packages/phone/images# mount -o loop system.img system /out/rk3568/packages/phone/images# cd system /out/rk3568/packages/phone/images/system# ls -al total 76 drwxr-xr-x. 16 root root 4096 12月 26 14:16 . drwxr-xr-x 4 root root 4096 12月 27 10:54 .. lrw-r--r--. 1 root root 11 12月 26 14:16 bin -> /system/bin drwxr-xr-x. 2 2000 root 4096 12月 26 14:16 chip_prod lrw-r--r--. 1 root root 7 12月 26 14:16 chipset -> /vendor dr-xr-xr-x. 2 root root 4096 12月 26 14:16 config drwxrwx--x. 2 hxd root 4096 12月 26 14:16 data drwxr-xr-x. 2 root root 4096 12月 26 14:16 dev lrw-r--r--. 1 root root 11 12月 26 14:16 etc -> /system/etc lrw-r--r--. 1 root root 16 12月 26 14:16 init -> /system/bin/init lrw-r--r--. 1 root root 11 12月 26 14:16 lib -> /system/lib drwx------. 2 root root 16384 12月 26 14:16 lost+found drwxr-xr-x. 2 hxd root 4096 12月 26 14:16 mnt drwxr-xr-x. 2 root root 4096 12月 26 14:16 proc drwxr-xr-x. 2 root root 4096 12月 26 14:16 storage drwxr-xr-x. 2 root root 4096 12月 26 14:16 sys drwxr-xr-x. 2 2000 root 4096 12月 26 14:16 sys_prod drwxr-xr-x. 9 root root 4096 12月 26 14:16 system drwxr-xr-x. 2 root root 4096 12月 26 14:16 tmp drwxr-xr-x. 2 root root 4096 12月 26 14:16 updater drwxr-xr-x. 2 2000 root 4096 12月 26 14:16 vendor
对ramdisk.img进行解包
/out/rk3568/packages/phone/images# cp ramdisk.img ramdisk.img.gz /out/rk3568/packages/phone/images# mv ramdisk.img ramdisk.img.compile /out/rk3568/packages/phone/images# gzip -d ramdisk.img.gz /out/rk3568/packages/phone/images# file ramdisk.img ramdisk.img: ASCII cpio archive (SVR4 with no CRC) /out/rk3568/packages/phone/images# cp ramdisk.img ramdisk /out/rk3568/packages/phone/images# cd ramdisk /out/rk3568/packages/phone/images# mkdir ramdisk /out/rk3568/packages/phone/images/ramdisk# cpio -idmv < ramdisk.img . lib lib/libsepol.z.so lib/libinit_stub_empty.so lib/librestorecon.z.so lib/libpcre2.z.so lib/libload_policy.z.so lib/ld-musl-arm.so.1 lib/libc.so lib/libinit_module_engine.so lib/libclang_rt.asan.so lib/libselinux.z.so sys dev storage mnt usr init system etc bin bin/mknod bin/echo bin/dnsdomainname bin/date bin/halt bin/split bin/wc bin/env bin/shred bin/ftpget bin/chroot bin/runcon bin/hexedit bin/count bin/md5sum bin/route bin/login bin/top bin/crc32 bin/df bin/grep bin/reset bin/readlink bin/ls bin/unlink bin/test bin/mkdir bin/swapoff bin/partprobe bin/dmesg bin/devmem bin/paste bin/base64 bin/hostname bin/file bin/truncate bin/sort bin/swapon bin/logname bin/gunzip bin/who bin/sysctl bin/free bin/du bin/sha1sum bin/lsusb bin/cal bin/ln bin/stat bin/dos2unix bin/id bin/blockdev bin/false bin/nsenter bin/kill bin/rmdir bin/freeramdisk bin/sha512sum bin/taskset bin/nbd-client bin/tr bin/killall5 bin/sha224sum bin/time bin/pwd bin/pwdx bin/cat bin/zcat bin/cmp bin/tail bin/expr bin/egrep bin/makedevs bin/oneit bin/nl bin/chown bin/switch_root bin/true bin/factor bin/cpio bin/i2cset bin/cksum bin/getconf bin/ftpput bin/sysctrl bin/mount bin/iotop bin/modinfo bin/pivot_root bin/mountpoint bin/toybox bin/renice bin/fstype bin/ping bin/poweroff bin/sh bin/cut bin/init bin/mkpasswd bin/uudecode bin/eject bin/unshare bin/clear bin/mv bin/microcom bin/flock bin/vconfig bin/nproc bin/head bin/chmod bin/logger bin/pidof bin/netstat bin/mdev bin/netcat bin/fsfreeze bin/printenv bin/mktemp bin/xxd bin/realpath bin/uname bin/ulimit bin/umount bin/lspci bin/whoami bin/setfattr bin/comm bin/tty bin/ifconfig bin/insmod bin/tac bin/gzip bin/pmap bin/w bin/nohup bin/hwclock bin/pgrep bin/rev bin/ping6 bin/uptime bin/inotifyd bin/prlimit bin/patch bin/fgrep bin/sha384sum bin/uuidgen bin/chrt bin/watch bin/touch bin/cp bin/sntp bin/mix bin/dd bin/xargs bin/printf bin/basename bin/rmmod bin/sync bin/pkill bin/od bin/ps bin/rm bin/more bin/timeout bin/lsattr bin/mkswap bin/yes bin/usleep bin/passwd bin/seq bin/shalsum bin/sleep bin/expand bin/unix2dos bin/groups bin/fmt bin/dirname bin/mkfifo bin/uniq bin/i2cget bin/nice bin/help bin/mcookie bin/iorenice bin/killall bin/rfkill bin/setsid bin/sha256sum bin/strings bin/which bin/vmstat bin/sendevent bin/losetup bin/readahead bin/fsync bin/link bin/chvt bin/tunctl bin/lsmod bin/su bin/find bin/uuencode bin/iconv bin/chgrp bin/fallocate bin/i2cdetect bin/i2cdump bin/tar bin/sed bin/ionice bin/install bin/tee bin/diff proc 8460 blocks /out/rk3568/packages/phone/images# ls -al total 4280 drwxr-xr-x 12 root root 4096 12月 27 11:25 . drwxr-xr-x 5 root root 4096 12月 27 11:22 .. drwxr-xr-x 2 root root 4096 12月 27 11:25 bin drwxr-xr-x 2 root root 4096 12月 26 14:16 dev drwxr-xr-x 2 root root 4096 12月 26 14:16 etc lrwxrwxrwx 1 root root 8 12月 27 11:25 init -> bin/init drwxr-xr-x 2 root root 4096 12月 27 11:25 lib drwxr-xr-x 2 root root 4096 12月 26 14:16 mnt drwxr-xr-x 2 root root 4096 12月 26 14:16 proc -rw-r--r-- 1 root root 4331520 12月 27 11:25 ramdisk.img drwxr-xr-x 2 root root 4096 12月 26 14:16 storage drwxr-xr-x 2 root root 4096 12月 26 14:16 sys drwxr-xr-x 2 root root 4096 12月 26 14:16 system drwxr-xr-x 2 root root 4096 12月 26 14:16 usr
out/rk3568/packages/phone# tree . -L 1
. ├── chip_prod ├── data ├── hisysevent ├── images ├── NOTICE_FILES ├── NOTICE_module_info.json ├── NOTICE.txt ├── NOTICE.txt.md5.stamp ├── notice_verify_result.out ├── NOTICE.xml ├── NOTICE.xml.gz ├── ramdisk ├── root ├── sa_profile ├── sys_prod ├── system ├── system_install_modules.json ├── system_install_parts.json ├── system_module_info.json ├── system_modules_list.txt ├── system_notice_files.zip ├── system.zip ├── updater └── vendor
镜像打包脚本
build/ohos/images/mkimage# tree . -L 1
. ├── chip_prod_image_conf.txt ├── dac.txt ├── debug ├── imkcovert.py ├── mkcpioimage.py //ramdisk打包 ├── mkextimage.py //其它iamge打包 ├── mkf2fsimage.py ├── mkimages.py ├── __pycache__ ├── ramdisk_image_conf.txt ├── README.txt ├── sys_prod_image_conf.txt ├── system_image_conf.txt ├── updater_image_conf.txt ├── updater_ramdisk_image_conf.txt ├── userdata_image_conf.txt └── vendor_image_conf.txt
OpenHarmony编译框架有很多学习和借鉴的。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。