1 //
2 // Copyright 2018 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 "VtsResourceManager"
17
18 #include "resource_manager/VtsResourceManager.h"
19
20 #include <dlfcn.h>
21 #include <fcntl.h>
22 #include <sys/stat.h>
23 #include <regex>
24
25 #include "test/vts/proto/ComponentSpecificationMessage.pb.h"
26 #include "test/vts/proto/VtsResourceControllerMessage.pb.h"
27
28 using android::hardware::kSynchronizedReadWrite;
29 using android::hardware::kUnsynchronizedWrite;
30
31 using namespace std;
32
33 namespace android {
34 namespace vts {
35
VtsResourceManager()36 VtsResourceManager::VtsResourceManager() {}
37
~VtsResourceManager()38 VtsResourceManager::~VtsResourceManager() {}
39
ProcessHidlHandleCommand(const HidlHandleRequestMessage & hidl_handle_request,HidlHandleResponseMessage * hidl_handle_response)40 void VtsResourceManager::ProcessHidlHandleCommand(
41 const HidlHandleRequestMessage& hidl_handle_request,
42 HidlHandleResponseMessage* hidl_handle_response) {
43 HidlHandleOp operation = hidl_handle_request.operation();
44 HandleId handle_id = hidl_handle_request.handle_id();
45 HandleDataValueMessage handle_info = hidl_handle_request.handle_info();
46 size_t read_data_size = hidl_handle_request.read_data_size();
47 const void* write_data =
48 static_cast<const void*>(hidl_handle_request.write_data().c_str());
49 size_t write_data_size = hidl_handle_request.write_data().length();
50 bool success = false;
51
52 switch (operation) {
53 case HANDLE_PROTO_CREATE_FILE: {
54 if (handle_info.fd_val().size() == 0) {
55 LOG(ERROR) << "No files to open.";
56 break;
57 }
58
59 // TODO: currently only support opening a single file.
60 // Support any file descriptor type in the future.
61 FdMessage file_desc_info = handle_info.fd_val(0);
62 if (file_desc_info.type() != FILE_TYPE) {
63 LOG(ERROR) << "Currently only support file type.";
64 break;
65 }
66
67 string filepath = file_desc_info.file_name();
68 int flag;
69 int mode = 0;
70 // Translate the mode into C++ flags and modes.
71 if (file_desc_info.file_mode_str() == "r" ||
72 file_desc_info.file_mode_str() == "rb") {
73 flag = O_RDONLY;
74 } else if (file_desc_info.file_mode_str() == "w" ||
75 file_desc_info.file_mode_str() == "wb") {
76 flag = O_WRONLY | O_CREAT | O_TRUNC;
77 mode = S_IRWXU; // User has the right to read/write/execute.
78 } else if (file_desc_info.file_mode_str() == "a" ||
79 file_desc_info.file_mode_str() == "ab") {
80 flag = O_WRONLY | O_CREAT | O_APPEND;
81 mode = S_IRWXU;
82 } else if (file_desc_info.file_mode_str() == "r+" ||
83 file_desc_info.file_mode_str() == "rb+" ||
84 file_desc_info.file_mode_str() == "r+b") {
85 flag = O_RDWR;
86 } else if (file_desc_info.file_mode_str() == "w+" ||
87 file_desc_info.file_mode_str() == "wb+" ||
88 file_desc_info.file_mode_str() == "w+b") {
89 flag = O_RDWR | O_CREAT | O_TRUNC;
90 mode = S_IRWXU;
91 } else if (file_desc_info.file_mode_str() == "a+" ||
92 file_desc_info.file_mode_str() == "ab+" ||
93 file_desc_info.file_mode_str() == "a+b") {
94 flag = O_RDWR | O_CREAT | O_APPEND;
95 mode = S_IRWXU;
96 } else if (file_desc_info.file_mode_str() == "x" ||
97 file_desc_info.file_mode_str() == "x+") {
98 struct stat buffer;
99 if (stat(filepath.c_str(), &buffer) == 0) {
100 LOG(ERROR) << "Host side creates a file with mode x, "
101 << "but file already exists";
102 break;
103 }
104 flag = O_CREAT;
105 mode = S_IRWXU;
106 if (file_desc_info.file_mode_str() == "x+") {
107 flag |= O_RDWR;
108 } else {
109 flag |= O_WRONLY;
110 }
111 } else {
112 LOG(ERROR) << "Unknown file mode.";
113 break;
114 }
115
116 // Convert repeated int field into vector.
117 vector<int> int_data(write_data_size);
118 transform(handle_info.int_val().cbegin(), handle_info.int_val().cend(),
119 int_data.begin(), [](const int& item) { return item; });
120 // Call API on hidl_handle driver to create a file handle.
121 int new_handle_id =
122 hidl_handle_driver_.CreateFileHandle(filepath, flag, mode, int_data);
123 hidl_handle_response->set_new_handle_id(new_handle_id);
124 success = new_handle_id != -1;
125 break;
126 }
127 case HANDLE_PROTO_READ_FILE: {
128 char read_data[read_data_size];
129 // Call API on hidl_handle driver to read the file.
130 ssize_t read_success_bytes = hidl_handle_driver_.ReadFile(
131 handle_id, static_cast<void*>(read_data), read_data_size);
132 success = read_success_bytes != -1;
133 hidl_handle_response->set_read_data(
134 string(read_data, read_success_bytes));
135 break;
136 }
137 case HANDLE_PROTO_WRITE_FILE: {
138 // Call API on hidl_handle driver to write to the file.
139 ssize_t write_success_bytes =
140 hidl_handle_driver_.WriteFile(handle_id, write_data, write_data_size);
141 success = write_success_bytes != -1;
142 hidl_handle_response->set_write_data_size(write_success_bytes);
143 break;
144 }
145 case HANDLE_PROTO_DELETE: {
146 // Call API on hidl_handle driver to unregister the handle object.
147 success = hidl_handle_driver_.UnregisterHidlHandle(handle_id);
148 break;
149 }
150 default:
151 LOG(ERROR) << "Unknown operation.";
152 break;
153 }
154 hidl_handle_response->set_success(success);
155 }
156
RegisterHidlHandle(const VariableSpecificationMessage & hidl_handle_msg)157 int VtsResourceManager::RegisterHidlHandle(
158 const VariableSpecificationMessage& hidl_handle_msg) {
159 size_t hidl_handle_address =
160 hidl_handle_msg.handle_value().hidl_handle_address();
161 if (hidl_handle_address == 0) {
162 LOG(ERROR) << "Invalid hidl_handle address."
163 << "HAL driver either didn't set the address or "
164 << "set a null pointer.";
165 return -1; // check for null pointer
166 }
167 return hidl_handle_driver_.RegisterHidlHandle(hidl_handle_address);
168 }
169
GetHidlHandleAddress(const VariableSpecificationMessage & hidl_handle_msg,size_t * result)170 bool VtsResourceManager::GetHidlHandleAddress(
171 const VariableSpecificationMessage& hidl_handle_msg, size_t* result) {
172 int handle_id = hidl_handle_msg.handle_value().handle_id();
173 bool success = hidl_handle_driver_.GetHidlHandleAddress(handle_id, result);
174 return success;
175 }
176
ProcessHidlMemoryCommand(const HidlMemoryRequestMessage & hidl_memory_request,HidlMemoryResponseMessage * hidl_memory_response)177 void VtsResourceManager::ProcessHidlMemoryCommand(
178 const HidlMemoryRequestMessage& hidl_memory_request,
179 HidlMemoryResponseMessage* hidl_memory_response) {
180 size_t mem_size = hidl_memory_request.mem_size();
181 int mem_id = hidl_memory_request.mem_id();
182 uint64_t start = hidl_memory_request.start();
183 uint64_t length = hidl_memory_request.length();
184 const string& write_data = hidl_memory_request.write_data();
185 bool success = false;
186
187 switch (hidl_memory_request.operation()) {
188 case MEM_PROTO_ALLOCATE: {
189 int new_mem_id = hidl_memory_driver_.Allocate(mem_size);
190 hidl_memory_response->set_new_mem_id(new_mem_id);
191 success = new_mem_id != -1;
192 break;
193 }
194 case MEM_PROTO_START_READ: {
195 success = hidl_memory_driver_.Read(mem_id);
196 break;
197 }
198 case MEM_PROTO_START_READ_RANGE: {
199 success = hidl_memory_driver_.ReadRange(mem_id, start, length);
200 break;
201 }
202 case MEM_PROTO_START_UPDATE: {
203 success = hidl_memory_driver_.Update(mem_id);
204 break;
205 }
206 case MEM_PROTO_START_UPDATE_RANGE: {
207 success = hidl_memory_driver_.UpdateRange(mem_id, start, length);
208 break;
209 }
210 case MEM_PROTO_UPDATE_BYTES: {
211 success = hidl_memory_driver_.UpdateBytes(mem_id, write_data.c_str(),
212 length, start);
213 break;
214 }
215 case MEM_PROTO_READ_BYTES: {
216 char read_data[length];
217 success = hidl_memory_driver_.ReadBytes(mem_id, read_data, length, start);
218 hidl_memory_response->set_read_data(string(read_data, length));
219 break;
220 }
221 case MEM_PROTO_COMMIT: {
222 success = hidl_memory_driver_.Commit(mem_id);
223 break;
224 }
225 case MEM_PROTO_GET_SIZE: {
226 size_t result_mem_size;
227 success = hidl_memory_driver_.GetSize(mem_id, &result_mem_size);
228 hidl_memory_response->set_mem_size(result_mem_size);
229 break;
230 }
231 default:
232 LOG(ERROR) << "unknown operation in hidl_memory_driver.";
233 break;
234 }
235 hidl_memory_response->set_success(success);
236 }
237
RegisterHidlMemory(const VariableSpecificationMessage & hidl_memory_msg)238 int VtsResourceManager::RegisterHidlMemory(
239 const VariableSpecificationMessage& hidl_memory_msg) {
240 size_t hidl_mem_address =
241 hidl_memory_msg.hidl_memory_value().hidl_mem_address();
242 if (hidl_mem_address == 0) {
243 LOG(ERROR) << "Resource manager: invalid hidl_memory address."
244 << "HAL driver either didn't set the address or "
245 << "set a null pointer.";
246 return -1; // check for null pointer
247 }
248 return hidl_memory_driver_.RegisterHidlMemory(hidl_mem_address);
249 }
250
GetHidlMemoryAddress(const VariableSpecificationMessage & hidl_memory_msg,size_t * result)251 bool VtsResourceManager::GetHidlMemoryAddress(
252 const VariableSpecificationMessage& hidl_memory_msg, size_t* result) {
253 int mem_id = hidl_memory_msg.hidl_memory_value().mem_id();
254 bool success = hidl_memory_driver_.GetHidlMemoryAddress(mem_id, result);
255 return success;
256 }
257
ProcessFmqCommand(const FmqRequestMessage & fmq_request,FmqResponseMessage * fmq_response)258 void VtsResourceManager::ProcessFmqCommand(const FmqRequestMessage& fmq_request,
259 FmqResponseMessage* fmq_response) {
260 const string& data_type = fmq_request.data_type();
261 // Find the correct function with template to process FMQ operation.
262 auto iterator = func_map_.find(data_type);
263 if (iterator == func_map_.end()) { // queue not found
264 LOG(ERROR) << "Resource manager: current FMQ driver doesn't support type "
265 << data_type;
266 fmq_response->set_success(false);
267 } else {
268 (this->*(iterator->second))(fmq_request, fmq_response);
269 }
270 }
271
RegisterFmq(const VariableSpecificationMessage & queue_msg)272 int VtsResourceManager::RegisterFmq(
273 const VariableSpecificationMessage& queue_msg) {
274 size_t queue_desc_addr = queue_msg.fmq_value(0).fmq_desc_address();
275 if (queue_desc_addr == 0) {
276 LOG(ERROR)
277 << "Resource manager: invalid queue descriptor address."
278 << "HAL driver either didn't set the address or set a null pointer.";
279 return -1; // check for null pointer
280 }
281
282 FmqRequestMessage fmq_request;
283 FmqResponseMessage fmq_response;
284 fmq_request.set_operation(FMQ_CREATE);
285 fmq_request.set_sync(queue_msg.type() == TYPE_FMQ_SYNC);
286 // TODO: support user-defined types in the future, only support scalar types
287 // for now.
288 fmq_request.set_data_type(queue_msg.fmq_value(0).scalar_type());
289 fmq_request.set_queue_desc_addr(queue_desc_addr);
290 ProcessFmqCommand(fmq_request, &fmq_response);
291 return fmq_response.queue_id();
292 }
293
GetQueueDescAddress(const VariableSpecificationMessage & queue_msg,size_t * result)294 bool VtsResourceManager::GetQueueDescAddress(
295 const VariableSpecificationMessage& queue_msg, size_t* result) {
296 FmqRequestMessage fmq_request;
297 FmqResponseMessage fmq_response;
298 fmq_request.set_operation(FMQ_GET_DESC_ADDR);
299 fmq_request.set_sync(queue_msg.type() == TYPE_FMQ_SYNC);
300 // TODO: support user-defined types in the future, only support scalar types
301 // for now.
302 fmq_request.set_data_type(queue_msg.fmq_value(0).scalar_type());
303 fmq_request.set_queue_id(queue_msg.fmq_value(0).fmq_id());
304 ProcessFmqCommand(fmq_request, &fmq_response);
305 bool success = fmq_response.success();
306 *result = fmq_response.sizet_return_val();
307 return success;
308 }
309
310 template <typename T>
ProcessFmqCommandWithType(const FmqRequestMessage & fmq_request,FmqResponseMessage * fmq_response)311 void VtsResourceManager::ProcessFmqCommandWithType(
312 const FmqRequestMessage& fmq_request, FmqResponseMessage* fmq_response) {
313 // Infers queue flavor and calls the internal method.
314 if (fmq_request.sync()) {
315 ProcessFmqCommandInternal<T, kSynchronizedReadWrite>(fmq_request,
316 fmq_response);
317 } else {
318 ProcessFmqCommandInternal<T, kUnsynchronizedWrite>(fmq_request,
319 fmq_response);
320 }
321 }
322
323 template <typename T, hardware::MQFlavor flavor>
ProcessFmqCommandInternal(const FmqRequestMessage & fmq_request,FmqResponseMessage * fmq_response)324 void VtsResourceManager::ProcessFmqCommandInternal(
325 const FmqRequestMessage& fmq_request, FmqResponseMessage* fmq_response) {
326 const string& data_type = fmq_request.data_type();
327 int queue_id = fmq_request.queue_id();
328 size_t queue_size = fmq_request.queue_size();
329 bool blocking = fmq_request.blocking();
330 bool reset_pointers = fmq_request.reset_pointers();
331 size_t write_data_size = fmq_request.write_data_size();
332 T write_data[write_data_size];
333 size_t read_data_size = fmq_request.read_data_size();
334 T read_data[read_data_size];
335 size_t queue_desc_addr = fmq_request.queue_desc_addr();
336 int64_t time_out_nanos = fmq_request.time_out_nanos();
337 // TODO: The three variables below are manually created.
338 // In the future, get these from host side when we support long-form
339 // blocking from host side.
340 uint32_t read_notification = 0;
341 uint32_t write_notification = 0;
342 atomic<uint32_t> event_flag_word;
343 bool success = false;
344 size_t sizet_result;
345
346 switch (fmq_request.operation()) {
347 case FMQ_CREATE: {
348 int new_queue_id = -1;
349 if (queue_id == -1) {
350 if (queue_desc_addr == 0) {
351 new_queue_id =
352 fmq_driver_.CreateFmq<T, flavor>(data_type, queue_size, blocking);
353 } else {
354 new_queue_id =
355 fmq_driver_.CreateFmq<T, flavor>(data_type, queue_desc_addr);
356 }
357 } else {
358 new_queue_id = fmq_driver_.CreateFmq<T, flavor>(data_type, queue_id,
359 reset_pointers);
360 }
361 fmq_response->set_queue_id(new_queue_id);
362 success = new_queue_id != -1;
363 break;
364 }
365 case FMQ_READ: {
366 success = fmq_driver_.ReadFmq<T, flavor>(data_type, queue_id, read_data,
367 read_data_size);
368 if (!FmqCpp2Proto<T>(fmq_response, data_type, read_data,
369 read_data_size)) {
370 LOG(ERROR) << "Resource manager: failed to convert C++ type into "
371 << "protobuf message for type " << data_type;
372 break;
373 }
374 break;
375 }
376 case FMQ_READ_BLOCKING: {
377 success = fmq_driver_.ReadFmqBlocking<T, flavor>(
378 data_type, queue_id, read_data, read_data_size, time_out_nanos);
379 if (!FmqCpp2Proto<T>(fmq_response, data_type, read_data,
380 read_data_size)) {
381 LOG(ERROR) << "Resource manager: failed to convert C++ type into "
382 << "protobuf message for type " << data_type;
383 break;
384 }
385 break;
386 }
387 case FMQ_READ_BLOCKING_LONG: {
388 // TODO: implement a meaningful long-form blocking mechanism
389 // Currently passing a dummy event flag word.
390 success = fmq_driver_.ReadFmqBlocking<T, flavor>(
391 data_type, queue_id, read_data, read_data_size, read_notification,
392 write_notification, time_out_nanos, &event_flag_word);
393 if (!FmqCpp2Proto<T>(fmq_response, data_type, read_data,
394 read_data_size)) {
395 LOG(ERROR) << "Resource manager: failed to convert C++ type into "
396 << "protobuf message for type " << data_type;
397 break;
398 }
399 break;
400 }
401 case FMQ_WRITE: {
402 if (!FmqProto2Cpp<T>(fmq_request, write_data, write_data_size)) {
403 LOG(ERROR) << "Resource manager: failed to convert protobuf message "
404 << "into C++ types for type " << data_type;
405 break;
406 }
407 success = fmq_driver_.WriteFmq<T, flavor>(data_type, queue_id, write_data,
408 write_data_size);
409 break;
410 }
411 case FMQ_WRITE_BLOCKING: {
412 if (!FmqProto2Cpp<T>(fmq_request, write_data, write_data_size)) {
413 LOG(ERROR) << "Resource manager: failed to convert protobuf message "
414 << "into C++ types for type " << data_type;
415 break;
416 }
417 success = fmq_driver_.WriteFmqBlocking<T, flavor>(
418 data_type, queue_id, write_data, write_data_size, time_out_nanos);
419 break;
420 }
421 case FMQ_WRITE_BLOCKING_LONG: {
422 // TODO: implement a meaningful long-form blocking mechanism
423 // Currently passing a dummy event flag word.
424 if (!FmqProto2Cpp<T>(fmq_request, write_data, write_data_size)) {
425 LOG(ERROR) << "Resource manager: failed to convert protobuf message "
426 << "into C++ types for type " << data_type;
427 break;
428 }
429 success = fmq_driver_.WriteFmqBlocking<T, flavor>(
430 data_type, queue_id, write_data, write_data_size, read_notification,
431 write_notification, time_out_nanos, &event_flag_word);
432 break;
433 }
434 case FMQ_AVAILABLE_WRITE: {
435 success = fmq_driver_.AvailableToWrite<T, flavor>(data_type, queue_id,
436 &sizet_result);
437 fmq_response->set_sizet_return_val(sizet_result);
438 break;
439 }
440 case FMQ_AVAILABLE_READ: {
441 success = fmq_driver_.AvailableToRead<T, flavor>(data_type, queue_id,
442 &sizet_result);
443 fmq_response->set_sizet_return_val(sizet_result);
444 break;
445 }
446 case FMQ_GET_QUANTUM_SIZE: {
447 success = fmq_driver_.GetQuantumSize<T, flavor>(data_type, queue_id,
448 &sizet_result);
449 fmq_response->set_sizet_return_val(sizet_result);
450 break;
451 }
452 case FMQ_GET_QUANTUM_COUNT: {
453 success = fmq_driver_.GetQuantumCount<T, flavor>(data_type, queue_id,
454 &sizet_result);
455 fmq_response->set_sizet_return_val(sizet_result);
456 break;
457 }
458 case FMQ_IS_VALID: {
459 success = fmq_driver_.IsValid<T, flavor>(data_type, queue_id);
460 break;
461 }
462 case FMQ_GET_DESC_ADDR: {
463 success = fmq_driver_.GetQueueDescAddress<T, flavor>(data_type, queue_id,
464 &sizet_result);
465 fmq_response->set_sizet_return_val(sizet_result);
466 break;
467 }
468 default:
469 LOG(ERROR) << "Resource manager: Unsupported FMQ operation.";
470 }
471 fmq_response->set_success(success);
472 }
473
474 template <typename T>
FmqProto2Cpp(const FmqRequestMessage & fmq_request,T * write_data,size_t write_data_size)475 bool VtsResourceManager::FmqProto2Cpp(const FmqRequestMessage& fmq_request,
476 T* write_data, size_t write_data_size) {
477 const string& data_type = fmq_request.data_type();
478 // Read from different proto fields based on type.
479 if (data_type == "int8_t") {
480 int8_t* convert_data = reinterpret_cast<int8_t*>(write_data);
481 for (int i = 0; i < write_data_size; i++) {
482 convert_data[i] = (fmq_request.write_data(i).scalar_value().int8_t());
483 }
484 } else if (data_type == "uint8_t") {
485 uint8_t* convert_data = reinterpret_cast<uint8_t*>(write_data);
486 for (int i = 0; i < write_data_size; i++) {
487 convert_data[i] = fmq_request.write_data(i).scalar_value().uint8_t();
488 }
489 } else if (data_type == "int16_t") {
490 int16_t* convert_data = reinterpret_cast<int16_t*>(write_data);
491 for (int i = 0; i < write_data_size; i++) {
492 convert_data[i] = fmq_request.write_data(i).scalar_value().int16_t();
493 }
494 } else if (data_type == "uint16_t") {
495 uint16_t* convert_data = reinterpret_cast<uint16_t*>(write_data);
496 for (int i = 0; i < write_data_size; i++) {
497 convert_data[i] = fmq_request.write_data(i).scalar_value().uint16_t();
498 }
499 } else if (data_type == "int32_t") {
500 int32_t* convert_data = reinterpret_cast<int32_t*>(write_data);
501 for (int i = 0; i < write_data_size; i++) {
502 convert_data[i] = fmq_request.write_data(i).scalar_value().int32_t();
503 }
504 } else if (data_type == "uint32_t") {
505 uint32_t* convert_data = reinterpret_cast<uint32_t*>(write_data);
506 for (int i = 0; i < write_data_size; i++) {
507 convert_data[i] = fmq_request.write_data(i).scalar_value().uint32_t();
508 }
509 } else if (data_type == "int64_t") {
510 int64_t* convert_data = reinterpret_cast<int64_t*>(write_data);
511 for (int i = 0; i < write_data_size; i++) {
512 convert_data[i] = fmq_request.write_data(i).scalar_value().int64_t();
513 }
514 } else if (data_type == "uint64_t") {
515 uint64_t* convert_data = reinterpret_cast<uint64_t*>(write_data);
516 for (int i = 0; i < write_data_size; i++) {
517 convert_data[i] = fmq_request.write_data(i).scalar_value().uint64_t();
518 }
519 } else if (data_type == "float_t") {
520 float* convert_data = reinterpret_cast<float*>(write_data);
521 for (int i = 0; i < write_data_size; i++) {
522 convert_data[i] = fmq_request.write_data(i).scalar_value().float_t();
523 }
524 } else if (data_type == "double_t") {
525 double* convert_data = reinterpret_cast<double*>(write_data);
526 for (int i = 0; i < write_data_size; i++) {
527 convert_data[i] = fmq_request.write_data(i).scalar_value().double_t();
528 }
529 } else if (data_type == "bool_t") {
530 bool* convert_data = reinterpret_cast<bool*>(write_data);
531 for (int i = 0; i < write_data_size; i++) {
532 convert_data[i] = fmq_request.write_data(i).scalar_value().bool_t();
533 }
534 } else {
535 // Encounter a predefined type in HAL service.
536 LOG(INFO) << "Resource manager: detected host side specifies a "
537 << "predefined type.";
538 void* shared_lib_obj = LoadSharedLibFromTypeName(data_type);
539
540 // Locate the symbol for the translation function.
541 typedef void (*parse_fn)(const VariableSpecificationMessage&, T*,
542 const string&);
543 parse_fn parser =
544 (parse_fn)(GetTranslationFuncPtr(shared_lib_obj, data_type, true));
545 if (!parser) return false; // Error logged in helper function.
546
547 // Parse the data from protobuf to C++.
548 for (int i = 0; i < write_data_size; i++) {
549 (*parser)(fmq_request.write_data(i), &write_data[i], "");
550 }
551 dlclose(shared_lib_obj);
552 }
553 return true;
554 }
555
556 // TODO: support user-defined types, only support primitive types now.
557 template <typename T>
FmqCpp2Proto(FmqResponseMessage * fmq_response,const string & data_type,T * read_data,size_t read_data_size)558 bool VtsResourceManager::FmqCpp2Proto(FmqResponseMessage* fmq_response,
559 const string& data_type, T* read_data,
560 size_t read_data_size) {
561 fmq_response->clear_read_data();
562 // Write to different proto fields based on type.
563 if (data_type == "int8_t") {
564 int8_t* convert_data = reinterpret_cast<int8_t*>(read_data);
565 for (size_t i = 0; i < read_data_size; i++) {
566 VariableSpecificationMessage* item = fmq_response->add_read_data();
567 item->set_type(TYPE_SCALAR);
568 item->set_scalar_type(data_type);
569 (item->mutable_scalar_value())->set_int8_t(convert_data[i]);
570 }
571 } else if (data_type == "uint8_t") {
572 uint8_t* convert_data = reinterpret_cast<uint8_t*>(read_data);
573 for (size_t i = 0; i < read_data_size; i++) {
574 VariableSpecificationMessage* item = fmq_response->add_read_data();
575 item->set_type(TYPE_SCALAR);
576 item->set_scalar_type(data_type);
577 (item->mutable_scalar_value())->set_uint8_t(convert_data[i]);
578 }
579 } else if (data_type == "int16_t") {
580 int16_t* convert_data = reinterpret_cast<int16_t*>(read_data);
581 for (size_t i = 0; i < read_data_size; i++) {
582 VariableSpecificationMessage* item = fmq_response->add_read_data();
583 item->set_type(TYPE_SCALAR);
584 item->set_scalar_type(data_type);
585 (item->mutable_scalar_value())->set_int16_t(convert_data[i]);
586 }
587 } else if (data_type == "uint16_t") {
588 uint16_t* convert_data = reinterpret_cast<uint16_t*>(read_data);
589 for (size_t i = 0; i < read_data_size; i++) {
590 VariableSpecificationMessage* item = fmq_response->add_read_data();
591 item->set_type(TYPE_SCALAR);
592 item->set_scalar_type(data_type);
593 (item->mutable_scalar_value())->set_uint16_t(convert_data[i]);
594 }
595 } else if (data_type == "int32_t") {
596 int32_t* convert_data = reinterpret_cast<int32_t*>(read_data);
597 for (size_t i = 0; i < read_data_size; i++) {
598 VariableSpecificationMessage* item = fmq_response->add_read_data();
599 item->set_type(TYPE_SCALAR);
600 item->set_scalar_type(data_type);
601 (item->mutable_scalar_value())->set_int32_t(convert_data[i]);
602 }
603 } else if (data_type == "uint32_t") {
604 uint32_t* convert_data = reinterpret_cast<uint32_t*>(read_data);
605 for (size_t i = 0; i < read_data_size; i++) {
606 VariableSpecificationMessage* item = fmq_response->add_read_data();
607 item->set_type(TYPE_SCALAR);
608 item->set_scalar_type(data_type);
609 (item->mutable_scalar_value())->set_uint32_t(convert_data[i]);
610 }
611 } else if (data_type == "int64_t") {
612 int64_t* convert_data = reinterpret_cast<int64_t*>(read_data);
613 for (size_t i = 0; i < read_data_size; i++) {
614 VariableSpecificationMessage* item = fmq_response->add_read_data();
615 item->set_type(TYPE_SCALAR);
616 item->set_scalar_type(data_type);
617 (item->mutable_scalar_value())->set_int64_t(convert_data[i]);
618 }
619 } else if (data_type == "uint64_t") {
620 uint64_t* convert_data = reinterpret_cast<uint64_t*>(read_data);
621 for (size_t i = 0; i < read_data_size; i++) {
622 VariableSpecificationMessage* item = fmq_response->add_read_data();
623 item->set_type(TYPE_SCALAR);
624 item->set_scalar_type(data_type);
625 (item->mutable_scalar_value())->set_uint64_t(convert_data[i]);
626 }
627 } else if (data_type == "float_t") {
628 float* convert_data = reinterpret_cast<float*>(read_data);
629 for (size_t i = 0; i < read_data_size; i++) {
630 VariableSpecificationMessage* item = fmq_response->add_read_data();
631 item->set_type(TYPE_SCALAR);
632 item->set_scalar_type(data_type);
633 (item->mutable_scalar_value())->set_float_t(convert_data[i]);
634 }
635 } else if (data_type == "double_t") {
636 double* convert_data = reinterpret_cast<double*>(read_data);
637 for (size_t i = 0; i < read_data_size; i++) {
638 VariableSpecificationMessage* item = fmq_response->add_read_data();
639 item->set_type(TYPE_SCALAR);
640 item->set_scalar_type(data_type);
641 (item->mutable_scalar_value())->set_double_t(convert_data[i]);
642 }
643 } else if (data_type == "bool_t") {
644 bool* convert_data = reinterpret_cast<bool*>(read_data);
645 for (size_t i = 0; i < read_data_size; i++) {
646 VariableSpecificationMessage* item = fmq_response->add_read_data();
647 item->set_type(TYPE_SCALAR);
648 item->set_scalar_type(data_type);
649 (item->mutable_scalar_value())->set_bool_t(convert_data[i]);
650 }
651 } else {
652 // Encounter a predefined type in HAL service.
653 LOG(INFO) << "Resource manager: detected host side specifies a "
654 << "predefined type.";
655 void* shared_lib_obj = LoadSharedLibFromTypeName(data_type);
656 if (!shared_lib_obj) return false;
657
658 // Locate the symbol for the translation function.
659 typedef void (*set_result_fn)(VariableSpecificationMessage*, T);
660 set_result_fn parser =
661 (set_result_fn)(GetTranslationFuncPtr(shared_lib_obj, data_type, 0));
662 if (!parser) return false; // Error logged in helper function.
663
664 // Parse the data from C++ to protobuf.
665 for (int i = 0; i < read_data_size; i++) {
666 VariableSpecificationMessage* item = fmq_response->add_read_data();
667 (*parser)(item, read_data[i]);
668 }
669 dlclose(shared_lib_obj);
670 }
671 return true;
672 }
673
LoadSharedLibFromTypeName(const string & data_type)674 void* VtsResourceManager::LoadSharedLibFromTypeName(const string& data_type) {
675 // Base path.
676 // TODO: Consider determining the path and bitness by passing a field
677 // in the protobuf message.
678 string shared_lib_path = "/data/local/tmp/64/";
679 // Start searching after the first ::
680 size_t curr_index = 0;
681 size_t next_index;
682 bool success = false;
683 regex version_regex("V[0-9]+_[0-9]+");
684 const string split_str = "::";
685
686 while ((next_index = data_type.find(split_str, curr_index)) != string::npos) {
687 if (curr_index == next_index) {
688 // No character between the current :: and the next ::
689 // Likely it is the first :: in the type name.
690 curr_index = next_index + split_str.length();
691 continue;
692 }
693 string curr_string = data_type.substr(curr_index, next_index - curr_index);
694 // Check if it is a version, e.g. V4_0.
695 if (regex_match(curr_string, version_regex)) {
696 size_t length = shared_lib_path.length();
697 // Change _ into ., e.g. V4_0 to V4.0.
698 size_t separator = curr_string.find("_");
699 curr_string.replace(separator, 1, ".");
700 // Use @ before version.
701 shared_lib_path.replace(length - 1, 1, "@");
702 // Exclude V in the front.
703 shared_lib_path += curr_string.substr(1);
704 success = true;
705 break;
706 } else {
707 shared_lib_path += curr_string + ".";
708 }
709 // Start searching from the next ::
710 curr_index = next_index + split_str.length();
711 }
712 // Failed to parse the shared library name from type name.
713 if (!success) return nullptr;
714
715 shared_lib_path += "-vts.driver.so";
716 // Load the shared library that contains translation functions.
717 void* shared_lib_obj = dlopen(shared_lib_path.c_str(), RTLD_LAZY);
718 if (!shared_lib_obj) {
719 LOG(ERROR) << "Resource manager: failed to load shared lib "
720 << shared_lib_path << " for type " << data_type;
721 return nullptr;
722 }
723 LOG(INFO) << "Resource manager: successfully loaded shared library "
724 << shared_lib_path;
725 return shared_lib_obj;
726 }
727
GetTranslationFuncPtr(void * shared_lib_obj,const string & data_type,bool is_proto_to_cpp)728 void* VtsResourceManager::GetTranslationFuncPtr(void* shared_lib_obj,
729 const string& data_type,
730 bool is_proto_to_cpp) {
731 string translation_func_name = data_type;
732 // Replace all :: with __.
733 // TODO: there might be a special case where part of the type name involves
734 // a single :. Consider fixing this in the future.
735 replace(translation_func_name.begin(), translation_func_name.end(), ':', '_');
736
737 void* func_ptr = nullptr;
738 if (is_proto_to_cpp) {
739 func_ptr =
740 dlsym(shared_lib_obj, ("MessageTo" + translation_func_name).c_str());
741 if (!func_ptr) {
742 LOG(ERROR) << "Resource manager: failed to load function name "
743 << "MessageTo" << translation_func_name << " or "
744 << "EnumValue" << translation_func_name
745 << " to parse protobuf message into C++ type.";
746 }
747 } else {
748 func_ptr =
749 dlsym(shared_lib_obj, ("SetResult" + translation_func_name).c_str());
750 if (!func_ptr) {
751 LOG(ERROR) << "Resource manager: failed to load the function name "
752 << "SetResult" << translation_func_name
753 << " to parse C++ type into protobuf message.";
754 }
755 }
756 return func_ptr;
757 }
758
759 } // namespace vts
760 } // namespace android
761