• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#!/usr/bin/python
2
3# Copyright 2017 The Chromium OS Authors. All rights reserved.
4# Use of this source code is governed by a BSD-style license that can be
5# found in the LICENSE file.
6
7import argparse
8import logging
9import pipes
10import re
11import time
12
13import common
14from autotest_lib.client.bin import utils
15from autotest_lib.client.common_lib import logging_config
16
17_ADB_POLLING_INTERVAL_SECONDS = 10
18_ADB_CONNECT_INTERVAL_SECONDS = 1
19
20
21def _get_adb_options(target, socket):
22    """Get adb global options."""
23    # ADB 1.0.36 does not support -L adb socket option. Parse the host and port
24    # part from the socket instead.
25    # https://developer.android.com/studio/command-line/adb.html#issuingcommands
26    pattern = r'^[^:]+:([^:]+):(\d+)$'
27    match = re.match(pattern, socket)
28    if not match:
29        raise ValueError('Unrecognized socket format: %s' % socket)
30    server_host, server_port = match.groups()
31    return '-s %s -H %s -P %s' % (
32        pipes.quote(target), pipes.quote(server_host), pipes.quote(server_port))
33
34
35def _run_adb_cmd(cmd, adb_option="", **kwargs):
36    """Run adb command.
37
38    @param cmd: command to issue with adb. (Ex: connect, devices)
39    @param target: Device to connect to.
40    @param adb_option: adb global option configuration.
41
42    @return: the stdout of the command.
43    """
44    adb_cmd = 'adb %s %s' % (adb_option, cmd)
45    output = utils.system_output(adb_cmd, **kwargs)
46    logging.debug('%s: %s', adb_cmd, output)
47    return output
48
49
50def _is_adb_connected(target, adb_option=""):
51    """Return true if adb is connected to the container.
52
53    @param target: Device to connect to.
54    @param adb_option: adb global option configuration.
55    """
56    output = _run_adb_cmd(
57        'get-state', adb_option=adb_option, ignore_status=True)
58    return output.strip() == 'device'
59
60
61def _ensure_adb_connected(target, adb_option=""):
62    """Ensures adb is connected to the container, reconnects otherwise.
63
64    @param target: Device to connect to.
65    @param adb_option: adb global options configuration.
66    """
67    while not _is_adb_connected(target, adb_option):
68        logging.info('adb not connected. attempting to reconnect')
69        _run_adb_cmd('connect %s' % pipes.quote(target),
70                     adb_option=adb_option, ignore_status=True)
71        time.sleep(_ADB_CONNECT_INTERVAL_SECONDS)
72
73
74if __name__ == '__main__':
75    logging_config.LoggingConfig().configure_logging(verbose=True)
76    parser = argparse.ArgumentParser(description='ensure adb is connected')
77    parser.add_argument('target', help='Device to connect to')
78    parser.add_argument('--socket', help='ADB server socket.',
79                        default='tcp:localhost:5037')
80    args = parser.parse_args()
81    adb_option = _get_adb_options(args.target, args.socket)
82
83    logging.info('Starting adb_keepalive for target %s on socket %s',
84                 args.target, args.socket)
85    while True:
86        try:
87            time.sleep(_ADB_POLLING_INTERVAL_SECONDS)
88            _ensure_adb_connected(args.target, adb_option=adb_option)
89        except KeyboardInterrupt:
90            logging.info('Shutting down')
91            break
92