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