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    with target:
28      output = cr.Host.Capture('{CR_ADB}', 'shell', 'ps')
29    pattern = re.compile(r'\S+\s+(\d+)\s+.*{CR_PROCESS}')
30    for line in output.split('\n'):
31      match = re.match(pattern, line)
32      if match:
33        pids.append(match.group(1))
34    return pids
35
36  @classmethod
37  def Run(cls, target, arguments):
38    """Invoke a target binary on the device."""
39    with target:
40      cr.Host.Execute(
41          '{CR_ADB}', 'shell', 'am', 'start',
42          '-a', '{CR_ACTION}',
43          '-n', '{CR_INTENT}',
44          '{CR_RUN_ARGUMENTS}',
45          *arguments
46    )
47
48  @classmethod
49  def Kill(cls, target, _):
50    """Kill all running processes for a target."""
51    target_name = target.build_target
52    if target_name in cls._kills:
53      # already killed this target, do nothing
54      return
55    pids = cls.GetPids(target)
56    if pids:
57      with target:
58        cr.Host.Execute('{CR_ADB}', 'shell', 'kill', *pids)
59    elif target.verbose:
60      print target.Substitute('{CR_TARGET_NAME} not running')
61    cls._kills[target_name] = True
62
63  @classmethod
64  def Uninstall(cls, target, arguments):
65    with target:
66      cr.Host.Execute(
67          '{CR_ADB}', 'uninstall',
68          '{CR_PACKAGE}',
69          *arguments
70    )
71
72  @classmethod
73  def Install(cls, target, arguments):
74    with target:
75      cr.Host.Execute(
76          '{CR_ADB}', 'install',
77          '{CR_BINARY}',
78          *arguments
79    )
80
81  @classmethod
82  def Reinstall(cls, target, arguments):
83    with target:
84      cr.Host.Execute(
85          '{CR_ADB}', 'install',
86          '-r',
87          '{CR_BINARY}',
88          *arguments
89    )
90
91  @classmethod
92  def AttachGdb(cls, target, arguments):
93    with target:
94      cr.Host.Execute(
95          '{CR_ADB_GDB}',
96          '--adb={CR_ADB}',
97          '--symbol-dir=${CR_BUILD_DIR}/lib',
98          '--program-name={CR_TARGET_NAME}',
99          '--package-name={CR_PACKAGE}',
100          *arguments
101    )
102
103
104class AdbRunner(cr.Runner):
105  """An implementation of cr.Runner for the android platform."""
106
107  @property
108  def enabled(self):
109    return cr.AndroidPlatform.GetInstance().is_active
110
111  def Kill(self, targets, arguments):
112    for target in targets:
113      Adb.Kill(target, arguments)
114
115  def Run(self, target, arguments):
116    Adb.Run(target, arguments)
117
118  def Test(self, target, arguments):
119    with target:
120      cr.Host.Execute(
121        '{CR_TEST_RUNNER}', '{CR_TEST_TYPE}',
122        '-s', '{CR_TARGET_NAME}',
123        '--{CR_TEST_MODE}',
124        *arguments
125    )
126
127
128class AdbInstaller(cr.Installer):
129  """An implementation of cr.Installer for the android platform."""
130
131  @property
132  def enabled(self):
133    return cr.AndroidPlatform.GetInstance().is_active
134
135  def Uninstall(self, targets, arguments):
136    for target in targets:
137      Adb.Uninstall(target, arguments)
138
139  def Install(self, targets, arguments):
140    for target in targets:
141      Adb.Install(target, arguments)
142
143  def Reinstall(self, targets, arguments):
144    for target in targets:
145      Adb.Reinstall(target, arguments)
146