1 /* 2 * Copyright 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 #define LOG_TAG "VtsHalDriverBase" 17 18 #include "driver_base/DriverBase.h" 19 20 #include <dirent.h> 21 #include <sys/stat.h> 22 #include <string> 23 #include <vector> 24 25 #include <android-base/logging.h> 26 27 #include "GcdaParser.h" 28 #include "component_loader/DllLoader.h" 29 #include "test/vts/proto/ComponentSpecificationMessage.pb.h" 30 #include "utils/InterfaceSpecUtil.h" 31 32 using namespace std; 33 using namespace android; 34 35 #define USE_GCOV 1 36 37 namespace android { 38 namespace vts { 39 40 const string default_gcov_output_basepath = "/data/misc/gcov"; 41 42 static void RemoveDir(char* path) { 43 struct dirent* entry = NULL; 44 DIR* dir = opendir(path); 45 46 while ((entry = readdir(dir)) != NULL) { 47 DIR* sub_dir = NULL; 48 FILE* file = NULL; 49 char abs_path[4096] = {0}; 50 51 if (*(entry->d_name) != '.') { 52 sprintf(abs_path, "%s/%s", path, entry->d_name); 53 if ((sub_dir = opendir(abs_path)) != NULL) { 54 closedir(sub_dir); 55 RemoveDir(abs_path); 56 } else if ((file = fopen(abs_path, "r")) != NULL) { 57 fclose(file); 58 remove(abs_path); 59 } 60 } 61 } 62 remove(path); 63 } 64 65 DriverBase::DriverBase(int target_class) 66 : device_(NULL), 67 hmi_(NULL), 68 target_dll_path_(NULL), 69 target_class_(target_class), 70 component_filename_(NULL), 71 gcov_output_basepath_(NULL) {} 72 73 DriverBase::~DriverBase() { free(component_filename_); } 74 75 void wfn() { LOG(DEBUG) << "debug"; } 76 77 void ffn() { LOG(DEBUG) << "debug"; } 78 79 bool DriverBase::LoadTargetComponent(const char* target_dll_path) { 80 if (target_dll_path && target_dll_path_ && 81 !strcmp(target_dll_path, target_dll_path_)) { 82 LOG(DEBUG) << "Skip loading " << target_dll_path; 83 return true; 84 } 85 86 if (!target_loader_.Load(target_dll_path)) return false; 87 target_dll_path_ = (char*)malloc(strlen(target_dll_path) + 1); 88 strcpy(target_dll_path_, target_dll_path); 89 LOG(DEBUG) << "Loaded the target"; 90 if (target_class_ == HAL_LEGACY) return true; 91 LOG(DEBUG) << "Loaded a non-legacy HAL file."; 92 93 if (target_dll_path_) { 94 LOG(DEBUG) << "Target DLL path " << target_dll_path_; 95 string target_path(target_dll_path_); 96 97 size_t offset = target_path.rfind("/", target_path.length()); 98 if (offset != string::npos) { 99 string filename = 100 target_path.substr(offset + 1, target_path.length() - offset); 101 filename = filename.substr(0, filename.length() - 3 /* for .so */); 102 component_filename_ = (char*)malloc(filename.length() + 1); 103 strcpy(component_filename_, filename.c_str()); 104 LOG(DEBUG) << "Module file name: " << component_filename_; 105 } 106 LOG(DEBUG) << "Target_dll_path " << target_dll_path_; 107 } 108 109 #if USE_GCOV 110 LOG(DEBUG) << "gcov init " << target_loader_.GcovInit(wfn, ffn); 111 #endif 112 return true; 113 } 114 115 bool DriverBase::Fuzz(vts::ComponentSpecificationMessage* message, 116 void** result) { 117 LOG(DEBUG) << "Fuzzing target component: " 118 << "class " << message->component_class() << " type " 119 << message->component_type() << " version " 120 << message->component_type_version(); 121 122 string function_name_prefix = GetFunctionNamePrefix(*message); 123 function_name_prefix_ = function_name_prefix.c_str(); 124 for (vts::FunctionSpecificationMessage func_msg : 125 *message->mutable_interface()->mutable_api()) { 126 Fuzz(&func_msg, result, ""); 127 } 128 return true; 129 } 130 131 void DriverBase::FunctionCallBegin() { 132 char product_path[4096]; 133 char product[128]; 134 char module_basepath[4096]; 135 136 snprintf(product_path, 4096, "%s/%s", default_gcov_output_basepath.c_str(), 137 "proc/self/cwd/out/target/product"); 138 DIR* srcdir = opendir(product_path); 139 if (!srcdir) { 140 LOG(WARNING) << "Couldn't open " << product_path; 141 return; 142 } 143 144 int dir_count = 0; 145 struct dirent* dent; 146 while ((dent = readdir(srcdir)) != NULL) { 147 struct stat st; 148 if (strcmp(dent->d_name, ".") == 0 || strcmp(dent->d_name, "..") == 0) { 149 continue; 150 } 151 if (fstatat(dirfd(srcdir), dent->d_name, &st, 0) < 0) { 152 LOG(ERROR) << "Error " << dent->d_name; 153 continue; 154 } 155 if (S_ISDIR(st.st_mode)) { 156 LOG(DEBUG) << "dir " << dent->d_name; 157 strcpy(product, dent->d_name); 158 dir_count++; 159 } 160 } 161 closedir(srcdir); 162 if (dir_count != 1) { 163 LOG(ERROR) << "More than one product dir found."; 164 return; 165 } 166 167 int n = snprintf(module_basepath, 4096, "%s/%s/obj/SHARED_LIBRARIES", 168 product_path, product); 169 if (n <= 0 || n >= 4096) { 170 LOG(ERROR) << "Couln't get module_basepath"; 171 return; 172 } 173 srcdir = opendir(module_basepath); 174 if (!srcdir) { 175 LOG(ERROR) << "Couln't open " << module_basepath; 176 return; 177 } 178 179 if (component_filename_ != NULL) { 180 dir_count = 0; 181 string target = string(component_filename_) + "_intermediates"; 182 bool hit = false; 183 while ((dent = readdir(srcdir)) != NULL) { 184 struct stat st; 185 if (strcmp(dent->d_name, ".") == 0 || strcmp(dent->d_name, "..") == 0) { 186 continue; 187 } 188 if (fstatat(dirfd(srcdir), dent->d_name, &st, 0) < 0) { 189 LOG(ERROR) << "Error " << dent->d_name; 190 continue; 191 } 192 if (S_ISDIR(st.st_mode)) { 193 LOG(DEBUG) << "module_basepath " << string(dent->d_name); 194 if (string(dent->d_name) == target) { 195 LOG(DEBUG) << "hit"; 196 hit = true; 197 } 198 dir_count++; 199 } 200 } 201 if (hit) { 202 free(gcov_output_basepath_); 203 gcov_output_basepath_ = 204 (char*)malloc(strlen(module_basepath) + target.length() + 2); 205 if (!gcov_output_basepath_) { 206 LOG(ERROR) << "Couldn't alloc memory"; 207 return; 208 } 209 sprintf(gcov_output_basepath_, "%s/%s", module_basepath, target.c_str()); 210 RemoveDir(gcov_output_basepath_); 211 } 212 } else { 213 LOG(ERROR) << "component_filename_ is NULL"; 214 } 215 // TODO: check how it works when there already is a file. 216 closedir(srcdir); 217 } 218 219 bool DriverBase::ReadGcdaFile(const string& basepath, const string& filename, 220 FunctionSpecificationMessage* msg) { 221 #if VTS_GCOV_DEBUG 222 LOG(DEBUG) << "file = " << dent->d_name; 223 #endif 224 if (string(filename).rfind(".gcda") != string::npos) { 225 string buffer = basepath + "/" + filename; 226 vector<unsigned> processed_data = 227 android::vts::GcdaRawCoverageParser(buffer.c_str()).Parse(); 228 for (const auto& data : processed_data) { 229 msg->mutable_processed_coverage_data()->Add(data); 230 } 231 232 FILE* gcda_file = fopen(buffer.c_str(), "rb"); 233 if (!gcda_file) { 234 LOG(ERROR) << "Unable to open a gcda file. " << buffer; 235 } else { 236 LOG(DEBUG) << "Opened a gcda file. " << buffer; 237 fseek(gcda_file, 0, SEEK_END); 238 long gcda_file_size = ftell(gcda_file); 239 #if VTS_GCOV_DEBUG 240 LOG(DEBUG) << "File size " << gcda_file_size << " bytes"; 241 #endif 242 fseek(gcda_file, 0, SEEK_SET); 243 244 char* gcda_file_buffer = (char*)malloc(gcda_file_size + 1); 245 if (!gcda_file_buffer) { 246 LOG(ERROR) << "Unable to allocate memory to read a gcda file."; 247 } else { 248 if (fread(gcda_file_buffer, gcda_file_size, 1, gcda_file) != 1) { 249 LOG(ERROR) << "File read error"; 250 } else { 251 #if VTS_GCOV_DEBUG 252 LOG(DEBUG) << "GCDA field populated."; 253 #endif 254 gcda_file_buffer[gcda_file_size] = '\0'; 255 NativeCodeCoverageRawDataMessage* raw_msg = 256 msg->mutable_raw_coverage_data()->Add(); 257 raw_msg->set_file_path(filename.c_str()); 258 string gcda_file_buffer_string(gcda_file_buffer, gcda_file_size); 259 raw_msg->set_gcda(gcda_file_buffer_string); 260 free(gcda_file_buffer); 261 } 262 } 263 fclose(gcda_file); 264 } 265 #if USE_GCOV_DEBUG 266 if (result) { 267 for (unsigned int index = 0; index < result->size(); index++) { 268 LOG(DEBUG) << result->at(index); 269 } 270 } 271 #endif 272 return true; 273 } 274 return false; 275 } 276 277 bool DriverBase::ScanAllGcdaFiles(const string& basepath, 278 FunctionSpecificationMessage* msg) { 279 DIR* srcdir = opendir(basepath.c_str()); 280 if (!srcdir) { 281 LOG(ERROR) << "Couln't open " << basepath; 282 return false; 283 } 284 285 struct dirent* dent; 286 while ((dent = readdir(srcdir)) != NULL) { 287 #if VTS_GCOV_DEBUG 288 LOG(DEBUG) << "readdir(" << basepath << ") for " << dent->d_name; 289 #endif 290 struct stat st; 291 if (strcmp(dent->d_name, ".") == 0 || strcmp(dent->d_name, "..") == 0) { 292 continue; 293 } 294 if (fstatat(dirfd(srcdir), dent->d_name, &st, 0) < 0) { 295 LOG(ERROR) << "error " << dent->d_name; 296 continue; 297 } 298 if (S_ISDIR(st.st_mode)) { 299 ScanAllGcdaFiles(basepath + "/" + dent->d_name, msg); 300 } else { 301 ReadGcdaFile(basepath, dent->d_name, msg); 302 } 303 } 304 #if VTS_GCOV_DEBUG 305 LOG(DEBUG) << "closedir(" << srcdir << ")"; 306 #endif 307 closedir(srcdir); 308 return true; 309 } 310 311 bool DriverBase::FunctionCallEnd(FunctionSpecificationMessage* msg) { 312 #if USE_GCOV 313 target_loader_.GcovFlush(); 314 // find the file. 315 if (!gcov_output_basepath_) { 316 LOG(WARNING) << "No gcov basepath set"; 317 return ScanAllGcdaFiles(default_gcov_output_basepath, msg); 318 } 319 DIR* srcdir = opendir(gcov_output_basepath_); 320 if (!srcdir) { 321 LOG(WARNING) << "Couln't open " << gcov_output_basepath_; 322 return false; 323 } 324 325 struct dirent* dent; 326 while ((dent = readdir(srcdir)) != NULL) { 327 LOG(DEBUG) << "readdir(" << srcdir << ") for " << dent->d_name; 328 329 struct stat st; 330 if (strcmp(dent->d_name, ".") == 0 || strcmp(dent->d_name, "..") == 0) { 331 continue; 332 } 333 if (fstatat(dirfd(srcdir), dent->d_name, &st, 0) < 0) { 334 LOG(ERROR) << "error " << dent->d_name; 335 continue; 336 } 337 if (!S_ISDIR(st.st_mode) && 338 ReadGcdaFile(gcov_output_basepath_, dent->d_name, msg)) { 339 break; 340 } 341 } 342 LOG(DEBUG) << "closedir(" << srcdir << ")"; 343 closedir(srcdir); 344 #endif 345 return true; 346 } 347 348 } // namespace vts 349 } // namespace android 350