Home | History | Annotate | Download | only in driver_base
      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