eca8b83a85e8e0ccfe22abee481c536191298e04
[platform/framework/web/crosswalk.git] / src / tools / telemetry / telemetry / core / backends / adb_commands.py
1 # Copyright 2013 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 """Brings in Chrome Android's android_commands module, which itself is a
5 thin(ish) wrapper around adb."""
6
7 import logging
8 import os
9 import shutil
10 import stat
11 import sys
12
13 from telemetry.core import util
14 from telemetry.core.platform.profiler import android_prebuilt_profiler_helper
15
16 # This is currently a thin wrapper around Chrome Android's
17 # build scripts, located in chrome/build/android. This file exists mainly to
18 # deal with locating the module.
19
20 util.AddDirToPythonPath(util.GetChromiumSrcDir(), 'build', 'android')
21 try:
22   from pylib import android_commands  # pylint: disable=F0401
23   from pylib import constants  # pylint: disable=F0401
24   from pylib import forwarder  # pylint: disable=F0401
25   from pylib import ports  # pylint: disable=F0401
26   from pylib.utils import apk_helper # #pylint: disable=F0401
27 except Exception:
28   android_commands = None
29
30
31 def IsAndroidSupported():
32   return android_commands != None
33
34
35 def GetAttachedDevices():
36   """Returns a list of attached, online android devices.
37
38   If a preferred device has been set with ANDROID_SERIAL, it will be first in
39   the returned list."""
40   return android_commands.GetAttachedDevices()
41
42
43 def AllocateTestServerPort():
44   return ports.AllocateTestServerPort()
45
46
47 def ResetTestServerPortAllocation():
48   return ports.ResetTestServerPortAllocation()
49
50
51 class AdbCommands(object):
52   """A thin wrapper around ADB"""
53
54   def __init__(self, device):
55     self._adb = android_commands.AndroidCommands(device)
56     self._device = device
57
58   def device(self):
59     return self._device
60
61   def Adb(self):
62     return self._adb
63
64   def Forward(self, local, remote):
65     ret = self._adb.Adb().SendCommand('forward %s %s' % (local, remote))
66     assert ret == ''
67
68   def RunShellCommand(self, command, timeout_time=20, log_result=False):
69     """Send a command to the adb shell and return the result.
70
71     Args:
72       command: String containing the shell command to send. Must not include
73                the single quotes as we use them to escape the whole command.
74       timeout_time: Number of seconds to wait for command to respond before
75         retrying, used by AdbInterface.SendShellCommand.
76       log_result: Boolean to indicate whether we should log the result of the
77                   shell command.
78
79     Returns:
80       list containing the lines of output received from running the command
81     """
82     return self._adb.RunShellCommand(command, timeout_time, log_result)
83
84   def CloseApplication(self, package):
85     """Attempt to close down the application, using increasing violence.
86
87     Args:
88       package: Name of the process to kill off, e.g.
89       com.google.android.apps.chrome
90     """
91     self._adb.CloseApplication(package)
92
93   def KillAll(self, process):
94     """Android version of killall, connected via adb.
95
96     Args:
97       process: name of the process to kill off
98
99     Returns:
100       the number of processess killed
101     """
102     return self._adb.KillAll(process)
103
104   def ExtractPid(self, process_name):
105     """Extracts Process Ids for a given process name from Android Shell.
106
107     Args:
108       process_name: name of the process on the device.
109
110     Returns:
111       List of all the process ids (as strings) that match the given name.
112       If the name of a process exactly matches the given name, the pid of
113       that process will be inserted to the front of the pid list.
114     """
115     return self._adb.ExtractPid(process_name)
116
117   def Install(self, apk_path):
118     """Installs specified package if necessary.
119
120     Args:
121       apk_path: Path to .apk file to install.
122     """
123
124     if (os.path.exists(os.path.join(
125         constants.GetOutDirectory('Release'), 'md5sum_bin_host'))):
126       constants.SetBuildType('Release')
127     elif (os.path.exists(os.path.join(
128         constants.GetOutDirectory('Debug'), 'md5sum_bin_host'))):
129       constants.SetBuildType('Debug')
130
131     apk_package_name = apk_helper.GetPackageName(apk_path)
132     return self._adb.ManagedInstall(apk_path, package_name=apk_package_name)
133
134   def StartActivity(self, package, activity, wait_for_completion=False,
135                     action='android.intent.action.VIEW',
136                     category=None, data=None,
137                     extras=None, trace_file_name=None,
138                     flags=None):
139     """Starts |package|'s activity on the device.
140
141     Args:
142       package: Name of package to start (e.g. 'com.google.android.apps.chrome').
143       activity: Name of activity (e.g. '.Main' or
144         'com.google.android.apps.chrome.Main').
145       wait_for_completion: wait for the activity to finish launching (-W flag).
146       action: string (e.g. 'android.intent.action.MAIN'). Default is VIEW.
147       category: string (e.g. 'android.intent.category.HOME')
148       data: Data string to pass to activity (e.g. 'http://www.example.com/').
149       extras: Dict of extras to pass to activity. Values are significant.
150       trace_file_name: If used, turns on and saves the trace to this file name.
151     """
152     return self._adb.StartActivity(package, activity, wait_for_completion,
153                     action,
154                     category, data,
155                     extras, trace_file_name,
156                     flags)
157
158   def Push(self, local, remote):
159     return self._adb.Adb().Push(local, remote)
160
161   def Pull(self, remote, local):
162     return self._adb.Adb().Pull(remote, local)
163
164   def FileExistsOnDevice(self, file_name):
165     return self._adb.FileExistsOnDevice(file_name)
166
167   def IsRootEnabled(self):
168     return self._adb.IsRootEnabled()
169
170   def GoHome(self):
171     return self._adb.GoHome()
172
173
174 def SetupPrebuiltTools(device):
175   # TODO(bulach): build the host tools for mac, and the targets for x86/mips.
176   # Prebuilt tools from r226197.
177   has_prebuilt = sys.platform.startswith('linux')
178   if has_prebuilt:
179     adb = AdbCommands(device)
180     abi = adb.RunShellCommand('getprop ro.product.cpu.abi')
181     has_prebuilt = abi and abi[0].startswith('armeabi')
182   if not has_prebuilt:
183     logging.error('Prebuilt tools only available for ARM.')
184     return False
185
186   prebuilt_tools = [
187       'forwarder_dist/device_forwarder',
188       'host_forwarder',
189       'md5sum_dist/md5sum_bin',
190       'md5sum_bin_host',
191   ]
192   for t in prebuilt_tools:
193     src = os.path.basename(t)
194     android_prebuilt_profiler_helper.GetIfChanged(src)
195     dest = os.path.join(constants.GetOutDirectory(), t)
196     if not os.path.exists(dest):
197       logging.warning('Setting up prebuilt %s', dest)
198       if not os.path.exists(os.path.dirname(dest)):
199         os.makedirs(os.path.dirname(dest))
200       shutil.copyfile(android_prebuilt_profiler_helper.GetHostPath(src), dest)
201       os.chmod(dest, stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR)
202   return True
203
204 def HasForwarder(buildtype=None):
205   if not buildtype:
206     return (HasForwarder(buildtype='Release') or
207             HasForwarder(buildtype='Debug'))
208   device_forwarder = os.path.join(
209       constants.GetOutDirectory(build_type=buildtype),
210       'forwarder_dist', 'device_forwarder')
211   host_forwarder = os.path.join(
212       constants.GetOutDirectory(build_type=buildtype), 'host_forwarder')
213   return os.path.exists(device_forwarder) and os.path.exists(host_forwarder)
214
215
216 class Forwarder(object):
217   def __init__(self, adb, *port_pairs):
218     self._adb = adb.Adb()
219     self._host_port = port_pairs[0].local_port
220
221     new_port_pairs = [(port_pair.local_port, port_pair.remote_port)
222                       for port_pair in port_pairs]
223
224     self._port_pairs = new_port_pairs
225     if HasForwarder('Release'):
226       constants.SetBuildType('Release')
227     elif HasForwarder('Debug'):
228       constants.SetBuildType('Debug')
229     else:
230       raise Exception('Build forwarder2')
231     forwarder.Forwarder.Map(new_port_pairs, self._adb)
232
233   @property
234   def url(self):
235     return 'http://127.0.0.1:%i' % self._host_port
236
237   def Close(self):
238     for (device_port, _) in self._port_pairs:
239       forwarder.Forwarder.UnmapDevicePort(device_port, self._adb)