Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1457)

Side by Side Diff: build/android/adb_logcat_monitor.py

Issue 10578032: Upstreaming android build tools (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Fixed lint issues Created 8 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | build/android/adb_logcat_printer.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 #!/usr/bin/python
2 #
3 # Copyright (c) 2012 The Chromium 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
7 """Saves logcats from all connected devices.
8
9 Usage: adb_logcat_monitor.py <base_dir> [<adb_binary_path>]
10
11 This script will repeatedly poll adb for new devices and save logcats
12 inside the <base_dir> directory, which it attempts to create. The
13 script will run until killed by an external signal. To test, run the
14 script in a shell and <Ctrl>-C it after a while. It should be
15 resilient across phone disconnects and reconnects and start the logcat
16 early enough to not miss anything.
17 """
18
19 import logging
20 import os
21 import re
22 import shutil
23 import signal
24 import subprocess
25 import sys
26 import time
27
28 # Map from device_id -> (process, logcat_num)
29 devices = {}
30
31
32 class TimeoutException(Exception):
33 """Exception used to signal a timeout."""
34 pass
35
36
37 class SigtermError(Exception):
38 """Exception used to catch a sigterm."""
39 pass
40
41
42 def StartLogcatIfNecessary(device_id, adb_cmd, base_dir):
43 """Spawns a adb logcat process if one is not currently running."""
44 process, logcat_num = devices[device_id]
45 if process:
46 if process.poll() is None:
47 # Logcat process is still happily running
48 return
49 else:
50 logging.info('Logcat for device %s has died', device_id)
51 error_filter = re.compile('- waiting for device -')
52 for line in process.stderr:
53 if not error_filter.match(line):
54 logging.error(device_id + ': ' + line)
55
56 logging.info('Starting logcat %d for device %s', logcat_num,
57 device_id)
58 logcat_filename = 'logcat_%s_%03d' % (device_id, logcat_num)
59 logcat_file = open(os.path.join(base_dir, logcat_filename), 'w')
60 process = subprocess.Popen([adb_cmd, '-s', device_id,
61 'logcat', '-v', 'threadtime'],
62 stdout=logcat_file,
63 stderr=subprocess.PIPE)
64 devices[device_id] = (process, logcat_num + 1)
65
66
67 def GetAttachedDevices(adb_cmd):
68 """Gets the device list from adb.
69
70 We use an alarm in this function to avoid deadlocking from an external
71 dependency.
72
73 Args:
74 adb_cmd: binary to run adb
75
76 Returns:
77 list of devices or an empty list on timeout
78 """
79 signal.alarm(2)
80 try:
81 out, err = subprocess.Popen([adb_cmd, 'devices'],
82 stdout=subprocess.PIPE,
83 stderr=subprocess.PIPE).communicate()
84 if err:
85 logging.warning('adb device error %s', err.strip())
86 return re.findall('^(\w+)\tdevice$', out, re.MULTILINE)
87 except TimeoutException:
88 logging.warning('"adb devices" command timed out')
89 return []
90 except (IOError, OSError):
91 logging.exception('Exception from "adb devices"')
92 return []
93 finally:
94 signal.alarm(0)
95
96
97 def main(base_dir, adb_cmd='adb'):
98 """Monitor adb forever. Expects a SIGINT (Ctrl-C) to kill."""
99 # We create the directory to ensure 'run once' semantics
100 if os.path.exists(base_dir):
101 print 'adb_logcat_monitor: %s already exists? Cleaning' % base_dir
102 shutil.rmtree(base_dir, ignore_errors=True)
103
104 os.makedirs(base_dir)
105 logging.basicConfig(filename=os.path.join(base_dir, 'eventlog'),
106 level=logging.INFO,
107 format='%(asctime)-2s %(levelname)-8s %(message)s')
108
109 # Set up the alarm for calling 'adb devices'. This is to ensure
110 # our script doesn't get stuck waiting for a process response
111 def TimeoutHandler(_, unused_frame):
112 raise TimeoutException()
113 signal.signal(signal.SIGALRM, TimeoutHandler)
114
115 # Handle SIGTERMs to ensure clean shutdown
116 def SigtermHandler(_, unused_frame):
117 raise SigtermError()
118 signal.signal(signal.SIGTERM, SigtermHandler)
119
120 logging.info('Started with pid %d', os.getpid())
121 pid_file_path = os.path.join(base_dir, 'LOGCAT_MONITOR_PID')
122
123 try:
124 with open(pid_file_path, 'w') as f:
125 f.write(str(os.getpid()))
126 while True:
127 for device_id in GetAttachedDevices(adb_cmd):
128 if not device_id in devices:
129 devices[device_id] = (None, 0)
130
131 for device in devices:
132 # This will spawn logcat watchers for any device ever detected
133 StartLogcatIfNecessary(device, adb_cmd, base_dir)
134
135 time.sleep(5)
136 except SigtermError:
137 logging.info('Received SIGTERM, shutting down')
138 except:
139 logging.exception('Unexpected exception in main.')
140 finally:
141 for process, _ in devices.itervalues():
142 if process:
143 try:
144 process.terminate()
145 except OSError:
146 pass
147 os.remove(pid_file_path)
148
149
150 if __name__ == '__main__':
151 if 2 <= len(sys.argv) <= 3:
152 print 'adb_logcat_monitor: Initializing'
153 sys.exit(main(*sys.argv[1:3]))
154
155 print 'Usage: %s <base_dir> [<adb_binary_path>]' % sys.argv[0]
OLDNEW
« no previous file with comments | « no previous file | build/android/adb_logcat_printer.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698