Android strong and weak pointers

Base class RefBase

  Both strong pointers and weak pointers in Android inherit from the RefBase class.
  It is worth noting that there is an inner class weakref_type in the Refbase class, which has a member variable of type weakref_impl*. The weakref_impl class inherits from the inner class weakref_type of the Refbase class. There is also a member mBase of type RefBase* in weakref_type that points to the corresponding Refbase object. The weakref_type class uses mStrong to record strong reference counts, mWeak to record weak reference counts, and mFlags to record what the pointer lifetime depends on. mStrong is initialized to INITIAL_STRONG_VALUE, the macro definition is defined as 2 to the 28th power, and mWeak is initialized to 0. Strong and weak reference counts determine when pointers should be freed. Among them, OBJECT_LIFETIME_STRONG (that is, the default initialization value) means that it is only affected by the strong reference count, OBJECT_LIFETIME_WEAK means that it is affected by both the strong reference count and the weak reference count, OBJECT_LIFETIME_MASK is a mask value, and the form of flag&OBJECT_LIFETIME_MASK will be used later to get the lowest bit of the flag numerical value.

/frameworks/rs/cpp/util/RefBase.h

enum {
        OBJECT_LIFETIME_STRONG  = 0x0000,
        OBJECT_LIFETIME_WEAK    = 0x0001,
        OBJECT_LIFETIME_MASK    = 0x0001
    };

/frameworks/rs/cpp/util/RefBase.h

class RefBase
{
public:
            void            incStrong(const void* id) const;
            void            decStrong(const void* id) const;

            void            forceIncStrong(const void* id) const;

            //! DEBUGGING ONLY: Get current strong ref count.
            int32_t         getStrongCount() const;

    class weakref_type
    {
    public:
        RefBase*            refBase() const;

        void                incWeak(const void* id);
        void                decWeak(const void* id);

        // acquires a strong reference if there is already one.
        bool                attemptIncStrong(const void* id);

        // acquires a weak reference if there is already one.
        // This is not always safe. see ProcessState.cpp and BpBinder.cpp
        // for proper use.
        bool                attemptIncWeak(const void* id);

        //! DEBUGGING ONLY: Get current weak ref count.
        int32_t             getWeakCount() const;

        //! DEBUGGING ONLY: Print references held on object.
        void                printRefs() const;

        //! DEBUGGING ONLY: Enable tracking for this object.
        // enable -- enable/disable tracking
        // retain -- when tracking is enable, if true, then we save a stack trace
        //           for each reference and dereference; when retain == false, we
        //           match up references and dereferences and keep only the
        //           outstanding ones.

        void                trackMe(bool enable, bool retain);
    };

            weakref_type*   createWeak(const void* id) const;

            weakref_type*   getWeakRefs() const;

            //! DEBUGGING ONLY: Print references held on object.
    inline  void            printRefs() const { getWeakRefs()->printRefs(); }

            //! DEBUGGING ONLY: Enable tracking of object.
    inline  void            trackMe(bool enable, bool retain)
    {
        getWeakRefs()->trackMe(enable, retain);
    }

    typedef RefBase basetype;

protected:
                            RefBase();
    virtual                 ~RefBase();

    //! Flags for extendObjectLifetime()
    enum {
        OBJECT_LIFETIME_STRONG  = 0x0000,
        OBJECT_LIFETIME_WEAK    = 0x0001,
        OBJECT_LIFETIME_MASK    = 0x0001
    };

            void            extendObjectLifetime(int32_t mode);

    //! Flags for onIncStrongAttempted()
    enum {
        FIRST_INC_STRONG = 0x0001
    };

    virtual void            onFirstRef();
    virtual void            onLastStrongRef(const void* id);
    virtual bool            onIncStrongAttempted(uint32_t flags, const void* id);
    virtual void            onLastWeakRef(const void* id);

private:
    friend class ReferenceMover;
    static void moveReferences(void* d, void const* s, size_t n,
            const ReferenceConverterBase& caster);

private:
    friend class weakref_type;
    class weakref_impl;

                            RefBase(const RefBase& o);
            RefBase&        operator=(const RefBase& o);

        weakref_impl* const mRefs;
};

  The constructor of RefBase takes this as a parameter and creates a new weakref_impl object.

/frameworks/rs/cpp/util/RefBase.cpp

RefBase::RefBase()
    : mRefs(new weakref_impl(this))
{
}

  The weakref_impl constructor saves the incoming RefBase in mBase.

/frameworks/rs/cpp/util/RefBase.cpp

class RefBase::weakref_impl : public RefBase::weakref_type
{
public:
    volatile int32_t    mStrong;
    volatile int32_t    mWeak;
    RefBase* const      mBase;
    volatile int32_t    mFlags;
    ...
    weakref_impl(RefBase* base)
        : mStrong(INITIAL_STRONG_VALUE)
        , mWeak(0)
        , mBase(base)
        , mFlags(0)
        , mStrongRefs(NULL)
        , mWeakRefs(NULL)
        , mTrackEnabled(!!DEBUG_REFS_ENABLED_BY_DEFAULT)
        , mRetain(false)
    {
    }
    ...

  The destructor of RefBase is defined as a virtual function, which prevents only the base class from being destructed but not the derived class.
/frameworks/rs/cpp/util/RefBase.cpp

RefBase::~RefBase()
{
    if (mRefs->mStrong == INITIAL_STRONG_VALUE) {
        // we never acquired a strong (and/or weak) reference on this object.
        delete mRefs;
    } else {
        // life-time of this object is extended to WEAK or FOREVER, in
        // which case weakref_impl doesn't out-live the object and we
        // can free it now.
        if ((mRefs->mFlags & OBJECT_LIFETIME_MASK) != OBJECT_LIFETIME_STRONG) {
            // It's possible that the weak count is not 0 if the object
            // re-acquired a weak reference in its destructor
            if (mRefs->mWeak == 0) {
                delete mRefs;
            }
        }
    }
    // for debugging purposes, clear this.
    const_cast<weakref_impl*&>(mRefs) = NULL;
}

strong pointer class sp

  The sp class is a template class, and the template parameters must inherit from RefBase. The sp class is the encapsulation of the ordinary pointer. It has an ordinary pointer member m_ptr inside, which stores the ordinary pointer. The ordinary pointer points to the same type as the template parameter.

/frameworks/rs/server/StrongPointer.h

template <typename T>
class sp
{
public:
    inline sp() : m_ptr(0) { }

    sp(T* other);
    sp(const sp<T>& other);
    template<typename U> sp(U* other);
    template<typename U> sp(const sp<U>& other);

    ~sp();

    // Assignment

    sp& operator = (T* other);
    sp& operator = (const sp<T>& other);

    template<typename U> sp& operator = (const sp<U>& other);
    template<typename U> sp& operator = (U* other);

    //! Special optimization for use by ProcessState (and nobody else).
    void force_set(T* other);

    // Reset

    void clear();

    // Accessors

    inline  T&      operator* () const  { return *m_ptr; }
    inline  T*      operator-> () const { return m_ptr;  }
    inline  T*      get() const         { return m_ptr; }

    // Operators

    COMPARE(==)
    COMPARE(!=)
    COMPARE(>)
    COMPARE(<)
    COMPARE(<=)
    COMPARE(>=)

private:
    template<typename Y> friend class sp;
    template<typename Y> friend class wp;
    void set_pointer(T* ptr);
    T* m_ptr;
};

  Let's take a look at how the sp instance is constructed. The sp class saves the parameters of the template type in the member m_ptr, and then calls the incStrong function of the parent class RefBase of the template parameter class.

/frameworks/rs/server/StrongPointer.h

template<typename T>
sp<T>::sp(T* other)
: m_ptr(other)
  {
    if (other) other->incStrong(this);
  }

  The this of sp is passed in as the id parameter of RefBase::incStrong, which is convenient for debugging. First, create a pointer to the same pointer as mRefs and call the RefBase::weakref_type::incWeak method. In the incWeak method, although the incWeak method of weakref_type is called, the caller refs is essentially of weakref_impl* type, so the pointer of weakref_type* type can be safely cast to the pointer of weakref_impl* type, so as to count the weak reference of mWeak inside weakref_impl plus 1. android_atomic_inc returns the value before adding 1. Go back to the RefBase::incStrong method, and then increment the strong reference count by 1. As mentioned earlier, when the strong reference count is initialized, it is INITIAL_STRONG_VALUE. After adding 1, you need to subtract INITIAL_STRONG_VALUE to restore the correct value. Finally, call onFirstRef of RefBase, which is an empty implementation, implemented by subclasses, and can add some logic when it is first referenced by a strong pointer.

/system/core/libutils/RefBase.cpp

void RefBase::incStrong(const void* id) const
{
    weakref_impl* const refs = mRefs;
    refs->incWeak(id);
    //debug方法
    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;
    }

    android_atomic_add(-INITIAL_STRONG_VALUE, &refs->mStrong);
    refs->mBase->onFirstRef();
}

/system/core/libutils/RefBase.cpp

void RefBase::weakref_type::incWeak(const void* id)
{
    weakref_impl* const impl = static_cast<weakref_impl*>(this);
    impl->addWeakRef(id);
    const int32_t c __unused = android_atomic_inc(&impl->mWeak);
    ALOG_ASSERT(c >= 0, "incWeak called on %p after last weak ref", this);
}

  It can be seen that when using incStrong to increase the strong reference count by 1, it also increases the weak reference count by 1.
  Look again at the destructor of sp. You can see that the decStrong function of RefBase is called.

/frameworks/rs/server/StrongPointer.h

template<typename T>
sp<T>::~sp()
{
    if (m_ptr) m_ptr->decStrong(this);
}

  In the RefBase::decStrong method, use android_atomic_dec to decrement the strong reference count by 1, and android_atomic_dec returns the value before decrementing 1. If the strong reference count has become 0 at this time and the pointer lifetime depends only on the strong reference count, release the RefBase object. Finally, decrement the weak reference count by 1. It can be seen that when decStrong is used to decrement the strong reference count by 1, the weak reference count is also decremented by 1.

/frameworks/rs/cpp/util/RefBase.cpp

void RefBase::decStrong(const void* id) const
{
    weakref_impl* const refs = mRefs;
    refs->removeStrongRef(id);
    const int32_t c = android_atomic_dec(&refs->mStrong);
#if PRINT_REFS
    ALOGD("decStrong of %p from %p: cnt=%d\n", this, id, c);
#endif
    ALOG_ASSERT(c >= 1, "decStrong() called on %p too many times", refs);
    if (c == 1) {
        refs->mBase->onLastStrongRef(id);
        if ((refs->mFlags&OBJECT_LIFETIME_MASK) == OBJECT_LIFETIME_STRONG) {
            delete this;
        }
    }
    refs->decWeak(id);
}

  Take a look at RefBase's destructor. If the strong reference count of the object is the initialized value, it means that it has never been referenced by a strong pointer, and the mRefs member is released. If it has been referenced by a strong pointer, and the life cycle does not depend only on the strong reference count, then when the weak reference count is 0, the mRefs member is released. Because the weak reference count always increases or decreases with the strong reference count, the weak reference count will never be less than the strong reference count, and when the weak reference count is 0, the strong reference count must be 0.

RefBase::~RefBase()
{
    if (mRefs->mStrong == INITIAL_STRONG_VALUE) {
        // we never acquired a strong (and/or weak) reference on this object.
        delete mRefs;
    } else {
        // life-time of this object is extended to WEAK or FOREVER, in
        // which case weakref_impl doesn't out-live the object and we
        // can free it now.
        if ((mRefs->mFlags & OBJECT_LIFETIME_MASK) != OBJECT_LIFETIME_STRONG) {
            // It's possible that the weak count is not 0 if the object
            // re-acquired a weak reference in its destructor
            if (mRefs->mWeak == 0) {
                delete mRefs;
            }
        }
    }
    // for debugging purposes, clear this.
    const_cast<weakref_impl*&>(mRefs) = NULL;
}

weak pointer class wp

  The weak pointer class wp and the strong pointer class sp also have the encapsulated pointer member m_ptr, as well as a weakref_type* type member.

/frameworks/rs/cpp/util/RefBase.h

template <typename T>
class wp
{
public:
    typedef typename RefBase::weakref_type weakref_type;

    inline wp() : m_ptr(0) { }

    wp(T* other);
    wp(const wp<T>& other);
    wp(const sp<T>& other);
    template<typename U> wp(U* other);
    template<typename U> wp(const sp<U>& other);
    template<typename U> wp(const wp<U>& other);
    ...
    private:
    template<typename Y> friend class sp;
    template<typename Y> friend class wp;

    T*              m_ptr;
    weakref_type*   m_refs;
};

  Take a look at wp's constructor.

/frameworks/rs/cpp/util/RefBase.h

template<typename T>
wp<T>::wp(T* other)
    : m_ptr(other)
{
    if (other) m_refs = other->createWeak(this);
}

/frameworks/rs/cpp/util/RefBase.h

template<typename T>
wp<T>::wp(const sp<T>& other)
    : m_ptr(other.m_ptr)
{
    if (m_ptr) {
        m_refs = m_ptr->createWeak(this);
    }
}

  createWeak calls the RefBase::weakref_type::incWeak method.

/frameworks/rs/cpp/util/RefBase.h

RefBase::weakref_type* RefBase::createWeak(const void* id) const
{
    mRefs->incWeak(id);
    return mRefs;
}

  The incWeak function increments the weak reference count by 1.

/frameworks/rs/cpp/util/RefBase.cpp

void RefBase::weakref_type::incWeak(const void* id)
{
    weakref_impl* const impl = static_cast<weakref_impl*>(this);
    impl->addWeakRef(id);
    const int32_t c __unused = android_atomic_inc(&impl->mWeak);
    ALOG_ASSERT(c >= 0, "incWeak called on %p after last weak ref", this);
}

  It can be found that whether in strong pointers or weak pointers, the number of weak reference counts will be greater than or equal to the number of strong reference counts (excluding the case where the strong reference count is INITIAL_STRONG_VALUE when it is not referenced by a strong pointer).
  Take a look at wp's destructor.

/frameworks/rs/cpp/util/RefBase.h

template<typename T>
wp<T>::~wp()
{
    if (m_ptr) m_refs->decWeak(this);
}

  In the decWeak function, the weak reference count is first decremented by 1. If the weak reference count is not equal to 0 after decrementing by 1, return directly. If it is equal to 0, enter the release step. In the release step, if the life cycle of the object is only affected by the strong reference count and has not been referenced by the strong pointer, the corresponding RefBase object is released; if the life cycle of the object is only affected by the strong reference count and has been referenced by the strong pointer, At this time, because the weak reference count is 0, the strong reference count must also be 0, and only the weakref_impl* pointer is released. Why not start from RefBase? Because the previous decStrong function has been released once. If the life cycle of the object is affected by both strong reference count and weak reference count, release the corresponding RefBase object.

/frameworks/rs/cpp/util/RefBase.cpp

void RefBase::weakref_type::decWeak(const void* id)
{
    weakref_impl* const impl = static_cast<weakref_impl*>(this);
    impl->removeWeakRef(id);
    const int32_t c = android_atomic_dec(&impl->mWeak);
    ALOG_ASSERT(c >= 1, "decWeak called on %p too many times", this);
    if (c != 1) return;

    if ((impl->mFlags&OBJECT_LIFETIME_WEAK) == OBJECT_LIFETIME_STRONG) {
        // This is the regular lifetime case. The object is destroyed
        // when the last strong reference goes away. Since weakref_impl
        // outlive the object, it is not destroyed in the dtor, and
        // we'll have to do it here.
        if (impl->mStrong == INITIAL_STRONG_VALUE) {
            // Special case: we never had a strong reference, so we need to
            // destroy the object now.
            delete impl->mBase;
        } else {
            // ALOGV("Freeing refs %p of old RefBase %p\n", this, impl->mBase);
            delete impl;
        }
    } else {
        // less common case: lifetime is OBJECT_LIFETIME_{WEAK|FOREVER}
        impl->mBase->onLastWeakRef(id);
        if ((impl->mFlags&OBJECT_LIFETIME_MASK) == OBJECT_LIFETIME_WEAK) {
            // this is the OBJECT_LIFETIME_WEAK case. The last weak-reference
            // is gone, we can destroy the object.
            delete impl->mBase;
        }
    }
}

weak pointer promotion promote

  Weak pointers cannot directly manipulate reference objects, and must be promoted to strong pointers to manipulate reference objects. Because wp class does not overload * and -> operators. wp pointers can be promoted to strong pointers through the promote function.

/frameworks/rs/cpp/util/RefBase.h

template<typename T>
sp<T> wp<T>::promote() const
{
    sp<T> result;
    if (m_ptr && m_refs->attemptIncStrong(&result)) {
        result.set_pointer(m_ptr);
    }
    return result;
}

  In the attemptIncStrong function, first use the incWeak function to increment the weak reference count by 1. curCount is recorded as the object's strong reference count. When the object is referenced by a strong pointer (curCount>0 and not the initial value), use android_atomic_cmpxchg to add 1 to curCount. Here, a while loop is used. If the addition of 1 fails, the original value is restored and the addition of 1 is performed again. If the object has never been referenced by a strong pointer or the strong reference count is less than or equal to 0, here is a case-by-case discussion based on the life cycle: 1. If the object life cycle is only affected by the strong reference count, when curCount is less than or equal to 0, it means the object Has been released, there is no possibility of promotion, directly use decWeak to decrement the weak reference count by 1, because the function adds 1 to the weak reference count at the beginning. When the object is not referenced by a strong pointer, increment curCount by 1. In the loop body that adds 1, if other threads make the strong reference count of the object become 0, it means that the object will be released, and call decWeak to decrement the weak reference count by 1. 2. If the object life cycle is in other ways, call onIncStrongAttempted to try to The strong reference count is increased by 1. onIncStrongAttempted is a virtual function of RefBase, which is rewritten by subclasses. The specific function is whether to allow the strong reference count to be increased by 1. If not allowed, the weak reference count is decremented by 1; if allowed, the strong reference count is increased by 1.
  Some of the above situations will result in a strong reference count greater than or equal to the initialized value, which is then restored by subtracting the INITIAL_STRONG_VALUE.

/frameworks/rs/cpp/util/RefBase.cpp

bool RefBase::weakref_type::attemptIncStrong(const void* id)
{
    incWeak(id);

    weakref_impl* const impl = static_cast<weakref_impl*>(this);
    int32_t curCount = impl->mStrong;

    ALOG_ASSERT(curCount >= 0,
            "attemptIncStrong called on %p after underflow", this);

    while (curCount > 0 && curCount != INITIAL_STRONG_VALUE) {
        // we're in the easy/common case of promoting a weak-reference
        // from an existing strong reference.
        if (android_atomic_cmpxchg(curCount, curCount+1, &impl->mStrong) == 0) {
            break;
        }
        // the strong count has changed on us, we need to re-assert our
        // situation.
        curCount = impl->mStrong;
    }

    if (curCount <= 0 || curCount == INITIAL_STRONG_VALUE) {
        // we're now in the harder case of either:
        // - there never was a strong reference on us
        // - or, all strong references have been released
        if ((impl->mFlags&OBJECT_LIFETIME_WEAK) == OBJECT_LIFETIME_STRONG) {
            // this object has a "normal" life-time, i.e.: it gets destroyed
            // when the last strong reference goes away
            if (curCount <= 0) {
                // the last strong-reference got released, the object cannot
                // be revived.
                decWeak(id);
                return false;
            }

            // here, curCount == INITIAL_STRONG_VALUE, which means
            // there never was a strong-reference, so we can try to
            // promote this object; we need to do that atomically.
            while (curCount > 0) {
                if (android_atomic_cmpxchg(curCount, curCount + 1,
                        &impl->mStrong) == 0) {
                    break;
                }
                // the strong count has changed on us, we need to re-assert our
                // situation (e.g.: another thread has inc/decStrong'ed us)
                curCount = impl->mStrong;
            }

            if (curCount <= 0) {
                // promote() failed, some other thread destroyed us in the
                // meantime (i.e.: strong count reached zero).
                decWeak(id);
                return false;
            }
        } else {
            // this object has an "extended" life-time, i.e.: it can be
            // revived from a weak-reference only.
            // Ask the object's implementation if it agrees to be revived
            if (!impl->mBase->onIncStrongAttempted(FIRST_INC_STRONG, id)) {
                // it didn't so give-up.
                decWeak(id);
                return false;
            }
            // grab a strong-reference, which is always safe due to the
            // extended life-time.
            curCount = android_atomic_inc(&impl->mStrong);
        }

        // If the strong reference count has already been incremented by
        // someone else, the implementor of onIncStrongAttempted() is holding
        // an unneeded reference.  So call onLastStrongRef() here to remove it.
        // (No, this is not pretty.)  Note that we MUST NOT do this if we
        // are in fact acquiring the first reference.
        if (curCount > 0 && curCount < INITIAL_STRONG_VALUE) {
            impl->mBase->onLastStrongRef(id);
        }
    }

    impl->addStrongRef(id);

#if PRINT_REFS
    ALOGD("attemptIncStrong of %p from %p: cnt=%d\n", this, id, curCount);
#endif

    // now we need to fix-up the count if it was INITIAL_STRONG_VALUE
    // this must be done safely, i.e.: handle the case where several threads
    // were here in attemptIncStrong().
    curCount = impl->mStrong;
    while (curCount >= INITIAL_STRONG_VALUE) {
        ALOG_ASSERT(curCount > INITIAL_STRONG_VALUE,
                "attemptIncStrong in %p underflowed to INITIAL_STRONG_VALUE",
                this);
        if (android_atomic_cmpxchg(curCount, curCount-INITIAL_STRONG_VALUE,
                &impl->mStrong) == 0) {
            break;
        }
        // the strong-count changed on us, we need to re-assert the situation,
        // for e.g.: it's possible the fix-up happened in another thread.
        curCount = impl->mStrong;
    }

    return true;
}

  Return to the promote function, if attemptIncStrong returns true and the pointer is promoted successfully, the set_pointer function saves the m_ptr member in wp in sp, and finally returns the sp object, and the pointer promotion is completed.

/frameworks/rs/server/StrongPointer.h

template<typename T>
void sp<T>::set_pointer(T* ptr) {
    m_ptr = ptr;
}

Summarize

  After sp destructing, the strong and weak reference counts are increased by 1, and after sp destructing, the strong and weak reference counts are decreased by 1.
  After wpization, the weak reference count is increased by 1, and after wp is destructed, the weak reference count is decreased by 1.

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325571523&siteId=291194637