diff options
author | Nataniel Borges <natanieljr@google.com> | 2022-04-21 17:52:11 +0000 |
---|---|---|
committer | Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com> | 2022-04-21 17:52:11 +0000 |
commit | fc37e65e61f0f3c259911d9f1bfefe876eea7c99 (patch) | |
tree | 64c2b970ff73995ffe12979d389cda291a301ffc | |
parent | c9f314173524340cafb6209384126d953d3d9815 (diff) | |
parent | 0043465bcc6376d8c1f1a4c91902b253b2576c11 (diff) | |
download | development-fc37e65e61f0f3c259911d9f1bfefe876eea7c99.tar.gz |
[DO NOT MERGE] Update winscope proxy on R am: 50775a7444 am: 0043465bcc
Original change: https://android-review.googlesource.com/c/platform/development/+/2071347
Change-Id: I0504b1374be2f2bb200ca66ea2d0d9e525af8bf5
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
-rwxr-xr-x | tools/winscope/adb_proxy/winscope_proxy.py | 441 |
1 files changed, 79 insertions, 362 deletions
diff --git a/tools/winscope/adb_proxy/winscope_proxy.py b/tools/winscope/adb_proxy/winscope_proxy.py index 344c3cc5b..85089c55b 100755 --- a/tools/winscope/adb_proxy/winscope_proxy.py +++ b/tools/winscope/adb_proxy/winscope_proxy.py @@ -42,12 +42,12 @@ import base64 # CONFIG # -LOG_LEVEL = logging.WARNING +LOG_LEVEL = logging.DEBUG PORT = 5544 # Keep in sync with WINSCOPE_PROXY_VERSION in Winscope DataAdb.vue -VERSION = '0.8' +VERSION = '0.5' WINSCOPE_VERSION_HEADER = "Winscope-Proxy-Version" WINSCOPE_TOKEN_HEADER = "Winscope-Token" @@ -55,14 +55,6 @@ WINSCOPE_TOKEN_HEADER = "Winscope-Token" # Location to save the proxy security token WINSCOPE_TOKEN_LOCATION = os.path.expanduser('~/.config/winscope/.token') -# Winscope traces extensions -WINSCOPE_EXT = ".winscope" -WINSCOPE_EXT_LEGACY = ".pb" -WINSCOPE_EXTS = [WINSCOPE_EXT, WINSCOPE_EXT_LEGACY] - -# Winscope traces directory -WINSCOPE_DIR = "/data/misc/wmtrace/" - # Max interval between the client keep-alive requests in seconds KEEP_ALIVE_INTERVAL_S = 5 @@ -71,203 +63,50 @@ logging.basicConfig(stream=sys.stderr, level=LOG_LEVEL, log = logging.getLogger("ADBProxy") -class File: - def __init__(self, file, filetype) -> None: - self.file = file - self.type = filetype - - def get_filepaths(self, device_id): - return [self.file] - - def get_filetype(self): - return self.type - - -class FileMatcher: - def __init__(self, path, matcher, filetype) -> None: - self.path = path - self.matcher = matcher - self.type = filetype - - def get_filepaths(self, device_id): - matchingFiles = call_adb( - f"shell su root find {self.path} -name {self.matcher}", device_id) - - log.debug("Found file %s", matchingFiles.split('\n')[:-1]) - return matchingFiles.split('\n')[:-1] - - def get_filetype(self): - return self.type - - -class WinscopeFileMatcher(FileMatcher): - def __init__(self, path, matcher, filetype) -> None: - self.path = path - self.internal_matchers = list(map(lambda ext: FileMatcher(path, f'{matcher}{ext}', filetype), - WINSCOPE_EXTS)) - self.type = filetype - - def get_filepaths(self, device_id): - for matcher in self.internal_matchers: - files = matcher.get_filepaths(device_id) - if len(files) > 0: - return files - log.debug("No files found") - return [] - - class TraceTarget: """Defines a single parameter to trace. Attributes: - file_matchers: the matchers used to identify the paths on the device the trace results are saved to. + file: the path on the device the trace results are saved to. trace_start: command to start the trace from adb shell, must not block. trace_stop: command to stop the trace, should block until the trace is stopped. """ - def __init__(self, files, trace_start: str, trace_stop: str) -> None: - if type(files) is not list: - files = [files] - self.files = files + def __init__(self, file: str, trace_start: str, trace_stop: str) -> None: + self.file = file self.trace_start = trace_start self.trace_stop = trace_stop -# Order of files matters as they will be expected in that order and decoded in that order TRACE_TARGETS = { "window_trace": TraceTarget( - WinscopeFileMatcher(WINSCOPE_DIR, "wm_trace", "window_trace"), + "/data/misc/wmtrace/wm_trace.pb", 'su root cmd window tracing start\necho "WM trace started."', 'su root cmd window tracing stop >/dev/null 2>&1' ), - "accessibility_trace": TraceTarget( - WinscopeFileMatcher("/data/misc/a11ytrace", "a11y_trace", "accessibility_trace"), - 'su root cmd accessibility start-trace\necho "Accessibility trace started."', - 'su root cmd accessibility stop-trace >/dev/null 2>&1' - ), "layers_trace": TraceTarget( - WinscopeFileMatcher(WINSCOPE_DIR, "layers_trace", "layers_trace"), + "/data/misc/wmtrace/layers_trace.pb", 'su root service call SurfaceFlinger 1025 i32 1\necho "SF trace started."', 'su root service call SurfaceFlinger 1025 i32 0 >/dev/null 2>&1' ), "screen_recording": TraceTarget( - File(f'/data/local/tmp/screen.mp4', "screen_recording"), - f'screenrecord --bit-rate 8M /data/local/tmp/screen.mp4 >/dev/null 2>&1 &\necho "ScreenRecorder started."', + "/data/local/tmp/screen.winscope.mp4", + 'screenrecord --bit-rate 8M /data/local/tmp/screen.winscope.mp4 >/dev/null 2>&1 &\necho "ScreenRecorder started."', 'pkill -l SIGINT screenrecord >/dev/null 2>&1' ), "transaction": TraceTarget( - [ - WinscopeFileMatcher(WINSCOPE_DIR, "transaction_trace", "transactions"), - FileMatcher(WINSCOPE_DIR, f'transaction_merges_*', "transaction_merges"), - ], + "/data/misc/wmtrace/transaction_trace.pb", 'su root service call SurfaceFlinger 1020 i32 1\necho "SF transactions recording started."', 'su root service call SurfaceFlinger 1020 i32 0 >/dev/null 2>&1' ), "proto_log": TraceTarget( - WinscopeFileMatcher(WINSCOPE_DIR, "wm_log", "proto_log"), + "/data/misc/wmtrace/wm_log.pb", 'su root cmd window logging start\necho "WM logging started."', 'su root cmd window logging stop >/dev/null 2>&1' ), - "ime_trace_clients": TraceTarget( - WinscopeFileMatcher(WINSCOPE_DIR, "ime_trace_clients", "ime_trace_clients"), - 'su root ime tracing start\necho "Clients IME trace started."', - 'su root ime tracing stop >/dev/null 2>&1' - ), - "ime_trace_service": TraceTarget( - WinscopeFileMatcher(WINSCOPE_DIR, "ime_trace_service", "ime_trace_service"), - 'su root ime tracing start\necho "Service IME trace started."', - 'su root ime tracing stop >/dev/null 2>&1' - ), - "ime_trace_managerservice": TraceTarget( - WinscopeFileMatcher(WINSCOPE_DIR, "ime_trace_managerservice", "ime_trace_managerservice"), - 'su root ime tracing start\necho "ManagerService IME trace started."', - 'su root ime tracing stop >/dev/null 2>&1' - ), } -class SurfaceFlingerTraceConfig: - """Handles optional configuration for surfaceflinger traces. - """ - - def __init__(self) -> None: - # default config flags CRITICAL | INPUT | SYNC - self.flags = 1 << 0 | 1 << 1 | 1 << 6 - - def add(self, config: str) -> None: - self.flags |= CONFIG_FLAG[config] - - def is_valid(self, config: str) -> bool: - return config in CONFIG_FLAG - - def command(self) -> str: - return f'su root service call SurfaceFlinger 1033 i32 {self.flags}' - -class SurfaceFlingerTraceSelectedConfig: - """Handles optional selected configuration for surfaceflinger traces. - """ - - def __init__(self) -> None: - # defaults set for all configs - self.selectedConfigs = { - "sfbuffersize": "16000" - } - - def add(self, configType, configValue) -> None: - self.selectedConfigs[configType] = configValue - - def is_valid(self, configType) -> bool: - return configType in CONFIG_SF_SELECTION - - def setBufferSize(self) -> str: - return f'su root service call SurfaceFlinger 1029 i32 {self.selectedConfigs["sfbuffersize"]}' - -class WindowManagerTraceSelectedConfig: - """Handles optional selected configuration for windowmanager traces. - """ - - def __init__(self) -> None: - # defaults set for all configs - self.selectedConfigs = { - "wmbuffersize": "16000", - "tracinglevel": "all", - "tracingtype": "frame", - } - - def add(self, configType, configValue) -> None: - self.selectedConfigs[configType] = configValue - - def is_valid(self, configType) -> bool: - return configType in CONFIG_WM_SELECTION - - def setBufferSize(self) -> str: - return f'su root cmd window tracing size {self.selectedConfigs["wmbuffersize"]}' - - def setTracingLevel(self) -> str: - return f'su root cmd window tracing level {self.selectedConfigs["tracinglevel"]}' - - def setTracingType(self) -> str: - return f'su root cmd window tracing {self.selectedConfigs["tracingtype"]}' - - -CONFIG_FLAG = { - "composition": 1 << 2, - "metadata": 1 << 3, - "hwc": 1 << 4 -} - -#Keep up to date with options in DataAdb.vue -CONFIG_SF_SELECTION = [ - "sfbuffersize", -] - -#Keep up to date with options in DataAdb.vue -CONFIG_WM_SELECTION = [ - "wmbuffersize", - "tracingtype", - "tracinglevel", -] - class DumpTarget: """Defines a single parameter to trace. @@ -276,21 +115,19 @@ class DumpTarget: dump_command: command to dump state to file. """ - def __init__(self, files, dump_command: str) -> None: - if type(files) is not list: - files = [files] - self.files = files + def __init__(self, file: str, dump_command: str) -> None: + self.file = file self.dump_command = dump_command DUMP_TARGETS = { "window_dump": DumpTarget( - File(f'/data/local/tmp/wm_dump{WINSCOPE_EXT}', "window_dump"), - f'su root dumpsys window --proto > /data/local/tmp/wm_dump{WINSCOPE_EXT}' + "/data/local/tmp/wm_dump.pb", + 'su root dumpsys window --proto > /data/local/tmp/wm_dump.pb' ), "layers_dump": DumpTarget( - File(f'/data/local/tmp/sf_dump{WINSCOPE_EXT}', "layers_dump"), - f'su root dumpsys SurfaceFlinger --proto > /data/local/tmp/sf_dump{WINSCOPE_EXT}' + "/data/local/tmp/sf_dump.pb", + 'su root dumpsys SurfaceFlinger --proto > /data/local/tmp/sf_dump.pb' ) } @@ -303,21 +140,18 @@ def get_token() -> str: try: with open(WINSCOPE_TOKEN_LOCATION, 'r') as token_file: token = token_file.readline() - log.debug("Loaded token {} from {}".format( - token, WINSCOPE_TOKEN_LOCATION)) + log.debug("Loaded token {} from {}".format(token, WINSCOPE_TOKEN_LOCATION)) return token except IOError: token = secrets.token_hex(32) os.makedirs(os.path.dirname(WINSCOPE_TOKEN_LOCATION), exist_ok=True) try: with open(WINSCOPE_TOKEN_LOCATION, 'w') as token_file: - log.debug("Created and saved token {} to {}".format( - token, WINSCOPE_TOKEN_LOCATION)) + log.debug("Created and saved token {} to {}".format(token, WINSCOPE_TOKEN_LOCATION)) token_file.write(token) os.chmod(WINSCOPE_TOKEN_LOCATION, 0o600) except IOError: - log.error("Unable to save persistent token {} to {}".format( - token, WINSCOPE_TOKEN_LOCATION)) + log.error("Unable to save persistent token {} to {}".format(token, WINSCOPE_TOKEN_LOCATION)) return token @@ -334,10 +168,8 @@ def add_standard_headers(server): server.send_header('Cache-Control', 'no-cache, no-store, must-revalidate') server.send_header('Access-Control-Allow-Origin', '*') server.send_header('Access-Control-Allow-Methods', 'POST, GET, OPTIONS') - server.send_header('Access-Control-Allow-Headers', - WINSCOPE_TOKEN_HEADER + ', Content-Type, Content-Length') - server.send_header('Access-Control-Expose-Headers', - 'Winscope-Proxy-Version') + server.send_header('Access-Control-Allow-Headers', WINSCOPE_TOKEN_HEADER + ', Content-Type, Content-Length') + server.send_header('Access-Control-Expose-Headers', 'Winscope-Proxy-Version') server.send_header(WINSCOPE_VERSION_HEADER, VERSION) server.end_headers() @@ -361,7 +193,7 @@ class BadRequest(Exception): class RequestRouter: - """Handles HTTP request authentication and routing""" + """Handles HTTP request authenticationn and routing""" def __init__(self, handler): self.request = handler @@ -377,8 +209,7 @@ class RequestRouter: def __internal_error(self, error: str): log.error("Internal error: " + error) - self.request.respond(HTTPStatus.INTERNAL_SERVER_ERROR, - error.encode("utf-8"), 'text/txt') + self.request.respond(HTTPStatus.INTERNAL_SERVER_ERROR, error.encode("utf-8"), 'text/txt') def __bad_token(self): log.info("Bad token") @@ -411,15 +242,11 @@ def call_adb(params: str, device: str = None, stdin: bytes = None): log.debug("Call: " + ' '.join(command)) return subprocess.check_output(command, stderr=subprocess.STDOUT, input=stdin).decode('utf-8') except OSError as ex: - log.debug('Error executing adb command: {}\n{}'.format( - ' '.join(command), repr(ex))) - raise AdbError('Error executing adb command: {}\n{}'.format( - ' '.join(command), repr(ex))) + log.debug('Error executing adb command: {}\n{}'.format(' '.join(command), repr(ex))) + raise AdbError('Error executing adb command: {}\n{}'.format(' '.join(command), repr(ex))) except subprocess.CalledProcessError as ex: - log.debug('Error executing adb command: {}\n{}'.format( - ' '.join(command), ex.output.decode("utf-8"))) - raise AdbError('Error executing adb command: adb {}\n{}'.format( - params, ex.output.decode("utf-8"))) + log.debug('Error executing adb command: {}\n{}'.format(' '.join(command), ex.output.decode("utf-8"))) + raise AdbError('Error executing adb command: adb {}\n{}'.format(params, ex.output.decode("utf-8"))) def call_adb_outfile(params: str, outfile, device: str = None, stdin: bytes = None): @@ -434,10 +261,8 @@ def call_adb_outfile(params: str, outfile, device: str = None, stdin: bytes = No raise AdbError('Error executing adb command: adb {}\n'.format(params) + err.decode( 'utf-8') + '\n' + outfile.read().decode('utf-8')) except OSError as ex: - log.debug('Error executing adb command: adb {}\n{}'.format( - params, repr(ex))) - raise AdbError( - 'Error executing adb command: adb {}\n{}'.format(params, repr(ex))) + log.debug('Error executing adb command: adb {}\n{}'.format(params, repr(ex))) + raise AdbError('Error executing adb command: adb {}\n{}'.format(params, repr(ex))) class ListDevicesEndpoint(RequestEndpoint): @@ -465,54 +290,34 @@ class DeviceRequestEndpoint(RequestEndpoint): def process_with_device(self, server, path, device_id): pass - def get_request(self, server) -> str: - try: - length = int(server.headers["Content-Length"]) - except KeyError as err: - raise BadRequest("Missing Content-Length header\n" + str(err)) - except ValueError as err: - raise BadRequest("Content length unreadable\n" + str(err)) - return json.loads(server.rfile.read(length).decode("utf-8")) - -class FetchFilesEndpoint(DeviceRequestEndpoint): +class FetchFileEndpoint(DeviceRequestEndpoint): def process_with_device(self, server, path, device_id): if len(path) != 1: raise BadRequest("File not specified") if path[0] in TRACE_TARGETS: - files = TRACE_TARGETS[path[0]].files + file_path = TRACE_TARGETS[path[0]].file elif path[0] in DUMP_TARGETS: - files = DUMP_TARGETS[path[0]].files + file_path = DUMP_TARGETS[path[0]].file else: raise BadRequest("Unknown file specified") - file_buffers = dict() - - for f in files: - file_type = f.get_filetype() - file_paths = f.get_filepaths(device_id) - - for file_path in file_paths: - with NamedTemporaryFile() as tmp: - log.debug( - f"Fetching file {file_path} from device to {tmp.name}") - call_adb_outfile('exec-out su root cat ' + - file_path, tmp, device_id) - log.debug(f"Deleting file {file_path} from device") - call_adb('shell su root rm ' + file_path, device_id) - log.debug(f"Uploading file {tmp.name}") - if file_type not in file_buffers: - file_buffers[file_type] = [] - buf = base64.encodebytes(tmp.read()).decode("utf-8") - file_buffers[file_type].append(buf) - - if (len(file_buffers) == 0): - log.error("Proxy didn't find any file to fetch") - - # server.send_header('X-Content-Type-Options', 'nosniff') - # add_standard_headers(server) - j = json.dumps(file_buffers) - server.respond(HTTPStatus.OK, j.encode("utf-8"), "text/json") + with NamedTemporaryFile() as tmp: + log.debug("Fetching file {} from device to {}".format(file_path, tmp.name)) + call_adb_outfile('exec-out su root cat ' + file_path, tmp, device_id) + log.debug("Deleting file {} from device".format(file_path)) + call_adb('shell su root rm ' + file_path, device_id) + server.send_response(HTTPStatus.OK) + server.send_header('X-Content-Type-Options', 'nosniff') + server.send_header('Content-type', 'application/octet-stream') + add_standard_headers(server) + log.debug("Uploading file {}".format(tmp.name)) + while True: + buf = tmp.read(1024) + if buf: + server.wfile.write(buf) + else: + break def check_root(device_id): @@ -537,41 +342,34 @@ class TraceThread(threading.Thread): self.process = subprocess.Popen(shell, stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE, start_new_session=True) except OSError as ex: - raise AdbError( - 'Error executing adb command: adb shell\n{}'.format(repr(ex))) + raise AdbError('Error executing adb command: adb shell\n{}'.format(repr(ex))) super().__init__() def timeout(self): if self.is_alive(): - log.warning( - "Keep-alive timeout for trace on {}".format(self._device_id)) + log.warning("Keep-alive timeout for trace on {}".format(self._device_id)) self.end_trace() if self._device_id in TRACE_THREADS: TRACE_THREADS.pop(self._device_id) def reset_timer(self): - log.debug( - "Resetting keep-alive clock for trace on {}".format(self._device_id)) + log.debug("Resetting keep-alive clock for trace on {}".format(self._device_id)) if self._keep_alive_timer: self._keep_alive_timer.cancel() - self._keep_alive_timer = threading.Timer( - KEEP_ALIVE_INTERVAL_S, self.timeout) + self._keep_alive_timer = threading.Timer(KEEP_ALIVE_INTERVAL_S, self.timeout) self._keep_alive_timer.start() def end_trace(self): if self._keep_alive_timer: self._keep_alive_timer.cancel() - log.debug("Sending SIGINT to the trace process on {}".format( - self._device_id)) + log.debug("Sending SIGINT to the trace process on {}".format(self._device_id)) self.process.send_signal(signal.SIGINT) try: - log.debug("Waiting for trace shell to exit for {}".format( - self._device_id)) + log.debug("Waiting for trace shell to exit for {}".format(self._device_id)) self.process.wait(timeout=5) except TimeoutError: - log.debug( - "TIMEOUT - sending SIGKILL to the trace process on {}".format(self._device_id)) + log.debug("TIMEOUT - sending SIGKILL to the trace process on {}".format(self._device_id)) self.process.kill() self.join() @@ -583,10 +381,8 @@ class TraceThread(threading.Thread): time.sleep(0.2) for i in range(10): if call_adb("shell su root cat /data/local/tmp/winscope_status", device=self._device_id) == 'TRACE_OK\n': - call_adb( - "shell su root rm /data/local/tmp/winscope_status", device=self._device_id) - log.debug("Trace finished successfully on {}".format( - self._device_id)) + call_adb("shell su root rm /data/local/tmp/winscope_status", device=self._device_id) + log.debug("Trace finished successfully on {}".format(self._device_id)) self._success = True break log.debug("Still waiting for cleanup on {}".format(self._device_id)) @@ -624,7 +420,13 @@ while true; do sleep 0.1; done def process_with_device(self, server, path, device_id): try: - requested_types = self.get_request(server) + length = int(server.headers["Content-Length"]) + except KeyError as err: + raise BadRequest("Missing Content-Length header\n" + str(err)) + except ValueError as err: + raise BadRequest("Content length unreadable\n" + str(err)) + try: + requested_types = json.loads(server.rfile.read(length).decode("utf-8")) requested_traces = [TRACE_TARGETS[t] for t in requested_types] except KeyError as err: raise BadRequest("Unsupported trace target\n" + str(err)) @@ -638,10 +440,8 @@ while true; do sleep 0.1; done command = StartTrace.TRACE_COMMAND.format( '\n'.join([t.trace_stop for t in requested_traces]), '\n'.join([t.trace_start for t in requested_traces])) - log.debug("Trace requested for {} with targets {}".format( - device_id, ','.join(requested_types))) - TRACE_THREADS[device_id] = TraceThread( - device_id, command.encode('utf-8')) + log.debug("Trace requested for {} with targets {}".format(device_id, ','.join(requested_types))) + TRACE_THREADS[device_id] = TraceThread(device_id, command.encode('utf-8')) TRACE_THREADS[device_id].start() server.respond(HTTPStatus.OK, b'', "text/plain") @@ -654,8 +454,7 @@ class EndTrace(DeviceRequestEndpoint): TRACE_THREADS[device_id].end_trace() success = TRACE_THREADS[device_id].success() - out = TRACE_THREADS[device_id].out + \ - b"\n" + TRACE_THREADS[device_id].err + out = TRACE_THREADS[device_id].out + b"\n" + TRACE_THREADS[device_id].err command = TRACE_THREADS[device_id].trace_command TRACE_THREADS.pop(device_id) if success: @@ -667,97 +466,24 @@ class EndTrace(DeviceRequestEndpoint): "utf-8")) -def execute_command(server, device_id, shell, configType, configValue): - process = subprocess.Popen(shell, stdout=subprocess.PIPE, stderr=subprocess.PIPE, - stdin=subprocess.PIPE, start_new_session=True) - log.debug(f"Changing trace config on device {device_id} {configType}:{configValue}") - out, err = process.communicate(configValue.encode('utf-8')) - if process.returncode != 0: - raise AdbError( - f"Error executing command:\n {configValue}\n\n### OUTPUT ###{out.decode('utf-8')}\n{err.decode('utf-8')}") - log.debug(f"Changing trace config finished on device {device_id}") - server.respond(HTTPStatus.OK, b'', "text/plain") - - -class ConfigTrace(DeviceRequestEndpoint): - def process_with_device(self, server, path, device_id): - try: - requested_configs = self.get_request(server) - config = SurfaceFlingerTraceConfig() - for requested_config in requested_configs: - if not config.is_valid(requested_config): - raise BadRequest( - f"Unsupported config {requested_config}\n") - config.add(requested_config) - except KeyError as err: - raise BadRequest("Unsupported trace target\n" + str(err)) - if device_id in TRACE_THREADS: - BadRequest(f"Trace in progress for {device_id}") - if not check_root(device_id): - raise AdbError( - f"Unable to acquire root privileges on the device - check the output of 'adb -s {device_id} shell su root id'") - command = config.command() - shell = ['adb', '-s', device_id, 'shell'] - log.debug(f"Starting shell {' '.join(shell)}") - execute_command(server, device_id, shell, "sf buffer size", command) - - -def add_selected_request_to_config(self, server, device_id, config): - try: - requested_configs = self.get_request(server) - for requested_config in requested_configs: - if config.is_valid(requested_config): - config.add(requested_config, requested_configs[requested_config]) - else: - raise BadRequest( - f"Unsupported config {requested_config}\n") - except KeyError as err: - raise BadRequest("Unsupported trace target\n" + str(err)) - if device_id in TRACE_THREADS: - BadRequest(f"Trace in progress for {device_id}") - if not check_root(device_id): - raise AdbError( - f"Unable to acquire root privileges on the device - check the output of 'adb -s {device_id} shell su root id'") - return config - - -class SurfaceFlingerSelectedConfigTrace(DeviceRequestEndpoint): - def process_with_device(self, server, path, device_id): - config = SurfaceFlingerTraceSelectedConfig() - config = add_selected_request_to_config(self, server, device_id, config) - setBufferSize = config.setBufferSize() - shell = ['adb', '-s', device_id, 'shell'] - log.debug(f"Starting shell {' '.join(shell)}") - execute_command(server, device_id, shell, "sf buffer size", setBufferSize) - - -class WindowManagerSelectedConfigTrace(DeviceRequestEndpoint): - def process_with_device(self, server, path, device_id): - config = WindowManagerTraceSelectedConfig() - config = add_selected_request_to_config(self, server, device_id, config) - setBufferSize = config.setBufferSize() - setTracingType = config.setTracingType() - setTracingLevel = config.setTracingLevel() - shell = ['adb', '-s', device_id, 'shell'] - log.debug(f"Starting shell {' '.join(shell)}") - execute_command(server, device_id, shell, "wm buffer size", setBufferSize) - execute_command(server, device_id, shell, "tracing type", setTracingType) - execute_command(server, device_id, shell, "tracing level", setTracingLevel) - - class StatusEndpoint(DeviceRequestEndpoint): def process_with_device(self, server, path, device_id): if device_id not in TRACE_THREADS: raise BadRequest("No trace in progress for {}".format(device_id)) TRACE_THREADS[device_id].reset_timer() - server.respond(HTTPStatus.OK, str( - TRACE_THREADS[device_id].is_alive()).encode("utf-8"), "text/plain") + server.respond(HTTPStatus.OK, str(TRACE_THREADS[device_id].is_alive()).encode("utf-8"), "text/plain") class DumpEndpoint(DeviceRequestEndpoint): def process_with_device(self, server, path, device_id): try: - requested_types = self.get_request(server) + length = int(server.headers["Content-Length"]) + except KeyError as err: + raise BadRequest("Missing Content-Length header\n" + str(err)) + except ValueError as err: + raise BadRequest("Content length unreadable\n" + str(err)) + try: + requested_types = json.loads(server.rfile.read(length).decode("utf-8")) requested_traces = [DUMP_TARGETS[t] for t in requested_types] except KeyError as err: raise BadRequest("Unsupported trace target\n" + str(err)) @@ -784,21 +510,12 @@ class DumpEndpoint(DeviceRequestEndpoint): class ADBWinscopeProxy(BaseHTTPRequestHandler): def __init__(self, request, client_address, server): self.router = RequestRouter(self) - self.router.register_endpoint( - RequestType.GET, "devices", ListDevicesEndpoint()) - self.router.register_endpoint( - RequestType.GET, "status", StatusEndpoint()) - self.router.register_endpoint( - RequestType.GET, "fetch", FetchFilesEndpoint()) + self.router.register_endpoint(RequestType.GET, "devices", ListDevicesEndpoint()) + self.router.register_endpoint(RequestType.GET, "status", StatusEndpoint()) + self.router.register_endpoint(RequestType.GET, "fetch", FetchFileEndpoint()) self.router.register_endpoint(RequestType.POST, "start", StartTrace()) self.router.register_endpoint(RequestType.POST, "end", EndTrace()) self.router.register_endpoint(RequestType.POST, "dump", DumpEndpoint()) - self.router.register_endpoint( - RequestType.POST, "configtrace", ConfigTrace()) - self.router.register_endpoint( - RequestType.POST, "selectedsfconfigtrace", SurfaceFlingerSelectedConfigTrace()) - self.router.register_endpoint( - RequestType.POST, "selectedwmconfigtrace", WindowManagerSelectedConfigTrace()) super().__init__(request, client_address, server) def respond(self, code: int, data: bytes, mime: str) -> None: |