#!/usr/bin/env python3 # # Copyright (C) 2020 The Android Open Source Project # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # import logging import os import posixpath as target_path_module import sys import unittest from vts.testcases.vndk import utils from vts.testcases.vndk.golden import vndk_data from vts.utils.python.vndk import vndk_utils class VtsVndkFilesTest(unittest.TestCase): """A test for VNDK files and directories. Attributes: _dut: The AndroidDevice under test. _vndk_version: The VNDK version of the device. """ # Some LL-NDK libraries may load the implementations with the same names # from /vendor/lib. Since a vendor may install an implementation of an # LL-NDK library with the same name, testNoLlndkInVendor doesn't raise # errors on these LL-NDK libraries. _LL_NDK_COLLIDING_NAMES = ("libEGL.so", "libGLESv1_CM.so", "libGLESv2.so", "libGLESv3.so") _TARGET_ODM_LIB = "/odm/{LIB}" _TARGET_VENDOR_LIB = "/vendor/{LIB}" def setUp(self): """Initializes attributes.""" serial_number = os.environ.get("ANDROID_SERIAL") self.assertTrue(serial_number, "$ANDROID_SERIAL is empty.") self._dut = utils.AndroidDevice(serial_number) self.assertTrue(self._dut.IsRoot(), "This test requires adb root.") self._vndk_version = self._dut.GetVndkVersion() def _ListFiles(self, dir_path): """Lists all files in a directory except subdirectories. Args: dir_path: A string, path to the directory on device. Returns: A list of strings, the file paths in the directory. """ if not self._dut.Exists(dir_path): logging.info("%s not found", dir_path) return [] return self._dut.FindFiles(dir_path, "*", "!", "-type", "d") def _Fail(self, unexpected_paths): """Logs error and fails current test. Args: unexpected_paths: A list of strings, the paths to be shown in the log message. """ logging.error("Unexpected files:\n%s", "\n".join(unexpected_paths)) assert_lines = unexpected_paths[:20] if len(unexpected_paths) > 20: assert_lines.append("...") assert_lines.append( "Total number of errors: %d" % len(unexpected_paths)) self.fail("\n".join(assert_lines)) def _TestVndkDirectory(self, vndk_dir, vndk_list_names): """Verifies that the VNDK directory doesn't contain extra files. Args: vndk_dir: The path to the VNDK directory on device. vndk_list_names: Strings, the categories of the VNDK libraries that can be in the directory. """ vndk_lists = vndk_data.LoadVndkLibraryListsFromResources( self._vndk_version, *vndk_list_names) self.assertTrue(vndk_lists, "Cannot load VNDK library lists.") vndk_set = set().union(*vndk_lists) logging.debug("vndk set: %s", vndk_set) unexpected = [x for x in self._ListFiles(vndk_dir) if target_path_module.basename(x) not in vndk_set] if unexpected: self._Fail(unexpected) def _TestNotInVndkDirecotory(self, vndk_dir, vndk_list_names, except_libs): """Verifies that VNDK directory doesn't contain specific files. Args: vndk_dir, The path to the VNDK directory on device. vndk_list_names: A list of strings, the categories of the VNDK libraries that should not be in the directory. except_libs: A set of strings, the file names of the libraries that are exceptions to this test. """ vndk_lists = vndk_data.LoadVndkLibraryListsFromResources( self._vndk_version, *vndk_list_names) self.assertTrue(vndk_lists, "Cannot load VNDK library lists.") vndk_set = set().union(*vndk_lists) vndk_set.difference_update(except_libs) logging.debug("vndk set: %s", vndk_set) unexpected = [x for x in self._ListFiles(vndk_dir) if target_path_module.basename(x) in vndk_set] if unexpected: self._Fail(unexpected) def _TestVndkCoreDirectory(self, bitness): """Verifies that VNDK directory doesn't contain extra files.""" if not vndk_utils.IsVndkRuntimeEnforced(self._dut): logging.info("Skip the test as VNDK runtime is not enforced on " "the device.") return self._TestVndkDirectory( vndk_utils.GetVndkDirectory(bitness, self._vndk_version), (vndk_data.VNDK, vndk_data.VNDK_PRIVATE, vndk_data.VNDK_SP, vndk_data.VNDK_SP_PRIVATE,)) def testVndkCoreDirectory32(self): """Runs _TestVndkCoreDirectory for 32-bit libraries.""" self._TestVndkCoreDirectory(32) def testVndkCoreDirectory64(self): """Runs _TestVndkCoreDirectory for 64-bit libraries.""" if self._dut.GetCpuAbiList(64): self._TestVndkCoreDirectory(64) else: logging.info("Skip the test as the device doesn't support 64-bit " "ABI.") def _TestNoLlndkInVendor(self, bitness): """Verifies that vendor partition has no LL-NDK libraries.""" self._TestNotInVndkDirecotory( vndk_utils.FormatVndkPath(self._TARGET_VENDOR_LIB, bitness), (vndk_data.LL_NDK,), self._LL_NDK_COLLIDING_NAMES) def testNoLlndkInVendor32(self): """Runs _TestNoLlndkInVendor for 32-bit libraries.""" self._TestNoLlndkInVendor(32) def testNoLlndkInVendor64(self): """Runs _TestNoLlndkInVendor for 64-bit libraries.""" if self._dut.GetCpuAbiList(64): self._TestNoLlndkInVendor(64) else: logging.info("Skip the test as the device doesn't support 64-bit " "ABI.") def _TestNoLlndkInOdm(self, bitness): """Verifies that odm partition has no LL-NDK libraries.""" self._TestNotInVndkDirecotory( vndk_utils.FormatVndkPath(self._TARGET_ODM_LIB, bitness), (vndk_data.LL_NDK,), self._LL_NDK_COLLIDING_NAMES) def testNoLlndkInOdm32(self): """Runs _TestNoLlndkInOdm for 32-bit libraries.""" self._TestNoLlndkInOdm(32) def testNoLlndkInOdm64(self): """Runs _TestNoLlndkInOdm for 64-bit libraries.""" if self._dut.GetCpuAbiList(64): self._TestNoLlndkInOdm(64) else: logging.info("Skip the test as the device doesn't support 64-bit " "ABI.") if __name__ == "__main__": # The logs are written to stdout so that TradeFed test runner can parse the # results from stderr. logging.basicConfig(stream=sys.stdout) # Setting verbosity is required to generate output that the TradeFed test # runner can parse. unittest.main(verbosity=3)