• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
19 #include <utils/RefBase.h>
20 
21 #include <utils/Atomic.h>
22 #include <utils/CallStack.h>
23 #include <utils/Log.h>
24 #include <utils/threads.h>
25 #include <utils/TextOutput.h>
26 
27 #include <stdlib.h>
28 #include <stdio.h>
29 #include <typeinfo>
30 #include <sys/types.h>
31 #include <sys/stat.h>
32 #include <fcntl.h>
33 #include <unistd.h>
34 
35 // compile with refcounting debugging enabled
36 #define DEBUG_REFS                      0
37 #define DEBUG_REFS_FATAL_SANITY_CHECKS  0
38 #define DEBUG_REFS_ENABLED_BY_DEFAULT   1
39 #define DEBUG_REFS_CALLSTACK_ENABLED    1
40 
41 // log all reference counting operations
42 #define PRINT_REFS                      0
43 
44 // ---------------------------------------------------------------------------
45 
46 namespace android {
47 
48 #define INITIAL_STRONG_VALUE (1<<28)
49 
50 // ---------------------------------------------------------------------------
51 
52 class RefBase::weakref_impl : public RefBase::weakref_type
53 {
54 public:
55     volatile int32_t    mStrong;
56     volatile int32_t    mWeak;
57     RefBase* const      mBase;
58     volatile int32_t    mFlags;
59 
60 #if !DEBUG_REFS
61 
weakref_impl(RefBase * base)62     weakref_impl(RefBase* base)
63         : mStrong(INITIAL_STRONG_VALUE)
64         , mWeak(0)
65         , mBase(base)
66         , mFlags(0)
67     {
68     }
69 
addStrongRef(const void *)70     void addStrongRef(const void* /*id*/) { }
removeStrongRef(const void *)71     void removeStrongRef(const void* /*id*/) { }
renameStrongRefId(const void *,const void *)72     void renameStrongRefId(const void* /*old_id*/, const void* /*new_id*/) { }
addWeakRef(const void *)73     void addWeakRef(const void* /*id*/) { }
removeWeakRef(const void *)74     void removeWeakRef(const void* /*id*/) { }
renameWeakRefId(const void *,const void *)75     void renameWeakRefId(const void* /*old_id*/, const void* /*new_id*/) { }
printRefs() const76     void printRefs() const { }
trackMe(bool,bool)77     void trackMe(bool, bool) { }
78 
79 #else
80 
weakref_impl(RefBase * base)81     weakref_impl(RefBase* base)
82         : mStrong(INITIAL_STRONG_VALUE)
83         , mWeak(0)
84         , mBase(base)
85         , mFlags(0)
86         , mStrongRefs(NULL)
87         , mWeakRefs(NULL)
88         , mTrackEnabled(!!DEBUG_REFS_ENABLED_BY_DEFAULT)
89         , mRetain(false)
90     {
91     }
92 
~weakref_impl()93     ~weakref_impl()
94     {
95         bool dumpStack = false;
96         if (!mRetain && mStrongRefs != NULL) {
97             dumpStack = true;
98 #if DEBUG_REFS_FATAL_SANITY_CHECKS
99             LOG_ALWAYS_FATAL("Strong references remain!");
100 #else
101             LOGE("Strong references remain:");
102 #endif
103             ref_entry* refs = mStrongRefs;
104             while (refs) {
105                 char inc = refs->ref >= 0 ? '+' : '-';
106                 LOGD("\t%c ID %p (ref %d):", inc, refs->id, refs->ref);
107 #if DEBUG_REFS_CALLSTACK_ENABLED
108                 refs->stack.dump();
109 #endif
110                 refs = refs->next;
111             }
112         }
113 
114         if (!mRetain && mWeakRefs != NULL) {
115             dumpStack = true;
116 #if DEBUG_REFS_FATAL_SANITY_CHECKS
117             LOG_ALWAYS_FATAL("Weak references remain:");
118 #else
119             LOGE("Weak references remain!");
120 #endif
121             ref_entry* refs = mWeakRefs;
122             while (refs) {
123                 char inc = refs->ref >= 0 ? '+' : '-';
124                 LOGD("\t%c ID %p (ref %d):", inc, refs->id, refs->ref);
125 #if DEBUG_REFS_CALLSTACK_ENABLED
126                 refs->stack.dump();
127 #endif
128                 refs = refs->next;
129             }
130         }
131         if (dumpStack) {
132             LOGE("above errors at:");
133             CallStack stack;
134             stack.update();
135             stack.dump();
136         }
137     }
138 
addStrongRef(const void * id)139     void addStrongRef(const void* id) {
140         //LOGD_IF(mTrackEnabled,
141         //        "addStrongRef: RefBase=%p, id=%p", mBase, id);
142         addRef(&mStrongRefs, id, mStrong);
143     }
144 
removeStrongRef(const void * id)145     void removeStrongRef(const void* id) {
146         //LOGD_IF(mTrackEnabled,
147         //        "removeStrongRef: RefBase=%p, id=%p", mBase, id);
148         if (!mRetain) {
149             removeRef(&mStrongRefs, id);
150         } else {
151             addRef(&mStrongRefs, id, -mStrong);
152         }
153     }
154 
renameStrongRefId(const void * old_id,const void * new_id)155     void renameStrongRefId(const void* old_id, const void* new_id) {
156         //LOGD_IF(mTrackEnabled,
157         //        "renameStrongRefId: RefBase=%p, oid=%p, nid=%p",
158         //        mBase, old_id, new_id);
159         renameRefsId(mStrongRefs, old_id, new_id);
160     }
161 
addWeakRef(const void * id)162     void addWeakRef(const void* id) {
163         addRef(&mWeakRefs, id, mWeak);
164     }
165 
removeWeakRef(const void * id)166     void removeWeakRef(const void* id) {
167         if (!mRetain) {
168             removeRef(&mWeakRefs, id);
169         } else {
170             addRef(&mWeakRefs, id, -mWeak);
171         }
172     }
173 
renameWeakRefId(const void * old_id,const void * new_id)174     void renameWeakRefId(const void* old_id, const void* new_id) {
175         renameRefsId(mWeakRefs, old_id, new_id);
176     }
177 
trackMe(bool track,bool retain)178     void trackMe(bool track, bool retain)
179     {
180         mTrackEnabled = track;
181         mRetain = retain;
182     }
183 
printRefs() const184     void printRefs() const
185     {
186         String8 text;
187 
188         {
189             Mutex::Autolock _l(mMutex);
190             char buf[128];
191             sprintf(buf, "Strong references on RefBase %p (weakref_type %p):\n", mBase, this);
192             text.append(buf);
193             printRefsLocked(&text, mStrongRefs);
194             sprintf(buf, "Weak references on RefBase %p (weakref_type %p):\n", mBase, this);
195             text.append(buf);
196             printRefsLocked(&text, mWeakRefs);
197         }
198 
199         {
200             char name[100];
201             snprintf(name, 100, "/data/%p.stack", this);
202             int rc = open(name, O_RDWR | O_CREAT | O_APPEND);
203             if (rc >= 0) {
204                 write(rc, text.string(), text.length());
205                 close(rc);
206                 LOGD("STACK TRACE for %p saved in %s", this, name);
207             }
208             else LOGE("FAILED TO PRINT STACK TRACE for %p in %s: %s", this,
209                       name, strerror(errno));
210         }
211     }
212 
213 private:
214     struct ref_entry
215     {
216         ref_entry* next;
217         const void* id;
218 #if DEBUG_REFS_CALLSTACK_ENABLED
219         CallStack stack;
220 #endif
221         int32_t ref;
222     };
223 
addRef(ref_entry ** refs,const void * id,int32_t mRef)224     void addRef(ref_entry** refs, const void* id, int32_t mRef)
225     {
226         if (mTrackEnabled) {
227             AutoMutex _l(mMutex);
228 
229             ref_entry* ref = new ref_entry;
230             // Reference count at the time of the snapshot, but before the
231             // update.  Positive value means we increment, negative--we
232             // decrement the reference count.
233             ref->ref = mRef;
234             ref->id = id;
235 #if DEBUG_REFS_CALLSTACK_ENABLED
236             ref->stack.update(2);
237 #endif
238             ref->next = *refs;
239             *refs = ref;
240         }
241     }
242 
removeRef(ref_entry ** refs,const void * id)243     void removeRef(ref_entry** refs, const void* id)
244     {
245         if (mTrackEnabled) {
246             AutoMutex _l(mMutex);
247 
248             ref_entry* const head = *refs;
249             ref_entry* ref = head;
250             while (ref != NULL) {
251                 if (ref->id == id) {
252                     *refs = ref->next;
253                     delete ref;
254                     return;
255                 }
256                 refs = &ref->next;
257                 ref = *refs;
258             }
259 
260 #if DEBUG_REFS_FATAL_SANITY_CHECKS
261             LOG_ALWAYS_FATAL("RefBase: removing id %p on RefBase %p"
262                     "(weakref_type %p) that doesn't exist!",
263                     id, mBase, this);
264 #endif
265 
266             LOGE("RefBase: removing id %p on RefBase %p"
267                     "(weakref_type %p) that doesn't exist!",
268                     id, mBase, this);
269 
270             ref = head;
271             while (ref) {
272                 char inc = ref->ref >= 0 ? '+' : '-';
273                 LOGD("\t%c ID %p (ref %d):", inc, ref->id, ref->ref);
274                 ref = ref->next;
275             }
276 
277             CallStack stack;
278             stack.update();
279             stack.dump();
280         }
281     }
282 
renameRefsId(ref_entry * r,const void * old_id,const void * new_id)283     void renameRefsId(ref_entry* r, const void* old_id, const void* new_id)
284     {
285         if (mTrackEnabled) {
286             AutoMutex _l(mMutex);
287             ref_entry* ref = r;
288             while (ref != NULL) {
289                 if (ref->id == old_id) {
290                     ref->id = new_id;
291                 }
292                 ref = ref->next;
293             }
294         }
295     }
296 
printRefsLocked(String8 * out,const ref_entry * refs) const297     void printRefsLocked(String8* out, const ref_entry* refs) const
298     {
299         char buf[128];
300         while (refs) {
301             char inc = refs->ref >= 0 ? '+' : '-';
302             sprintf(buf, "\t%c ID %p (ref %d):\n",
303                     inc, refs->id, refs->ref);
304             out->append(buf);
305 #if DEBUG_REFS_CALLSTACK_ENABLED
306             out->append(refs->stack.toString("\t\t"));
307 #else
308             out->append("\t\t(call stacks disabled)");
309 #endif
310             refs = refs->next;
311         }
312     }
313 
314     mutable Mutex mMutex;
315     ref_entry* mStrongRefs;
316     ref_entry* mWeakRefs;
317 
318     bool mTrackEnabled;
319     // Collect stack traces on addref and removeref, instead of deleting the stack references
320     // on removeref that match the address ones.
321     bool mRetain;
322 
323 #endif
324 };
325 
326 // ---------------------------------------------------------------------------
327 
incStrong(const void * id) const328 void RefBase::incStrong(const void* id) const
329 {
330     weakref_impl* const refs = mRefs;
331     refs->incWeak(id);
332 
333     refs->addStrongRef(id);
334     const int32_t c = android_atomic_inc(&refs->mStrong);
335     LOG_ASSERT(c > 0, "incStrong() called on %p after last strong ref", refs);
336 #if PRINT_REFS
337     LOGD("incStrong of %p from %p: cnt=%d\n", this, id, c);
338 #endif
339     if (c != INITIAL_STRONG_VALUE)  {
340         return;
341     }
342 
343     android_atomic_add(-INITIAL_STRONG_VALUE, &refs->mStrong);
344     refs->mBase->onFirstRef();
345 }
346 
decStrong(const void * id) const347 void RefBase::decStrong(const void* id) const
348 {
349     weakref_impl* const refs = mRefs;
350     refs->removeStrongRef(id);
351     const int32_t c = android_atomic_dec(&refs->mStrong);
352 #if PRINT_REFS
353     LOGD("decStrong of %p from %p: cnt=%d\n", this, id, c);
354 #endif
355     LOG_ASSERT(c >= 1, "decStrong() called on %p too many times", refs);
356     if (c == 1) {
357         refs->mBase->onLastStrongRef(id);
358         if ((refs->mFlags&OBJECT_LIFETIME_MASK) == OBJECT_LIFETIME_STRONG) {
359             delete this;
360         }
361     }
362     refs->decWeak(id);
363 }
364 
forceIncStrong(const void * id) const365 void RefBase::forceIncStrong(const void* id) const
366 {
367     weakref_impl* const refs = mRefs;
368     refs->incWeak(id);
369 
370     refs->addStrongRef(id);
371     const int32_t c = android_atomic_inc(&refs->mStrong);
372     LOG_ASSERT(c >= 0, "forceIncStrong called on %p after ref count underflow",
373                refs);
374 #if PRINT_REFS
375     LOGD("forceIncStrong of %p from %p: cnt=%d\n", this, id, c);
376 #endif
377 
378     switch (c) {
379     case INITIAL_STRONG_VALUE:
380         android_atomic_add(-INITIAL_STRONG_VALUE, &refs->mStrong);
381         // fall through...
382     case 0:
383         refs->mBase->onFirstRef();
384     }
385 }
386 
getStrongCount() const387 int32_t RefBase::getStrongCount() const
388 {
389     return mRefs->mStrong;
390 }
391 
refBase() const392 RefBase* RefBase::weakref_type::refBase() const
393 {
394     return static_cast<const weakref_impl*>(this)->mBase;
395 }
396 
incWeak(const void * id)397 void RefBase::weakref_type::incWeak(const void* id)
398 {
399     weakref_impl* const impl = static_cast<weakref_impl*>(this);
400     impl->addWeakRef(id);
401     const int32_t c = android_atomic_inc(&impl->mWeak);
402     LOG_ASSERT(c >= 0, "incWeak called on %p after last weak ref", this);
403 }
404 
405 
decWeak(const void * id)406 void RefBase::weakref_type::decWeak(const void* id)
407 {
408     weakref_impl* const impl = static_cast<weakref_impl*>(this);
409     impl->removeWeakRef(id);
410     const int32_t c = android_atomic_dec(&impl->mWeak);
411     LOG_ASSERT(c >= 1, "decWeak called on %p too many times", this);
412     if (c != 1) return;
413 
414     if ((impl->mFlags&OBJECT_LIFETIME_WEAK) == OBJECT_LIFETIME_STRONG) {
415         // This is the regular lifetime case. The object is destroyed
416         // when the last strong reference goes away. Since weakref_impl
417         // outlive the object, it is not destroyed in the dtor, and
418         // we'll have to do it here.
419         if (impl->mStrong == INITIAL_STRONG_VALUE) {
420             // Special case: we never had a strong reference, so we need to
421             // destroy the object now.
422             delete impl->mBase;
423         } else {
424             // LOGV("Freeing refs %p of old RefBase %p\n", this, impl->mBase);
425             delete impl;
426         }
427     } else {
428         // less common case: lifetime is OBJECT_LIFETIME_{WEAK|FOREVER}
429         impl->mBase->onLastWeakRef(id);
430         if ((impl->mFlags&OBJECT_LIFETIME_MASK) == OBJECT_LIFETIME_WEAK) {
431             // this is the OBJECT_LIFETIME_WEAK case. The last weak-reference
432             // is gone, we can destroy the object.
433             delete impl->mBase;
434         }
435     }
436 }
437 
attemptIncStrong(const void * id)438 bool RefBase::weakref_type::attemptIncStrong(const void* id)
439 {
440     incWeak(id);
441 
442     weakref_impl* const impl = static_cast<weakref_impl*>(this);
443 
444     int32_t curCount = impl->mStrong;
445     LOG_ASSERT(curCount >= 0, "attemptIncStrong called on %p after underflow",
446                this);
447     while (curCount > 0 && curCount != INITIAL_STRONG_VALUE) {
448         if (android_atomic_cmpxchg(curCount, curCount+1, &impl->mStrong) == 0) {
449             break;
450         }
451         curCount = impl->mStrong;
452     }
453 
454     if (curCount <= 0 || curCount == INITIAL_STRONG_VALUE) {
455         bool allow;
456         if (curCount == INITIAL_STRONG_VALUE) {
457             // Attempting to acquire first strong reference...  this is allowed
458             // if the object does NOT have a longer lifetime (meaning the
459             // implementation doesn't need to see this), or if the implementation
460             // allows it to happen.
461             allow = (impl->mFlags&OBJECT_LIFETIME_WEAK) != OBJECT_LIFETIME_WEAK
462                   || impl->mBase->onIncStrongAttempted(FIRST_INC_STRONG, id);
463         } else {
464             // Attempting to revive the object...  this is allowed
465             // if the object DOES have a longer lifetime (so we can safely
466             // call the object with only a weak ref) and the implementation
467             // allows it to happen.
468             allow = (impl->mFlags&OBJECT_LIFETIME_WEAK) == OBJECT_LIFETIME_WEAK
469                   && impl->mBase->onIncStrongAttempted(FIRST_INC_STRONG, id);
470         }
471         if (!allow) {
472             decWeak(id);
473             return false;
474         }
475         curCount = android_atomic_inc(&impl->mStrong);
476 
477         // If the strong reference count has already been incremented by
478         // someone else, the implementor of onIncStrongAttempted() is holding
479         // an unneeded reference.  So call onLastStrongRef() here to remove it.
480         // (No, this is not pretty.)  Note that we MUST NOT do this if we
481         // are in fact acquiring the first reference.
482         if (curCount > 0 && curCount < INITIAL_STRONG_VALUE) {
483             impl->mBase->onLastStrongRef(id);
484         }
485     }
486 
487     impl->addStrongRef(id);
488 
489 #if PRINT_REFS
490     LOGD("attemptIncStrong of %p from %p: cnt=%d\n", this, id, curCount);
491 #endif
492 
493     if (curCount == INITIAL_STRONG_VALUE) {
494         android_atomic_add(-INITIAL_STRONG_VALUE, &impl->mStrong);
495         impl->mBase->onFirstRef();
496     }
497 
498     return true;
499 }
500 
attemptIncWeak(const void * id)501 bool RefBase::weakref_type::attemptIncWeak(const void* id)
502 {
503     weakref_impl* const impl = static_cast<weakref_impl*>(this);
504 
505     int32_t curCount = impl->mWeak;
506     LOG_ASSERT(curCount >= 0, "attemptIncWeak called on %p after underflow",
507                this);
508     while (curCount > 0) {
509         if (android_atomic_cmpxchg(curCount, curCount+1, &impl->mWeak) == 0) {
510             break;
511         }
512         curCount = impl->mWeak;
513     }
514 
515     if (curCount > 0) {
516         impl->addWeakRef(id);
517     }
518 
519     return curCount > 0;
520 }
521 
getWeakCount() const522 int32_t RefBase::weakref_type::getWeakCount() const
523 {
524     return static_cast<const weakref_impl*>(this)->mWeak;
525 }
526 
printRefs() const527 void RefBase::weakref_type::printRefs() const
528 {
529     static_cast<const weakref_impl*>(this)->printRefs();
530 }
531 
trackMe(bool enable,bool retain)532 void RefBase::weakref_type::trackMe(bool enable, bool retain)
533 {
534     static_cast<weakref_impl*>(this)->trackMe(enable, retain);
535 }
536 
createWeak(const void * id) const537 RefBase::weakref_type* RefBase::createWeak(const void* id) const
538 {
539     mRefs->incWeak(id);
540     return mRefs;
541 }
542 
getWeakRefs() const543 RefBase::weakref_type* RefBase::getWeakRefs() const
544 {
545     return mRefs;
546 }
547 
RefBase()548 RefBase::RefBase()
549     : mRefs(new weakref_impl(this))
550 {
551 }
552 
~RefBase()553 RefBase::~RefBase()
554 {
555     if (mRefs->mStrong == INITIAL_STRONG_VALUE) {
556         // we never acquired a strong (and/or weak) reference on this object.
557         delete mRefs;
558     } else {
559         // life-time of this object is extended to WEAK or FOREVER, in
560         // which case weakref_impl doesn't out-live the object and we
561         // can free it now.
562         if ((mRefs->mFlags & OBJECT_LIFETIME_MASK) != OBJECT_LIFETIME_STRONG) {
563             // It's possible that the weak count is not 0 if the object
564             // re-acquired a weak reference in its destructor
565             if (mRefs->mWeak == 0) {
566                 delete mRefs;
567             }
568         }
569     }
570     // for debugging purposes, clear this.
571     const_cast<weakref_impl*&>(mRefs) = NULL;
572 }
573 
extendObjectLifetime(int32_t mode)574 void RefBase::extendObjectLifetime(int32_t mode)
575 {
576     android_atomic_or(mode, &mRefs->mFlags);
577 }
578 
onFirstRef()579 void RefBase::onFirstRef()
580 {
581 }
582 
onLastStrongRef(const void *)583 void RefBase::onLastStrongRef(const void* /*id*/)
584 {
585 }
586 
onIncStrongAttempted(uint32_t flags,const void * id)587 bool RefBase::onIncStrongAttempted(uint32_t flags, const void* id)
588 {
589     return (flags&FIRST_INC_STRONG) ? true : false;
590 }
591 
onLastWeakRef(const void *)592 void RefBase::onLastWeakRef(const void* /*id*/)
593 {
594 }
595 
596 // ---------------------------------------------------------------------------
597 
moveReferences(void * dst,void const * src,size_t n,const ReferenceConverterBase & caster)598 void RefBase::moveReferences(void* dst, void const* src, size_t n,
599         const ReferenceConverterBase& caster)
600 {
601 #if DEBUG_REFS
602     const size_t itemSize = caster.getReferenceTypeSize();
603     for (size_t i=0 ; i<n ; i++) {
604         void*       d = reinterpret_cast<void      *>(intptr_t(dst) + i*itemSize);
605         void const* s = reinterpret_cast<void const*>(intptr_t(src) + i*itemSize);
606         RefBase* ref(reinterpret_cast<RefBase*>(caster.getReferenceBase(d)));
607         ref->mRefs->renameStrongRefId(s, d);
608         ref->mRefs->renameWeakRefId(s, d);
609     }
610 #endif
611 }
612 
613 // ---------------------------------------------------------------------------
614 
printStrongPointer(TextOutput & to,const void * val)615 TextOutput& printStrongPointer(TextOutput& to, const void* val)
616 {
617     to << "sp<>(" << val << ")";
618     return to;
619 }
620 
printWeakPointer(TextOutput & to,const void * val)621 TextOutput& printWeakPointer(TextOutput& to, const void* val)
622 {
623     to << "wp<>(" << val << ")";
624     return to;
625 }
626 
627 
628 }; // namespace android
629