1#!/usr/bin/env python
2#
3# Copyright (C) 2018 The Android Open Source Project
4#
5# Licensed under the Apache License, Version 2.0 (the "License");
6# you may not use this file except in compliance with the License.
7# You may obtain a copy of the License at
8#
9#      http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS,
13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14# See the License for the specific language governing permissions and
15# limitations under the License.
16#
17
18import logging
19import random
20
21from vts.runners.host import asserts
22from vts.runners.host import base_test
23from vts.runners.host import const
24from vts.runners.host import test_runner
25from vts.proto import ComponentSpecificationMessage_pb2 as CompSpecMsg
26
27
28class VtsCodelabHidlMemoryTest(base_test.BaseTestClass):
29    """Test hidl_memory APIs from host side to target side and HAL server.
30
31    This class tests APIs to operate on memory object from host side.
32    It also tests sending memory objects (including argument and return values)
33    in HAL servers.
34    We use a test HAL service IMemoryTest.hal in this script.
35
36    Attributes:
37        MAX_RETRY: int, maximum times to check if HAL server has started.
38                   If server is still not started after MAX_RETRY times,
39                   stop the testcase.
40        SERVICE_NAME: string, script to start the memory test HAL server.
41        COMMAND_32: string, command to start the HAL server in a 32-bit device.
42        COMMAND_64: string, command to start the HAL server in a 64-bit device.
43        CHECK_COMMAND: string, command to check if memory HAL service
44                       has started.
45        MEM_VAL: int, data to fill the memory with.
46        MEM_SIZE: int, size of the memory region allocated on the target side.
47        _mem_obj: memory mirror object that users can use to read from or
48                  write into.
49        _tests_memory: HAL server instance that users can directly call API on.
50    """
51    # Some constants.
52    MAX_RETRY = 3
53    SERVICE_NAME = "hidl_test_servers"
54    COMMAND_32 = "/data/nativetest/" + SERVICE_NAME + "/" + SERVICE_NAME + " &"
55    COMMAND_64 = "/data/nativetest64/" + SERVICE_NAME + "/" + SERVICE_NAME + " &"
56    CHECK_COMMAND = "lshal --types=b | grep \"android.hardware.tests.memory@1.0\""
57    MEM_SIZE = 1024
58
59    def setUpClass(self):
60        """Do necessary setup including starting the HAL service.
61
62        This method starts the HAL service and loads it in the target-side
63        driver. It also initializes a memory object on the target side, and
64        users can use it for reading and writing.
65        """
66        self.dut = self.android_devices[0]
67        # Send command to start the HAL server.
68        if int(self.abi_bitness) == 64:
69            self.dut.shell.Execute(self.COMMAND_64)
70        else:
71            self.dut.shell.Execute(self.COMMAND_32)
72
73        # Wait until service is started.
74        # Retry at most three times.
75        start_hal_success = False
76        for _ in range(self.MAX_RETRY):
77            result = self.dut.shell.Execute(self.CHECK_COMMAND)
78            if result[const.STDOUT][0] != "":
79                start_hal_success = True  # setup successful
80                break
81            time.sleep(1)  # wait one second.
82        # memory HAL service is still not started after waiting for
83        # self.MAX_RETRY times, stop the testcase.
84        if not start_hal_success:
85            logging.error("Failed to start hidl_memory HAL service.")
86            return False
87
88        # Load a hidl_memory test hal driver.
89        self.dut.hal.InitHidlHal(
90            target_type="tests_memory",
91            target_basepaths=self.dut.libPaths,
92            target_version_major=1,
93            target_version_minor=0,
94            target_package="android.hardware.tests.memory",
95            target_component_name="IMemoryTest",
96            hw_binder_service_name="memory",
97            bits=int(self.abi_bitness),
98            is_test_hal=True)
99        # Create a shortcut for HAL server.
100        self._tests_memory = self.dut.hal.tests_memory
101
102        # Create a memory object on the client side.
103        self._mem_obj = self.dut.resource.InitHidlMemory(
104            mem_size=self.MEM_SIZE,
105            client=self.dut.hal.GetTcpClient("tests_memory"))
106
107        # Do necessary super class setup.
108        super(VtsCodelabHidlMemoryTest, self).setUpClass()
109
110    def testGetSize(self):
111        """Test getting memory size correctness. """
112        asserts.assertEqual(self.MEM_SIZE, self._mem_obj.getSize())
113
114    def testSimpleWriteRead(self):
115        """Test writing to the memory and reading the same data back. """
116        write_data = "abcdef"
117        # Write data into memory.
118        self._mem_obj.update()
119        self._mem_obj.updateBytes(write_data, len(write_data))
120        self._mem_obj.commit()
121
122        # Read data from memory.
123        self._mem_obj.read()
124        read_data = self._mem_obj.readBytes(len(write_data))
125        asserts.assertEqual(write_data, read_data)
126
127    def testLargeWriteRead(self):
128        """Test consecutive writes and reads using integers.
129
130        For each of the 5 iterations, write 5 integers into
131        different chunks of memory, and read them back.
132        """
133        for i in range(5):
134            # Writes five integers.
135            write_data = [random.randint(0, 100) for j in range(10)]
136            write_data_str = str(bytearray(write_data))
137            # Start writing at offset i * 5.
138            self._mem_obj.updateRange(i * 5, len(write_data_str))
139            self._mem_obj.updateBytes(write_data_str, len(write_data_str),
140                                      i * 5)
141            self._mem_obj.commit()
142
143            # Reads data back.
144            self._mem_obj.readRange(i * 5, len(write_data_str))
145            read_data_str = self._mem_obj.readBytes(len(write_data_str), i * 5)
146            read_data = list(bytearray(read_data_str))
147            # Check if read data is correct.
148            asserts.assertEqual(write_data, read_data)
149
150    def testWriteTwoRegionsInOneBuffer(self):
151        """Test writing into different regions in one memory buffer.
152
153        Writer requests the beginning of the first half and
154        the beginning of the second half of the buffer.
155        It writes to the second half, commits, and reads the data back.
156        Then it writes to the first half, commits, and reads the data back.
157        """
158        write_data1 = "abcdef"
159        write_data2 = "ghijklmno"
160
161        # Reserve both regions.
162        self._mem_obj.updateRange(0, len(write_data1))
163        self._mem_obj.updateRange(self.MEM_SIZE / 2, len(write_data2))
164        # Write to the second region.
165        self._mem_obj.updateBytes(write_data2, len(write_data2),
166                                  self.MEM_SIZE / 2)
167        self._mem_obj.commit()
168
169        # Read from the second region.
170        self._mem_obj.read()
171        read_data2 = self._mem_obj.readBytes(
172            len(write_data2), self.MEM_SIZE / 2)
173        self._mem_obj.commit()
174        # Check if read data is correct.
175        asserts.assertEqual(read_data2, write_data2)
176
177        # Write to the first region.
178        self._mem_obj.updateBytes(write_data1, len(write_data1))
179        self._mem_obj.commit()
180
181        # Read from the first region.
182        self._mem_obj.read()
183        read_data1 = self._mem_obj.readBytes(len(write_data1))
184        self._mem_obj.commit()
185        # Check if read data is correct.
186        asserts.assertEqual(write_data1, read_data1)
187
188    def testSharedMemory(self):
189        """Test HAL server API fillMemory(), which takes in hidl_memory.
190
191        The memory filled out by the HAL server should be seen by the client.
192        """
193        # Zero out memory.
194        self._mem_obj.update()
195        self._mem_obj.updateBytes("\0" * self.MEM_SIZE, self.MEM_SIZE)
196        self._mem_obj.commit()
197
198        # Tell HAL server to fill the memory, should be seen by the client,
199        # because they use shared memory.
200        var_msg = self.prepareHidlMemoryArgument(self._mem_obj.memId)
201        # Fill the memory with each byte be integer value 42.
202        self._tests_memory.fillMemory(var_msg, 42)
203        self._mem_obj.read()
204        read_data = self._mem_obj.readBytes(self.MEM_SIZE)
205        self._mem_obj.commit()
206
207        # Convert read_data to a list of chars, and convert them back to int8_t.
208        read_data = list(read_data)
209        read_data = map(lambda i: ord(i), read_data)
210
211        # Check read data.
212        asserts.assertEqual(read_data, [42] * self.MEM_SIZE)
213
214    def testSameMemoryDifferentId(self):
215        """Test HAL server API haveSomeMemory(), which returns hidl_memory.
216
217        haveSomeMemory() returns input memory directly.
218        We pass the client memory object to this API, and the return value
219        of this API should be registered in our target-side drivers as well.
220        The returned memory object is basically identical to the first memory
221        object held by the client.
222        They have different id, but they share the same memory region.
223        """
224        # Prepare a hidl_memory argument.
225        var_msg = self.prepareHidlMemoryArgument(self._mem_obj.memId)
226
227        # memory_client2 is identical to self._mem_obj because
228        # haveSomeMemory() API in the server just returns the input
229        # hidl_memory reference directly.
230        memory_client2 = self._tests_memory.haveSomeMemory(var_msg)
231        asserts.assertNotEqual(memory_client2, None)
232        asserts.assertNotEqual(memory_client2.memId, -1)
233        # Check these two clients are stored as different objects.
234        asserts.assertNotEqual(memory_client2.memId,
235                               self._mem_obj.memId)
236
237        # Fill the memory with each byte being integer value 50.
238        self._tests_memory.fillMemory(var_msg, 50)
239
240        # Both clients read.
241        self._mem_obj.read()
242        read_data1 = self._mem_obj.readBytes(self.MEM_SIZE)
243        self._mem_obj.commit()
244        memory_client2.read()
245        read_data2 = memory_client2.readBytes(self.MEM_SIZE)
246        memory_client2.commit()
247
248        # Convert read_data to a list of chars, and convert them back to int8_t.
249        read_data1 = list(read_data1)
250        read_data1 = map(lambda i: ord(i), read_data1)
251        read_data2 = list(read_data2)
252        read_data2 = map(lambda i: ord(i), read_data2)
253
254        # Check read data.
255        asserts.assertEqual(read_data1, [50] * self.MEM_SIZE)
256        asserts.assertEqual(read_data2, [50] * self.MEM_SIZE)
257
258    @staticmethod
259    def prepareHidlMemoryArgument(mem_id):
260        """Prepare VariableSpecificationMessage containing hidl_memory argument.
261
262        Args:
263            mem_id: int, identifies the memory object.
264
265        Returns:
266            VariableSpecificationMessage, specifies the memory id.
267        """
268        var_msg = CompSpecMsg.VariableSpecificationMessage()
269        var_msg.type = CompSpecMsg.TYPE_HIDL_MEMORY
270        var_msg.hidl_memory_value.mem_id = mem_id
271        return var_msg
272
273
274if __name__ == "__main__":
275    test_runner.main()
276