Commit 540d961e authored by mikecase's avatar mikecase Committed by Commit bot

[Android] Add timeout for joining logcat record thread.

Currently, the logcat monitor can hang if nothing is being output
by logcat after you try to join the recorder thread. Adding a
timeout to join to prevent this.

BUG=581352

Review URL: https://codereview.chromium.org/1648443002

Cr-Commit-Position: refs/heads/master@{#371880}
parent dfcb362e
...@@ -21,6 +21,7 @@ from devil.utils import reraiser_thread ...@@ -21,6 +21,7 @@ from devil.utils import reraiser_thread
class LogcatMonitor(object): class LogcatMonitor(object):
_RECORD_THREAD_JOIN_WAIT = 2.0
_WAIT_TIME = 0.2 _WAIT_TIME = 0.2
_THREADTIME_RE_FORMAT = ( _THREADTIME_RE_FORMAT = (
r'(?P<date>\S*) +(?P<time>\S*) +(?P<proc_id>%s) +(?P<thread_id>%s) +' r'(?P<date>\S*) +(?P<time>\S*) +(?P<proc_id>%s) +(?P<thread_id>%s) +'
...@@ -43,6 +44,7 @@ class LogcatMonitor(object): ...@@ -43,6 +44,7 @@ class LogcatMonitor(object):
self._filter_specs = filter_specs self._filter_specs = filter_specs
self._output_file = output_file self._output_file = output_file
self._record_file = None self._record_file = None
self._record_file_lock = threading.Lock()
self._record_thread = None self._record_thread = None
self._stop_recording_event = threading.Event() self._stop_recording_event = threading.Event()
...@@ -155,13 +157,13 @@ class LogcatMonitor(object): ...@@ -155,13 +157,13 @@ class LogcatMonitor(object):
def record_to_file(): def record_to_file():
# Write the log with line buffering so the consumer sees each individual # Write the log with line buffering so the consumer sees each individual
# line. # line.
with open(self._record_file.name, 'a', 1) as f: for data in self._adb.Logcat(filter_specs=self._filter_specs,
for data in self._adb.Logcat(filter_specs=self._filter_specs, logcat_format='threadtime'):
logcat_format='threadtime'): with self._record_file_lock:
if self._stop_recording_event.isSet(): if self._stop_recording_event.isSet():
f.flush()
return return
f.write(data + '\n') if self._record_file and not self._record_file.closed:
self._record_file.write(data + '\n')
self._stop_recording_event.clear() self._stop_recording_event.clear()
if not self._record_thread: if not self._record_thread:
...@@ -172,7 +174,7 @@ class LogcatMonitor(object): ...@@ -172,7 +174,7 @@ class LogcatMonitor(object):
"""Finish recording logcat.""" """Finish recording logcat."""
if self._record_thread: if self._record_thread:
self._stop_recording_event.set() self._stop_recording_event.set()
self._record_thread.join() self._record_thread.join(timeout=self._RECORD_THREAD_JOIN_WAIT)
self._record_thread.ReraiseIfException() self._record_thread.ReraiseIfException()
self._record_thread = None self._record_thread = None
...@@ -184,7 +186,7 @@ class LogcatMonitor(object): ...@@ -184,7 +186,7 @@ class LogcatMonitor(object):
if self._clear: if self._clear:
self._adb.Logcat(clear=True) self._adb.Logcat(clear=True)
if not self._record_file: if not self._record_file:
self._record_file = tempfile.NamedTemporaryFile() self._record_file = tempfile.NamedTemporaryFile(mode='a', bufsize=1)
self._StartRecording() self._StartRecording()
def Stop(self): def Stop(self):
...@@ -194,22 +196,24 @@ class LogcatMonitor(object): ...@@ -194,22 +196,24 @@ class LogcatMonitor(object):
|self._output_file|. |self._output_file|.
""" """
self._StopRecording() self._StopRecording()
if self._record_file and self._output_file: with self._record_file_lock:
try: if self._record_file and self._output_file:
os.makedirs(os.path.dirname(self._output_file)) try:
except OSError as e: os.makedirs(os.path.dirname(self._output_file))
if e.errno != errno.EEXIST: except OSError as e:
raise if e.errno != errno.EEXIST:
shutil.copy(self._record_file.name, self._output_file) raise
shutil.copy(self._record_file.name, self._output_file)
def Close(self): def Close(self):
"""Closes logcat recording file. """Closes logcat recording file.
Should be called when finished using the logcat monitor. Should be called when finished using the logcat monitor.
""" """
if self._record_file: with self._record_file_lock:
self._record_file.close() if self._record_file:
self._record_file = None self._record_file.close()
self._record_file = None
def __enter__(self): def __enter__(self):
"""Starts the logcat monitor.""" """Starts the logcat monitor."""
...@@ -222,9 +226,12 @@ class LogcatMonitor(object): ...@@ -222,9 +226,12 @@ class LogcatMonitor(object):
def __del__(self): def __del__(self):
"""Closes logcat recording file in case |Close| was never called.""" """Closes logcat recording file in case |Close| was never called."""
if self._record_file: with self._record_file_lock:
logging.warning('Need to call |Close| on the logcat monitor when done!') if self._record_file:
self._record_file.close() logging.warning(
'Need to call |Close| on the logcat monitor when done!')
self._record_file.close()
class LogcatMonitorCommandError(device_errors.CommandFailedError): class LogcatMonitorCommandError(device_errors.CommandFailedError):
"""Exception for errors with logcat monitor commands.""" """Exception for errors with logcat monitor commands."""
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment