• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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