Reland "Move tracing calls to libbinder_ndk"

00f5a992a682e9d9ef943f165da3a9813f1501e1

Change-Id: I2151e6b2c3ddb15d9aedd493018b0252938c3639
diff --git a/libs/binder/OS.h b/libs/binder/OS.h
index 04869a1..64b1fd4 100644
--- a/libs/binder/OS.h
+++ b/libs/binder/OS.h
@@ -27,6 +27,7 @@
 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 893ee15..4e9230c 100644
--- a/libs/binder/OS_android.cpp
+++ b/libs/binder/OS_android.cpp
@@ -48,6 +48,10 @@
     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 0c64eb6..6bba823 100644
--- a/libs/binder/OS_non_android_linux.cpp
+++ b/libs/binder/OS_non_android_linux.cpp
@@ -41,6 +41,10 @@
 
 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 2f450cb..a3e6c8a 100644
--- a/libs/binder/include/binder/Trace.h
+++ b/libs/binder/include/binder/Trace.h
@@ -42,6 +42,7 @@
 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 af280d3..ff31dd0 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::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 @@
     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::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 @@
       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 @@
     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 @@
 
 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 @@
                         "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 f5b738c..a93dc1f 100644
--- a/libs/binder/ndk/ibinder_internal.h
+++ b/libs/binder/ndk/ibinder_internal.h
@@ -132,6 +132,9 @@
 
     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 @@
     // 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 af56bf0..379bdbb 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 @@
      * 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 @@
 }
 
 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_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 72d255e..2f6c4e3 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 @@
 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 c9e669e..c885816 100644
--- a/libs/binder/ndk/libbinder_ndk.map.txt
+++ b/libs/binder/ndk/libbinder_ndk.map.txt
@@ -250,6 +250,10 @@
 
 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 3cd2b9a..e5a3da4 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 @@
     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 3a1471e..e3a3371 100644
--- a/libs/binder/tests/parcel_fuzzer/binder_ndk.cpp
+++ b/libs/binder/tests/parcel_fuzzer/binder_ndk.cpp
@@ -49,7 +49,8 @@
     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 157ab3c..ba9e457 100644
--- a/libs/binder/trusty/OS.cpp
+++ b/libs/binder/trusty/OS.cpp
@@ -42,6 +42,10 @@
 
 void trace_int(uint64_t, const char*, int32_t) {}
 
+uint64_t get_trace_enabled_tags() {
+    return 0;
+}
+
 uint64_t GetThreadId() {
     return 0;
 }