1# 2# Copyright (C) 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# 16import logging 17 18from vts.proto import AndroidSystemControlMessage_pb2 as ASysCtrlMsg 19from vts.proto import VtsResourceControllerMessage_pb2 as ResControlMsg 20from vts.proto import ComponentSpecificationMessage_pb2 as CompSpecMsg 21from vts.utils.python.mirror import mirror_object 22 23 24class ResourceFmqMirror(mirror_object.MirrorObject): 25 """This is a class that mirrors FMQ resource allocated on the target side. 26 27 Attributes: 28 SUPPORTED_SCALAR_TYPES: set, contains all scalar types supported by FMQ. 29 If the type of FMQ is one of those, this class 30 prepares the write data from caller provided 31 Python data. 32 _client: VtsTcpClient, the TCP client instance. 33 _queue_id: int, used to identify the queue object on the target side. 34 _data_type: type of data in the queue. 35 _sync: bool, whether the queue is synchronized. 36 """ 37 38 SUPPORTED_SCALAR_TYPES = { 39 "uint8_t", "int8_t", "uint16_t", "int16_t", "uint32_t", "int32_t", 40 "uint64_t", "int64_t", "bool_t", "double_t" 41 } 42 43 def __init__(self, data_type, sync, client, queue_id=-1): 44 """Initialize a FMQ mirror. 45 46 Args: 47 data_type: string, type of data in the queue 48 (e.g. "uint32_t", "int16_t"). 49 sync: bool, whether queue is synchronized (only has one reader). 50 client: VtsTcpClient, specifies the session that this mirror use. 51 queue_id: int, identifies the queue on the target side. 52 Optional if caller initializes a new FMQ mirror. 53 """ 54 super(ResourceFmqMirror, self).__init__(client) 55 self._data_type = data_type 56 self._sync = sync 57 self._queue_id = queue_id 58 59 def _create(self, queue_id, queue_size, blocking, reset_pointers): 60 """Initiate a fast message queue object on the target side. 61 62 This method registers a FMQ object on the target side, and stores 63 the queue_id in the class attribute. 64 Users should not directly call this method because it will overwrite 65 the original queue_id stored in the mirror object, leaving that 66 queue object out of reference. 67 Users should always call InitFmq() in mirror_tracker.py to obtain a 68 new queue object. 69 70 Args: 71 queue_id: int, identifies the message queue object on the target side. 72 queue_size: int, size of the queue. 73 blocking: bool, whether blocking is enabled in the queue. 74 reset_pointers: bool, whether to reset read/write pointers when 75 creating a message queue object based on an existing message queue. 76 """ 77 # Prepare arguments. 78 request_msg = self._createTemplateRequestMessage( 79 ResControlMsg.FMQ_CREATE, queue_id) 80 request_msg.queue_size = queue_size 81 request_msg.blocking = blocking 82 request_msg.reset_pointers = reset_pointers 83 84 # Send and receive data. 85 fmq_response = self._client.SendFmqRequest(request_msg) 86 if fmq_response is not None and fmq_response.queue_id != -1: 87 self._queue_id = fmq_response.queue_id 88 else: 89 self._queue_id = -1 90 logging.error("Failed to create a new queue object.") 91 92 def read(self, data, data_size): 93 """Initiate a non-blocking read request to FMQ driver. 94 95 Args: 96 data: list, data to be filled by this function. The list will 97 be emptied before the function starts to put read data into 98 it, which is consistent with the function behavior on the 99 target side. 100 data_size: int, length of data to read. 101 102 Returns: 103 bool, true if the operation succeeds, 104 false otherwise. 105 """ 106 # Prepare arguments. 107 del data[:] 108 request_msg = self._createTemplateRequestMessage( 109 ResControlMsg.FMQ_READ, self._queue_id) 110 request_msg.read_data_size = data_size 111 112 # Send and receive data. 113 fmq_response = self._client.SendFmqRequest(request_msg) 114 if fmq_response is not None and fmq_response.success: 115 self._extractReadData(fmq_response, data) 116 return True 117 return False 118 119 # TODO: support long-form blocking read in the future when there is use case. 120 def readBlocking(self, data, data_size, time_out_nanos=0): 121 """Initiate a blocking read request (short-form) to FMQ driver. 122 123 Args: 124 data: list, data to be filled by this function. The list will 125 be emptied before the function starts to put read data into 126 it, which is consistent with the function behavior on the 127 target side. 128 data_size: int, length of data to read. 129 time_out_nanos: int, wait time (in nanoseconds) when blocking. 130 The default value is 0 (no blocking). 131 132 Returns: 133 bool, true if the operation succeeds, 134 false otherwise. 135 """ 136 # Prepare arguments. 137 del data[:] 138 request_msg = self._createTemplateRequestMessage( 139 ResControlMsg.FMQ_READ_BLOCKING, self._queue_id) 140 request_msg.read_data_size = data_size 141 request_msg.time_out_nanos = time_out_nanos 142 143 # Send and receive data. 144 fmq_response = self._client.SendFmqRequest(request_msg) 145 if fmq_response is not None and fmq_response.success: 146 self._extractReadData(fmq_response, data) 147 return True 148 return False 149 150 def write(self, data, data_size): 151 """Initiate a non-blocking write request to FMQ driver. 152 153 Args: 154 data: list, data to be written. 155 data_size: int, length of data to write. 156 The function will only write data up until data_size, 157 i.e. extraneous data will be discarded. 158 159 Returns: 160 bool, true if the operation succeeds, 161 false otherwise. 162 """ 163 # Prepare arguments. 164 request_msg = self._createTemplateRequestMessage( 165 ResControlMsg.FMQ_WRITE, self._queue_id) 166 prepare_result = self._prepareWriteData(request_msg, data[:data_size]) 167 if not prepare_result: 168 # Prepare write data failure, error logged in _prepareWriteData(). 169 return False 170 171 # Send and receive data. 172 fmq_response = self._client.SendFmqRequest(request_msg) 173 if fmq_response is not None: 174 return fmq_response.success 175 return False 176 177 # TODO: support long-form blocking write in the future when there is use case. 178 def writeBlocking(self, data, data_size, time_out_nanos=0): 179 """Initiate a blocking write request (short-form) to FMQ driver. 180 181 Args: 182 data: list, data to be written. 183 data_size: int, length of data to write. 184 The function will only write data up until data_size, 185 i.e. extraneous data will be discarded. 186 time_out_nanos: int, wait time (in nanoseconds) when blocking. 187 The default value is 0 (no blocking). 188 189 Returns: 190 bool, true if the operation succeeds, 191 false otherwise. 192 """ 193 # Prepare arguments. 194 request_msg = self._createTemplateRequestMessage( 195 ResControlMsg.FMQ_WRITE_BLOCKING, self._queue_id) 196 prepare_result = self._prepareWriteData(request_msg, data[:data_size]) 197 if not prepare_result: 198 # Prepare write data failure, error logged in _prepareWriteData(). 199 return False 200 request_msg.time_out_nanos = time_out_nanos 201 202 # Send and receive data. 203 fmq_response = self._client.SendFmqRequest(request_msg) 204 if fmq_response is not None: 205 return fmq_response.success 206 return False 207 208 def availableToWrite(self): 209 """Get space available to write in the queue. 210 211 Returns: 212 int, number of slots available. 213 """ 214 # Prepare arguments. 215 request_msg = self._createTemplateRequestMessage( 216 ResControlMsg.FMQ_AVAILABLE_WRITE, self._queue_id) 217 218 # Send and receive data. 219 return self._processUtilMethod(request_msg) 220 221 def availableToRead(self): 222 """Get number of items available to read. 223 224 Returns: 225 int, number of items. 226 """ 227 # Prepare arguments. 228 request_msg = self._createTemplateRequestMessage( 229 ResControlMsg.FMQ_AVAILABLE_READ, self._queue_id) 230 231 # Send and receive data. 232 return self._processUtilMethod(request_msg) 233 234 def getQuantumSize(self): 235 """Get size of item in the queue. 236 237 Returns: 238 int, size of item. 239 """ 240 # Prepare arguments. 241 request_msg = self._createTemplateRequestMessage( 242 ResControlMsg.FMQ_GET_QUANTUM_SIZE, self._queue_id) 243 244 # send and receive data 245 return self._processUtilMethod(request_msg) 246 247 def getQuantumCount(self): 248 """Get number of items that fit in the queue. 249 250 Returns: 251 int, number of items. 252 """ 253 # Prepare arguments. 254 request_msg = self._createTemplateRequestMessage( 255 ResControlMsg.FMQ_GET_QUANTUM_COUNT, self._queue_id) 256 257 # Send and receive data. 258 return self._processUtilMethod(request_msg) 259 260 def isValid(self): 261 """Check if the queue is valid. 262 263 Returns: 264 bool, true if the queue is valid. 265 """ 266 # Prepare arguments. 267 request_msg = self._createTemplateRequestMessage( 268 ResControlMsg.FMQ_IS_VALID, self._queue_id) 269 270 # Send and receive data. 271 fmq_response = self._client.SendFmqRequest(request_msg) 272 if fmq_response is not None: 273 return fmq_response.success 274 return False 275 276 @property 277 def queueId(self): 278 """Gets the id assigned from the target side. 279 280 Returns: 281 int, id of the queue. 282 """ 283 return self._queue_id 284 285 @property 286 def dataType(self): 287 """Get the type of data of this FMQ mirror. 288 289 Returns: 290 string, type of data in the queue 291 """ 292 return self._data_type 293 294 @property 295 def sync(self): 296 """Get the synchronization option of this FMQ mirror. 297 298 Returns: 299 bool, true if the queue is synchronized (only has one reader). 300 """ 301 return self._sync 302 303 def _createTemplateRequestMessage(self, operation, queue_id): 304 """Creates a template FmqRequestMessage with common arguments among 305 all FMQ operations. 306 307 Args: 308 operation: FmqOp, fmq operations. 309 (see test/vts/proto/VtsResourceControllerMessage.proto). 310 queue_id: int, identifies the message queue object on target side. 311 312 Returns: 313 FmqRequestMessage, fmq request message. 314 (See test/vts/proto/VtsResourceControllerMessage.proto). 315 """ 316 request_msg = ResControlMsg.FmqRequestMessage() 317 request_msg.operation = operation 318 request_msg.data_type = self._data_type 319 request_msg.sync = self._sync 320 request_msg.queue_id = queue_id 321 return request_msg 322 323 def _prepareWriteData(self, request_msg, data): 324 """Converts python list to repeated protobuf field. 325 326 If the type of data in the queue is a supported scalar, caller can 327 directly supply the python native value. Otherwise, caller needs to 328 supply a list of VariableSpecificationMessage. 329 330 Args: 331 request_msg: FmqRequestMessage, arguments for a FMQ operation 332 request. 333 data: VariableSpecificationMessage list or a list of scalar values. 334 If the type of FMQ is scalar type, caller can directly 335 specify the Python scalar data. Otherwise, caller has to 336 provide each item as VariableSpecificationMessage. 337 338 Returns: 339 bool, true if preparation succeeds, false otherwise. 340 This function can fail if caller doesn't provide a list of 341 VariableSpecificationMessage when type of data in the queue 342 is not a supported scalar type. 343 """ 344 for curr_value in data: 345 new_message = request_msg.write_data.add() 346 if isinstance(curr_value, 347 CompSpecMsg.VariableSpecificationMessage): 348 new_message.CopyFrom(curr_value) 349 elif self._data_type in self.SUPPORTED_SCALAR_TYPES: 350 new_message.type = CompSpecMsg.TYPE_SCALAR 351 new_message.scalar_type = self._data_type 352 setattr(new_message.scalar_value, self._data_type, curr_value) 353 else: 354 logging.error("Need to provide VariableSpecificationMessage " + 355 "if type of data in the queue is not a " + 356 "supported scalar type.") 357 return False 358 return True 359 360 def _extractReadData(self, response_msg, data): 361 """Extracts read data from the response message returned by client. 362 363 Args: 364 response_msg: FmqResponseMessage, contains response from FMQ driver. 365 data: list, to be filled by this function. data buffer is provided 366 by caller, so this function will append every element to the 367 buffer. 368 """ 369 for item in response_msg.read_data: 370 data.append(self._client.GetPythonDataOfVariableSpecMsg(item)) 371 372 def _processUtilMethod(self, request_msg): 373 """Sends request message and process response message for util methods 374 that return an unsigned integer, 375 e.g. availableToWrite, availableToRead. 376 377 Args: 378 request_msg: FmqRequestMessage, arguments for a FMQ operation request. 379 380 Returns: int, information about the queue, 381 None if the operation is unsuccessful. 382 """ 383 fmq_response = self._client.SendFmqRequest(request_msg) 384 if fmq_response is not None and fmq_response.success: 385 return fmq_response.sizet_return_val 386 return None 387 388 389class ResourceHidlMemoryMirror(mirror_object.MirrorObject): 390 """This class mirrors hidl_memory resource allocated on the target side. 391 392 Attributes: 393 _client: the TCP client instance. 394 _mem_id: int, used to identify the memory region on the target side. 395 """ 396 397 def __init__(self, client, mem_id=-1): 398 super(ResourceHidlMemoryMirror, self).__init__(client) 399 self._mem_id = mem_id 400 401 def _allocate(self, mem_size): 402 """Initiate a hidl_memory region on the target side. 403 404 This method stores the mem_id in the class attribute. 405 Users should not directly call this method to get a new memory region, 406 because it will overwrite the original memory object with mem_id, 407 making that memory object out of reference. 408 Users should always call InitHidlMemory() in mirror_tracker.py to get 409 a new memory region. 410 411 Args: 412 mem_size: int, size of the requested memory region. 413 """ 414 # Prepare arguments. 415 request_msg = self._createTemplateRequestMessage( 416 ResControlMsg.MEM_PROTO_ALLOCATE) 417 request_msg.mem_size = mem_size 418 419 # Send and receive data. 420 response_msg = self._client.SendHidlMemoryRequest(request_msg) 421 if response_msg is not None and response_msg.new_mem_id != -1: 422 self._mem_id = response_msg.new_mem_id 423 else: 424 logging.error("Failed to allocate memory region.") 425 426 def read(self): 427 """Notify that caller will read the entire memory region. 428 429 Before every actual read operation, caller must call this method 430 or readRange() first. 431 432 Returns: 433 bool, true if the operation succeeds, false otherwise. 434 """ 435 request_msg = self._createTemplateRequestMessage( 436 ResControlMsg.MEM_PROTO_START_READ) 437 438 response_msg = self._client.SendHidlMemoryRequest(request_msg) 439 if response_msg is not None: 440 if not response_msg.success: 441 logging.error("Failed to find memory region with id %d", 442 self._mem_id) 443 return response_msg.success 444 return False 445 446 def readRange(self, start, length): 447 """Notify that caller will read only part of memory region. 448 449 Notify that caller will read starting at start and 450 ending at start + length. 451 Before every actual read operation, caller must call this method 452 or read() first. 453 454 Args: 455 start: int, offset from the start of memory region to be modified. 456 length: int, number of bytes to be modified. 457 458 Returns: 459 bool, true if the operation succeeds, false otherwise. 460 """ 461 request_msg = self._createTemplateRequestMessage( 462 ResControlMsg.MEM_PROTO_START_READ_RANGE) 463 request_msg.start = start 464 request_msg.length = length 465 466 response_msg = self._client.SendHidlMemoryRequest(request_msg) 467 if response_msg is not None: 468 if not response_msg.success: 469 logging.error("Failed to find memory region with id %d", 470 self._mem_id) 471 return response_msg.success 472 return False 473 474 def update(self): 475 """Notify that caller will possibly write to all memory region. 476 477 Before every actual write operation, caller must call this method 478 or updateRange() first. 479 480 Returns: 481 bool, true if the operation succeeds, false otherwise. 482 """ 483 request_msg = self._createTemplateRequestMessage( 484 ResControlMsg.MEM_PROTO_START_UPDATE) 485 486 response_msg = self._client.SendHidlMemoryRequest(request_msg) 487 if response_msg is not None: 488 if not response_msg.success: 489 logging.error("Failed to find memory region with id %d", 490 self._mem_id) 491 return response_msg.success 492 return False 493 494 def updateRange(self, start, length): 495 """Notify that caller will only write to part of memory region. 496 497 Notify that caller will only write starting at start and 498 ending at start + length. 499 Before every actual write operation, caller must call this method 500 or update() first. 501 502 Args: 503 start: int, offset from the start of memory region to be modified. 504 length: int, number of bytes to be modified. 505 506 Returns: 507 bool, true if the operation succeeds, false otherwise. 508 """ 509 request_msg = self._createTemplateRequestMessage( 510 ResControlMsg.MEM_PROTO_START_UPDATE_RANGE) 511 request_msg.start = start 512 request_msg.length = length 513 514 response_msg = self._client.SendHidlMemoryRequest(request_msg) 515 if response_msg is not None: 516 if not response_msg.success: 517 logging.error("Failed to find memory region with id %d", 518 self._mem_id) 519 return response_msg.success 520 return False 521 522 def readBytes(self, length, start=0): 523 """This method performs actual read operation. 524 525 This method helps caller perform actual read operation on the 526 memory region, because host side won't be able to cast c++ pointers. 527 528 Args: 529 length: int, number of bytes to read. 530 start: int, offset from the start of memory region to read. 531 532 Returns: 533 string, data read from memory. 534 Caller can perform conversion on the result to obtain the 535 corresponding data structure in python. 536 None, indicate if the read fails. 537 """ 538 request_msg = self._createTemplateRequestMessage( 539 ResControlMsg.MEM_PROTO_READ_BYTES) 540 request_msg.start = start 541 request_msg.length = length 542 543 response_msg = self._client.SendHidlMemoryRequest(request_msg) 544 if response_msg is not None: 545 if response_msg.success: 546 return response_msg.read_data 547 logging.error("Failed to find memory region with id %d", 548 self._mem_id) 549 return None 550 551 def updateBytes(self, data, length, start=0): 552 """This method performs actual write operation. 553 554 This method helps caller perform actual write operation on the 555 memory region, because host side won't be able to cast c++ pointers. 556 557 Args: 558 data: string, bytes to be written into memory. 559 Caller can use bytearray() function to convert python 560 data structures into python, and call str() on the resulting 561 bytearray object. 562 length: int, number of bytes to write. 563 start: int, offset from the start of memory region to be modified. 564 565 Returns: 566 bool, true if the operation succeeds, false otherwise. 567 """ 568 request_msg = self._createTemplateRequestMessage( 569 ResControlMsg.MEM_PROTO_UPDATE_BYTES) 570 request_msg.write_data = data 571 request_msg.start = start 572 request_msg.length = length 573 574 response_msg = self._client.SendHidlMemoryRequest(request_msg) 575 if response_msg is not None: 576 if not response_msg.success: 577 logging.error("Failed to find memory region with id %d", 578 self._mem_id) 579 return response_msg.success 580 return False 581 582 def commit(self): 583 """Caller signals done with operating on the memory region. 584 585 Caller needs to call this method after reading/writing. 586 587 Returns: 588 bool, true if the operation succeeds, false otherwise. 589 """ 590 request_msg = self._createTemplateRequestMessage( 591 ResControlMsg.MEM_PROTO_COMMIT) 592 593 response_msg = self._client.SendHidlMemoryRequest(request_msg) 594 if response_msg is not None: 595 if not response_msg.success: 596 logging.error("Failed to find memory region with id %d", 597 self._mem_id) 598 return response_msg.success 599 return False 600 601 def getSize(self): 602 """Gets the size of the memory region. 603 604 Returns: 605 int, size of memory region, -1 to signal operation failure. 606 """ 607 request_msg = self._createTemplateRequestMessage( 608 ResControlMsg.MEM_PROTO_GET_SIZE) 609 610 response_msg = self._client.SendHidlMemoryRequest(request_msg) 611 if response_msg is not None: 612 if response_msg.success: 613 return response_msg.mem_size 614 logging.error("Failed to find memory region with id %d", 615 self._mem_id) 616 return -1 617 618 @property 619 def memId(self): 620 """Gets the id assigned from the target side. 621 622 Returns: 623 int, id of the memory object. 624 """ 625 return self._mem_id 626 627 def _createTemplateRequestMessage(self, operation): 628 """Creates a template HidlMemoryRequestMessage. 629 630 This method creates a message that contains common arguments among 631 all hidl_memory operations. 632 633 Args: 634 operation: HidlMemoryOp, hidl_memory operations. 635 (see test/vts/proto/VtsResourceControllerMessage.proto). 636 637 Returns: 638 HidlMemoryRequestMessage, hidl_memory request message. 639 (See test/vts/proto/VtsResourceControllerMessage.proto). 640 """ 641 request_msg = ResControlMsg.HidlMemoryRequestMessage() 642 request_msg.operation = operation 643 request_msg.mem_id = self._mem_id 644 return request_msg 645 646 647class ResourceHidlHandleMirror(mirror_object.MirrorObject): 648 """This class mirrors hidl_handle resource allocated on the target side. 649 650 TODO: support more than file types in the future, e.g. socket, pipe. 651 652 Attributes: 653 _client: the TCP client instance. 654 _handle_id: int, used to identify the handle object on the target side. 655 """ 656 657 def __init__(self, client, handle_id=-1): 658 super(ResourceHidlHandleMirror, self).__init__(client) 659 self._handle_id = handle_id 660 661 def CleanUp(self): 662 """Close open file descriptors on target-side drivers. 663 664 Developers can call this method to close open file descriptors 665 in all handle objects. 666 Note: This method needs to be called before self._client 667 is disconnected. self._client is most likely initialized in 668 one of the hal_mirror. 669 """ 670 request_msg = self._createTemplateRequestMessage( 671 ResControlMsg.HANDLE_PROTO_DELETE) 672 self._client.SendHidlHandleRequest(request_msg) 673 674 def _createHandleForSingleFile(self, filepath, mode, int_data): 675 """Initiate a hidl_handle object containing a single file descriptor. 676 677 This method stores the handle_id in the class attribute. 678 Users should not directly call this method to create a new 679 handle object, because it will overwrite the original handle object, 680 making that handle object out of reference. 681 Users should always call InitHidlHandle() in mirror_tracker.py to get 682 a new handle object. 683 684 Args: 685 filepath: string, path to the file to be opened. 686 mode: string, specifying the mode to open the file. 687 int_data: int list, useful integers to store in the handle object. 688 """ 689 # Prepare arguments. 690 request_msg = self._createTemplateRequestMessage( 691 ResControlMsg.HANDLE_PROTO_CREATE_FILE) 692 request_msg.handle_info.num_fds = 1 693 request_msg.handle_info.num_ints = len(int_data) 694 695 # TODO: support more than one file descriptors at once. 696 # Add the file information into proto message. 697 fd_message = request_msg.handle_info.fd_val.add() 698 fd_message.type = CompSpecMsg.FILE_TYPE 699 fd_message.file_mode_str = mode 700 fd_message.file_name = filepath 701 702 # Add the integers into proto message. 703 request_msg.handle_info.int_val.extend(int_data) 704 705 # Send and receive data. 706 response_msg = self._client.SendHidlHandleRequest(request_msg) 707 if response_msg is not None and response_msg.new_handle_id != -1: 708 self._handle_id = response_msg.new_handle_id 709 else: 710 logging.error("Failed to create handle object.") 711 712 def readFile(self, read_data_size, index=0): 713 """Reads from a given file in the handle object. 714 715 Args: 716 read_data_size: int, number of bytes to read. 717 index: int, index of file among all files in the handle object. 718 Optional if host only wants to read from one file. 719 720 Returns: 721 string, data read from the file. 722 """ 723 # Prepare arguments. 724 request_msg = self._createTemplateRequestMessage( 725 ResControlMsg.HANDLE_PROTO_READ_FILE) 726 request_msg.read_data_size = read_data_size 727 728 # Send and receive data. 729 response_msg = self._client.SendHidlHandleRequest(request_msg) 730 if response_msg is not None and response_msg.success: 731 return response_msg.read_data 732 # TODO: more detailed error message. 733 logging.error("Failed to read from the file.") 734 return None 735 736 def writeFile(self, write_data, index=0): 737 """Writes to a given file to the handle object. 738 739 Args: 740 write_data: string, data to be written into file. 741 index: int, index of file among all files in the handle object. 742 Optional if host only wants to write into one file. 743 744 Returns: 745 int, number of bytes written. 746 """ 747 # Prepare arguments. 748 request_msg = self._createTemplateRequestMessage( 749 ResControlMsg.HANDLE_PROTO_WRITE_FILE) 750 request_msg.write_data = write_data 751 752 # Send and receive data. 753 response_msg = self._client.SendHidlHandleRequest(request_msg) 754 if response_msg is not None and response_msg.success: 755 return response_msg.write_data_size 756 # TODO: more detailed error message. 757 logging.error("Failed to write into the file.") 758 return None 759 760 @property 761 def handleId(self): 762 """Gets the id assigned from the target side. 763 764 Returns: 765 int, id of the handle object. 766 """ 767 return self._handle_id 768 769 def _createTemplateRequestMessage(self, operation): 770 """Creates a template HidlHandleRequestMessage. 771 772 This method creates a HidlHandleRequestMessage with common arguments 773 among all hidl_handle operations. 774 775 Args: 776 operation: HidlHandleOp, hidl_handle operations. 777 (see test/vts/proto/VtsResourceControllerMessage.proto). 778 779 Returns: 780 HidlHandleRequestMessage, hidl_handle request message. 781 (See test/vts/proto/VtsResourceControllerMessage.proto). 782 """ 783 request_msg = ResControlMsg.HidlHandleRequestMessage() 784 request_msg.operation = operation 785 request_msg.handle_id = self._handle_id 786 return request_msg 787