轻鸿蒙samgr实现分析

1 前言

在鸿蒙L0开发时,发现里面经常会用到samgr,用于各个模块之间的通讯。
这里,最重要的就是一个组件化的概念,所有的模块,都是service,注册到samgr中,供其他模块使用。
同时,也可以调用samgr,获取其他模块的接口,并进行调用。
这里分析的是基于L0的samgr_lite,因为这个实现比较简单,它本身是单进程的系统,不需要涉及跨进行的消息交互。
但同时,这个samgr也不简单,它已超越了组件管理的概念,加入了不一样的东西。

  • 服务注册与查询;
  • 服务的子服务(Feature)的注册与查询;
  • 服务的线程管理和消息队列;
  • 消息总线机制;

2 总体框架

服务中心是一个单例模式,所有服务在开机时注册到服务中心。
开机以后,各个客户查询并使用服务。
面向服务的开发
服务中心的组成如下
服务中心实现
服务中心里,通过vector保存了多个服务;
每一个服务对应一个线程池和消息队列;
每一个服务又对应0个或多个feature;

3 服务

3.1 服务接口

服务的接口如下:
foundation/distributedschedule/samgr_lite/interfaces/kits/samgr/service.h

    const char *(*GetName)(Service * service); 
    BOOL (*Initialize)(Service * service, Identity identity);
    BOOL (*MessageHandle)(Service * service, Request * request);
    TaskConfig (*GetTaskConfig)(Service * service)

3.2 服务实现样例

代码路径applications/sample/wifi-iot/app/samgr/service_example.c

typedef struct DefaultFeatureApi {
    INHERIT_IUNKNOWN;
    void (*SyncCall)(IUnknown *iUnknown);
} DefaultFeatureApi;

typedef struct ExampleService {
    INHERIT_SERVICE;
    INHERIT_IUNKNOWNENTRY(DefaultFeatureApi);
    Identity identity;
} ExampleService;

展开后其实是这样的:

typedef struct DefaultFeatureApi {
    int (*QueryInterface)(IUnknown *iUnknown, int version, void **target); 
    int (*AddRef)(IUnknown *iUnknown);  
    int (*Release)(IUnknown *iUnknown);
    void (*SyncCall)(IUnknown *iUnknown);  // 服务自定义的特殊函数
} DefaultFeatureApi;

typedef struct ExampleService {
     // 下面4个是服务接口
     const char *(*GetName)(Service * service); 
    BOOL (*Initialize)(Service * service, Identity identity);
    BOOL (*MessageHandle)(Service * service, Request * request);
    TaskConfig (*GetTaskConfig)(Service * service);
    
    // 这二个是iknow用到的标识,实际上没什么用
    uint16 ver; 
    int16 ref;  
    DefaultFeatureApi iUnknow;
    Identity identity;
} ExampleService;

创建实例

static ExampleService g_example = {
    .GetName = GetName,
    .Initialize = Initialize,
    .MessageHandle = MessageHandle,
    .GetTaskConfig = GetTaskConfig,
    DEFAULT_IUNKNOWN_ENTRY_BEGIN,
    .SyncCall = SyncCall,
    DEFAULT_IUNKNOWN_ENTRY_END,
};

展开后为:

static ExampleService g_example = {
    .GetName = GetName,
    .Initialize = Initialize,
    .MessageHandle = MessageHandle,
    .GetTaskConfig = GetTaskConfig,

    .ver = 0x20,
    .ref = 1,  
    .iUnknown = { 
        .QueryInterface = IUNKNOWN_QueryInterface, 
        .AddRef = IUNKNOWN_AddRef,  
        .Release = IUNKNOWN_Release,
        . SyncCall = SyncCall,  // 组件自定义函数的实现指针
   },

3.3 神奇的iUnknow

iUnkow这个东东,发现到处都有它的影子, windows, linux , android。 但如果说解释得最清楚,非潘爱民的《com原理与应用》 这本书莫属。

3.3.1 引用计数

AddRef和Release比较好理解, 本质上就是引用计数,c++和java都有这个概念,用于做内存管理,当计数器为0时才会真正释放对象。
但QueryInterface,如果单从鸿蒙的代码看,是看出不内容的。 因为鸿蒙虽然用了这个接口,但实际上返回的都是一样的作用。

3.3.2 查询接口QueryInterface

QueryInterface的作用,一般是用于如果组件比较复杂,可能有有多个接口,则可以通过唯一标识,查询对应的接口。如下面的字典对象,如果邮件客户端在使用时,有可能就只用语法检查的能力,这样邮件客户端使用过程如下:

  • 首先从系统得到IUnknown接口;
  • 调用QueryInterface,传入语法检查的标识uuid,得到ISpellCheck的接口集;
  • 在用户输入文字时,调用ISpellCheck接口集中的函数进行拼写检查;
    字典对象的接口
    鸿蒙并没有让组件自己管理自己的多个Interface(子能力或Feature),因此这个接口严重退化到,只返回自身。

鸿蒙samgr在实现时,把子服务的管理,放到samgr中, 参见服务中心的组成。这样做法,简化了各个服务及Feature的开发,但确实与QueryInterface的概念有冲突。

参考文档

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值