OpenHarmony轻量系统服务管理-samgr:iunknown实现分析

100 篇文章 1 订阅
100 篇文章 0 订阅

往期知识点记录:

一、前言

承接上一篇iunknown.h的赏析,本文接着对iunknown.c中的实现进行分析。在分析iunknown的实现之前,先介绍一下关于iunknown的相关背景,便于读者对后续代码的理解。

二、IUnknown背景

要想清楚的理解IUnknown就必须知道COM标准到底是什么。

COM全称Component Object Model,即组件对象模型,这是一种遵循COM规范的面向对象编程技术。它包含了三个基本的接口类,分别是IUnknown、IClassFactory和IDispatch。除了IUnknown以外,在鸿蒙后续的代码中,我们也会看到IClassFactory和IDispatch的身影,这里先分析IUnknown。COM规定任何的组件或接口都必须从IUnknown继承,而我在对模块二后续代码的分析中发现了大量的案例,如PubSubInterface、IClientProxy、IServerProxy等。IUnknown包含三个函数,分别是QueryInterface、AddRef、Release。

QueryInterface:查询实现的接口类,需要注意查询完后要调用release解除引用
AddRef:增加引用计数
Release:减少引用计数

看到这里可能会很疑惑,引用计数是什么,有什么作用?我们为什么要使用引用计数?

引用计数牵涉到内存管理的概念,每增加1就代表当前组件被一个对象引用,每减少1就代表当前组件少一个引用者,当引用计数为0时,就代表已经没有对象使用它了,那么它的生命周期就到此结束,释放自己占用的资源。通过引用计数来管理自己的生命周期,不需要其他对象的干预,这种方式极大的减少了代码开发者的工作。这种方式就跟C++11中的智能指针一样,通过引用计数来控制对象的生命周期,减少开发者的工作,避免内存泄漏。

三、代码分析

  • 宏定义分析
//从IUnknown实现类的子类对象T(通用宏)获取IUnknown接口对象的指针
#define GET_IUNKNOWN(T) (IUnknown *)(&((T).iUnknown))
  • 函数实现分析

为IUnknown对象添加引用

//增加iUnknown接口的引用计数,当重新实现QueryInterface函数时,需要在新的QueryInterface中调用该函数
int IUNKNOWN_AddRef(IUnknown *iUnknown)
{
    if (iUnknown == NULL) {
        return EC_INVALID;
    }
    //返回IUnknownEntry类型的地址,通过iUnknown的地址推断
    IUnknownEntry *entry = GET_OBJECT(iUnknown, IUnknownEntry, iUnknown);
    entry->ref++;//引用计数加1
    return entry->ref;
}

查询接口信息

/*
    函数功能:查询接口信息
    函数参数:@iUnknown:iUnknown对象
            @ver:版本号
            @target:返回需要的IUnknown的子类类型
    函数返回:成功 返回EC_SUCCESS,失败 返回EC_INVALID
    函数描述:
            1.查询指定版本的IUnknown接口。
            2.在获得IUnknown接口对象后,函数调用者使用QueryInterface将该对象转换为所需的子类类型,内部将转换为调用者所需的子类类型。
*/
int IUNKNOWN_QueryInterface(IUnknown *iUnknown, int ver, void **target)
{
    //参数检查
    if (iUnknown == NULL || target == NULL) {
        return EC_INVALID;
    }
    //返回IUnknownEntry类型的地址,通过iUnknown的地址推断
    IUnknownEntry *entry = GET_OBJECT(iUnknown, IUnknownEntry, iUnknown);
    //判断版本信息是否有效
    if ((entry->ver & (uint16)ver) != ver) {
        return EC_INVALID;
    }
    if (ver == OLD_VERSION &&
        entry->ver != OLD_VERSION &&
        (entry->ver & (uint16)DEFAULT_VERSION) != DEFAULT_VERSION) {
        return EC_INVALID;
    }
    //作为返回值
    *target = iUnknown;
    //添加引用
    iUnknown->AddRef(iUnknown);
    return EC_SUCCESS;
}

释放引用数

/*
    函数功能:释放iUnknown对象的引用数
    函数参数:@iUnknown:iUnknown对象
    函数返回:成功 引用计数,失败 返回EC_INVALID
    详细描述:
            1.释放不再使用的IUnknown接口的引用
            2.在系统提供的默认实现中,如果引用计数为0,则IUnknown接口对象和实现对象的内存不会被释放
*/
int IUNKNOWN_Release(IUnknown *iUnknown)
{
    //参数检查
    if (iUnknown == NULL) {
        return EC_INVALID;
    }
    //转换为IUnknownEntry对象
    IUnknownEntry *entry = GET_OBJECT(iUnknown, IUnknownEntry, iUnknown);
    int ref = entry->ref - 1;//引用数-1
    if (ref < 0) {
        //存在异常
    } else {
        if (ref == 0) {
            //iunknown对象的引用数为0,应删除
            //在默认版本中,iunknown可能是全局变量,默认不删除。
        } else {
            entry->ref = ref;//更新计数
        }
    }
    return ref;
}

写在最后

如果你觉得这篇内容对你还蛮有帮助,我想邀请你帮我三个小忙

  • 点赞,转发,有你们的 『点赞和评论』,才是我创造的动力。
  • 关注小编,同时可以期待后续文章ing🚀,不定期分享原创知识。
  • 想要获取更多完整鸿蒙最新学习资源,请看下图提示:
    在这里插入图片描述
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值