• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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