blob: 0fd404d66c1ed86a3566ff7a4c774d78dccf8493 [file] [log] [blame]
The Android Open Source Projectcbb10112009-03-03 19:31:44 -08001/*
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>
The Android Open Source Projectcbb10112009-03-03 19:31:44 -080023#include <utils/Log.h>
24#include <utils/threads.h>
Mathias Agopian84a23fa2011-02-16 15:23:08 -080025#include <utils/TextOutput.h>
The Android Open Source Projectcbb10112009-03-03 19:31:44 -080026
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
Mathias Agopianb26ea8b2011-02-16 20:23:43 -080037#define DEBUG_REFS_FATAL_SANITY_CHECKS 0
The Android Open Source Projectcbb10112009-03-03 19:31:44 -080038#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
46namespace android {
47
48#define INITIAL_STRONG_VALUE (1<<28)
49
50// ---------------------------------------------------------------------------
51
52class RefBase::weakref_impl : public RefBase::weakref_type
53{
54public:
55 volatile int32_t mStrong;
56 volatile int32_t mWeak;
57 RefBase* const mBase;
58 volatile int32_t mFlags;
59
60
61#if !DEBUG_REFS
62
63 weakref_impl(RefBase* base)
64 : mStrong(INITIAL_STRONG_VALUE)
65 , mWeak(0)
66 , mBase(base)
67 , mFlags(0)
68 {
69 }
70
71 void addStrongRef(const void* /*id*/) { }
72 void removeStrongRef(const void* /*id*/) { }
Mathias Agopianb26ea8b2011-02-16 20:23:43 -080073 void renameStrongRefId(const void* /*old_id*/, const void* /*new_id*/) { }
The Android Open Source Projectcbb10112009-03-03 19:31:44 -080074 void addWeakRef(const void* /*id*/) { }
75 void removeWeakRef(const void* /*id*/) { }
Mathias Agopianb26ea8b2011-02-16 20:23:43 -080076 void renameWeakRefId(const void* /*old_id*/, const void* /*new_id*/) { }
The Android Open Source Projectcbb10112009-03-03 19:31:44 -080077 void printRefs() const { }
78 void trackMe(bool, bool) { }
79
80#else
81
82 weakref_impl(RefBase* base)
83 : mStrong(INITIAL_STRONG_VALUE)
84 , mWeak(0)
85 , mBase(base)
86 , mFlags(0)
87 , mStrongRefs(NULL)
88 , mWeakRefs(NULL)
89 , mTrackEnabled(!!DEBUG_REFS_ENABLED_BY_DEFAULT)
90 , mRetain(false)
91 {
The Android Open Source Projectcbb10112009-03-03 19:31:44 -080092 }
93
94 ~weakref_impl()
95 {
Mathias Agopianb26ea8b2011-02-16 20:23:43 -080096 bool dumpStack = false;
97 if (!mRetain && mStrongRefs != NULL) {
98 dumpStack = true;
99#if DEBUG_REFS_FATAL_SANITY_CHECKS
100 LOG_ALWAYS_FATAL("Strong references remain!");
101#else
102 LOGE("Strong references remain!");
103#endif
104 }
105
106 if (!mRetain && mWeakRefs != NULL) {
107 dumpStack = true;
108#if DEBUG_REFS_FATAL_SANITY_CHECKS
109 LOG_ALWAYS_FATAL("Weak references remain!");
110#else
111 LOGE("Weak references remain!");
112#endif
113 }
114
115 if (dumpStack) {
116 CallStack stack;
117 stack.update();
118 stack.dump();
119 }
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800120 }
121
Mathias Agopianb26ea8b2011-02-16 20:23:43 -0800122 void addStrongRef(const void* id) {
123 //LOGD_IF(mTrackEnabled,
124 // "addStrongRef: RefBase=%p, id=%p", mBase, id);
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800125 addRef(&mStrongRefs, id, mStrong);
126 }
127
Mathias Agopianb26ea8b2011-02-16 20:23:43 -0800128 void removeStrongRef(const void* id) {
129 //LOGD_IF(mTrackEnabled,
130 // "removeStrongRef: RefBase=%p, id=%p", mBase, id);
131 if (!mRetain) {
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800132 removeRef(&mStrongRefs, id);
Mathias Agopianb26ea8b2011-02-16 20:23:43 -0800133 } else {
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800134 addRef(&mStrongRefs, id, -mStrong);
Mathias Agopianb26ea8b2011-02-16 20:23:43 -0800135 }
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800136 }
137
Mathias Agopianb26ea8b2011-02-16 20:23:43 -0800138 void renameStrongRefId(const void* old_id, const void* new_id) {
139 //LOGD_IF(mTrackEnabled,
140 // "renameStrongRefId: RefBase=%p, oid=%p, nid=%p",
141 // mBase, old_id, new_id);
142 renameRefsId(mStrongRefs, old_id, new_id);
143 }
144
145 void addWeakRef(const void* id) {
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800146 addRef(&mWeakRefs, id, mWeak);
147 }
148
Mathias Agopianb26ea8b2011-02-16 20:23:43 -0800149 void removeWeakRef(const void* id) {
150 if (!mRetain) {
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800151 removeRef(&mWeakRefs, id);
Mathias Agopianb26ea8b2011-02-16 20:23:43 -0800152 } else {
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800153 addRef(&mWeakRefs, id, -mWeak);
Mathias Agopianb26ea8b2011-02-16 20:23:43 -0800154 }
155 }
156
157 void renameWeakRefId(const void* old_id, const void* new_id) {
158 renameRefsId(mWeakRefs, old_id, new_id);
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800159 }
160
161 void trackMe(bool track, bool retain)
162 {
163 mTrackEnabled = track;
164 mRetain = retain;
165 }
166
167 void printRefs() const
168 {
169 String8 text;
170
171 {
Mathias Agopianb26ea8b2011-02-16 20:23:43 -0800172 Mutex::Autolock _l(const_cast<weakref_impl*>(this)->mMutex);
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800173 char buf[128];
174 sprintf(buf, "Strong references on RefBase %p (weakref_type %p):\n", mBase, this);
175 text.append(buf);
176 printRefsLocked(&text, mStrongRefs);
177 sprintf(buf, "Weak references on RefBase %p (weakref_type %p):\n", mBase, this);
178 text.append(buf);
179 printRefsLocked(&text, mWeakRefs);
180 }
181
182 {
183 char name[100];
184 snprintf(name, 100, "/data/%p.stack", this);
185 int rc = open(name, O_RDWR | O_CREAT | O_APPEND);
186 if (rc >= 0) {
187 write(rc, text.string(), text.length());
188 close(rc);
189 LOGD("STACK TRACE for %p saved in %s", this, name);
190 }
191 else LOGE("FAILED TO PRINT STACK TRACE for %p in %s: %s", this,
192 name, strerror(errno));
193 }
194 }
195
196private:
197 struct ref_entry
198 {
199 ref_entry* next;
200 const void* id;
201#if DEBUG_REFS_CALLSTACK_ENABLED
202 CallStack stack;
203#endif
204 int32_t ref;
205 };
206
207 void addRef(ref_entry** refs, const void* id, int32_t mRef)
208 {
209 if (mTrackEnabled) {
210 AutoMutex _l(mMutex);
Mathias Agopianb26ea8b2011-02-16 20:23:43 -0800211
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800212 ref_entry* ref = new ref_entry;
213 // Reference count at the time of the snapshot, but before the
214 // update. Positive value means we increment, negative--we
215 // decrement the reference count.
216 ref->ref = mRef;
217 ref->id = id;
218#if DEBUG_REFS_CALLSTACK_ENABLED
219 ref->stack.update(2);
220#endif
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800221 ref->next = *refs;
222 *refs = ref;
223 }
224 }
225
226 void removeRef(ref_entry** refs, const void* id)
227 {
228 if (mTrackEnabled) {
229 AutoMutex _l(mMutex);
230
231 ref_entry* ref = *refs;
232 while (ref != NULL) {
233 if (ref->id == id) {
234 *refs = ref->next;
235 delete ref;
236 return;
237 }
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800238 refs = &ref->next;
239 ref = *refs;
240 }
Mathias Agopianb26ea8b2011-02-16 20:23:43 -0800241
242#if DEBUG_REFS_FATAL_SANITY_CHECKS
243 LOG_ALWAYS_FATAL("RefBase: removing id %p on RefBase %p"
244 "(weakref_type %p) that doesn't exist!",
245 id, mBase, this);
246#endif
247
248 LOGE("RefBase: removing id %p on RefBase %p"
249 "(weakref_type %p) that doesn't exist!",
250 id, mBase, this);
251
252 CallStack stack;
253 stack.update();
254 stack.dump();
255 }
256 }
257
258 void renameRefsId(ref_entry* r, const void* old_id, const void* new_id)
259 {
260 if (mTrackEnabled) {
261 AutoMutex _l(mMutex);
262 ref_entry* ref = r;
263 while (ref != NULL) {
264 if (ref->id == old_id) {
265 ref->id = new_id;
266 }
267 ref = ref->next;
268 }
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800269 }
270 }
271
272 void printRefsLocked(String8* out, const ref_entry* refs) const
273 {
274 char buf[128];
275 while (refs) {
276 char inc = refs->ref >= 0 ? '+' : '-';
277 sprintf(buf, "\t%c ID %p (ref %d):\n",
278 inc, refs->id, refs->ref);
279 out->append(buf);
280#if DEBUG_REFS_CALLSTACK_ENABLED
281 out->append(refs->stack.toString("\t\t"));
282#else
283 out->append("\t\t(call stacks disabled)");
284#endif
285 refs = refs->next;
286 }
287 }
288
289 Mutex mMutex;
290 ref_entry* mStrongRefs;
291 ref_entry* mWeakRefs;
292
293 bool mTrackEnabled;
294 // Collect stack traces on addref and removeref, instead of deleting the stack references
295 // on removeref that match the address ones.
296 bool mRetain;
297
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800298#endif
299};
300
301// ---------------------------------------------------------------------------
302
303void RefBase::incStrong(const void* id) const
304{
305 weakref_impl* const refs = mRefs;
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800306 refs->incWeak(id);
307
308 refs->addStrongRef(id);
309 const int32_t c = android_atomic_inc(&refs->mStrong);
310 LOG_ASSERT(c > 0, "incStrong() called on %p after last strong ref", refs);
311#if PRINT_REFS
312 LOGD("incStrong of %p from %p: cnt=%d\n", this, id, c);
313#endif
314 if (c != INITIAL_STRONG_VALUE) {
315 return;
316 }
317
318 android_atomic_add(-INITIAL_STRONG_VALUE, &refs->mStrong);
319 const_cast<RefBase*>(this)->onFirstRef();
320}
321
322void RefBase::decStrong(const void* id) const
323{
324 weakref_impl* const refs = mRefs;
325 refs->removeStrongRef(id);
326 const int32_t c = android_atomic_dec(&refs->mStrong);
327#if PRINT_REFS
328 LOGD("decStrong of %p from %p: cnt=%d\n", this, id, c);
329#endif
330 LOG_ASSERT(c >= 1, "decStrong() called on %p too many times", refs);
331 if (c == 1) {
332 const_cast<RefBase*>(this)->onLastStrongRef(id);
333 if ((refs->mFlags&OBJECT_LIFETIME_WEAK) != OBJECT_LIFETIME_WEAK) {
334 delete this;
335 }
336 }
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800337 refs->decWeak(id);
338}
339
340void RefBase::forceIncStrong(const void* id) const
341{
342 weakref_impl* const refs = mRefs;
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800343 refs->incWeak(id);
344
345 refs->addStrongRef(id);
346 const int32_t c = android_atomic_inc(&refs->mStrong);
347 LOG_ASSERT(c >= 0, "forceIncStrong called on %p after ref count underflow",
348 refs);
349#if PRINT_REFS
350 LOGD("forceIncStrong of %p from %p: cnt=%d\n", this, id, c);
351#endif
352
353 switch (c) {
354 case INITIAL_STRONG_VALUE:
355 android_atomic_add(-INITIAL_STRONG_VALUE, &refs->mStrong);
356 // fall through...
357 case 0:
358 const_cast<RefBase*>(this)->onFirstRef();
359 }
360}
361
362int32_t RefBase::getStrongCount() const
363{
364 return mRefs->mStrong;
365}
366
367
368
369RefBase* RefBase::weakref_type::refBase() const
370{
371 return static_cast<const weakref_impl*>(this)->mBase;
372}
373
374void RefBase::weakref_type::incWeak(const void* id)
375{
376 weakref_impl* const impl = static_cast<weakref_impl*>(this);
377 impl->addWeakRef(id);
378 const int32_t c = android_atomic_inc(&impl->mWeak);
379 LOG_ASSERT(c >= 0, "incWeak called on %p after last weak ref", this);
380}
381
382void RefBase::weakref_type::decWeak(const void* id)
383{
384 weakref_impl* const impl = static_cast<weakref_impl*>(this);
385 impl->removeWeakRef(id);
386 const int32_t c = android_atomic_dec(&impl->mWeak);
387 LOG_ASSERT(c >= 1, "decWeak called on %p too many times", this);
388 if (c != 1) return;
389
390 if ((impl->mFlags&OBJECT_LIFETIME_WEAK) != OBJECT_LIFETIME_WEAK) {
391 if (impl->mStrong == INITIAL_STRONG_VALUE)
392 delete impl->mBase;
393 else {
Mathias Agopianb26ea8b2011-02-16 20:23:43 -0800394 // LOGV("Freeing refs %p of old RefBase %p\n", this, impl->mBase);
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800395 delete impl;
396 }
397 } else {
398 impl->mBase->onLastWeakRef(id);
399 if ((impl->mFlags&OBJECT_LIFETIME_FOREVER) != OBJECT_LIFETIME_FOREVER) {
400 delete impl->mBase;
401 }
402 }
403}
404
405bool RefBase::weakref_type::attemptIncStrong(const void* id)
406{
407 incWeak(id);
408
409 weakref_impl* const impl = static_cast<weakref_impl*>(this);
410
411 int32_t curCount = impl->mStrong;
412 LOG_ASSERT(curCount >= 0, "attemptIncStrong called on %p after underflow",
413 this);
414 while (curCount > 0 && curCount != INITIAL_STRONG_VALUE) {
415 if (android_atomic_cmpxchg(curCount, curCount+1, &impl->mStrong) == 0) {
416 break;
417 }
418 curCount = impl->mStrong;
419 }
420
421 if (curCount <= 0 || curCount == INITIAL_STRONG_VALUE) {
422 bool allow;
423 if (curCount == INITIAL_STRONG_VALUE) {
424 // Attempting to acquire first strong reference... this is allowed
425 // if the object does NOT have a longer lifetime (meaning the
426 // implementation doesn't need to see this), or if the implementation
427 // allows it to happen.
428 allow = (impl->mFlags&OBJECT_LIFETIME_WEAK) != OBJECT_LIFETIME_WEAK
429 || impl->mBase->onIncStrongAttempted(FIRST_INC_STRONG, id);
430 } else {
431 // Attempting to revive the object... this is allowed
432 // if the object DOES have a longer lifetime (so we can safely
433 // call the object with only a weak ref) and the implementation
434 // allows it to happen.
435 allow = (impl->mFlags&OBJECT_LIFETIME_WEAK) == OBJECT_LIFETIME_WEAK
436 && impl->mBase->onIncStrongAttempted(FIRST_INC_STRONG, id);
437 }
438 if (!allow) {
439 decWeak(id);
440 return false;
441 }
442 curCount = android_atomic_inc(&impl->mStrong);
443
444 // If the strong reference count has already been incremented by
445 // someone else, the implementor of onIncStrongAttempted() is holding
446 // an unneeded reference. So call onLastStrongRef() here to remove it.
447 // (No, this is not pretty.) Note that we MUST NOT do this if we
448 // are in fact acquiring the first reference.
449 if (curCount > 0 && curCount < INITIAL_STRONG_VALUE) {
450 impl->mBase->onLastStrongRef(id);
451 }
452 }
453
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800454 impl->addStrongRef(id);
455
456#if PRINT_REFS
457 LOGD("attemptIncStrong of %p from %p: cnt=%d\n", this, id, curCount);
458#endif
459
460 if (curCount == INITIAL_STRONG_VALUE) {
461 android_atomic_add(-INITIAL_STRONG_VALUE, &impl->mStrong);
462 impl->mBase->onFirstRef();
463 }
464
465 return true;
466}
467
468bool RefBase::weakref_type::attemptIncWeak(const void* id)
469{
470 weakref_impl* const impl = static_cast<weakref_impl*>(this);
Mathias Agopianb26ea8b2011-02-16 20:23:43 -0800471
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800472 int32_t curCount = impl->mWeak;
473 LOG_ASSERT(curCount >= 0, "attemptIncWeak called on %p after underflow",
474 this);
475 while (curCount > 0) {
476 if (android_atomic_cmpxchg(curCount, curCount+1, &impl->mWeak) == 0) {
477 break;
478 }
479 curCount = impl->mWeak;
480 }
481
482 if (curCount > 0) {
483 impl->addWeakRef(id);
484 }
485
486 return curCount > 0;
487}
488
489int32_t RefBase::weakref_type::getWeakCount() const
490{
491 return static_cast<const weakref_impl*>(this)->mWeak;
492}
493
494void RefBase::weakref_type::printRefs() const
495{
496 static_cast<const weakref_impl*>(this)->printRefs();
497}
498
499void RefBase::weakref_type::trackMe(bool enable, bool retain)
500{
501 static_cast<const weakref_impl*>(this)->trackMe(enable, retain);
502}
503
504RefBase::weakref_type* RefBase::createWeak(const void* id) const
505{
506 mRefs->incWeak(id);
507 return mRefs;
508}
509
510RefBase::weakref_type* RefBase::getWeakRefs() const
511{
512 return mRefs;
513}
514
515RefBase::RefBase()
516 : mRefs(new weakref_impl(this))
517{
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800518}
519
520RefBase::~RefBase()
521{
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800522 if (mRefs->mWeak == 0) {
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800523 delete mRefs;
524 }
525}
526
527void RefBase::extendObjectLifetime(int32_t mode)
528{
529 android_atomic_or(mode, &mRefs->mFlags);
530}
531
532void RefBase::onFirstRef()
533{
534}
535
536void RefBase::onLastStrongRef(const void* /*id*/)
537{
538}
539
540bool RefBase::onIncStrongAttempted(uint32_t flags, const void* id)
541{
542 return (flags&FIRST_INC_STRONG) ? true : false;
543}
544
545void RefBase::onLastWeakRef(const void* /*id*/)
546{
547}
Mathias Agopian84a23fa2011-02-16 15:23:08 -0800548
549// ---------------------------------------------------------------------------
550
Mathias Agopianb26ea8b2011-02-16 20:23:43 -0800551void RefBase::moveReferences(void* dst, void const* src, size_t n,
552 const ReferenceConverterBase& caster)
553{
554#if DEBUG_REFS
555 const size_t itemSize = caster.getReferenceTypeSize();
556 for (size_t i=0 ; i<n ; i++) {
557 void* d = reinterpret_cast<void *>(intptr_t(dst) + i*itemSize);
558 void const* s = reinterpret_cast<void const*>(intptr_t(src) + i*itemSize);
559 RefBase* ref(reinterpret_cast<RefBase*>(caster.getReferenceBase(d)));
560 ref->mRefs->renameStrongRefId(s, d);
561 ref->mRefs->renameWeakRefId(s, d);
562 }
563#endif
564}
565
566// ---------------------------------------------------------------------------
567
Mathias Agopian84a23fa2011-02-16 15:23:08 -0800568TextOutput& printStrongPointer(TextOutput& to, const void* val)
569{
570 to << "sp<>(" << val << ")";
571 return to;
572}
573
574TextOutput& printWeakPointer(TextOutput& to, const void* val)
575{
576 to << "wp<>(" << val << ")";
577 return to;
578}
579
580
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800581}; // namespace android