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 test_runner
24
25from vts.testcases.kernel.api.proc import ProcAsoundTests
26from vts.testcases.kernel.api.proc import ProcCmdlineTest
27from vts.testcases.kernel.api.proc import ProcCpuFileTests
28from vts.testcases.kernel.api.proc import ProcFsFileTests
29from vts.testcases.kernel.api.proc import ProcKmsgTest
30from vts.testcases.kernel.api.proc import ProcMapsTest
31from vts.testcases.kernel.api.proc import ProcMiscTest
32from vts.testcases.kernel.api.proc import ProcMemInfoTest
33from vts.testcases.kernel.api.proc import ProcModulesTest
34from vts.testcases.kernel.api.proc import ProcQtaguidCtrlTest
35from vts.testcases.kernel.api.proc import ProcRemoveUidRangeTest
36from vts.testcases.kernel.api.proc import ProcSimpleFileTests
37from vts.testcases.kernel.api.proc import ProcShowUidStatTest
38from vts.testcases.kernel.api.proc import ProcStatTest
39from vts.testcases.kernel.api.proc import ProcUidIoStatsTest
40from vts.testcases.kernel.api.proc import ProcUidTimeInStateTest
41from vts.testcases.kernel.api.proc import ProcUidConcurrentTimeTests
42from vts.testcases.kernel.api.proc import ProcUidCpuPowerTests
43from vts.testcases.kernel.api.proc import ProcVersionTest
44from vts.testcases.kernel.api.proc import ProcVmallocInfoTest
45from vts.testcases.kernel.api.proc import ProcVmstatTest
46from vts.testcases.kernel.api.proc import ProcZoneInfoTest
47
48from vts.utils.python.controllers import android_device
49from vts.utils.python.file import target_file_utils
50
51TEST_OBJECTS = {
52    ProcAsoundTests.ProcAsoundCardsTest(),
53    ProcCmdlineTest.ProcCmdlineTest(),
54    ProcCpuFileTests.ProcCpuInfoTest(),
55    ProcCpuFileTests.ProcLoadavgTest(),
56    ProcFsFileTests.ProcDiskstatsTest(),
57    ProcFsFileTests.ProcFilesystemsTest(),
58    ProcFsFileTests.ProcMountsTest(),
59    ProcFsFileTests.ProcSwapsTest(),
60    ProcKmsgTest.ProcKmsgTest(),
61    ProcMapsTest.ProcMapsTest(),
62    ProcMiscTest.ProcMisc(),
63    ProcMemInfoTest.ProcMemInfoTest(),
64    ProcModulesTest.ProcModulesTest(),
65    ProcQtaguidCtrlTest.ProcQtaguidCtrlTest(),
66    ProcRemoveUidRangeTest.ProcRemoveUidRangeTest(),
67    ProcSimpleFileTests.ProcCorePattern(),
68    ProcSimpleFileTests.ProcCorePipeLimit(),
69    ProcSimpleFileTests.ProcDirtyBackgroundBytes(),
70    ProcSimpleFileTests.ProcDirtyBackgroundRatio(),
71    ProcSimpleFileTests.ProcDirtyExpireCentisecs(),
72    ProcSimpleFileTests.ProcDmesgRestrict(),
73    ProcSimpleFileTests.ProcDomainname(),
74    ProcSimpleFileTests.ProcDropCaches(),
75    ProcSimpleFileTests.ProcExtraFreeKbytes(),
76    ProcSimpleFileTests.ProcHostname(),
77    ProcSimpleFileTests.ProcHungTaskTimeoutSecs(),
78    ProcSimpleFileTests.ProcKptrRestrictTest(),
79    ProcSimpleFileTests.ProcMaxMapCount(),
80    ProcSimpleFileTests.ProcMmapMinAddrTest(),
81    ProcSimpleFileTests.ProcMmapRndBitsTest(),
82    ProcSimpleFileTests.ProcModulesDisabled(),
83    ProcSimpleFileTests.ProcOverCommitMemoryTest(),
84    ProcSimpleFileTests.ProcPageCluster(),
85    ProcSimpleFileTests.ProcPanicOnOops(),
86    ProcSimpleFileTests.ProcPerfEventMaxSampleRate(),
87    ProcSimpleFileTests.ProcPerfEventParanoid(),
88    ProcSimpleFileTests.ProcPidMax(),
89    ProcSimpleFileTests.ProcPipeMaxSize(),
90    ProcSimpleFileTests.ProcProtectedHardlinks(),
91    ProcSimpleFileTests.ProcProtectedSymlinks(),
92    ProcSimpleFileTests.ProcRandomizeVaSpaceTest(),
93    ProcSimpleFileTests.ProcSchedChildRunsFirst(),
94    ProcSimpleFileTests.ProcSchedLatencyNS(),
95    ProcSimpleFileTests.ProcSchedRTPeriodUS(),
96    ProcSimpleFileTests.ProcSchedRTRuntimeUS(),
97    ProcSimpleFileTests.ProcSchedTunableScaling(),
98    ProcSimpleFileTests.ProcSchedWakeupGranularityNS(),
99    ProcShowUidStatTest.ProcShowUidStatTest(),
100    ProcSimpleFileTests.ProcSuidDumpable(),
101    ProcSimpleFileTests.ProcSysKernelRandomBootId(),
102    ProcSimpleFileTests.ProcSysRqTest(),
103    ProcSimpleFileTests.ProcUptime(),
104    ProcStatTest.ProcStatTest(),
105    ProcUidIoStatsTest.ProcUidIoStatsTest(),
106    ProcUidTimeInStateTest.ProcUidTimeInStateTest(),
107    ProcUidConcurrentTimeTests.ProcUidConcurrentActiveTimeTest(),
108    ProcUidConcurrentTimeTests.ProcUidConcurrentPolicyTimeTest(),
109    ProcUidCpuPowerTests.ProcUidCpuPowerTimeInStateTest(),
110    ProcUidCpuPowerTests.ProcUidCpuPowerConcurrentActiveTimeTest(),
111    ProcUidCpuPowerTests.ProcUidCpuPowerConcurrentPolicyTimeTest(),
112    ProcVersionTest.ProcVersionTest(),
113    ProcVmallocInfoTest.ProcVmallocInfoTest(),
114    ProcVmstatTest.ProcVmstat(),
115    ProcZoneInfoTest.ProcZoneInfoTest(),
116}
117
118TEST_OBJECTS_64 = {
119    ProcSimpleFileTests.ProcMmapRndCompatBitsTest(),
120}
121
122
123class VtsKernelProcFileApiTest(base_test.BaseTestClass):
124    """Test cases which check content of proc files.
125
126    Attributes:
127        _PROC_SYS_ABI_SWP_FILE_PATH: the path of a file which decides behaviour of SWP instruction.
128    """
129
130    _PROC_SYS_ABI_SWP_FILE_PATH = "/proc/sys/abi/swp"
131
132    def setUpClass(self):
133        self.dut = self.android_devices[0]
134        self.shell = self.dut.shell
135
136    def runProcFileTest(self, test_object):
137        """Reads from the file and checks that it parses and the content is valid.
138
139        Args:
140            test_object: inherits KernelProcFileTestBase, contains the test functions
141        """
142        asserts.skipIf(test_object in TEST_OBJECTS_64 and not self.dut.is64Bit,
143                       "Skip test for 64-bit kernel.")
144        test_object.set_api_level(self.dut)
145        filepath = test_object.get_path()
146        asserts.skipIf(not target_file_utils.Exists(filepath, self.shell) and
147                       test_object.file_optional(shell=self.shell, dut=self.dut),
148                       "%s does not exist and is optional." % filepath)
149        target_file_utils.assertPermissionsAndExistence(
150            self.shell, filepath, test_object.get_permission_checker())
151
152        logging.info("Testing format of %s", filepath)
153
154        asserts.assertTrue(
155            test_object.prepare_test(self.shell, self.dut), "Setup failed!")
156
157        if not test_object.test_format():
158            return
159
160        file_content = self.ReadFileContent(filepath)
161        try:
162            parse_result = test_object.parse_contents(file_content)
163        except (SyntaxError, ValueError, IndexError) as e:
164            asserts.fail("Failed to parse! " + str(e))
165        asserts.assertTrue(
166            test_object.result_correct(parse_result), "Results not valid!")
167
168    def generateProcFileTests(self):
169        """Run all proc file tests."""
170        self.runGeneratedTests(
171            test_func=self.runProcFileTest,
172            settings=TEST_OBJECTS.union(TEST_OBJECTS_64),
173            name_func=lambda test_obj: "test" + test_obj.__class__.__name__)
174
175    def ReadFileContent(self, filepath):
176        """Read the content of a file and perform assertions.
177
178        Args:
179            filepath: string, path to file
180
181        Returns:
182            string, content of file
183        """
184        cmd = "cat %s" % filepath
185        results = self.shell.Execute(cmd)
186
187        # checks the exit code
188        asserts.assertEqual(
189            results[const.EXIT_CODE][0], 0,
190            "%s: Error happened while reading the file." % filepath)
191
192        return results[const.STDOUT][0]
193
194    def testProcPagetypeinfo(self):
195        # TODO(b/109884074): make mandatory once incident_helper is in AOSP.
196        try:
197            self.dut.adb.shell("which incident_helper")
198        except:
199            asserts.skip("incident_helper not present")
200
201        filepath = "/proc/pagetypeinfo"
202        # Check that incident_helper can parse /proc/pagetypeinfo.
203        result = self.shell.Execute("cat %s | incident_helper -s 2001" % filepath)
204        asserts.assertEqual(
205            result[const.EXIT_CODE][0], 0,
206            "Failed to parse %s." % filepath)
207
208    def testProcSysrqTrigger(self):
209        filepath = "/proc/sysrq-trigger"
210
211        # This command only performs a best effort attempt to remount all
212        # filesystems. Check that it doesn't throw an error.
213        self.dut.adb.shell("echo u > %s" % filepath)
214
215        # Reboot the device.
216        self.dut.adb.shell("echo b > %s" % filepath)
217        asserts.assertFalse(self.dut.hasBooted(), "Device is still alive.")
218        self.dut.waitForBootCompletion()
219        self.dut.rootAdb()
220
221    def testProcUidProcstatSet(self):
222        def UidIOStats(uid):
223            """Returns I/O stats for a given uid.
224
225            Args:
226                uid, uid number.
227
228            Returns:
229                list of I/O numbers.
230            """
231            stats_path = "/proc/uid_io/stats"
232            result = self.dut.adb.shell(
233                    "cat %s | grep '^%d'" % (stats_path, uid),
234                    no_except=True)
235            return result[const.STDOUT].split()
236
237        def CheckStatsInState(state):
238            """Sets VTS (root uid) into a given state and checks the stats.
239
240            Args:
241                state, boolean. Use False for foreground,
242                and True for background.
243            """
244            state = 1 if state else 0
245            filepath = "/proc/uid_procstat/set"
246            root_uid = 0
247
248            # fg write chars are at index 2, and bg write chars are at 6.
249            wchar_index = 6 if state else 2
250            old_wchar = UidIOStats(root_uid)[wchar_index]
251            self.dut.adb.shell("echo %d %s > %s" % (root_uid, state, filepath))
252            # This should increase the number of write syscalls.
253            self.dut.adb.shell("echo foo")
254            asserts.assertLess(
255                int(old_wchar),
256                int(UidIOStats(root_uid)[wchar_index]),
257                "Number of write syscalls has not increased.")
258
259        CheckStatsInState(False)
260        CheckStatsInState(True)
261
262    def testProcPerUidTimes(self):
263        # TODO: make these files mandatory once they're in AOSP
264        try:
265            filepaths = self.dut.adb.shell("find /proc/uid -name time_in_state")
266        except:
267            asserts.skip("/proc/uid/ directory does not exist and is optional")
268
269        asserts.skipIf(not filepaths,
270                       "per-UID time_in_state files do not exist and are optional")
271
272        filepaths = filepaths.splitlines()
273        for filepath in filepaths:
274            target_file_utils.assertPermissionsAndExistence(
275                self.shell, filepath, target_file_utils.IsReadOnly
276            )
277            file_content = self.ReadFileContent(filepath)
278
279    def testProcSysAbiSwpInstruction(self):
280        """Tests /proc/sys/abi/swp.
281
282        /proc/sys/abi/swp sets the execution behaviour for the obsoleted ARM instruction
283        SWP. As per the setting in /proc/sys/abi/swp, the usage of SWP{B}
284        can either generate an undefined instruction abort or use software emulation
285        or hardware execution.
286        """
287
288        asserts.skipIf(not ("arm" in self.dut.cpu_abi and self.dut.is64Bit),
289                       "file not present on non-ARM64 device")
290        target_file_utils.assertPermissionsAndExistence(
291            self.shell, self._PROC_SYS_ABI_SWP_FILE_PATH, target_file_utils.IsReadWrite)
292        file_content = self.ReadFileContent(self._PROC_SYS_ABI_SWP_FILE_PATH)
293        try:
294            swp_state = int(file_content)
295        except ValueError as e:
296            asserts.fail("Failed to parse %s" % self._PROC_SYS_ABI_SWP_FILE_PATH)
297        asserts.assertTrue(swp_state >= 0 and swp_state <= 2,
298                           "%s contains incorrect value: %d" % (self._PROC_SYS_ABI_SWP_FILE_PATH,
299                                                                swp_state))
300
301if __name__ == "__main__":
302    test_runner.main()
303