关于android sp和wp的实现原理,网上很多介绍的。但是为何android为何要设计这两个智能指针?使用过程中需要注意什么?
为何设计智能指针
首先sp和wp是针对c++而设计的,因为Java根本就没有指针的概念,替使用者减少了很多不必要的麻烦。在指针的使用过程中,如果处理不妥当,甚至会出现程序的崩溃:
1. 指针没有初始化;
2. new了对象后没有delete;
3. ptr1 和 ptr2同时指向了对象A,当释放了ptr1,同时ptr1=NULL后,ptr2并不知道它所指向的对象不存在了。
关于对象存在多个引用的问题, android设计了两个引用计数相关的类,LightRefBase和RefBase。我们能够想到对象的引用计数应该是保存在对象中的,所以我们在使用引用计数类时,只需要让普通类去继承LightRefBase和RefBase即可,这样普通类产生的对象中就自然而然拥有了引用计数。
首先是LightRefBase,使用mCount作为引用计数。
template <class T>
class LightRefBase
{
//引用计数原子+1
inline void incStrong(__attribute__((unused)) const void* id) const {
android_atomic_inc(&mCount);
}
//引用计数原子-1,当引用计数为0时,销毁对象
inline void decStrong(__attribute__((unused)) const void* id) const {
if (android_atomic_dec(&mCount) == 1) {
delete static_cast<const T*>(this);
}
}
private:
//引用计数
mutable volatile int32_t mCount;
}
考虑另外一种情况,循环引用,父类中保存了子类的对象,子类中保存了父类的对象,这样就是一个“死循环”,父类和子类的引用计数永远不会为0,所以这种情况下单纯使用”mCount”就解决不了这个问题,所以有了RefBase。
对RefBase,没有使用int作为引用计数,而是使用了类weakref_impl* const mRefs;
这个类中同时保存了强引用计数和弱引用计数,也就牵扯出了sp和wp,强智能指针和弱智能指针。并且定义了三种普通对象的生命周期,
class RefBase::weakref_impl : public RefBase::weakref_type
{
public:
volatile int32_t mStrong;
volatile int32_t mWeak;
}
enum {
//对象的生命周期受强指针控制
OBJECT_LIFETIME_STRONG = 0x0000,
//对象的生命周期受弱指针控制
OBJECT_LIFETIME_WEAK = 0x0001,
OBJECT_LIFETIME_MASK = 0x0001
};
如果一个普通对象的生命周期受强指针控制,当强引用计数为0时,普通对象就可以被销毁,但是RefBase中的mRefs对象的销毁由弱引用计数决定。在这种情况下,父子对象可以一个使用强指针,一个使用弱指针,解决循环引用的问题。
同时规定:弱指针必须先升级为强指针,才能去访问智能指针所指向的真实对象。
使用中需要注意的问题
onFirstRef函数
在frameworks中有部分类都实现了onFirstRef函数(需要使用智能指针的类重写了父类RefBase的onFirstRef函数),这个非常有用,当强指针在第一次引用的时候,会去调用这个函数,
void RefBase::incStrong(const void* id) const
{
weakref_impl* const refs = mRefs;
refs->incWeak(id);
refs->addStrongRef(id);
const int32_t c = android_atomic_inc(&refs->mStrong);
ALOG_ASSERT(c > 0, "incStrong() called on %p after last strong ref", refs);
#if PRINT_REFS
ALOGD("incStrong of %p from %p: cnt=%d\n", this, id, c);
#endif
if (c != INITIAL_STRONG_VALUE) {
return;
}
//第一次incStrong的时候,mStrong就是INITIAL_STRONG_VALUE,会调用refs->mBase->onFirstRef()
android_atomic_add(-INITIAL_STRONG_VALUE, &refs->mStrong);
refs->mBase->onFirstRef();
}
下面是SurfaceFlinger中创建Layer的例子,
status_t SurfaceFlinger::createNormalLayer(const sp<Client>& client,
const String8& name, uint32_t w, uint32_t h, uint32_t flags, PixelFormat& format,
sp<IBinder>* handle, sp<IGraphicBufferProducer>* gbp, sp<Layer>* outLayer)
{
// initialize the surfaces
switch (format) {
case PIXEL_FORMAT_TRANSPARENT:
case PIXEL_FORMAT_TRANSLUCENT:
format = PIXEL_FORMAT_RGBA_8888;
break;
case PIXEL_FORMAT_OPAQUE:
#ifdef NO_RGBX_8888
format = PIXEL_FORMAT_RGB_565;
#else
format = PIXEL_FORMAT_RGBX_8888;
#endif
break;
}
#ifdef NO_RGBX_8888
if (format == PIXEL_FORMAT_RGBX_8888)
format = PIXEL_FORMAT_RGBA_8888;
#endif
*outLayer = new Layer(this, client, name, w, h, flags);
status_t err = (*outLayer)->setBuffers(w, h, format, flags);
if (err == NO_ERROR) {
*handle = (*outLayer)->getHandle();
*gbp = (*outLayer)->getBufferQueue();
}
ALOGE_IF(err, "createNormalLayer() failed (%s)", strerror(-err));
return err;
}
*outLayer = new Layer(this, client, name, w, h, flags);
创建一个Layer对象,赋值给outLayer ,这时候会增加强引用计数,同时会去调用Layer的onFirstRef()函数。
void Layer::onFirstRef() {
// Creates a custom BufferQueue for SurfaceFlingerConsumer to use
mBufferQueue = new SurfaceTextureLayer(mFlinger);
mSurfaceFlingerConsumer = new SurfaceFlingerConsumer(mBufferQueue, mTextureName);
mSurfaceFlingerConsumer->setConsumerUsageBits(getEffectiveUsage(0));
mSurfaceFlingerConsumer->setFrameAvailableListener(this);
mSurfaceFlingerConsumer->setName(mName);
#ifdef TARGET_DISABLE_TRIPLE_BUFFERING
#warning "disabling triple buffering"
mSurfaceFlingerConsumer->setDefaultMaxBufferCount(2);
#else
mSurfaceFlingerConsumer->setDefaultMaxBufferCount(3);
#endif
const sp<const DisplayDevice> hw(mFlinger->getDefaultDisplayDevice());
updateTransformHint(hw);
}
wp无法操作真实对象
sp中重载了*和->运算符,返回真实对象,所以可以利用sp去操作真实对象。
//m_ptr是真实对象的指针
inline T& operator* () const { return *m_ptr; }
inline T* operator-> () const { return m_ptr; }
对于wp中没有重载*和->运算符,无法操作真实对象,需要先promote为强指针才能去操作。这种情况就适合于解决如果真实对象已经被delete了,还去操作指针的操作,下面是android中找的例子:
首先在ProxyConsumerListener中定义了一个wp,wp<ConsumerListener> mConsumerListener;
class ProxyConsumerListener : public BnConsumerListener {
public:
ProxyConsumerListener(const wp<ConsumerListener>& consumerListener);
virtual ~ProxyConsumerListener();
virtual void onFrameAvailable();
virtual void onBuffersReleased();
private:
// mConsumerListener is a weak reference to the IConsumerListener. This is
// the raison d'etre of ProxyConsumerListener.
wp<ConsumerListener> mConsumerListener;
};
在使用时,首先对wp需要promote,返回sp后才能去操作真实对象(调用方法嘛),返回为null,则说明没有真实对象的存在。
void BufferQueue::ProxyConsumerListener::onFrameAvailable() {
sp<ConsumerListener> listener(mConsumerListener.promote());
if (listener != NULL) {
listener->onFrameAvailable();
}
}
真实对象是在哪存在的?
将sp<IConsumerListener>& consumerListener
赋值给wp,这时候wp可以成功promote。
status_t BufferQueue::consumerConnect(const sp<IConsumerListener>& consumerListener,
bool controlledByApp) {
ST_LOGV("consumerConnect controlledByApp=%s",
controlledByApp ? "true" : "false");
Mutex::Autolock lock(mMutex);
if (mAbandoned) {
ST_LOGE("consumerConnect: BufferQueue has been abandoned!");
return NO_INIT;
}
if (consumerListener == NULL) {
ST_LOGE("consumerConnect: consumerListener may not be NULL");
return BAD_VALUE;
}
mConsumerListener = consumerListener;
mConsumerControlledByApp = controlledByApp;
mFrameLost = 0;
return NO_ERROR;
}