这一篇我们继续深入一点点,尝试打通从用户态UI到内核态HDF之间的联系。其中涉及到的调用关系比较复杂,建议在“用鸿蒙开发AI应用(五)HDF 驱动补光灯”的基础上阅读本文,HDF的相关细节这里就不在赘述了。
背景知识
用户程序框架子系统包含两个大的模块:Ability子系统和包管理子系统。
1. Ability子系统
1.1 Ability
Ability是系统调度应用的最小单元,是能够完成一个独立功能的组件,一个应用可以包含一个或多个Ability。Ability分为两种类型:Page类型的Ability和Service类型的Ability
Page类型的Ability:带有界面,为用户提供人机交互的能力。
Service类型的Ability:不带界面,为用户提供后台任务机制。
1.2 AbilitySlice
AbilitySlice是单个页面及其控制逻辑的总和,是Page类型Ability特有的组件,一个Page类型的Ability可以包含多个AbilitySlice,此时,这些页面提供的业务能力应当是高度相关的。
1.3 生命周期
生命周期是Ability被调度到启动、激活、隐藏和退出等各个状态的的统称。
Ability生命周期各状态解析:
UNINITIALIZED:未初始状态,为临时状态,Ability被创建后会由UNINITIALIZED状态进入INITIAL状态;
INITIAL:初始化状态,也表示停止状态,表示当前Ability未运行,调用Start后进入INACTIVE,同时回调开发者的OnStart生命周期回调;
INACTIVE:未激活状态,表示当前窗口已显示但是无焦点状态,由于Window暂未支持焦点的概念,当前状态与ACTIVE一致。
ACTIVE:前台激活状态,表示当前窗口已显示,并获取焦点,Ability在退到后台之前先由ACTIVE状态进入INACTIVE状态;
BACKGROUND: 后台状态,表示当前Ability退到后台,Ability在被销毁后由BACKGROUND状态进入INITIAL状态,或者重新被激活后由BACKGROUND状态进入ACTIVE状态。
1.4 AbilityLoader
AbilityLoader负责注册和加载开发者Ability的模块。开发者开发的Ability先要调用AbilityLoader的注册接口注册到框架中,接着Ability启动时会被实例化。
1.5 AbilityManager
AbilityManager负责AbilityKit和Ability管理服务进行IPC的通信。
1.6 EventHandler
EventHandler是AbilityKit提供给开发者的用于在Ability中实现线程间通信的一个模块。
1.7 Ability运行管理服务
Ability运行管理服务是用于协调各Ability运行关系、及生命周期进行调度的系统服务。
其中,服务启动模块负责Ability管理服务的启动、注册等。
服务接口管理模块负责Ability管理服务对外能力的管理。
进程管理模块负责Ability应用所在进程的启动和销毁、及其进程信息维护等功能。Ability栈管理模块负责维护各个Ability之间跳转的先后关系。
生命周期调度模块是Ability管理服务根据系统当前的操作调度Ability进入相应的状态的模块。
连接管理模块是Ability管理服务对Service类型Ability连接管理的模块。
1.8 AppSpawn
AppSpawn是负责创建Ability应用所在进程的系统服务,该服务有较高的权限,为Ability应用设置相应的权限,并预加载一些通用的模块,加速应用的启动。
2. 包管理子系统
包管理子系统,是OpenHarmony为开发者提供的安装包管理框架。
BundleKit:是包管理服务对外提供的接口,有安装/卸载接口、包信息查询接口、包状态变化监听接口。
包扫描器:用来解析本地预制或者安装的安装包,提取里面的各种信息,供管理子模块进行管理,持久化。
包安装子模块:安装,卸载,升级一个包;包安装服务一个单独进程的用于创建删除安装目录,具有较高的权限。
包管理子模块:管理安装包相关的信息,存储持久化包信息。
包安全管理子模块:签名检查、权限授予、权限管理。
HDF驱动LED(可选)
之前在内核中已经注册过一个led_driver驱动,并以led_service服务发布,这一节稍微重构一下代码,功能上没有变化,我们快速过一遍,熟悉HDF的可以自行跳过。
1. 业务代码
先新建头文件vendorhuaweihdfledincludeled_ctrl.h。
#ifndef _LED_CTRL_H #define _LED_CTRL_H #include "hdf_device_desc.h" #include "hdf_log.h" #include "device_resource_if.h" #include "osal_io.h" #include "osal_mem.h" #include "gpio_if.h" #include "osal_irq.h" #include "osal_time.h" #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ extern int32_t CtlLED(int mode); #ifdef __cplusplus } #endif /* __cplusplus */ #endif /* _LED_CTRL_H */
再新建源文件 vendorhuaweihdfledled_ctrl.c
#include "led_ctrl.h" #define HDF_LOG_TAG led_driver // 打印日志所包含的标签,如果不定义则用默认定义的HDF_TAG标签 int32_t CtlLED(int mode) { int32_t ret; uint16_t valRead; /* LED的GPIO管脚号 */ // uint16_t gpio = 5 * 8 + 1; // 红外补光灯 uint16_t gpio = 2 * 8 + 3; // 绿色指示灯 // uint16_t gpio = 3 * 8 + 4; // 红色指示灯 /* 将GPIO管脚配置为输出 */ ret = GpioSetDir(gpio, GPIO_DIR_OUT); if (ret != 0) { HDF_LOGE("GpioSerDir: failed, ret %d ", ret); return ret; } if (mode == -1) { // 翻转输出口 (void)GpioRead(gpio, &valRead); ret = GpioWrite(gpio, (valRead == GPIO_VAL_LOW) ? GPIO_VAL_HIGH : GPIO_VAL_LOW); } else { ret = GpioWrite(gpio, mode); } if (ret != 0) { HDF_LOGE("GpioWrite: failed, ret %d ", ret); return ret; } return ret; }
先完成对绿色指示灯的控制逻辑。
2. 驱动实现 在 huawei/hdf 目录下新建一个文件夹 led, 然后在其中新建一个源文件 led.c。
#include "hdf_device_desc.h" // HDF框架对驱动开放相关能力接口的头文件 #include "hdf_log.h" // HDF 框架提供的日志接口头文件 #include "led_ctrl.h" // #define HDF_LOG_TAG led_driver // 打印日志所包含的标签,如果不定义则用默认定义的HDF_TAG标签 #define LED_WRITE_READ 1 // 读写操作码1 // Dispatch是用来处理用户态发下来的消息 int32_t LedDriverDispatch(struct HdfDeviceIoClient *client, int cmdCode, struct HdfSBuf *data, struct HdfSBuf *reply) { int32_t result = HDF_FAILURE; HDF_LOGE("Led driver dispatch"); if (client == NULL || client->device == NULL) { HDF_LOGE("Led driver device is NULL"); return HDF_ERR_INVALID_OBJECT; } switch (cmdCode) { case LED_WRITE_READ: const char *recv = HdfSbufReadString(data); if (recv != NULL) { HDF_LOGI("recv: %s", recv); result = CtlLED(-1); // result = CtlLED(GPIO_VAL_HIGH); if (!HdfSbufWriteInt32(reply, result)) { HDF_LOGE("replay is fail"); } return HdfDeviceSendEvent(client->device, cmdCode, data); } break; default: break; } return result; } //驱动对外提供的服务能力,将相关的服务接口绑定到HDF框架 int32_t HdfLedDriverBind(struct HdfDeviceObject *deviceObject) { if (deviceObject == NULL) { HDF_LOGE("Led driver bind failed!"); return HDF_ERR_INVALID_OBJECT; } static struct IDeviceIoService ledDriver = { .Dispatch = LedDriverDispatch, }; deviceObject->service = (struct IDeviceIoService *)(&ledDriver); HDF_LOGD("Led driver bind success"); return HDF_SUCCESS; } // 驱动自身业务初始的接口 int32_t HdfLedDriverInit(struct HdfDeviceObject *deviceObject) { if (deviceObject == NULL) { HDF_LOGE("Led driver Init failed!"); return HDF_ERR_INVALID_OBJECT; } HDF_LOGD("Led driver Init success"); return HDF_SUCCESS; } // 驱动资源释放的接口 void HdfLedDriverRelease(struct HdfDeviceObject *deviceObject) { if (deviceObject == NULL) { HDF_LOGE("Led driver release failed!"); return; } HDF_LOGD("Led driver release success"); return; } // 定义驱动入口的对象,必须为HdfDriverEntry(在hdf_device_desc.h中定义)类型的全局变量 struct HdfDriverEntry g_ledDriverEntry = { .moduleVersion = 1, .moduleName = "led_driver", .Bind = HdfLedDriverBind, .Init = HdfLedDriverInit, .Release = HdfLedDriverRelease, }; // 调用HDF_INIT将驱动入口注册到HDF框架中,在加载驱动时HDF框架会先调用Bind函数,再调用Init函数加载该驱动,当Init调用异常时,HDF框架会调用Release释放驱动资源并退出。 HDF_INIT(g_ledDriverEntry);
3. 驱动编译 在 huawei/hdf/led 目录下新建编译文件 Makefile。
include $(LITEOSTOPDIR)/../../drivers/hdf/lite/lite.mk MODULE_NAME := hdf_led_driver LOCAL_SRCS += led_ctrl.c led.c LOCAL_INCLUDE := ./include LOCAL_CFLAGS += -fstack-protector-strong -Wextra -Wall -Werror include $(HDF_DRIVER)
4. 编译结果链接到内核镜像 修改 huawei/hdf/hdf_vendor.mk 文件,添加以下代码
LITEOS_BASELIB += -lhdf_led_driver #链接生成的静态库 LIB_SUBDIRS += $(VENDOR_HDF_DRIVERS_ROOT)/led #驱动代码Makefile的目录
5. 驱动配置 修改 vendor/hisi/hi35xx/hi3516dv300/config/device_info/device_info.hcs配置文件,添加驱动的设备描述。
platform :: host { hostName = "platform_host"; // host名称,host节点是用来存放某一类驱动的容器 priority = 50; // host启动优先级(0-200),值越大优先级越低,建议默认配100,优先级相同则不保证host的加载顺序 device_led :: device { // led设备节点 device0 :: deviceNode { // led驱动的DeviceNode节点 policy = 2; // policy字段是驱动服务发布的策略,在驱动服务管理章节有详细介绍 priority = 100; // 驱动启动优先级(0-200),值越大优先级越低,建议默认配100,优先级相同则不保证device的加载顺序 preload = 0; // 驱动按需加载字段 permission = 0666; // 驱动创建设备节点权限 moduleName = "led_driver"; // 驱动名称,该字段的值必须和驱动入口结构的moduleName值一致 serviceName = "led_service"; // 驱动对外发布服务的名称,必须唯一 deviceMatchAttr = "led_config"; // 驱动私有数据匹配的关键字,必须和驱动私有数据配置表中的match_attr值相等 } }
编译用户程序框架子系统 1. 添加配置文件 在 build/lite/platform/hi3516dv300_liteos_a/platform.json中的subsystems字段下面添加appexecfwk和aafwk。
{ "subsystem": "aafwk", "components": [ { "component": "ability", "optional": "true", "dirs": [ "foundation/aafwk" ], "targets": [ "//foundation/aafwk/frameworks/ability_lite:aafwk_abilitykit_lite", "//foundation/aafwk/frameworks/ability_lite:aafwk_abilityMain_lite", "//foundation/aafwk/frameworks/abilitymgr_lite:aafwk_abilityManager_lite", "//foundation/aafwk/services/abilitymgr_lite:aafwk_services_lite" ], "features": [ {"enable_ohos_appexecfwk_feature_ability": "true"} ], "deps": { "components": [ "hilog_a", "bundle_mgr", "system_ability_manager", "distributed_schedule", "graphic", "utils", "ipc" ], "third_party": [ "cjson", "bounds_checking_function" ] } } ] }, { "subsystem": "appexecfwk", "components": [ { "component": "bundle_mgr", "optional": "true", "dirs": [ "foundation/appexecfwk" ], "targets": [ "//foundation/appexecfwk/services/bundlemgr_lite:appexecfwk_services_lite", "//foundation/appexecfwk/frameworks/bundle_lite:appexecfwk_kits_lite" ], "features": [], "deps": { "components": [ "iam", "app_verify", "hilog_a", "system_ability_manager", "global_resource_manager", "graphic", "utils" ], "third_party": [ "cjson", "zlib" ] } } ] },
2. 添加编译文件 新建buildliteconfigsubsystemaafwkBUILD.gn文件,
import("//build/lite/config/subsystem/lite_subsystem.gni") lite_subsystem("aafwk") { subsystem_components = [ "//foundation/aafwk/frameworks/ability_lite:aafwk_abilitykit_lite", "//foundation/aafwk/frameworks/abilitymgr_lite:aafwk_abilityManager_lite", "//foundation/aafwk/services/abilitymgr_lite:aafwk_services_lite", ] }
新建/build/lite/config/subsystem/appexecfwk/BUILD.gn文件,
import("//build/lite/config/subsystem/lite_subsystem.gni") lite_subsystem("appexecfwk") { subsystem_components = [ "//foundation/appexecfwk/kits/appkit_lite:appexecfwk_kit_lite", "//foundation/appexecfwk/services/bundlemgr_lite:appexecfwk_services_lite", ] }
3. 运行管理服务 用户程序框架有两个系统服务ability管理服务(abilityms)和(bundlems),两系统服务运行于foundation进程中。
abilityms和bundlems注册到sa_manager中,sa_manager运行于foundation进程中,sa_manager为abilityms和bundlems创建线程运行环境。
在foundation/distributedschedule/services/safwk_lite/BUILD.gn中添加对abilityms和bundlems
deps = [ "...", ] if (ohos_kernel_type == "liteos_a") { deps += [ "...", "//foundation/aafwk/services/abilitymgr_lite:abilityms", "//foundation/appexecfwk/services/bundlemgr_lite:bundlems", "...", ] }
基于AbilityKit开发的Ability 1. 主页面实现 新建源文件applicationssamplecameramyLedAppsrcmain_ability.cpp
#include "main_ability.h" namespace OHOS { REGISTER_AA(MainAbility) void MainAbility::OnStart(const Want &want) { printf("MainAbility::OnStart "); SetMainRoute("MainAbilitySlice"); Ability::OnStart(want); }
2. 分片页面 2.1 定义控件常量 新建源文件main_ability_slice.cpp, 屏幕大小为960x480
#include "main_ability_slice.h" #include "ability_manager.h" #include "components/ui_label.h" #include "components/ui_label_button.h" namespace OHOS { REGISTER_AS(MainAbilitySlice) constexpr static int BUTTON1_POSITION_X = 380; constexpr static int BUTTON1_POSITION_Y = 200; constexpr static int BUTTON_WIDTH = 200; constexpr static int BUTTON_HEIGHT = 80; constexpr static int ROOT_VIEW_POSITION_X = 0; constexpr static int ROOT_VIEW_POSITION_Y = 0; constexpr static int ROOT_VIEW_WIDTH = 960; constexpr static int ROOT_VIEW_HEIGHT = 480; constexpr static uint8_t ROOT_VIEW_OPACITY = 255; constexpr static uint8_t FONT_ID = 10; constexpr static int BUTTON1_POSITION_X = 380; constexpr static int BUTTON1_POSITION_Y = 200; constexpr static int BUTTON_WIDTH = 200; constexpr static int BUTTON_HEIGHT = 80; constexpr static int ROOT_VIEW_POSITION_X = 0; constexpr static int ROOT_VIEW_POSITION_Y = 0; constexpr static int ROOT_VIEW_WIDTH = 960; constexpr static int ROOT_VIEW_HEIGHT = 480; constexpr static uint8_t ROOT_VIEW_OPACITY = 255; constexpr static uint8_t FONT_ID = 10; } // namespace OHOS
2.2 创建按钮和布局 在生命周期函数OnStart中,全屏放置一个rootView_,居中位置放置一个按钮button1。
void MainAbilitySlice::OnStart(const Want &want) { printf("MainAbilitySlice::OnStart "); AbilitySlice::OnStart(want); auto button1 = new UILabelButton(); button1->SetPosition(BUTTON1_POSITION_X, BUTTON1_POSITION_Y); button1->SetText("翻转 LED"); button1->Resize(BUTTON_WIDTH, BUTTON_HEIGHT); button1->SetFontId(FONT_ID); button1->SetStyle(STYLE_TEXT_COLOR, Color::Black().full); button1->SetStyle(STYLE_TEXT_OPA, ROOT_VIEW_OPACITY); button1->SetStyle(STYLE_BACKGROUND_OPA, ROOT_VIEW_OPACITY); rootView_ = RootView::GetWindowRootView(); rootView_->SetPosition(ROOT_VIEW_POSITION_X, ROOT_VIEW_POSITION_Y); rootView_->Resize(ROOT_VIEW_WIDTH, ROOT_VIEW_HEIGHT); rootView_->Add(button1); SetUIContent(rootView_); }
2.3 实现驱动消息机制 这里顺便提一下,文档中DevSvcManagerClntGetService接口仅在内核态有效,可以方便的获取服务并直接调用。鸿蒙作为微内核的OS,想从用户态调用内核态函数,要么用框架的消息机制,要么自己用中断服务实现。
#define LED_WRITE_READ 1 #define LED_SERVICE "led_service" static int OnDevEventReceived(void *priv, uint32_t id, struct HdfSBuf *data) { const char *string = HdfSbufReadString(data); if (string == NULL) { printf("fail to read string in event data "); return HDF_FAILURE; } printf("%s: dev event received: %u %s ", (char *)priv, id, string); return HDF_SUCCESS; } static int SendEvent(struct HdfIoService *serv, const char *eventData) { int ret = 0; struct HdfSBuf *data = HdfSBufObtainDefaultSize(); if (data == NULL) { printf("fail to obtain sbuf data "); return 1; } struct HdfSBuf *reply = HdfSBufObtainDefaultSize(); if (reply == NULL) { printf("fail to obtain sbuf reply "); ret = HDF_DEV_ERR_NO_MEMORY; HdfSBufRecycle(data); return ret; } if (!HdfSbufWriteString(data, eventData)) { printf("fail to write sbuf "); ret = HDF_FAILURE; HdfSBufRecycle(data); HdfSBufRecycle(reply); return ret; } ret = serv->dispatcher->Dispatch(&serv->object, LED_WRITE_READ, data, reply); if (ret != HDF_SUCCESS) { printf("fail to send service call "); HdfSBufRecycle(data); HdfSBufRecycle(reply); return ret; } int replyData = 0; if (!HdfSbufReadInt32(reply, &replyData)) { printf("fail to get service call reply "); ret = HDF_ERR_INVALID_OBJECT; HdfSBufRecycle(data); HdfSBufRecycle(reply); return ret; } printf("Get reply is: %d ", replyData); HdfSBufRecycle(data); HdfSBufRecycle(reply); return ret; }
2.4 加入点击事件 每次点击按钮,向内核态发送一次消息。
auto onClick = [this](UIView &view, const Event &event) -> bool { printf("led button pressed "); struct HdfIoService *serv = HdfIoServiceBind(LED_SERVICE, 0); if (serv == NULL) { printf("fail to get service %s ", LED_SERVICE); return false; } static struct HdfDevEventlistener listener = { .callBack = OnDevEventReceived, .priv = (void *)"Service0"}; if (HdfDeviceRegisterEventListener(serv, &listener) != HDF_SUCCESS) { printf("fail to register event listener "); return false; } const char *send_cmd = "toggle LED"; if (SendEvent(serv, send_cmd)) { printf("fail to send event "); return false; } if (HdfDeviceUnregisterEventListener(serv, &listener)) { printf("fail to unregister listener "); return false; } HdfIoServiceRecycle(serv); return true; };
2.5 注销页面 在生命周期函数OnStop中,删除所有节点,回收系统资源。
void DeleteViewChildren(UIView *view) { if (view == nullptr) { return; } while (view != nullptr) { UIView *tempView = view; view = view->GetNextSibling(); if (tempView->IsViewGroup()) { DeleteViewChildren(dynamic_cast(tempView)->GetChildrenHead()); } if (tempView->GetParent()) { dynamic_cast (tempView->GetParent())->Remove(tempView); } delete tempView; } } void MainAbilitySlice::OnStop() { printf("MainAbilitySlice::OnStop "); AbilitySlice::OnStop(); DeleteViewChildren(rootView_); }
3. 编译配置 新增 applicationssamplecameramyLedAppBUILD.gn文件
import("//build/lite/config/component/lite_component.gni") import("//build/lite/config/subsystem/aafwk/config.gni") HDF_FRAMEWORKS = "//drivers/hdf/frameworks" src_path = "//applications/sample/camera/myLedApp/src" lite_library("ledability") { target_type = "shared_library" ldflags = [ "-shared", ] sources = [ "${src_path}/main_ability.cpp", "${src_path}/main_ability_slice.cpp", ] include_dirs = [ ".", "//foundation/aafwk/frameworks/ability_lite/example/entry/src/main/cpp", "//foundation/aafwk/interfaces/innerkits/abilitymgr_lite", "//foundation/aafwk/interfaces/kits/ability_lite", "//foundation/aafwk/interfaces/kits/want_lite", "//foundation/appexecfwk/interfaces/kits/bundle_lite", "//foundation/appexecfwk/utils/bundle_lite", "//foundation/communication/interfaces/kits/ipc_lite", "//foundation/graphic/lite/interfaces/kits/config", "//foundation/graphic/lite/interfaces/kits/ui", "//foundation/graphic/lite/interfaces/kits/utils", "//kernel/liteos_a/kernel/common", "//kernel/liteos_a/kernel/include", "//drivers/hdf/lite/include/host", "$HDF_FRAMEWORKS/ability/sbuf/include", "$HDF_FRAMEWORKS/core/shared/include", "$HDF_FRAMEWORKS/core/host/include", "$HDF_FRAMEWORKS/core/master/include", "$HDF_FRAMEWORKS/include/core", "$HDF_FRAMEWORKS/include/utils", "$HDF_FRAMEWORKS/utils/include", "$HDF_FRAMEWORKS/include/osal", "//kernel/liteos_a/platform/include", "$HDF_FRAMEWORKS/adapter/syscall/include", "$HDF_FRAMEWORKS/adapter/vnode/include", ] deps = [ "//foundation/aafwk/frameworks/ability_lite:aafwk_abilitykit_lite", "//drivers/hdf/lite/manager:hdf_core", "//drivers/hdf/lite/adapter/osal/posix:hdf_posix_osal", ] defines = [ "OHOS_APPEXECFWK_BMS_BUNDLEMANAGER", ] if (enable_ohos_appexecfwk_feature_ability == true) { deps += [ "//foundation/graphic/lite/frameworks/ui:ui", ] defines += [ "ENABLE_WINDOW=1", "ABILITY_WINDOW_SUPPORT" ] } output_dir = "$root_out_dir/dev_tools/led" }
4. 应用配置文件 新建 applicationssamplecameramyLedAppconfig.json
{ "app": { "bundleName": "com.bluishfish.ledability", "vendor": "huawei", "version": { "code": 1, "name": "1.0" }, "apiVersion": { "compatible": 3, "target": 3 } }, "deviceConfig": { "default": { "keepAlive": false } }, "module": { "deviceType": [ "smartVision" ], "distro": { "deliveryWithInstall": true, "moduleName": "ledability", "moduleType": "entry" }, "abilities": [{ "name": "MainAbility", "icon": "assets/entry/resources/base/media/icon.png", "label": "Led Ability", "launchType": "standard", "type": "page", "visible": true } ] } }
5. 板级编译配置 复制 build/lite/product/ipcamera_hi3516dv300.json,改名为my_hi3516dv300在子系统里加入
{ "ohos_version": "OpenHarmony 1.0", "board": "hi3516dv300", "kernel": "liteos_a", "compiler": "clang", "subsystem": [ { "name": "aafwk", "component": [ "......", { "name": "ability_led", "dir": "//applications/sample/camera/myLedApp:ledability", "features": []} ] "......"
6. 编译应用
python build.py my_hi3516dv300 -b debug
将系统烧录到开发板上。
7. 打包应用 在 assetsentry esourcesasemedia目录下放置一个icon.png作为启动图标。
将applicationssamplecameramyLedAppconfig.json和 Z:openharmonyoutmy_hi3516dv300dev_toolsledlibledability.so打包压缩成zip包
改名为ledability.hap ,复制到NFS共享目录
8. 安装Hap
mkdir nfs mount 192.168.1.57:/nfs /nfs nfs ./nfs/dev_tools/bin/bm set -s disable ./nfs/dev_tools/bin/bm install -p ./nfs/ledability.hap
9. 运行程序
./nfs/dev_tools/bin/aa start -p com.bluishfish.ledability -n MainAbility
完美!
-
AI
+关注
关注
87文章
30758浏览量
268902 -
鸿蒙系统
+关注
关注
183文章
2634浏览量
66308
发布评论请先 登录
相关推荐
评论