diff options
| -rw-r--r-- | libs/binder/ndk/AIBinder.cpp | 97 | ||||
| -rw-r--r-- | libs/binder/ndk/AIBinder_internal.h | 26 | ||||
| -rw-r--r-- | libs/binder/ndk/AParcel.cpp | 10 | ||||
| -rw-r--r-- | libs/binder/ndk/AServiceManager.cpp | 6 | ||||
| -rw-r--r-- | libs/binder/ndk/include_ndk/android/binder_ibinder.h | 7 | ||||
| -rw-r--r-- | libs/binder/ndk/test/iface.cpp | 7 |
6 files changed, 80 insertions, 73 deletions
diff --git a/libs/binder/ndk/AIBinder.cpp b/libs/binder/ndk/AIBinder.cpp index d0ce98db93..fe07914c04 100644 --- a/libs/binder/ndk/AIBinder.cpp +++ b/libs/binder/ndk/AIBinder.cpp @@ -28,14 +28,29 @@ using ::android::sp; using ::android::String16; using ::android::wp; +namespace ABBinderTag { + +static const void* kId = "ABBinder"; +static void* kValue = static_cast<void*>(new bool{true}); +void cleanId(const void* /*id*/, void* /*obj*/, void* /*cookie*/){/* do nothing */}; + +static void attach(const sp<IBinder>& binder) { + binder->attachObject(kId, kValue, nullptr /*cookie*/, cleanId); +} +static bool has(const sp<IBinder>& binder) { + return binder != nullptr && binder->findObject(kId) == kValue; +} + +} // namespace ABBinderTag + AIBinder::AIBinder(const AIBinder_Class* clazz) : mClazz(clazz) {} AIBinder::~AIBinder() {} -sp<AIBinder> AIBinder::associateClass(const AIBinder_Class* clazz) { +bool AIBinder::associateClass(const AIBinder_Class* clazz) { using ::android::String8; - if (clazz == nullptr) return nullptr; - if (mClazz == clazz) return this; + if (clazz == nullptr) return false; + if (mClazz == clazz) return true; String8 newDescriptor(clazz->getInterfaceDescriptor()); @@ -45,42 +60,31 @@ sp<AIBinder> AIBinder::associateClass(const AIBinder_Class* clazz) { LOG(ERROR) << __func__ << ": Class descriptors '" << currentDescriptor << "' match during associateClass, but they are different class objects. " "Class descriptor collision?"; - return nullptr; + } else { + LOG(ERROR) << __func__ + << ": Class cannot be associated on object which already has a class. " + "Trying to associate to '" + << newDescriptor.c_str() << "' but already set to '" + << currentDescriptor.c_str() << "'."; } - LOG(ERROR) << __func__ - << ": Class cannot be associated on object which already has a class. Trying to " - "associate to '" - << newDescriptor.c_str() << "' but already set to '" << currentDescriptor.c_str() - << "'."; - return nullptr; + // always a failure because we know mClazz != clazz + return false; } + CHECK(asABpBinder() != nullptr); // ABBinder always has a descriptor + String8 descriptor(getBinder()->getInterfaceDescriptor()); if (descriptor != newDescriptor) { LOG(ERROR) << __func__ << ": Expecting binder to have class '" << newDescriptor.c_str() << "' but descriptor is actually '" << descriptor.c_str() << "'."; - return nullptr; - } - - // The descriptor matches, so if it is local, this is guaranteed to be the libbinder_ndk class. - // An error here can occur if there is a conflict between descriptors (two unrelated classes - // define the same descriptor), but this should never happen. - - // if this is a local ABBinder, mClazz should be non-null - CHECK(asABBinder() == nullptr); - CHECK(asABpBinder() != nullptr); - - if (!isRemote()) { - // ABpBinder but proxy to a local object. Therefore that local object must be an ABBinder. - ABBinder* binder = static_cast<ABBinder*>(getBinder().get()); - return binder; + return false; } - // This is a remote object + // if this is a local object, it's not one known to libbinder_ndk mClazz = clazz; - return this; + return true; } ABBinder::ABBinder(const AIBinder_Class* clazz, void* userData) @@ -111,12 +115,22 @@ binder_status_t ABBinder::onTransact(transaction_code_t code, const Parcel& data } } -ABpBinder::ABpBinder(::android::sp<::android::IBinder> binder) +ABpBinder::ABpBinder(const ::android::sp<::android::IBinder>& binder) : AIBinder(nullptr /*clazz*/), BpRefBase(binder) { CHECK(binder != nullptr); } ABpBinder::~ABpBinder() {} +sp<AIBinder> ABpBinder::fromBinder(const ::android::sp<::android::IBinder>& binder) { + if (binder == nullptr) { + return nullptr; + } + if (ABBinderTag::has(binder)) { + return static_cast<ABBinder*>(binder.get()); + } + return new ABpBinder(binder); +} + struct AIBinder_Weak { wp<AIBinder> binder; }; @@ -162,9 +176,11 @@ AIBinder* AIBinder_new(const AIBinder_Class* clazz, void* args) { void* userData = clazz->onCreate(args); - AIBinder* ret = new ABBinder(clazz, userData); - AIBinder_incStrong(ret); - return ret; + sp<AIBinder> ret = new ABBinder(clazz, userData); + ABBinderTag::attach(ret->getBinder()); + + AIBinder_incStrong(ret.get()); + return ret.get(); } bool AIBinder_isRemote(AIBinder* binder) { @@ -200,23 +216,12 @@ int32_t AIBinder_debugGetRefCount(AIBinder* binder) { return binder->getStrongCount(); } -void AIBinder_associateClass(AIBinder** binder, const AIBinder_Class* clazz) { - if (binder == nullptr || *binder == nullptr) { - return; - } - - sp<AIBinder> result = (*binder)->associateClass(clazz); - - // This function takes one refcount of 'binder' and delivers one refcount of 'result' to the - // callee. First we give the callee their refcount and then take it away from binder. This is - // done in this order in order to handle the case that the result and the binder are the same - // object. - if (result != nullptr) { - AIBinder_incStrong(result.get()); +bool AIBinder_associateClass(AIBinder* binder, const AIBinder_Class* clazz) { + if (binder == nullptr) { + return false; } - AIBinder_decStrong(*binder); - *binder = result.get(); // Maybe no-op + return binder->associateClass(clazz); } const AIBinder_Class* AIBinder_getClass(AIBinder* binder) { diff --git a/libs/binder/ndk/AIBinder_internal.h b/libs/binder/ndk/AIBinder_internal.h index d44b937ec7..ed3b37b9f2 100644 --- a/libs/binder/ndk/AIBinder_internal.h +++ b/libs/binder/ndk/AIBinder_internal.h @@ -35,24 +35,14 @@ struct AIBinder : public virtual ::android::RefBase { AIBinder(const AIBinder_Class* clazz); virtual ~AIBinder(); - // This returns an AIBinder object with this class associated. If the class is already - // associated, 'this' will be returned. If there is a local AIBinder implementation, that will - // be returned. If this is a remote object, the class will be associated and this will be ready - // to be used for transactions. - ::android::sp<AIBinder> associateClass(const AIBinder_Class* clazz); + bool associateClass(const AIBinder_Class* clazz); const AIBinder_Class* getClass() const { return mClazz; } - // This does not create the binder if it does not exist in the process. virtual ::android::sp<::android::IBinder> getBinder() = 0; virtual ABBinder* asABBinder() { return nullptr; } virtual ABpBinder* asABpBinder() { return nullptr; } - bool isRemote() { - auto binder = getBinder(); - // if the binder is nullptr, then it is a local object which hasn't been sent out of process - // yet. - return binder != nullptr && binder->remoteBinder() != nullptr; - } + bool isRemote() { return getBinder()->remoteBinder() != nullptr; } private: // AIBinder instance is instance of this class for a local object. In order to transact on a @@ -63,7 +53,6 @@ private: // This is a local AIBinder object with a known class. struct ABBinder : public AIBinder, public ::android::BBinder { - ABBinder(const AIBinder_Class* clazz, void* userData); virtual ~ABBinder(); void* getUserData() { return mUserData; } @@ -76,6 +65,11 @@ struct ABBinder : public AIBinder, public ::android::BBinder { ::android::Parcel* reply, binder_flags_t flags) override; private: + ABBinder(const AIBinder_Class* clazz, void* userData); + + // only thing that should create an ABBinder + friend AIBinder* AIBinder_new(const AIBinder_Class*, void*); + // Can contain implementation if this is a local binder. This can still be nullptr for a local // binder. If it is nullptr, the implication is the implementation state is entirely external to // this object and the functionality provided in the AIBinder_Class is sufficient. @@ -85,11 +79,15 @@ private: // This binder object may be remote or local (even though it is 'Bp'). It is not yet associated with // a class. struct ABpBinder : public AIBinder, public ::android::BpRefBase { - ABpBinder(::android::sp<::android::IBinder> binder); + static ::android::sp<AIBinder> fromBinder(const ::android::sp<::android::IBinder>& binder); + virtual ~ABpBinder(); ::android::sp<::android::IBinder> getBinder() override { return remote(); } ABpBinder* asABpBinder() override { return this; } + +private: + ABpBinder(const ::android::sp<::android::IBinder>& binder); }; struct AIBinder_Class { diff --git a/libs/binder/ndk/AParcel.cpp b/libs/binder/ndk/AParcel.cpp index b63b138dc4..f39e7321af 100644 --- a/libs/binder/ndk/AParcel.cpp +++ b/libs/binder/ndk/AParcel.cpp @@ -34,8 +34,9 @@ binder_status_t AParcel_readStrongBinder(const AParcel* parcel, AIBinder** binde if (status != EX_NONE) { return status; } - *binder = new ABpBinder(readBinder); - AIBinder_incStrong(*binder); + sp<AIBinder> ret = ABpBinder::fromBinder(readBinder); + AIBinder_incStrong(ret.get()); + *binder = ret.get(); return status; } binder_status_t AParcel_readNullableStrongBinder(const AParcel* parcel, AIBinder** binder) { @@ -44,8 +45,9 @@ binder_status_t AParcel_readNullableStrongBinder(const AParcel* parcel, AIBinder if (status != EX_NONE) { return status; } - *binder = new ABpBinder(readBinder); - AIBinder_incStrong(*binder); + sp<AIBinder> ret = ABpBinder::fromBinder(readBinder); + AIBinder_incStrong(ret.get()); + *binder = ret.get(); return status; } diff --git a/libs/binder/ndk/AServiceManager.cpp b/libs/binder/ndk/AServiceManager.cpp index f61b914089..3979945e45 100644 --- a/libs/binder/ndk/AServiceManager.cpp +++ b/libs/binder/ndk/AServiceManager.cpp @@ -41,7 +41,7 @@ AIBinder* AServiceManager_getService(const char* instance) { sp<IServiceManager> sm = defaultServiceManager(); sp<IBinder> binder = sm->getService(String16(instance)); - AIBinder* ret = new ABpBinder(binder); - AIBinder_incStrong(ret); - return ret; + sp<AIBinder> ret = ABpBinder::fromBinder(binder); + AIBinder_incStrong(ret.get()); + return ret.get(); } diff --git a/libs/binder/ndk/include_ndk/android/binder_ibinder.h b/libs/binder/ndk/include_ndk/android/binder_ibinder.h index 23136a2de8..fb82ab6ba9 100644 --- a/libs/binder/ndk/include_ndk/android/binder_ibinder.h +++ b/libs/binder/ndk/include_ndk/android/binder_ibinder.h @@ -167,11 +167,10 @@ int32_t AIBinder_debugGetRefCount(AIBinder* binder); * However, if an object is just intended to be passed through to another process or used as a * handle this need not be called. * - * The binder parameter may or may not be updated. If it is updated, the ownership of the original - * object is transferred to the new object. If the class association fails, ownership of the binder - * is lost, and it is set to nullptr. + * This returns true if the class association succeeds. If it fails, no change is made to the + * binder object. */ -void AIBinder_associateClass(AIBinder** binder, const AIBinder_Class* clazz); +bool AIBinder_associateClass(AIBinder* binder, const AIBinder_Class* clazz); /* * Returns the class that this binder was constructed with or associated with. diff --git a/libs/binder/ndk/test/iface.cpp b/libs/binder/ndk/test/iface.cpp index eed09f02c7..1317a74c59 100644 --- a/libs/binder/ndk/test/iface.cpp +++ b/libs/binder/ndk/test/iface.cpp @@ -118,12 +118,15 @@ binder_status_t IFoo::addService(const char* instance) { sp<IFoo> IFoo::getService(const char* instance) { AIBinder* binder = AServiceManager_getService(instance); // maybe nullptr - AIBinder_associateClass(&binder, IFoo::kClass); - if (binder == nullptr) { return nullptr; } + if (!AIBinder_associateClass(binder, IFoo::kClass)) { + AIBinder_decStrong(binder); + return nullptr; + } + if (AIBinder_isRemote(binder)) { sp<IFoo> ret = new BpFoo(binder); // takes ownership of binder return ret; |