Home | History | Annotate | Download | only in utils
      1 /*
      2  * Copyright (C) 2005 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #define LOG_TAG "RefBase"
     18 // #define LOG_NDEBUG 0
     19 
     20 #include <utils/RefBase.h>
     21 
     22 #include <utils/Atomic.h>
     23 #include <utils/CallStack.h>
     24 #include <utils/Log.h>
     25 #include <utils/threads.h>
     26 #include <utils/TextOutput.h>
     27 
     28 #include <stdlib.h>
     29 #include <stdio.h>
     30 #include <typeinfo>
     31 #include <sys/types.h>
     32 #include <sys/stat.h>
     33 #include <fcntl.h>
     34 #include <unistd.h>
     35 
     36 // compile with refcounting debugging enabled
     37 #define DEBUG_REFS                      0
     38 
     39 // whether ref-tracking is enabled by default, if not, trackMe(true, false)
     40 // needs to be called explicitly
     41 #define DEBUG_REFS_ENABLED_BY_DEFAULT   0
     42 
     43 // whether callstack are collected (significantly slows things down)
     44 #define DEBUG_REFS_CALLSTACK_ENABLED    1
     45 
     46 // folder where stack traces are saved when DEBUG_REFS is enabled
     47 // this folder needs to exist and be writable
     48 #define DEBUG_REFS_CALLSTACK_PATH       "/data/debug"
     49 
     50 // log all reference counting operations
     51 #define PRINT_REFS                      0
     52 
     53 // ---------------------------------------------------------------------------
     54 
     55 namespace android {
     56 
     57 #define INITIAL_STRONG_VALUE (1<<28)
     58 
     59 // ---------------------------------------------------------------------------
     60 
     61 class RefBase::weakref_impl : public RefBase::weakref_type
     62 {
     63 public:
     64     volatile int32_t    mStrong;
     65     volatile int32_t    mWeak;
     66     RefBase* const      mBase;
     67     volatile int32_t    mFlags;
     68 
     69 #if !DEBUG_REFS
     70 
     71     weakref_impl(RefBase* base)
     72         : mStrong(INITIAL_STRONG_VALUE)
     73         , mWeak(0)
     74         , mBase(base)
     75         , mFlags(0)
     76     {
     77     }
     78 
     79     void addStrongRef(const void* /*id*/) { }
     80     void removeStrongRef(const void* /*id*/) { }
     81     void renameStrongRefId(const void* /*old_id*/, const void* /*new_id*/) { }
     82     void addWeakRef(const void* /*id*/) { }
     83     void removeWeakRef(const void* /*id*/) { }
     84     void renameWeakRefId(const void* /*old_id*/, const void* /*new_id*/) { }
     85     void printRefs() const { }
     86     void trackMe(bool, bool) { }
     87 
     88 #else
     89 
     90     weakref_impl(RefBase* base)
     91         : mStrong(INITIAL_STRONG_VALUE)
     92         , mWeak(0)
     93         , mBase(base)
     94         , mFlags(0)
     95         , mStrongRefs(NULL)
     96         , mWeakRefs(NULL)
     97         , mTrackEnabled(!!DEBUG_REFS_ENABLED_BY_DEFAULT)
     98         , mRetain(false)
     99     {
    100     }
    101 
    102     ~weakref_impl()
    103     {
    104         bool dumpStack = false;
    105         if (!mRetain && mStrongRefs != NULL) {
    106             dumpStack = true;
    107             ALOGE("Strong references remain:");
    108             ref_entry* refs = mStrongRefs;
    109             while (refs) {
    110                 char inc = refs->ref >= 0 ? '+' : '-';
    111                 ALOGD("\t%c ID %p (ref %d):", inc, refs->id, refs->ref);
    112 #if DEBUG_REFS_CALLSTACK_ENABLED
    113                 refs->stack.dump(LOG_TAG);
    114 #endif
    115                 refs = refs->next;
    116             }
    117         }
    118 
    119         if (!mRetain && mWeakRefs != NULL) {
    120             dumpStack = true;
    121             ALOGE("Weak references remain!");
    122             ref_entry* refs = mWeakRefs;
    123             while (refs) {
    124                 char inc = refs->ref >= 0 ? '+' : '-';
    125                 ALOGD("\t%c ID %p (ref %d):", inc, refs->id, refs->ref);
    126 #if DEBUG_REFS_CALLSTACK_ENABLED
    127                 refs->stack.dump(LOG_TAG);
    128 #endif
    129                 refs = refs->next;
    130             }
    131         }
    132         if (dumpStack) {
    133             ALOGE("above errors at:");
    134             CallStack stack(LOG_TAG);
    135         }
    136     }
    137 
    138     void addStrongRef(const void* id) {
    139         //ALOGD_IF(mTrackEnabled,
    140         //        "addStrongRef: RefBase=%p, id=%p", mBase, id);
    141         addRef(&mStrongRefs, id, mStrong);
    142     }
    143 
    144     void removeStrongRef(const void* id) {
    145         //ALOGD_IF(mTrackEnabled,
    146         //        "removeStrongRef: RefBase=%p, id=%p", mBase, id);
    147         if (!mRetain) {
    148             removeRef(&mStrongRefs, id);
    149         } else {
    150             addRef(&mStrongRefs, id, -mStrong);
    151         }
    152     }
    153 
    154     void renameStrongRefId(const void* old_id, const void* new_id) {
    155         //ALOGD_IF(mTrackEnabled,
    156         //        "renameStrongRefId: RefBase=%p, oid=%p, nid=%p",
    157         //        mBase, old_id, new_id);
    158         renameRefsId(mStrongRefs, old_id, new_id);
    159     }
    160 
    161     void addWeakRef(const void* id) {
    162         addRef(&mWeakRefs, id, mWeak);
    163     }
    164 
    165     void removeWeakRef(const void* id) {
    166         if (!mRetain) {
    167             removeRef(&mWeakRefs, id);
    168         } else {
    169             addRef(&mWeakRefs, id, -mWeak);
    170         }
    171     }
    172 
    173     void renameWeakRefId(const void* old_id, const void* new_id) {
    174         renameRefsId(mWeakRefs, old_id, new_id);
    175     }
    176 
    177     void trackMe(bool track, bool retain)
    178     {
    179         mTrackEnabled = track;
    180         mRetain = retain;
    181     }
    182 
    183     void printRefs() const
    184     {
    185         String8 text;
    186 
    187         {
    188             Mutex::Autolock _l(mMutex);
    189             char buf[128];
    190             sprintf(buf, "Strong references on RefBase %p (weakref_type %p):\n", mBase, this);
    191             text.append(buf);
    192             printRefsLocked(&text, mStrongRefs);
    193             sprintf(buf, "Weak references on RefBase %p (weakref_type %p):\n", mBase, this);
    194             text.append(buf);
    195             printRefsLocked(&text, mWeakRefs);
    196         }
    197 
    198         {
    199             char name[100];
    200             snprintf(name, 100, DEBUG_REFS_CALLSTACK_PATH "/%p.stack", this);
    201             int rc = open(name, O_RDWR | O_CREAT | O_APPEND, 644);
    202             if (rc >= 0) {
    203                 write(rc, text.string(), text.length());
    204                 close(rc);
    205                 ALOGD("STACK TRACE for %p saved in %s", this, name);
    206             }
    207             else ALOGE("FAILED TO PRINT STACK TRACE for %p in %s: %s", this,
    208                       name, strerror(errno));
    209         }
    210     }
    211 
    212 private:
    213     struct ref_entry
    214     {
    215         ref_entry* next;
    216         const void* id;
    217 #if DEBUG_REFS_CALLSTACK_ENABLED
    218         CallStack stack;
    219 #endif
    220         int32_t ref;
    221     };
    222 
    223     void addRef(ref_entry** refs, const void* id, int32_t mRef)
    224     {
    225         if (mTrackEnabled) {
    226             AutoMutex _l(mMutex);
    227 
    228             ref_entry* ref = new ref_entry;
    229             // Reference count at the time of the snapshot, but before the
    230             // update.  Positive value means we increment, negative--we
    231             // decrement the reference count.
    232             ref->ref = mRef;
    233             ref->id = id;
    234 #if DEBUG_REFS_CALLSTACK_ENABLED
    235             ref->stack.update(2);
    236 #endif
    237             ref->next = *refs;
    238             *refs = ref;
    239         }
    240     }
    241 
    242     void removeRef(ref_entry** refs, const void* id)
    243     {
    244         if (mTrackEnabled) {
    245             AutoMutex _l(mMutex);
    246 
    247             ref_entry* const head = *refs;
    248             ref_entry* ref = head;
    249             while (ref != NULL) {
    250                 if (ref->id == id) {
    251                     *refs = ref->next;
    252                     delete ref;
    253                     return;
    254                 }
    255                 refs = &ref->next;
    256                 ref = *refs;
    257             }
    258 
    259             ALOGE("RefBase: removing id %p on RefBase %p"
    260                     "(weakref_type %p) that doesn't exist!",
    261                     id, mBase, this);
    262 
    263             ref = head;
    264             while (ref) {
    265                 char inc = ref->ref >= 0 ? '+' : '-';
    266                 ALOGD("\t%c ID %p (ref %d):", inc, ref->id, ref->ref);
    267                 ref = ref->next;
    268             }
    269 
    270             CallStack stack(LOG_TAG);
    271         }
    272     }
    273 
    274     void renameRefsId(ref_entry* r, const void* old_id, const void* new_id)
    275     {
    276         if (mTrackEnabled) {
    277             AutoMutex _l(mMutex);
    278             ref_entry* ref = r;
    279             while (ref != NULL) {
    280                 if (ref->id == old_id) {
    281                     ref->id = new_id;
    282                 }
    283                 ref = ref->next;
    284             }
    285         }
    286     }
    287 
    288     void printRefsLocked(String8* out, const ref_entry* refs) const
    289     {
    290         char buf[128];
    291         while (refs) {
    292             char inc = refs->ref >= 0 ? '+' : '-';
    293             sprintf(buf, "\t%c ID %p (ref %d):\n",
    294                     inc, refs->id, refs->ref);
    295             out->append(buf);
    296 #if DEBUG_REFS_CALLSTACK_ENABLED
    297             out->append(refs->stack.toString("\t\t"));
    298 #else
    299             out->append("\t\t(call stacks disabled)");
    300 #endif
    301             refs = refs->next;
    302         }
    303     }
    304 
    305     mutable Mutex mMutex;
    306     ref_entry* mStrongRefs;
    307     ref_entry* mWeakRefs;
    308 
    309     bool mTrackEnabled;
    310     // Collect stack traces on addref and removeref, instead of deleting the stack references
    311     // on removeref that match the address ones.
    312     bool mRetain;
    313 
    314 #endif
    315 };
    316 
    317 // ---------------------------------------------------------------------------
    318 
    319 void RefBase::incStrong(const void* id) const
    320 {
    321     weakref_impl* const refs = mRefs;
    322     refs->incWeak(id);
    323 
    324     refs->addStrongRef(id);
    325     const int32_t c = android_atomic_inc(&refs->mStrong);
    326     ALOG_ASSERT(c > 0, "incStrong() called on %p after last strong ref", refs);
    327 #if PRINT_REFS
    328     ALOGD("incStrong of %p from %p: cnt=%d\n", this, id, c);
    329 #endif
    330     if (c != INITIAL_STRONG_VALUE)  {
    331         return;
    332     }
    333 
    334     android_atomic_add(-INITIAL_STRONG_VALUE, &refs->mStrong);
    335     refs->mBase->onFirstRef();
    336 }
    337 
    338 void RefBase::decStrong(const void* id) const
    339 {
    340     weakref_impl* const refs = mRefs;
    341     refs->removeStrongRef(id);
    342     const int32_t c = android_atomic_dec(&refs->mStrong);
    343 #if PRINT_REFS
    344     ALOGD("decStrong of %p from %p: cnt=%d\n", this, id, c);
    345 #endif
    346     ALOG_ASSERT(c >= 1, "decStrong() called on %p too many times", refs);
    347     if (c == 1) {
    348         refs->mBase->onLastStrongRef(id);
    349         if ((refs->mFlags&OBJECT_LIFETIME_MASK) == OBJECT_LIFETIME_STRONG) {
    350             delete this;
    351         }
    352     }
    353     refs->decWeak(id);
    354 }
    355 
    356 void RefBase::forceIncStrong(const void* id) const
    357 {
    358     weakref_impl* const refs = mRefs;
    359     refs->incWeak(id);
    360 
    361     refs->addStrongRef(id);
    362     const int32_t c = android_atomic_inc(&refs->mStrong);
    363     ALOG_ASSERT(c >= 0, "forceIncStrong called on %p after ref count underflow",
    364                refs);
    365 #if PRINT_REFS
    366     ALOGD("forceIncStrong of %p from %p: cnt=%d\n", this, id, c);
    367 #endif
    368 
    369     switch (c) {
    370     case INITIAL_STRONG_VALUE:
    371         android_atomic_add(-INITIAL_STRONG_VALUE, &refs->mStrong);
    372         // fall through...
    373     case 0:
    374         refs->mBase->onFirstRef();
    375     }
    376 }
    377 
    378 int32_t RefBase::getStrongCount() const
    379 {
    380     return mRefs->mStrong;
    381 }
    382 
    383 RefBase* RefBase::weakref_type::refBase() const
    384 {
    385     return static_cast<const weakref_impl*>(this)->mBase;
    386 }
    387 
    388 void RefBase::weakref_type::incWeak(const void* id)
    389 {
    390     weakref_impl* const impl = static_cast<weakref_impl*>(this);
    391     impl->addWeakRef(id);
    392     const int32_t c = android_atomic_inc(&impl->mWeak);
    393     ALOG_ASSERT(c >= 0, "incWeak called on %p after last weak ref", this);
    394 }
    395 
    396 
    397 void RefBase::weakref_type::decWeak(const void* id)
    398 {
    399     weakref_impl* const impl = static_cast<weakref_impl*>(this);
    400     impl->removeWeakRef(id);
    401     const int32_t c = android_atomic_dec(&impl->mWeak);
    402     ALOG_ASSERT(c >= 1, "decWeak called on %p too many times", this);
    403     if (c != 1) return;
    404 
    405     if ((impl->mFlags&OBJECT_LIFETIME_WEAK) == OBJECT_LIFETIME_STRONG) {
    406         // This is the regular lifetime case. The object is destroyed
    407         // when the last strong reference goes away. Since weakref_impl
    408         // outlive the object, it is not destroyed in the dtor, and
    409         // we'll have to do it here.
    410         if (impl->mStrong == INITIAL_STRONG_VALUE) {
    411             // Special case: we never had a strong reference, so we need to
    412             // destroy the object now.
    413             delete impl->mBase;
    414         } else {
    415             // ALOGV("Freeing refs %p of old RefBase %p\n", this, impl->mBase);
    416             delete impl;
    417         }
    418     } else {
    419         // less common case: lifetime is OBJECT_LIFETIME_{WEAK|FOREVER}
    420         impl->mBase->onLastWeakRef(id);
    421         if ((impl->mFlags&OBJECT_LIFETIME_MASK) == OBJECT_LIFETIME_WEAK) {
    422             // this is the OBJECT_LIFETIME_WEAK case. The last weak-reference
    423             // is gone, we can destroy the object.
    424             delete impl->mBase;
    425         }
    426     }
    427 }
    428 
    429 bool RefBase::weakref_type::attemptIncStrong(const void* id)
    430 {
    431     incWeak(id);
    432 
    433     weakref_impl* const impl = static_cast<weakref_impl*>(this);
    434     int32_t curCount = impl->mStrong;
    435 
    436     ALOG_ASSERT(curCount >= 0,
    437             "attemptIncStrong called on %p after underflow", this);
    438 
    439     while (curCount > 0 && curCount != INITIAL_STRONG_VALUE) {
    440         // we're in the easy/common case of promoting a weak-reference
    441         // from an existing strong reference.
    442         if (android_atomic_cmpxchg(curCount, curCount+1, &impl->mStrong) == 0) {
    443             break;
    444         }
    445         // the strong count has changed on us, we need to re-assert our
    446         // situation.
    447         curCount = impl->mStrong;
    448     }
    449 
    450     if (curCount <= 0 || curCount == INITIAL_STRONG_VALUE) {
    451         // we're now in the harder case of either:
    452         // - there never was a strong reference on us
    453         // - or, all strong references have been released
    454         if ((impl->mFlags&OBJECT_LIFETIME_WEAK) == OBJECT_LIFETIME_STRONG) {
    455             // this object has a "normal" life-time, i.e.: it gets destroyed
    456             // when the last strong reference goes away
    457             if (curCount <= 0) {
    458                 // the last strong-reference got released, the object cannot
    459                 // be revived.
    460                 decWeak(id);
    461                 return false;
    462             }
    463 
    464             // here, curCount == INITIAL_STRONG_VALUE, which means
    465             // there never was a strong-reference, so we can try to
    466             // promote this object; we need to do that atomically.
    467             while (curCount > 0) {
    468                 if (android_atomic_cmpxchg(curCount, curCount + 1,
    469                         &impl->mStrong) == 0) {
    470                     break;
    471                 }
    472                 // the strong count has changed on us, we need to re-assert our
    473                 // situation (e.g.: another thread has inc/decStrong'ed us)
    474                 curCount = impl->mStrong;
    475             }
    476 
    477             if (curCount <= 0) {
    478                 // promote() failed, some other thread destroyed us in the
    479                 // meantime (i.e.: strong count reached zero).
    480                 decWeak(id);
    481                 return false;
    482             }
    483         } else {
    484             // this object has an "extended" life-time, i.e.: it can be
    485             // revived from a weak-reference only.
    486             // Ask the object's implementation if it agrees to be revived
    487             if (!impl->mBase->onIncStrongAttempted(FIRST_INC_STRONG, id)) {
    488                 // it didn't so give-up.
    489                 decWeak(id);
    490                 return false;
    491             }
    492             // grab a strong-reference, which is always safe due to the
    493             // extended life-time.
    494             curCount = android_atomic_inc(&impl->mStrong);
    495         }
    496 
    497         // If the strong reference count has already been incremented by
    498         // someone else, the implementor of onIncStrongAttempted() is holding
    499         // an unneeded reference.  So call onLastStrongRef() here to remove it.
    500         // (No, this is not pretty.)  Note that we MUST NOT do this if we
    501         // are in fact acquiring the first reference.
    502         if (curCount > 0 && curCount < INITIAL_STRONG_VALUE) {
    503             impl->mBase->onLastStrongRef(id);
    504         }
    505     }
    506 
    507     impl->addStrongRef(id);
    508 
    509 #if PRINT_REFS
    510     ALOGD("attemptIncStrong of %p from %p: cnt=%d\n", this, id, curCount);
    511 #endif
    512 
    513     // now we need to fix-up the count if it was INITIAL_STRONG_VALUE
    514     // this must be done safely, i.e.: handle the case where several threads
    515     // were here in attemptIncStrong().
    516     curCount = impl->mStrong;
    517     while (curCount >= INITIAL_STRONG_VALUE) {
    518         ALOG_ASSERT(curCount > INITIAL_STRONG_VALUE,
    519                 "attemptIncStrong in %p underflowed to INITIAL_STRONG_VALUE",
    520                 this);
    521         if (android_atomic_cmpxchg(curCount, curCount-INITIAL_STRONG_VALUE,
    522                 &impl->mStrong) == 0) {
    523             break;
    524         }
    525         // the strong-count changed on us, we need to re-assert the situation,
    526         // for e.g.: it's possible the fix-up happened in another thread.
    527         curCount = impl->mStrong;
    528     }
    529 
    530     return true;
    531 }
    532 
    533 bool RefBase::weakref_type::attemptIncWeak(const void* id)
    534 {
    535     weakref_impl* const impl = static_cast<weakref_impl*>(this);
    536 
    537     int32_t curCount = impl->mWeak;
    538     ALOG_ASSERT(curCount >= 0, "attemptIncWeak called on %p after underflow",
    539                this);
    540     while (curCount > 0) {
    541         if (android_atomic_cmpxchg(curCount, curCount+1, &impl->mWeak) == 0) {
    542             break;
    543         }
    544         curCount = impl->mWeak;
    545     }
    546 
    547     if (curCount > 0) {
    548         impl->addWeakRef(id);
    549     }
    550 
    551     return curCount > 0;
    552 }
    553 
    554 int32_t RefBase::weakref_type::getWeakCount() const
    555 {
    556     return static_cast<const weakref_impl*>(this)->mWeak;
    557 }
    558 
    559 void RefBase::weakref_type::printRefs() const
    560 {
    561     static_cast<const weakref_impl*>(this)->printRefs();
    562 }
    563 
    564 void RefBase::weakref_type::trackMe(bool enable, bool retain)
    565 {
    566     static_cast<weakref_impl*>(this)->trackMe(enable, retain);
    567 }
    568 
    569 RefBase::weakref_type* RefBase::createWeak(const void* id) const
    570 {
    571     mRefs->incWeak(id);
    572     return mRefs;
    573 }
    574 
    575 RefBase::weakref_type* RefBase::getWeakRefs() const
    576 {
    577     return mRefs;
    578 }
    579 
    580 RefBase::RefBase()
    581     : mRefs(new weakref_impl(this))
    582 {
    583 }
    584 
    585 RefBase::~RefBase()
    586 {
    587     if (mRefs->mStrong == INITIAL_STRONG_VALUE) {
    588         // we never acquired a strong (and/or weak) reference on this object.
    589         delete mRefs;
    590     } else {
    591         // life-time of this object is extended to WEAK or FOREVER, in
    592         // which case weakref_impl doesn't out-live the object and we
    593         // can free it now.
    594         if ((mRefs->mFlags & OBJECT_LIFETIME_MASK) != OBJECT_LIFETIME_STRONG) {
    595             // It's possible that the weak count is not 0 if the object
    596             // re-acquired a weak reference in its destructor
    597             if (mRefs->mWeak == 0) {
    598                 delete mRefs;
    599             }
    600         }
    601     }
    602     // for debugging purposes, clear this.
    603     const_cast<weakref_impl*&>(mRefs) = NULL;
    604 }
    605 
    606 void RefBase::extendObjectLifetime(int32_t mode)
    607 {
    608     android_atomic_or(mode, &mRefs->mFlags);
    609 }
    610 
    611 void RefBase::onFirstRef()
    612 {
    613 }
    614 
    615 void RefBase::onLastStrongRef(const void* /*id*/)
    616 {
    617 }
    618 
    619 bool RefBase::onIncStrongAttempted(uint32_t flags, const void* id)
    620 {
    621     return (flags&FIRST_INC_STRONG) ? true : false;
    622 }
    623 
    624 void RefBase::onLastWeakRef(const void* /*id*/)
    625 {
    626 }
    627 
    628 // ---------------------------------------------------------------------------
    629 
    630 void RefBase::renameRefs(size_t n, const ReferenceRenamer& renamer) {
    631 #if DEBUG_REFS
    632     for (size_t i=0 ; i<n ; i++) {
    633         renamer(i);
    634     }
    635 #endif
    636 }
    637 
    638 void RefBase::renameRefId(weakref_type* ref,
    639         const void* old_id, const void* new_id) {
    640     weakref_impl* const impl = static_cast<weakref_impl*>(ref);
    641     impl->renameStrongRefId(old_id, new_id);
    642     impl->renameWeakRefId(old_id, new_id);
    643 }
    644 
    645 void RefBase::renameRefId(RefBase* ref,
    646         const void* old_id, const void* new_id) {
    647     ref->mRefs->renameStrongRefId(old_id, new_id);
    648     ref->mRefs->renameWeakRefId(old_id, new_id);
    649 }
    650 
    651 // ---------------------------------------------------------------------------
    652 
    653 TextOutput& printStrongPointer(TextOutput& to, const void* val)
    654 {
    655     to << "sp<>(" << val << ")";
    656     return to;
    657 }
    658 
    659 TextOutput& printWeakPointer(TextOutput& to, const void* val)
    660 {
    661     to << "wp<>(" << val << ")";
    662     return to;
    663 }
    664 
    665 
    666 }; // namespace android
    667