1 /* 2 * Copyright (C) 2016 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #define LOG_TAG "HidlInternal" 18 19 #include <hidl/HidlInternal.h> 20 21 #include <android-base/logging.h> 22 #include <cutils/properties.h> 23 24 #ifdef LIBHIDL_TARGET_DEBUGGABLE 25 #include <dirent.h> 26 #include <dlfcn.h> 27 #include <regex> 28 #endif 29 30 namespace android { 31 namespace hardware { 32 namespace details { 33 34 void logAlwaysFatal(const char *message) { 35 LOG(FATAL) << message; 36 } 37 38 // ---------------------------------------------------------------------- 39 // HidlInstrumentor implementation. 40 HidlInstrumentor::HidlInstrumentor(const std::string& package, const std::string& interface) 41 : mEnableInstrumentation(false), 42 mInstrumentationLibPackage(package), 43 mInterfaceName(interface) { 44 configureInstrumentation(false); 45 } 46 47 HidlInstrumentor:: ~HidlInstrumentor() {} 48 49 void HidlInstrumentor::configureInstrumentation(bool log) { 50 bool enableInstrumentation = property_get_bool( 51 "hal.instrumentation.enable", 52 false); 53 if (enableInstrumentation != mEnableInstrumentation) { 54 mEnableInstrumentation = enableInstrumentation; 55 if (mEnableInstrumentation) { 56 if (log) { 57 LOG(INFO) << "Enable instrumentation."; 58 } 59 registerInstrumentationCallbacks (&mInstrumentationCallbacks); 60 } else { 61 if (log) { 62 LOG(INFO) << "Disable instrumentation."; 63 } 64 mInstrumentationCallbacks.clear(); 65 } 66 } 67 } 68 69 void HidlInstrumentor::registerInstrumentationCallbacks( 70 std::vector<InstrumentationCallback> *instrumentationCallbacks) { 71 #ifdef LIBHIDL_TARGET_DEBUGGABLE 72 std::vector<std::string> instrumentationLibPaths; 73 char instrumentationLibPath[PROPERTY_VALUE_MAX]; 74 if (property_get("hal.instrumentation.lib.path", 75 instrumentationLibPath, 76 "") > 0) { 77 instrumentationLibPaths.push_back(instrumentationLibPath); 78 } else { 79 instrumentationLibPaths.push_back(HAL_LIBRARY_PATH_SYSTEM); 80 instrumentationLibPaths.push_back(HAL_LIBRARY_PATH_VENDOR); 81 instrumentationLibPaths.push_back(HAL_LIBRARY_PATH_ODM); 82 } 83 84 for (auto path : instrumentationLibPaths) { 85 DIR *dir = opendir(path.c_str()); 86 if (dir == 0) { 87 LOG(WARNING) << path << " does not exist. "; 88 return; 89 } 90 91 struct dirent *file; 92 while ((file = readdir(dir)) != NULL) { 93 if (!isInstrumentationLib(file)) 94 continue; 95 96 void *handle = dlopen((path + file->d_name).c_str(), RTLD_NOW); 97 char *error; 98 if (handle == nullptr) { 99 LOG(WARNING) << "couldn't load file: " << file->d_name 100 << " error: " << dlerror(); 101 continue; 102 } 103 104 dlerror(); /* Clear any existing error */ 105 106 using cbFun = void (*)( 107 const InstrumentationEvent, 108 const char *, 109 const char *, 110 const char *, 111 const char *, 112 std::vector<void *> *); 113 std::string package = mInstrumentationLibPackage; 114 for (size_t i = 0; i < package.size(); i++) { 115 if (package[i] == '.') { 116 package[i] = '_'; 117 continue; 118 } 119 120 if (package[i] == '@') { 121 package[i] = '_'; 122 package.insert(i + 1, "V"); 123 continue; 124 } 125 } 126 auto cb = (cbFun)dlsym(handle, ("HIDL_INSTRUMENTATION_FUNCTION_" 127 + package + "_" + mInterfaceName).c_str()); 128 if ((error = dlerror()) != NULL) { 129 LOG(WARNING) 130 << "couldn't find symbol: HIDL_INSTRUMENTATION_FUNCTION_" 131 << package << "_" << mInterfaceName << ", error: " << error; 132 continue; 133 } 134 instrumentationCallbacks->push_back(cb); 135 LOG(INFO) << "Register instrumentation callback from " 136 << file->d_name; 137 } 138 closedir(dir); 139 } 140 #else 141 // No-op for user builds. 142 (void) instrumentationCallbacks; 143 return; 144 #endif 145 } 146 147 bool HidlInstrumentor::isInstrumentationLib(const dirent *file) { 148 #ifdef LIBHIDL_TARGET_DEBUGGABLE 149 if (file->d_type != DT_REG) return false; 150 std::cmatch cm; 151 std::regex e("^" + mInstrumentationLibPackage + "(.*).profiler.so$"); 152 if (std::regex_match(file->d_name, cm, e)) return true; 153 #else 154 (void) file; 155 #endif 156 return false; 157 } 158 159 } // namespace details 160 } // namespace hardware 161 } // namespace android 162