diff options
-rw-r--r-- | libs/binder/OS.h | 1 | ||||
-rw-r--r-- | libs/binder/OS_android.cpp | 4 | ||||
-rw-r--r-- | libs/binder/OS_non_android_linux.cpp | 4 | ||||
-rw-r--r-- | libs/binder/include/binder/Trace.h | 1 | ||||
-rw-r--r-- | libs/binder/ndk/ibinder.cpp | 133 | ||||
-rw-r--r-- | libs/binder/ndk/ibinder_internal.h | 7 | ||||
-rw-r--r-- | libs/binder/ndk/include_cpp/android/binder_interface_utils.h | 28 | ||||
-rw-r--r-- | libs/binder/ndk/include_ndk/android/binder_ibinder.h | 44 | ||||
-rw-r--r-- | libs/binder/ndk/libbinder_ndk.map.txt | 4 | ||||
-rw-r--r-- | libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp | 31 | ||||
-rw-r--r-- | libs/binder/tests/parcel_fuzzer/binder_ndk.cpp | 3 | ||||
-rw-r--r-- | libs/binder/trusty/OS.cpp | 4 |
12 files changed, 260 insertions, 4 deletions
diff --git a/libs/binder/OS.h b/libs/binder/OS.h index 04869a170f..64b1fd48fd 100644 --- a/libs/binder/OS.h +++ b/libs/binder/OS.h @@ -27,6 +27,7 @@ namespace android::binder::os { LIBBINDER_EXPORTED void trace_begin(uint64_t tag, const char* name); LIBBINDER_EXPORTED void trace_end(uint64_t tag); LIBBINDER_EXPORTED void trace_int(uint64_t tag, const char* name, int32_t value); +LIBBINDER_EXPORTED uint64_t get_trace_enabled_tags(); status_t setNonBlocking(borrowed_fd fd); diff --git a/libs/binder/OS_android.cpp b/libs/binder/OS_android.cpp index 893ee15578..4e9230ce58 100644 --- a/libs/binder/OS_android.cpp +++ b/libs/binder/OS_android.cpp @@ -48,6 +48,10 @@ void trace_int(uint64_t tag, const char* name, int32_t value) { atrace_int(tag, name, value); } +uint64_t get_trace_enabled_tags() { + return atrace_enabled_tags; +} + } // namespace os // Legacy trace symbol. To be removed once all of downstream rebuilds. diff --git a/libs/binder/OS_non_android_linux.cpp b/libs/binder/OS_non_android_linux.cpp index 0c64eb61c6..6bba823897 100644 --- a/libs/binder/OS_non_android_linux.cpp +++ b/libs/binder/OS_non_android_linux.cpp @@ -41,6 +41,10 @@ void trace_end(uint64_t) {} void trace_int(uint64_t, const char*, int32_t) {} +uint64_t get_trace_enabled_tags() { + return 0; +} + uint64_t GetThreadId() { return syscall(__NR_gettid); } diff --git a/libs/binder/include/binder/Trace.h b/libs/binder/include/binder/Trace.h index 2f450cb36b..a3e6c8a12b 100644 --- a/libs/binder/include/binder/Trace.h +++ b/libs/binder/include/binder/Trace.h @@ -42,6 +42,7 @@ namespace os { void trace_begin(uint64_t tag, const char* name); void trace_end(uint64_t tag); void trace_int(uint64_t tag, const char* name, int32_t value); +uint64_t get_trace_enabled_tags(); } // namespace os class LIBBINDER_EXPORTED ScopedTrace { diff --git a/libs/binder/ndk/ibinder.cpp b/libs/binder/ndk/ibinder.cpp index af280d38a3..ff31dd0193 100644 --- a/libs/binder/ndk/ibinder.cpp +++ b/libs/binder/ndk/ibinder.cpp @@ -18,8 +18,10 @@ #include <android/binder_ibinder_platform.h> #include <android/binder_stability.h> #include <android/binder_status.h> +#include <binder/Functional.h> #include <binder/IPCThreadState.h> #include <binder/IResultReceiver.h> +#include <binder/Trace.h> #if __has_include(<private/android_filesystem_config.h>) #include <private/android_filesystem_config.h> #endif @@ -40,6 +42,23 @@ using ::android::statusToString; using ::android::String16; using ::android::String8; using ::android::wp; +using ::android::binder::impl::make_scope_guard; +using ::android::binder::impl::scope_guard; +using ::android::binder::os::get_trace_enabled_tags; +using ::android::binder::os::trace_begin; +using ::android::binder::os::trace_end; + +// transaction codes for getInterfaceHash and getInterfaceVersion are defined +// in file : system/tools/aidl/aidl.cpp +static constexpr int kGetInterfaceVersionId = 0x00fffffe; +static const char* kInterfaceVersion = "getInterfaceVersion"; +static constexpr int kGetInterfaceHashId = 0x00fffffd; +static const char* kInterfaceHash = "getInterfaceHash"; +static const char* kNdkTrace = "AIDL::ndk::"; +static const char* kServerTrace = "::server"; +static const char* kClientTrace = "::client"; +static const char* kSeparator = "::"; +static const char* kUnknownCode = "Unknown_Transaction_Code:"; namespace ABBinderTag { @@ -90,6 +109,51 @@ static std::string SanitizeString(const String16& str) { return sanitized; } +const std::string getMethodName(const AIBinder_Class* clazz, transaction_code_t code) { + // TODO(b/150155678) - Move getInterfaceHash and getInterfaceVersion to libbinder and remove + // hardcoded cases. + if (code <= clazz->getTransactionCodeToFunctionLength() && code >= FIRST_CALL_TRANSACTION) { + // Codes have FIRST_CALL_TRANSACTION as added offset. Subtract to access function name + return clazz->getFunctionName(code); + } else if (code == kGetInterfaceVersionId) { + return kInterfaceVersion; + } else if (code == kGetInterfaceHashId) { + return kInterfaceHash; + } + return kUnknownCode + std::to_string(code); +} + +const std::string getTraceSectionName(const AIBinder_Class* clazz, transaction_code_t code, + bool isServer) { + if (clazz == nullptr) { + ALOGE("class associated with binder is null. Class is needed to add trace with interface " + "name and function name"); + return kNdkTrace; + } + + const std::string descriptor = clazz->getInterfaceDescriptorUtf8(); + const std::string methodName = getMethodName(clazz, code); + + size_t traceSize = + strlen(kNdkTrace) + descriptor.size() + strlen(kSeparator) + methodName.size(); + traceSize += isServer ? strlen(kServerTrace) : strlen(kClientTrace); + + std::string trace; + // reserve to avoid repeated allocations + trace.reserve(traceSize); + + trace += kNdkTrace; + trace += clazz->getInterfaceDescriptorUtf8(); + trace += kSeparator; + trace += methodName; + trace += isServer ? kServerTrace : kClientTrace; + + LOG_ALWAYS_FATAL_IF(trace.size() != traceSize, "Trace size mismatch. Expected %zu, got %zu", + traceSize, trace.size()); + + return trace; +} + bool AIBinder::associateClass(const AIBinder_Class* clazz) { if (clazz == nullptr) return false; @@ -203,6 +267,17 @@ status_t ABBinder::dump(int fd, const ::android::Vector<String16>& args) { status_t ABBinder::onTransact(transaction_code_t code, const Parcel& data, Parcel* reply, binder_flags_t flags) { + std::string sectionName; + bool tracingEnabled = get_trace_enabled_tags() & ATRACE_TAG_AIDL; + if (tracingEnabled) { + sectionName = getTraceSectionName(getClass(), code, true /*isServer*/); + trace_begin(ATRACE_TAG_AIDL, sectionName.c_str()); + } + + scope_guard guard = make_scope_guard([&]() { + if (tracingEnabled) trace_end(ATRACE_TAG_AIDL); + }); + if (isUserCommand(code)) { if (getClass()->writeHeader && !data.checkInterface(this)) { return STATUS_BAD_TYPE; @@ -385,6 +460,31 @@ AIBinder_Class::AIBinder_Class(const char* interfaceDescriptor, AIBinder_Class_o mInterfaceDescriptor(interfaceDescriptor), mWideInterfaceDescriptor(interfaceDescriptor) {} +bool AIBinder_Class::setTransactionCodeMap(const char** transactionCodeMap, size_t length) { + if (mTransactionCodeToFunction != nullptr) { + ALOGE("mTransactionCodeToFunction is already set!"); + return false; + } + mTransactionCodeToFunction = transactionCodeMap; + mTransactionCodeToFunctionLength = length; + return true; +} + +const char* AIBinder_Class::getFunctionName(transaction_code_t code) const { + if (mTransactionCodeToFunction == nullptr) { + ALOGE("mTransactionCodeToFunction is not set!"); + return nullptr; + } + + if (code < FIRST_CALL_TRANSACTION || + code - FIRST_CALL_TRANSACTION >= mTransactionCodeToFunctionLength) { + ALOGE("Function name for requested code not found!"); + return nullptr; + } + + return mTransactionCodeToFunction[code - FIRST_CALL_TRANSACTION]; +} + AIBinder_Class* AIBinder_Class_define(const char* interfaceDescriptor, AIBinder_Class_onCreate onCreate, AIBinder_Class_onDestroy onDestroy, @@ -404,6 +504,24 @@ void AIBinder_Class_setOnDump(AIBinder_Class* clazz, AIBinder_onDump onDump) { clazz->onDump = onDump; } +void AIBinder_Class_setTransactionCodeToFunctionNameMap(AIBinder_Class* clazz, + const char** transactionCodeToFunction, + size_t length) { + LOG_ALWAYS_FATAL_IF(clazz == nullptr || transactionCodeToFunction == nullptr, + "Valid clazz and transactionCodeToFunction are needed to set code to " + "function mapping."); + LOG_ALWAYS_FATAL_IF(!clazz->setTransactionCodeMap(transactionCodeToFunction, length), + "Failed to set transactionCodeToFunction to clazz! Is " + "transactionCodeToFunction already set?"); +} + +const char* AIBinder_Class_getFunctionName(AIBinder_Class* clazz, transaction_code_t code) { + LOG_ALWAYS_FATAL_IF( + clazz == nullptr, + "Valid clazz is needed to get function name for requested transaction code"); + return clazz->getFunctionName(code); +} + void AIBinder_Class_disableInterfaceTokenHeader(AIBinder_Class* clazz) { LOG_ALWAYS_FATAL_IF(clazz == nullptr, "disableInterfaceTokenHeader requires non-null clazz"); @@ -734,6 +852,19 @@ static void DestroyParcel(AParcel** parcel) { binder_status_t AIBinder_transact(AIBinder* binder, transaction_code_t code, AParcel** in, AParcel** out, binder_flags_t flags) { + const AIBinder_Class* clazz = binder ? binder->getClass() : nullptr; + + std::string sectionName; + bool tracingEnabled = get_trace_enabled_tags() & ATRACE_TAG_AIDL; + if (tracingEnabled) { + sectionName = getTraceSectionName(clazz, code, false /*isServer*/); + trace_begin(ATRACE_TAG_AIDL, sectionName.c_str()); + } + + scope_guard guard = make_scope_guard([&]() { + if (tracingEnabled) trace_end(ATRACE_TAG_AIDL); + }); + if (in == nullptr) { ALOGE("%s: requires non-null in parameter", __func__); return STATUS_UNEXPECTED_NULL; @@ -872,4 +1003,4 @@ void AIBinder_setInheritRt(AIBinder* binder, bool inheritRt) { "AIBinder_setInheritRt must be called on a local binder"); localBinder->setInheritRt(inheritRt); -} +}
\ No newline at end of file diff --git a/libs/binder/ndk/ibinder_internal.h b/libs/binder/ndk/ibinder_internal.h index f5b738c1ef..a93dc1f674 100644 --- a/libs/binder/ndk/ibinder_internal.h +++ b/libs/binder/ndk/ibinder_internal.h @@ -132,6 +132,9 @@ struct AIBinder_Class { const ::android::String16& getInterfaceDescriptor() const { return mWideInterfaceDescriptor; } const char* getInterfaceDescriptorUtf8() const { return mInterfaceDescriptor.c_str(); } + bool setTransactionCodeMap(const char** transactionCodeMap, size_t transactionCodeMapSize); + const char* getFunctionName(transaction_code_t code) const; + size_t getTransactionCodeToFunctionLength() const { return mTransactionCodeToFunctionLength; } // whether a transaction header should be written bool writeHeader = true; @@ -151,6 +154,10 @@ struct AIBinder_Class { // This must be a String16 since BBinder virtual getInterfaceDescriptor returns a reference to // one. const ::android::String16 mWideInterfaceDescriptor; + // Array which holds names of the functions + const char** mTransactionCodeToFunction = nullptr; + // length of mmTransactionCodeToFunctionLength array + size_t mTransactionCodeToFunctionLength = 0; }; // Ownership is like this (when linked to death): diff --git a/libs/binder/ndk/include_cpp/android/binder_interface_utils.h b/libs/binder/ndk/include_cpp/android/binder_interface_utils.h index af56bf0da1..379bdbbe12 100644 --- a/libs/binder/ndk/include_cpp/android/binder_interface_utils.h +++ b/libs/binder/ndk/include_cpp/android/binder_interface_utils.h @@ -30,6 +30,17 @@ #include <android/binder_auto_utils.h> #include <android/binder_ibinder.h> +#if defined(__ANDROID_VENDOR__) +#include <android/llndk-versioning.h> +#elif !defined(API_LEVEL_AT_LEAST) +#if defined(__BIONIC__) +#define API_LEVEL_AT_LEAST(sdk_api_level, vendor_api_level) \ + (__builtin_available(android sdk_api_level, *)) +#else +#define API_LEVEL_AT_LEAST(sdk_api_level, vendor_api_level) (true) +#endif // __BIONIC__ +#endif // __ANDROID_VENDOR__ + #if __has_include(<android/binder_shell.h>) #include <android/binder_shell.h> #define HAS_BINDER_SHELL_COMMAND @@ -164,7 +175,8 @@ class ICInterface : public SharedRefBase { * Helper method to create a class */ static inline AIBinder_Class* defineClass(const char* interfaceDescriptor, - AIBinder_Class_onTransact onTransact); + AIBinder_Class_onTransact onTransact, + const char** codeToFunction, size_t functionCount); private: class ICInterfaceData { @@ -255,7 +267,8 @@ std::shared_ptr<ICInterface> ICInterface::asInterface(AIBinder* binder) { } AIBinder_Class* ICInterface::defineClass(const char* interfaceDescriptor, - AIBinder_Class_onTransact onTransact) { + AIBinder_Class_onTransact onTransact, + const char** codeToFunction, size_t functionCount) { AIBinder_Class* clazz = AIBinder_Class_define(interfaceDescriptor, ICInterfaceData::onCreate, ICInterfaceData::onDestroy, onTransact); if (clazz == nullptr) { @@ -274,6 +287,17 @@ AIBinder_Class* ICInterface::defineClass(const char* interfaceDescriptor, AIBinder_Class_setHandleShellCommand(clazz, ICInterfaceData::handleShellCommand); } #endif + +// TODO(b/368559337): fix versioning on product partition +#if !defined(__ANDROID_PRODUCT__) && \ + (defined(__ANDROID_UNAVAILABLE_SYMBOLS_ARE_WEAK__) || __ANDROID_API__ >= 36) + if API_LEVEL_AT_LEAST (36, 202504) { + AIBinder_Class_setTransactionCodeToFunctionNameMap(clazz, codeToFunction, functionCount); + } +#else + (void)codeToFunction; + (void)functionCount; +#endif // defined(__ANDROID_UNAVAILABLE_SYMBOLS_ARE_WEAK__) || __ANDROID_API__ >= 36 return clazz; } diff --git a/libs/binder/ndk/include_ndk/android/binder_ibinder.h b/libs/binder/ndk/include_ndk/android/binder_ibinder.h index 72d255e816..2f6c4e3642 100644 --- a/libs/binder/ndk/include_ndk/android/binder_ibinder.h +++ b/libs/binder/ndk/include_ndk/android/binder_ibinder.h @@ -219,6 +219,50 @@ typedef binder_status_t (*AIBinder_onDump)(AIBinder* binder, int fd, const char* void AIBinder_Class_setOnDump(AIBinder_Class* clazz, AIBinder_onDump onDump) __INTRODUCED_IN(29); /** + * Associates a mapping of transaction codes(transaction_code_t) to function names for the given + * class. + * + * Trace messages will use the provided names instead of bare integer codes when set. If not set by + * this function, trace messages will only be identified by the bare code. This should be called one + * time during clazz initialization. clazz and transactionCodeToFunctionMap should have same + * lifetime. Resetting/clearing the transactionCodeToFunctionMap is not allowed. + * + * Available since API level 36. + * + * \param clazz class which should use this transaction to code function map. + * \param transactionCodeToFunctionMap array of function names indexed by transaction code. + * Transaction codes start from 1, functions with transaction code 1 will correspond to index 0 in + * transactionCodeToFunctionMap. When defining methods, transaction codes are expected to be + * contiguous, and this is required for maximum memory efficiency. + * You can use nullptr if certain transaction codes are not used. Lifetime should be same as clazz. + * \param length number of elements in the transactionCodeToFunctionMap + * + * \return true if setting codeToFunction to clazz is successful. return false if clazz or + * codeToFunction is nullptr. + */ +void AIBinder_Class_setTransactionCodeToFunctionNameMap(AIBinder_Class* clazz, + const char** transactionCodeToFunctionMap, + size_t length) __INTRODUCED_IN(36); + +/** + * Get function name associated with transaction code for given class + * + * This function returns function name associated with provided transaction code for given class. + * AIBinder_Class_setTransactionCodeToFunctionNameMap should be called first to associate function + * to transaction code mapping. + * + * Available since API level 36. + * + * \param clazz class for which function name is requested + * \param transactionCode transaction_code_t for which function name is requested. + * + * \return function name in form of const char* if transaction code is valid for given class. + * if transaction code is invalid or transactionCodeToFunctionMap is not set, nullptr is returned + */ +const char* AIBinder_Class_getFunctionName(AIBinder_Class* clazz, transaction_code_t code) + __INTRODUCED_IN(36); + +/** * This tells users of this class not to use a transaction header. By default, libbinder_ndk users * read/write transaction headers implicitly (in the SDK, this must be manually written by * android.os.Parcel#writeInterfaceToken, and it is read/checked with diff --git a/libs/binder/ndk/libbinder_ndk.map.txt b/libs/binder/ndk/libbinder_ndk.map.txt index c9e669ed36..c885816e56 100644 --- a/libs/binder/ndk/libbinder_ndk.map.txt +++ b/libs/binder/ndk/libbinder_ndk.map.txt @@ -250,6 +250,10 @@ LIBBINDER_NDK35 { # introduced=VanillaIceCream LIBBINDER_NDK36 { # introduced=36 global: + AIBinder_Class_setTransactionCodeToFunctionNameMap; + AIBinder_Class_setTransactionCodeToFunctionNameMap; # llndk=202504 + AIBinder_Class_getFunctionName; + AIBinder_Class_getFunctionName; # llndk=202504 ABinderRpc_registerAccessorProvider; # systemapi ABinderRpc_unregisterAccessorProvider; # systemapi ABinderRpc_Accessor_new; # systemapi diff --git a/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp b/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp index 3cd2b9a891..e5a3da460e 100644 --- a/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp +++ b/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp @@ -1108,6 +1108,37 @@ TEST(NdkBinder_ScopedAResource, Release) { EXPECT_EQ(deleteCount, 0); } +void* EmptyOnCreate(void* args) { + return args; +} +void EmptyOnDestroy(void* /*userData*/) {} +binder_status_t EmptyOnTransact(AIBinder* /*binder*/, transaction_code_t /*code*/, + const AParcel* /*in*/, AParcel* /*out*/) { + return STATUS_OK; +} + +TEST(NdkBinder_DeathTest, SetCodeMapTwice) { + const char* codeToFunction1[] = {"function-1", "function-2", "function-3"}; + const char* codeToFunction2[] = {"function-4", "function-5"}; + const char* interfaceName = "interface_descriptor"; + AIBinder_Class* clazz = + AIBinder_Class_define(interfaceName, EmptyOnCreate, EmptyOnDestroy, EmptyOnTransact); + AIBinder_Class_setTransactionCodeToFunctionNameMap(clazz, codeToFunction1, 3); + // Reset/clear is not allowed + EXPECT_DEATH(AIBinder_Class_setTransactionCodeToFunctionNameMap(clazz, codeToFunction2, 2), ""); +} + +TEST(NdkBinder_DeathTest, SetNullCodeMap) { + const char* codeToFunction[] = {"function-1", "function-2", "function-3"}; + const char* interfaceName = "interface_descriptor"; + AIBinder_Class* clazz = + AIBinder_Class_define(interfaceName, EmptyOnCreate, EmptyOnDestroy, EmptyOnTransact); + EXPECT_DEATH(AIBinder_Class_setTransactionCodeToFunctionNameMap(nullptr, codeToFunction, 3), + ""); + EXPECT_DEATH(AIBinder_Class_setTransactionCodeToFunctionNameMap(clazz, nullptr, 0), ""); + EXPECT_DEATH(AIBinder_Class_setTransactionCodeToFunctionNameMap(nullptr, nullptr, 0), ""); +} + int main(int argc, char* argv[]) { ::testing::InitGoogleTest(&argc, argv); diff --git a/libs/binder/tests/parcel_fuzzer/binder_ndk.cpp b/libs/binder/tests/parcel_fuzzer/binder_ndk.cpp index 3a1471eabe..e3a337171f 100644 --- a/libs/binder/tests/parcel_fuzzer/binder_ndk.cpp +++ b/libs/binder/tests/parcel_fuzzer/binder_ndk.cpp @@ -49,7 +49,8 @@ static binder_status_t onTransact(AIBinder*, transaction_code_t, const AParcel*, return STATUS_UNKNOWN_TRANSACTION; } -static AIBinder_Class* g_class = ::ndk::ICInterface::defineClass("ISomeInterface", onTransact); +static AIBinder_Class* g_class = + ::ndk::ICInterface::defineClass("ISomeInterface", onTransact, nullptr, 0); class BpSomeInterface : public ::ndk::BpCInterface<ISomeInterface> { public: diff --git a/libs/binder/trusty/OS.cpp b/libs/binder/trusty/OS.cpp index 157ab3c85d..ba9e457a75 100644 --- a/libs/binder/trusty/OS.cpp +++ b/libs/binder/trusty/OS.cpp @@ -42,6 +42,10 @@ void trace_end(uint64_t) {} void trace_int(uint64_t, const char*, int32_t) {} +uint64_t get_trace_enabled_tags() { + return 0; +} + uint64_t GetThreadId() { return 0; } |