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