Android 智能指针(2):RefBase 核心篇

上篇:Android 智能指针(1):hello world 篇

上篇介绍了Android 指针基本的使用前提,对象需要继承RefBase。Android 指针的灵魂也是在于这个RefBase 类。尽力梳理常用的方法背后的原理。

一,RefBase

arduino 复制代码
class RefBase
{
public:
            void            incStrong(const void* id) const;
            void            decStrong(const void* id) const;
            //! DEBUGGING ONLY: Get current strong ref count.
            int32_t         getStrongCount() const;
 
    class weakref_type
    {
    public:
        RefBase*            refBase() const;
        //skip...
        void                trackMe(bool enable, bool retain);
    };
            weakref_type*   createWeak(const void* id) const;       
            weakref_type*   getWeakRefs() const;
 
protected:
    // When constructing these objects, prefer using sp::make<>. Using a RefBase
    // object on the stack or with other refcount mechanisms (e.g.
    // std::shared_ptr) is inherently wrong. RefBase types have an implicit
    // ownership model and cannot be safely used with other ownership models.
                            RefBase();
    virtual                 ~RefBase();
    //skip...
    // Invoked after creation of initial strong pointer/reference.
    virtual void            onFirstRef();
    // Invoked when either the last strong reference goes away, or we need to undo
    // the effect of an unnecessary onIncStrongAttempted.
    virtual void            onLastStrongRef(const void* id);
    //skip...
 
private:
    friend class weakref_type;
    class weakref_impl;
    
                            RefBase(const RefBase& o);
            RefBase&        operator=(const RefBase& o);
 
private:
    friend class ReferenceMover;
 //skip...
        weakref_impl* const mRefs;
};

用法上只需要注意:不能使用栈上的对象,以及不能和其它智能指针混用,即管理的对象不能是c++通用智能指针。没有必要挑战它使用的权威性,梳理下计数的原理即可。

c 复制代码
void testSpStack(){
    string name("stack-test");
    TestSP local(name);
    sp<TestSP>ptr(&local);
}
//double free运行结果:
//free(): invalid pointer
//Aborted (core dumped)
 
void testSpStack(){
 
    string name("stack-test");
    /*
    TestSP local(name);
    sp<TestSP>ptr(&local);
    */
   std::shared_ptr<TestSP>  test_ptr= std::make_shared<TestSP>(name);
}
//不同的Android 版本可能表现不一样,移植的程序,会弹出警告,不会有上面的crash
/*
[Waring] RefBase: Explicit destruction, weak count = 0 (in 0x5555c4b71ec0). Use sp<> to manage this object.
*/

二,SP计数机制

arduino 复制代码
RefBase::RefBase()
    : mRefs(new weakref_impl(this))
{
}
 
class RefBase::weakref_impl : public RefBase::weakref_type {
public:   
    std::atomic<int32_t>    mStrong;
    std::atomic<int32_t>    mWeak;
    RefBase* const          mBase;
    std::atomic<int32_t>    mFlags;
//skip
}

回顾下sp指针的创建:

scss 复制代码
template <typename T>
sp<T>& sp<T>::operator=(T* other) {
    T* oldPtr(*const_cast<T* volatile*>(&m_ptr));
    if (other) {
        other->incStrong(this);
    }
    if (oldPtr) oldPtr->decStrong(this);
    if (oldPtr != *const_cast<T* volatile*>(&m_ptr)) sp_report_race();
    m_ptr = other;
    return *this;
}

假设通过new的方式创建的sp,如上,可以知道,它需要去call 对象的incStrong 函数,然后才将指针赋值给sp的成员m_ptr.

所以这里的逻辑,引用计数是通过对象自身去管理计数。

rust 复制代码
void RefBase::incStrong(const void* id) const
{
    weakref_impl* const refs = mRefs;
    refs->incWeak(id);
 
    const int32_t c = refs->mStrong.fetch_add(1, std::memory_order_relaxed);
//skip...
    refs->mBase->onFirstRef();
}

这里计数对象是std::atomic<int32_t> mStrong;

即:原子计数,保证了计数是线程安全的。

这里还有一个函数比较重要:onFirstRef

Android native 层有很多service服务都是利用这个onFirstRef 函数的功能。即,在service服务创建的时候,利用这个调用的时间,都会重载onFirstRef函数做些资源初始化的事情。test:

c 复制代码
    //override
    void onFirstRef()
    {
        std::cout << "Hi,onFirstRef...\n";
    }
    //override
    // id: is sp self ,not the object
    void onLastStrongRef(const void *id)
    {
        std::cout << "onLastStrongRef,Bye: " << id << std::endl;
    }
 
//testcase:
void testSpCreate()
{
    string name(">>>HelloWorld<<<");
    sp<TestSP> ptr = sp<TestSP>::make(name);
    std::cout << "refrence count:" << ptr->getStrongCount() << std::endl;
    sp<TestSP> ptr2 = ptr;
    std::cout << "ptr addr:" << &ptr << ",ptr2 addr:>>" << &ptr2 << ", this:" << ptr.get() << ", " << ptr2->getStrongCount() << std::endl;
}
kotlin 复制代码
TestSP Construct: 0x5556845aded0 ,>>>HelloWorld<<<
Hi,onFirstRef...
refrence count:1
ptr addr:0x7fffd14f1570,ptr2 addr:>>0x7fffd14f1568, this:0x5556845aded0, 2
onLastStrongRef,Bye: 0x7fffd14f1570
Bye,TestSP Destructor...

onFirstRef 函数相成对的是onLastStrongRef,即最后一引用即将析构的时候,在析构前调用。

三,onFirstRef举例

ini 复制代码
void AudioPolicyService::onFirstRef()
{
    // Log an AudioPolicy "constructor" mediametrics event on first ref.
    // This records the time it takes to load the audio modules and devices.
    mediametrics::Defer defer([beginNs = systemTime()] {
        mediametrics::LogItem(AMEDIAMETRICS_KEY_AUDIO_POLICY)
            .set(AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_EVENT_VALUE_CTOR)
            .set(AMEDIAMETRICS_PROP_EXECUTIONTIMENS, (int64_t)(systemTime() - beginNs))
            .record(); });
    {
        Mutex::Autolock _l(mLock);
 
        // start audio commands thread
        mAudioCommandThread = new AudioCommandThread(String8("ApmAudio"), this);
        // start output activity command thread
        mOutputCommandThread = new AudioCommandThread(String8("ApmOutput"), this);
 
        mAudioPolicyClient = new AudioPolicyClient(this);
 
        loadAudioPolicyManager();
        mAudioPolicyManager = mCreateAudioPolicyManager(mAudioPolicyClient);
    }
 
    // load audio processing modules
    const sp<EffectsFactoryHalInterface> effectsFactoryHal = EffectsFactoryHalInterface::create();
    sp<AudioPolicyEffects> audioPolicyEffects = new AudioPolicyEffects(effectsFactoryHal);
    sp<UidPolicy> uidPolicy = new UidPolicy(this);
    sp<SensorPrivacyPolicy> sensorPrivacyPolicy = new SensorPrivacyPolicy(this);
    {
        Mutex::Autolock _l(mLock);
        mAudioPolicyEffects = audioPolicyEffects;
        mUidPolicy = uidPolicy;
        mSensorPrivacyPolicy = sensorPrivacyPolicy;
    }
    uidPolicy->registerSelf();
    sensorPrivacyPolicy->registerSelf();
 
    // Create spatializer if supported
    if (mAudioPolicyManager != nullptr) {
        Mutex::Autolock _l(mLock);
        const audio_attributes_t attr = attributes_initializer(AUDIO_USAGE_MEDIA);
        AudioDeviceTypeAddrVector devices;
        bool hasSpatializer = mAudioPolicyManager->canBeSpatialized(&attr, nullptr, devices);
        if (hasSpatializer) {
            mSpatializer = Spatializer::create(this, effectsFactoryHal);
        }
        if (mSpatializer == nullptr) {
            // No spatializer created, signal the reason: NO_INIT a failure, OK means intended.
            const status_t createStatus = hasSpatializer ? NO_INIT : OK;
            Spatializer::sendEmptyCreateSpatializerMetricWithStatus(createStatus);
        }
    }
    AudioSystem::audioPolicyReady();
}

AudioPolicyService服务启动做了以下资源初始化:

线程启动:

创建并启动两个线程:

AudioCommandThread: 处理音频命令。

OutputCommandThread: 处理输出设备相关的命令。

创建核心对象:

创建 AudioPolicyClient 对象,用于与 AudioPolicyManager 进行通信。加载并创建 AudioPolicyManager 对象,这是音频策略的核心管理模块。

加载音频处理模块:

创建 AudioPolicyEffects 对象,用于管理音频效果。创建 UidPolicy 对象,用于管理用户ID相关策略。创建 SensorPrivacyPolicy 对象,用于管理传感器隐私策略。将这些模块注册到系统中。

创建空间音频处理模块:

检查设备是否支持空间音频。如果支持,则创建 Spatializer 对象,用于处理空间音频效果。如果创建失败,则记录错误信息。

通知系统:

通知 AudioSystem 音频策略服务已准备就绪。

onFirstRef() 函数是 AudioPolicyService 的初始化函数,负责完成一系列关键任务:创建线程、加载核心模块、初始化音频处理模块、创建空间音频处理模块等,为后续的音频处理工作做好准备

四,总结

主要梳理Android 智能指针实现方式,以及从代码的角度说明为什么Android的智能指针管理的对象必须要继承RefBase的对象。在了解Android智能指针机制之后,Android Native 层的开发将会更加的丝滑~

相关推荐
秋知叶i1 小时前
【轻松学C:编程小白的大冒险】--- 选择 开发工具(IDE)Dev-c++ 03
c语言·开发语言·c++
daily_23331 小时前
c++领域展开第十幕——类和对象(内存管理——c/c++内存分布、c++内存管理方式、new/delete与malloc/free区别)超详细!!!!
c语言·c++
就叫飞六吧1 小时前
C语言中,`extern` 和 `#include`
c语言·c++·算法
涛ing2 小时前
12. C语言 数组与指针(深入理解)
linux·c语言·开发语言·数据结构·c++·算法·ubuntu
黑果果的思考4 小时前
C++例程:使用I/O模拟IIC接口(6)
开发语言·c++
yodala4 小时前
C++中的表达式
android·c++
十年一梦实验室5 小时前
C++ 如何将 gRPC集成到机器人系统中
开发语言·c++·机器人
不是AI5 小时前
【C语言】【C++】报错:[错误]‘vector‘ does not name a type
c语言·开发语言·c++
fadtes6 小时前
用c实现C++类(八股)
c语言·c++