Skip to content

Commit

Permalink
android: fix logs forwarding latency
Browse files Browse the repository at this point in the history
Instead of executing an adb shell command for each log line, spawn one
adb shell per android device and write one log command per log to its
stdin. This considerably reduce the forwarding latency.
  • Loading branch information
uael committed Nov 28, 2023
1 parent 62d6e59 commit 78b6906
Showing 1 changed file with 28 additions and 15 deletions.
43 changes: 28 additions & 15 deletions avatar/pandora_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,10 @@
import grpc
import grpc.aio
import logging
import os
import portpicker
import re
import shlex
import subprocess
import threading
import types

Expand Down Expand Up @@ -118,6 +118,7 @@ class AndroidPandoraServer(PandoraServer[AndroidDevice]):
_port: int
_logger: logging.Logger
_handler: logging.Handler
_adb_shell: subprocess.Popen[bytes]

def start(self) -> PandoraClient:
"""Sets up and starts the Pandora server on the Android device."""
Expand All @@ -140,27 +141,36 @@ def start(self) -> PandoraClient:

# Forward all logging to ADB logs
adb = self.device.adb
self._adb_shell = subprocess.Popen(['adb', '-s', adb.serial, 'shell'], stdin=subprocess.PIPE)

# This regex match all ANSI escape sequences (colors, style, ..).
ansi_escape = re.compile(r'\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])')

Check warning

Code scanning / CodeQL

Overly permissive regular expression range Medium

Suspicious character range that is equivalent to [@A-Z].

Check warning

Code scanning / CodeQL

Overly permissive regular expression range Medium

Suspicious character range that is equivalent to \[0-9:;<=>?\].

class AdbLoggingHandler(logging.Handler):
LOGGING_TO_ANDROID_LEVELS = {
logging.FATAL: 'f',
logging.ERROR: 'e',
logging.WARN: 'w',
logging.INFO: 'i',
logging.DEBUG: 'd',
logging.NOTSET: 'd',
}

def __init__(self, adb_shell: subprocess.Popen[bytes]) -> None:
self.adb_shell = adb_shell

def emit(self, record: logging.LogRecord) -> None:
if record.levelno <= logging.DEBUG:
return
ansi_escape = re.compile(r'\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])')
msg = self.format(record)
msg = ansi_escape.sub('', msg)
level = {
logging.FATAL: 'f',
logging.ERROR: 'e',
logging.WARN: 'w',
logging.INFO: 'i',
logging.DEBUG: 'd',
logging.NOTSET: 'd',
}[record.levelno]
for msg in msg.splitlines():
os.system(f'adb -s {adb.serial} shell "log -t Avatar -p {level} {shlex.quote(msg)}"')
# Format and remove all ANSI escape sequences.
msg = ansi_escape.sub('', self.format(record))
level = AdbLoggingHandler.LOGGING_TO_ANDROID_LEVELS[record.levelno]
assert self.adb_shell.stdin
self.adb_shell.stdin.write(f'log -t Avatar -p {level} {shlex.quote(msg)}\n'.encode('utf-8'))
self.adb_shell.stdin.flush()

self._logger = logging.getLogger()
self._handler = AdbLoggingHandler()
self._handler = AdbLoggingHandler(self._adb_shell)
self._logger.addHandler(self._handler)

return PandoraClient(f'localhost:{self._port}', 'android')
Expand All @@ -176,6 +186,9 @@ def stop(self) -> None:

# Remove ADB logging handler
self._logger.removeHandler(self._handler)
assert self._adb_shell.stdin
self._adb_shell.stdin.close()
self._adb_shell.wait()

self.device.adb.forward(['--remove', f'tcp:{self._port}']) # type: ignore
self._instrumentation.join()
Expand Down

0 comments on commit 78b6906

Please sign in to comment.