1# Copyright 2014 The Chromium Authors. All rights reserved. 2# Use of this source code is governed by a BSD-style license that can be 3# found in the LICENSE file. 4 5import os 6import pickle 7import re 8import shutil 9import tempfile 10import unittest 11 12from telemetry import benchmark 13from telemetry.core import util 14from telemetry.core.platform.profiler import android_profiling_helper 15from telemetry.unittest import simple_mock 16from telemetry.unittest import tab_test_case 17 18 19def _GetLibrariesMappedIntoProcesses(device, pids): 20 libs = set() 21 for pid in pids: 22 maps_file = '/proc/%d/maps' % pid 23 maps = device.ReadFile(maps_file, as_root=True) 24 for map_line in maps: 25 lib = re.match(r'.*\s(/.*[.]so)$', map_line) 26 if lib: 27 libs.add(lib.group(1)) 28 return libs 29 30 31class TestAndroidProfilingHelper(unittest.TestCase): 32 33 def testGetRequiredLibrariesForPerfProfile(self): 34 perf_output = os.path.join( 35 util.GetUnittestDataDir(), 'sample_perf_report_output.txt') 36 with open(perf_output) as f: 37 perf_output = f.read() 38 39 mock_popen = simple_mock.MockObject() 40 mock_popen.ExpectCall('communicate').WillReturn([None, perf_output]) 41 42 mock_subprocess = simple_mock.MockObject() 43 mock_subprocess.ExpectCall( 44 'Popen').WithArgs(simple_mock.DONT_CARE).WillReturn(mock_popen) 45 mock_subprocess.SetAttribute('PIPE', simple_mock.MockObject()) 46 47 real_subprocess = android_profiling_helper.subprocess 48 android_profiling_helper.subprocess = mock_subprocess 49 try: 50 libs = android_profiling_helper.GetRequiredLibrariesForPerfProfile('foo') 51 self.assertEqual(libs, set([ 52 '/data/app-lib/com.google.android.apps.chrome-2/libchrome.2016.0.so', 53 '/system/lib/libart.so', 54 '/system/lib/libc.so', 55 '/system/lib/libm.so'])) 56 finally: 57 android_profiling_helper.subprocess = real_subprocess 58 59 @benchmark.Enabled('android') 60 def testGetRequiredLibrariesForVTuneProfile(self): 61 vtune_db_output = os.path.join( 62 util.GetUnittestDataDir(), 'sample_vtune_db_output') 63 with open(vtune_db_output, 'rb') as f: 64 vtune_db_output = pickle.load(f) 65 66 mock_cursor = simple_mock.MockObject() 67 mock_cursor.ExpectCall( 68 'execute').WithArgs(simple_mock.DONT_CARE).WillReturn(vtune_db_output) 69 70 mock_conn = simple_mock.MockObject() 71 mock_conn.ExpectCall('cursor').WillReturn(mock_cursor) 72 mock_conn.ExpectCall('close') 73 74 mock_sqlite3 = simple_mock.MockObject() 75 mock_sqlite3.ExpectCall( 76 'connect').WithArgs(simple_mock.DONT_CARE).WillReturn(mock_conn) 77 78 real_sqlite3 = android_profiling_helper.sqlite3 79 android_profiling_helper.sqlite3 = mock_sqlite3 80 try: 81 libs = android_profiling_helper.GetRequiredLibrariesForVTuneProfile('foo') 82 self.assertEqual(libs, set([ 83 '/data/app-lib/com.google.android.apps.chrome-1/libchrome.2019.0.so', 84 '/system/lib/libdvm.so', 85 '/system/lib/libc.so', 86 '/system/lib/libm.so'])) 87 finally: 88 android_profiling_helper.sqlite3 = real_sqlite3 89 90 91class TestAndroidProfilingHelperTabTestCase(tab_test_case.TabTestCase): 92 93 def setUp(self): 94 super(TestAndroidProfilingHelperTabTestCase, self).setUp() 95 # pylint: disable=W0212 96 browser_backend = self._browser._browser_backend 97 self._device = browser_backend._adb.device() 98 99 @benchmark.Enabled('android') 100 def testCreateSymFs(self): 101 # pylint: disable=W0212 102 browser_pid = self._browser._browser_backend.pid 103 pids = ([browser_pid] + 104 self._browser._platform_backend.GetChildPids(browser_pid)) 105 libs = _GetLibrariesMappedIntoProcesses(self._device, pids) 106 assert libs 107 108 symfs_dir = tempfile.mkdtemp() 109 try: 110 kallsyms = android_profiling_helper.CreateSymFs(self._device, symfs_dir, 111 libs) 112 113 # Check that we have kernel symbols. 114 assert os.path.exists(kallsyms) 115 116 is_unstripped = re.compile('^/data/app/.*\.so$') 117 has_unstripped = False 118 119 # Check that all requested libraries are present. 120 for lib in libs: 121 has_unstripped = has_unstripped or is_unstripped.match(lib) 122 assert os.path.exists(os.path.join(symfs_dir, lib[1:])), \ 123 '%s not found in symfs' % lib 124 125 # Make sure we found at least one unstripped library. 126 assert has_unstripped 127 finally: 128 shutil.rmtree(symfs_dir) 129 130 @benchmark.Enabled('android') 131 def testGetToolchainBinaryPath(self): 132 with tempfile.NamedTemporaryFile() as libc: 133 self._device.PullFile('/system/lib/libc.so', libc.name) 134 path = android_profiling_helper.GetToolchainBinaryPath(libc.name, 135 'objdump') 136 assert os.path.exists(path) 137