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 
logAlwaysFatal(const char * message)49 void logAlwaysFatal(const char* message) {
50     LOG(FATAL) << message;
51 }
52 
getVndkVersionStr()53 std::string getVndkVersionStr() {
54     static std::string vndkVersion = base::GetProperty("ro.vndk.version", "");
55     return vndkVersion;
56 }
57 
58 // ----------------------------------------------------------------------
59 // HidlInstrumentor implementation.
HidlInstrumentor(const std::string & package,const std::string & interface)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 
~HidlInstrumentor()110 HidlInstrumentor::~HidlInstrumentor() {}
111 
configureInstrumentation(bool log)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 
registerInstrumentationCallbacks(std::vector<InstrumentationCallback> * instrumentationCallbacks)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 
isInstrumentationLib(const dirent * file)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