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 <android-base/properties.h> 23 #include <android-base/stringprintf.h> 24 25 #ifdef LIBHIDL_TARGET_DEBUGGABLE 26 #include <dirent.h> 27 #include <dlfcn.h> 28 #include <link.h> 29 #include <utils/misc.h> 30 #include <regex> 31 32 extern "C" __attribute__((weak)) void __sanitizer_cov_dump(); 33 34 const char kGcovPrefixEnvVar[] = "GCOV_PREFIX"; 35 const char kGcovPrefixOverrideEnvVar[] = "GCOV_PREFIX_OVERRIDE"; 36 const char kGcovPrefixPath[] = "/data/misc/trace/"; 37 const char kSysPropHalCoverage[] = "hal.coverage.enable"; 38 #if defined(__LP64__) 39 const char kSysPropInstrumentationPath[] = "hal.instrumentation.lib.path.64"; 40 #else 41 const char kSysPropInstrumentationPath[] = "hal.instrumentation.lib.path.32"; 42 #endif 43 #endif // LIBHIDL_TARGET_DEBUGGABLE 44 45 namespace android { 46 namespace hardware { 47 namespace details { 48 49 void logAlwaysFatal(const char* message) { 50 LOG(FATAL) << message; 51 } 52 53 std::string getVndkVersionStr() { 54 static std::string vndkVersion = base::GetProperty("ro.vndk.version", ""); 55 return vndkVersion; 56 } 57 58 // ---------------------------------------------------------------------- 59 // HidlInstrumentor implementation. 60 HidlInstrumentor::HidlInstrumentor(const std::string& package, const std::string& interface) 61 : mEnableInstrumentation(false), 62 mInstrumentationLibPackage(package), 63 mInterfaceName(interface) { 64 #ifdef LIBHIDL_TARGET_DEBUGGABLE 65 configureInstrumentation(false); 66 if (__sanitizer_cov_dump != nullptr) { 67 ::android::add_sysprop_change_callback( 68 []() { 69 bool enableCoverage = base::GetBoolProperty(kSysPropHalCoverage, false); 70 if (enableCoverage) { 71 __sanitizer_cov_dump(); 72 } 73 }, 74 0); 75 } 76 if (base::GetBoolProperty("ro.vts.coverage", false)) { 77 const char* prefixOverride = getenv(kGcovPrefixOverrideEnvVar); 78 if (prefixOverride == nullptr || strcmp(prefixOverride, "true") != 0) { 79 const std::string gcovPath = kGcovPrefixPath + std::to_string(getpid()); 80 setenv(kGcovPrefixEnvVar, gcovPath.c_str(), true /* overwrite */); 81 } 82 ::android::add_sysprop_change_callback( 83 []() { 84 const bool enableCoverage = base::GetBoolProperty(kSysPropHalCoverage, false); 85 if (enableCoverage) { 86 dl_iterate_phdr( 87 [](struct dl_phdr_info* info, size_t /* size */, void* /* data */) { 88 if (strlen(info->dlpi_name) == 0) return 0; 89 90 void* handle = dlopen(info->dlpi_name, RTLD_LAZY); 91 if (handle == nullptr) { 92 LOG(INFO) << "coverage dlopen failed: " << dlerror(); 93 return 0; 94 } 95 void (*flush)() = (void (*)())dlsym(handle, "__gcov_flush"); 96 if (flush == nullptr) { 97 return 0; 98 } 99 flush(); 100 return 0; 101 }, 102 nullptr /* data */); 103 } 104 }, 105 0 /* priority */); 106 } 107 #endif 108 } 109 110 HidlInstrumentor::~HidlInstrumentor() {} 111 112 void HidlInstrumentor::configureInstrumentation(bool log) { 113 mEnableInstrumentation = base::GetBoolProperty("hal.instrumentation.enable", false); 114 if (mEnableInstrumentation) { 115 if (log) { 116 LOG(INFO) << "Enable instrumentation."; 117 } 118 mInstrumentationCallbacks.clear(); 119 registerInstrumentationCallbacks(&mInstrumentationCallbacks); 120 } else { 121 if (log) { 122 LOG(INFO) << "Disable instrumentation."; 123 } 124 mInstrumentationCallbacks.clear(); 125 } 126 } 127 128 void HidlInstrumentor::registerInstrumentationCallbacks( 129 std::vector<InstrumentationCallback> *instrumentationCallbacks) { 130 #ifdef LIBHIDL_TARGET_DEBUGGABLE 131 std::vector<std::string> instrumentationLibPaths; 132 const std::string instrumentationLibPath = base::GetProperty(kSysPropInstrumentationPath, ""); 133 if (instrumentationLibPath.size() > 0) { 134 instrumentationLibPaths.push_back(instrumentationLibPath); 135 } else { 136 static std::string halLibPathVndkSp = android::base::StringPrintf( 137 HAL_LIBRARY_PATH_VNDK_SP_FOR_VERSION, getVndkVersionStr().c_str()); 138 #ifndef __ANDROID_VNDK__ 139 instrumentationLibPaths.push_back(HAL_LIBRARY_PATH_SYSTEM); 140 #endif 141 instrumentationLibPaths.push_back(halLibPathVndkSp); 142 instrumentationLibPaths.push_back(HAL_LIBRARY_PATH_VENDOR); 143 instrumentationLibPaths.push_back(HAL_LIBRARY_PATH_ODM); 144 } 145 146 for (const auto& path : instrumentationLibPaths) { 147 DIR *dir = opendir(path.c_str()); 148 if (dir == nullptr) { 149 LOG(WARNING) << path << " does not exist. "; 150 return; 151 } 152 153 struct dirent *file; 154 while ((file = readdir(dir)) != nullptr) { 155 if (!isInstrumentationLib(file)) 156 continue; 157 158 void *handle = dlopen((path + file->d_name).c_str(), RTLD_NOW); 159 char *error; 160 if (handle == nullptr) { 161 LOG(WARNING) << "couldn't load file: " << file->d_name 162 << " error: " << dlerror(); 163 continue; 164 } 165 166 dlerror(); /* Clear any existing error */ 167 168 using cbFun = void (*)( 169 const InstrumentationEvent, 170 const char *, 171 const char *, 172 const char *, 173 const char *, 174 std::vector<void *> *); 175 std::string package = mInstrumentationLibPackage; 176 for (size_t i = 0; i < package.size(); i++) { 177 if (package[i] == '.') { 178 package[i] = '_'; 179 continue; 180 } 181 182 if (package[i] == '@') { 183 package[i] = '_'; 184 package.insert(i + 1, "V"); 185 continue; 186 } 187 } 188 auto cb = (cbFun)dlsym(handle, ("HIDL_INSTRUMENTATION_FUNCTION_" 189 + package + "_" + mInterfaceName).c_str()); 190 if ((error = dlerror()) != nullptr) { 191 LOG(WARNING) 192 << "couldn't find symbol: HIDL_INSTRUMENTATION_FUNCTION_" 193 << package << "_" << mInterfaceName << ", error: " << error; 194 continue; 195 } 196 instrumentationCallbacks->push_back(cb); 197 LOG(INFO) << "Register instrumentation callback from " 198 << file->d_name; 199 } 200 closedir(dir); 201 } 202 #else 203 // No-op for user builds. 204 (void) instrumentationCallbacks; 205 return; 206 #endif 207 } 208 209 bool HidlInstrumentor::isInstrumentationLib(const dirent *file) { 210 #ifdef LIBHIDL_TARGET_DEBUGGABLE 211 if (file->d_type != DT_REG) return false; 212 std::cmatch cm; 213 std::regex e("^" + mInstrumentationLibPackage + "(.*).profiler.so$"); 214 if (std::regex_match(file->d_name, cm, e)) return true; 215 #else 216 (void) file; 217 #endif 218 return false; 219 } 220 221 } // namespace details 222 } // namespace hardware 223 } // namespace android 224