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
5"""A module to hold adb specific action implementations."""
6
7import re
8
9import cr
10
11
12class Adb(object):
13  """Exposes the functionality of the adb tool to the rest of cr.
14
15  This is intended as the only class in the cr that needs to understand the
16  adb command line, and expose it in neutral form to the rest of the code.
17  """
18
19  # Tracks the set of killed target names, so we don't keep issuing kill
20  # commands that are not going to have any effect.
21  _kills = {}
22
23  @classmethod
24  def GetPids(cls, target):
25    """Gets the set of running PIDs that match the specified target."""
26    pids = []
27    output = cr.Host.Capture(target, '{CR_ADB}', 'shell', 'ps')
28    pattern = re.compile(r'\S+\s+(\d+)\s+.*{CR_PROCESS}')
29    for line in output.split('\n'):
30      match = re.match(pattern, line)
31      if match:
32        pids.append(match.group(1))
33    return pids
34
35  @classmethod
36  def Run(cls, target, arguments):
37    """Invoke a target binary on the device."""
38    cr.Host.Execute(
39        target,
40        '{CR_ADB}', 'shell', 'am', 'start',
41        '-a', '{CR_ACTION}',
42        '-n', '{CR_INTENT}',
43        '{CR_RUN_ARGUMENTS}',
44        *arguments
45    )
46
47  @classmethod
48  def Kill(cls, target, _):
49    """Kill all running processes for a target."""
50    target_name = target.build_target
51    if target_name in cls._kills:
52      # already killed this target, do nothing
53      return
54    pids = cls.GetPids(target)
55    if pids:
56      cr.Host.Execute(target, '{CR_ADB}', 'shell', 'kill', *pids)
57    elif target.verbose:
58      print target.Substitute('{CR_TARGET_NAME} not running')
59    cls._kills[target_name] = True
60
61  @classmethod
62  def Uninstall(cls, target, arguments):
63    cr.Host.Execute(
64        target,
65        '{CR_ADB}', 'uninstall',
66        '{CR_PACKAGE}',
67        *arguments
68    )
69
70  @classmethod
71  def Install(cls, target, arguments):
72    cr.Host.Execute(
73        target,
74        '{CR_ADB}', 'install',
75        '{CR_BINARY}',
76        *arguments
77    )
78
79  @classmethod
80  def Reinstall(cls, target, arguments):
81    cr.Host.Execute(
82        target,
83        '{CR_ADB}', 'install',
84        '-r',
85        '-d',
86        '{CR_BINARY}',
87        *arguments
88    )
89
90  @classmethod
91  def AttachGdb(cls, target, arguments):
92    cr.Host.Execute(
93        target,
94        '{CR_ADB_GDB}',
95        '--adb={CR_ADB}',
96        '--symbol-dir=${CR_BUILD_DIR}/lib',
97        '--program-name={CR_TARGET_NAME}',
98        '--package-name={CR_PACKAGE}',
99        *arguments
100    )
101
102
103class AdbRunner(cr.Runner):
104  """An implementation of cr.Runner for the android platform."""
105
106  @property
107  def enabled(self):
108    return cr.AndroidPlatform.GetInstance().is_active
109
110  def Kill(self, context, targets, arguments):
111    for target in targets:
112      Adb.Kill(target, arguments)
113
114  def Run(self, context, target, arguments):
115    Adb.Run(target, arguments)
116
117  def Test(self, context, target, arguments):
118    cr.Host.Execute(
119        target,
120        '{CR_TEST_RUNNER}', '{CR_TEST_TYPE}',
121        '-s', '{CR_TARGET_NAME}',
122        '--{CR_TEST_MODE}',
123        *arguments
124    )
125
126
127class AdbInstaller(cr.Installer):
128  """An implementation of cr.Installer for the android platform."""
129
130  @property
131  def enabled(self):
132    return cr.AndroidPlatform.GetInstance().is_active
133
134  def Uninstall(self, context, targets, arguments):
135    for target in targets:
136      Adb.Uninstall(target, arguments)
137
138  def Install(self, context, targets, arguments):
139    for target in targets:
140      Adb.Install(target, arguments)
141
142  def Reinstall(self, context, targets, arguments):
143    for target in targets:
144      Adb.Reinstall(target, arguments)
145