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
VtsHidlHalReplayer(const string & spec_path,const string & callback_socket_name)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
LoadComponentSpecification(const string & package,float version,const string & interface_name,ComponentSpecificationMessage * message)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
ParseTrace(const string & trace_file,vector<VtsProfilingRecord> * call_msgs,vector<VtsProfilingRecord> * result_msgs)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
ReplayTrace(const string & spec_lib_file_path,const string & trace_file,const string & hal_service_name)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