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 # On a properly running system, out is a line with 11 fields that 165 # looks like this: 166 # "0 9006642940 84253078 9751207936 1064480768 0 0 0 0 1048 0" 167 # where the stat at each index corresponds to the following: 168 # 0 : uid 169 # 1 : fg_rchar 170 # 2 : fg_wchar 171 # 3 : fg_rbytes 172 # 4 : fg_wbytes 173 # 5 : bg_rchar 174 # 6 : bg_wchar 175 # 7 : bg_rbytes 176 # 8 : bg_wbytes 177 # 9 : fg_fsync 178 # 10: bg_fsync 179 return out.split() 180 181 def GetUidIoStat(uid, index): 182 """Returns the I/O stat at the given index for a given uid. 183 184 Args: 185 uid, uid number. 186 index, index of the desired I/O stat in the array. 187 188 Returns: 189 value of the I/O stat at the given index. 190 """ 191 stats = UidIOStats(uid) 192 # UidIOStats() can return a blank line if the entries are not found 193 # so we need to check the length of the return to prevent a list 194 # index out of range exception. 195 arr_len = len(stats) 196 197 self.assertTrue(arr_len == 11, 198 "Array len returned by UidIOStats() unexpected: %d" % 199 arr_len) 200 self.assertTrue(index < 11, 201 "Index passed into GetUidIoStat out of bounds: %d" % 202 index) 203 204 return int(stats[index]) 205 206 207 def GetWcharCount(uid, state): 208 """Returns the wchar count (bytes written) for a given uid. 209 210 Args: 211 uid, uid number. 212 state, boolean. Use False for foreground, 213 and True for background. 214 215 Returns: 216 wchar, the number of bytes written by a uid in the given state. 217 """ 218 # fg write chars are at index 2, and bg write chars are at 6. 219 wchar_index = 6 if state else 2 220 221 return GetUidIoStat(uid, wchar_index) 222 223 def GetFsyncCount(uid, state): 224 """Returns the fsync syscall count by a given uid. 225 226 Args: 227 uid, uid number. 228 state, boolean. Use False for foreground, 229 and True for background. 230 231 Returns: 232 fsync, the number of calls to fsync by a uid in the given state. 233 """ 234 # fg write chars are at index 2, and bg write chars are at 6. 235 fsync_index = 10 if state else 9 236 237 return GetUidIoStat(uid, fsync_index) 238 239 def CheckStatsInState(state): 240 """Sets VTS (root uid) into a given state and checks the stats. 241 242 Args: 243 state, boolean. Use False for foreground, 244 and True for background. 245 """ 246 state = 1 if state else 0 247 filepath = "/proc/uid_procstat/set" 248 root_uid = 0 249 250 old_wchar = GetWcharCount(root_uid, state) 251 old_fsync = GetFsyncCount(root_uid, state) 252 self.dut.shell.Execute("echo %d %s > %s" % (root_uid, state, filepath)) 253 254 # This should increase the number of write syscalls. 255 self.dut.shell.Execute("echo foo") 256 new_wchar = GetWcharCount(root_uid, state) 257 258 # This should increase the number of fsync syscalls. 259 self.dut.shell.Execute("fsync /tmp") 260 new_fsync = GetFsyncCount(root_uid, state) 261 262 self.assertLess( 263 old_wchar, 264 new_wchar, 265 "Number of write syscalls has not increased.") 266 267 self.assertLess( 268 old_fsync, 269 new_fsync, 270 "Number of fsync syscalls has not increased.") 271 272 CheckStatsInState(False) 273 CheckStatsInState(True) 274 275 def testProcPerUidTimes(self): 276 # TODO: make these files mandatory once they're in AOSP 277 try: 278 filepaths = self.dut.FindFiles('/proc/uid', 'time_in_state') 279 except: 280 logging.info("/proc/uid/ directory does not exist and is optional") 281 return 282 283 if not filepaths: 284 logging.info('per-UID time_in_state files do not exist and are optional') 285 return 286 287 for filepath in filepaths: 288 self.assertTrue(self.dut.Exists(filepath), 289 '%s does not exist.' % filepath) 290 permission = self.dut.GetPermission(filepath) 291 self.assertTrue(target_file_utils.IsReadOnly(permission)) 292 file_content = self.dut.ReadFileContent(filepath) 293 294 def testProcSysAbiSwpInstruction(self): 295 """Tests /proc/sys/abi/swp. 296 297 /proc/sys/abi/swp sets the execution behaviour for the obsoleted ARM instruction 298 SWP. As per the setting in /proc/sys/abi/swp, the usage of SWP{B} 299 can either generate an undefined instruction abort or use software emulation 300 or hardware execution. 301 """ 302 if not ('arm' in self.cpu_abi(self.dut) and self.is64Bit(self.dut)): 303 logging.info("file not present on non-ARM64 device") 304 return 305 306 filepath = '/proc/sys/abi/swp' 307 308 self.assertTrue(self.dut.Exists(filepath), '%s does not exist.' % filepath) 309 permission = self.dut.GetPermission(filepath) 310 self.assertTrue(target_file_utils.IsReadWrite(permission)) 311 312 file_content = self.dut.ReadFileContent(filepath) 313 try: 314 swp_state = int(file_content) 315 except ValueError as e: 316 self.fail("Failed to parse %s" % filepath) 317 self.assertTrue(swp_state >= 0 and swp_state <= 2, 318 "%s contains incorrect value: %d" 319 % (filepath, swp_state)) 320 321 def cpu_abi(self, dut): 322 """CPU ABI (Application Binary Interface) of the device.""" 323 out = dut._GetProp("ro.product.cpu.abi") 324 if not out: 325 return "unknown" 326 327 cpu_abi = out.lower() 328 return cpu_abi 329 330 def is64Bit(self, dut): 331 """True if device is 64 bit.""" 332 out, _, _ = dut.shell.Execute('uname -m') 333 return "64" in out 334 335 336def run_proc_file_test(test_object): 337 """Reads from the file and checks that it parses and the content is valid. 338 339 Args: 340 test_object: inherits KernelProcFileTestBase, contains the test functions 341 """ 342 def test(self): 343 if test_object in TEST_OBJECTS_64 and not self.is64Bit(self.dut): 344 logging.info("Skip test for 64-bit kernel.") 345 return 346 test_object.set_api_level(self.dut) 347 filepath = test_object.get_path() 348 if not self.dut.Exists(filepath) and test_object.file_optional(dut=self.dut): 349 logging.info("%s does not exist and is optional." % filepath) 350 return 351 self.assertTrue(self.dut.Exists(filepath), '%s does not exist.' % filepath) 352 permission = self.dut.GetPermission(filepath) 353 self.assertTrue(test_object.get_permission_checker()) 354 self.assertTrue(test_object.get_permission_checker()(permission), 355 "%s: File has invalid permissions (%s)" % (filepath, 356 permission)) 357 358 logging.info("Testing format of %s", filepath) 359 self.assertTrue( 360 test_object.prepare_test(self.dut), "Setup failed!") 361 362 if not test_object.test_format(): 363 return 364 365 file_content = self.dut.ReadFileContent(filepath) 366 try: 367 parse_result = test_object.parse_contents(file_content) 368 except (SyntaxError, ValueError, IndexError) as e: 369 self.fail("Failed to parse! " + str(e)) 370 self.assertTrue( 371 test_object.result_correct(parse_result), "Results not valid!") 372 return test 373 374 375if __name__ == "__main__": 376 try: 377 for test_object in TEST_OBJECTS.union(TEST_OBJECTS_64): 378 test_func = run_proc_file_test(test_object) 379 setattr(VtsKernelProcFileApiTest, 'test_' + 380 test_object.__class__.__name__, test_func) 381 suite = unittest.TestLoader().loadTestsFromTestCase( 382 VtsKernelProcFileApiTest) 383 results = unittest.TextTestRunner(verbosity=2).run(suite) 384 finally: 385 if results.failures: 386 sys.exit(1) 387