/* * Copyright (C) 2018 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. */ #include #include "ibinder_internal.h" #include #include #include "parcel_internal.h" #include "status_internal.h" #include #include #include #include using DeathRecipient = ::android::IBinder::DeathRecipient; using ::android::IBinder; using ::android::IResultReceiver; using ::android::Parcel; using ::android::sp; using ::android::status_t; using ::android::String16; using ::android::String8; using ::android::wp; namespace ABBinderTag { static const void* kId = "ABBinder"; static void* kValue = static_cast(new bool{true}); void clean(const void* /*id*/, void* /*obj*/, void* /*cookie*/){/* do nothing */}; static void attach(const sp& binder) { binder->attachObject(kId, kValue, nullptr /*cookie*/, clean); } static bool has(const sp& binder) { return binder != nullptr && binder->findObject(kId) == kValue; } } // namespace ABBinderTag namespace ABpBinderTag { static std::mutex gLock; static const void* kId = "ABpBinder"; struct Value { wp binder; }; void clean(const void* id, void* obj, void* cookie) { CHECK(id == kId) << id << " " << obj << " " << cookie; delete static_cast(obj); }; } // namespace ABpBinderTag AIBinder::AIBinder(const AIBinder_Class* clazz) : mClazz(clazz) {} AIBinder::~AIBinder() {} bool AIBinder::associateClass(const AIBinder_Class* clazz) { if (clazz == nullptr) return false; if (mClazz == clazz) return true; String8 newDescriptor(clazz->getInterfaceDescriptor()); if (mClazz != nullptr) { String8 currentDescriptor(mClazz->getInterfaceDescriptor()); if (newDescriptor == currentDescriptor) { LOG(ERROR) << __func__ << ": Class descriptors '" << currentDescriptor << "' match during associateClass, but they are different class objects. " "Class descriptor collision?"; } 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() << "'."; } // 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 false; } // if this is a local object, it's not one known to libbinder_ndk mClazz = clazz; return true; } ABBinder::ABBinder(const AIBinder_Class* clazz, void* userData) : AIBinder(clazz), BBinder(), mUserData(userData) { CHECK(clazz != nullptr); } ABBinder::~ABBinder() { getClass()->onDestroy(mUserData); } const String16& ABBinder::getInterfaceDescriptor() const { return getClass()->getInterfaceDescriptor(); } status_t ABBinder::dump(int fd, const ::android::Vector& args) { AIBinder_onDump onDump = getClass()->onDump; if (onDump == nullptr) { return STATUS_OK; } // technically UINT32_MAX would be okay here, but INT32_MAX is expected since this may be // null in Java if (args.size() > INT32_MAX) { LOG(ERROR) << "ABBinder::dump received too many arguments: " << args.size(); return STATUS_BAD_VALUE; } std::vector utf8Args; // owns memory of utf8s utf8Args.reserve(args.size()); std::vector utf8Pointers; // what can be passed over NDK API utf8Pointers.reserve(args.size()); for (size_t i = 0; i < args.size(); i++) { utf8Args.push_back(String8(args[i])); utf8Pointers.push_back(utf8Args[i].c_str()); } return onDump(this, fd, utf8Pointers.data(), utf8Pointers.size()); } status_t ABBinder::onTransact(transaction_code_t code, const Parcel& data, Parcel* reply, binder_flags_t flags) { if (isUserCommand(code)) { if (!data.checkInterface(this)) { return STATUS_BAD_TYPE; } const AParcel in = AParcel::readOnly(this, &data); AParcel out = AParcel(this, reply, false /*owns*/); binder_status_t status = getClass()->onTransact(this, code, &in, &out); return PruneStatusT(status); } else if (code == SHELL_COMMAND_TRANSACTION) { int in = data.readFileDescriptor(); int out = data.readFileDescriptor(); int err = data.readFileDescriptor(); int argc = data.readInt32(); std::vector utf8Args; // owns memory of utf8s std::vector utf8Pointers; // what can be passed over NDK API for (int i = 0; i < argc && data.dataAvail() > 0; i++) { utf8Args.push_back(String8(data.readString16())); utf8Pointers.push_back(utf8Args[i].c_str()); } data.readStrongBinder(); // skip over the IShellCallback sp resultReceiver = IResultReceiver::asInterface(data.readStrongBinder()); // Shell commands should only be callable by ADB. uid_t uid = AIBinder_getCallingUid(); if (uid != AID_ROOT && uid != AID_SHELL) { if (resultReceiver != nullptr) { resultReceiver->send(-1); } return STATUS_PERMISSION_DENIED; } // Check that the file descriptors are valid. if (in == STATUS_BAD_TYPE || out == STATUS_BAD_TYPE || err == STATUS_BAD_TYPE) { if (resultReceiver != nullptr) { resultReceiver->send(-1); } return STATUS_BAD_VALUE; } binder_status_t status = getClass()->handleShellCommand( this, in, out, err, utf8Pointers.data(), utf8Pointers.size()); if (resultReceiver != nullptr) { resultReceiver->send(status); } return status; } else { return BBinder::onTransact(code, data, reply, flags); } } ABpBinder::ABpBinder(const ::android::sp<::android::IBinder>& binder) : AIBinder(nullptr /*clazz*/), BpRefBase(binder) { CHECK(binder != nullptr); } ABpBinder::~ABpBinder() {} void ABpBinder::onLastStrongRef(const void* id) { { std::lock_guard lock(ABpBinderTag::gLock); // Since ABpBinder is OBJECT_LIFETIME_WEAK, we must remove this weak reference in order for // the ABpBinder to be deleted. Since a strong reference to this ABpBinder object should no // longer be able to exist at the time of this method call, there is no longer a need to // recover it. ABpBinderTag::Value* value = static_cast(remote()->findObject(ABpBinderTag::kId)); if (value != nullptr) { value->binder = nullptr; } } BpRefBase::onLastStrongRef(id); } sp ABpBinder::lookupOrCreateFromBinder(const ::android::sp<::android::IBinder>& binder) { if (binder == nullptr) { return nullptr; } if (ABBinderTag::has(binder)) { return static_cast(binder.get()); } // The following code ensures that for a given binder object (remote or local), if it is not an // ABBinder then at most one ABpBinder object exists in a given process representing it. std::lock_guard lock(ABpBinderTag::gLock); ABpBinderTag::Value* value = static_cast(binder->findObject(ABpBinderTag::kId)); if (value == nullptr) { value = new ABpBinderTag::Value; binder->attachObject(ABpBinderTag::kId, static_cast(value), nullptr /*cookie*/, ABpBinderTag::clean); } sp ret = value->binder.promote(); if (ret == nullptr) { ret = new ABpBinder(binder); value->binder = ret; } return ret; } struct AIBinder_Weak { wp binder; }; AIBinder_Weak* AIBinder_Weak_new(AIBinder* binder) { if (binder == nullptr) { return nullptr; } return new AIBinder_Weak{wp(binder)}; } void AIBinder_Weak_delete(AIBinder_Weak* weakBinder) { delete weakBinder; } AIBinder* AIBinder_Weak_promote(AIBinder_Weak* weakBinder) { if (weakBinder == nullptr) { return nullptr; } sp binder = weakBinder->binder.promote(); AIBinder_incStrong(binder.get()); return binder.get(); } AIBinder_Class::AIBinder_Class(const char* interfaceDescriptor, AIBinder_Class_onCreate onCreate, AIBinder_Class_onDestroy onDestroy, AIBinder_Class_onTransact onTransact) : onCreate(onCreate), onDestroy(onDestroy), onTransact(onTransact), mInterfaceDescriptor(interfaceDescriptor) {} AIBinder_Class* AIBinder_Class_define(const char* interfaceDescriptor, AIBinder_Class_onCreate onCreate, AIBinder_Class_onDestroy onDestroy, AIBinder_Class_onTransact onTransact) { if (interfaceDescriptor == nullptr || onCreate == nullptr || onDestroy == nullptr || onTransact == nullptr) { return nullptr; } return new AIBinder_Class(interfaceDescriptor, onCreate, onDestroy, onTransact); } void AIBinder_Class_setOnDump(AIBinder_Class* clazz, AIBinder_onDump onDump) { CHECK(clazz != nullptr) << "setOnDump requires non-null clazz"; // this is required to be called before instances are instantiated clazz->onDump = onDump; } void AIBinder_Class_setHandleShellCommand(AIBinder_Class* clazz, AIBinder_handleShellCommand handleShellCommand) { CHECK(clazz != nullptr) << "setHandleShellCommand requires non-null clazz"; clazz->handleShellCommand = handleShellCommand; } void AIBinder_DeathRecipient::TransferDeathRecipient::binderDied(const wp& who) { CHECK(who == mWho); mOnDied(mCookie); sp recipient = mParentRecipient.promote(); sp strongWho = who.promote(); // otherwise this will be cleaned up later with pruneDeadTransferEntriesLocked if (recipient != nullptr && strongWho != nullptr) { status_t result = recipient->unlinkToDeath(strongWho, mCookie); if (result != ::android::DEAD_OBJECT) { LOG(WARNING) << "Unlinking to dead binder resulted in: " << result; } } mWho = nullptr; } AIBinder_DeathRecipient::AIBinder_DeathRecipient(AIBinder_DeathRecipient_onBinderDied onDied) : mOnDied(onDied) { CHECK(onDied != nullptr); } void AIBinder_DeathRecipient::pruneDeadTransferEntriesLocked() { mDeathRecipients.erase(std::remove_if(mDeathRecipients.begin(), mDeathRecipients.end(), [](const sp& tdr) { return tdr->getWho() == nullptr; }), mDeathRecipients.end()); } binder_status_t AIBinder_DeathRecipient::linkToDeath(sp binder, void* cookie) { CHECK(binder != nullptr); std::lock_guard l(mDeathRecipientsMutex); sp recipient = new TransferDeathRecipient(binder, cookie, this, mOnDied); status_t status = binder->linkToDeath(recipient, cookie, 0 /*flags*/); if (status != STATUS_OK) { return PruneStatusT(status); } mDeathRecipients.push_back(recipient); pruneDeadTransferEntriesLocked(); return STATUS_OK; } binder_status_t AIBinder_DeathRecipient::unlinkToDeath(sp binder, void* cookie) { CHECK(binder != nullptr); std::lock_guard l(mDeathRecipientsMutex); for (auto it = mDeathRecipients.rbegin(); it != mDeathRecipients.rend(); ++it) { sp recipient = *it; if (recipient->getCookie() == cookie && recipient->getWho() == binder) { mDeathRecipients.erase(it.base() - 1); status_t status = binder->unlinkToDeath(recipient, cookie, 0 /*flags*/); if (status != ::android::OK) { LOG(ERROR) << __func__ << ": removed reference to death recipient but unlink failed."; } return PruneStatusT(status); } } return STATUS_NAME_NOT_FOUND; } // start of C-API methods AIBinder* AIBinder_new(const AIBinder_Class* clazz, void* args) { if (clazz == nullptr) { LOG(ERROR) << __func__ << ": Must provide class to construct local binder."; return nullptr; } void* userData = clazz->onCreate(args); sp ret = new ABBinder(clazz, userData); ABBinderTag::attach(ret->getBinder()); AIBinder_incStrong(ret.get()); return ret.get(); } bool AIBinder_isRemote(const AIBinder* binder) { if (binder == nullptr) { return false; } return binder->isRemote(); } bool AIBinder_isAlive(const AIBinder* binder) { if (binder == nullptr) { return false; } return const_cast(binder)->getBinder()->isBinderAlive(); } binder_status_t AIBinder_ping(AIBinder* binder) { if (binder == nullptr) { return STATUS_UNEXPECTED_NULL; } return PruneStatusT(binder->getBinder()->pingBinder()); } binder_status_t AIBinder_dump(AIBinder* binder, int fd, const char** args, uint32_t numArgs) { if (binder == nullptr) { return STATUS_UNEXPECTED_NULL; } ABBinder* bBinder = binder->asABBinder(); if (bBinder != nullptr) { AIBinder_onDump onDump = binder->getClass()->onDump; if (onDump == nullptr) { return STATUS_OK; } return PruneStatusT(onDump(bBinder, fd, args, numArgs)); } ::android::Vector utf16Args; utf16Args.setCapacity(numArgs); for (uint32_t i = 0; i < numArgs; i++) { utf16Args.push(String16(String8(args[i]))); } status_t status = binder->getBinder()->dump(fd, utf16Args); return PruneStatusT(status); } binder_status_t AIBinder_linkToDeath(AIBinder* binder, AIBinder_DeathRecipient* recipient, void* cookie) { if (binder == nullptr || recipient == nullptr) { LOG(ERROR) << __func__ << ": Must provide binder and recipient."; return STATUS_UNEXPECTED_NULL; } // returns binder_status_t return recipient->linkToDeath(binder->getBinder(), cookie); } binder_status_t AIBinder_unlinkToDeath(AIBinder* binder, AIBinder_DeathRecipient* recipient, void* cookie) { if (binder == nullptr || recipient == nullptr) { LOG(ERROR) << __func__ << ": Must provide binder and recipient."; return STATUS_UNEXPECTED_NULL; } // returns binder_status_t return recipient->unlinkToDeath(binder->getBinder(), cookie); } uid_t AIBinder_getCallingUid() { return ::android::IPCThreadState::self()->getCallingUid(); } pid_t AIBinder_getCallingPid() { return ::android::IPCThreadState::self()->getCallingPid(); } void AIBinder_incStrong(AIBinder* binder) { if (binder == nullptr) { return; } binder->incStrong(nullptr); } void AIBinder_decStrong(AIBinder* binder) { if (binder == nullptr) { LOG(ERROR) << __func__ << ": on null binder"; return; } binder->decStrong(nullptr); } int32_t AIBinder_debugGetRefCount(AIBinder* binder) { if (binder == nullptr) { LOG(ERROR) << __func__ << ": on null binder"; return -1; } return binder->getStrongCount(); } bool AIBinder_associateClass(AIBinder* binder, const AIBinder_Class* clazz) { if (binder == nullptr) { return false; } return binder->associateClass(clazz); } const AIBinder_Class* AIBinder_getClass(AIBinder* binder) { if (binder == nullptr) { return nullptr; } return binder->getClass(); } void* AIBinder_getUserData(AIBinder* binder) { if (binder == nullptr) { return nullptr; } ABBinder* bBinder = binder->asABBinder(); if (bBinder == nullptr) { return nullptr; } return bBinder->getUserData(); } binder_status_t AIBinder_prepareTransaction(AIBinder* binder, AParcel** in) { if (binder == nullptr || in == nullptr) { LOG(ERROR) << __func__ << ": requires non-null parameters."; return STATUS_UNEXPECTED_NULL; } const AIBinder_Class* clazz = binder->getClass(); if (clazz == nullptr) { LOG(ERROR) << __func__ << ": Class must be defined for a remote binder transaction. See " "AIBinder_associateClass."; return STATUS_INVALID_OPERATION; } if (!binder->isRemote()) { LOG(WARNING) << "A binder object at " << binder << " is being transacted on, however, this object is in the same process as " "its proxy. Transacting with this binder is expensive compared to just " "calling the corresponding functionality in the same process."; } *in = new AParcel(binder); status_t status = (*in)->get()->writeInterfaceToken(clazz->getInterfaceDescriptor()); binder_status_t ret = PruneStatusT(status); if (ret != STATUS_OK) { delete *in; *in = nullptr; } return ret; } static void DestroyParcel(AParcel** parcel) { delete *parcel; *parcel = nullptr; } binder_status_t AIBinder_transact(AIBinder* binder, transaction_code_t code, AParcel** in, AParcel** out, binder_flags_t flags) { if (in == nullptr) { LOG(ERROR) << __func__ << ": requires non-null in parameter"; return STATUS_UNEXPECTED_NULL; } using AutoParcelDestroyer = std::unique_ptr; // This object is the input to the transaction. This function takes ownership of it and deletes // it. AutoParcelDestroyer forIn(in, DestroyParcel); if (!isUserCommand(code)) { LOG(ERROR) << __func__ << ": Only user-defined transactions can be made from the NDK."; return STATUS_UNKNOWN_TRANSACTION; } constexpr binder_flags_t kAllFlags = FLAG_PRIVATE_VENDOR | FLAG_ONEWAY; if ((flags & ~kAllFlags) != 0) { LOG(ERROR) << __func__ << ": Unrecognized flags sent: " << flags; return STATUS_BAD_VALUE; } if (binder == nullptr || *in == nullptr || out == nullptr) { LOG(ERROR) << __func__ << ": requires non-null parameters."; return STATUS_UNEXPECTED_NULL; } if ((*in)->getBinder() != binder) { LOG(ERROR) << __func__ << ": parcel is associated with binder object " << binder << " but called with " << (*in)->getBinder(); return STATUS_BAD_VALUE; } *out = new AParcel(binder); status_t status = binder->getBinder()->transact(code, *(*in)->get(), (*out)->get(), flags); binder_status_t ret = PruneStatusT(status); if (ret != STATUS_OK) { delete *out; *out = nullptr; } return ret; } AIBinder_DeathRecipient* AIBinder_DeathRecipient_new( AIBinder_DeathRecipient_onBinderDied onBinderDied) { if (onBinderDied == nullptr) { LOG(ERROR) << __func__ << ": requires non-null onBinderDied parameter."; return nullptr; } auto ret = new AIBinder_DeathRecipient(onBinderDied); ret->incStrong(nullptr); return ret; } void AIBinder_DeathRecipient_delete(AIBinder_DeathRecipient* recipient) { if (recipient == nullptr) { return; } recipient->decStrong(nullptr); } binder_status_t AIBinder_getExtension(AIBinder* binder, AIBinder** outExt) { if (binder == nullptr || outExt == nullptr) { if (outExt != nullptr) { *outExt = nullptr; } return STATUS_UNEXPECTED_NULL; } sp ext; status_t res = binder->getBinder()->getExtension(&ext); if (res != android::OK) { *outExt = nullptr; return PruneStatusT(res); } sp ret = ABpBinder::lookupOrCreateFromBinder(ext); if (ret != nullptr) ret->incStrong(binder); *outExt = ret.get(); return STATUS_OK; } binder_status_t AIBinder_setExtension(AIBinder* binder, AIBinder* ext) { if (binder == nullptr || ext == nullptr) { return STATUS_UNEXPECTED_NULL; } ABBinder* rawBinder = binder->asABBinder(); if (rawBinder == nullptr) { return STATUS_INVALID_OPERATION; } rawBinder->setExtension(ext->getBinder()); return STATUS_OK; }