上篇: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 层的开发将会更加的丝滑~