当前位置: 首页 > news >正文

OpenHarmony(鸿蒙南向开发)——轻量系统芯片移植案例(一)

往期知识点记录:

  • 鸿蒙(HarmonyOS)应用层开发(北向)知识点汇总
  • 鸿蒙(OpenHarmony)南向开发保姆级知识点汇总~
  • 持续更新中……

轻量带屏解决方案之恒玄芯片移植案例

本文章基于恒玄科技BES2600W芯片的欧智通 Multi-modal V200Z-R开发板 ,进行轻量带屏开发板的标准移植,开发了智能开关面板样例,同时实现了ace_engine_litearkui_ui_liteaafwk_liteappexecfwk_liteHDF等部件基于OpenHarmony LiteOS-M内核的适配。移植架构上采用BoardSoC分离的方案,工具链Newlib C库与Musl C库可选,LiteOS-M内核编译采用gn结合Kconfig图形化配置等需求。

编译构建

目录规划

本案例在芯片移植架构方面进行了一些改进,以前的芯片适配目录规划为:

device
└── <device_company>└── <device_name>

这样会导致,小熊派BearPi-HM Nano开发板与润和的HiSpark Pegasus开发板使用小海思的hi3861SoC时,需要在这两款开发板里面都放置一份重复的代码。为了解决该问题,本案例将单板厂商与SoC厂商进行分离,可以参考 Board和SoC解耦的设计思路 ,并把芯片适配目录规划为:

device
├── board                                --- 单板厂商目录
│   └── fnlink                           --- 单板厂商名字:欧智通
│       └── v200zr                       --- 单板名:v200zr
└── soc									 --- SoC厂商目录└── bestechnic                       --- SoC厂商名字:恒玄└── bes2600						 --- SoC Series名:bes2600是一个系列,里面包含bes2600w等SoC名

产品样例目录规划为:

vendor
└── bestechnic							 --- 开发产品样例厂商目录,恒玄开发的带屏样例,因此以bestechnic命名└── display_demo         			 --- 产品名字:以智能开关面板的带屏显示样例

预编译适配

在进行移植之前,需要进行预编译适配。

预编译适配主要使用hb set命令,设置整个项目的根目录、单板目录、产品目录、单板公司名等环境变量,为编译做准备。

具体的预编译适配步骤如下:

  1. vendor/bestechnic/display_demo目录下新增config.json文件,用于描述这个产品样例所使用的单板、内核等信息,描述信息可参考如下内容:
{"product_name": "display_demo",       --- 用于hb set进行选择时,显示的产品名称"type": "mini",                       --- 构建系统的类型,mini/small/standard"version": "3.0",                     --- 构建系统的版本,1.0/2.0/3.0"device_company": "fnlink",           --- 单板厂商名,用于编译时找到/device/board/fnlink目录"board": "v200zr",                    --- 单板名,用于编译时找到/device/board/fnlink/v200zr目录"kernel_type": "liteos_m",            --- 内核类型,因为OpenHarmony支持多内核,一块单板可能适配了多个内核,所以需要指定某个内核进行编译"kernel_version": "3.0.0",            --- 内核版本,一块单板可能适配了多个linux内核版本,所以需要指定某个具体的内核版本进行编译"subsystems": [ ]                     --- 选择所需要编译构建的子系统
}
  1. device/board/fnlink/v200zr/liteos_m目录下新增config.gni文件,用于描述这个产品样例所使用的单板、内核等信息,描述信息可参考如下内容:
# Kernel type, e.g. "linux", "liteos_a", "liteos_m".
kernel_type = "liteos_m"                --- 内核类型,跟config.json中kernel_type对应# Kernel version.
kernel_version = "3.0.0"                --- 内核版本,跟config.json中kernel_version对应
  1. 验证hb set配置是否正确,输入hb set能够显示如下图片表示配置正确。

执行hb set输入项目根目录,并且回车,hb命令会遍历所有//vendor/<product_company>/<product_name>目录下的config.json,给出可选产品编译选项,config.jsonproduct_name用于显示产品名,device_companyboard用于关联出//device/board/<device_company>/<board>目录,并且匹配<any_dir_name>/config.gni文件,如果能够匹配多个文件,表示该单板适配了多个内核,那么可以根据config.jsonkernel_typekernel_version来唯一匹配config.gnikernel_typekernel_version,即可确定了需要编译适配了哪个内核的单板。

     	通过`hb env`可以查看选择出来的预编译环境变量。

在执行hb build之前,需要准备好LiteOS-M内核适配,具体适配步骤请参 内核移植。

内核移植

内核移植需要完成LiteOS-M Kconfig适配、gn的编译构建和内核启动最小适配。

LiteOS-M Kconfig适配

//kernel/liteos_m目录下执行make menuconfig命令,完成编译配置选项的选择。在Makefile文件中,会将hb env的结果转换成环境变量,即PRODUCT_PATHDEVICE_PATHBOARD_COMPANY。如下代码块所示:

$(foreach line,$(shell hb env | sed 's/\[OHOS INFO\]/ohos/g;s/ /_/g;s/:_/=/g' || true),$(eval $(line)))
ifneq ($(ohos_kernel),liteos_m)
$(error The selected product ($(ohos_product)) is not a liteos_m kernel type product)
endif
--- 将hb env的每一行输出转化为变量形式,例如将[OHOS INFO] device company: fnlink转换为ohos_device_company=fnlink……ifeq ($(BOARD_COMPANY),)
BOARD_COMPANY:=$(ohos_device_company)
endif
……
export BOARD_COMPANY
--- 将ohos_device_company转化为BOARD_COMPANY环境变量

//kernel/liteos_m/Kconfig文件中使用这些导出的环境变量,Kconfiglib采用ulfalizer开发基于python的版本,源码地址,功能介绍连接参考,里面用到了orsource关键字,其中o表示optional,表示这个文件是否存在可选,r表示relative,表示这个文件相对当前文件的相对路径。

config SOC_COMPANYstring "SoC company name to locate soc build path"helpThis option specifies the SoC company name, used to locate the build path for soc. This option is set by theSoC's Kconfig file, and should be exactly the same with SoC company path, and the user should generally avoidmodifying it via the menu configuration.orsource "../../device/board/*/Kconfig.liteos_m.shields"                                 --- 将所有扩展板配置信息加载进来,因为单板厂商A提供扩展板可以给单板厂商B使用,所以这里使用*匹配所有的扩展板,而非BOARD_COMPANY。另外由于OpenHarmony支持多内核设计,Kconfig文件采用liteos_m作为后缀,在进行单板适配过程中,其他内核在适配过程中,可以使用对应的内核名作为后缀名进行扩展。orsource "../../device/board/$(BOARD_COMPANY)/Kconfig.liteos_m.defconfig.boards"         --- 加载BOARD_COMPANY的所有单板预定义配置choiceprompt "Board Selection"orsource "../../device/board/$(BOARD_COMPANY)/Kconfig.liteos_m.boards"                   --- 提供Board选择列表endchoiceorsource "../../device/soc/*/Kconfig.liteos_m.defconfig"                                 --- 加载所有SoC的默认配置定义choiceprompt "SoC Series Selection"orsource "../../device/soc/*/Kconfig.liteos_m.series"                                    --- 提供所有SoC Series选择列表endchoiceorsource "../../device/soc/*/Kconfig.liteos_m.soc"                                       --- 加载所有SoC配置

//kernel/liteos_m/Kconfig文件可以看出需要在//device/board/fnlink目录下新增如下Kconfig文件进行适配:

├── v200zr                                       --- v200zr单板配置目录
│   ├── Kconfig.liteos_m.board                   --- 提供v200zr单板的配置选项
│   ├── Kconfig.liteos_m.defconfig.board         --- 提供v200zr单板的默认配置项
│   └── liteos_m
│       └── config.gni
├── Kconfig.liteos_m.boards                      --- 提供fnlink单板厂商下Boards配置信息
├── Kconfig.liteos_m.defconfig.boards			 --- 提供fnlink单板厂商下Boards默认配置信息
├── Kconfig.liteos_m.shields					 --- 提供fnlink单板厂商下扩展板配置信息
└── shields										 --- fnlink单板厂商的扩展板目录├── v200zr-t0								 --- fnlink单板厂商的扩展板v200zr-t0│   ├── Kconfig.liteos_m.defconfig.shield	 --- 扩展板v200zr-t0默认配置│   └── Kconfig.liteos_m.shield				 --- 扩展板v200zr-t0配置信息├── v200zr-t1│   ├── Kconfig.liteos_m.defconfig.shield│   └── Kconfig.liteos_m.shield└── Kconfig.liteos_m.shields

在 v200zr/Kconfig.liteos_m.board需要配置选择该单板的选项,以及它依赖的SoC,如下:

config BOARD_v200zrbool "select board v200zr"depends on SOC_BES2600W		 --- v200zr单板用的bes2600w的SoC,只有 bes2600w的SoC被选择后,v200zr单板配置选项才可见,可以被选择。

在 v200zr/Kconfig.liteos_m.defconfig.board需要配置选择该单板后,默认定义 BOARD 的名字为 "v200zr" ,如下:

if BOARD_v200zr
config BOARDstring		 --- string后没有带提示,因此用户不可见default "v200zr"endif # BOARD_v200zr

//kernel/liteos_m/Kconfig文件可以看出需要在//device/soc/bestechnic目录下新增如下Kconfig文件进行适配:

.
├── bes2600									 --- bes2600 SoC系列
│   ├── Kconfig.liteos_m.defconfig.bes2600w	 --- bestechnic芯片厂商bes2600w SoC Series配置
│   ├── Kconfig.liteos_m.defconfig.series	 --- bestechnic芯片厂商bes2600默认配置
│   ├── Kconfig.liteos_m.series				 --- bestechnic芯片厂商bes2600 SoC Series配置
│   └── Kconfig.liteos_m.soc				 --- bestechnic芯片厂商bes2600 SoC配置
├── Kconfig.liteos_m.defconfig				 --- bestechnic芯片厂商SoC默认配置
├── Kconfig.liteos_m.series					 --- bestechnic芯片厂商SoC Series配置
└── Kconfig.liteos_m.soc					 --- bestechnic芯片厂商 SoC配置

在 bes2600/Kconfig.liteos_m.series 需要配置bes2600 SoC series,以及它的芯片架构等信息,如下:

config SOC_SERIES_BES2600			 --- 提供bes2600 SoC Series选项bool "Bestechnic 2600 Series"select ARM						 --- 选择bes2600后,默认选择ARM架构select SOC_COMPANY_BESTECHNIC    --- 选择bes2600后,默认选择bestechnic芯片公司,驱动会依赖这个宏配置,选择配置编译对应厂商的驱动select CPU_CORTEX_M33			 --- 选择bes2600后,默认选择cortex-m33 CPUhelpEnable support for Bestechnic 2600 series

在 bes2600/Kconfig.liteos_m.soc 需要提供bes2600 SoC series下有多少个具体的SoC可供选择,如下:

choiceprompt "Bestechnic 2600 series SoC"depends on SOC_SERIES_BES2600	 --- 只有选择了bes2600 Series后,才会出现如下配置选项config SOC_BES2600W					 --- 增加bes2600w SoC配置选择项bool "SoC BES2600w"endchoice

在 bes2600/Kconfig.liteos_m.defconfig.series 需要提供bes2600 SoC series选择后的默认配置,如下:

if SOC_SERIES_BES2600							 --- 选择了bes2600 Series后,才会增加如下默认配置选项rsource "Kconfig.liteos_m.defconfig.bes2600w"	 --- 增加bes2600w SoC的默认配置config SOC_SERIES								 --- 增加SOC_SERIES的默认配置stringdefault "bes2600"endif

配置完成后,还需要根据 kernel/liteos_m/Makefile 文件配置make menuconfigdefconfig保存路径:

ifeq ($(TEE:1=y),y)
tee = _tee
endif
ifeq ($(RELEASE:1=y),y)
CONFIG ?= $(PRODUCT_PATH)/kernel_configs/release$(tee).config
else
CONFIG ?= $(PRODUCT_PATH)/kernel_configs/debug$(tee).config		 --- 配置文件保存在$(CONFIG)中,由产品最终定义
endif……update_config menuconfig:$(HIDE)test -f "$(CONFIG)" && cp -v "$(CONFIG)" .config && menuconfig $(args) && savedefconfig --out "$(CONFIG)"

在这个例子中,defconfig配置路径为 $(PRODUCT_PATH)/kernel_configs/debug.config,创建该文件后,内容为空,产品的目录文件结构如下:

.
└── display_demo├── config.json└── kernel_configs└── debug.config

配置完成后,在 kernel/liteos_m 目录下执行 make menuconfig能够对SoC Series/SoC/Board进行选择,如下:

结果将自动保存在$(PRODUCT_PATH)/kernel_configs/debug.config,下次执行make menuconfig时会导出保存的结果。

gn编译适配

在上一步Kconfig的图形化配置后,将其生成的配置结果可以作为gn编译的输入,以控制不同模块是否编译。另外为了解决之前gn编写时,随意include的问题,内核编译做了模块化编译的设计,使得整个编译逻辑更加清晰,设计思路请参考 LiteOS-M内核BUILD.gn编写指南。

在 kernel/liteos_m/BUILD.gn 中,指定了BoardSoC的编译入口为//device/board/fnlink//device/soc/bestechnic

deps += [ "//device/board/$device_company" ]
deps += [ "//device/soc/$LOSCFG_SOC_COMPANY" ]

//device/board/fnlink/BUILD.gn中,新增内容如下:

if (ohos_kernel_type == "liteos_m") {                    --- 由于多内核设计,对于LiteOS-M内核适配,需要用宏来隔离import("//kernel/liteos_m/liteos.gni")				 --- 引入内核gn编写模板module_name = get_path_info(rebase_path("."), "name")	 --- 动态获取当前文件目录作为模块名,防止目录名修改后,这里还需要跟着修改module_group(module_name) {							 --- 采用module_group模板modules = [											 --- 添加需要编译的模块]}
}

同理//device/soc/bestechnic/BUILD.gn也是一样。

内核启动适配

系统启动流程分为三个阶段:

阶段名称分区规划描述
BOOT1[0, 0x10000]第一阶段启动,进行固件启动
BOOT2[0x2C010000, 0x2C020000]第二阶段启动,进行OTA升级启动
RTOS_MAIN[0x2C080000, 0x2C860000]第三阶段启动,进行内核启动

在第三阶段内核启动中,需要适配的文件路径在 //device/soc/bestechnic/bes2600/liteos_m/sdk/bsp/rtos/liteos/liteos_m/board.c

内核启动适配总体思路如下:

  1. 中断向量的初始化os_vector_init ,初始化中断的处理函数。
  2. 内核初始化osKernelInitialize 。
  3. 创建线程board_main,进行芯片平台初始化。
  4. 内核启动,开始调度线程osKernelStart 。

其中,本章节详细对第3步进行展开,其他几步为对内核函数调用,不作详细描述。

第3步中board_main在启动OHOS_SystemInit之前,需要初始化必要的动作,如下:

...if(!ret) {...OhosSystemAdapterHooks();    --- 系统启动时候设置钩子,启动OpenHarmonyOHOS_SystemInit的之前完成打印和驱动的初始化...OHOS_SystemInit(); 			 --- 启动OpenHarmony服务,以及组件初始化}
....

OhosSystemAdapterHooks函数在device/soc/bestechnic/bes2600/liteos_m/components/utils/src/hm_sys.c文件中,如下:

int OhosSystemAdapterHooks(void)
{init_trace_system(); 	 --- 初始化打印函数DeviceManagerStart(); 	 --- 调用DeviceManagerStart函数进行HDF驱动初始化,这个过程会调用单板代码中的驱动配置文件hdf.hcs以及drivers源码实现return 0;
}

littlefs文件系统移植

V200Z-R开发板开发板采用最大32MB的支持XIPNor Flash,文件系统可以使用example,适配过程中,需要在指定路径下放置文件系统预置文件,根据配置可自动生成文件系统镜像,可以实现自动化生成和打包到烧录包中。

  1. 配置指定目录放置打包文件系统config.json,通过flash_partition_dir指定目录:
  "flash_partition_dir": "fs" 	 --- 表示在vendor/bestechnic/display_demo/fs目录下放置文件系统预置文件
  1. 在指定目录vendor/bestechnic/display_demo/fs下放置两部分内容:
  • wifi_Download_cfg.yaml:镜像的烧录配置文件,可以根据实际情况调整分区。
  • /data/data:第一个/data是挂载的根目录;第二个data是根目录里面的data目录,里面可以存放预置文件,或者在第二个data的同级目录再创建一个目录,打包的时候只认第一个data挂载根目录。
  1. config.json中根据wifi_Download_cfg.yaml最后调整结果。
  • fs_src配置文件系统挂载名字。
  • fs_name是最后生成文件系统的名字。
  • block_size配置成4K对齐,建议不修改。
  • fs_size是生成文件系统的大小。
  • burn_name是烧录bin名字的大小。
  • enable 表示是否生成这个文件系统
  1. //device/soc/bestechnic/bes2600/liteos_m/components/hdf_config/hdf.hcs文件配置文件系统的烧录的起始地址、文件系统的大小以及读数据块的大小block_size等信息,参考配置如下:
    misc {fs_config {example_config {match_attr = "littlefs_config";mount_points = ["/data"];partitions = [10];block_size = [4096];block_count = [1024];}}storage_config {flash_config {match_attr = "flash_config";partitions = [10];owner = [0];description = ["littlefs"];start_addr = [0xB60000];length = [0x400000];options = [3];}}}

最后在device/soc/bestechnic/bes2600/liteos_m/components/fs/fs_init.c中,通过hdf加载数据,进行读写flash,如下:

static int32_t FsDriverInit(struct HdfDeviceObject *object)
{if (object == NULL) {return HDF_FAILURE;}if (object->property) {if (FsGetResource(fs, object->property) != HDF_SUCCESS) {HDF_LOGE("%s: FsGetResource failed", __func__);return HDF_FAILURE;}}for (int i = 0; i < sizeof(fs) / sizeof(fs[0]); i++) {if (fs[i].mount_point == NULL)continue;fs[i].lfs_cfg.read = littlefs_block_read;fs[i].lfs_cfg.prog = littlefs_block_write;fs[i].lfs_cfg.erase = littlefs_block_erase;fs[i].lfs_cfg.sync = littlefs_block_sync;fs[i].lfs_cfg.read_size = 256;fs[i].lfs_cfg.prog_size = 256;fs[i].lfs_cfg.cache_size = 256;fs[i].lfs_cfg.lookahead_size = 16;fs[i].lfs_cfg.block_cycles = 1000;int ret = mount(NULL, fs[i].mount_point, "littlefs", 0, &fs[i].lfs_cfg);HDF_LOGI("%s: mount fs on '%s' %s\n", __func__, fs[i].mount_point, (ret == 0) ? "succeed" : "failed");}return HDF_SUCCESS;
}

C库适配

在轻量系统中,C库适配比较复杂,设计思路请参考 LiteOS-M内核支持musl与newlib平滑切换方案,由于我们的工具链采用 gcc-arm-none-eabi-10.3-2021.10-x86_64-linux.tar.bz2自带newlib的C库,那么系统移植整体采用newlib的C库。那么在内核的make menuconfig中选择newlib,如下图:

malloc适配

malloc适配参考 The Red Hat newlib C Library-malloc。实现malloc适配有以下两种方法:

  • 实现 _sbrk_r 函数。这种方法中,内存分配函数使用newlib中的。
  • 实现 _malloc_r_realloc_r_reallocf_r_free_r_memalign_r, 和 _malloc_usable_size_r。这种方法中,内存分配函数可以使用内核的。

为了方便地根据业务进行内存分配算法调优和问题定位,在这两种方法中,本案例选择后者。

首先,由于newlib中已经存在这些函数的符号,因此需要用到gccwrap的链接选项替换这些函数符号为内核的实现,内核的实现为 //kernel/liteos_m/kal/libc/newlib/porting/src/malloc.c

然后,在//device/board/fnlink/v200zr/liteos_m/config.gni的新增这些函数的wrap链接选项。

board_ld_flags += ["-Wl,--wrap=_malloc_r","-Wl,--wrap=_realloc_r","-Wl,--wrap=_reallocf_r","-Wl,--wrap=_free_r","-Wl,--wrap=_memalign_r","-Wl,--wrap=_malloc_usable_size_r",
]
vsprintf等适配

参考 https://sourceware.org/newlib/libc.html#vfprintf ,实现 vprintfvfprintfprintfsnprintf 和sprintf

类似malloc适配,首先要提供这些函数的实现,//device/soc/bestechnic/bes2600/liteos_m/components/utils/src/printf.c,本案例直接采用开源协议友好的实现。与malloc适配不同的是,这个函数由芯片原厂提供。因为就打印来说,根据项目的需要,实现可大可小,内核不方便提供统一的实现。

然后,在//device/board/fnlink/v200zr/liteos_m/config.gni的新增这些函数的wrap链接选项。

board_ld_flags += ["-Wl,--wrap=printf","-Wl,--wrap=sprintf","-Wl,--wrap=snprintf","-Wl,--wrap=vsnprintf","-Wl,--wrap=vprintf",
]
open等适配

这部分实现由内核统一实现,芯片适配无须关注,内核文件//kernel/liteos_m/kal/libc/newlib/porting/src/fs.c,适配了newlib_read_write等函数,如下:

……
ssize_t _read(int fd, void *buf, size_t nbyte)
{return LOS_Read(fd, buf, nbyte);
}ssize_t _write(int fd, const void *buf, size_t nbyte)
{return LOS_Write(fd, buf, nbyte);
}off_t _lseek(int fd, off_t offset, int whence)
{return LOS_Lseek(fd, offset, whence);
}
……

板级系统移植

驱动移植

SoC芯片平台HDF驱动移植

驱动适配相关文件放置在drivers/adapter/platform中,对应有gpioi2cpwmspiuartwatchdog,都是通过HDF机制加载,本章节以gpio为例进行详细说明。

GPIO驱动适配

gpio驱动适配需要完成编译的适配、源码的适配。

//drivers/adapter/platform/gpio/BUILD.gn文件中,描述了恒玄gpio驱动的编译适配。如下:

module_switch = defined(LOSCFG_DRIVERS_HDF_PLATFORM_GPIO)	 --- 如果打开HDF的GPIO配置开关,才进行如下编译
module_name = get_path_info(rebase_path("."), "name")hdf_driver(module_name) {sources = []if (defined(LOSCFG_SOC_COMPANY_BESTECHNIC)) {				 --- 如果打开恒玄的芯片配置开关,才进行恒玄GPIO的驱动编译sources += [ "gpio_bes.c" ]}include_dirs = [ "." ]
}

//drivers/adapter/platform/gpio/gpio_bes.c文件中,描述了恒玄gpio驱动的源码适配。 首先,按照OpenHarmonyHDF驱动框架加载驱动基本适配框架,如下:

struct HdfDriverEntry g_GpioDriverEntry = {.moduleVersion = 1,.moduleName = "BES_GPIO_MODULE_HDF",.Bind = GpioDriverBind,.Init = GpioDriverInit,.Release = GpioDriverRelease,
};
HDF_INIT(g_GpioDriverEntry); 	 --- 通过HDF_INIT 加载GPIO驱动

然后,在初始化的时候会获取hcs参数进行初始化,如下:

static int32_t GpioDriverInit(struct HdfDeviceObject *device)
{int32_t ret;struct GpioCntlr *gpioCntlr = NULL;if (device == NULL) {HDF_LOGE("%s: device is NULL", __func__);return HDF_ERR_INVALID_PARAM;}gpioCntlr = GpioCntlrFromDevice(device); 	 --- gpioCntlr节点变量就可以获取具体gpio配置if (gpioCntlr == NULL) {...

编码规范和设计思想见 bes 驱动适配PR 的评论。

Board外设器件HDF驱动移植

Board外设器件表示通过SoC平台总线连接的外设器件,在本案例中,显示屏属于外设器件,其驱动适配放在//device/board/fnlink/drivers/liteos_m目录中。

显示驱动适配

SoC驱动适配,在//device/board/fnlink/drivers/liteos_m/display/BUILD.gn文件中,根据hdf_driver模板加载驱动模块,如下:

module_name = get_path_info(rebase_path("."), "name")
hdf_driver(module_name) {sources = ["zzw395.c",]include_dirs = ["//drivers/peripheral/display/interfaces/include",...]
}

//device/board/fnlink/drivers/liteos_m/display/zzw395.c文件中,根据驱动框架加载显示驱动,如下:

static struct HdfDriverEntry g_ZZW395DriverEntry = {.moduleVersion = 1,.moduleName = "HDF_PANEL_ZZW395",.Bind = PanelDriverBind,.Init = PanelDriverInit,.Release = PanelDriverRelease,
};HDF_INIT(g_ZZW395DriverEntry);

其中的驱动参数根据hcs配置,在PanelDriverInit初始化时加载,如下:

static int32_t PanelDriverInit(struct HdfDeviceObject *object)
{if (object == NULL) {return HDF_FAILURE;}HDF_LOGD("%s entry !!!", __func__);if (object->property) {if (PanelGetResource(&priv, object->property) != HDF_SUCCESS) {HDF_LOGE("%s: PanelGetResource failed", __func__);return HDF_FAILURE;}}
...

OpenHarmony子系统适配

OpenHarmony子系统适配一般包含两部分:

  • config.json中增加对应子系统和部件,这样编译系统会将该部件纳入编译目标中。
  • 针对该部件的HAL层接口进行硬件适配,或者可选的软件功能适配。
分布式软总线子系统适配
wifi_lite部件适配

首先,在config.json文件中,增加communication子系统的wifi_lite部件,如下:

    {"subsystem": "communication","components": [{"component": "wifi_lite","optional": "true"}]},

wifi_lite部件在//build/lite/components/communication.json文件中,描述如下:

    {"component": "wifi_lite",
……"targets": ["//foundation/communication/wifi_lite:wifi"		 --- wifi_lite的编译目标],
……},

//foundation/communication/wifi_lite/BUILD.gn文件中,描述需要适配的接口头文件路径,如下:

config("include") {include_dirs = [ "interfaces/wifiservice" ]	 --- 因为wifi_lite只提供头文件,不提供wifi的具体实现,所以wifi模块暴露出适配的目录路径提供给硬件厂商来适配,厂商提供wifi协议栈源码实现。
}group("wifi") {public_configs = [ ":include" ]
}

因为在本案例中,wifi属于SoC提供的功能,所以适配源码放在SoC//device/soc/bestechnic/hals/communication/wifi_lite/wifiservice目录下,包含wifi_device.cwifi_hotspot.c分别适配wifi_device.hwifi_hotspot.h。如下:

……
WifiErrorCode Scan(void)	 --- wifi_device.c中扫描wifi热点的函数,对wifi_device.h中Scan函数的适配实现
{WifiErrorCode ret = ERROR_WIFI_BUSY;if (IsWifiActive() != WIFI_STA_ACTIVE)return ERROR_WIFI_IFACE_INVALID;if (g_HalHmosWifiInfo.scan_state == SCAN_REQUEST ||g_HalHmosWifiInfo.scan_state == SCAN_TRIGGER)return ERROR_WIFI_BUSY;HalHmosWifiLock();ret = ((HalHmosSendEvent(HMOS_ON_WIFI_SCAN_STATE_CHANGED, NULL) == 0) ? WIFI_SUCCESS : ERROR_WIFI_BUSY);HalHmosWifiUnLock();return ret;
}
……
int GetSignalLevel(int rssi, int band)	 --- wifi_hotspot.c中获取wifi信号热点函数,对wifi_hotspot.h中GetSignalLevel函数的适配实现。
{if (band == HOTSPOT_BAND_TYPE_2G) {if (rssi >= RSSI_LEVEL_4_2_G)return RSSI_LEVEL_4;if (rssi >= RSSI_LEVEL_3_2_G)return RSSI_LEVEL_3;if (rssi >= RSSI_LEVEL_2_2_G)return RSSI_LEVEL_2;if (rssi >= RSSI_LEVEL_1_2_G)return RSSI_LEVEL_1;}if (band == HOTSPOT_BAND_TYPE_5G) {if (rssi >= RSSI_LEVEL_4_5_G)return RSSI_LEVEL_4;if (rssi >= RSSI_LEVEL_3_5_G)return RSSI_LEVEL_3;if (rssi >= RSSI_LEVEL_2_5_G)return RSSI_LEVEL_2;if (rssi >= RSSI_LEVEL_1_5_G)return RSSI_LEVEL_1;}return ERROR_WIFI_INVALID_ARGS;
}
LWIP部件适配

LiteOS-M kernel目录下默认配置了lwip,因而具有编译功能,可以在kernel组件中指定lwip编译的目录。如下:

    {"subsystem": "kernel","components": [{"component": "liteos_m","features": ["ohos_kernel_liteos_m_lwip_path = \"//device/soc/bestechnic/bes2600/liteos_m/components/net/lwip-2.1\""		 --- 指定在芯片厂商目录中进行适配]}]},

//device/soc/bestechnic/bes2600/liteos_m/components/net/lwip-2.1/BUILD.gn文件中,描述了lwip的编译,如下:

import("//kernel/liteos_m/liteos.gni")
import("$LITEOSTHIRDPARTY/lwip/lwip.gni")
import("$LITEOSTOPDIR/components/net/lwip-2.1/lwip_porting.gni")module_switch = defined(LOSCFG_NET_LWIP_SACK)
module_name = "lwip"
kernel_module(module_name) {sources = LWIP_PORTING_FILES + LWIPNOAPPSFILES -[ "$LWIPDIR/api/sockets.c" ] + [ "porting/src/ethernetif.c" ]		 --- 增加ethernetif.c文件,用以适配ethernet网卡的初始化适配defines = [ "LITEOS_LWIP=1" ]defines += [ "CHECKSUM_BY_HARDWARE=1" ]
}config("public") {defines = [ "_BSD_SOURCE=1" ]include_dirs =[ "porting/include" ] + LWIP_PORTING_INCLUDE_DIRS + LWIP_INCLUDE_DIRS
}

//device/soc/bestechnic/bes2600/liteos_m/components/net/lwip-2.1/porting/include/lwip/lwipopts.h文件中,说明原有lwip配置选项保持不变,软总线会依赖这些配置选项,并且新增硬件适配的配置项,如下:

#ifndef _PORTING_LWIPOPTS_H_
#define _PORTING_LWIPOPTS_H_#include_next "lwip/lwipopts.h"				 --- 保持原来的配置项不变#define LWIP_NETIF_STATUS_CALLBACK      1
#define LWIP_CHECKSUM_ON_COPY           0
#define CHECKSUM_GEN_UDP                0	 --- 新增硬件适配选项#endif /* _PORTING_LWIPOPTS_H_ */

//device/soc/bestechnic/bes2600/liteos_m/components/net/lwip-2.1/porting/src/ethernetif.c文件中,说明对ethernet网卡初始化的适配,如下:

err_t
ethernetif_init(struct netif *netif)
{
……
#ifdef CHECKSUM_BY_HARDWAREeth_hw_checksum_init();
#endif
……netif->linkoutput = low_level_output;netif->drv_send = liteos_low_level_output;netif->hwaddr_len = NETIF_MAX_HWADDR_LEN;low_level_init(netif);driverif_init(netif);return ERR_OK;
……
}
dsoftbus部件适配

config.json中增加dsoftbus部件配置如下:

{"component": "dsoftbus","features": ["softbus_adapter_config = \"//vendor/bestechnic/mini_distributed_music_player/dsoftbus_lite_config\""]
},

dsoftbus部件在//foundation/communication/dsoftbus/dsoftbus.gni文件中提供了softbus_adapter_config配置选项可供移植过程进行配置,该配置设定了软总线移植适配的路径。

在本案例中,softbus_adapter_config配置为//vendor/bestechnic/mini_distributed_music_player/dsoftbus_lite_config路径,该路径下的内容为:

.
├── feature_config					--- 软总线功能特性配置,例如是否开启自发现功能等
│   └── mini
│       └── config.gni
└── spec_config						--- 软总线规格特性配置,例如设置软总线日志级别设置├── softbus_config_adapter.c├── softbus_config_adapter.h└── softbus_config_type.h

config.gni文件中规定了以下配置项:

配置项描述
dsoftbus_feature_disc_ble是否开启BLE发现功能
dsoftbus_feature_disc_coap是否开启COAP发现功能
dsoftbus_feature_conn_tcp是否开启TCP连接功能
dsoftbus_feature_conn_br是否开启BR连接功能
dsoftbus_feature_conn_ble是否开启BLE连接功能
dsoftbus_feature_conn_p2p是否开启P2P连接功能
dsoftbus_feature_trans_udp是否开启UDP传输功能
dsoftbus_feature_trans_udp_stream是否开启UDP传输流功能
dsoftbus_feature_trans_udp_file是否开启UDP传输文件功能
dsoftbus_feature_ip_auth是否开启认证传输通道功能
dsoftbus_feature_auth_account是否开启基于账号认证功能
dsoftbus_feature_qos是否开启QoS功能

softbus_config_adapter.c文件中规定了以下配置项:

配置项描述
SOFTBUS_INT_MAX_BYTES_LENGTHSendBytes发送最大Bytes长度
SOFTBUS_INT_MAX_MESSAGE_LENGTHSendMessage发送最大消息的长度
SOFTBUS_INT_CONN_BR_MAX_DATA_LENGTH蓝牙最大接收数据量
SOFTBUS_INT_CONN_RFCOM_SEND_MAX_LEN蓝牙最大接收数据量
SOFTBUS_INT_ADAPTER_LOG_LEVEL日志级别设置
SOFTBUS_STR_STORAGE_DIRECTORY存储目录设置

因为软总线配置了后,不会默认启动,所以需要在通过启动框架调用InitSoftBusServer函数,如下:

static void DSoftBus(void)
{osThreadAttr_t attr;attr.name = "dsoftbus task";attr.attr_bits = 0U;attr.cb_mem = NULL;attr.cb_size = 0U;attr.stack_mem = NULL;attr.stack_size = 65536;attr.priority = 24;extern void InitSoftBusServer(void);if (osThreadNew((osThreadFunc_t) InitSoftBusServer, NULL, &attr) == NULL) {printf("Failed to create WifiSTATask!\n");}
}APP_FEATURE_INIT(DSoftBus);
RPC部件适配

config.json中增加rpc部件配置如下:

{"component": "rpc"
},

同样地,rpc部件需要通过启动框架调用StartDBinderService函数,由于该函数正常运行依赖主机已经获取IP地址,因此在LWIP协议栈注册IP地址变化事件的回调函数中调用该函数,如下:

static void RpcServerWifiDHCPSucCB(struct netif *netif, netif_nsc_reason_t reason,const netif_ext_callback_args_t *args)
{(void) args;if (netif == NULL) {printf("%s %d, error: input netif is NULL!\n", __FUNCTION__, __LINE__);return;}if (reason == LWIP_NSC_IPSTATUS_CHANGE) {if (netif_is_up(netif) && !ip_addr_isany(&netif->ip_addr)) {printf("%s %d, start rpc server!\n", __FUNCTION__, __LINE__);StartDBinderService();}}
}static void WifiDHCPRpcServerCB(void)
{NETIF_DECLARE_EXT_CALLBACK(WifiReadyRpcServerCallback);netif_add_ext_callback(&WifiReadyRpcServerCallback, RpcServerWifiDHCPSucCB);
}APP_FEATURE_INIT(WifiDHCPRpcServerCB);
启动恢复子系统适配

启动恢复子系统适配bootstrap_lite/syspara_lite两个部件。请在vendor/bestechnic_bak/display_demo/config.json中新增对应的配置选项。

{"subsystem": "startup","components": [{"component": "bootstrap_lite"		 --- bootstrap_lite 部件},{"component": "syspara_lite",		 --- syspara_lite 部件"features": ["enable_ohos_startup_syspara_lite_use_posix_file_api = true"]}]
},

适配bootstrap_lite部件时,需要在连接脚本文件//device/soc/bestechnic/bes2600/liteos_m/sdk/bsp/out/best2600w_liteos/_best2001.lds中手动新增如下段:

       __zinitcall_bsp_start = .;KEEP (*(.zinitcall.bsp0.init))KEEP (*(.zinitcall.bsp1.init))KEEP (*(.zinitcall.bsp2.init))KEEP (*(.zinitcall.bsp3.init))KEEP (*(.zinitcall.bsp4.init))__zinitcall_bsp_end = .;__zinitcall_device_start = .;KEEP (*(.zinitcall.device0.init))KEEP (*(.zinitcall.device1.init))KEEP (*(.zinitcall.device2.init))KEEP (*(.zinitcall.device3.init))KEEP (*(.zinitcall.device4.init))__zinitcall_device_end = .;__zinitcall_core_start = .;KEEP (*(.zinitcall.core0.init))KEEP (*(.zinitcall.core1.init))KEEP (*(.zinitcall.core2.init))KEEP (*(.zinitcall.core3.init))KEEP (*(.zinitcall.core4.init))__zinitcall_core_end = .;__zinitcall_sys_service_start = .;KEEP (*(.zinitcall.sys.service0.init))KEEP (*(.zinitcall.sys.service1.init))KEEP (*(.zinitcall.sys.service2.init))KEEP (*(.zinitcall.sys.service3.init))KEEP (*(.zinitcall.sys.service4.init))__zinitcall_sys_service_end = .;__zinitcall_sys_feature_start = .;KEEP (*(.zinitcall.sys.feature0.init))KEEP (*(.zinitcall.sys.feature1.init))KEEP (*(.zinitcall.sys.feature2.init))KEEP (*(.zinitcall.sys.feature3.init))KEEP (*(.zinitcall.sys.feature4.init))__zinitcall_sys_feature_end = .;__zinitcall_run_start = .;KEEP (*(.zinitcall.run0.init))KEEP (*(.zinitcall.run1.init))KEEP (*(.zinitcall.run2.init))KEEP (*(.zinitcall.run3.init))KEEP (*(.zinitcall.run4.init))__zinitcall_run_end = .;__zinitcall_app_service_start = .;KEEP (*(.zinitcall.app.service0.init))KEEP (*(.zinitcall.app.service1.init))KEEP (*(.zinitcall.app.service2.init))KEEP (*(.zinitcall.app.service3.init))KEEP (*(.zinitcall.app.service4.init))__zinitcall_app_service_end = .;__zinitcall_app_feature_start = .;KEEP (*(.zinitcall.app.feature0.init))KEEP (*(.zinitcall.app.feature1.init))KEEP (*(.zinitcall.app.feature2.init))KEEP (*(.zinitcall.app.feature3.init))KEEP (*(.zinitcall.app.feature4.init))__zinitcall_app_feature_end = .;__zinitcall_test_start = .;KEEP (*(.zinitcall.test0.init))KEEP (*(.zinitcall.test1.init))KEEP (*(.zinitcall.test2.init))KEEP (*(.zinitcall.test3.init))KEEP (*(.zinitcall.test4.init))__zinitcall_test_end = .;__zinitcall_exit_start = .;KEEP (*(.zinitcall.exit0.init))KEEP (*(.zinitcall.exit1.init))KEEP (*(.zinitcall.exit2.init))KEEP (*(.zinitcall.exit3.init))KEEP (*(.zinitcall.exit4.init))__zinitcall_exit_end = .;

需要新增上述段是因为bootstrap_init提供的对外接口,见//utils/native/lite/include/ohos_init.h文件,采用的是灌段的形式,最终会保存到上述链接段中。主要的服务自动初始化宏如下表格所示:

接口名描述
SYS_SERVICE_INIT(func)标识核心系统服务的初始化启动入口
SYS_FEATURE_INIT(func)标识核心系统功能的初始化启动入口
APP_SERVICE_INIT(func)标识应用层服务的初始化启动入口
APP_FEATURE_INIT(func)标识应用层功能的初始化启动入口

说明: 通过上面加载的组件编译出来的lib文件需要手动加入强制链接。

如在 vendor/bestechnic/display_demo/config.json 中配置了bootstrap_lite 部件

    {"subsystem": "startup","components": [{"component": "bootstrap_lite"},...]},

bootstrap_lite部件会编译//base/startup/bootstrap_lite/services/source/bootstrap_service.c,该文件中,通过SYS_SERVICE_INITInit函数符号灌段到__zinitcall_sys_service_start__zinitcall_sys_service_end中,由于Init函数是没有显式调用它,所以需要将它强制链接到最终的镜像。如下:

static void Init(void)
{static Bootstrap bootstrap;bootstrap.GetName = GetName;bootstrap.Initialize = Initialize;bootstrap.MessageHandle = MessageHandle;bootstrap.GetTaskConfig = GetTaskConfig;bootstrap.flag = FALSE;SAMGR_GetInstance()->RegisterService((Service *)&bootstrap);
}
SYS_SERVICE_INIT(Init);   --- 通过SYS启动即SYS_INIT启动就需要强制链接生成的lib

在//base/startup/bootstrap_lite/services/source/BUILD.gn文件中,描述了在out/v200zr/display_demo/libs 生成 libbootstrap.a,如下:

static_library("bootstrap") {sources = ["bootstrap_service.c","system_init.c",]....

那么需要在 vendor/bestechnic/display_demo/config.json 配置强制链接库bootstrap,如下:

  "bin_list": [{"elf_name": "wifiiot","bsp_target_name": "best2600w_liteos","signature": "false","burn_name": "rtos_main","enable": "true","force_link_libs": ["bootstrap",	 --- 强制链接libbootstrap.a...]},

适配syspara_lite部件时,系统参数会最终写到文件中进行持久化保存。在轻量系统中,文件操作相关接口有POSIX接口与HalFiles接口这两套实现。

因为对接内核的文件系统,采用POSIX相关的接口,所以features字段中需要增加enable_ohos_startup_syspara_lite_use_posix_file_api = true。

如果对接HalFiles相关的接口实现的,则无须修改。

在适配GetSerial接口时,开发板不像产线生产过程那样,会写入一个具体的Serial Number,因而需要确定一个数据对开发板进行唯一标识。本案例采用WiFi Mac地址进行适配。

#define ETH_ALEN 6
#define MAC_BITS 4
#define MAC_HIGH_MASK 0xf0
#define MAC_LOW_MASK 0x0f
#define HEX_A 0xa
#define CHAR_NUM_OFFSET 0x30
#define CHAR_CAPITAL_OFFSET 0x37
#define STR_END_FLAG '\0'typedef unsigned char               u8;static char serialNumber[2*ETH_ALEN + 1];		 --- 最后一位留作'\0'结束符标识static char Hex2Char(u8 hex)
{if (hex < HEX_A) {return hex + CHAR_NUM_OFFSET;			 --- 将数值0转为char的'0'} else {return hex + CHAR_CAPITAL_OFFSET;		 --- 将数值0xa转为char的'A'}
}const char* HalGetSerial(void)
{char macAddr[ETH_ALEN];// as devboard has no production serial number, we just// use wifi mac address as device serial number.if (serialNumber[0] == STR_END_FLAG) {		 --- 只有第一次调用时,才去获取mac地址extern int bwifi_get_own_mac(u8 *addr);bwifi_get_own_mac(macAddr);				 --- 获取mac地址int j = 0;for (int i = 0; i < ETH_ALEN; i++) {u8 lowFour, highFour;highFour = (macAddr[i] & MAC_HIGH_MASK) >> MAC_BITS;serialNumber[j] = Hex2Char(highFour);j++;lowFour = macAddr[i] & MAC_LOW_MASK;serialNumber[j] = Hex2Char(lowFour);j++;}		 --- 将mac地址值转化为serial number}return serialNumber;
}
DFX子系统适配

进行DFX子系统适配需要添加hilog_lite部件,直接在config.json文件配置即可。

{"subsystem": "hiviewdfx","components": [{"component": "hilog_lite","optional": "true"}]
},

配置完成之后,在//device/soc/bestechnic/bes2600/liteos_m/components/utils/src/hm_sys.c中注册日志输出实现函数。

boolean HilogProc_Impl(const HiLogContent *hilogContent, uint32 len)
{char tempOutStr[LOG_FMT_MAX_LEN] = {0};if (LogContentFmt(tempOutStr, sizeof(tempOutStr), hilogContent) > 0) {printf(tempOutStr);}return TRUE;   
}HiviewRegisterHilogProc(HilogProc_Impl);
系统服务管理子系统适配

进行系统服务管理子系统适配需要添加samgr_lite部件,直接在config.json配置即可。

{"subsystem": "systemabilitymgr","components": [{"component": "samgr_lite","features": ["config_ohos_systemabilitymgr_samgr_lite_shared_task_size = 4096"]}]
},

在轻量系统中,samgr_lite配置的共享任务栈大小默认为0x800。当函数调用栈较大时,会出现栈溢出的问题。在本次适配过程中,将其调整为0x1000。

安全子系统适配

进行安全子系统适配需要添加huks/deviceauth_lite部件,直接在config.json配置即可。

    {"subsystem": "security","components": [{"component": "huks","features": ["huks_use_lite_storage = true","huks_use_hardware_root_key = true","huks_config_file = \"hks_config_lite.h\"","huks_key_store_path = \"/data/\"","ohos_security_huks_mbedtls_porting_path = \"//device/soc/bestechnic/hals/mbedtls\""]},{"component": "deviceauth_lite","features": ["deviceauth_storage_path = \"/data/\"","deviceauth_hichain_thread_stack_size = 9472"]}]}

huks部件适配时,huks_key_store_path配置选项用于指定存放秘钥路径,ohos_security_huks_mbedtls_porting_path配置选项用于指定进行mbedtls适配的目录,用于芯片对mbedtls进行硬件随机数等适配。

deviceauth_lite部件适配时,deviceauth_storage_path配置选项用于指定存放设备认证信息的路径,deviceauth_hichain_thread_stack_size用于指定线程栈大小。

媒体子系统适配

进行媒体子系统适配需要添加histreamer部件,直接在config.json配置即可。

{"subsystem": "multimedia","components": [{"component": "histreamer","features": ["histreamer_enable_plugin_hdi_adapter = true","histreamer_enable_plugin_minimp3_adapter = true","histreamer_enable_plugin_ffmpeg_adapter = false","config_ohos_histreamer_stack_size = 65536"]}]
},

histreamer部件配置项说明如下:

配置项说明
histreamer_enable_plugin_hdi_adapter是否使能histreamer对接到hdi接口
histreamer_enable_plugin_minimp3_adapter是否使能插件适配minimp3
histreamer_enable_plugin_ffmpeg_adapter是否使能插件适配FFmpeg
config_ohos_histreamer_stack_sizehistreamer栈大小设置
公共基础库子系统适配

进行公共基础库子系统适配需要添加kv_store/js_builtin/timer_task/kal_timer部件,直接在config.json配置即可。

{"subsystem": "utils","components": [{"component": "kv_store","features": ["enable_ohos_utils_native_lite_kv_store_use_posix_kv_api = true"]},{"component": "js_builtin"},{"component": "timer_task"},{"component": "kal_timer",}]
},

与适配syspara_lite部件类似,适配kv_store部件时,键值对会写到文件中。在轻量系统中,文件操作相关接口有POSIX接口与HalFiles接口这两套实现。因为对接内核的文件系统,采用POSIX相关的接口,所以features需要增加enable_ohos_utils_native_lite_kv_store_use_posix_kv_api = true。如果对接HalFiles相关的接口实现的,则无须修改。

图形子系统适配

进行图形子系统适配需要添加graphic_utils部件,直接在config.json配置即可。

    {"components": [{"component": "graphic_utils","features": ["enable_ohos_graphic_utils_product_config = true"]},{"component": "ui"}]},

graphic配置文件见 //vendor/bestechnic/display_demo/graphic_config/product_graphic_lite_config.h。

graphic适配见//device/soc/bestechnic/bes2600/liteos_m/components/ui, 主要功能如下:

  • display_device:实例化BaseGfxEngine。
  • touch_input:实例化PointerInputDevice。
  • UiMainTask:初始化字体引擎,执行渲染任务等。

图形子系统层次:

aafwk_lite + appexecfwk_lite    (AAFWK + APPEXECFWK)|
ace_engine_lite + jerryscript + i18n_lite + resmgr_lite + utils/native/lite/... (ACE,JS引擎及其依赖)|
arkui_ui_lite + graphic_utils      (图形框架)|
giflib + libjpeg + libpng + qrcodegen + freetype... (图形第三方库)

图形应用示例见文件//vendor/bestechnic/display_demo/tests/app.cpp,如下:

/* ui app entry */
void RunApp()
{
#ifdef UI_TESTAnimatorDemoStart(); 	 --- native ui demo
#elif defined(ABILITY_TEST)StartJSApp(); 			 --- js demo
#endif
}void AppEntry(void)
{UiMain();
}APP_FEATURE_INIT(AppEntry);

ACE开发框架子系统适配

进行ACE开发框架子系统适配需要添加ace_engine_lite部件,直接在config.json配置即可。

{"subsystem": "ace","components": [{"component": "ace_engine_lite","features": ["enable_ohos_ace_engine_lite_product_config = true"]}]
},

ace_engine_lite部件配置文件见 //vendor/bestechnic/display_demo/ace_lite_config/product_acelite_config.h

ace_lite的应用采用js语言进行开发,详细步骤如下:

1.用DevEco Studio编写js应用,参考 轻量级智能穿戴开发 。
2.使用预览功能进行预览,并且得到js包:entry\.preview\intermediates\res\debug\lite\assets\js\default
3.将js包放到对应的文件系统目录下,文件系统路径为vendor/bestechnic/display_demo/fs/data/data/js,如下:

├── app.js
├── common
├── i18n
├── manifest.json
└── pages

4.最终编译生成系统镜像,烧录到单板后,系统会从app.js加载启动ace的应用。

元能力子系统适配

进行元能力子系统适配需要添加aafwk_lite部件,直接在config.json配置即可。

    {"subsystem": "aafwk","components": [{"component": "aafwk_lite","features": ["enable_ohos_appexecfwk_feature_ability = true",	 --- 支持FA特性,即包含图形能力"config_ohos_aafwk_ams_task_size = 4096"			 --- 配置aafwk栈的大小]}]},

aafwk_lite相关的应用样例见vendor/bestechnic/display_demo/tests/ability目录,包含launcherjs app这两类应用,应用的函数调用流程描述如下:

  1. launcher应用,通过InstallLauncher安装BundleName为 "com.example.launcher"native ui应用,在AbilityMgrSliteFeature启动后会调用AbilityMgrHandler::StartLauncher()启动launcher应用。

  2. StartJSApp应用,通过StartAbility启动任意Want,通过将want data传递JS_APP_PATHSetWantData(&want, JS_APP_PATH, strlen(JS_APP_PATH) + 1)

包管理子系统适配

进行包管理子系统适配需要添加appexecfwk_lite部件,直接在config.json配置即可。

    {"subsystem": "appexecfwk","components": [{"component": "appexecfwk_lite"}]},

推荐

经常有很多小伙伴抱怨说:不知道学习鸿蒙开发哪些技术?不知道需要重点掌握哪些鸿蒙应用开发知识点?

为了能够帮助到大家能够有规划的学习,这里特别整理了一套纯血版鸿蒙(HarmonyOS Next)全栈开发技术的学习路线,包含了鸿蒙开发必掌握的核心知识要点,内容有(ArkTS、ArkUI开发组件、Stage模型、多端部署、分布式应用开发、WebGL、元服务、OpenHarmony多媒体技术、Napi组件、OpenHarmony内核、OpenHarmony驱动开发、系统定制移植等等)鸿蒙(HarmonyOS NEXT)技术知识点。

在这里插入图片描述

《鸿蒙 (Harmony OS)开发学习手册》(共计892页):https://gitcode.com/HarmonyOS_MN/733GH/overview

如何快速入门?

1.基本概念
2.构建第一个ArkTS应用
3.……

鸿蒙开发面试真题(含参考答案):

在这里插入图片描述

《OpenHarmony源码解析》:

  • 搭建开发环境
  • Windows 开发环境的搭建
  • Ubuntu 开发环境搭建
  • Linux 与 Windows 之间的文件共享
  • ……
  • 系统架构分析
  • 构建子系统
  • 启动流程
  • 子系统
  • 分布式任务调度子系统
  • 分布式通信子系统
  • 驱动子系统
  • ……

图片

OpenHarmony 设备开发学习手册:https://gitcode.com/HarmonyOS_MN/733GH/overview

图片
在这里插入图片描述

相关文章:

OpenHarmony(鸿蒙南向开发)——轻量系统芯片移植案例(一)

往期知识点记录&#xff1a; 鸿蒙&#xff08;HarmonyOS&#xff09;应用层开发&#xff08;北向&#xff09;知识点汇总 鸿蒙&#xff08;OpenHarmony&#xff09;南向开发保姆级知识点汇总~ 持续更新中…… 轻量带屏解决方案之恒玄芯片移植案例 本文章基于恒玄科技BES2600W…...

【Llamaindex RAG实践】

基础任务 (完成此任务即完成闯关) 任务要求&#xff1a;基于 LlamaIndex 构建自己的 RAG 知识库&#xff0c;寻找一个问题 A 在使用 LlamaIndex 之前InternLM2-Chat-1.8B模型不会回答&#xff0c;借助 LlamaIndex 后 InternLM2-Chat-1.8B 模型具备回答 A 的能力&#xff0c;截…...

[Linux]:线程(三)

✨✨ 欢迎大家来到贝蒂大讲堂✨✨ &#x1f388;&#x1f388;养成好习惯&#xff0c;先赞后看哦~&#x1f388;&#x1f388; 所属专栏&#xff1a;Linux学习 贝蒂的主页&#xff1a;Betty’s blog 1. POSIX 信号量 1.1 信号量的概念 为了解决多执行流访问临界区&#xff0c…...

云原生(四十一) | 阿里云ECS服务器介绍

文章目录 阿里云ECS服务器介绍 一、云计算概述 二、什么是公有云 三、公有云优缺点 1、优点 2、缺点 四、公有云品牌 五、市场占有率 六、阿里云ECS概述 七、阿里云ECS特点 阿里云ECS服务器介绍 一、云计算概述 云计算是一种按使用量付费的模式&#xff0c;这种模式…...

qemu-system-aarch64开启user用户模式网络连接

一、问题 在使用qemu构建arm64的虚拟机时&#xff0c;虚拟机没有网络&#xff0c;桥接方式相对麻烦&#xff0c;我只是需要联网更新即可。与宿主机的通信我使用共享文件夹即可满足要求。 使用指令启动虚拟机时&#xff0c;网络部分的参数为 -net user,hostfwdtcp::10022-:22 …...

Android车载——VehicleHal初始化(Android 11)

1 概述 VehicleHal是AOSP中车辆服务相关的hal层服务。它主要定义了与汽车硬件交互的标准化接口和属性管理&#xff0c;是一个独立的进程。 2 进程启动 VehicleHal相关代码在源码树中的hardware/interfaces/automotive目录下 首先看下Android.bp文件&#xff1a; cc_binary …...

CTFshow 命令执行 web37-web40

目录 web37 方法一&#xff1a;php://input 方法二&#xff1a;data协议 web38 web39 web40 方法一&#xff1a;构造文件读取 方法二&#xff1a;构造数组rce web37 error_reporting(0); if(isset($_GET[c])){$c $_GET[c];if(!preg_match("/flag/i", $c)){incl…...

数据结构与算法篇((原/反/补)码 进制)

目录 讲解一&#xff1a;原/反/补)码 一、原码 二、反码 三、补码 四、有符号位整型 五、无符号位整型 六、Java中的整型 七、整数在底层存储形式 讲解二&#xff1a;进制 一、简介 二、常用的进制 十进制 二进制 八进制 十六进制 知识补充 三、进制转换 1. 二…...

Python画笔案例-077 绘制 颜色饱和度测试

1、绘制 颜色饱和度测试 通过 python 的turtle 库绘制 颜色饱和度测试,如下图: 2、实现代码 绘制 颜色饱和度测试,以下为实现代码: """饱和度渐变示例,本程序需要coloradd模块支持,请在cmd窗口,即命令提示符下输入pip install coloradd进行安装。本程序演…...

简历投递经验01

嵌入式简历制作指南与秋招求职建议 技术要求概览 在嵌入式领域求职时&#xff0c;技术能力是HR和面试官最关注的点之一。以下是一些关键技术点&#xff0c;以及它们在简历中的体现方式。 1. 编程语言与开发环境 掌握C/C语言。熟悉至少一种单片机或微处理器的开发环境。 2.…...

数据和算力共享

数据和算力共享 针对数字化应用实践中需要在不同的物理域和信息域中进行数据的访问交换以及共享计算等需求,本文分析了在数据平台、数据集成系统以及信息交换系统中存在的问题。 在基于联邦学习的基础上,提出一种跨域数据计算共享系统,能够同时共享数据和计算资源,并支持在线…...

SpringBoot 集成 Ehcache 实现本地缓存

目录 1、Ehcache 简介2、Ehcache 集群方式3、工作原理3.1、缓存写入3.2、缓存查找3.3、缓存过期和驱逐3.4、缓存持久化 4、入门案例 —— Ehcache 2.x 版本4.1、单独使用 Ehcache4.1.1、引入依赖4.1.2、配置 Ehcache4.1.2.1、XML 配置方式4.1.2.1.1、新建 ehcache.xml4.1.2.1.2…...

CSP-J 复赛真题 P9749 [CSP-J 2023] 公路

文章目录 前言[CSP-J 2023] 公路题目描述输入格式输出格式样例 #1样例输入 #1样例输出 #1 提示 示例代码代码解析思考过程总结 总结 前言 在CSP-J 2023的复赛中&#xff0c;出现了一道引人注目的题目——“公路”。这道题目不仅考察了选手们对算法的理解和运用能力&#xff0c…...

MeterSphere压测配置说明

在MeterSphere中&#xff0c;执行性能测试时的配置参数对测试结果有重要影响。以下是对MeterSphere压测配置中几个关键参数的解释&#xff1a; 执行方式&#xff1a;决定了测试的执行模式&#xff0c;例如可以按照持续时间或迭代次数来执行测试。 按持续时间&#xff1a;在这种…...

数据库软题6.1-关系模式-关系模式的各种键

关系模式的各种键 题1-由关系模式求候选键 1. 候选键唯一不冗余 对选项进行闭包运算&#xff0c;如果得到全部属性U&#xff0c;则为候选码 A:AC-ABC-ABCD B:AB-ABC-ABCD C:AE-ABE-ABCE -ABCDE-ABCDEH D:DE2. R的候选码可以从A1,A2,A3,A1A2,A1A3,A2A3,A1A2A3中选择&#xff…...

ulimit:资源限制

一、命令简介 ​ulimit​ 是一个用于资源管理的工具&#xff0c;对于确保系统资源的合理分配和安全使用至关重要。 ‍ 使用场景&#xff1a; 系统管理&#xff1a;限制用户进程使用的资源&#xff0c;防止资源滥用&#xff0c;保证系统稳定。调试&#xff1a;调整核心文件大…...

解决Python使用Selenium 时遇到网页 <body> 划不动的问题

如果在使用 Selenium 时遇到网页的 <body> 划不动的问题&#xff0c;这通常是因为页面的滚动机制&#xff08;例如&#xff0c;可能使用了一个具有固定高度的容器或自定义的滚动条&#xff09;导致无法通过简单的 JavaScript 实现滚动。可以通过以下方法来解决该问题。 …...

pytorch版本和cuda版本不匹配问题

文章目录 &#x1f315;问题&#xff1a;Python11.8安装pytorch11.3失败&#x1f315;CUDA版本和pytorch版本的关系&#x1f315;安装Pytorch2.0.0&#x1f319;pip方法&#x1f319;cuda方法 &#x1f315;问题&#xff1a;Python11.8安装pytorch11.3失败 &#x1f315;CUDA版…...

Vue/组件的生命周期

这篇文章借鉴了coderwhy大佬的Vue生命周期 在Vue实例化或者创建组件的过程中 内部涉及到一系列复杂的阶段 每一个阶段的前后时机都可能对应一个钩子函数 以下是我根据coderwhy大佬文章对于每一个阶段的一些看法 1.过程一 首先实例化Vue或者组件 在实例化之前 会对应一个钩子函…...

【Nacos架构 原理】内核设计之Nacos寻址机制

文章目录 前提设计内部实现单机寻址文件寻址地址服务器寻址 前提 对于集群模式&#xff0c;集群内的每个Nacos成员都需要相互通信。因此这就带来一个问题&#xff0c;该以何种方式去管理集群内部的Nacos成员节点信息&#xff0c;即Nacos内部的寻址机制。 设计 要能够感知到节…...

入门案例:mybatis流程,核心,常见错误

入门案例&#xff1a;mybatis执行流程分析 说明&#xff1a; 1.第一步&#xff1a;是从核心配置文件mybatis-config.xml中构建SqlSessionFactory对象&#xff0c;由于核心配置文件mybatis-config.xml中关联了映射文件UserMapper.xml,所以在SqlSessionFactory中也存在映射文件的…...

C++ | Leetcode C++题解之第456题132模式

题目&#xff1a; 题解&#xff1a; class Solution { public:bool find132pattern(vector<int>& nums) {int n nums.size();vector<int> candidate_i {nums[0]};vector<int> candidate_j {nums[0]};for (int k 1; k < n; k) {auto it_i upper_…...

自然语言处理问答系统

✅作者简介&#xff1a;2022年博客新星 第八。热爱国学的Java后端开发者&#xff0c;修心和技术同步精进。 &#x1f34e;个人主页&#xff1a;Java Fans的博客 &#x1f34a;个人信条&#xff1a;不迁怒&#xff0c;不贰过。小知识&#xff0c;大智慧。 &#x1f49e;当前专栏…...

Python的几个高级特性

引言 Python是一种功能强大的编程语言&#xff0c;它简洁的语法和强大的库支持使其成为数据科学和机器学习领域的热门选择。在Python的高级特性中&#xff0c;生成器、迭代器、闭包、装饰器和内置高阶函数是实现高效、优雅代码的关键。本文将逐一介绍这些特性&#xff0c;并提…...

【颜色平衡树 / E】

题目 思路 DFS暴力 60分 代码 #include <bits/stdc.h> using namespace std; const int N 5010; const int M 5010; int h[N], e[M], ne[M], idx; int c[N], f; int ans; void add(int a, int b) // 添加一条边a->b {e[idx] b, ne[idx] h[a], h[a] idx ; } …...

滑动窗口--(中篇)

将X减到0的最小操作数 给你一个整数数组 nums 和一个整数 x 。每一次操作时&#xff0c;你应当移除数组 nums 最左边或最右边的元素&#xff0c;然后从 x 中减去该元素的值。请注意&#xff0c;需要 修改 数组以供接下来的操作使用。 如果可以将 x 恰好 减到 0 &#xff0c;返…...

Java性能调优:实战技巧与最佳实践

引言 Java作为企业级应用开发的首选语言之一&#xff0c;其性能直接影响到系统的响应速度和用户体验。性能调优是一项复杂的工作&#xff0c;涉及多个层面的知识和技术。本文将通过具体的示例&#xff0c;探讨一些常见的性能调优技巧及最佳实践。 1. 了解你的应用程序 示例&…...

排版套料系统设计说明

先上效果图 项目地址 1.产品介绍 产品名称&#xff1a;StreamFit 智能排版套料系统 主要功能&#xff1a; 智能排版优化 功能描述&#xff1a;StreamFit 利用先进的算法技术&#xff0c;自动对各类材料&#xff08;如布料、金属板材、纸张等&#xff09;进行高效排版布局&am…...

算法修炼之路之二分查找

目录 一:三大二分介绍及模板 1.普通二分 2.查找左右边界的二分及模板 二:LeetCode OJ练习 1.第一题 2.第二题 3.第三题 4.第四题 5.第五题 6.第六题 一:三大二分介绍及模板 1.普通二分 这里通过一道题来引出普通二分及模板 LeetCode_704 二分查找 画图分析: 具体代…...

OpenAI预计明年将推出“代理”系统

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…...