Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / build / android / pylib / valgrind_tools.py
1 # Copyright (c) 2012 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
5 """
6 Classes in this file define additional actions that need to be taken to run a
7 test under some kind of runtime error detection tool.
8
9 The interface is intended to be used as follows.
10
11 1. For tests that simply run a native process (i.e. no activity is spawned):
12
13 Call tool.CopyFiles().
14 Prepend test command line with tool.GetTestWrapper().
15
16 2. For tests that spawn an activity:
17
18 Call tool.CopyFiles().
19 Call tool.SetupEnvironment().
20 Run the test as usual.
21 Call tool.CleanUpEnvironment().
22 """
23 # pylint: disable=R0201
24
25 import glob
26 import os.path
27 import subprocess
28 import sys
29
30 from pylib.constants import DIR_SOURCE_ROOT
31
32
33 def SetChromeTimeoutScale(device, scale):
34   """Sets the timeout scale in /data/local/tmp/chrome_timeout_scale to scale."""
35   path = '/data/local/tmp/chrome_timeout_scale'
36   if not scale or scale == 1.0:
37     # Delete if scale is None/0.0/1.0 since the default timeout scale is 1.0
38     device.old_interface.RunShellCommand('rm %s' % path)
39   else:
40     device.old_interface.SetProtectedFileContents(path, '%f' % scale)
41
42
43 class BaseTool(object):
44   """A tool that does nothing."""
45
46   def __init__(self):
47     """Does nothing."""
48     pass
49
50   def GetTestWrapper(self):
51     """Returns a string that is to be prepended to the test command line."""
52     return ''
53
54   def GetUtilWrapper(self):
55     """Returns the wrapper name for the utilities.
56
57     Returns:
58        A string that is to be prepended to the command line of utility
59     processes (forwarder, etc.).
60     """
61     return ''
62
63   def CopyFiles(self):
64     """Copies tool-specific files to the device, create directories, etc."""
65     pass
66
67   def SetupEnvironment(self):
68     """Sets up the system environment for a test.
69
70     This is a good place to set system properties.
71     """
72     pass
73
74   def CleanUpEnvironment(self):
75     """Cleans up environment."""
76     pass
77
78   def GetTimeoutScale(self):
79     """Returns a multiplier that should be applied to timeout values."""
80     return 1.0
81
82   def NeedsDebugInfo(self):
83     """Whether this tool requires debug info.
84
85     Returns:
86       True if this tool can not work with stripped binaries.
87     """
88     return False
89
90
91 class AddressSanitizerTool(BaseTool):
92   """AddressSanitizer tool."""
93
94   WRAPPER_NAME = '/system/bin/asanwrapper'
95   # Disable memcmp overlap check.There are blobs (gl drivers)
96   # on some android devices that use memcmp on overlapping regions,
97   # nothing we can do about that.
98   EXTRA_OPTIONS = 'strict_memcmp=0,use_sigaltstack=1'
99
100   def __init__(self, device):
101     super(AddressSanitizerTool, self).__init__()
102     self._device = device
103     # Configure AndroidCommands to run utils (such as md5sum_bin) under ASan.
104     # This is required because ASan is a compiler-based tool, and md5sum
105     # includes instrumented code from base.
106     device.old_interface.SetUtilWrapper(self.GetUtilWrapper())
107     libs = glob.glob(os.path.join(DIR_SOURCE_ROOT,
108                                   'third_party/llvm-build/Release+Asserts/',
109                                   'lib/clang/*/lib/linux/',
110                                   'libclang_rt.asan-arm-android.so'))
111     assert len(libs) == 1
112     self._lib = libs[0]
113
114   def CopyFiles(self):
115     """Copies ASan tools to the device."""
116     subprocess.call([os.path.join(DIR_SOURCE_ROOT,
117                                   'tools/android/asan/asan_device_setup.sh'),
118                      '--device', self._device.old_interface.GetDevice(),
119                      '--lib', self._lib,
120                      '--extra-options', AddressSanitizerTool.EXTRA_OPTIONS])
121     self._device.old_interface.WaitForDevicePm()
122
123   def GetTestWrapper(self):
124     return AddressSanitizerTool.WRAPPER_NAME
125
126   def GetUtilWrapper(self):
127     """Returns the wrapper for utilities, such as forwarder.
128
129     AddressSanitizer wrapper must be added to all instrumented binaries,
130     including forwarder and the like. This can be removed if such binaries
131     were built without instrumentation. """
132     return self.GetTestWrapper()
133
134   def SetupEnvironment(self):
135     self._device.old_interface.EnableAdbRoot()
136     SetChromeTimeoutScale(self._device, self.GetTimeoutScale())
137
138   def CleanUpEnvironment(self):
139     SetChromeTimeoutScale(self._device, None)
140
141   def GetTimeoutScale(self):
142     # Very slow startup.
143     return 20.0
144
145
146 class ValgrindTool(BaseTool):
147   """Base abstract class for Valgrind tools."""
148
149   VG_DIR = '/data/local/tmp/valgrind'
150   VGLOGS_DIR = '/data/local/tmp/vglogs'
151
152   def __init__(self, device):
153     super(ValgrindTool, self).__init__()
154     self._device = device
155     # exactly 31 chars, SystemProperties::PROP_NAME_MAX
156     self._wrap_properties = ['wrap.com.google.android.apps.ch',
157                              'wrap.org.chromium.native_test']
158
159   def CopyFiles(self):
160     """Copies Valgrind tools to the device."""
161     self._device.old_interface.RunShellCommand(
162         'rm -r %s; mkdir %s' % (ValgrindTool.VG_DIR, ValgrindTool.VG_DIR))
163     self._device.old_interface.RunShellCommand(
164         'rm -r %s; mkdir %s' % (ValgrindTool.VGLOGS_DIR,
165                                 ValgrindTool.VGLOGS_DIR))
166     files = self.GetFilesForTool()
167     for f in files:
168       self._device.old_interface.PushIfNeeded(
169           os.path.join(DIR_SOURCE_ROOT, f),
170           os.path.join(ValgrindTool.VG_DIR, os.path.basename(f)))
171
172   def SetupEnvironment(self):
173     """Sets up device environment."""
174     self._device.old_interface.RunShellCommand('chmod 777 /data/local/tmp')
175     self._device.old_interface.RunShellCommand('setenforce 0')
176     for prop in self._wrap_properties:
177       self._device.old_interface.RunShellCommand(
178           'setprop %s "logwrapper %s"' % (prop, self.GetTestWrapper()))
179     SetChromeTimeoutScale(self._device, self.GetTimeoutScale())
180
181   def CleanUpEnvironment(self):
182     """Cleans up device environment."""
183     for prop in self._wrap_properties:
184       self._device.old_interface.RunShellCommand('setprop %s ""' % (prop,))
185     SetChromeTimeoutScale(self._device, None)
186
187   def GetFilesForTool(self):
188     """Returns a list of file names for the tool."""
189     raise NotImplementedError()
190
191   def NeedsDebugInfo(self):
192     """Whether this tool requires debug info.
193
194     Returns:
195       True if this tool can not work with stripped binaries.
196     """
197     return True
198
199
200 class MemcheckTool(ValgrindTool):
201   """Memcheck tool."""
202
203   def __init__(self, device):
204     super(MemcheckTool, self).__init__(device)
205
206   def GetFilesForTool(self):
207     """Returns a list of file names for the tool."""
208     return ['tools/valgrind/android/vg-chrome-wrapper.sh',
209             'tools/valgrind/memcheck/suppressions.txt',
210             'tools/valgrind/memcheck/suppressions_android.txt']
211
212   def GetTestWrapper(self):
213     """Returns a string that is to be prepended to the test command line."""
214     return ValgrindTool.VG_DIR + '/' + 'vg-chrome-wrapper.sh'
215
216   def GetTimeoutScale(self):
217     """Returns a multiplier that should be applied to timeout values."""
218     return 30
219
220
221 class TSanTool(ValgrindTool):
222   """ThreadSanitizer tool. See http://code.google.com/p/data-race-test ."""
223
224   def __init__(self, device):
225     super(TSanTool, self).__init__(device)
226
227   def GetFilesForTool(self):
228     """Returns a list of file names for the tool."""
229     return ['tools/valgrind/android/vg-chrome-wrapper-tsan.sh',
230             'tools/valgrind/tsan/suppressions.txt',
231             'tools/valgrind/tsan/suppressions_android.txt',
232             'tools/valgrind/tsan/ignores.txt']
233
234   def GetTestWrapper(self):
235     """Returns a string that is to be prepended to the test command line."""
236     return ValgrindTool.VG_DIR + '/' + 'vg-chrome-wrapper-tsan.sh'
237
238   def GetTimeoutScale(self):
239     """Returns a multiplier that should be applied to timeout values."""
240     return 30.0
241
242
243 TOOL_REGISTRY = {
244     'memcheck': MemcheckTool,
245     'memcheck-renderer': MemcheckTool,
246     'tsan': TSanTool,
247     'tsan-renderer': TSanTool,
248     'asan': AddressSanitizerTool,
249 }
250
251
252 def CreateTool(tool_name, device):
253   """Creates a tool with the specified tool name.
254
255   Args:
256     tool_name: Name of the tool to create.
257     device: A DeviceUtils instance.
258   Returns:
259     A tool for the specified tool_name.
260   """
261   if not tool_name:
262     return BaseTool()
263
264   ctor = TOOL_REGISTRY.get(tool_name)
265   if ctor:
266     return ctor(device)
267   else:
268     print 'Unknown tool %s, available tools: %s' % (
269         tool_name, ', '.join(sorted(TOOL_REGISTRY.keys())))
270     sys.exit(1)