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