根据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里面,欢迎大家留言交流。

相关链接

【OpenHarmony】从入门到肝疼

Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐