Revert "Revert "Move HidlInstrumentor to HidlInternal and namespace details.""

This reverts commit f9fd88291caa3a2bab89c1b8ff128b1659da81b4.
Test: make libhidlbase
Change-Id: I85eb85bd9e89c28026e9865f799dce2b0df584fc
diff --git a/base/HidlInternal.cpp b/base/HidlInternal.cpp
index 45afda3..9c0efbb 100644
--- a/base/HidlInternal.cpp
+++ b/base/HidlInternal.cpp
@@ -19,6 +19,14 @@
 #include <hidl/HidlInternal.h>
 
 #include <android-base/logging.h>
+#include <cutils/properties.h>
+
+#ifdef LIBHIDL_TARGET_DEBUGGABLE
+#include <dirent.h>
+#include <dlfcn.h>
+#include <hidl-util/FQName.h>
+#include <regex>
+#endif
 
 namespace android {
 namespace hardware {
@@ -28,6 +36,113 @@
     LOG(FATAL) << message;
 }
 
+// ----------------------------------------------------------------------
+// HidlInstrumentor implementation.
+HidlInstrumentor::HidlInstrumentor(
+        const std::string &package,
+        const std::string &interface)
+        : mInstrumentationLibPackage(package), mInterfaceName(interface) {
+    configureInstrumentation(false);
+}
+
+HidlInstrumentor:: ~HidlInstrumentor() {}
+
+void HidlInstrumentor::configureInstrumentation(bool log) {
+    bool enable_instrumentation = property_get_bool(
+            "hal.instrumentation.enable",
+            false);
+    if (enable_instrumentation != mEnableInstrumentation) {
+        mEnableInstrumentation = enable_instrumentation;
+        if (mEnableInstrumentation) {
+            if (log) {
+                LOG(INFO) << "Enable instrumentation.";
+            }
+            registerInstrumentationCallbacks (&mInstrumentationCallbacks);
+        } else {
+            if (log) {
+                LOG(INFO) << "Disable instrumentation.";
+            }
+            mInstrumentationCallbacks.clear();
+        }
+    }
+}
+
+void HidlInstrumentor::registerInstrumentationCallbacks(
+        std::vector<InstrumentationCallback> *instrumentationCallbacks) {
+#ifdef LIBHIDL_TARGET_DEBUGGABLE
+    std::vector<std::string> instrumentationLibPaths;
+    char instrumentation_lib_path[PROPERTY_VALUE_MAX];
+    if (property_get("hal.instrumentation.lib.path",
+                     instrumentation_lib_path,
+                     "") > 0) {
+        instrumentationLibPaths.push_back(instrumentation_lib_path);
+    } else {
+        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 exist. ";
+            return;
+        }
+
+        struct dirent *file;
+        while ((file = readdir(dir)) != NULL) {
+            if (!isInstrumentationLib(file))
+                continue;
+
+            void *handle = dlopen((path + file->d_name).c_str(), RTLD_NOW);
+            char *error;
+            if (handle == nullptr) {
+                LOG(WARNING) << "couldn't load file: " << file->d_name
+                    << " error: " << dlerror();
+                continue;
+            }
+
+            dlerror(); /* Clear any existing error */
+
+            using cb_fun = void (*)(
+                    const InstrumentationEvent,
+                    const char *,
+                    const char *,
+                    const char *,
+                    const char *,
+                    std::vector<void *> *);
+            FQName package_name = FQName(mInstrumentationLibPackage);
+            auto cb = (cb_fun)dlsym(handle, ("HIDL_INSTRUMENTATION_FUNCTION_"
+                        + package_name.tokenName() + "_"
+                        + mInterfaceName).c_str());
+            if ((error = dlerror()) != NULL) {
+                LOG(WARNING)
+                    << "couldn't find symbol: HIDL_INSTRUMENTATION_FUNCTION_"
+                    << mInterfaceName << ", error: " << error;
+                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 HidlInstrumentor::isInstrumentationLib(const dirent *file) {
+#ifdef LIBHIDL_TARGET_DEBUGGABLE
+    if (file->d_type != DT_REG) return false;
+    std::cmatch cm;
+    std::regex e("^" + mInstrumentationLibPackage + "(.*).profiler.so$");
+    if (std::regex_match(file->d_name, cm, e)) return true;
+#endif
+    return false;
+}
+
 }  // namespace details
 }  // namespace hardware
 }  // namespace android