android中的sp和wp


关于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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值