1#!/usr/bin/env python 2# 3# Copyright (C) 2017 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 19 20from vts.runners.host import asserts 21from vts.runners.host import base_test 22from vts.runners.host import const 23from vts.runners.host import keys 24from vts.runners.host import test_runner 25from vts.testcases.vndk.golden import vndk_data 26from vts.utils.python.os import path_utils 27from vts.utils.python.vndk import vndk_utils 28 29 30class VtsVndkOpenLibrariesTest(base_test.BaseTestClass): 31 """A test module to verify libraries opened by running processes. 32 33 Attributes: 34 data_file_path: The path to VTS data directory. 35 _dut: The AndroidDevice under test. 36 _shell: The ShellMirrorObject to execute commands 37 """ 38 39 def setUpClass(self): 40 """Initializes the data file path and shell.""" 41 required_params = [keys.ConfigKeys.IKEY_DATA_FILE_PATH] 42 self.getUserParams(required_params) 43 self._dut = self.android_devices[0] 44 self._shell = self._dut.shell 45 46 def _ListProcessCommands(self, cmd_filter): 47 """Finds current processes whose commands match the filter. 48 49 Args: 50 cmd_filter: A function that takes a binary file path as argument and 51 returns whether the path matches the condition. 52 53 Returns: 54 A dict of {pid: command} where pid and command are strings. 55 """ 56 result = self._shell.Execute("ps -Aw -o PID,COMMAND") 57 asserts.assertEqual(result[const.EXIT_CODE][0], 0) 58 lines = result[const.STDOUT][0].split("\n") 59 pid_end = lines[0].index("PID") + len("PID") 60 cmd_begin = lines[0].index("COMMAND", pid_end) 61 cmds = {} 62 for line in lines[1:]: 63 cmd = line[cmd_begin:] 64 if not cmd_filter(cmd): 65 continue 66 pid = line[:pid_end].lstrip() 67 cmds[pid] = cmd 68 return cmds 69 70 def _ListOpenFiles(self, pids, file_filter): 71 """Finds open files whose names match the filter. 72 73 Args: 74 pids: A collection of strings, the PIDs to list open files. 75 file_filter: A function that takes a file path as argument and 76 returns whether the path matches the condition. 77 78 Returns: 79 A dict of {pid: [file, ...]} where pid and file are strings. 80 """ 81 lsof_cmd = "lsof -p " + ",".join(pids) 82 result = self._shell.Execute(lsof_cmd) 83 asserts.assertEqual(result[const.EXIT_CODE][0], 0) 84 lines = result[const.STDOUT][0].split("\n") 85 pid_end = lines[0].index("PID") + len("PID") 86 name_begin = lines[0].index("NAME") 87 files = {} 88 for line in lines[1:]: 89 name = line[name_begin:] 90 if not file_filter(name): 91 continue 92 pid_begin = line.rindex(" ", 0, pid_end) + 1 93 pid = line[pid_begin:pid_end] 94 if pid in files: 95 files[pid].append(name) 96 else: 97 files[pid] = [name] 98 return files 99 100 def testVendorProcessOpenLibraries(self): 101 """Checks if vendor processes load shared libraries on system.""" 102 asserts.skipIf(not vndk_utils.IsVndkRuntimeEnforced(self._dut), 103 "VNDK runtime is not enforced on the device.") 104 vndk_lists = vndk_data.LoadVndkLibraryLists( 105 self.data_file_path, 106 self._dut.vndk_version, 107 vndk_data.LL_NDK, 108 vndk_data.LL_NDK_PRIVATE, 109 vndk_data.VNDK, 110 vndk_data.VNDK_PRIVATE, 111 vndk_data.VNDK_SP, 112 vndk_data.VNDK_SP_PRIVATE) 113 asserts.assertTrue(vndk_lists, "Cannot load VNDK library lists.") 114 allowed_libs = set().union(*vndk_lists) 115 logging.debug("Allowed system libraries: %s", allowed_libs) 116 117 asserts.assertTrue(self._dut.isAdbRoot, 118 "Must be root to find all libraries in use.") 119 cmds = self._ListProcessCommands(lambda x: (x.startswith("/odm/") or 120 x.startswith("/vendor/"))) 121 122 def _IsDisallowedSystemLib(lib_path): 123 return (lib_path.startswith("/system/") and 124 lib_path.endswith(".so") and 125 path_utils.TargetBaseName(lib_path) not in allowed_libs) 126 127 deps = self._ListOpenFiles(cmds.keys(), _IsDisallowedSystemLib) 128 if deps: 129 error_lines = ["%s %s %s" % (pid, cmds[pid], libs) 130 for pid, libs in deps.iteritems()] 131 logging.error("pid command libraries\n%s", "\n".join(error_lines)) 132 asserts.fail("Number of vendor processes using system libraries: " + 133 str(len(deps))) 134 135 136if __name__ == "__main__": 137 test_runner.main() 138