1 /*
2  * Copyright (c) 2021 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "refbase.h"
17 #include "utils_log.h"
18 #ifdef DEBUG_REFBASE
19 #include <unistd.h>
20 #endif
21 
22 namespace OHOS {
23 
WeakRefCounter(RefCounter * counter,void * cookie)24 WeakRefCounter::WeakRefCounter(RefCounter *counter, void *cookie)
25     : atomicWeak_(0), refCounter_(counter), cookie_(cookie)
26 {
27     if (refCounter_ != nullptr) {
28         refCounter_->IncRefCount();
29     }
30 }
31 
~WeakRefCounter()32 WeakRefCounter::~WeakRefCounter()
33 {
34     if (refCounter_ != nullptr) {
35         refCounter_->DecRefCount();
36     }
37 }
38 
GetWeakRefCount() const39 int WeakRefCounter::GetWeakRefCount() const
40 {
41     return atomicWeak_.load(std::memory_order_relaxed);
42 }
43 
GetRefPtr()44 void* WeakRefCounter::GetRefPtr()
45 {
46     if ((cookie_ != nullptr) && (!refCounter_->IsRefPtrValid())) {
47         cookie_ = nullptr;
48     }
49     return cookie_;
50 }
51 
IncWeakRefCount(const void * objectId)52 void WeakRefCounter::IncWeakRefCount(const void *objectId)
53 {
54     if (atomicWeak_.fetch_add(1, std::memory_order_relaxed) == 0) {
55         refCounter_->IncWeakRefCount(objectId);
56     }
57 }
58 
DecWeakRefCount(const void * objectId)59 void WeakRefCounter::DecWeakRefCount(const void *objectId)
60 {
61     if (atomicWeak_.fetch_sub(1, std::memory_order_release) == 1) {
62         refCounter_->DecWeakRefCount(objectId);
63         delete this;
64     }
65 }
66 
AttemptIncStrongRef(const void * objectId)67 bool WeakRefCounter::AttemptIncStrongRef(const void *objectId)
68 {
69     int unuse = 0;
70     return refCounter_->AttemptIncStrongRef(objectId, unuse);
71 }
72 
73 #if ((defined DEBUG_REFBASE) && (!defined PRINT_TRACK_AT_ONCE))
74 // RefTracker is a debug tool, used to record the trace of RefBase.
75 // RefTracker will save the information about the count of RefBase,
76 // including the pointer of sptr/wptr(The pointer of itself, not the pointer
77 // it manages), the amount of strong/weak/refcout and the PID&TID.
78 // The Tracker can live with RefCounter.
79 // User should keep thread-safety of RefTracker.
80 class RefTracker {
81 public:
82     RefTracker(RefTracker* exTracker, const void* id, int strong, int weak, int ref, int pid, int tid);
83 
84     void PrintTrace(const void* refCounterPtr);
85 
86     RefTracker* PopTrace(const void* refCounterPtr);
87 
88 private:
89     const void* ptrID;
90     int strongRefCnt;
91     int weakRefCnt;
92     int refCnt;
93     int PID;
94     int TID;
95     RefTracker* exTrace;
96 };
97 
RefTracker(RefTracker * exTracker,const void * id,int strong,int weak,int ref,int pid,int tid)98 RefTracker::RefTracker(RefTracker* exTracker, const void* id, int strong, int weak, int ref, int pid, int tid)
99     : ptrID (id), strongRefCnt (strong), weakRefCnt (weak), refCnt (ref), PID (pid), TID (tid), exTrace (exTracker)
100 {
101 }
102 
PrintTrace(const void * refCounterPtr)103 void RefTracker::PrintTrace(const void* refCounterPtr)
104 {
105     UTILS_LOGI("%{public}p call %{public}p. strong: %{public}d weak: %{public}d " \
106         "refcnt: %{public}d PID: %{public}d TID: %{public}d",
107         ptrID, refCounterPtr, strongRefCnt, weakRefCnt, refCnt, PID, TID);
108 }
109 
PopTrace(const void * refCounterPtr)110 RefTracker* RefTracker::PopTrace(const void* refCounterPtr)
111 {
112     RefTracker* ref = exTrace;
113     PrintTrace(refCounterPtr);
114     delete this;
115     return ref;
116 }
117 #endif
118 
119 #ifdef DEBUG_REFBASE
120 #ifdef PRINT_TRACK_AT_ONCE
PrintRefs(const void * objectId)121 void RefCounter::PrintRefs(const void* objectId)
122 {
123     std::lock_guard<std::mutex> lock(trackerMutex);
124     UTILS_LOGI("%{public}p call %{public}p. strong: %{public}d weak: %{public}d " \
125         "refcnt: %{public}d", objectId, this, atomicStrong_.load(std::memory_order_relaxed),
126         atomicWeak_.load(std::memory_order_relaxed), atomicRefCount_.load(std::memory_order_relaxed));
127 }
128 #else
GetNewTrace(const void * objectId)129 void RefCounter::GetNewTrace(const void* objectId)
130 {
131     std::lock_guard<std::mutex> lock(trackerMutex);
132     RefTracker* newTracker = new RefTracker(refTracker, objectId, atomicStrong_,
133         atomicWeak_, atomicRefCount_, getpid(), gettid());
134     refTracker = newTracker;
135 }
136 
PrintTracker()137 void RefCounter::PrintTracker()
138 {
139     std::lock_guard<std::mutex> lock(trackerMutex);
140     if (refTracker) {
141         UTILS_LOGI("%{public}p start backtrace", this);
142         while (refTracker) {
143             refTracker = refTracker->PopTrace(this);
144         }
145         UTILS_LOGI("%{public}p end backtrace", this);
146     }
147 }
148 #endif
149 
150 #ifndef TRACK_ALL
EnableTracker()151 void RefCounter::EnableTracker()
152 {
153     std::lock_guard<std::mutex> lock(trackerMutex);
154 #ifdef PRINT_TRACK_AT_ONCE
155     UTILS_LOGI("%{public}p start tracking", this);
156 #endif
157     enableTrack = true;
158 }
159 #endif
160 #endif
161 
162 void RefCounter::DebugRefBase([[maybe_unused]]const void* objectId)
163 {
164 #ifdef DEBUG_REFBASE
165     if (enableTrack) {
166 #ifdef PRINT_TRACK_AT_ONCE
167         PrintRefs(objectId);
168 #else
169         GetNewTrace(objectId);
170 #endif
171     }
172 #endif
173 }
174 
RefCounter()175 RefCounter::RefCounter()
176     : atomicStrong_(INITIAL_PRIMARY_VALUE), atomicWeak_(0), atomicRefCount_(0), atomicFlags_(0), atomicAttempt_(0)
177 {
178 }
179 
GetRefCount()180 int RefCounter::GetRefCount()
181 {
182     return atomicRefCount_.load(std::memory_order_relaxed);
183 }
184 
IncRefCount()185 void RefCounter::IncRefCount()
186 {
187     atomicRefCount_.fetch_add(1, std::memory_order_relaxed);
188 }
189 
DecRefCount()190 void RefCounter::DecRefCount()
191 {
192     if (atomicRefCount_.load(std::memory_order_relaxed) > 0) {
193         if (atomicRefCount_.fetch_sub(1, std::memory_order_release) == 1) {
194             delete (this);
195         }
196     }
197 }
198 
SetCallback(const RefPtrCallback & callback)199 void RefCounter::SetCallback(const RefPtrCallback& callback)
200 {
201     callback_ = callback;
202 }
203 
RemoveCallback()204 void RefCounter::RemoveCallback()
205 {
206     callback_ = nullptr;
207 }
208 
IsRefPtrValid()209 bool RefCounter::IsRefPtrValid()
210 {
211     return callback_ != nullptr;
212 }
213 
214 #ifndef EMULATOR_PLATFORM
SetCanPromote(const CanPromote & canPromote)215 void RefCounter::SetCanPromote(const CanPromote &canPromote)
216 {
217     canPromote_ = canPromote;
218 }
219 
RemoveCanPromote()220 void RefCounter::RemoveCanPromote()
221 {
222     canPromote_ = nullptr;
223 }
224 
IsCanPromoteValid()225 bool RefCounter::IsCanPromoteValid()
226 {
227     return canPromote_ != nullptr;
228 }
229 #endif
230 
~RefCounter()231 RefCounter::~RefCounter()
232 {
233 #ifdef DEBUG_REFBASE
234     if (enableTrack) {
235 #ifdef PRINT_TRACK_AT_ONCE
236         UTILS_LOGI("%{public}p end tracking", this);
237 #else
238         PrintTracker();
239 #endif
240     }
241 #endif
242 }
243 
IncStrongRefCount(const void * objectId)244 int RefCounter::IncStrongRefCount(const void* objectId)
245 {
246     DebugRefBase(objectId);
247     int curCount = atomicStrong_.load(std::memory_order_relaxed);
248     if (curCount >= 0) {
249         curCount = atomicStrong_.fetch_add(1, std::memory_order_relaxed);
250         if (curCount == INITIAL_PRIMARY_VALUE) {
251             atomicStrong_.fetch_sub(INITIAL_PRIMARY_VALUE, std::memory_order_release);
252         }
253     }
254 
255     return curCount;
256 }
257 
DecStrongRefCount(const void * objectId)258 int RefCounter::DecStrongRefCount(const void* objectId)
259 {
260     DebugRefBase(objectId);
261     int curCount = GetStrongRefCount();
262     if (curCount == INITIAL_PRIMARY_VALUE) {
263         // unexpected case: there had never a strong reference.
264         UTILS_LOGD("decStrongRef when there is nerver a strong reference");
265     } else if (curCount > 0) {
266         // we should update the current count here.
267         // it may be changed after last operation.
268         curCount = atomicStrong_.fetch_sub(1, std::memory_order_release);
269     }
270 
271     return curCount;
272 }
273 
GetStrongRefCount()274 int RefCounter::GetStrongRefCount()
275 {
276     return atomicStrong_.load(std::memory_order_relaxed);
277 }
278 
IncWeakRefCount(const void * objectId)279 int RefCounter::IncWeakRefCount(const void* objectId)
280 {
281     DebugRefBase(objectId);
282     return atomicWeak_.fetch_add(1, std::memory_order_relaxed);
283 }
284 
DecWeakRefCount(const void * objectId)285 int RefCounter::DecWeakRefCount(const void* objectId)
286 {
287     DebugRefBase(objectId);
288     int curCount = GetWeakRefCount();
289     if (curCount > 0) {
290         curCount = atomicWeak_.fetch_sub(1, std::memory_order_release);
291     }
292 
293     if (curCount != 1) {
294         return curCount;
295     }
296     std::atomic_thread_fence(std::memory_order_acquire);
297     if (IsLifeTimeExtended()) {
298         if (callback_) {
299             callback_();
300         }
301     } else {
302         // only weak ptr but never had a strong ref, we should do nothing here theoretically. But it may cause a leak.
303         if (GetStrongRefCount() == INITIAL_PRIMARY_VALUE) {
304             UTILS_LOGW("dec the last weakRef before it had a strong reference, delete refbase to avoid Memory Leak");
305             if (callback_) {
306                 callback_();
307             }
308         } else {
309             // free RefCounter
310             DecRefCount();
311         }
312     }
313 
314     return curCount;
315 }
316 
GetWeakRefCount()317 int RefCounter::GetWeakRefCount()
318 {
319     return atomicWeak_.load(std::memory_order_relaxed);
320 }
321 
GetAttemptAcquire()322 int RefCounter::GetAttemptAcquire()
323 {
324     return atomicAttempt_.load(std::memory_order_relaxed);
325 }
326 
SetAttemptAcquire()327 void RefCounter::SetAttemptAcquire()
328 {
329     (void)atomicAttempt_.fetch_add(1, std::memory_order_relaxed);
330 }
331 
IsAttemptAcquireSet()332 bool RefCounter::IsAttemptAcquireSet()
333 {
334     return static_cast<bool>(atomicAttempt_.load(std::memory_order_relaxed) > 0);
335 }
336 
ClearAttemptAcquire()337 void RefCounter::ClearAttemptAcquire()
338 {
339     atomicAttempt_.fetch_sub(1, std::memory_order_relaxed);
340 }
341 
ExtendObjectLifetime()342 void RefCounter::ExtendObjectLifetime()
343 {
344     atomicFlags_.fetch_or(FLAG_EXTEND_LIFE_TIME, std::memory_order_relaxed);
345 }
346 
IsLifeTimeExtended()347 bool RefCounter::IsLifeTimeExtended()
348 {
349     return static_cast<bool>(atomicFlags_.load(std::memory_order_relaxed) & FLAG_EXTEND_LIFE_TIME);
350 }
351 
AttemptIncStrongRef(const void * objectId,int & outCount)352 bool RefCounter::AttemptIncStrongRef(const void *objectId, int &outCount)
353 {
354     int curCount = GetStrongRefCount();
355     IncWeakRefCount(objectId);
356 
357     // if the object already had strong references.just promoting it.
358     while ((curCount > 0) && (curCount != INITIAL_PRIMARY_VALUE)) {
359         if (atomicStrong_.compare_exchange_weak(curCount, curCount + 1, std::memory_order_relaxed)) {
360             goto ATTEMPT_SUCCESS;
361         }
362         // someone else changed the counter.re-acquire the counter value.
363         curCount = atomicStrong_.load(std::memory_order_relaxed);
364     }
365 
366     if ((curCount == INITIAL_PRIMARY_VALUE) && !IsLifeTimeExtended()) {
367         // this object has a "normal" life-time,
368         while (curCount > 0) {
369             if (atomicStrong_.compare_exchange_weak(curCount, curCount + 1, std::memory_order_relaxed)) {
370                 goto ATTEMPT_SUCCESS;
371             }
372             curCount = atomicStrong_.load(std::memory_order_relaxed);
373         }
374     }
375 
376     if (IsLifeTimeExtended()) {
377 #ifndef EMULATOR_PLATFORM
378         if (!IsCanPromoteValid() || !canPromote_()) {
379             return false;
380         }
381 #endif
382         curCount = atomicStrong_.fetch_add(1, std::memory_order_relaxed);
383     }
384 
385 ATTEMPT_SUCCESS:
386     if (curCount == INITIAL_PRIMARY_VALUE) {
387         outCount = curCount;
388         atomicStrong_.fetch_sub(INITIAL_PRIMARY_VALUE, std::memory_order_release);
389         return true;
390     }
391 
392     if (curCount < 0 || (!IsLifeTimeExtended() && curCount == 0)) {
393         // the object destroyed on strong reference count reduce to zero.
394         DecWeakRefCount(objectId);
395         return false;
396     }
397 
398     return true;
399 }
400 
AttemptIncStrong(const void * objectId)401 bool RefCounter::AttemptIncStrong(const void *objectId)
402 {
403     IncWeakRefCount(objectId);
404     int curCount = GetStrongRefCount();
405     while (curCount > 0) {
406         if (atomicStrong_.compare_exchange_weak(curCount, curCount + 1, std::memory_order_relaxed)) {
407             break;
408         }
409         // curCount has been updated.
410     }
411     if (curCount <= 0) {
412         DecWeakRefCount(objectId);
413     }
414     return curCount > 0;
415 }
416 
RefBase()417 RefBase::RefBase() : refs_(new RefCounter())
418 {
419     refs_->IncRefCount();
420     refs_->SetCallback([this] { this->RefPtrCallback(); });
421 #ifndef EMULATOR_PLATFORM
422     refs_->SetCanPromote([this] { return this->CanPromote(); });
423 #endif
424 }
425 
RefBase(const RefBase &)426 RefBase::RefBase(const RefBase &)
427 {
428     refs_ = new (std::nothrow) RefCounter();
429     if (refs_ != nullptr) {
430         refs_->IncRefCount();
431         refs_->SetCallback([this] { this->RefPtrCallback(); });
432 #ifndef EMULATOR_PLATFORM
433         refs_->SetCanPromote([this] { return this->CanPromote(); });
434 #endif
435     }
436 }
437 
438 #ifndef EMULATOR_PLATFORM
CanPromote()439 bool RefBase::CanPromote()
440 {
441     return true;
442 }
443 #endif
444 
RefPtrCallback()445 void RefBase::RefPtrCallback()
446 {
447     delete this;
448 }
449 
450 /*
451  * The two ends of the assignment are two independent and exclusive,
452  * and the application should not share the reference counter.
453  * RISK: If there is a reference count on the left of the equal sign,
454  * it may cause a reference count exception
455  */
operator =(const RefBase &)456 RefBase &RefBase::operator=(const RefBase &)
457 {
458     if (refs_ != nullptr) {
459         refs_->RemoveCallback();
460         refs_->DecRefCount();
461     }
462 
463     refs_ = new (std::nothrow) RefCounter();
464     if (refs_ != nullptr) {
465         refs_->IncRefCount();
466         refs_->SetCallback([this] { this->RefPtrCallback(); });
467 #ifndef EMULATOR_PLATFORM
468         refs_->SetCanPromote([this] { return this->CanPromote(); });
469 #endif
470     }
471 
472     return *this;
473 }
474 
RefBase(RefBase && other)475 RefBase::RefBase(RefBase &&other) noexcept
476 {
477     refs_ = other.refs_;
478     other.refs_ = nullptr;
479 }
480 
operator =(RefBase && other)481 RefBase &RefBase::operator=(RefBase &&other) noexcept
482 {
483     if (refs_ == other.refs_) {
484         return *this;
485     }
486 
487     if (refs_ != nullptr) {
488         refs_->RemoveCallback();
489         refs_->DecRefCount();
490     }
491 
492     refs_ = other.refs_;
493     other.refs_ = nullptr;
494     return *this;
495 }
496 
~RefBase()497 RefBase::~RefBase()
498 {
499     if (refs_ != nullptr) {
500         refs_->RemoveCallback();
501         if ((refs_->IsLifeTimeExtended() && refs_->GetWeakRefCount() == 0) ||
502              refs_->GetStrongRefCount() == INITIAL_PRIMARY_VALUE) {
503             refs_->DecRefCount();
504         }
505         refs_ = nullptr;
506     }
507 }
508 
ExtendObjectLifetime()509 void RefBase::ExtendObjectLifetime()
510 {
511     refs_->ExtendObjectLifetime();
512 }
513 
IncStrongRef(const void * objectId)514 void RefBase::IncStrongRef(const void *objectId)
515 {
516     if (refs_ == nullptr) {
517         return;
518     }
519 
520     IncWeakRef(objectId);
521     const int curCount = refs_->IncStrongRefCount(objectId);
522     if (!refs_->IsLifeTimeExtended() && curCount == 0) {
523         UTILS_LOGF("%{public}p still incStrongRef after last strong ref", this);
524     }
525     if (curCount == INITIAL_PRIMARY_VALUE) {
526         OnFirstStrongRef(objectId);
527     }
528 }
529 
CheckIsAttemptAcquireSet(const void * objectId)530 void RefBase::CheckIsAttemptAcquireSet(const void *objectId)
531 {
532     if (refs_->IsAttemptAcquireSet()) {
533         refs_->ClearAttemptAcquire();
534         const int attemptCount = refs_->GetAttemptAcquire();
535         if (attemptCount < 0) {
536             UTILS_LOGF("Multi-threads trigger illegal decstrong from %{public}d due to AttemptIncStrong in ipc",
537                 attemptCount);
538         }
539         refs_->DecStrongRefCount(objectId);
540         refs_->DecWeakRefCount(objectId);
541     }
542 }
543 
DecStrongRef(const void * objectId)544 void RefBase::DecStrongRef(const void *objectId)
545 {
546     if (refs_ == nullptr) {
547         return;
548     }
549 
550     RefCounter * const refs = refs_;
551     const int curCount = refs->DecStrongRefCount(objectId);
552     if (curCount <= 0) {
553         UTILS_LOGF("%{public}p call decStrongRef too many times", this);
554     }
555     if (curCount == 1) {
556         std::atomic_thread_fence(std::memory_order_acquire);
557         OnLastStrongRef(objectId);
558         if (!refs->IsLifeTimeExtended()) {
559             if (refs->callback_) {
560                 refs->callback_();
561             }
562         }
563     }
564 
565     refs->DecWeakRefCount(objectId);
566 }
567 
GetSptrRefCount()568 int RefBase::GetSptrRefCount()
569 {
570     if (refs_ == nullptr) {
571         return 0;
572     }
573     return refs_->GetStrongRefCount();
574 }
575 
CreateWeakRef(void * cookie)576 WeakRefCounter *RefBase::CreateWeakRef(void *cookie)
577 {
578     if (refs_ != nullptr) {
579         return new WeakRefCounter(refs_, cookie);
580     }
581     return nullptr;
582 }
583 
IncWeakRef(const void * objectId)584 void RefBase::IncWeakRef(const void *objectId)
585 {
586     if (refs_ != nullptr) {
587         refs_->IncWeakRefCount(objectId);
588     }
589 }
590 
GetRefCounter() const591 RefCounter *RefBase::GetRefCounter() const
592 {
593     return refs_;
594 }
595 
DecWeakRef(const void * objectId)596 void RefBase::DecWeakRef(const void *objectId)
597 {
598     if (refs_ != nullptr) {
599         refs_->DecWeakRefCount(objectId);
600     }
601 }
602 
GetWptrRefCount()603 int RefBase::GetWptrRefCount()
604 {
605     if (refs_ == nullptr) {
606         return 0;
607     }
608     return refs_->GetWeakRefCount();
609 }
610 
AttemptAcquire(const void * objectId)611 bool RefBase::AttemptAcquire(const void *objectId)
612 {
613     if (refs_ == nullptr) {
614         return false;
615     }
616 
617     int count = 0;
618     if (refs_->AttemptIncStrongRef(objectId, count)) {
619         refs_->SetAttemptAcquire();
620         if (count == INITIAL_PRIMARY_VALUE) {
621             OnFirstStrongRef(objectId);
622         }
623 
624         return true;
625     }
626     return false;
627 }
628 
AttemptIncStrongRef(const void * objectId)629 bool RefBase::AttemptIncStrongRef(const void *objectId)
630 {
631     if ((refs_ != nullptr) && (OnAttemptPromoted(objectId))) {
632         int count = 0;
633         bool ret = refs_->AttemptIncStrongRef(objectId, count);
634         if (count == INITIAL_PRIMARY_VALUE) {
635             OnFirstStrongRef(objectId);
636         }
637         return ret;
638     }
639 
640     return false;
641 }
642 
AttemptIncStrong(const void * objectId)643 bool RefBase::AttemptIncStrong(const void *objectId)
644 {
645     if (refs_ == nullptr) {
646         return false;
647     }
648     if (refs_->AttemptIncStrong(objectId)) {
649         refs_->SetAttemptAcquire();
650         return true;
651     }
652     return false;
653 }
654 
IsAttemptAcquireSet()655 bool RefBase::IsAttemptAcquireSet()
656 {
657     if (refs_ == nullptr) {
658         return false;
659     }
660     return refs_->IsAttemptAcquireSet();
661 }
662 
IsExtendLifeTimeSet()663 bool RefBase::IsExtendLifeTimeSet()
664 {
665     if (refs_ == nullptr) {
666         return false;
667     }
668     return refs_->IsLifeTimeExtended();
669 }
670 
OnFirstStrongRef(const void *)671 void RefBase::OnFirstStrongRef(const void*)
672 {}
673 
OnLastStrongRef(const void *)674 void RefBase::OnLastStrongRef(const void*)
675 {}
676 
OnLastWeakRef(const void *)677 void RefBase::OnLastWeakRef(const void*)
678 {}
679 
OnAttemptPromoted(const void *)680 bool RefBase::OnAttemptPromoted(const void*)
681 {
682     return true;
683 }
684 
685 #if ((defined DEBUG_REFBASE) && (!defined TRACK_ALL))
EnableTracker()686 void RefBase::EnableTracker()
687 {
688     refs_->EnableTracker();
689 }
690 #else
EnableTracker()691 void RefBase::EnableTracker()
692 {
693 }
694 #endif
695 
696 }  // namespace OHOS
697