【OpenHarmony】L1 新增SA
根据OpenHarmony开源社区的samgr_lite的说明文档,写一个SA的demo。
OpenHarmony L1 新增SA
根据OpenHarmony开源社区的samgr_lite的说明文档,写一个SA的demo。
https://gitee.com/openharmony/systemabilitymgr_samgr_lite
环境与设备说明
当前文档记录时,使用的是OpenHarmony4.0版本。
使用的L1设备是Hi3516,对应编译类型是ipcamera_hispark_taurus和ipcamera_hispark_taurus_linux,内核分别是liteos-a和linux。
另外,L0设备Hi3861,是单进程,没有IPC,没有SA。
demo代码
目录树
mymodule/lite/frameworks # SA框架
├── mini # L0对外接口实现的存放目录
├── small # L1的SA存放目录
│ └── include # 头文件存放目录
│ └── my_module_define.h
│ └── src # 源文件存放目录
│ └── my_module_client_proxy.c
│ └── my_module_feature.c
│ └── my_module_server.c
│ └── my_module_service.c
│ └── BUILD.gn # L1编译配置脚本
├── BUILD.gn # L0L1编译配置脚本
mymodule/lite/interfaces # 对外提供接口头文件路径
├── innerkits # C/C++使用
│ └── my_module_interface.h
├── kits # JS或其他使用
my_module_define.h
用于存放L1的SA代码常用的宏
#ifndef MY_MODULE_DEFINE_H
#define MY_MODULE_DEFINE_H
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#define MAX_DATA_LEN 1024
#define MODULE_STACK_SIZE 0x1000
#define MODULE_QUEUE_SIZE 20
#define EXAMPLE_SERVICE "example_service"
#define EXAMPLE_FEATURE "example_feature"
#define EXAMPLE_SUCCESS 0
#define EXAMPLE_FAILED (-1)
typedef enum {
MY_MODULE_MSG_PROC,
MY_MODULE_MSG_TIME_PROC,
MY_MODULE_MSG_HELLO,
MY_MODULE_MSG_ID_MAX
} MyModuleMsgID;
typedef struct {
int result;
size_t messageLen;
uint8_t *message;
} ServiceRspMsg;
#endif // MY_MODULE_DEFINE_H
my_module_server.c
L1的SA的开发服务
#include <unistd.h>
#include <stdio.h>
#include <ohos_init.h>
#include <iunknown.h>
#include "samgr_lite.h"
#include "my_module_define.h"
typedef struct {
INHERIT_SERVICE;
Identity identity;
} ExampleServer;
static const char *GetName(Service *service);
static BOOL Initialize(Service *service, Identity identity);
static BOOL MessageHandle(Service *service, Request *msg);
static TaskConfig GetTaskConfig(Service *service);
// 创建服务对象
static ExampleServer g_example = {
.GetName = GetName,
.Initialize = Initialize,
.MessageHandle = MessageHandle,
.GetTaskConfig = GetTaskConfig,
{-1, -1, NULL}
};
//实现服务的生命周期函数
static const char *GetName(Service *service)
{
(void)service;
return EXAMPLE_SERVICE;
}
static BOOL Initialize(Service *service, Identity identity)
{
ExampleServer *example = (ExampleServer *)service;
example->identity = identity;
return TRUE;
}
static BOOL MessageHandle(Service *service, Request *msg)
{
ExampleServer *example = (ExampleServer *)service;
(void)example;
switch (msg->msgId) {
case MY_MODULE_MSG_PROC:
//业务处理
break;
default: break;
}
return FALSE;
}
static TaskConfig GetTaskConfig(Service *service)
{
(void)service;
TaskConfig config = {LEVEL_HIGH, PRI_BELOW_NORMAL, MODULE_STACK_SIZE, MODULE_QUEUE_SIZE, SINGLE_TASK};
return config;
}
//向SAMGR注册服务及接口
static void Init(void)
{
SAMGR_GetInstance()->RegisterService((Service *)&g_example);
}
//定义服务的初始化入口
SYS_SERVICE_INIT(Init);
my_module_feature.c
L1的SA的开发服务的子功能
#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>
#include <unistd.h>
#include <securec.h>
#include <ohos_init.h>
#include <iunknown.h>
#include "samgr_lite.h"
#include "iproxy_client.h"
#include "iproxy_server.h"
#include "my_module_define.h"
typedef struct {
INHERIT_SERVER_IPROXY;
} ExampleFeatureApi;
typedef struct {
INHERIT_FEATURE;
INHERIT_IUNKNOWNENTRY(ExampleFeatureApi);
Identity identity;
Service *parent;
} ExampleFeature;
static const char *FEATURE_GetName(Feature *feature);
static void FEATURE_OnInitialize(Feature *feature, Service *parent, Identity identity);
static void FEATURE_OnStop(Feature *feature, Identity identity);
static BOOL FEATURE_OnMessage(Feature *feature, Request *request);
static int32_t Invoke(IServerProxy *iProxy, int funcId, void *origin, IpcIo *req, IpcIo *reply);
//创建功能对象
static ExampleFeature g_example = {
.GetName = FEATURE_GetName,
.OnInitialize = FEATURE_OnInitialize,
.OnStop = FEATURE_OnStop,
.OnMessage = FEATURE_OnMessage,
SERVER_IPROXY_IMPL_BEGIN,
.Invoke = Invoke,
IPROXY_END,
.identity = {-1, -1, NULL},
};
//实现功能的生命周期函数
static const char *FEATURE_GetName(Feature *feature)
{
(void)feature;
return EXAMPLE_FEATURE;
}
static void FEATURE_OnInitialize(Feature *feature, Service *parent, Identity identity)
{
ExampleFeature *exampleFeature = (ExampleFeature *)feature;
exampleFeature->identity = identity;
exampleFeature->parent = parent;
}
static void FEATURE_OnStop(Feature *feature, Identity identity)
{
(void)feature;
(void)identity;
g_example.identity.queueId = NULL;
g_example.identity.featureId = -1;
g_example.identity.serviceId = -1;
}
static BOOL FEATURE_OnMessage(Feature *feature, Request *request)
{
(void)feature;
if (request->msgId == MY_MODULE_MSG_PROC) {
Response response = {.data = "Yes, you did!", .len = 0};
SAMGR_SendResponse(request, &response);
return TRUE;
}
return FALSE;
}
static int32_t Invoke(IServerProxy *iProxy, int funcId, void *origin, IpcIo *req, IpcIo *reply)
{
(void)origin;
if ((iProxy == NULL) || (req == NULL) || (reply == NULL)) {
return EXAMPLE_FAILED;
}
size_t tempLen = 0;
uint8_t *buf = NULL;
switch (funcId) {
case MY_MODULE_MSG_HELLO:
buf = ReadString(req, &tempLen);
printf("[feature] tempLen:%u\n\r", tempLen);
printf("[feature] req: %s\n\r", buf);
WriteInt32(reply, EXAMPLE_SUCCESS);
WriteString(reply, "Hello world");
break;
default:
WriteInt32(reply, EXAMPLE_FAILED);
break;
}
return EXAMPLE_SUCCESS;
}
//向SAMGR注册功能及接口
static void Init(void)
{
SAMGR_GetInstance()->RegisterFeature(EXAMPLE_SERVICE, (Feature *)&g_example);
SAMGR_GetInstance()->RegisterFeatureApi(EXAMPLE_SERVICE, EXAMPLE_FEATURE, GET_IUNKNOWN(g_example));
}
//定义功能的初始化入口:
SYS_FEATURE_INIT(Init);
my_module_client_proxy.c
L1的客户端代理
#include <stdio.h>
#include <stdint.h>
#include <unistd.h>
#include <pthread.h>
#include <registry.h>
#include <securec.h>
#include <ohos_errno.h>
#include <ohos_types.h>
#include <iunknown.h>
#include "samgr_lite.h"
#include "iproxy_server.h"
#include "iproxy_client.h"
#include "my_module_define.h"
typedef struct {
INHERIT_CLIENT_IPROXY;
int32_t(*HandleModuleMsgSync)(IUnknown *iUnknown, const char *buff);
// int32_t(*HandleModuleMsgAsync)(IUnknown *iUnknown, const char *buff);
} MyModuleClientProxy;
typedef struct {
INHERIT_IUNKNOWNENTRY(MyModuleClientProxy);
} MyMoudleClientEntry;
static MyModuleClientProxy *g_clientProxy;
static int32_t HandleModuleMsgSync(IUnknown *iUnknown, const char *buff);
static void *CreateClient(const char *service, const char *feature, uint32 size);
static void DestroyClient(const char *service, const char *feature, void *iproxy);
static int32_t ModuleSamgrInitialize(void)
{
int32_t ret = (int32_t)SAMGR_RegisterFactory(EXAMPLE_SERVICE, EXAMPLE_FEATURE, CreateClient, DestroyClient);
if (ret != EXAMPLE_SUCCESS) {
return EXAMPLE_FAILED;
}
return EXAMPLE_SUCCESS;
}
static void *CreateClient(const char *service, const char *feature, uint32 size)
{
(void)service;
(void)feature;
uint32 len = size + sizeof(MyMoudleClientEntry);
uint8 *client = malloc(len);
if (client == NULL) {
return NULL;
}
(void)memset_s(client, len, 0, len);
MyMoudleClientEntry *entry = (MyMoudleClientEntry *)&client[size];
entry->ver = ((uint16)CLIENT_PROXY_VER | (uint16)DEFAULT_VERSION);
entry->ref = 1;
entry->iUnknown.QueryInterface = IUNKNOWN_QueryInterface;
entry->iUnknown.AddRef = IUNKNOWN_AddRef;
entry->iUnknown.Release = IUNKNOWN_Release;
entry->iUnknown.Invoke = NULL;
entry->iUnknown.HandleModuleMsgSync = HandleModuleMsgSync;
// entry->iUnknown.HandleModuleMsgAsync = HandleModuleMsgAsync;
return client;
}
void DestroyClient(const char *service, const char *feature, void *iproxy)
{
(void)service;
(void)feature;
if (iproxy != NULL) {
free(iproxy);
iproxy = NULL;
}
}
static int32_t GetModuleClientApi()
{
IUnknown *iUnknown = SAMGR_GetInstance()->GetFeatureApi(EXAMPLE_SERVICE, EXAMPLE_FEATURE);
if (iUnknown == NULL) {
return EXAMPLE_FAILED;
}
int32_t ret = iUnknown->QueryInterface(iUnknown, DEFAULT_VERSION, (void **)&g_clientProxy);
if (ret != EXAMPLE_SUCCESS || g_clientProxy == NULL) {
return EXAMPLE_FAILED;
}
return EXAMPLE_SUCCESS;
}
// 消息回调函数
static int HandleModuleMsgCb(void *owner, int code, IpcIo *reply)
{
(void)code;
if ((owner == NULL) || (reply == NULL)) {
return EXAMPLE_FAILED;
}
ServiceRspMsg *respInfo = (ServiceRspMsg *)owner;
if (!ReadInt32(reply, &respInfo->result)) {
return EXAMPLE_FAILED;
}
if (respInfo->result == EXAMPLE_SUCCESS) {
respInfo->message = ReadString(reply, &respInfo->messageLen);
printf("[HandleModuleMsgCb] message:%s\n\r", respInfo->message);
}
return EXAMPLE_SUCCESS;
}
static int32_t HandleModuleMsgSync(IUnknown *iUnknown, const char *buff)
{
MyModuleClientProxy *proxy = (MyModuleClientProxy *)iUnknown;
// IPC消息传入
IpcIo request;
char data[MAX_DATA_LEN];
IpcIoInit(&request, data, MAX_DATA_LEN, 0);
(void)WriteString(&request, buff);
// IPC消息获取
ServiceRspMsg reply = { 0 };
// 使用同步调用IPC
int ret = proxy->Invoke((IClientProxy *)proxy, MY_MODULE_MSG_HELLO, &request, &reply, HandleModuleMsgCb);
if (ret != EXAMPLE_SUCCESS) {
return EXAMPLE_FAILED;
}
if (reply.result != EXAMPLE_SUCCESS) {
return EXAMPLE_FAILED;
}
return EXAMPLE_SUCCESS;
}
// static int32_t HandleModuleMsgAsync(IUnknown *iUnknown, const char *buff)
// {
// MyModuleClientProxy *proxy = (MyModuleClientProxy *)iUnknown;
// // IPC消息传入
// IpcIo request;
// char data[MAX_DATA_LEN];
// IpcIoInit(&request, data, MAX_DATA_LEN, 0);
// WriteString(&request, buff);
// // 使用异步调用IPC
// int ret = proxy->Invoke((IClientProxy *)proxy, MY_MODULE_MSG_HELLO, &request, NULL, NULL);
// return ret == EC_SUCCESS;
// }
int HandleModule(void)
{
int32_t ret = ModuleSamgrInitialize();
if (ret != EXAMPLE_SUCCESS) {
return EXAMPLE_FAILED;
}
ret = GetModuleClientApi();
if ((ret != EXAMPLE_SUCCESS) || (g_clientProxy == NULL)) {
return EXAMPLE_FAILED;
}
if (g_clientProxy->HandleModuleMsgSync == NULL) {
return EXAMPLE_FAILED;
}
ret = g_clientProxy->HandleModuleMsgSync((IUnknown *)g_clientProxy, "Hi");
if (ret != EXAMPLE_SUCCESS) {
printf("[HandleModule] ret:%d\n\r", ret);
}
(void)g_clientProxy->Release((IUnknown *)g_clientProxy);
return EXAMPLE_SUCCESS;
}
moduleservice.c
#include <stdio.h>
#include <unistd.h>
#include <samgr_lite.h>
#define MY_MODULE_SLEEP_TIME 2
int main(void)
{
sleep(MY_MODULE_SLEEP_TIME);
printf("my_module-start:SAMGR_Bootstrap\r\n");
SAMGR_Bootstrap();
while (1) {
pause();
}
return 0;
}
small目录下的BUILD.gn
import("//build/lite/config/component/lite_component.gni")
CFLAGS_COMMON = [
"-ftrapv",
"-Werror",
"-Wextra",
"-Wshadow",
"-fstack-protector-all",
"-D_FORTIFY_SOURCE=2",
"-Wformat=2",
"-Wfloat-equal",
"-Wdate-time",
]
INCLUDE_COMMON = [ "include" ]
# L1 server
shared_library("my_module_server") {
sources = [
"src/my_module_feature.c",
"src/my_module_server.c",
]
cflags = CFLAGS_COMMON
cflags += [ "-fPIC" ]
ldflags = [ "-pthread" ]
include_dirs = INCLUDE_COMMON
deps = [ "//foundation/systemabilitymgr/samgr_lite/samgr:samgr" ]
}
# L1 client
shared_library("my_module_client") {
sources = [ "src/my_module_client_proxy.c" ]
cflags = CFLAGS_COMMON
cflags += [ "-fPIC" ]
ldflags = [ "-pthread" ]
include_dirs = INCLUDE_COMMON
include_dirs += [ "../../../interfaces/innerkits" ]
deps = [ "//foundation/systemabilitymgr/samgr_lite/samgr:samgr" ]
}
# L1 service bin
executable("my_module_service") {
sources = [ "src/my_module_service.c" ]
cflags = CFLAGS_COMMON
ldflags = [ "-pthread" ]
include_dirs = INCLUDE_COMMON
deps = [
":my_module_server",
"//foundation/systemabilitymgr/samgr_lite/samgr:samgr",
]
}
small上一级目录的BUILD.gn
import("//build/lite/config/component/lite_component.gni")
lite_component("my_module_lite") {
if (ohos_kernel_type == "liteos_m") {
features = []
} else {
features = [
"small:my_module_client",
"small:my_module_service",
]
}
}
my_module_interface.h
对外提供接口
#ifndef MY_MODULE_INTERFACE_H
#define MY_MODULE_INTERFACE_H
#ifdef __cplusplus
#if __cplusplus
extern "C" {
#endif
#endif /* __cplusplus */
// 自定义接口
int HandleModule(void);
#ifdef __cplusplus
#if __cplusplus
}
#endif
#endif /* __cplusplus */
#endif // MY_MODULE_INTERFACE_H
SA的IPC提供的接口
foundation/communication/ipc/interfaces/innerkits/c/ipc/include/serializer.h
代码编译
关于代码编译问题,可以查看这篇文章:
【OpenHarmony】L0L1 添加子系统/组件
新增启动进程
拿hispark_taurus举例:
在目录vendor\hisilicon\hispark_taurus\init_configs下,对文件
init_liteos_a_3516dv300.cfg 和
init_liteos_a_3516dv300_mksh.cfg 进行修改
“jobs” -> {“name” : “init” …} -> "cmds"下,增加
"start my_module_service"
以及在"services"下增加
{
"name" : "my_module_service",
"path":["/bin/my_module_service"],
"uid":0',
"gid":0,
"once":1,
"importance":0,
"caps":[]
}
注意:正式代码,不建议给uid和gid设置为0,root权限。uid和gid不为0时,遇到调用底层接口报错,可以在"caps"增加对应的linux的能力capability。
新增SA的IPC权限
修改文件base\security\permission_lite\services\ipc_auth\include\policy_preset.h
增加内容:
FeaturePolicy mymoduleFeature[] = {
{
"example_feature",
{
{
.type = RANGE,
.uidMin = 0,
.uidMax = __INT_MAX__,
},
},
},
};
以及在g_presetPolicies[]里面增加
{"example_service", mymoduleFeature, 1}
注意,“example_service"对应my_module_define.h里的"example_service”,且其长度最长15个字节。
生成文件
编译生成的bin文件在
out/hispark_taurus/ipcamera_hispark_taurus/bin
编译生成的so文件在
out/hispark_taurus/ipcamera_hispark_taurus/usr/lib
smaple样例
写一个测试样例,调用interfaces的接口,测试客户端与服务端的IPC。
my_module_smaple.c
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <my_module_interface.h>
int main(int argc, char **argv)
{
int ret = HandleModule();
printf("[test] ret: %d\n\r", ret);
return 0;
}
BUILD.gn
自行完成
更多
运行smaple样例之后,日志串口会打印
[ERR][hello_test:thread2]LiteIpcRead failed ERROR: -132
其中LiteIpcRead属于是内核里IPC通信机制,在目录kernel里。
而-132,对应的错误码是ERFKILL(Linux内核错误码大全)。是因为my_module_smaple.c里执行完业务接口后,就直接return 0了,导致IPC的信号断开。
如果不想出现这句报错打印,在my_module_smaple.c最后添加
while (1) {
pause();
}
这个SA的demo,有些部分与开源社区提供的文档有出入。我遇到的一些问题,也会放到Q&A里面,欢迎大家留言交流。
相关链接
更多推荐
所有评论(0)