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