前言
上一篇,我们体验了一下鸿蒙上的界面的开发流程,这一篇我们继续深入一点点,尝试打通从用户态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. 业务代码
先新建头文件vendor\huawei\hdf\led\include\led_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 */
再新建源文件 vendor\huawei\hdf\led\led_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\n", 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\n", 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. 添加编译文件
新建build\lite\config\subsystem\aafwk\BUILD.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. 主页面实现
新建源文件applications\sample\camera\myLedApp\src\main_ability.cpp
#include "main_ability.h"
namespace OHOS {
REGISTER_AA(MainAbility)
void MainAbility::OnStart(const Want &want)
{
printf("MainAbility::OnStart\n");
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\n");
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\n");
return HDF_FAILURE;
}
printf("%s: dev event received: %u %s\n", (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\n");
return 1;
}
struct HdfSBuf *reply = HdfSBufObtainDefaultSize();
if (reply == NULL)
{
printf("fail to obtain sbuf reply\n");
ret = HDF_DEV_ERR_NO_MEMORY;
HdfSBufRecycle(data);
return ret;
}
if (!HdfSbufWriteString(data, eventData))
{
printf("fail to write sbuf\n");
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\n");
HdfSBufRecycle(data);
HdfSBufRecycle(reply);
return ret;
}
int replyData = 0;
if (!HdfSbufReadInt32(reply, &replyData))
{
printf("fail to get service call reply\n");
ret = HDF_ERR_INVALID_OBJECT;
HdfSBufRecycle(data);
HdfSBufRecycle(reply);
return ret;
}
printf("Get reply is: %d\n", replyData);
HdfSBufRecycle(data);
HdfSBufRecycle(reply);
return ret;
}
2.4 加入点击事件
每次点击按钮,向内核态发送一次消息。
auto onClick = [this](UIView &view, const Event &event) -> bool {
printf("led button pressed\n");
struct HdfIoService *serv = HdfIoServiceBind(LED_SERVICE, 0);
if (serv == NULL)
{
printf("fail to get service %s\n", 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\n");
return false;
}
const char *send_cmd = "toggle LED";
if (SendEvent(serv, send_cmd))
{
printf("fail to send event\n");
return false;
}
if (HdfDeviceUnregisterEventListener(serv, &listener))
{
printf("fail to unregister listener\n");
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<UIViewGroup *>(tempView)->GetChildrenHead());
}
if (tempView->GetParent()) {
dynamic_cast<UIViewGroup *>(tempView->GetParent())->Remove(tempView);
}
delete tempView;
}
}
void MainAbilitySlice::OnStop()
{
printf("MainAbilitySlice::OnStop\n");
AbilitySlice::OnStop();
DeleteViewChildren(rootView_);
}
3. 编译配置
新增 applications\sample\camera\myLedApp\BUILD.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. 应用配置文件
新建 applications\sample\camera\myLedApp\config.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. 打包应用
在 assets\entry\resources\base\media\
目录下放置一个icon.png
作为启动图标。
将applications\sample\camera\myLedApp\config.json
和 Z:\openharmony\out\my_hi3516dv300\dev_tools\led\libledability.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
完美!
总结
整理一下思路,
我们先用AbilityKit
绘制Ability
页面,在其button1
上绑定一个按钮事件;
触发后,由用户子系统寻找到led_server
服务,向HDF框架发送消息;
内核驱动led_driver
接收到消息后,调用底层GPIO
控制LED
翻转,并将操作状态以reply
消息的形式传回用户侧;
后续可以接着根据返回状态更新下界面。
好了,在此基础上美化下界面,接个继电器做个智能家居的App
应该不是难事了。
源码下载
下一篇预告
用
C++
来写UI
开发效率总是不如java
和js
高的,何况还没法用上
DevEco Studio
辅助设计,下一篇我们尝试实现更多的设备能力,
并用JS框架来访问内核层,
敬请期待...