blob: ea1e4db84dfd170af8edf68b61396caa22a35221 [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"
Mathias Agopianda8ec4b2013-03-19 17:36:57 -070018// #define LOG_NDEBUG 0
The Android Open Source Projectcbb10112009-03-03 19:31:44 -080019
Mark Salyzyn5bed8032014-04-30 11:10:46 -070020#include <fcntl.h>
21#include <stdio.h>
22#include <stdlib.h>
23#include <sys/stat.h>
24#include <sys/types.h>
25#include <typeinfo>
26#include <unistd.h>
27
The Android Open Source Projectcbb10112009-03-03 19:31:44 -080028#include <utils/RefBase.h>
29
30#include <utils/Atomic.h>
31#include <utils/CallStack.h>
The Android Open Source Projectcbb10112009-03-03 19:31:44 -080032#include <utils/Log.h>
33#include <utils/threads.h>
34
Mark Salyzyn5bed8032014-04-30 11:10:46 -070035#ifndef __unused
36#define __unused __attribute__((__unused__))
37#endif
The Android Open Source Projectcbb10112009-03-03 19:31:44 -080038
39// compile with refcounting debugging enabled
40#define DEBUG_REFS 0
Mathias Agopian6d4419d2013-03-18 20:31:18 -070041
42// whether ref-tracking is enabled by default, if not, trackMe(true, false)
43// needs to be called explicitly
44#define DEBUG_REFS_ENABLED_BY_DEFAULT 0
45
46// whether callstack are collected (significantly slows things down)
The Android Open Source Projectcbb10112009-03-03 19:31:44 -080047#define DEBUG_REFS_CALLSTACK_ENABLED 1
48
Mathias Agopian6d4419d2013-03-18 20:31:18 -070049// folder where stack traces are saved when DEBUG_REFS is enabled
50// this folder needs to exist and be writable
51#define DEBUG_REFS_CALLSTACK_PATH "/data/debug"
52
The Android Open Source Projectcbb10112009-03-03 19:31:44 -080053// log all reference counting operations
54#define PRINT_REFS 0
55
56// ---------------------------------------------------------------------------
57
58namespace android {
59
60#define INITIAL_STRONG_VALUE (1<<28)
61
62// ---------------------------------------------------------------------------
63
64class RefBase::weakref_impl : public RefBase::weakref_type
65{
66public:
67 volatile int32_t mStrong;
68 volatile int32_t mWeak;
69 RefBase* const mBase;
70 volatile int32_t mFlags;
Mathias Agopian9c8fa9e2011-06-15 20:42:47 -070071
The Android Open Source Projectcbb10112009-03-03 19:31:44 -080072#if !DEBUG_REFS
73
74 weakref_impl(RefBase* base)
75 : mStrong(INITIAL_STRONG_VALUE)
76 , mWeak(0)
77 , mBase(base)
78 , mFlags(0)
79 {
80 }
81
82 void addStrongRef(const void* /*id*/) { }
83 void removeStrongRef(const void* /*id*/) { }
Mathias Agopianad099652011-08-10 21:07:02 -070084 void renameStrongRefId(const void* /*old_id*/, const void* /*new_id*/) { }
The Android Open Source Projectcbb10112009-03-03 19:31:44 -080085 void addWeakRef(const void* /*id*/) { }
86 void removeWeakRef(const void* /*id*/) { }
Mathias Agopianad099652011-08-10 21:07:02 -070087 void renameWeakRefId(const void* /*old_id*/, const void* /*new_id*/) { }
The Android Open Source Projectcbb10112009-03-03 19:31:44 -080088 void printRefs() const { }
89 void trackMe(bool, bool) { }
90
91#else
92
93 weakref_impl(RefBase* base)
94 : mStrong(INITIAL_STRONG_VALUE)
95 , mWeak(0)
96 , mBase(base)
97 , mFlags(0)
98 , mStrongRefs(NULL)
99 , mWeakRefs(NULL)
100 , mTrackEnabled(!!DEBUG_REFS_ENABLED_BY_DEFAULT)
101 , mRetain(false)
102 {
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800103 }
104
105 ~weakref_impl()
106 {
Mathias Agopianad099652011-08-10 21:07:02 -0700107 bool dumpStack = false;
108 if (!mRetain && mStrongRefs != NULL) {
109 dumpStack = true;
Steve Block1b781ab2012-01-06 19:20:56 +0000110 ALOGE("Strong references remain:");
Mathias Agopianad099652011-08-10 21:07:02 -0700111 ref_entry* refs = mStrongRefs;
112 while (refs) {
113 char inc = refs->ref >= 0 ? '+' : '-';
Steve Blockeb095332011-12-20 16:23:08 +0000114 ALOGD("\t%c ID %p (ref %d):", inc, refs->id, refs->ref);
Mathias Agopianad099652011-08-10 21:07:02 -0700115#if DEBUG_REFS_CALLSTACK_ENABLED
Ian McKellar55e0f1c2014-03-31 15:59:31 -0700116 refs->stack.log(LOG_TAG);
Mathias Agopianad099652011-08-10 21:07:02 -0700117#endif
118 refs = refs->next;
119 }
120 }
121
122 if (!mRetain && mWeakRefs != NULL) {
123 dumpStack = true;
Steve Block1b781ab2012-01-06 19:20:56 +0000124 ALOGE("Weak references remain!");
Mathias Agopianad099652011-08-10 21:07:02 -0700125 ref_entry* refs = mWeakRefs;
126 while (refs) {
127 char inc = refs->ref >= 0 ? '+' : '-';
Steve Blockeb095332011-12-20 16:23:08 +0000128 ALOGD("\t%c ID %p (ref %d):", inc, refs->id, refs->ref);
Mathias Agopianad099652011-08-10 21:07:02 -0700129#if DEBUG_REFS_CALLSTACK_ENABLED
Ian McKellar55e0f1c2014-03-31 15:59:31 -0700130 refs->stack.log(LOG_TAG);
Mathias Agopianad099652011-08-10 21:07:02 -0700131#endif
132 refs = refs->next;
133 }
134 }
135 if (dumpStack) {
Steve Block1b781ab2012-01-06 19:20:56 +0000136 ALOGE("above errors at:");
Mathias Agopiand34a8ca2013-03-21 17:12:40 -0700137 CallStack stack(LOG_TAG);
Mathias Agopianad099652011-08-10 21:07:02 -0700138 }
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800139 }
140
Mathias Agopianad099652011-08-10 21:07:02 -0700141 void addStrongRef(const void* id) {
Steve Blockeb095332011-12-20 16:23:08 +0000142 //ALOGD_IF(mTrackEnabled,
Mathias Agopianad099652011-08-10 21:07:02 -0700143 // "addStrongRef: RefBase=%p, id=%p", mBase, id);
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800144 addRef(&mStrongRefs, id, mStrong);
145 }
146
Mathias Agopianad099652011-08-10 21:07:02 -0700147 void removeStrongRef(const void* id) {
Steve Blockeb095332011-12-20 16:23:08 +0000148 //ALOGD_IF(mTrackEnabled,
Mathias Agopianad099652011-08-10 21:07:02 -0700149 // "removeStrongRef: RefBase=%p, id=%p", mBase, id);
150 if (!mRetain) {
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800151 removeRef(&mStrongRefs, id);
Mathias Agopianad099652011-08-10 21:07:02 -0700152 } else {
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800153 addRef(&mStrongRefs, id, -mStrong);
Mathias Agopianad099652011-08-10 21:07:02 -0700154 }
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800155 }
156
Mathias Agopianad099652011-08-10 21:07:02 -0700157 void renameStrongRefId(const void* old_id, const void* new_id) {
Steve Blockeb095332011-12-20 16:23:08 +0000158 //ALOGD_IF(mTrackEnabled,
Mathias Agopianad099652011-08-10 21:07:02 -0700159 // "renameStrongRefId: RefBase=%p, oid=%p, nid=%p",
160 // mBase, old_id, new_id);
161 renameRefsId(mStrongRefs, old_id, new_id);
162 }
163
164 void addWeakRef(const void* id) {
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800165 addRef(&mWeakRefs, id, mWeak);
166 }
167
Mathias Agopianad099652011-08-10 21:07:02 -0700168 void removeWeakRef(const void* id) {
169 if (!mRetain) {
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800170 removeRef(&mWeakRefs, id);
Mathias Agopianad099652011-08-10 21:07:02 -0700171 } else {
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800172 addRef(&mWeakRefs, id, -mWeak);
Mathias Agopianad099652011-08-10 21:07:02 -0700173 }
174 }
175
176 void renameWeakRefId(const void* old_id, const void* new_id) {
177 renameRefsId(mWeakRefs, old_id, new_id);
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800178 }
179
180 void trackMe(bool track, bool retain)
181 {
182 mTrackEnabled = track;
183 mRetain = retain;
184 }
185
186 void printRefs() const
187 {
188 String8 text;
189
190 {
Mathias Agopianad099652011-08-10 21:07:02 -0700191 Mutex::Autolock _l(mMutex);
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800192 char buf[128];
George Burgess IVe7aa2b22016-03-02 14:02:55 -0800193 snprintf(buf, sizeof(buf),
194 "Strong references on RefBase %p (weakref_type %p):\n",
195 mBase, this);
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800196 text.append(buf);
197 printRefsLocked(&text, mStrongRefs);
George Burgess IVe7aa2b22016-03-02 14:02:55 -0800198 snprintf(buf, sizeof(buf),
199 "Weak references on RefBase %p (weakref_type %p):\n",
200 mBase, this);
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800201 text.append(buf);
202 printRefsLocked(&text, mWeakRefs);
203 }
204
205 {
206 char name[100];
George Burgess IVe7aa2b22016-03-02 14:02:55 -0800207 snprintf(name, sizeof(name), DEBUG_REFS_CALLSTACK_PATH "/%p.stack",
208 this);
Mathias Agopian769828d2013-03-06 17:51:15 -0800209 int rc = open(name, O_RDWR | O_CREAT | O_APPEND, 644);
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800210 if (rc >= 0) {
211 write(rc, text.string(), text.length());
212 close(rc);
Steve Blockeb095332011-12-20 16:23:08 +0000213 ALOGD("STACK TRACE for %p saved in %s", this, name);
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800214 }
Steve Block1b781ab2012-01-06 19:20:56 +0000215 else ALOGE("FAILED TO PRINT STACK TRACE for %p in %s: %s", this,
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800216 name, strerror(errno));
217 }
218 }
219
220private:
221 struct ref_entry
222 {
223 ref_entry* next;
224 const void* id;
225#if DEBUG_REFS_CALLSTACK_ENABLED
226 CallStack stack;
227#endif
228 int32_t ref;
229 };
230
231 void addRef(ref_entry** refs, const void* id, int32_t mRef)
232 {
233 if (mTrackEnabled) {
234 AutoMutex _l(mMutex);
Mathias Agopianad099652011-08-10 21:07:02 -0700235
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800236 ref_entry* ref = new ref_entry;
237 // Reference count at the time of the snapshot, but before the
238 // update. Positive value means we increment, negative--we
239 // decrement the reference count.
240 ref->ref = mRef;
241 ref->id = id;
242#if DEBUG_REFS_CALLSTACK_ENABLED
243 ref->stack.update(2);
244#endif
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800245 ref->next = *refs;
246 *refs = ref;
247 }
248 }
249
250 void removeRef(ref_entry** refs, const void* id)
251 {
252 if (mTrackEnabled) {
253 AutoMutex _l(mMutex);
254
Mathias Agopianad099652011-08-10 21:07:02 -0700255 ref_entry* const head = *refs;
256 ref_entry* ref = head;
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800257 while (ref != NULL) {
258 if (ref->id == id) {
259 *refs = ref->next;
260 delete ref;
261 return;
262 }
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800263 refs = &ref->next;
264 ref = *refs;
265 }
Mathias Agopianad099652011-08-10 21:07:02 -0700266
Steve Block1b781ab2012-01-06 19:20:56 +0000267 ALOGE("RefBase: removing id %p on RefBase %p"
Mathias Agopianad099652011-08-10 21:07:02 -0700268 "(weakref_type %p) that doesn't exist!",
269 id, mBase, this);
270
271 ref = head;
272 while (ref) {
273 char inc = ref->ref >= 0 ? '+' : '-';
Steve Blockeb095332011-12-20 16:23:08 +0000274 ALOGD("\t%c ID %p (ref %d):", inc, ref->id, ref->ref);
Mathias Agopianad099652011-08-10 21:07:02 -0700275 ref = ref->next;
276 }
277
Mathias Agopiand34a8ca2013-03-21 17:12:40 -0700278 CallStack stack(LOG_TAG);
Mathias Agopianad099652011-08-10 21:07:02 -0700279 }
280 }
281
282 void renameRefsId(ref_entry* r, const void* old_id, const void* new_id)
283 {
284 if (mTrackEnabled) {
285 AutoMutex _l(mMutex);
286 ref_entry* ref = r;
287 while (ref != NULL) {
288 if (ref->id == old_id) {
289 ref->id = new_id;
290 }
291 ref = ref->next;
292 }
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800293 }
294 }
295
296 void printRefsLocked(String8* out, const ref_entry* refs) const
297 {
298 char buf[128];
299 while (refs) {
300 char inc = refs->ref >= 0 ? '+' : '-';
George Burgess IVe7aa2b22016-03-02 14:02:55 -0800301 snprintf(buf, sizeof(buf), "\t%c ID %p (ref %d):\n",
302 inc, refs->id, refs->ref);
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800303 out->append(buf);
304#if DEBUG_REFS_CALLSTACK_ENABLED
305 out->append(refs->stack.toString("\t\t"));
306#else
307 out->append("\t\t(call stacks disabled)");
308#endif
309 refs = refs->next;
310 }
311 }
312
Mathias Agopianad099652011-08-10 21:07:02 -0700313 mutable Mutex mMutex;
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800314 ref_entry* mStrongRefs;
315 ref_entry* mWeakRefs;
316
317 bool mTrackEnabled;
318 // Collect stack traces on addref and removeref, instead of deleting the stack references
319 // on removeref that match the address ones.
320 bool mRetain;
321
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800322#endif
323};
324
325// ---------------------------------------------------------------------------
326
327void RefBase::incStrong(const void* id) const
328{
329 weakref_impl* const refs = mRefs;
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800330 refs->incWeak(id);
331
332 refs->addStrongRef(id);
333 const int32_t c = android_atomic_inc(&refs->mStrong);
Steve Blockae074452012-01-09 18:35:44 +0000334 ALOG_ASSERT(c > 0, "incStrong() called on %p after last strong ref", refs);
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800335#if PRINT_REFS
Steve Blockeb095332011-12-20 16:23:08 +0000336 ALOGD("incStrong of %p from %p: cnt=%d\n", this, id, c);
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800337#endif
338 if (c != INITIAL_STRONG_VALUE) {
339 return;
340 }
341
342 android_atomic_add(-INITIAL_STRONG_VALUE, &refs->mStrong);
Mathias Agopianad099652011-08-10 21:07:02 -0700343 refs->mBase->onFirstRef();
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800344}
345
346void RefBase::decStrong(const void* id) const
347{
348 weakref_impl* const refs = mRefs;
349 refs->removeStrongRef(id);
350 const int32_t c = android_atomic_dec(&refs->mStrong);
351#if PRINT_REFS
Steve Blockeb095332011-12-20 16:23:08 +0000352 ALOGD("decStrong of %p from %p: cnt=%d\n", this, id, c);
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800353#endif
Steve Blockae074452012-01-09 18:35:44 +0000354 ALOG_ASSERT(c >= 1, "decStrong() called on %p too many times", refs);
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800355 if (c == 1) {
Mathias Agopianad099652011-08-10 21:07:02 -0700356 refs->mBase->onLastStrongRef(id);
357 if ((refs->mFlags&OBJECT_LIFETIME_MASK) == OBJECT_LIFETIME_STRONG) {
Mathias Agopian9c8fa9e2011-06-15 20:42:47 -0700358 delete this;
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800359 }
360 }
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800361 refs->decWeak(id);
362}
363
364void RefBase::forceIncStrong(const void* id) const
365{
366 weakref_impl* const refs = mRefs;
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800367 refs->incWeak(id);
368
369 refs->addStrongRef(id);
370 const int32_t c = android_atomic_inc(&refs->mStrong);
Steve Blockae074452012-01-09 18:35:44 +0000371 ALOG_ASSERT(c >= 0, "forceIncStrong called on %p after ref count underflow",
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800372 refs);
373#if PRINT_REFS
Steve Blockeb095332011-12-20 16:23:08 +0000374 ALOGD("forceIncStrong of %p from %p: cnt=%d\n", this, id, c);
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800375#endif
376
377 switch (c) {
378 case INITIAL_STRONG_VALUE:
379 android_atomic_add(-INITIAL_STRONG_VALUE, &refs->mStrong);
380 // fall through...
381 case 0:
Mathias Agopianad099652011-08-10 21:07:02 -0700382 refs->mBase->onFirstRef();
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800383 }
384}
385
386int32_t RefBase::getStrongCount() const
387{
388 return mRefs->mStrong;
389}
390
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800391RefBase* RefBase::weakref_type::refBase() const
392{
393 return static_cast<const weakref_impl*>(this)->mBase;
394}
395
396void RefBase::weakref_type::incWeak(const void* id)
397{
398 weakref_impl* const impl = static_cast<weakref_impl*>(this);
399 impl->addWeakRef(id);
Mark Salyzyn5bed8032014-04-30 11:10:46 -0700400 const int32_t c __unused = android_atomic_inc(&impl->mWeak);
Steve Blockae074452012-01-09 18:35:44 +0000401 ALOG_ASSERT(c >= 0, "incWeak called on %p after last weak ref", this);
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800402}
403
Mathias Agopianad099652011-08-10 21:07:02 -0700404
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800405void RefBase::weakref_type::decWeak(const void* id)
406{
407 weakref_impl* const impl = static_cast<weakref_impl*>(this);
408 impl->removeWeakRef(id);
409 const int32_t c = android_atomic_dec(&impl->mWeak);
Steve Blockae074452012-01-09 18:35:44 +0000410 ALOG_ASSERT(c >= 1, "decWeak called on %p too many times", this);
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800411 if (c != 1) return;
Mathias Agopianad099652011-08-10 21:07:02 -0700412
413 if ((impl->mFlags&OBJECT_LIFETIME_WEAK) == OBJECT_LIFETIME_STRONG) {
414 // This is the regular lifetime case. The object is destroyed
415 // when the last strong reference goes away. Since weakref_impl
416 // outlive the object, it is not destroyed in the dtor, and
417 // we'll have to do it here.
418 if (impl->mStrong == INITIAL_STRONG_VALUE) {
419 // Special case: we never had a strong reference, so we need to
420 // destroy the object now.
Mathias Agopian9c8fa9e2011-06-15 20:42:47 -0700421 delete impl->mBase;
Mathias Agopianad099652011-08-10 21:07:02 -0700422 } else {
Steve Blockb37fbe92011-10-20 11:56:00 +0100423 // ALOGV("Freeing refs %p of old RefBase %p\n", this, impl->mBase);
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800424 delete impl;
425 }
426 } else {
Mathias Agopianad099652011-08-10 21:07:02 -0700427 // less common case: lifetime is OBJECT_LIFETIME_{WEAK|FOREVER}
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800428 impl->mBase->onLastWeakRef(id);
Mathias Agopianad099652011-08-10 21:07:02 -0700429 if ((impl->mFlags&OBJECT_LIFETIME_MASK) == OBJECT_LIFETIME_WEAK) {
430 // this is the OBJECT_LIFETIME_WEAK case. The last weak-reference
431 // is gone, we can destroy the object.
Mathias Agopian9c8fa9e2011-06-15 20:42:47 -0700432 delete impl->mBase;
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800433 }
434 }
435}
436
437bool RefBase::weakref_type::attemptIncStrong(const void* id)
438{
439 incWeak(id);
440
441 weakref_impl* const impl = static_cast<weakref_impl*>(this);
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800442 int32_t curCount = impl->mStrong;
Dianne Hackborna729ab12013-03-14 15:26:30 -0700443
444 ALOG_ASSERT(curCount >= 0,
445 "attemptIncStrong called on %p after underflow", this);
446
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800447 while (curCount > 0 && curCount != INITIAL_STRONG_VALUE) {
Dianne Hackborna729ab12013-03-14 15:26:30 -0700448 // we're in the easy/common case of promoting a weak-reference
449 // from an existing strong reference.
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800450 if (android_atomic_cmpxchg(curCount, curCount+1, &impl->mStrong) == 0) {
451 break;
452 }
Dianne Hackborna729ab12013-03-14 15:26:30 -0700453 // the strong count has changed on us, we need to re-assert our
454 // situation.
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800455 curCount = impl->mStrong;
456 }
457
458 if (curCount <= 0 || curCount == INITIAL_STRONG_VALUE) {
Dianne Hackborna729ab12013-03-14 15:26:30 -0700459 // we're now in the harder case of either:
460 // - there never was a strong reference on us
461 // - or, all strong references have been released
462 if ((impl->mFlags&OBJECT_LIFETIME_WEAK) == OBJECT_LIFETIME_STRONG) {
463 // this object has a "normal" life-time, i.e.: it gets destroyed
464 // when the last strong reference goes away
465 if (curCount <= 0) {
466 // the last strong-reference got released, the object cannot
467 // be revived.
468 decWeak(id);
469 return false;
470 }
471
472 // here, curCount == INITIAL_STRONG_VALUE, which means
473 // there never was a strong-reference, so we can try to
474 // promote this object; we need to do that atomically.
475 while (curCount > 0) {
476 if (android_atomic_cmpxchg(curCount, curCount + 1,
477 &impl->mStrong) == 0) {
478 break;
479 }
480 // the strong count has changed on us, we need to re-assert our
481 // situation (e.g.: another thread has inc/decStrong'ed us)
482 curCount = impl->mStrong;
483 }
484
485 if (curCount <= 0) {
486 // promote() failed, some other thread destroyed us in the
487 // meantime (i.e.: strong count reached zero).
488 decWeak(id);
489 return false;
490 }
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800491 } else {
Dianne Hackborna729ab12013-03-14 15:26:30 -0700492 // this object has an "extended" life-time, i.e.: it can be
493 // revived from a weak-reference only.
494 // Ask the object's implementation if it agrees to be revived
495 if (!impl->mBase->onIncStrongAttempted(FIRST_INC_STRONG, id)) {
496 // it didn't so give-up.
497 decWeak(id);
498 return false;
499 }
500 // grab a strong-reference, which is always safe due to the
501 // extended life-time.
502 curCount = android_atomic_inc(&impl->mStrong);
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800503 }
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800504
505 // If the strong reference count has already been incremented by
506 // someone else, the implementor of onIncStrongAttempted() is holding
507 // an unneeded reference. So call onLastStrongRef() here to remove it.
508 // (No, this is not pretty.) Note that we MUST NOT do this if we
509 // are in fact acquiring the first reference.
510 if (curCount > 0 && curCount < INITIAL_STRONG_VALUE) {
511 impl->mBase->onLastStrongRef(id);
512 }
513 }
514
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800515 impl->addStrongRef(id);
516
517#if PRINT_REFS
Steve Blockeb095332011-12-20 16:23:08 +0000518 ALOGD("attemptIncStrong of %p from %p: cnt=%d\n", this, id, curCount);
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800519#endif
520
Dianne Hackborna729ab12013-03-14 15:26:30 -0700521 // now we need to fix-up the count if it was INITIAL_STRONG_VALUE
522 // this must be done safely, i.e.: handle the case where several threads
523 // were here in attemptIncStrong().
524 curCount = impl->mStrong;
525 while (curCount >= INITIAL_STRONG_VALUE) {
526 ALOG_ASSERT(curCount > INITIAL_STRONG_VALUE,
527 "attemptIncStrong in %p underflowed to INITIAL_STRONG_VALUE",
528 this);
529 if (android_atomic_cmpxchg(curCount, curCount-INITIAL_STRONG_VALUE,
530 &impl->mStrong) == 0) {
531 break;
532 }
533 // the strong-count changed on us, we need to re-assert the situation,
534 // for e.g.: it's possible the fix-up happened in another thread.
535 curCount = impl->mStrong;
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800536 }
Dianne Hackborna729ab12013-03-14 15:26:30 -0700537
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800538 return true;
539}
540
541bool RefBase::weakref_type::attemptIncWeak(const void* id)
542{
543 weakref_impl* const impl = static_cast<weakref_impl*>(this);
Mathias Agopianad099652011-08-10 21:07:02 -0700544
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800545 int32_t curCount = impl->mWeak;
Steve Blockae074452012-01-09 18:35:44 +0000546 ALOG_ASSERT(curCount >= 0, "attemptIncWeak called on %p after underflow",
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800547 this);
548 while (curCount > 0) {
549 if (android_atomic_cmpxchg(curCount, curCount+1, &impl->mWeak) == 0) {
550 break;
551 }
552 curCount = impl->mWeak;
553 }
554
555 if (curCount > 0) {
556 impl->addWeakRef(id);
557 }
558
559 return curCount > 0;
560}
561
562int32_t RefBase::weakref_type::getWeakCount() const
563{
564 return static_cast<const weakref_impl*>(this)->mWeak;
565}
566
567void RefBase::weakref_type::printRefs() const
568{
569 static_cast<const weakref_impl*>(this)->printRefs();
570}
571
572void RefBase::weakref_type::trackMe(bool enable, bool retain)
573{
Mathias Agopianad099652011-08-10 21:07:02 -0700574 static_cast<weakref_impl*>(this)->trackMe(enable, retain);
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800575}
576
577RefBase::weakref_type* RefBase::createWeak(const void* id) const
578{
579 mRefs->incWeak(id);
580 return mRefs;
581}
582
583RefBase::weakref_type* RefBase::getWeakRefs() const
584{
585 return mRefs;
586}
587
588RefBase::RefBase()
589 : mRefs(new weakref_impl(this))
590{
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800591}
592
593RefBase::~RefBase()
594{
Mathias Agopianad099652011-08-10 21:07:02 -0700595 if (mRefs->mStrong == INITIAL_STRONG_VALUE) {
596 // we never acquired a strong (and/or weak) reference on this object.
Mathias Agopian9c8fa9e2011-06-15 20:42:47 -0700597 delete mRefs;
Mathias Agopianad099652011-08-10 21:07:02 -0700598 } else {
599 // life-time of this object is extended to WEAK or FOREVER, in
600 // which case weakref_impl doesn't out-live the object and we
601 // can free it now.
602 if ((mRefs->mFlags & OBJECT_LIFETIME_MASK) != OBJECT_LIFETIME_STRONG) {
603 // It's possible that the weak count is not 0 if the object
604 // re-acquired a weak reference in its destructor
605 if (mRefs->mWeak == 0) {
606 delete mRefs;
607 }
608 }
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800609 }
Mathias Agopianad099652011-08-10 21:07:02 -0700610 // for debugging purposes, clear this.
611 const_cast<weakref_impl*&>(mRefs) = NULL;
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800612}
613
614void RefBase::extendObjectLifetime(int32_t mode)
615{
616 android_atomic_or(mode, &mRefs->mFlags);
617}
618
619void RefBase::onFirstRef()
620{
621}
622
623void RefBase::onLastStrongRef(const void* /*id*/)
624{
625}
626
Mark Salyzyn5bed8032014-04-30 11:10:46 -0700627bool RefBase::onIncStrongAttempted(uint32_t flags, const void* /*id*/)
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800628{
629 return (flags&FIRST_INC_STRONG) ? true : false;
630}
631
632void RefBase::onLastWeakRef(const void* /*id*/)
633{
634}
Mathias Agopianad099652011-08-10 21:07:02 -0700635
636// ---------------------------------------------------------------------------
637
Mathias Agopianad099652011-08-10 21:07:02 -0700638#if DEBUG_REFS
Mark Salyzyn5bed8032014-04-30 11:10:46 -0700639void RefBase::renameRefs(size_t n, const ReferenceRenamer& renamer) {
Mathias Agopianad099652011-08-10 21:07:02 -0700640 for (size_t i=0 ; i<n ; i++) {
Mathias Agopian6cd548c2013-03-18 22:27:41 -0700641 renamer(i);
Mathias Agopianad099652011-08-10 21:07:02 -0700642 }
Mathias Agopianad099652011-08-10 21:07:02 -0700643}
Mark Salyzyn5bed8032014-04-30 11:10:46 -0700644#else
645void RefBase::renameRefs(size_t /*n*/, const ReferenceRenamer& /*renamer*/) { }
646#endif
Mathias Agopianad099652011-08-10 21:07:02 -0700647
Mathias Agopian6cd548c2013-03-18 22:27:41 -0700648void RefBase::renameRefId(weakref_type* ref,
649 const void* old_id, const void* new_id) {
650 weakref_impl* const impl = static_cast<weakref_impl*>(ref);
651 impl->renameStrongRefId(old_id, new_id);
652 impl->renameWeakRefId(old_id, new_id);
653}
654
655void RefBase::renameRefId(RefBase* ref,
656 const void* old_id, const void* new_id) {
657 ref->mRefs->renameStrongRefId(old_id, new_id);
658 ref->mRefs->renameWeakRefId(old_id, new_id);
659}
660
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800661}; // namespace android