Add utility methods to support hidl instrumentation.

* Add method registerInstrumentationCallback which looks up and
  dynamically loads the hidl instrumentation libraries and registers
  the instrumentation callbacks.
* The method looks up interumentation libraries under directories:
  /system/lib(64)/hw, /vender/lib(64)/hw, /odm/lib(64)/hw.
* The method only loads libraries with a particualr name pattern, e.g.
  android.hardware.nfc@1.0.*.profiler.so
* The method is a no-op for user builds.

Bug: 31266145
Test: test pass with hidl_test.

Change-Id: Id11486e36081d75481a45836219f84ddf5b112d7
diff --git a/Android.mk b/Android.mk
index 3b15645..c4f7bd3 100644
--- a/Android.mk
+++ b/Android.mk
@@ -29,6 +29,10 @@
 	Static.cpp 		\
 	Status.cpp
 
+ifeq ($(TARGET_BUILD_VARIANT),user)
+   LOCAL_CFLAGS += -DLIBHIDL_TARGET_BUILD_VARIANT_USER
+endif
+
 LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
 LOCAL_MULTILIB := both
 include $(BUILD_SHARED_LIBRARY)
diff --git a/HidlSupport.cpp b/HidlSupport.cpp
index 27daa94..37d4b9f 100644
--- a/HidlSupport.cpp
+++ b/HidlSupport.cpp
@@ -16,6 +16,12 @@
 
 #include <hidl/HidlSupport.h>
 
+#ifndef DLIBHIDL_TARGET_BUILD_VARIANT_USER
+#include <android-base/logging.h>
+#include <cutils/properties.h>
+#include <regex>
+#endif
+
 namespace android {
 namespace hardware {
 
@@ -116,6 +122,74 @@
 // static
 const size_t hidl_string::kOffsetOfBuffer = offsetof(hidl_string, mBuffer);
 
+
+
+void registerInstrumentationCallbacks(
+        const std::string &profilerPrefix,
+        std::vector<InstrumentationCallback> *instrumentationCallbacks) {
+#ifndef DLIBHIDL_TARGET_BUILD_VARIANT_USER
+    std::vector<std::string> instrumentationLibPaths;
+    instrumentationLibPaths.push_back(HAL_LIBRARY_PATH_SYSTEM);
+    instrumentationLibPaths.push_back(HAL_LIBRARY_PATH_VENDOR);
+    instrumentationLibPaths.push_back(HAL_LIBRARY_PATH_ODM);
+    for (auto path : instrumentationLibPaths) {
+        DIR *dir = opendir(path.c_str());
+        if (dir == 0) {
+            LOG(WARNING) << path << " does not exit. ";
+            return;
+        }
+
+        struct dirent *file;
+        while ((file = readdir(dir)) != NULL) {
+            if (!isInstrumentationLib(profilerPrefix, file))
+                continue;
+
+            void *handle = dlopen((path + file->d_name).c_str(), RTLD_NOW);
+            if (handle == nullptr) {
+                LOG(WARNING) << "couldn't load file: " << file->d_name
+                    << " error: " << dlerror();
+                continue;
+            }
+            using cb_fun = void (*)(
+                    const InstrumentationEvent,
+                    const char *,
+                    const char *,
+                    const char *,
+                    const char *,
+                    std::vector<void *> *);
+            auto cb = (cb_fun)dlsym(handle, "HIDL_INSTRUMENTATION_FUNCTION");
+            if (cb == nullptr) {
+                LOG(WARNING)
+                    << "couldn't find symbol: HIDL_INSTRUMENTATION_FUNCTION, "
+                       "error: "
+                    << dlerror();
+                continue;
+            }
+            instrumentationCallbacks->push_back(cb);
+            LOG(INFO) << "Register instrumentation callback from "
+                << file->d_name;
+        }
+        closedir(dir);
+    }
+#else
+    // No-op for user builds.
+    return;
+#endif
+}
+
+bool isInstrumentationLib(
+        const std::string &profiler_prefix,
+        const dirent *file) {
+#ifndef DLIBHIDL_TARGET_BUILD_VARIANT_USER
+    if (file->d_type != DT_REG) return false;
+    std::cmatch cm;
+    std::regex e("^" + profiler_prefix + "(.*).profiler.so$");
+    if (std::regex_match(file->d_name, cm, e)) return true;
+#else
+#endif
+    return false;
+}
+
 }  // namespace hardware
 }  // namespace android
 
diff --git a/include/hidl/HidlSupport.h b/include/hidl/HidlSupport.h
index 347d9e4..6b88664 100644
--- a/include/hidl/HidlSupport.h
+++ b/include/hidl/HidlSupport.h
@@ -18,6 +18,7 @@
 #define ANDROID_HIDL_SUPPORT_H
 
 #include <algorithm>
+#include <dirent.h>
 #include <dlfcn.h>
 #include <hwbinder/Parcel.h>
 #include <utils/Errors.h>
@@ -286,6 +287,53 @@
                               I##INTERFACE::version);                                    \
     }
 
+// ----------------------------------------------------------------------
+// Hidl instrumentation utilities.
+
+// Event that triggers the instrumentation. e.g. enter of an API call on
+// the server/client side, exit of an API call on the server/client side etc.
+enum InstrumentationEvent {
+    SERVER_API_ENTRY = 0,
+    SERVER_API_EXIT,
+    CLIENT_API_ENTRY,
+    CLIENT_API_EXIT,
+    SYNC_CALLBACK_ENTRY,
+    SYNC_CALLBACK_EXIT,
+    ASYNC_CALLBACK_ENTRY,
+    ASYNC_CALLBACK_EXIT,
+};
+
+// Signature of the instrumentation callback function.
+using InstrumentationCallback = std::function<void(
+        const InstrumentationEvent event,
+        const char *package,
+        const char *version,
+        const char *interface,
+        const char *method,
+        std::vector<void *> *args)>;
+
+// Function that lookup and dynamically loads the hidl instrumentation libraries
+// and registers the instrumentation callback functions.
+//
+// The instrumentation libraries should be stored under any of the following
+// directories: HAL_LIBRARY_PATH_SYSTEM, HAL_LIBRARY_PATH_VENDOR and
+// HAL_LIBRARY_PATH_ODM. The name of instrumentation libraries should follow
+// pattern: ^profilerPrefix(.*).profiler.so$
+//
+// Each instrumentation library is expected to implement the instrumentation
+// function called HIDL_INSTRUMENTATION_FUNCTION.
+//
+// A no-op for user build.
+void registerInstrumentationCallbacks(
+        const std::string &profilerPrefix,
+        std::vector<InstrumentationCallback> *instrumentationCallbacks);
+
+// Utility function to determine whether a give file is a instrumentation
+// library (i.e. the file name follow the expected pattern).
+bool isInstrumentationLib(
+        const std::string &profilerPrefix,
+        const dirent *file);
+
 }  // namespace hardware
 }  // namespace android