文章目录
-
- 文档说明
- 目录
- [1. Samgr Lite 介绍](#1. Samgr Lite 介绍)
-
- [1.1 什么是 Samgr Lite](#1.1 什么是 Samgr Lite)
- [1.2 核心概念](#1.2 核心概念)
- [1.3 目录结构](#1.3 目录结构)
- [2. 核心 API 详解](#2. 核心 API 详解)
-
- [2.1 SamgrLite 主类接口](#2.1 SamgrLite 主类接口)
- [2.2 Service 结构详解](#2.2 Service 结构详解)
- [2.3 Feature 结构详解](#2.3 Feature 结构详解)
- [2.4 IUnknown 接口详解](#2.4 IUnknown 接口详解)
- [2.5 TaskConfig 任务配置详解](#2.5 TaskConfig 任务配置详解)
- [3. 服务端-客户端框架介绍](#3. 服务端-客户端框架介绍)
-
- [3.1 整体架构](#3.1 整体架构)
- [3.2 服务端实现流程](#3.2 服务端实现流程)
- [3.3 客户端实现流程](#3.3 客户端实现流程)
- [4. 普通接入调用示例](#4. 普通接入调用示例)
-
- [4.1 服务端完整示例](#4.1 服务端完整示例)
- [4.2 客户端完整调用示例](#4.2 客户端完整调用示例)
- [4.3 使用示例](#4.3 使用示例)
- [5. 深入分析回调接口实现](#5. 深入分析回调接口实现)
-
- [5.1 回调机制概述](#5.1 回调机制概述)
- [5.2 回调类型定义](#5.2 回调类型定义)
- [5.3 服务端回调管理器实现](#5.3 服务端回调管理器实现)
- [5.4 客户端回调处理](#5.4 客户端回调处理)
- [5.5 带回调的 IPC 调用流程](#5.5 带回调的 IPC 调用流程)
- [6. 权限管理与 SA 启动](#6. 权限管理与 SA 启动)
-
- [6.1 权限管理机制](#6.1 权限管理机制)
- [6.2 策略配置示例](#6.2 策略配置示例)
- [6.3 SA 启动流程](#6.3 SA 启动流程)
- [6.4 启动宏说明](#6.4 启动宏说明)
- [6.5 Bootstrap 服务](#6.5 Bootstrap 服务)
- [7. 常用数据结构使用](#7. 常用数据结构使用)
-
- [7.1 Vector 动态数组](#7.1 Vector 动态数组)
- [7.2 Doubly Linked List(双向链表)](#7.2 Doubly Linked List(双向链表))
- [7.3 Identity 消息标识](#7.3 Identity 消息标识)
- [7.4 Request/Response 消息结构](#7.4 Request/Response 消息结构)
- [7.5 IUnknownEntry 接口入口](#7.5 IUnknownEntry 接口入口)
- [8. 实战:完整 SA 开发模板](#8. 实战:完整 SA 开发模板)
-
- [8.1 目录结构](#8.1 目录结构)
- [8.2 类型定义](#8.2 类型定义)
- [8.3 Service 实现](#8.3 Service 实现)
- [8.4 Feature 实现](#8.4 Feature 实现)
- [8.5 Proxy 实现](#8.5 Proxy 实现)
- [8.6 对外头文件](#8.6 对外头文件)
- [8.7 使用示例](#8.7 使用示例)
- [附录 A:常用宏速查表](#附录 A:常用宏速查表)
- [附录 B:错误码定义](#附录 B:错误码定义)
- [附录 D:IPC/RPC 框架接口详解](#附录 D:IPC/RPC 框架接口详解)
-
- [D.1 IPC 框架架构](#D.1 IPC 框架架构)
- [附录 E:常见问题与调试技巧](#附录 E:常见问题与调试技巧)
-
- [E.1 调试 IPC 通信](#E.1 调试 IPC 通信)
- [E.2 常见错误](#E.2 常见错误)
- 参考文件列表(完整)
-
- [Samgr Lite 相关](#Samgr Lite 相关)
- [IPC/RPC 相关](#IPC/RPC 相关)
- 工具类
文档说明
本文档基于 OpenHarmony 的标准 IPC/RPC 框架编写,参考了:
foundation/systemabilitymgr/samgr_lite- 系统能力管理器foundation/communication/ipc- 进程间通信框架foundation/controller/controller_service- 实际控制器服务示例
目录
- [Samgr Lite 介绍](#Samgr Lite 介绍)
- [核心 API 详解](#核心 API 详解)
- 服务端-客户端框架介绍
- 普通接入调用示例
- 深入分析回调接口实现
- [权限管理与 SA 启动](#权限管理与 SA 启动)
- 常用数据结构使用
- [实战:完整 SA 开发模板](#实战:完整 SA 开发模板)
1. Samgr Lite 介绍
1.1 什么是 Samgr Lite
Samgr Lite 是 OpenHarmony 小型系统系统能力管理框架,负责管理系统中的各种服务(Service)和功能(Feature),提供服务的注册、发现和跨进程通信能力。
核心特性:
| 特性 | 说明 |
|---|---|
| 服务注册 | 将自定义 SA 注册到系统 |
| 服务发现 | 客户端获取服务接口进行调用 |
| 进程间通信 | IPC 机制支持跨进程调用 |
| 生命周期管理 | 服务的初始化、消息处理、停止 |
| 权限控制 | 基于策略的访问控制 |
1.2 核心概念
┌─────────────────────────────────────────────────────────────────┐
│ Samgr Lite │
├─────────────────────────────────────────────────────────────────┤
│ │
│ ┌──────────────────┐ ┌──────────────────┐ │
│ │ Service │ │ Service │ │
│ │ ┌────────────┐ │ │ ┌────────────┐ │ │
│ │ │ Feature │ │ │ │ Feature │ │ │
│ │ │ ┌────────┐ │ │ │ │ ┌────────┐ │ │ │
│ │ │ │IUnknown│ │ │ │ │ │IUnknown│ │ │ │
│ │ │ └────────┘ │ │ │ │ └────────┘ │ │ │
│ │ └────────────┘ │ │ └────────────┘ │ │
│ └──────────────────┘ └──────────────────┘ │
│ │
│ ▲ 跨进程调用通过 Endpoint/IPC │
│ │
│ ┌──────────────────┐ ┌──────────────────┐ │
│ │ 客户端 Proxy │ ──── │ 服务端 Stub │ │
│ └──────────────────┘ └──────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────┘
三层架构:
- Service(服务):最顶层容器,管理多个 Feature
- Feature(功能):具体的功能模块,提供 IUnknown 接口
- IUnknown(接口):对外暴露的 API 接口,支持版本管理
1.3 目录结构
foundation/systemabilitymgr/samgr_lite/
├── interfaces/kits/
│ ├── samgr/ # Samgr 核心头文件
│ │ ├── samgr_lite.h # SamgrLite 主接口类
│ │ ├── service.h # Service 结构定义
│ │ ├── feature.h # Feature 结构定义
│ │ ├── message.h # 消息通信结构
│ │ ├── iunknown.h # IUnknown 接口基类
│ │ └── common.h # 通用工具宏/结构
│ └── registry/ # IPC 注册相关
│ ├── iproxy_client.h # 客户端代理
│ ├── iproxy_server.h # 服务端代理
│ └── registry.h # 服务注册
├── samgr/
│ ├── source/ # Samgr 核心实现
│ │ ├── samgr_lite.c # SamgrLite 主实现
│ │ ├── service.c # Service 管理
│ │ ├── feature.c # Feature 管理
│ │ ├── service_impl.c # ServiceImpl
│ │ ├── feature_impl.c # FeatureImpl
│ │ ├── iunknown.c # IUnknown 实现
│ │ ├── message.c # 消息处理
│ │ └── task_manager.c # 任务/线程管理
│ └── registry/ # 服务注册实现
├── samgr_endpoint/ # IPC Endpoint
│ └── source/
│ └── endpoint.c # IPC 端点
└── adapter/ # 平台适配层
├── memory_adapter.h # 内存管理
├── thread_adapter.h # 线程管理
├── time_adapter.h # 时间管理
└── queue_adapter.h # 队列管理
2. 核心 API 详解
2.1 SamgrLite 主类接口
SamgrLite 是整个框架的核心入口,通过 SAMGR_GetInstance() 获取单例实例。
c
// samgr_lite.h
typedef struct SamgrLite {
// ===== 服务管理 =====
BOOL (*RegisterService)(Service *service); // 注册服务
Service *(*UnregisterService)(const char *name); // 注销服务
// ===== Feature 管理 =====
BOOL (*RegisterFeature)(const char *serviceName, Feature *feature); // 注册 Feature
Feature *(*UnregisterFeature)(const char *serviceName, const char *featureName); // 注销 Feature
// ===== 接口 API 管理 =====
BOOL (*RegisterDefaultFeatureApi)(const char *service, IUnknown *publicApi); // 注册默认接口
IUnknown *(*UnregisterDefaultFeatureApi)(const char *service); // 注销默认接口
BOOL (*RegisterFeatureApi)(const char *service, const char *feature, IUnknown *publicApi); // 注册 Feature 接口
IUnknown *(*UnregisterFeatureApi)(const char *service, const char *feature); // 注销 Feature 接口
// ===== 接口获取 =====
IUnknown *(*GetDefaultFeatureApi)(const char *service); // 获取默认接口
IUnknown *(*GetFeatureApi)(const char *serviceName, const char *feature); // 获取 Feature 接口
#ifdef MINI_SAMGR_LITE_RPC
IUnknown *(*GetRemoteDefaultFeatureApi)(char *deviceId, const char *serviceName); // 远程获取
#endif
// ===== 系统能力 =====
int32 (*AddSystemCapability)(const char *sysCap); // 添加系统能力
BOOL (*HasSystemCapability)(const char *sysCap); // 检查系统能力
int32 (*GetSystemAvailableCapabilities)(char sysCaps[][MAX_SYSCAP_NAME_LEN], int32 *sysCapNum); // 获取所有能力
} SamgrLite;
2.2 Service 结构详解
c
// service.h
struct Service {
// 获取服务名称(必填,返回字符串指针)
const char *(*GetName)(Service *service);
// 服务初始化(必填,在任务线程中调用)
BOOL (*Initialize)(Service *service, Identity identity);
// 消息处理(必填,处理客户端请求)
BOOL (*MessageHandle)(Service *service, Request *request);
// 获取任务配置(必填,配置服务运行参数)
TaskConfig (*GetTaskConfig)(Service *service);
};
Service 生命周期:
注册服务 ──► SAMGR_Bootstrap() ──► 创建任务线程 ──► Initialize() ──► MessageHandle()
│ │ │
│ ▼ │
│ 创建消息队列 │
│ ▼
│ 处理客户端请求
│ │
▼ ▼
注销服务 服务运行中
2.3 Feature 结构详解
c
// feature.h
struct Feature {
// 获取 Feature 名称
const char *(*GetName)(Feature *feature);
// 初始化(在 OnInitialize 中注册 IPC 接口)
void (*OnInitialize)(Feature *feature, Service *parent, Identity identity);
// 停止(清理资源)
void (*OnStop)(Feature *feature, Identity identity);
// 消息处理
BOOL (*OnMessage)(Feature *feature, Request *request);
};
2.4 IUnknown 接口详解
IUnknown 是所有对外接口的基类,支持版本管理和引用计数:
c
// iunknown.h
struct IUnknown {
// 查询接口版本(向下转型)
int (*QueryInterface)(IUnknown *iUnknown, int version, void **target);
// 增加引用计数
int (*AddRef)(IUnknown *iUnknown);
// 释放引用
int (*Release)(IUnknown *iUnknown);
};
使用宏快速实现:
c
// 定义接口实现类
typedef struct {
INHERIT_IUNKNOWNENTRY(ControllerFrameworkApi);
// 自定义成员...
} ControllerFrameworkEntry;
// 初始化
static ControllerFrameworkEntry g_entry = {
IUNKNOWN_ENTRY_BEGIN(DEFAULT_VERSION),
.QueryInterface = MyQueryInterface,
.AddRef = IUNKNOWN_AddRef,
.Release = IUNKNOWN_Release,
// 其他函数指针...
IUNKNOWN_ENTRY_END
};
// 获取 IUnknown 指针
IUnknown *api = GET_IUNKNOWN(g_entry);
2.5 TaskConfig 任务配置详解
c
// service.h
struct TaskConfig {
int16 level; // 任务级别(SHARED_TASK 共享时使用)
int16 priority; // 优先级 (9-38)
uint16 stackSize; // 栈大小
uint16 queueSize; // 消息队列大小
uint8 taskFlags; // 任务类型
};
// 任务类型枚举
typedef enum TaskType {
SHARED_TASK = 0, // 共享任务(多个服务共用)
SINGLE_TASK = 1, // 独占任务(独立线程)
SPECIFIED_TASK = 2, // 指定任务(相同配置的服务共享)
NO_TASK = 0xFF, // 无任务
} TaskType;
// 预设任务级别
typedef enum SpecifyTag {
LEVEL_HIGH = 0, // 高级
LEVEL_MIDDLE = 1, // 中级
LEVEL_LOW = 2, // 低级
LEVEL_CUSTOM_BEGIN, // 自定义起始
} SpecifyTag;
3. 服务端-客户端框架介绍
3.1 整体架构
┌─────────────────────────────────────────────────────────────────────────────┐
│ 客户端进程 │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ ┌──────────────┐ ┌──────────────────┐ │
│ │ 应用代码 │────────▶│ Client Proxy │ │
│ │ │ │ (IUnknown) │ │
│ └──────────────┘ └────────┬─────────┘ │
│ │ │
│ │ Invoke() │
│ ▼ │
│ ┌──────────────┐ ┌──────────────────┐ │
│ │ IPC 适配层 │◀────────│ IPC Stub │ │
│ └──────────────┘ └──────────────────┘ │
│ │ │
└──────────────────────────────────────│─────────────────────────────────────┘
│ LiteIPC
┌──────────────────────────────────────│─────────────────────────────────────┐
│ 服务端进程 │
│ ▼ │
│ ┌──────────────┐ ┌──────────────────┐ │
│ │ IPC 骨架 │────────▶│ Server Stub │ │
│ └──────────────┘ │ (IServerProxy) │ │
│ └────────┬─────────┘ │
│ │ │
│ │ Invoke() │
│ ▼ │
│ ┌──────────────┐ ┌──────────────────┐ │
│ │ Service │◀────────│ Feature │ │
│ │ │ │ (业务逻辑) │ │
│ └──────────────┘ └──────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────────────┘
3.2 服务端实现流程
Step 1: 定义 Service
c
// 1. 定义 Service 结构体
typedef struct {
INHERIT_SERVICE; // 继承服务接口
Identity identity; // 保存系统分配的标识
} MyService;
// 2. 实现服务方法
static const char *MyGetName(Service *service)
{
(void)service;
return "MyService"; // 服务名称(唯一标识)
}
static BOOL MyInitialize(Service *service, Identity identity)
{
MyService *myService = (MyService *)service;
myService->identity = identity;
HILOG_INFO("MyService initialized, serviceId=%d", identity.serviceId);
return TRUE;
}
static BOOL MyMessageHandle(Service *service, Request *request)
{
// 处理同步消息(一般用于 Samgr 内部消息)
(void)service;
(void)request;
return FALSE;
}
static TaskConfig MyGetTaskConfig(Service *service)
{
(void)service;
// 返回任务配置:高级、中优先级、独立任务
return (TaskConfig){LEVEL_HIGH, PRI_NORMAL, 4096, 32, SINGLE_TASK};
}
// 3. 定义全局服务实例
static MyService g_myService = {
.GetName = MyGetName,
.Initialize = MyInitialize,
.MessageHandle = MyMessageHandle,
.GetTaskConfig = MyGetTaskConfig,
.identity = {-1, -1, NULL}
};
// 4. 注册函数
static void MyServiceInit(void)
{
SAMGR_GetInstance()->RegisterService((Service *)&g_myService);
}
// 5. 使用宏自动注册
SYS_SERVICE_INIT(MyServiceInit); // 系统服务初始化宏
Step 2: 定义 Feature
c
// 1. 定义 Feature 结构体
typedef struct {
INHERIT_FEATURE; // 继承 Feature 接口
INHERIT_IUNKNOWNENTRY(MyFeatureApi); // 继承 IUnknown 入口
Identity identity; // Feature 标识
Service *parent; // 父 Service
} MyFeature;
// 2. 定义业务 API 接口
typedef struct {
INHERIT_SERVER_IPROXY; // 继承服务端代理
// 业务方法(可选,根据需要定义)
int32 (*MyMethod)(IServerProxy *iProxy, int32 param1, const char *param2);
} MyFeatureApi;
// 3. 实现 Feature 方法
static const char *FeatureGetName(Feature *feature)
{
(void)feature;
return "MyFeature";
}
static void FeatureOnInitialize(Feature *feature, Service *parent, Identity identity)
{
MyFeature *myFeature = (MyFeature *)feature;
myFeature->identity = identity;
myFeature->parent = parent;
// 在此初始化业务资源
HILOG_INFO("MyFeature initialized");
}
static void FeatureOnStop(Feature *feature, Identity identity)
{
(void)feature;
(void)identity;
// 清理业务资源
}
static BOOL FeatureOnMessage(Feature *feature, Request *request)
{
(void)feature;
(void)request;
return FALSE;
}
// 4. IPC 调用入口(核心!)
static int32_t FeatureInvoke(IServerProxy *iProxy, int32_t funcId,
void *origin, IpcIo *req, IpcIo *reply)
{
(void)origin;
uint32_t ret = CTRL_OK;
switch (funcId) {
case MY_IPC_METHOD_1: {
// 读取请求参数
uint32_t param1 = 0;
if (!ReadUint32(req, ¶m1)) {
ret = CTRL_PARAMS_ERROR;
break;
}
// 执行业务逻辑
ret = DoSomething(param1);
// 写入响应
WriteInt32(reply, (int32_t)ret);
break;
}
default:
ret = CTRL_PARAMS_ERROR;
break;
}
return ret;
}
// 5. 定义 Feature 实例
static MyFeature g_myFeature = {
.GetName = FeatureGetName,
.OnInitialize = FeatureOnInitialize,
.OnStop = FeatureOnStop,
.OnMessage = FeatureOnMessage,
SERVER_IPROXY_IMPL_BEGIN,
.Invoke = FeatureInvoke,
IPROXY_END,
.identity = {-1, -1, NULL},
};
// 6. Feature 注册函数
static void MyFeatureInit(void)
{
// 注册 Feature
SAMGR_GetInstance()->RegisterFeature("MyService", (Feature *)&g_myFeature);
// 注册 Feature 的 API
SAMGR_GetInstance()->RegisterFeatureApi("MyService", "MyFeature",
GET_IUNKNOWN(g_myFeature));
}
// 7. 使用宏自动注册
SYS_FEATURE_INIT(MyFeatureInit);
Step 3: main 函数入口
c
#include <samgr_lite.h>
#include <ohos_init.h>
static void SystemInit(void *argv)
{
(void)argv;
HILOG_INFO("System starting...");
SAMGR_Bootstrap(); // 启动所有已注册的服务
HILOG_INFO("System started");
}
int main(void)
{
sleep(1); // 等待系统就绪
SystemInit(NULL);
while (1) {
pause(); // 主线程进入睡眠
}
return 0;
}
3.3 客户端实现流程
Step 1: 定义 Proxy 结构体
c
// controller_proxy_internal.h
typedef struct {
INHERIT_CLIENT_IPROXY; // 继承客户端代理
// 业务方法
int32 (*MyMethod)(IUnknown *iUnknown, uint32_t param1);
int32 (*AnotherMethod)(IUnknown *iUnknown, const char *data);
} MyClientProxy;
typedef struct {
INHERIT_IUNKNOWNENTRY(MyClientProxy);
} MyClientEntry;
Step 2: 实现 Proxy 方法
c
// proxy 实现文件
// IPC 响应回调
static int32_t ProxyInvokeCallback(void *owner, int32_t code, IpcIo *reply)
{
(void)owner;
if (reply == NULL) {
return CTRL_FAIL;
}
int32_t result = CTRL_FAIL;
ReadInt32(reply, &result);
return result;
}
// 具体 Proxy 方法实现
static int32_t ProxyMyMethod(IUnknown *iUnknown, uint32_t param1)
{
if (iUnknown == NULL) {
return CTRL_PARAMS_ERROR;
}
MyClientProxy *proxy = (MyClientProxy *)iUnknown;
// 1. 准备请求数据
uint8_t ipcBuffer[256];
IpcIo req;
IpcIoInit(&req, ipcBuffer, sizeof(ipcBuffer), 0);
WriteUint32(&req, param1);
// 2. 发起 IPC 调用
int32_t ret = proxy->Invoke((IClientProxy *)proxy,
MY_IPC_METHOD_1, // 方法 ID
&req,
NULL, // owner
ProxyInvokeCallback); // 回调
return (ret == EC_SUCCESS) ? CTRL_OK : CTRL_FAIL;
}
// Proxy 注册
void MyProxyRegister(MyClientProxy *proxy)
{
proxy->MyMethod = ProxyMyMethod;
// 其他方法...
}
Step 3: 客户端代理管理
c
static MyClientEntry *g_clientEntry = NULL;
// 获取代理
int32_t AcquireProxy(void)
{
if (g_clientEntry != NULL) {
g_clientEntry->ref++;
return CTRL_OK;
}
// 从 Samgr 获取服务 API
IUnknown *api = SAMGR_GetInstance()->GetFeatureApi("MyService", "MyFeature");
if (api == NULL) {
return CTRL_FAIL;
}
// 查询特定版本
int ret = api->QueryInterface(api, DEFAULT_VERSION, (void **)&g_clientEntry);
if (ret != EC_SUCCESS) {
return CTRL_FAIL;
}
// 注册方法
MyProxyRegister((MyClientProxy *)g_clientEntry);
return CTRL_OK;
}
// 释放代理
void ReleaseProxy(void)
{
if (g_clientEntry != NULL) {
g_clientEntry->ref--;
if (g_clientEntry->ref <= 0) {
g_clientEntry->iUnknown.Release((IUnknown *)g_clientEntry);
g_clientEntry = NULL;
}
}
}
// 对外接口
int32_t MyClientMethod(uint32_t param)
{
if (AcquireProxy() != CTRL_OK) {
return CTRL_FAIL;
}
MyClientProxy *proxy = (MyClientProxy *)g_clientEntry;
int32_t ret = proxy->MyMethod((IUnknown *)proxy, param);
ReleaseProxy();
return ret;
}
4. 普通接入调用示例
4.1 服务端完整示例
以 Controller Service 为例,展示完整的数字量 IO 控制服务:
c
/*
* controller_stub_feature.c - 服务端 Feature 实现
*/
#include <stdio.h>
#include <ohos_init.h>
#include <iunknown.h>
#include <samgr_lite.h>
#include <iproxy_server.h>
// ========== 类型定义 ==========
typedef struct {
INHERIT_SERVER_IPROXY;
} ControllerFrameworkApi;
typedef struct {
INHERIT_FEATURE;
INHERIT_IUNKNOWNENTRY(ControllerFrameworkApi);
Identity identity;
Service *parent;
} ControllerFrameworkFeature;
// ========== 业务实现 ==========
// 数字量输出控制
static uint32_t IoPortControl(uint32_t groupIndex, uint32_t portNum, int32_t level)
{
// 实际硬件操作在此实现
HILOG_INFO("PortControl: group=%d, port=%d, level=%d", groupIndex, portNum, level);
return CTRL_OK;
}
// 数字量输入检测
static uint32_t IoPortDetect(uint32_t groupIndex, uint32_t portNum, int32_t *state)
{
// 实际读取 GPIO 状态
*state = ReadGpioLevel(groupIndex, portNum);
return CTRL_OK;
}
// ========== Feature 方法 ==========
static const char *GetName(Feature *feature)
{
(void)feature;
return "ControllerFeature";
}
static void OnInitialize(Feature *feature, Service *parent, Identity identity)
{
ControllerFrameworkFeature *ctrlFeature = (ControllerFrameworkFeature *)feature;
ctrlFeature->identity = identity;
ctrlFeature->parent = parent;
// 初始化硬件资源
InitHardware();
HILOG_INFO("Controller Feature initialized");
}
static void OnStop(Feature *feature, Identity identity)
{
(void)feature;
(void)identity;
// 释放硬件资源
DeinitHardware();
}
static BOOL OnMessage(Feature *feature, Request *request)
{
(void)feature;
(void)request;
return FALSE;
}
// ========== IPC 入口 ==========
static int32_t Invoke(IServerProxy *iProxy, int32_t funcId,
void *origin, IpcIo *req, IpcIo *reply)
{
(void)origin;
uint32_t ret = CTRL_OK;
switch (funcId) {
case CONTROLLER_IPC_PORT_CONTROL: {
// 读取参数
uint32_t groupIndex = 0;
uint32_t portNum = 0;
int32_t level = 0;
if (!ReadUint32(req, &groupIndex) ||
!ReadUint32(req, &portNum) ||
!ReadInt32(req, &level)) {
ret = CTRL_PARAMS_ERROR;
break;
}
// 执行业务
ret = IoPortControl(groupIndex, portNum, level);
// 写回结果
WriteInt32(reply, (int32_t)ret);
break;
}
case CONTROLLER_IPC_PORT_DETECT: {
uint32_t groupIndex = 0;
uint32_t portNum = 0;
int32_t state = 0;
if (!ReadUint32(req, &groupIndex) || !ReadUint32(req, &portNum)) {
ret = CTRL_PARAMS_ERROR;
break;
}
ret = IoPortDetect(groupIndex, portNum, &state);
WriteInt32(reply, (int32_t)ret);
WriteInt32(reply, state); // 附加输出参数
break;
}
default:
ret = CTRL_PARAMS_ERROR;
break;
}
return ret;
}
// ========== Feature 定义与注册 ==========
static ControllerFrameworkFeature g_controllerFeature = {
.GetName = GetName,
.OnInitialize = OnInitialize,
.OnStop = OnStop,
.OnMessage = OnMessage,
SERVER_IPROXY_IMPL_BEGIN,
.Invoke = Invoke,
IPROXY_END,
.identity = {-1, -1, NULL},
};
static void Init(void)
{
SAMGR_GetInstance()->RegisterFeature("ControllerService",
(Feature *)&g_controllerFeature);
SAMGR_GetInstance()->RegisterFeatureApi("ControllerService",
"ControllerFeature",
GET_IUNKNOWN(g_controllerFeature));
}
SYS_FEATURE_INIT(Init);
4.2 客户端完整调用示例
c
/*
* controller_proxy_io.c - 客户端 Proxy 实现
*/
#include <iproxy_client.h>
#define IPC_BUFFER_SIZE 256
// ========== IPC 回调 ==========
static int32_t InvokeCallback(void *owner, int32_t code, IpcIo *reply)
{
(void)owner;
int32_t result = CTRL_FAIL;
if (reply != NULL) {
ReadInt32(reply, &result);
}
return result;
}
// ========== Proxy 方法实现 ==========
static int32_t ProxyPortControl(IUnknown *iUnknown, uint32_t groupIndex,
uint32_t portNum, int32_t level)
{
if (iUnknown == NULL || portNum == 0) {
return CTRL_PARAMS_ERROR;
}
ControllerClientProxy *proxy = (ControllerClientProxy *)iUnknown;
// 1. 序列化请求参数
uint8_t buffer[IPC_BUFFER_SIZE];
IpcIo req;
IpcIoInit(&req, buffer, sizeof(buffer), 0);
WriteUint32(&req, groupIndex);
WriteUint32(&req, portNum);
WriteInt32(&req, level);
// 2. IPC 调用
int32_t ret = proxy->Invoke((IClientProxy *)proxy,
CONTROLLER_IPC_PORT_CONTROL,
&req, NULL, InvokeCallback);
return (ret == EC_SUCCESS) ? CTRL_OK : CTRL_FAIL;
}
static int32_t ProxyPortDetect(IUnknown *iUnknown, uint32_t groupIndex,
uint32_t portNum, int32_t *state)
{
if (iUnknown == NULL || state == NULL) {
return CTRL_PARAMS_ERROR;
}
ControllerClientProxy *proxy = (ControllerClientProxy *)iUnknown;
uint8_t buffer[IPC_BUFFER_SIZE];
IpcIo req;
IpcIoInit(&req, buffer, sizeof(buffer), 0);
WriteUint32(&req, groupIndex);
WriteUint32(&req, portNum);
// 使用同步 IPC 等待响应
int32_t ret = proxy->Invoke((IClientProxy *)proxy,
CONTROLLER_IPC_PORT_DETECT,
&req, NULL, InvokeCallback);
if (ret == EC_SUCCESS) {
// 从回调结果中读取 state
*state = g_lastState; // 实际需要从回调中获取
}
return ret;
}
// ========== 对外接口 ==========
int32_t IoPortControl(uint32_t groupIndex, uint32_t portNum, int32_t level)
{
if (AcquireProxy() != CTRL_OK) {
return CTRL_FAIL;
}
ControllerClientProxy *proxy = GetClientProxy();
int32_t ret = proxy->PortControl((IUnknown *)proxy, groupIndex, portNum, level);
ReleaseProxy();
return ret;
}
int32_t IoPortDetect(uint32_t groupIndex, uint32_t portNum, int32_t *state)
{
if (AcquireProxy() != CTRL_OK) {
return CTRL_FAIL;
}
ControllerClientProxy *proxy = GetClientProxy();
int32_t ret = proxy->PortDetect((IUnknown *)proxy, groupIndex, portNum, state);
ReleaseProxy();
return ret;
}
4.3 使用示例
c
// 客户端使用示例
#include "controller_proxy.h"
void Demo(void)
{
// 控制 GPIO 输出
uint32_t ret = IoPortControl(0, 5, HIGH_LEVEL); // GPIO0.5 置高
if (ret == CTRL_OK) {
printf("GPIO set high success\n");
}
// 读取 GPIO 输入
int32_t state = 0;
ret = IoPortDetect(0, 10, &state); // 读取 GPIO0.10 状态
if (ret == CTRL_OK) {
printf("GPIO state: %s\n", state ? "HIGH" : "LOW");
}
}
5. 深入分析回调接口实现
5.1 回调机制概述
在控制器服务中,回调机制用于异步通知客户端事件发生,例如边沿检测触发、定时器到期等。
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ 服务端 │ 边沿触发 │ 回调管理 │ 跨进程回调 │ 客户端 │
│ 硬件驱动 │────────▶│ 器 │────────▶│ 回调 │
│ │ │ │ │ 处理 │
└─────────────┘ └─────────────┘ └─────────────┘
5.2 回调类型定义
c
// ctrl_types.h
// 端口电平
typedef enum {
LOW_LEVEL = 0,
HIGH_LEVEL = 1,
} PortLevel;
// 检测类型
typedef enum {
RISING_EDGE_DETECT = 0, // 上升沿检测
FALLING_EDGE_DETECT = 1, // 下降沿检测
ALL_EDGE_DETECT = 2, // 所有边沿检测
} DetectType;
// 检测同步标志
typedef enum {
SYNC_DETECT = 0, // 同步检测
ASYNC_DETECT = 1, // 异步检测
AUTO_SYNC_OR_ASYNC_DETECT = 2, // 自动
} DetectSyncFlag;
// 回调函数类型
typedef void (*PortDetectCallback)(uint32_t groupIndex, uint32_t portNum, PortLevel level);
typedef void (*DetectCallbackTrigger)(uint32_t groupIndex, uint32_t portNum, PortLevel level);
5.3 服务端回调管理器实现
c
// port_detect_callback_server.h/.c
#include "utils_list.h"
#define MAX_CALLBACK_NUM 32
// 回调节点
typedef struct DetectCallbackNode {
UTILS_DL_LIST list; // 链表节点
uint32_t groupIndex; // GPIO 组
uint32_t portNum; // 端口号
DetectType type; // 检测类型
SvcIdentity clientId; // 客户端身份
DetectCallbackTrigger trigger; // 触发函数
void *userData; // 用户数据
} DetectCallbackNode;
// 回调管理器
typedef struct {
UTILS_DL_LIST callbacks; // 回调链表
uint32_t count; // 回调数量
MutexId mutex; // 互斥锁
} DetectCallbackMgr;
// 全局管理器
static DetectCallbackMgr g_callbackMgr;
// 初始化管理器
void DetectCallbackMgrInit(void)
{
UtilsListInit(&g_callbackMgr.callbacks);
g_callbackMgr.count = 0;
g_callbackMgr.mutex = MUTEX_InitValue();
}
// 销毁管理器
void DetectCallbackMgrDeinit(void)
{
UTILS_DL_LIST *node = NULL;
UTILS_DL_LIST *next = NULL;
MUTEX_Lock(g_callbackMgr.mutex);
// 遍历释放所有节点
UTILS_DL_LIST_FOR_EACH_SAFE(node, next, &g_callbackMgr.callbacks) {
UtilsListDelete(node);
DetectCallbackNode *cbNode = UTILS_DL_LIST_ENTRY(node, DetectCallbackNode, list);
SAMGR_Free(cbNode);
}
g_callbackMgr.count = 0;
MUTEX_Unlock(g_callbackMgr.mutex);
}
// 注册回调
uint32_t DetectCallbackRegister(uint32_t groupIndex, uint32_t portNum,
DetectType type, SvcIdentity *clientId)
{
if (g_callbackMgr.count >= MAX_CALLBACK_NUM) {
return CTRL_FAIL;
}
// 检查是否已存在
DetectCallbackNode *existing = NULL;
UTILS_DL_LIST_FOR_EACH_ENTRY(existing, &g_callbackMgr.callbacks,
DetectCallbackNode, list) {
if (existing->groupIndex == groupIndex &&
existing->portNum == portNum) {
return CTRL_EXISTED; // 已存在
}
}
// 分配新节点
DetectCallbackNode *newNode = SAMGR_Malloc(sizeof(DetectCallbackNode));
if (newNode == NULL) {
return CTRL_FAIL;
}
newNode->groupIndex = groupIndex;
newNode->portNum = portNum;
newNode->type = type;
newNode->clientId = *clientId;
newNode->trigger = NULL;
newNode->userData = NULL;
// 添加到链表
MUTEX_Lock(g_callbackMgr.mutex);
UtilsListTailInsert(&g_callbackMgr.callbacks, &newNode->list);
g_callbackMgr.count++;
MUTEX_Unlock(g_callbackMgr.mutex);
return CTRL_OK;
}
// 注销回调
uint32_t DetectCallbackUnregister(uint32_t groupIndex, uint32_t portNum)
{
MUTEX_Lock(g_callbackMgr.mutex);
DetectCallbackNode *node = NULL;
UTILS_DL_LIST_FOR_EACH_ENTRY(node, &g_callbackMgr.callbacks,
DetectCallbackNode, list) {
if (node->groupIndex == groupIndex && node->portNum == portNum) {
UtilsListDelete(&node->list);
g_callbackMgr.count--;
MUTEX_Unlock(g_callbackMgr.mutex);
SAMGR_Free(node);
return CTRL_OK;
}
}
MUTEX_Unlock(g_callbackMgr.mutex);
return CTRL_NOT_FOUND;
}
// 触发回调(被硬件驱动调用)
void DetectCallbackTrigger(uint32_t groupIndex, uint32_t portNum, PortLevel level)
{
MUTEX_Lock(g_callbackMgr.mutex);
DetectCallbackNode *node = NULL;
UTILS_DL_LIST_FOR_EACH_ENTRY(node, &g_callbackMgr.callbacks,
DetectCallbackNode, list) {
if (node->groupIndex == groupIndex && node->portNum == portNum) {
// 检查检测类型是否匹配
if (node->type == ALL_EDGE_DETECT ||
(node->type == RISING_EDGE_DETECT && level == HIGH_LEVEL) ||
(node->type == FALLING_EDGE_DETECT && level == LOW_LEVEL)) {
// 跨进程回调通知客户端
SendCallbackToClient(&node->clientId, portNum, level);
}
}
}
MUTEX_Unlock(g_callbackMgr.mutex);
}
5.4 客户端回调处理
c
// port_detect_callback_client.h/.c
#include "utils_list.h"
// 回调节点
typedef struct ClientCallbackNode {
UTILS_DL_LIST list;
uint32_t groupIndex;
uint32_t portNum;
PortDetectCallback callback;
void *userData;
} ClientCallbackNode;
// 客户端回调列表
static UTILS_DL_LIST g_clientCallbacks;
static MutexId g_callbackMutex;
// 用户回调函数
static void PortDetectCallbackHandler(uint32_t groupIndex, uint32_t portNum, PortLevel level)
{
MUTEX_Lock(g_callbackMutex);
ClientCallbackNode *node = NULL;
UTILS_DL_LIST_FOR_EACH_ENTRY(node, &g_clientCallbacks,
ClientCallbackNode, list) {
if (node->groupIndex == groupIndex && node->portNum == portNum) {
// 调用用户回调
if (node->callback != NULL) {
node->callback(groupIndex, portNum, level);
}
break;
}
}
MUTEX_Unlock(g_callbackMutex);
}
// 注册客户端回调
int32_t RegisterPortDetectCallback(uint32_t groupIndex, uint32_t portNum,
PortDetectCallback cb, void *userData)
{
ClientCallbackNode *node = SAMGR_Malloc(sizeof(ClientCallbackNode));
if (node == NULL) {
return CTRL_FAIL;
}
node->groupIndex = groupIndex;
node->portNum = portNum;
node->callback = cb;
node->userData = userData;
UtilsListTailInsert(&g_clientCallbacks, &node->list);
return CTRL_OK;
}
// 获取客户端 SvcIdentity(用于跨进程回调)
int32_t GetClientCallbackSvcIdentity(SvcIdentity *svcId)
{
// 获取当前进程的 IPC 标识
// 实际实现需要根据具体 IPC 框架
*svcId = GetCurrentProcessIdentity();
return CTRL_OK;
}
5.5 带回调的 IPC 调用流程
┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│ 客户端 │ │ IPC │ │ 服务端 │
└──────┬───────┘ └──────┬───────┘ └──────┬───────┘
│ │ │
│ 1. 注册本地回调 │ │
│────────────────────────▶│ │
│ │ │
│ 2. 获取 SvcIdentity │ │
│────────────────────────▶│ │
│ │ │
│ 3. IPC: 订阅边沿检测 │ │
│───────────────────────▶ │───────────────────────▶│
│ │ │
│ │ 4. 注册到回调管理器
│ │ │
│ │ │ ◀── 硬件边沿触发
│ │ │
│ │ 5. 跨进程回调 │
│◀───────────────────────│◀───────────────────────│
│ │ │
│ 6. 调度本地回调 │ │
│────────────────────────▶│ │
│ │ │
▼ ▼ ▼
客户端订阅边沿检测代码:
c
// 边沿检测回调函数
static void MyEdgeCallback(uint32_t group, uint32_t port, PortLevel level)
{
printf("Edge detected! group=%u, port=%u, level=%s\n",
group, port, level ? "HIGH" : "LOW");
}
// 订阅边沿检测
int32_t SubscribeEdgeDetect(uint32_t groupIndex, uint32_t portNum,
DetectType type)
{
// 1. 注册本地回调
int32_t ret = RegisterPortDetectCallback(groupIndex, portNum,
MyEdgeCallback, NULL);
if (ret != CTRL_OK) {
return ret;
}
// 2. 通过 IPC 订阅服务端
ret = IoPortDetectWithCallback(groupIndex, portNum, type, MyEdgeCallback);
if (ret != CTRL_OK) {
UnregisterPortDetectCallback(groupIndex, portNum);
return ret;
}
return CTRL_OK;
}
6. 权限管理与 SA 启动
6.1 权限管理机制
Samgr Lite 通过**策略(Policy)**来控制服务的访问权限:
c
// 权限策略类型
typedef enum {
RANGE = 0, // UID 范围策略
FIXED = 1, // 固定 UID 列表
BUNDLENAME = 2, // 包名策略
} PolicyType;
// 策略结构
typedef struct {
PolicyType type; // 策略类型
union {
struct {
int32 uidMin; // UID 最小值
int32 uidMax; // UID 最大值
} range;
int32 fixedUid[UID_SIZE]; // 固定 UID 数组
};
} PolicyTrans;
6.2 策略配置示例
c
// endpoint.c 中的策略判断逻辑
static boolean JudgePolicy(uid_t callingUid, const PolicyTrans *policy, uint32 policyNum)
{
for (uint32 i = 0; i < policyNum; i++) {
switch (policy[i].type) {
case RANGE:
// UID 在范围内允许访问
if (callingUid >= policy[i].uidMin &&
callingUid <= policy[i].uidMax) {
return TRUE;
}
break;
case FIXED:
// UID 在固定列表中允许访问
for (int j = 0; j < UID_SIZE; j++) {
if (callingUid == policy[i].fixedUid[j]) {
return TRUE;
}
}
break;
case BUNDLENAME:
// 根据包名判断
// ...
break;
}
}
return FALSE;
}
6.3 SA 启动流程
┌─────────────────────────────────────────────────────────────────┐
│ 系统启动 │
├─────────────────────────────────────────────────────────────────┤
│ │
│ 1. 内核启动 ──▶ Init进程 ──▶ init.rc 解析 │
│ │ │
│ ▼ │
│ 2. Samgr 进程启动 ──▶ SAMGR_GetInstance() │
│ │ │
│ ▼ │
│ 3. Samgr 初始化 ──▶ Init() │
│ - 初始化互斥锁 │
│ - 创建服务向量表 │
│ - 设置启动状态 BOOT_SYS │
│ │ │
│ ▼ │
│ 4. 各 SA 库加载 ──▶ SYS_SERVICE_INIT() / SYS_FEATURE_INIT() │
│ - 静态注册服务和 Feature │
│ - 调用 RegisterService() │
│ - 调用 RegisterFeature() │
│ - 调用 RegisterFeatureApi() │
│ │ │
│ ▼ │
│ 5. SAMGR_Bootstrap() ──▶ 批量启动服务 │
│ - 遍历所有已注册服务 │
│ - 创建任务线程池 │
│ - 调用 Initialize() │
│ │ │
│ ▼ │
│ 6. 服务运行中 ──▶ MessageHandle() 处理请求 │
│ │
└─────────────────────────────────────────────────────────────────┘
6.4 启动宏说明
c
// ohos_init.h 中定义的启动宏
// 系统服务启动(核心系统服务)
#define SYS_SERVICE_INIT(func) \
static void *_##func##_service_init(void) \
__attribute__((section(".service_list.init"))) = (void *)func
// 功能特性启动(普通 SA)
#define SYS_FEATURE_INIT(func) \
static void *_##func##_feature_init(void) \
__attribute__((section(".feature_list.init"))) = (void *)func
// 应用启动(应用层服务)
#define APP_SERVICE_INIT(func) \
static void *_##func##_app_service_init(void) \
__attribute__((section(".app_service_list.init"))) = (void *)func
// 应用特性启动
#define APP_FEATURE_INIT(func) \
static void *_##func##_app_feature_init(void) \
__attribute__((section(".app_feature_list.init"))) = (void *)func
链接脚本中的段定义:
ld
/* 链接脚本示例 */
SECTIONS
{
.service_list.init : {
__service_list_start = .;
KEEP(*(.service_list.init))
__service_list_end = .;
}
.feature_list.init : {
__feature_list_start = .;
KEEP(*(.feature_list.init))
__feature_list_end = .;
}
}
6.5 Bootstrap 服务
Samgr 提供了 Bootstrap 服务用于分阶段启动:
c
// 引导消息类型
typedef enum BootMessage {
BOOT_SYS_COMPLETED = 0, // 核心系统服务初始化完成
BOOT_APP_COMPLETED = 1, // 应用服务初始化完成
BOOT_REG_SERVICE = 2, // 运行时注册服务
} BootMessage;
// Bootstrap 处理示例
static void BootstrapHandleRequest(const Request *request, const Response *response)
{
switch (request->msgId) {
case BOOT_SYS_COMPLETED:
// 核心系统服务已就绪,可以启动进一步的服务
break;
case BOOT_APP_COMPLETED:
// 所有服务已就绪
break;
}
}
7. 常用数据结构使用
7.1 Vector 动态数组
Vector 是 Samgr 中使用的简化动态数组实现:
c
// common.h
typedef void *(*VECTOR_Key)(const void *);
typedef int (*VECTOR_Compare)(const void *, const void *);
typedef struct SimpleVector {
int16 max; // 最大容量
int16 top; // 顶部索引
int16 fre; // 释放计数
void **data; // 数据指针数组
VECTOR_Key key; // 键值提取函数
VECTOR_Compare compare; // 比较函数
} Vector;
使用示例:
c
// 定义比较函数
static int CompareService(const void *a, const void *b)
{
return strcmp((const char *)a, (const char *)b);
}
// 创建向量
Vector services = VECTOR_Make((VECTOR_Key)strcmp, CompareService);
// 添加元素
ServiceImpl *impl = CreateServiceImpl(service);
int16 pos = VECTOR_Add(&services, impl);
// 查找元素
int16 index = VECTOR_FindByKey(&services, "MyService");
// 获取元素
ServiceImpl *found = VECTOR_At(&services, index);
// 遍历
for (int16 i = 0; i < VECTOR_Size(&services); i++) {
ServiceImpl *impl = VECTOR_At(&services, i);
if (impl != NULL) {
// 处理 impl
}
}
// 删除元素
void *removed = VECTOR_Swap(&services, index, NULL);
// 清理
VECTOR_Clear(&services);
7.2 Doubly Linked List(双向链表)
鸿蒙提供了 utils_list.h 中的双向链表实现:
c
// utils_list.h
#include "utils_list.h"
typedef struct UTILS_DL_LIST {
struct UTILS_DL_LIST *pstPrev;
struct UTILS_DL_LIST *pstNext;
} UTILS_DL_LIST;
使用示例 - 定义节点:
c
// 定义带链表的节点结构
typedef struct MyNode {
int32 id;
char name[32];
UTILS_DL_LIST node; // 必须在结构体中包含链表节点
} MyNode;
// 创建节点
MyNode *node1 = malloc(sizeof(MyNode));
node1->id = 1;
strcpy(node1->name, "Node1");
UtilsListInit(&node1->node); // 初始化链表节点
使用示例 - 链表操作:
c
// 初始化链表头
UTILS_DL_LIST g_myList;
UtilsListInit(&g_myList);
// 插入节点(头插)
UtilsListHeadInsert(&g_myList, &node1->node);
// 尾插
UtilsListTailInsert(&g_myList, &node2->node);
// 删除节点
UtilsListDelete(&node1->node);
// 判空
if (UtilsListEmpty(&g_myList)) {
// 链表为空
}
// 遍历(不安全删除)
UTILS_DL_LIST *item = NULL;
UTILS_DL_LIST_FOR_EACH(item, &g_myList) {
MyNode *myNode = UTILS_DL_LIST_ENTRY(item, MyNode, node);
printf("ID: %d, Name: %s\n", myNode->id, myNode->name);
}
// 安全遍历(允许删除当前节点)
UTILS_DL_LIST *item = NULL;
UTILS_DL_LIST *next = NULL;
UTILS_DL_LIST_FOR_EACH_SAFE(item, next, &g_myList) {
MyNode *myNode = UTILS_DL_LIST_ENTRY(item, MyNode, node);
if (myNode->id == 1) {
UtilsListDelete(item);
free(myNode);
}
}
// 按类型遍历
MyNode *entry = NULL;
UTILS_DL_LIST_FOR_EACH_ENTRY(entry, &g_myList, MyNode, node) {
// 处理 entry
}
// 安全版本(允许删除)
MyNode *entry = NULL;
MyNode *nextEntry = NULL;
UTILS_DL_LIST_FOR_EACH_ENTRY_SAFE(entry, nextEntry, &g_myList, MyNode, node) {
// 可以安全删除 entry
}
// 合并链表
UtilsListAddList(&list1, &list2);
// 取出头节点类型
MyNode *head = UTILS_ListPeekHeadType(&g_myList, MyNode, node);
// 弹出头节点
MyNode *popped = UTILS_ListRemoveHeadType(&g_myList, MyNode, node);
7.3 Identity 消息标识
c
// message.h
struct Identity {
int16 serviceId; // 服务 ID
int16 featureId; // Feature ID
MQueueId queueId; // 消息队列 ID
};
使用示例:
c
// 获取 Feature 的 Identity
ServiceImpl *serviceImpl = GetServiceImpl("MyService");
Identity id = DEFAULT_GetFeatureId(serviceImpl, "MyFeature");
// 发送请求
Request request = {
.msgId = MY_MSG_ID,
.len = sizeof(myData),
.data = &myData,
.msgValue = 0
};
// 同步发送
int32 ret = SAMGR_SendRequest(&id, &request, MyResponseHandler);
// 响应处理
static void MyResponseHandler(const Request *request, const Response *response)
{
printf("Response received, len=%d\n", response->len);
MyResult *result = (MyResult *)response->data;
// 处理结果
}
// 发送响应
Response resp = {
.data = resultData,
.len = sizeof(resultData)
};
SAMGR_SendResponse(request, &resp);
7.4 Request/Response 消息结构
c
// 请求结构
struct Request {
int16 msgId; // 消息 ID
int16 len; // 数据长度
void *data; // 数据指针
uint32 msgValue; // 消息值
};
// 响应结构
struct Response {
void *data; // 响应数据
int16 len; // 数据长度
void *reply; // 回复标记
};
7.5 IUnknownEntry 接口入口
c
// 标准接口入口定义
#define INHERIT_IUNKNOWNENTRY(T) \
uint16 ver; \
int16 ref; \
T iUnknown
typedef struct IUnknownEntry {
uint16 ver; // 版本号
int16 ref; // 引用计数
IUnknown iUnknown;
} IUnknownEntry;
// 初始化宏
#define IUNKNOWN_ENTRY_BEGIN(version) \
.ver = (version), \
.ref = 1, \
.iUnknown = { \
.QueryInterface = IUNKNOWN_QueryInterface, \
.AddRef = IUNKNOWN_AddRef, \
.Release = IUNKNOWN_Release
#define IUNKNOWN_ENTRY_END }
// 使用示例
typedef struct {
INHERIT_IUNKNOWNENTRY(ControllerClientProxy);
} ControllerClientEntry;
static ControllerClientEntry g_entry = {
IUNKNOWN_ENTRY_BEGIN(DEFAULT_VERSION),
// 自定义方法...
IUNKNOWN_ENTRY_END
};
// 获取 IUnknown 指针
IUnknown *api = GET_IUNKNOWN(g_entry);
8. 实战:完整 SA 开发模板
8.1 目录结构
my_sa/
├── include/
│ ├── my_sa.h # 对外头文件
│ └── my_sa_types.h # 类型定义
├── src/
│ ├── my_sa_service.c # Service 实现
│ ├── my_sa_feature.c # Feature 实现
│ ├── my_sa_proxy.c # Proxy 实现
│ └── my_sa_main.c # 入口
└── BUILD.gn # 构建脚本
8.2 类型定义
c
// my_sa_types.h
#ifndef MY_SA_TYPES_H
#define MY_SA_TYPES_H
#include <stdint.h>
// 错误码
#define MY_SA_OK 0
#define MY_SA_FAIL 1
#define MY_SA_PARAM_ERR 2
#define MY_SA_BUSY 3
// IPC 方法 ID
#define MY_SA_IPC_METHOD_A 1
#define MY_SA_IPC_METHOD_B 2
#define MY_SA_IPC_METHOD_C 3
// 接口版本
#define MY_SA_INTERFACE_VERSION 0x20
// 请求数据结构
typedef struct {
uint32_t param1;
uint32_t param2;
} MyRequestData;
// 响应数据结构
typedef struct {
uint32_t result;
uint32_t value;
} MyResponseData;
#endif
8.3 Service 实现
c
// my_sa_service.c
#include <samgr_lite.h>
#include <ohos_init.h>
#include "my_sa_types.h"
#define MY_SERVICE_NAME "MyService"
typedef struct {
INHERIT_SERVICE;
Identity identity;
} MyService;
static const char *GetName(Service *service)
{
(void)service;
return MY_SERVICE_NAME;
}
static BOOL Initialize(Service *service, Identity identity)
{
MyService *myService = (MyService *)service;
myService->identity = identity;
HILOG_INFO("MyService initialized, serviceId=%d", identity.serviceId);
return TRUE;
}
static BOOL MessageHandle(Service *service, Request *request)
{
(void)service;
(void)request;
return FALSE;
}
static TaskConfig GetTaskConfig(Service *service)
{
(void)service;
return (TaskConfig) {
.level = LEVEL_HIGH,
.priority = PRI_NORMAL,
.stackSize = 4096,
.queueSize = 32,
.taskFlags = SINGLE_TASK
};
}
static MyService g_myService = {
.GetName = GetName,
.Initialize = Initialize,
.MessageHandle = MessageHandle,
.GetTaskConfig = GetTaskConfig,
.identity = {-1, -1, NULL}
};
static void MyServiceInit(void)
{
SAMGR_GetInstance()->RegisterService((Service *)&g_myService);
}
SYS_SERVICE_INIT(MyServiceInit);
8.4 Feature 实现
c
// my_sa_feature.c
#include <samgr_lite.h>
#include <ohos_init.h>
#include <iproxy_server.h>
#include "my_sa_types.h"
#define MY_FEATURE_NAME "MyFeature"
typedef struct {
INHERIT_SERVER_IPROXY;
} MyFeatureApi;
typedef struct {
INHERIT_FEATURE;
INHERIT_IUNKNOWNENTRY(MyFeatureApi);
Identity identity;
Service *parent;
} MyFeature;
static const char *GetName(Feature *feature)
{
(void)feature;
return MY_FEATURE_NAME;
}
static void OnInitialize(Feature *feature, Service *parent, Identity identity)
{
MyFeature *myFeature = (MyFeature *)feature;
myFeature->identity = identity;
myFeature->parent = parent;
HILOG_INFO("MyFeature initialized");
}
static void OnStop(Feature *feature, Identity identity)
{
(void)feature;
(void)identity;
HILOG_INFO("MyFeature stopped");
}
static BOOL OnMessage(Feature *feature, Request *request)
{
(void)feature;
(void)request;
return FALSE;
}
// 业务方法 A
static uint32_t DoMethodA(uint32_t param1, uint32_t param2)
{
HILOG_INFO("MethodA called: %u, %u", param1, param2);
return param1 + param2;
}
// 业务方法 B
static uint32_t DoMethodB(uint32_t value)
{
HILOG_INFO("MethodB called: %u", value);
return value * 2;
}
static int32_t Invoke(IServerProxy *iProxy, int32_t funcId,
void *origin, IpcIo *req, IpcIo *reply)
{
(void)origin;
(void)iProxy;
uint32_t ret = MY_SA_OK;
switch (funcId) {
case MY_SA_IPC_METHOD_A: {
uint32_t param1 = 0, param2 = 0;
if (!ReadUint32(req, ¶m1) || !ReadUint32(req, ¶m2)) {
ret = MY_SA_PARAM_ERR;
break;
}
uint32_t result = DoMethodA(param1, param2);
WriteUint32(reply, result);
break;
}
case MY_SA_IPC_METHOD_B: {
uint32_t value = 0;
if (!ReadUint32(req, &value)) {
ret = MY_SA_PARAM_ERR;
break;
}
uint32_t result = DoMethodB(value);
WriteUint32(reply, result);
break;
}
default:
ret = MY_SA_PARAM_ERR;
break;
}
return ret;
}
static MyFeature g_myFeature = {
.GetName = GetName,
.OnInitialize = OnInitialize,
.OnStop = OnStop,
.OnMessage = OnMessage,
SERVER_IPROXY_IMPL_BEGIN,
.Invoke = Invoke,
IPROXY_END,
.identity = {-1, -1, NULL},
};
static void MyFeatureInit(void)
{
BOOL ret = SAMGR_GetInstance()->RegisterFeature(
MY_SERVICE_NAME, (Feature *)&g_myFeature);
if (!ret) {
HILOG_ERROR("RegisterFeature failed");
return;
}
ret = SAMGR_GetInstance()->RegisterFeatureApi(
MY_SERVICE_NAME, MY_FEATURE_NAME, GET_IUNKNOWN(g_myFeature));
if (!ret) {
HILOG_ERROR("RegisterFeatureApi failed");
}
}
SYS_FEATURE_INIT(MyFeatureInit);
8.5 Proxy 实现
c
// my_sa_proxy.c
#include <samxy_client.h>
#include "my_sa_types.h"
static MyClientEntry *g_clientEntry = NULL;
static MutexId g_mutex = NULL;
static int32_t InvokeCallback(void *owner, int32_t code, IpcIo *reply)
{
(void)owner;
(void)reply;
return code;
}
static int32_t ProxyMethodA(IUnknown *iUnknown, uint32_t param1, uint32_t param2)
{
if (iUnknown == NULL) {
return MY_SA_PARAM_ERR;
}
MyClientProxy *proxy = (MyClientProxy *)iUnknown;
uint8_t buffer[256];
IpcIo req;
IpcIoInit(&req, buffer, sizeof(buffer), 0);
WriteUint32(&req, param1);
WriteUint32(&req, param2);
int32_t ret = proxy->Invoke((IClientProxy *)proxy,
MY_SA_IPC_METHOD_A,
&req, NULL, InvokeCallback);
return (ret == EC_SUCCESS) ? MY_SA_OK : MY_SA_FAIL;
}
static int32_t ProxyMethodB(IUnknown *iUnknown, uint32_t value)
{
if (iUnknown == NULL) {
return MY_SA_PARAM_ERR;
}
MyClientProxy *proxy = (MyClientProxy *)iUnknown;
uint8_t buffer[256];
IpcIo req;
IpcIoInit(&req, buffer, sizeof(buffer), 0);
WriteUint32(&req, value);
int32_t ret = proxy->Invoke((IClientProxy *)proxy,
MY_SA_IPC_METHOD_B,
&req, NULL, InvokeCallback);
return (ret == EC_SUCCESS) ? MY_SA_OK : MY_SA_FAIL;
}
static void ProxyRegister(MyClientProxy *proxy)
{
proxy->MethodA = ProxyMethodA;
proxy->MethodB = ProxyMethodB;
}
// 对外 API
int32_t AcquireMyService(void)
{
if (g_clientEntry != NULL) {
g_clientEntry->ref++;
return MY_SA_OK;
}
IUnknown *api = SAMGR_GetInstance()->GetFeatureApi(
MY_SERVICE_NAME, MY_FEATURE_NAME);
if (api == NULL) {
return MY_SA_FAIL;
}
int ret = api->QueryInterface(api, MY_SA_INTERFACE_VERSION,
(void **)&g_clientEntry);
if (ret != EC_SUCCESS) {
return MY_SA_FAIL;
}
ProxyRegister((MyClientProxy *)g_clientEntry);
return MY_SA_OK;
}
void ReleaseMyService(void)
{
if (g_clientEntry != NULL) {
g_clientEntry->ref--;
if (g_clientEntry->ref <= 0) {
g_clientEntry->iUnknown.Release((IUnknown *)g_clientEntry);
g_clientEntry = NULL;
}
}
}
int32_t MyMethodA(uint32_t param1, uint32_t param2)
{
if (AcquireMyService() != MY_SA_OK) {
return MY_SA_FAIL;
}
MyClientProxy *proxy = (MyClientProxy *)g_clientEntry;
int32_t ret = proxy->MethodA((IUnknown *)proxy, param1, param2);
ReleaseMyService();
return ret;
}
int32_t MyMethodB(uint32_t value)
{
if (AcquireMyService() != MY_SA_OK) {
return MY_SA_FAIL;
}
MyClientProxy *proxy = (MyClientProxy *)g_clientEntry;
int32_t ret = proxy->MethodB((IUnknown *)proxy, value);
ReleaseMyService();
return ret;
}
8.6 对外头文件
c
// my_sa.h
#ifndef MY_SA_H
#define MY_SA_H
#include "my_sa_types.h"
// 初始化客户端
int32_t AcquireMyService(void);
void ReleaseMyService(void);
// 业务 API
int32_t MyMethodA(uint32_t param1, uint32_t param2);
int32_t MyMethodB(uint32_t value);
#endif
8.7 使用示例
c
// 使用 my_sa 的客户端代码
#include "my_sa.h"
void Demo(void)
{
// 调用 Method A
int32_t ret = MyMethodA(10, 20);
if (ret == MY_SA_OK) {
printf("MethodA executed successfully\n");
}
// 调用 Method B
ret = MyMethodB(100);
if (ret == MY_SA_OK) {
printf("MethodB executed successfully\n");
}
}
附录 A:常用宏速查表
| 宏名 | 说明 | 用途 |
|---|---|---|
INHERIT_SERVICE |
继承服务接口 | 定义 Service 结构体 |
INHERIT_FEATURE |
继承功能接口 | 定义 Feature 结构体 |
INHERIT_IUNKNOWN |
继承 IUnknown | 定义 IUnknown 接口 |
INHERIT_CLIENT_IPROXY |
继承客户端代理 | 定义客户端 Proxy |
INHERIT_SERVER_IPROXY |
继承服务端代理 | 定义服务端 Stub |
SERVER_IPROXY_IMPL_BEGIN |
服务端代理实现开始 | Feature 定义中使用 |
IPROXY_END |
IProxy 实现结束 | Feature 定义中使用 |
GET_IUNKNOWN(obj) |
获取 IUnknown 指针 | 注册 API 时使用 |
SYS_SERVICE_INIT(func) |
系统服务初始化 | Service 注册 |
SYS_FEATURE_INIT(func) |
功能初始化 | Feature 注册 |
IUNKNOWN_ENTRY_BEGIN(ver) |
IUnknown 入口开始 | 接口定义 |
IUNKNOWN_ENTRY_END |
IUnknown 入口结束 | 接口定义 |
附录 B:错误码定义
| 错误码 | 值 | 说明 |
|---|---|---|
EC_SUCCESS |
0 | 成功 |
EC_INVALID |
-1 | 参数无效 |
EC_FAILURE |
-2 | 失败 |
EC_NOMEMORY |
-3 | 内存不足 |
EC_TIMEOUT |
-4 | 超时 |
EC_BUSY |
-5 | 忙 |
EC_NOINIT |
-6 | 未初始化 |
附录 D:IPC/RPC 框架接口详解
OpenHarmony 的 IPC(Inter-Process Communication)框架基于 Binder 驱动实现设备内跨进程通信,RPC(Remote Procedure Call)基于 DSoftBus 实现跨设备通信。两者采用统一的 Client-Server 模型。
D.1 IPC 框架架构
┌────────────────────────────────────────────────────────────────────┐
│ IPC 框架架构 │
├────────────────────────────────────────────────────────────────────┤
│ │
│ ┌──────────────┐ ┌──────────────┐ ┌─────────────┐ │
│ │ Client │────────▶│ IPC Core │───────▶│ Server │ │
│ │ Application│ │ │ │ │ │
│ └──────┬───────┘ └──────┬───────┘ └──────┬──────┘ │
│ │ │ │ │
│ │ 1. 获取 SA Proxy │ │ │
│ │───────────────────────▶ │ │ │
│ │ │ │ │
│ │ 2. 调用业务方法 │ │ │
│ │───────────────────────▶ │ │ │
│ │ │ 3. 反序列化参数 │ │
│ │ │───────────────────────▶│ │
│ │ │ │ │
│ │ │ 4. 调用 Stub.OnRemoteRequest│ │
│ │ │───────────────────────▶│ │
│ │ │ │ │
│ │ 5. 序列化响应返回 │ │ │
│ │◀───────────────────────│ │ │
│ │ │ │ │
│ ┌──────┴───────┐ ┌──────┴───────┐ ┌──────┴──────┐ │
│ │ 业务Proxy │ │ IPC Skeleton│ │ 业务Stub │ │
│ │ (IRemoteProxy)│ │ (框架骨架) │ │ (IRemoteStub)│ │
│ └──────────────┘ └──────────────┘ └─────────────┘ │
│ │
└───────────────────────────────────────────────��────────────────────┘
附录 E:常见问题与调试技巧
E.1 调试 IPC 通信
- 使能日志:
c
// 在 build 配置中使能
#define LOG_DOMAIN 0xD001800
#define LOG_TAG "MyService"
#include <log.h>
// 运行时查看日志
hilog -b all -d -p "MyService"
- 检查消息序列化:
c
// 在发送前打印参数
HILOG_INFO("Sending request: code=%d, param1=%d", code, param1);
- 验证代理获取:
c
IUnknown *api = SAMGR_GetInstance()->GetFeatureApi("MyService", "MyFeature");
if (api == NULL) {
HILOG_ERROR("Failed to get feature API");
return;
}
E.2 常见错误
| 错误码 | 可能原因 | 解决方案 |
|---|---|---|
CTRL_PARAMS_ERROR |
参数为空或非法 | 检查输入参数 |
CTRL_FAIL |
IPC 调用失败 | 检查服务是否注册 |
ERR_INVALID_PARAM |
序列化失败 | 检查数据类型匹配 |
ERR_NO_INIT |
IPC 骨架未初始化 | 确保 SAMGR_Bootstrap() 已调用 |
ERR_IPC_SKELETON_NOT_INIT |
IPC 骨架未就绪 | 检查进程启动顺序 |
参考文件列表(完整)
Samgr Lite 相关
| 文件路径 | 说明 |
|---|---|
samgr_lite/interfaces/kits/samgr/samgr_lite.h |
SamgrLite 主接口 |
samgr_lite/interfaces/kits/samgr/service.h |
Service 定义 |
samgr_lite/interfaces/kits/samgr/feature.h |
Feature 定义 |
samgr_lite/interfaces/kits/samgr/iunknown.h |
IUnknown 基类 |
samgr_lite/interfaces/kits/samgr/message.h |
消息通信结构 |
samgr_lite/interfaces/kits/samgr/common.h |
通用工具(Vector、宏) |
samgr_lite/samgr/source/samgr_lite.c |
SamgrLite 实现 |
samgr_lite/samgr/source/service.c |
Service 管理 |
samgr_lite/samgr/source/feature.c |
Feature 管理 |
samgr_lite/samgr/source/task_manager.c |
任务/线程池管理 |
IPC/RPC 相关
| 文件路径 | 说明 |
|---|---|
interfaces/innerkits/ipc_core/include/iremote_broker.h |
接口基类 |
interfaces/innerkits/ipc_core/include/iremote_object.h |
远程对象基类 |
interfaces/innerkits/ipc_core/include/iremote_proxy.h |
代理基类 |
interfaces/innerkits/ipc_core/include/iremote_stub.h |
Stub 基类 |
interfaces/innerkits/ipc_core/include/ipc_skeleton.h |
IPC 骨架(静态方法) |
interfaces/innerkits/ipc_core/include/ipc_object_proxy.h |
代理对象实现 |
interfaces/innerkits/ipc_core/include/ipc_object_stub.h |
Stub 对象实现 |
interfaces/innerkits/ipc_core/include/message_parcel.h |
数据序列化 |
interfaces/innerkits/ipc_core/include/message_option.h |
消息选项 |
interfaces/innerkits/ipc_core/include/ipc_types.h |
类型定义 |
interfaces/innerkits/ipc_core/include/serializer.h |
序列化工具 |
ipc/native/c/manager/src/ipc_skeleton.c |
IPC 骨架实现 |
ipc/native/c/manager/include/ipc_process_skeleton.h |
进程骨架 |
工具类
| 文件路径 | 说明 |
|---|---|
commonlibrary/utils_lite/include/utils_list.h |
双向链表 |
commonlibrary/utils_lite/include/utils_vector.h |
向量容器 |