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.
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.
9 The interface is intended to be used as follows.
11 1. For tests that simply run a native process (i.e. no activity is spawned):
13 Call tool.CopyFiles(device).
14 Prepend test command line with tool.GetTestWrapper().
16 2. For tests that spawn an activity:
18 Call tool.CopyFiles(device).
19 Call tool.SetupEnvironment().
20 Run the test as usual.
21 Call tool.CleanUpEnvironment().
23 # pylint: disable=R0201
31 from pylib
.constants
import DIR_SOURCE_ROOT
32 from pylib
.device
import device_errors
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
)
42 device
.WriteFile(path
, '%f' % scale
, as_root
=True)
45 class BaseTool(object):
46 """A tool that does nothing."""
52 def GetTestWrapper(self
):
53 """Returns a string that is to be prepended to the test command line."""
56 def GetUtilWrapper(self
):
57 """Returns the wrapper name for the utilities.
60 A string that is to be prepended to the command line of utility
61 processes (forwarder, etc.).
66 def CopyFiles(cls
, device
):
67 """Copies tool-specific files to the device, create directories, etc."""
70 def SetupEnvironment(self
):
71 """Sets up the system environment for a test.
73 This is a good place to set system properties.
77 def CleanUpEnvironment(self
):
78 """Cleans up environment."""
81 def GetTimeoutScale(self
):
82 """Returns a multiplier that should be applied to timeout values."""
85 def NeedsDebugInfo(self
):
86 """Whether this tool requires debug info.
89 True if this tool can not work with stripped binaries.
94 class AddressSanitizerTool(BaseTool
):
95 """AddressSanitizer tool."""
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'
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())
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
122 'tools/android/asan/third_party/asan_device_setup.sh'),
123 '--device', str(device
),
125 '--extra-options', AddressSanitizerTool
.EXTRA_OPTIONS
])
126 device
.WaitUntilFullyBooted()
128 def GetTestWrapper(self
):
129 return AddressSanitizerTool
.WRAPPER_NAME
131 def GetUtilWrapper(self
):
132 """Returns the wrapper for utilities, such as forwarder.
134 AddressSanitizer wrapper must be added to all instrumented binaries,
135 including forwarder and the like. This can be removed if such binaries
136 were built without instrumentation. """
137 return self
.GetTestWrapper()
139 def SetupEnvironment(self
):
141 self
._device
.EnableRoot()
142 except device_errors
.CommandFailedError
as e
:
143 # Try to set the timeout scale anyway.
144 # TODO(jbudorick) Handle this exception appropriately after interface
145 # conversions are finished.
146 logging
.error(str(e
))
147 SetChromeTimeoutScale(self
._device
, self
.GetTimeoutScale())
149 def CleanUpEnvironment(self
):
150 SetChromeTimeoutScale(self
._device
, None)
152 def GetTimeoutScale(self
):
157 class ValgrindTool(BaseTool
):
158 """Base abstract class for Valgrind tools."""
160 VG_DIR
= '/data/local/tmp/valgrind'
161 VGLOGS_DIR
= '/data/local/tmp/vglogs'
163 def __init__(self
, device
):
164 super(ValgrindTool
, self
).__init
__()
165 self
._device
= device
166 # exactly 31 chars, SystemProperties::PROP_NAME_MAX
167 self
._wrap
_properties
= ['wrap.com.google.android.apps.ch',
168 'wrap.org.chromium.native_test']
171 def CopyFiles(cls
, device
):
172 """Copies Valgrind tools to the device."""
173 device
.RunShellCommand(
174 'rm -r %s; mkdir %s' % (ValgrindTool
.VG_DIR
, ValgrindTool
.VG_DIR
))
175 device
.RunShellCommand(
176 'rm -r %s; mkdir %s' % (ValgrindTool
.VGLOGS_DIR
,
177 ValgrindTool
.VGLOGS_DIR
))
178 files
= cls
.GetFilesForTool()
179 device
.PushChangedFiles(
180 [((os
.path
.join(DIR_SOURCE_ROOT
, f
),
181 os
.path
.join(ValgrindTool
.VG_DIR
, os
.path
.basename(f
)))
184 def SetupEnvironment(self
):
185 """Sets up device environment."""
186 self
._device
.RunShellCommand('chmod 777 /data/local/tmp')
187 self
._device
.RunShellCommand('setenforce 0')
188 for prop
in self
._wrap
_properties
:
189 self
._device
.RunShellCommand(
190 'setprop %s "logwrapper %s"' % (prop
, self
.GetTestWrapper()))
191 SetChromeTimeoutScale(self
._device
, self
.GetTimeoutScale())
193 def CleanUpEnvironment(self
):
194 """Cleans up device environment."""
195 for prop
in self
._wrap
_properties
:
196 self
._device
.RunShellCommand('setprop %s ""' % (prop
,))
197 SetChromeTimeoutScale(self
._device
, None)
200 def GetFilesForTool():
201 """Returns a list of file names for the tool."""
202 raise NotImplementedError()
204 def NeedsDebugInfo(self
):
205 """Whether this tool requires debug info.
208 True if this tool can not work with stripped binaries.
213 class MemcheckTool(ValgrindTool
):
216 def __init__(self
, device
):
217 super(MemcheckTool
, self
).__init
__(device
)
220 def GetFilesForTool():
221 """Returns a list of file names for the tool."""
222 return ['tools/valgrind/android/vg-chrome-wrapper.sh',
223 'tools/valgrind/memcheck/suppressions.txt',
224 'tools/valgrind/memcheck/suppressions_android.txt']
226 def GetTestWrapper(self
):
227 """Returns a string that is to be prepended to the test command line."""
228 return ValgrindTool
.VG_DIR
+ '/' + 'vg-chrome-wrapper.sh'
230 def GetTimeoutScale(self
):
231 """Returns a multiplier that should be applied to timeout values."""
235 class TSanTool(ValgrindTool
):
236 """ThreadSanitizer tool. See http://code.google.com/p/data-race-test ."""
238 def __init__(self
, device
):
239 super(TSanTool
, self
).__init
__(device
)
242 def GetFilesForTool():
243 """Returns a list of file names for the tool."""
244 return ['tools/valgrind/android/vg-chrome-wrapper-tsan.sh',
245 'tools/valgrind/tsan/suppressions.txt',
246 'tools/valgrind/tsan/suppressions_android.txt',
247 'tools/valgrind/tsan/ignores.txt']
249 def GetTestWrapper(self
):
250 """Returns a string that is to be prepended to the test command line."""
251 return ValgrindTool
.VG_DIR
+ '/' + 'vg-chrome-wrapper-tsan.sh'
253 def GetTimeoutScale(self
):
254 """Returns a multiplier that should be applied to timeout values."""
259 'memcheck': MemcheckTool
,
260 'memcheck-renderer': MemcheckTool
,
262 'tsan-renderer': TSanTool
,
263 'asan': AddressSanitizerTool
,
267 def CreateTool(tool_name
, device
):
268 """Creates a tool with the specified tool name.
271 tool_name: Name of the tool to create.
272 device: A DeviceUtils instance.
274 A tool for the specified tool_name.
279 ctor
= TOOL_REGISTRY
.get(tool_name
)
283 print 'Unknown tool %s, available tools: %s' % (
284 tool_name
, ', '.join(sorted(TOOL_REGISTRY
.keys())))
287 def PushFilesForTool(tool_name
, device
):
288 """Pushes the files required for |tool_name| to |device|.
291 tool_name: Name of the tool to create.
292 device: A DeviceUtils instance.
297 clazz
= TOOL_REGISTRY
.get(tool_name
)
299 clazz
.CopyFiles(device
)
301 print 'Unknown tool %s, available tools: %s' % (
302 tool_name
, ', '.join(sorted(TOOL_REGISTRY
.keys())))