Small SA(System Ability)开发详解

文章目录

    • 文档说明
    • 目录
    • [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 - 实际控制器服务示例

目录

  1. [Samgr Lite 介绍](#Samgr Lite 介绍)
  2. [核心 API 详解](#核心 API 详解)
  3. 服务端-客户端框架介绍
  4. 普通接入调用示例
  5. 深入分析回调接口实现
  6. [权限管理与 SA 启动](#权限管理与 SA 启动)
  7. 常用数据结构使用
  8. [实战:完整 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    │                │
│  └──────────────────┘      └──────────────────┘                │
│                                                                  │
└─────────────────────────────────────────────────────────────────┘

三层架构:

  1. Service(服务):最顶层容器,管理多个 Feature
  2. Feature(功能):具体的功能模块,提供 IUnknown 接口
  3. 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, &param1)) {
                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, &param1) || !ReadUint32(req, &param2)) {
                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 通信

  1. 使能日志
c 复制代码
// 在 build 配置中使能
#define LOG_DOMAIN 0xD001800
#define LOG_TAG "MyService"
#include <log.h>

// 运行时查看日志
hilog -b all -d -p "MyService"
  1. 检查消息序列化
c 复制代码
// 在发送前打印参数
HILOG_INFO("Sending request: code=%d, param1=%d", code, param1);
  1. 验证代理获取
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 向量容器

相关推荐
jiuri_121511 天前
OpenHarmony 移植 OpenSSH/sshd
linux·sshd·ohos
郑知鱼1 年前
【拥抱鸿蒙】HarmonyOS NEXT实现双路预览并识别文字
华为·ocr·harmonyos·鸿蒙·移动端·鸿蒙next·ohos
郑知鱼1 年前
【拥抱鸿蒙】Flutter+Cursor轻松打造HarmonyOS应用(二)
flutter·华为·harmonyos·鸿蒙·cursor·移动端·鸿蒙next·ohos
郑知鱼1 年前
【拥抱鸿蒙】Flutter+Cursor轻松打造HarmonyOS应用(一)
flutter·华为·harmonyos·鸿蒙·cursor·移动端·鸿蒙next·ohos
郑知鱼1 年前
【拥抱鸿蒙】基于 Cocos Creator 的 HarmonyOS 自动构建
华为·harmonyos·鸿蒙·移动端·鸿蒙next·ohos
津津有味道1 年前
写NFC标签支持Android安卓Ohos纯血鸿蒙唤醒微信小程序
微信小程序·小程序·鸿蒙·nfc·ndef·ohos