diff options
| -rw-r--r-- | libs/binder/Binder.cpp | 19 | ||||
| -rw-r--r-- | libs/binder/BpBinder.cpp | 36 | ||||
| -rw-r--r-- | libs/binder/include/binder/Binder.h | 2 | ||||
| -rw-r--r-- | libs/binder/include/binder/BpBinder.h | 10 | ||||
| -rw-r--r-- | libs/binder/include/binder/Delegate.h | 93 | ||||
| -rw-r--r-- | libs/binder/include/binder/IBinder.h | 3 | ||||
| -rw-r--r-- | libs/binder/tests/binderBinderUnitTest.cpp | 49 |
7 files changed, 208 insertions, 4 deletions
diff --git a/libs/binder/Binder.cpp b/libs/binder/Binder.cpp index b5ea60f102..1dc62334cb 100644 --- a/libs/binder/Binder.cpp +++ b/libs/binder/Binder.cpp @@ -202,6 +202,17 @@ void IBinder::withLock(const std::function<void()>& doWithLock) { proxy->withLock(doWithLock); } +sp<IBinder> IBinder::lookupOrCreateWeak(const void* objectID, object_make_func make, + const void* makeArgs) { + BBinder* local = localBinder(); + if (local) { + return local->lookupOrCreateWeak(objectID, make, makeArgs); + } + BpBinder* proxy = this->remoteBinder(); + LOG_ALWAYS_FATAL_IF(proxy == nullptr, "binder object must be either local or remote"); + return proxy->lookupOrCreateWeak(objectID, make, makeArgs); +} + // --------------------------------------------------------------------------- class BBinder::RpcServerLink : public IBinder::DeathRecipient { @@ -378,6 +389,14 @@ void BBinder::withLock(const std::function<void()>& doWithLock) { doWithLock(); } +sp<IBinder> BBinder::lookupOrCreateWeak(const void* objectID, object_make_func make, + const void* makeArgs) { + Extras* e = getOrCreateExtras(); + LOG_ALWAYS_FATAL_IF(!e, "no memory"); + AutoMutex _l(e->mLock); + return e->mObjects.lookupOrCreateWeak(objectID, make, makeArgs); +} + BBinder* BBinder::localBinder() { return this; diff --git a/libs/binder/BpBinder.cpp b/libs/binder/BpBinder.cpp index b6d35ef3ef..d9b723108e 100644 --- a/libs/binder/BpBinder.cpp +++ b/libs/binder/BpBinder.cpp @@ -100,6 +100,36 @@ void* BpBinder::ObjectManager::detach(const void* objectID) { return value; } +namespace { +struct Tag { + wp<IBinder> binder; +}; +} // namespace + +static void cleanWeak(const void* /* id */, void* obj, void* /* cookie */) { + delete static_cast<Tag*>(obj); +} + +sp<IBinder> BpBinder::ObjectManager::lookupOrCreateWeak(const void* objectID, object_make_func make, + const void* makeArgs) { + entry_t& e = mObjects[objectID]; + if (e.object != nullptr) { + if (auto attached = static_cast<Tag*>(e.object)->binder.promote()) { + return attached; + } + } else { + e.object = new Tag; + LOG_ALWAYS_FATAL_IF(!e.object, "no more memory"); + } + sp<IBinder> newObj = make(makeArgs); + + static_cast<Tag*>(e.object)->binder = newObj; + e.cleanupCookie = nullptr; + e.func = cleanWeak; + + return newObj; +} + void BpBinder::ObjectManager::kill() { const size_t N = mObjects.size(); @@ -516,6 +546,12 @@ void BpBinder::withLock(const std::function<void()>& doWithLock) { doWithLock(); } +sp<IBinder> BpBinder::lookupOrCreateWeak(const void* objectID, object_make_func make, + const void* makeArgs) { + AutoMutex _l(mLock); + return mObjects.lookupOrCreateWeak(objectID, make, makeArgs); +} + BpBinder* BpBinder::remoteBinder() { return this; diff --git a/libs/binder/include/binder/Binder.h b/libs/binder/include/binder/Binder.h index 46223bb00e..88d9ca1d58 100644 --- a/libs/binder/include/binder/Binder.h +++ b/libs/binder/include/binder/Binder.h @@ -59,6 +59,8 @@ public: virtual void* findObject(const void* objectID) const final; virtual void* detachObject(const void* objectID) final; void withLock(const std::function<void()>& doWithLock); + sp<IBinder> lookupOrCreateWeak(const void* objectID, IBinder::object_make_func make, + const void* makeArgs); virtual BBinder* localBinder(); diff --git a/libs/binder/include/binder/BpBinder.h b/libs/binder/include/binder/BpBinder.h index 19ad5e6efe..4172cc511e 100644 --- a/libs/binder/include/binder/BpBinder.h +++ b/libs/binder/include/binder/BpBinder.h @@ -72,6 +72,8 @@ public: virtual void* findObject(const void* objectID) const final; virtual void* detachObject(const void* objectID) final; void withLock(const std::function<void()>& doWithLock); + sp<IBinder> lookupOrCreateWeak(const void* objectID, IBinder::object_make_func make, + const void* makeArgs); virtual BpBinder* remoteBinder(); @@ -96,6 +98,8 @@ public: IBinder::object_cleanup_func func); void* find(const void* objectID) const; void* detach(const void* objectID); + sp<IBinder> lookupOrCreateWeak(const void* objectID, IBinder::object_make_func make, + const void* makeArgs); void kill(); @@ -104,9 +108,9 @@ public: ObjectManager& operator=(const ObjectManager&); struct entry_t { - void* object; - void* cleanupCookie; - IBinder::object_cleanup_func func; + void* object = nullptr; + void* cleanupCookie = nullptr; + IBinder::object_cleanup_func func = nullptr; }; std::map<const void*, entry_t> mObjects; diff --git a/libs/binder/include/binder/Delegate.h b/libs/binder/include/binder/Delegate.h new file mode 100644 index 0000000000..8b3fc1cc10 --- /dev/null +++ b/libs/binder/include/binder/Delegate.h @@ -0,0 +1,93 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include <binder/IBinder.h> + +#ifndef __BIONIC__ +#ifndef __assert + +// defined differently by liblog +#pragma push_macro("LOG_PRI") +#ifdef LOG_PRI +#undef LOG_PRI +#endif +#include <syslog.h> +#pragma pop_macro("LOG_PRI") + +#define __assert(a, b, c) \ + do { \ + syslog(LOG_ERR, a ": " c); \ + abort(); \ + } while (false) +#endif // __assert +#endif // __BIONIC__ + +namespace android { + +/* + * Used to manage AIDL's *Delegator types. + * This is used to: + * - create a new *Delegator object that delegates to the binder argument. + * - or return an existing *Delegator object that already delegates to the + * binder argument. + * - or return the underlying delegate binder if the binder argument is a + * *Delegator itself. + * + * @param binder - the binder to delegate to or unwrap + * + * @return pointer to the *Delegator object or the unwrapped binder object + */ +template <typename T> +sp<T> delegate(const sp<T>& binder) { + const void* isDelegatorId = &T::descriptor; + const void* hasDelegatorId = &T::descriptor + 1; + // is binder itself a delegator? + if (T::asBinder(binder)->findObject(isDelegatorId)) { + if (T::asBinder(binder)->findObject(hasDelegatorId)) { + __assert(__FILE__, __LINE__, + "This binder has a delegator and is also delegator itself! This is " + "likely an unintended mixing of binders."); + return nullptr; + } + // unwrap the delegator + return static_cast<typename T::DefaultDelegator*>(binder.get())->getImpl(); + } + + struct MakeArgs { + const sp<T>* binder; + const void* id; + } makeArgs; + makeArgs.binder = &binder; + makeArgs.id = isDelegatorId; + + // the binder is not a delegator, so construct one + sp<IBinder> newDelegator = T::asBinder(binder)->lookupOrCreateWeak( + hasDelegatorId, + [](const void* args) -> sp<IBinder> { + auto delegator = sp<typename T::DefaultDelegator>::make( + *static_cast<const MakeArgs*>(args)->binder); + // make sure we know this binder is a delegator by attaching a unique ID + (void)delegator->attachObject(static_cast<const MakeArgs*>(args)->id, + reinterpret_cast<void*>(0x1), nullptr, nullptr); + return delegator; + }, + static_cast<const void*>(&makeArgs)); + return sp<typename T::DefaultDelegator>::cast(newDelegator); +} + +} // namespace android diff --git a/libs/binder/include/binder/IBinder.h b/libs/binder/include/binder/IBinder.h index 43fc5ff1a9..83aaca7f95 100644 --- a/libs/binder/include/binder/IBinder.h +++ b/libs/binder/include/binder/IBinder.h @@ -284,6 +284,9 @@ public: virtual BBinder* localBinder(); virtual BpBinder* remoteBinder(); + typedef sp<IBinder> (*object_make_func)(const void* makeArgs); + sp<IBinder> lookupOrCreateWeak(const void* objectID, object_make_func make, + const void* makeArgs); protected: virtual ~IBinder(); diff --git a/libs/binder/tests/binderBinderUnitTest.cpp b/libs/binder/tests/binderBinderUnitTest.cpp index ce2770f943..b6aed0db28 100644 --- a/libs/binder/tests/binderBinderUnitTest.cpp +++ b/libs/binder/tests/binderBinderUnitTest.cpp @@ -15,10 +15,11 @@ */ #include <binder/Binder.h> -#include <binder/IBinder.h> +#include <binder/IInterface.h> #include <gtest/gtest.h> using android::BBinder; +using android::IBinder; using android::OK; using android::sp; @@ -48,3 +49,49 @@ TEST(Binder, AttachExtension) { binder->setExtension(ext); EXPECT_EQ(ext, binder->getExtension()); } + +struct MyCookie { + bool* deleted; +}; + +class UniqueBinder : public BBinder { +public: + UniqueBinder(const void* c) : cookie(reinterpret_cast<const MyCookie*>(c)) { + *cookie->deleted = false; + } + ~UniqueBinder() { *cookie->deleted = true; } + const MyCookie* cookie; +}; + +static sp<IBinder> make(const void* arg) { + return sp<UniqueBinder>::make(arg); +} + +TEST(Binder, LookupOrCreateWeak) { + auto binder = sp<BBinder>::make(); + bool deleted; + MyCookie cookie = {&deleted}; + sp<IBinder> createdBinder = binder->lookupOrCreateWeak(kObjectId1, make, &cookie); + EXPECT_NE(binder, createdBinder); + + sp<IBinder> lookedUpBinder = binder->lookupOrCreateWeak(kObjectId1, make, &cookie); + EXPECT_EQ(createdBinder, lookedUpBinder); + EXPECT_FALSE(deleted); +} + +TEST(Binder, LookupOrCreateWeakDropSp) { + auto binder = sp<BBinder>::make(); + bool deleted1 = false; + bool deleted2 = false; + MyCookie cookie1 = {&deleted1}; + MyCookie cookie2 = {&deleted2}; + sp<IBinder> createdBinder = binder->lookupOrCreateWeak(kObjectId1, make, &cookie1); + EXPECT_NE(binder, createdBinder); + + createdBinder.clear(); + EXPECT_TRUE(deleted1); + + sp<IBinder> lookedUpBinder = binder->lookupOrCreateWeak(kObjectId1, make, &cookie2); + EXPECT_EQ(&cookie2, sp<UniqueBinder>::cast(lookedUpBinder)->cookie); + EXPECT_FALSE(deleted2); +} |