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