Home | History | Annotate | Download | only in replayer
      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 #include "replayer/VtsHidlHalReplayer.h"
     17 
     18 #include <fstream>
     19 #include <iomanip>
     20 #include <iostream>
     21 #include <sstream>
     22 #include <string>
     23 
     24 #include <cutils/properties.h>
     25 #include <google/protobuf/text_format.h>
     26 
     27 #include "fuzz_tester/FuzzerBase.h"
     28 #include "fuzz_tester/FuzzerWrapper.h"
     29 #include "specification_parser/InterfaceSpecificationParser.h"
     30 #include "test/vts/proto/ComponentSpecificationMessage.pb.h"
     31 #include "test/vts/proto/VtsProfilingMessage.pb.h"
     32 #include "utils/StringUtil.h"
     33 
     34 using namespace std;
     35 
     36 namespace android {
     37 namespace vts {
     38 
     39 VtsHidlHalReplayer::VtsHidlHalReplayer(const string& spec_path,
     40                                        const string& callback_socket_name)
     41     : spec_path_(spec_path), callback_socket_name_(callback_socket_name) {}
     42 
     43 bool VtsHidlHalReplayer::LoadComponentSpecification(const string& package,
     44     float version, const string& interface_name,
     45     ComponentSpecificationMessage* message) {
     46   if (spec_path_.empty()) {
     47     cerr << __func__ << "spec file not specified. " << endl;
     48     return false;
     49   }
     50   if (!message) {
     51     cerr << __func__ << "message could not be NULL. " << endl;
     52     return false;
     53   }
     54   string package_name = package;
     55   ReplaceSubString(package_name, ".", "/");
     56   stringstream stream;
     57   stream << fixed << setprecision(1) << version;
     58   string version_str = stream.str();
     59   string spec_file = spec_path_ + '/' + package_name + '/'
     60       + version_str + '/' + interface_name.substr(1) + ".vts";
     61   cout << "spec_file: " << spec_file << endl;
     62   if (InterfaceSpecificationParser::parse(spec_file.c_str(), message)) {
     63     if (message->component_class() != HAL_HIDL) {
     64       cerr << __func__ << ": only support Hidl Hal. " << endl;
     65       return false;
     66     }
     67 
     68     if (message->package() != package
     69         || message->component_type_version() != version
     70         || message->component_name() != interface_name) {
     71       cerr << __func__ << ": spec file mismatch. " << "expected package: "
     72            << package << " version: " << version << " interface_name: "
     73            << interface_name << ", actual: package: " << message->package()
     74            << " version: " << message->component_type_version()
     75            << " interface_name: " << message->component_name();
     76       return false;
     77     }
     78   } else {
     79     cerr << __func__ << ": can not parse spec: " << spec_file << endl;
     80     return false;
     81   }
     82   return true;
     83 }
     84 
     85 bool VtsHidlHalReplayer::ParseTrace(const string& trace_file,
     86     vector<VtsProfilingRecord>* call_msgs,
     87     vector<VtsProfilingRecord>* result_msgs) {
     88   std::ifstream in(trace_file, std::ios::in);
     89   bool new_record = true;
     90   string record_str;
     91   string line;
     92 
     93   while (getline(in, line)) {
     94     // Assume records are separated by '\n'.
     95     if (line.empty()) {
     96       new_record = false;
     97     }
     98     if (new_record) {
     99       record_str += line + "\n";
    100     } else {
    101       unique_ptr<VtsProfilingRecord> record(new VtsProfilingRecord());
    102       if (!google::protobuf::TextFormat::MergeFromString(record_str,
    103                                                          record.get())) {
    104         cerr << __func__ << ": Can't parse a given function message: "
    105             << record_str << endl;
    106         return false;
    107       }
    108       if (record->event() == InstrumentationEventType::SERVER_API_ENTRY
    109           || record->event() == InstrumentationEventType::CLIENT_API_ENTRY
    110           || record->event() == InstrumentationEventType::SYNC_CALLBACK_ENTRY
    111           || record->event() == InstrumentationEventType::ASYNC_CALLBACK_ENTRY
    112           || record->event() == InstrumentationEventType::PASSTHROUGH_ENTRY) {
    113         call_msgs->push_back(*record);
    114       } else {
    115         result_msgs->push_back(*record);
    116       }
    117       new_record = true;
    118       record_str.clear();
    119     }
    120   }
    121   return true;
    122 }
    123 
    124 bool VtsHidlHalReplayer::ReplayTrace(const string& spec_lib_file_path,
    125     const string& trace_file, const string& hal_service_name) {
    126   if (!wrapper_.LoadInterfaceSpecificationLibrary(spec_lib_file_path.c_str())) {
    127     return false;
    128   }
    129 
    130   // Determine the binder/passthrough mode based on system property.
    131   char get_sub_property[PROPERTY_VALUE_MAX];
    132   bool get_stub = false; /* default is binderized */
    133   if (property_get("vts.hidl.get_stub", get_sub_property, "") > 0) {
    134     if (!strcmp(get_sub_property, "true") || !strcmp(get_sub_property, "True")
    135         || !strcmp(get_sub_property, "1")) {
    136       get_stub = true;
    137     }
    138   }
    139 
    140   // Parse the trace file to get the sequence of function calls.
    141   vector<VtsProfilingRecord> call_msgs;
    142   vector<VtsProfilingRecord> result_msgs;
    143   if (!ParseTrace(trace_file, &call_msgs, &result_msgs)) {
    144     cerr << __func__ << ": couldn't parse trace file: " << trace_file << endl;
    145     return false;
    146   }
    147   // Replay each function call from the trace and verify the results.
    148   string interface = "";
    149   FuzzerBase* fuzzer = NULL;
    150   for (size_t i = 0; i < call_msgs.size(); i++) {
    151     VtsProfilingRecord call_msg = call_msgs[i];
    152     VtsProfilingRecord expected_result_msg = result_msgs[i];
    153     cout << __func__ << ": replay function: " << call_msg.DebugString();
    154 
    155     // Load spec file and get fuzzer.
    156     if (interface != call_msg.interface()) {
    157       interface = call_msg.interface();
    158       ComponentSpecificationMessage interface_specification_message;
    159       if (!LoadComponentSpecification(call_msg.package(), call_msg.version(),
    160                                       call_msg.interface(),
    161                                       &interface_specification_message)) {
    162         cerr << __func__ << ": can not load component spec: " << spec_path_;
    163         return false;
    164       }
    165       fuzzer = wrapper_.GetFuzzer(interface_specification_message);
    166       if (!fuzzer) {
    167         cerr << __func__ << ": couldn't get a fuzzer base class" << endl;
    168         return false;
    169       }
    170 
    171       if (!fuzzer->GetService(get_stub, hal_service_name.c_str())) {
    172         cerr << __func__ << ": couldn't get service: " << hal_service_name
    173              << endl;
    174         return false;
    175       }
    176     }
    177 
    178     vts::FunctionSpecificationMessage result_msg;
    179     if (!fuzzer->CallFunction(call_msg.func_msg(), callback_socket_name_,
    180                               &result_msg)) {
    181       cerr << __func__ << ": replay function fail." << endl;
    182       return false;
    183     }
    184     if (!fuzzer->VerifyResults(expected_result_msg.func_msg(), result_msg)) {
    185       // Verification is not strict, i.e. if fail, output error message and
    186       // continue the process.
    187       cerr << __func__ << ": verification fail.\nexpected_result: "
    188           << expected_result_msg.func_msg().DebugString() << "\nactual_result: "
    189           << result_msg.DebugString() << endl;
    190     }
    191   }
    192   return true;
    193 }
    194 
    195 }  // namespace vts
    196 }  // namespace android
    197