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