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 
RemoveDir(char * path)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 
DriverBase(int target_class)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 
~DriverBase()73 DriverBase::~DriverBase() { free(component_filename_); }
74 
wfn()75 void wfn() { LOG(DEBUG) << "debug"; }
76 
ffn()77 void ffn() { LOG(DEBUG) << "debug"; }
78 
LoadTargetComponent(const char * target_dll_path)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 
Fuzz(vts::ComponentSpecificationMessage * message,void ** result)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              << GetVersionString(message->component_type_version_major(),
121                                  message->component_type_version_minor());
122 
123   string function_name_prefix = GetFunctionNamePrefix(*message);
124   function_name_prefix_ = function_name_prefix.c_str();
125   for (vts::FunctionSpecificationMessage func_msg :
126        *message->mutable_interface()->mutable_api()) {
127     Fuzz(&func_msg, result, "");
128   }
129   return true;
130 }
131 
FunctionCallBegin()132 void DriverBase::FunctionCallBegin() {
133   char product_path[4096];
134   char product[128];
135   char module_basepath[4096];
136 
137   snprintf(product_path, 4096, "%s/%s", default_gcov_output_basepath.c_str(),
138            "proc/self/cwd/out/target/product");
139   DIR* srcdir = opendir(product_path);
140   if (!srcdir) {
141     LOG(WARNING) << "Couldn't open " << product_path;
142     return;
143   }
144 
145   int dir_count = 0;
146   struct dirent* dent;
147   while ((dent = readdir(srcdir)) != NULL) {
148     struct stat st;
149     if (strcmp(dent->d_name, ".") == 0 || strcmp(dent->d_name, "..") == 0) {
150       continue;
151     }
152     if (fstatat(dirfd(srcdir), dent->d_name, &st, 0) < 0) {
153       LOG(ERROR) << "Error " << dent->d_name;
154       continue;
155     }
156     if (S_ISDIR(st.st_mode)) {
157       LOG(DEBUG) << "dir " << dent->d_name;
158       strcpy(product, dent->d_name);
159       dir_count++;
160     }
161   }
162   closedir(srcdir);
163   if (dir_count != 1) {
164     LOG(ERROR) << "More than one product dir found.";
165     return;
166   }
167 
168   int n = snprintf(module_basepath, 4096, "%s/%s/obj/SHARED_LIBRARIES",
169                    product_path, product);
170   if (n <= 0 || n >= 4096) {
171     LOG(ERROR) << "Couln't get module_basepath";
172     return;
173   }
174   srcdir = opendir(module_basepath);
175   if (!srcdir) {
176     LOG(ERROR) << "Couln't open " << module_basepath;
177     return;
178   }
179 
180   if (component_filename_ != NULL) {
181     dir_count = 0;
182     string target = string(component_filename_) + "_intermediates";
183     bool hit = false;
184     while ((dent = readdir(srcdir)) != NULL) {
185       struct stat st;
186       if (strcmp(dent->d_name, ".") == 0 || strcmp(dent->d_name, "..") == 0) {
187         continue;
188       }
189       if (fstatat(dirfd(srcdir), dent->d_name, &st, 0) < 0) {
190         LOG(ERROR) << "Error " << dent->d_name;
191         continue;
192       }
193       if (S_ISDIR(st.st_mode)) {
194         LOG(DEBUG) << "module_basepath " << string(dent->d_name);
195         if (string(dent->d_name) == target) {
196           LOG(DEBUG) << "hit";
197           hit = true;
198         }
199         dir_count++;
200       }
201     }
202     if (hit) {
203       free(gcov_output_basepath_);
204       gcov_output_basepath_ =
205           (char*)malloc(strlen(module_basepath) + target.length() + 2);
206       if (!gcov_output_basepath_) {
207         LOG(ERROR) << "Couldn't alloc memory";
208         return;
209       }
210       sprintf(gcov_output_basepath_, "%s/%s", module_basepath, target.c_str());
211       RemoveDir(gcov_output_basepath_);
212     }
213   } else {
214     LOG(ERROR) << "component_filename_ is NULL";
215   }
216   // TODO: check how it works when there already is a file.
217   closedir(srcdir);
218 }
219 
ReadGcdaFile(const string & basepath,const string & filename,FunctionSpecificationMessage * msg)220 bool DriverBase::ReadGcdaFile(const string& basepath, const string& filename,
221                               FunctionSpecificationMessage* msg) {
222 #if VTS_GCOV_DEBUG
223   LOG(DEBUG) << "file = " << dent->d_name;
224 #endif
225   if (string(filename).rfind(".gcda") != string::npos) {
226     string buffer = basepath + "/" + filename;
227     vector<unsigned> processed_data =
228         android::vts::GcdaRawCoverageParser(buffer.c_str()).Parse();
229     for (const auto& data : processed_data) {
230       msg->mutable_processed_coverage_data()->Add(data);
231     }
232 
233     FILE* gcda_file = fopen(buffer.c_str(), "rb");
234     if (!gcda_file) {
235       LOG(ERROR) << "Unable to open a gcda file. " << buffer;
236     } else {
237       LOG(DEBUG) << "Opened a gcda file. " << buffer;
238       fseek(gcda_file, 0, SEEK_END);
239       long gcda_file_size = ftell(gcda_file);
240 #if VTS_GCOV_DEBUG
241       LOG(DEBUG) << "File size " << gcda_file_size << " bytes";
242 #endif
243       fseek(gcda_file, 0, SEEK_SET);
244 
245       char* gcda_file_buffer = (char*)malloc(gcda_file_size + 1);
246       if (!gcda_file_buffer) {
247         LOG(ERROR) << "Unable to allocate memory to read a gcda file.";
248       } else {
249         if (fread(gcda_file_buffer, gcda_file_size, 1, gcda_file) != 1) {
250           LOG(ERROR) << "File read error";
251         } else {
252 #if VTS_GCOV_DEBUG
253           LOG(DEBUG) << "GCDA field populated.";
254 #endif
255           gcda_file_buffer[gcda_file_size] = '\0';
256           NativeCodeCoverageRawDataMessage* raw_msg =
257               msg->mutable_raw_coverage_data()->Add();
258           raw_msg->set_file_path(filename.c_str());
259           string gcda_file_buffer_string(gcda_file_buffer, gcda_file_size);
260           raw_msg->set_gcda(gcda_file_buffer_string);
261           free(gcda_file_buffer);
262         }
263       }
264       fclose(gcda_file);
265     }
266 #if USE_GCOV_DEBUG
267     if (result) {
268       for (unsigned int index = 0; index < result->size(); index++) {
269         LOG(DEBUG) << result->at(index);
270       }
271     }
272 #endif
273     return true;
274   }
275   return false;
276 }
277 
ScanAllGcdaFiles(const string & basepath,FunctionSpecificationMessage * msg)278 bool DriverBase::ScanAllGcdaFiles(const string& basepath,
279                                   FunctionSpecificationMessage* msg) {
280   DIR* srcdir = opendir(basepath.c_str());
281   if (!srcdir) {
282     LOG(ERROR) << "Couln't open " << basepath;
283     return false;
284   }
285 
286   struct dirent* dent;
287   while ((dent = readdir(srcdir)) != NULL) {
288 #if VTS_GCOV_DEBUG
289     LOG(DEBUG) << "readdir(" << basepath << ") for " << dent->d_name;
290 #endif
291     struct stat st;
292     if (strcmp(dent->d_name, ".") == 0 || strcmp(dent->d_name, "..") == 0) {
293       continue;
294     }
295     if (fstatat(dirfd(srcdir), dent->d_name, &st, 0) < 0) {
296       LOG(ERROR) << "error " << dent->d_name;
297       continue;
298     }
299     if (S_ISDIR(st.st_mode)) {
300       ScanAllGcdaFiles(basepath + "/" + dent->d_name, msg);
301     } else {
302       ReadGcdaFile(basepath, dent->d_name, msg);
303     }
304   }
305 #if VTS_GCOV_DEBUG
306   LOG(DEBUG) << "closedir(" << srcdir << ")";
307 #endif
308   closedir(srcdir);
309   return true;
310 }
311 
FunctionCallEnd(FunctionSpecificationMessage * msg)312 bool DriverBase::FunctionCallEnd(FunctionSpecificationMessage* msg) {
313 #if USE_GCOV
314   target_loader_.GcovFlush();
315   // find the file.
316   if (!gcov_output_basepath_) {
317     LOG(WARNING) << "No gcov basepath set";
318     return ScanAllGcdaFiles(default_gcov_output_basepath, msg);
319   }
320   DIR* srcdir = opendir(gcov_output_basepath_);
321   if (!srcdir) {
322     LOG(WARNING) << "Couln't open " << gcov_output_basepath_;
323     return false;
324   }
325 
326   struct dirent* dent;
327   while ((dent = readdir(srcdir)) != NULL) {
328     LOG(DEBUG) << "readdir(" << srcdir << ") for " << dent->d_name;
329 
330     struct stat st;
331     if (strcmp(dent->d_name, ".") == 0 || strcmp(dent->d_name, "..") == 0) {
332       continue;
333     }
334     if (fstatat(dirfd(srcdir), dent->d_name, &st, 0) < 0) {
335       LOG(ERROR) << "error " << dent->d_name;
336       continue;
337     }
338     if (!S_ISDIR(st.st_mode) &&
339         ReadGcdaFile(gcov_output_basepath_, dent->d_name, msg)) {
340       break;
341     }
342   }
343   LOG(DEBUG) << "closedir(" << srcdir << ")";
344   closedir(srcdir);
345 #endif
346   return true;
347 }
348 
349 }  // namespace vts
350 }  // namespace android
351