1#!/usr/bin/env python 2# 3# Copyright (C) 2020 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 os 20import sys 21import unittest 22 23import target_file_utils 24import proc_utils as utils 25 26from proc_tests import ProcAsoundTests 27from proc_tests import ProcCmdlineTest 28from proc_tests import ProcCpuFileTests 29from proc_tests import ProcFsFileTests 30from proc_tests import ProcKmsgTest 31from proc_tests import ProcMapsTest 32from proc_tests import ProcMiscTest 33from proc_tests import ProcMemInfoTest 34from proc_tests import ProcModulesTest 35from proc_tests import ProcRemoveUidRangeTest 36from proc_tests import ProcSimpleFileTests 37from proc_tests import ProcShowUidStatTest 38from proc_tests import ProcStatTest 39from proc_tests import ProcUidIoStatsTest 40from proc_tests import ProcUidTimeInStateTest 41from proc_tests import ProcUidConcurrentTimeTests 42from proc_tests import ProcUidCpuPowerTests 43from proc_tests import ProcVersionTest 44from proc_tests import ProcVmallocInfoTest 45from proc_tests import ProcVmstatTest 46from proc_tests import ProcZoneInfoTest 47 48TEST_OBJECTS = { 49 ProcAsoundTests.ProcAsoundCardsTest(), 50 ProcCmdlineTest.ProcCmdlineTest(), 51 ProcCpuFileTests.ProcCpuInfoTest(), 52 ProcCpuFileTests.ProcLoadavgTest(), 53 ProcFsFileTests.ProcDiskstatsTest(), 54 ProcFsFileTests.ProcFilesystemsTest(), 55 ProcFsFileTests.ProcMountsTest(), 56 ProcFsFileTests.ProcSwapsTest(), 57 ProcKmsgTest.ProcKmsgTest(), 58 ProcMapsTest.ProcMapsTest(), 59 ProcMiscTest.ProcMisc(), 60 ProcMemInfoTest.ProcMemInfoTest(), 61 ProcModulesTest.ProcModulesTest(), 62 ProcRemoveUidRangeTest.ProcRemoveUidRangeTest(), 63 ProcSimpleFileTests.ProcCorePattern(), 64 ProcSimpleFileTests.ProcCorePipeLimit(), 65 ProcSimpleFileTests.ProcDirtyBackgroundBytes(), 66 ProcSimpleFileTests.ProcDirtyBackgroundRatio(), 67 ProcSimpleFileTests.ProcDirtyExpireCentisecs(), 68 ProcSimpleFileTests.ProcDmesgRestrict(), 69 ProcSimpleFileTests.ProcDomainname(), 70 ProcSimpleFileTests.ProcDropCaches(), 71 ProcSimpleFileTests.ProcExtraFreeKbytes(), 72 ProcSimpleFileTests.ProcHostname(), 73 ProcSimpleFileTests.ProcHungTaskTimeoutSecs(), 74 ProcSimpleFileTests.ProcKptrRestrictTest(), 75 ProcSimpleFileTests.ProcMaxMapCount(), 76 ProcSimpleFileTests.ProcMmapMinAddrTest(), 77 ProcSimpleFileTests.ProcMmapRndBitsTest(), 78 ProcSimpleFileTests.ProcModulesDisabled(), 79 ProcSimpleFileTests.ProcOverCommitMemoryTest(), 80 ProcSimpleFileTests.ProcPageCluster(), 81 ProcSimpleFileTests.ProcPanicOnOops(), 82 ProcSimpleFileTests.ProcPerfEventMaxSampleRate(), 83 ProcSimpleFileTests.ProcPerfEventParanoid(), 84 ProcSimpleFileTests.ProcPidMax(), 85 ProcSimpleFileTests.ProcPipeMaxSize(), 86 ProcSimpleFileTests.ProcProtectedHardlinks(), 87 ProcSimpleFileTests.ProcProtectedSymlinks(), 88 ProcSimpleFileTests.ProcRandomizeVaSpaceTest(), 89 ProcSimpleFileTests.ProcSchedChildRunsFirst(), 90 ProcSimpleFileTests.ProcSchedRTPeriodUS(), 91 ProcSimpleFileTests.ProcSchedRTRuntimeUS(), 92 ProcShowUidStatTest.ProcShowUidStatTest(), 93 ProcSimpleFileTests.ProcSuidDumpable(), 94 ProcSimpleFileTests.ProcSysKernelRandomBootId(), 95 ProcSimpleFileTests.ProcSysRqTest(), 96 ProcSimpleFileTests.ProcUptime(), 97 ProcStatTest.ProcStatTest(), 98 ProcUidIoStatsTest.ProcUidIoStatsTest(), 99 ProcUidTimeInStateTest.ProcUidTimeInStateTest(), 100 ProcUidConcurrentTimeTests.ProcUidConcurrentActiveTimeTest(), 101 ProcUidConcurrentTimeTests.ProcUidConcurrentPolicyTimeTest(), 102 ProcUidCpuPowerTests.ProcUidCpuPowerTimeInStateTest(), 103 ProcUidCpuPowerTests.ProcUidCpuPowerConcurrentActiveTimeTest(), 104 ProcUidCpuPowerTests.ProcUidCpuPowerConcurrentPolicyTimeTest(), 105 ProcVersionTest.ProcVersionTest(), 106 ProcVmallocInfoTest.ProcVmallocInfoTest(), 107 ProcVmstatTest.ProcVmstat(), 108 ProcZoneInfoTest.ProcZoneInfoTest(), 109} 110 111TEST_OBJECTS_64 = { 112 ProcSimpleFileTests.ProcMmapRndCompatBitsTest(), 113} 114 115 116class VtsKernelProcFileApiTest(unittest.TestCase): 117 """Test cases which check content of proc files. 118 119 Attributes: 120 _PROC_SYS_ABI_SWP_FILE_PATH: the path of a file which decides behaviour of SWP instruction. 121 """ 122 123 _PROC_SYS_ABI_SWP_FILE_PATH = "/proc/sys/abi/swp" 124 125 def setUp(self): 126 """Initializes tests. 127 128 Data file path, device, remote shell instance and temporary directory 129 are initialized. 130 """ 131 serial_number = os.environ.get("ANDROID_SERIAL") 132 self.assertTrue(serial_number, "$ANDROID_SERIAL is empty.") 133 self.dut = utils.AndroidDevice(serial_number) 134 135 def testProcPagetypeinfo(self): 136 # TODO(b/109884074): make mandatory once incident_helper is in AOSP. 137 out, err, r_code = self.dut.shell.Execute("which incident_helper") 138 if r_code != 0: 139 logging.info("incident_helper not present") 140 return 141 142 filepath = "/proc/pagetypeinfo" 143 # Check that incident_helper can parse /proc/pagetypeinfo. 144 out, err, r_code = self.dut.shell.Execute( 145 "cat %s | incident_helper -s 2001" % filepath) 146 self.assertEqual( 147 r_code, 0, 148 "Failed to parse %s." % filepath) 149 150 def testProcUidProcstatSet(self): 151 152 def UidIOStats(uid): 153 """Returns I/O stats for a given uid. 154 155 Args: 156 uid, uid number. 157 158 Returns: 159 list of I/O numbers, can be blank if uid not found. 160 """ 161 stats_path = "/proc/uid_io/stats" 162 out, err, r_code = self.dut.shell.Execute( 163 "cat %s | grep '^%d'" % (stats_path, uid)) 164 return out.split() 165 166 def GetWcharCount(uid, state): 167 """Returns the wchar count (bytes written) for a given uid. 168 169 Args: 170 uid, uid number. 171 state, boolean. Use False for foreground, 172 and True for background. 173 174 Returns: 175 wchar, the number of bytes written by a uid in the given state.. 176 """ 177 # fg write chars are at index 2, and bg write chars are at 6. 178 wchar_index = 6 if state else 2 179 180 stats = UidIOStats(uid) 181 # UidIOStats() can return a blank line if the entries are not found 182 # so we need to check the length of the return to prevent a list 183 # index out of range exception. 184 arr_len = len(stats) 185 186 # On a properly running system, the output of 187 # 'cat /proc/uid_io/stats | grep ^0' 188 # (which is what UidIOStats() does) results in something that has 11 189 # fields and looks like this: 190 # "0 9006642940 84253078 9751207936 1064480768 0 0 0 0 1048 0" 191 self.assertTrue(arr_len == 11, 192 "Array len returned by UidIOStats() unexpected: %d" % 193 arr_len) 194 return int(stats[wchar_index]) 195 196 def CheckStatsInState(state): 197 """Sets VTS (root uid) into a given state and checks the stats. 198 199 Args: 200 state, boolean. Use False for foreground, 201 and True for background. 202 """ 203 state = 1 if state else 0 204 filepath = "/proc/uid_procstat/set" 205 root_uid = 0 206 207 old_wchar = GetWcharCount(root_uid, state) 208 self.dut.shell.Execute("echo %d %s > %s" % (root_uid, state, filepath)) 209 # This should increase the number of write syscalls. 210 self.dut.shell.Execute("echo foo") 211 new_wchar = GetWcharCount(root_uid, state) 212 self.assertLess( 213 old_wchar, 214 new_wchar, 215 "Number of write syscalls has not increased.") 216 217 CheckStatsInState(False) 218 CheckStatsInState(True) 219 220 def testProcPerUidTimes(self): 221 # TODO: make these files mandatory once they're in AOSP 222 try: 223 filepaths = self.dut.FindFiles('/proc/uid', 'time_in_state') 224 except: 225 logging.info("/proc/uid/ directory does not exist and is optional") 226 return 227 228 if not filepaths: 229 logging.info('per-UID time_in_state files do not exist and are optional') 230 return 231 232 for filepath in filepaths: 233 self.assertTrue(self.dut.Exists(filepath), 234 '%s does not exist.' % filepath) 235 permission = self.dut.GetPermission(filepath) 236 self.assertTrue(target_file_utils.IsReadOnly(permission)) 237 file_content = self.dut.ReadFileContent(filepath) 238 239 def testProcSysAbiSwpInstruction(self): 240 """Tests /proc/sys/abi/swp. 241 242 /proc/sys/abi/swp sets the execution behaviour for the obsoleted ARM instruction 243 SWP. As per the setting in /proc/sys/abi/swp, the usage of SWP{B} 244 can either generate an undefined instruction abort or use software emulation 245 or hardware execution. 246 """ 247 if not ('arm' in self.cpu_abi(self.dut) and self.is64Bit(self.dut)): 248 logging.info("file not present on non-ARM64 device") 249 return 250 251 filepath = '/proc/sys/abi/swp' 252 253 self.assertTrue(self.dut.Exists(filepath), '%s does not exist.' % filepath) 254 permission = self.dut.GetPermission(filepath) 255 self.assertTrue(target_file_utils.IsReadWrite(permission)) 256 257 file_content = self.dut.ReadFileContent(filepath) 258 try: 259 swp_state = int(file_content) 260 except ValueError as e: 261 self.fail("Failed to parse %s" % filepath) 262 self.assertTrue(swp_state >= 0 and swp_state <= 2, 263 "%s contains incorrect value: %d" 264 % (filepath, swp_state)) 265 266 def cpu_abi(self, dut): 267 """CPU ABI (Application Binary Interface) of the device.""" 268 out = dut._GetProp("ro.product.cpu.abi") 269 if not out: 270 return "unknown" 271 272 cpu_abi = out.lower() 273 return cpu_abi 274 275 def is64Bit(self, dut): 276 """True if device is 64 bit.""" 277 out, _, _ = dut.shell.Execute('uname -m') 278 return "64" in out 279 280 281def run_proc_file_test(test_object): 282 """Reads from the file and checks that it parses and the content is valid. 283 284 Args: 285 test_object: inherits KernelProcFileTestBase, contains the test functions 286 """ 287 def test(self): 288 if test_object in TEST_OBJECTS_64 and not self.is64Bit(self.dut): 289 logging.info("Skip test for 64-bit kernel.") 290 return 291 test_object.set_api_level(self.dut) 292 filepath = test_object.get_path() 293 if not self.dut.Exists(filepath) and test_object.file_optional(dut=self.dut): 294 logging.info("%s does not exist and is optional." % filepath) 295 return 296 self.assertTrue(self.dut.Exists(filepath), '%s does not exist.' % filepath) 297 permission = self.dut.GetPermission(filepath) 298 self.assertTrue(test_object.get_permission_checker()) 299 self.assertTrue(test_object.get_permission_checker()(permission), 300 "%s: File has invalid permissions (%s)" % (filepath, 301 permission)) 302 303 logging.info("Testing format of %s", filepath) 304 self.assertTrue( 305 test_object.prepare_test(self.dut), "Setup failed!") 306 307 if not test_object.test_format(): 308 return 309 310 file_content = self.dut.ReadFileContent(filepath) 311 try: 312 parse_result = test_object.parse_contents(file_content) 313 except (SyntaxError, ValueError, IndexError) as e: 314 self.fail("Failed to parse! " + str(e)) 315 self.assertTrue( 316 test_object.result_correct(parse_result), "Results not valid!") 317 return test 318 319 320if __name__ == "__main__": 321 try: 322 for test_object in TEST_OBJECTS.union(TEST_OBJECTS_64): 323 test_func = run_proc_file_test(test_object) 324 setattr(VtsKernelProcFileApiTest, 'test_' + 325 test_object.__class__.__name__, test_func) 326 suite = unittest.TestLoader().loadTestsFromTestCase( 327 VtsKernelProcFileApiTest) 328 results = unittest.TextTestRunner(verbosity=2).run(suite) 329 finally: 330 if results.failures: 331 sys.exit(1) 332