• 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/KeyedVector.h>
24 #include <utils/Log.h>
25 #include <utils/threads.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_ENABLED_BY_DEFAULT   1
38 #define DEBUG_REFS_CALLSTACK_ENABLED    1
39 
40 // log all reference counting operations
41 #define PRINT_REFS                      0
42 
43 // ---------------------------------------------------------------------------
44 
45 namespace android {
46 
47 #define INITIAL_STRONG_VALUE (1<<28)
48 
49 // ---------------------------------------------------------------------------
50 
~Destroyer()51 RefBase::Destroyer::~Destroyer() {
52 }
53 
54 // ---------------------------------------------------------------------------
55 
56 class RefBase::weakref_impl : public RefBase::weakref_type
57 {
58 public:
59     volatile int32_t    mStrong;
60     volatile int32_t    mWeak;
61     RefBase* const      mBase;
62     volatile int32_t    mFlags;
63     Destroyer*          mDestroyer;
64 
65 #if !DEBUG_REFS
66 
weakref_impl(RefBase * base)67     weakref_impl(RefBase* base)
68         : mStrong(INITIAL_STRONG_VALUE)
69         , mWeak(0)
70         , mBase(base)
71         , mFlags(0)
72         , mDestroyer(0)
73     {
74     }
75 
addStrongRef(const void *)76     void addStrongRef(const void* /*id*/) { }
removeStrongRef(const void *)77     void removeStrongRef(const void* /*id*/) { }
addWeakRef(const void *)78     void addWeakRef(const void* /*id*/) { }
removeWeakRef(const void *)79     void removeWeakRef(const void* /*id*/) { }
printRefs() const80     void printRefs() const { }
trackMe(bool,bool)81     void trackMe(bool, bool) { }
82 
83 #else
84 
weakref_impl(RefBase * base)85     weakref_impl(RefBase* base)
86         : mStrong(INITIAL_STRONG_VALUE)
87         , mWeak(0)
88         , mBase(base)
89         , mFlags(0)
90         , mStrongRefs(NULL)
91         , mWeakRefs(NULL)
92         , mTrackEnabled(!!DEBUG_REFS_ENABLED_BY_DEFAULT)
93         , mRetain(false)
94     {
95         //LOGI("NEW weakref_impl %p for RefBase %p", this, base);
96     }
97 
~weakref_impl()98     ~weakref_impl()
99     {
100         LOG_ALWAYS_FATAL_IF(!mRetain && mStrongRefs != NULL, "Strong references remain!");
101         LOG_ALWAYS_FATAL_IF(!mRetain && mWeakRefs != NULL, "Weak references remain!");
102     }
103 
addStrongRef(const void * id)104     void addStrongRef(const void* id)
105     {
106         addRef(&mStrongRefs, id, mStrong);
107     }
108 
removeStrongRef(const void * id)109     void removeStrongRef(const void* id)
110     {
111         if (!mRetain)
112             removeRef(&mStrongRefs, id);
113         else
114             addRef(&mStrongRefs, id, -mStrong);
115     }
116 
addWeakRef(const void * id)117     void addWeakRef(const void* id)
118     {
119         addRef(&mWeakRefs, id, mWeak);
120     }
121 
removeWeakRef(const void * id)122     void removeWeakRef(const void* id)
123     {
124         if (!mRetain)
125             removeRef(&mWeakRefs, id);
126         else
127             addRef(&mWeakRefs, id, -mWeak);
128     }
129 
trackMe(bool track,bool retain)130     void trackMe(bool track, bool retain)
131     {
132         mTrackEnabled = track;
133         mRetain = retain;
134     }
135 
printRefs() const136     void printRefs() const
137     {
138         String8 text;
139 
140         {
141             AutoMutex _l(const_cast<weakref_impl*>(this)->mMutex);
142 
143             char buf[128];
144             sprintf(buf, "Strong references on RefBase %p (weakref_type %p):\n", mBase, this);
145             text.append(buf);
146             printRefsLocked(&text, mStrongRefs);
147             sprintf(buf, "Weak references on RefBase %p (weakref_type %p):\n", mBase, this);
148             text.append(buf);
149             printRefsLocked(&text, mWeakRefs);
150         }
151 
152         {
153             char name[100];
154             snprintf(name, 100, "/data/%p.stack", this);
155             int rc = open(name, O_RDWR | O_CREAT | O_APPEND);
156             if (rc >= 0) {
157                 write(rc, text.string(), text.length());
158                 close(rc);
159                 LOGD("STACK TRACE for %p saved in %s", this, name);
160             }
161             else LOGE("FAILED TO PRINT STACK TRACE for %p in %s: %s", this,
162                       name, strerror(errno));
163         }
164     }
165 
166 private:
167     struct ref_entry
168     {
169         ref_entry* next;
170         const void* id;
171 #if DEBUG_REFS_CALLSTACK_ENABLED
172         CallStack stack;
173 #endif
174         int32_t ref;
175     };
176 
addRef(ref_entry ** refs,const void * id,int32_t mRef)177     void addRef(ref_entry** refs, const void* id, int32_t mRef)
178     {
179         if (mTrackEnabled) {
180             AutoMutex _l(mMutex);
181             ref_entry* ref = new ref_entry;
182             // Reference count at the time of the snapshot, but before the
183             // update.  Positive value means we increment, negative--we
184             // decrement the reference count.
185             ref->ref = mRef;
186             ref->id = id;
187 #if DEBUG_REFS_CALLSTACK_ENABLED
188             ref->stack.update(2);
189 #endif
190 
191             ref->next = *refs;
192             *refs = ref;
193         }
194     }
195 
removeRef(ref_entry ** refs,const void * id)196     void removeRef(ref_entry** refs, const void* id)
197     {
198         if (mTrackEnabled) {
199             AutoMutex _l(mMutex);
200 
201             ref_entry* ref = *refs;
202             while (ref != NULL) {
203                 if (ref->id == id) {
204                     *refs = ref->next;
205                     delete ref;
206                     return;
207                 }
208 
209                 refs = &ref->next;
210                 ref = *refs;
211             }
212 
213             LOG_ALWAYS_FATAL("RefBase: removing id %p on RefBase %p (weakref_type %p) that doesn't exist!",
214                              id, mBase, this);
215         }
216     }
217 
printRefsLocked(String8 * out,const ref_entry * refs) const218     void printRefsLocked(String8* out, const ref_entry* refs) const
219     {
220         char buf[128];
221         while (refs) {
222             char inc = refs->ref >= 0 ? '+' : '-';
223             sprintf(buf, "\t%c ID %p (ref %d):\n",
224                     inc, refs->id, refs->ref);
225             out->append(buf);
226 #if DEBUG_REFS_CALLSTACK_ENABLED
227             out->append(refs->stack.toString("\t\t"));
228 #else
229             out->append("\t\t(call stacks disabled)");
230 #endif
231             refs = refs->next;
232         }
233     }
234 
235     Mutex mMutex;
236     ref_entry* mStrongRefs;
237     ref_entry* mWeakRefs;
238 
239     bool mTrackEnabled;
240     // Collect stack traces on addref and removeref, instead of deleting the stack references
241     // on removeref that match the address ones.
242     bool mRetain;
243 
244 #if 0
245     void addRef(KeyedVector<const void*, int32_t>* refs, const void* id)
246     {
247         AutoMutex _l(mMutex);
248         ssize_t i = refs->indexOfKey(id);
249         if (i >= 0) {
250             ++(refs->editValueAt(i));
251         } else {
252             i = refs->add(id, 1);
253         }
254     }
255 
256     void removeRef(KeyedVector<const void*, int32_t>* refs, const void* id)
257     {
258         AutoMutex _l(mMutex);
259         ssize_t i = refs->indexOfKey(id);
260         LOG_ALWAYS_FATAL_IF(i < 0, "RefBase: removing id %p that doesn't exist!", id);
261         if (i >= 0) {
262             int32_t val = --(refs->editValueAt(i));
263             if (val == 0) {
264                 refs->removeItemsAt(i);
265             }
266         }
267     }
268 
269     void printRefs(const KeyedVector<const void*, int32_t>& refs)
270     {
271         const size_t N=refs.size();
272         for (size_t i=0; i<N; i++) {
273             printf("\tID %p: %d remain\n", refs.keyAt(i), refs.valueAt(i));
274         }
275     }
276 
277     mutable Mutex mMutex;
278     KeyedVector<const void*, int32_t> mStrongRefs;
279     KeyedVector<const void*, int32_t> mWeakRefs;
280 #endif
281 
282 #endif
283 };
284 
285 // ---------------------------------------------------------------------------
286 
incStrong(const void * id) const287 void RefBase::incStrong(const void* id) const
288 {
289     weakref_impl* const refs = mRefs;
290     refs->addWeakRef(id);
291     refs->incWeak(id);
292 
293     refs->addStrongRef(id);
294     const int32_t c = android_atomic_inc(&refs->mStrong);
295     LOG_ASSERT(c > 0, "incStrong() called on %p after last strong ref", refs);
296 #if PRINT_REFS
297     LOGD("incStrong of %p from %p: cnt=%d\n", this, id, c);
298 #endif
299     if (c != INITIAL_STRONG_VALUE)  {
300         return;
301     }
302 
303     android_atomic_add(-INITIAL_STRONG_VALUE, &refs->mStrong);
304     const_cast<RefBase*>(this)->onFirstRef();
305 }
306 
decStrong(const void * id) const307 void RefBase::decStrong(const void* id) const
308 {
309     weakref_impl* const refs = mRefs;
310     refs->removeStrongRef(id);
311     const int32_t c = android_atomic_dec(&refs->mStrong);
312 #if PRINT_REFS
313     LOGD("decStrong of %p from %p: cnt=%d\n", this, id, c);
314 #endif
315     LOG_ASSERT(c >= 1, "decStrong() called on %p too many times", refs);
316     if (c == 1) {
317         const_cast<RefBase*>(this)->onLastStrongRef(id);
318         if ((refs->mFlags&OBJECT_LIFETIME_WEAK) != OBJECT_LIFETIME_WEAK) {
319             if (refs->mDestroyer) {
320                 refs->mDestroyer->destroy(this);
321             } else {
322                 delete this;
323             }
324         }
325     }
326     refs->removeWeakRef(id);
327     refs->decWeak(id);
328 }
329 
forceIncStrong(const void * id) const330 void RefBase::forceIncStrong(const void* id) const
331 {
332     weakref_impl* const refs = mRefs;
333     refs->addWeakRef(id);
334     refs->incWeak(id);
335 
336     refs->addStrongRef(id);
337     const int32_t c = android_atomic_inc(&refs->mStrong);
338     LOG_ASSERT(c >= 0, "forceIncStrong called on %p after ref count underflow",
339                refs);
340 #if PRINT_REFS
341     LOGD("forceIncStrong of %p from %p: cnt=%d\n", this, id, c);
342 #endif
343 
344     switch (c) {
345     case INITIAL_STRONG_VALUE:
346         android_atomic_add(-INITIAL_STRONG_VALUE, &refs->mStrong);
347         // fall through...
348     case 0:
349         const_cast<RefBase*>(this)->onFirstRef();
350     }
351 }
352 
getStrongCount() const353 int32_t RefBase::getStrongCount() const
354 {
355     return mRefs->mStrong;
356 }
357 
setDestroyer(RefBase::Destroyer * destroyer)358 void RefBase::setDestroyer(RefBase::Destroyer* destroyer) {
359     mRefs->mDestroyer = destroyer;
360 }
361 
refBase() const362 RefBase* RefBase::weakref_type::refBase() const
363 {
364     return static_cast<const weakref_impl*>(this)->mBase;
365 }
366 
incWeak(const void * id)367 void RefBase::weakref_type::incWeak(const void* id)
368 {
369     weakref_impl* const impl = static_cast<weakref_impl*>(this);
370     impl->addWeakRef(id);
371     const int32_t c = android_atomic_inc(&impl->mWeak);
372     LOG_ASSERT(c >= 0, "incWeak called on %p after last weak ref", this);
373 }
374 
decWeak(const void * id)375 void RefBase::weakref_type::decWeak(const void* id)
376 {
377     weakref_impl* const impl = static_cast<weakref_impl*>(this);
378     impl->removeWeakRef(id);
379     const int32_t c = android_atomic_dec(&impl->mWeak);
380     LOG_ASSERT(c >= 1, "decWeak called on %p too many times", this);
381     if (c != 1) return;
382 
383     if ((impl->mFlags&OBJECT_LIFETIME_WEAK) != OBJECT_LIFETIME_WEAK) {
384         if (impl->mStrong == INITIAL_STRONG_VALUE) {
385             if (impl->mBase) {
386                 if (impl->mDestroyer) {
387                     impl->mDestroyer->destroy(impl->mBase);
388                 } else {
389                     delete impl->mBase;
390                 }
391             }
392         } else {
393             // LOGV("Freeing refs %p of old RefBase %p\n", this, impl->mBase);
394             delete impl;
395         }
396     } else {
397         impl->mBase->onLastWeakRef(id);
398         if ((impl->mFlags&OBJECT_LIFETIME_FOREVER) != OBJECT_LIFETIME_FOREVER) {
399             if (impl->mBase) {
400                 if (impl->mDestroyer) {
401                     impl->mDestroyer->destroy(impl->mBase);
402                 } else {
403                     delete impl->mBase;
404                 }
405             }
406         }
407     }
408 }
409 
attemptIncStrong(const void * id)410 bool RefBase::weakref_type::attemptIncStrong(const void* id)
411 {
412     incWeak(id);
413 
414     weakref_impl* const impl = static_cast<weakref_impl*>(this);
415 
416     int32_t curCount = impl->mStrong;
417     LOG_ASSERT(curCount >= 0, "attemptIncStrong called on %p after underflow",
418                this);
419     while (curCount > 0 && curCount != INITIAL_STRONG_VALUE) {
420         if (android_atomic_cmpxchg(curCount, curCount+1, &impl->mStrong) == 0) {
421             break;
422         }
423         curCount = impl->mStrong;
424     }
425 
426     if (curCount <= 0 || curCount == INITIAL_STRONG_VALUE) {
427         bool allow;
428         if (curCount == INITIAL_STRONG_VALUE) {
429             // Attempting to acquire first strong reference...  this is allowed
430             // if the object does NOT have a longer lifetime (meaning the
431             // implementation doesn't need to see this), or if the implementation
432             // allows it to happen.
433             allow = (impl->mFlags&OBJECT_LIFETIME_WEAK) != OBJECT_LIFETIME_WEAK
434                   || impl->mBase->onIncStrongAttempted(FIRST_INC_STRONG, id);
435         } else {
436             // Attempting to revive the object...  this is allowed
437             // if the object DOES have a longer lifetime (so we can safely
438             // call the object with only a weak ref) and the implementation
439             // allows it to happen.
440             allow = (impl->mFlags&OBJECT_LIFETIME_WEAK) == OBJECT_LIFETIME_WEAK
441                   && impl->mBase->onIncStrongAttempted(FIRST_INC_STRONG, id);
442         }
443         if (!allow) {
444             decWeak(id);
445             return false;
446         }
447         curCount = android_atomic_inc(&impl->mStrong);
448 
449         // If the strong reference count has already been incremented by
450         // someone else, the implementor of onIncStrongAttempted() is holding
451         // an unneeded reference.  So call onLastStrongRef() here to remove it.
452         // (No, this is not pretty.)  Note that we MUST NOT do this if we
453         // are in fact acquiring the first reference.
454         if (curCount > 0 && curCount < INITIAL_STRONG_VALUE) {
455             impl->mBase->onLastStrongRef(id);
456         }
457     }
458 
459     impl->addWeakRef(id);
460     impl->addStrongRef(id);
461 
462 #if PRINT_REFS
463     LOGD("attemptIncStrong of %p from %p: cnt=%d\n", this, id, curCount);
464 #endif
465 
466     if (curCount == INITIAL_STRONG_VALUE) {
467         android_atomic_add(-INITIAL_STRONG_VALUE, &impl->mStrong);
468         impl->mBase->onFirstRef();
469     }
470 
471     return true;
472 }
473 
attemptIncWeak(const void * id)474 bool RefBase::weakref_type::attemptIncWeak(const void* id)
475 {
476     weakref_impl* const impl = static_cast<weakref_impl*>(this);
477 
478     int32_t curCount = impl->mWeak;
479     LOG_ASSERT(curCount >= 0, "attemptIncWeak called on %p after underflow",
480                this);
481     while (curCount > 0) {
482         if (android_atomic_cmpxchg(curCount, curCount+1, &impl->mWeak) == 0) {
483             break;
484         }
485         curCount = impl->mWeak;
486     }
487 
488     if (curCount > 0) {
489         impl->addWeakRef(id);
490     }
491 
492     return curCount > 0;
493 }
494 
getWeakCount() const495 int32_t RefBase::weakref_type::getWeakCount() const
496 {
497     return static_cast<const weakref_impl*>(this)->mWeak;
498 }
499 
printRefs() const500 void RefBase::weakref_type::printRefs() const
501 {
502     static_cast<const weakref_impl*>(this)->printRefs();
503 }
504 
trackMe(bool enable,bool retain)505 void RefBase::weakref_type::trackMe(bool enable, bool retain)
506 {
507     static_cast<const weakref_impl*>(this)->trackMe(enable, retain);
508 }
509 
createWeak(const void * id) const510 RefBase::weakref_type* RefBase::createWeak(const void* id) const
511 {
512     mRefs->incWeak(id);
513     return mRefs;
514 }
515 
getWeakRefs() const516 RefBase::weakref_type* RefBase::getWeakRefs() const
517 {
518     return mRefs;
519 }
520 
RefBase()521 RefBase::RefBase()
522     : mRefs(new weakref_impl(this))
523 {
524 //    LOGV("Creating refs %p with RefBase %p\n", mRefs, this);
525 }
526 
~RefBase()527 RefBase::~RefBase()
528 {
529     if ((mRefs->mFlags & OBJECT_LIFETIME_WEAK) == OBJECT_LIFETIME_WEAK) {
530         if (mRefs->mWeak == 0) {
531             delete mRefs;
532         }
533     }
534 }
535 
extendObjectLifetime(int32_t mode)536 void RefBase::extendObjectLifetime(int32_t mode)
537 {
538     android_atomic_or(mode, &mRefs->mFlags);
539 }
540 
onFirstRef()541 void RefBase::onFirstRef()
542 {
543 }
544 
onLastStrongRef(const void *)545 void RefBase::onLastStrongRef(const void* /*id*/)
546 {
547 }
548 
onIncStrongAttempted(uint32_t flags,const void * id)549 bool RefBase::onIncStrongAttempted(uint32_t flags, const void* id)
550 {
551     return (flags&FIRST_INC_STRONG) ? true : false;
552 }
553 
onLastWeakRef(const void *)554 void RefBase::onLastWeakRef(const void* /*id*/)
555 {
556 }
557 
558 }; // namespace android
559