diff --git a/tools/winscope/adb_proxy/winscope_proxy.py b/tools/winscope/adb_proxy/winscope_proxy.py index 8c16e9647..344c3cc5b 100755 --- a/tools/winscope/adb_proxy/winscope_proxy.py +++ b/tools/winscope/adb_proxy/winscope_proxy.py @@ -203,6 +203,52 @@ class SurfaceFlingerTraceConfig: 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, @@ -210,6 +256,17 @@ CONFIG_FLAG = { "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. @@ -610,6 +667,18 @@ 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: @@ -630,15 +699,50 @@ class ConfigTrace(DeviceRequestEndpoint): command = config.command() shell = ['adb', '-s', device_id, 'shell'] log.debug(f"Starting shell {' '.join(shell)}") - 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} cmd:{command}") - out, err = process.communicate(command.encode('utf-8')) - if process.returncode != 0: - raise AdbError( - f"Error executing command:\n {command}\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") + 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): @@ -691,6 +795,10 @@ class ADBWinscopeProxy(BaseHTTPRequestHandler): 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: diff --git a/tools/winscope/src/DataAdb.vue b/tools/winscope/src/DataAdb.vue index 1cffa610b..6490f394b 100644 --- a/tools/winscope/src/DataAdb.vue +++ b/tools/winscope/src/DataAdb.vue @@ -86,10 +86,29 @@
{{TRACES[traceKey].name}}
-
-

{{TRACES[traceKey].name}} config

+
+

Surface Flinger config

- {{config}} + {{config}} +
+ + + {{selectConfig}} + {{ option }} + + +
+
+
+
+

Window Manager config

+
+ + + {{selectConfig}} + {{ option }} + +
Start trace @@ -149,6 +168,8 @@ const PROXY_ENDPOINTS = { START_TRACE: '/start/', END_TRACE: '/end/', CONFIG_TRACE: '/configtrace/', + SELECTED_WM_CONFIG_TRACE: '/selectedwmconfigtrace/', + SELECTED_SF_CONFIG_TRACE: '/selectedsfconfigtrace/', DUMP: '/dump/', FETCH: '/fetch/', STATUS: '/status/', @@ -192,6 +213,33 @@ const TRACE_CONFIG = { ], }; +const SF_SELECTED_CONFIG = { + 'sfbuffersize': [ + '4000', + '8000', + '16000', + '32000', + ], +}; + +const WM_SELECTED_CONFIG = { + 'wmbuffersize': [ + '4000', + '8000', + '16000', + '32000', + ], + 'tracingtype': [ + 'frame', + 'transaction', + ], + 'tracinglevel': [ + 'all', + 'trim', + 'critical', + ], +}; + const DUMPS = { 'window_dump': { name: 'Window Manager', @@ -228,6 +276,10 @@ export default { STATES, TRACES, TRACE_CONFIG, + SF_SELECTED_CONFIG, + WM_SELECTED_CONFIG, + SF_SELECTED_CONFIG_VALUES: {}, + WM_SELECTED_CONFIG_VALUES: {}, DUMPS, FILE_DECODERS, WINSCOPE_PROXY_VERSION, @@ -292,7 +344,7 @@ export default { this.keep_alive_worker = null; return; } - this.callProxy('GET', PROXY_ENDPOINTS.STATUS + this.deviceId() + '/', this, function(request, view) { + this.callProxy('GET', `${PROXY_ENDPOINTS.STATUS}${this.deviceId()}/`, this, function(request, view) { if (request.responseText !== 'True') { view.endTrace(); } else if (view.keep_alive_worker === null) { @@ -303,16 +355,21 @@ export default { startTrace() { const requested = this.toTrace(); const requestedConfig = this.toTraceConfig(); + const requestedSelectedSfConfig = this.toSelectedSfTraceConfig(); + const requestedSelectedWmConfig = this.toSelectedWmTraceConfig(); if (requested.length < 1) { this.errorText = 'No targets selected'; this.status = STATES.ERROR; this.newEventOccurred("No targets selected"); return; } + this.newEventOccurred("Start Trace"); - this.callProxy('POST', PROXY_ENDPOINTS.CONFIG_TRACE + this.deviceId() + '/', this, null, null, requestedConfig); + this.callProxy('POST', `${PROXY_ENDPOINTS.CONFIG_TRACE}${this.deviceId()}/`, this, null, null, requestedConfig); + this.callProxy('POST', `${PROXY_ENDPOINTS.SELECTED_SF_CONFIG_TRACE}${this.deviceId()}/`, this, null, null, requestedSelectedSfConfig); + this.callProxy('POST', `${PROXY_ENDPOINTS.SELECTED_WM_CONFIG_TRACE}${this.deviceId()}/`, this, null, null, requestedSelectedWmConfig); this.status = STATES.END_TRACE; - this.callProxy('POST', PROXY_ENDPOINTS.START_TRACE + this.deviceId() + '/', this, function(request, view) { + this.callProxy('POST', `${PROXY_ENDPOINTS.START_TRACE}${this.deviceId()}/`, this, function(request, view) { view.keepAliveTrace(); }, null, requested); }, @@ -326,19 +383,19 @@ export default { return; } this.status = STATES.LOAD_DATA; - this.callProxy('POST', PROXY_ENDPOINTS.DUMP + this.deviceId() + '/', this, function(request, view) { + this.callProxy('POST', `${PROXY_ENDPOINTS.DUMP}${this.deviceId()}/`, this, function(request, view) { view.loadFile(requested, 0); }, null, requested); }, endTrace() { this.status = STATES.LOAD_DATA; - this.callProxy('POST', PROXY_ENDPOINTS.END_TRACE + this.deviceId() + '/', this, function(request, view) { + this.callProxy('POST', `${PROXY_ENDPOINTS.END_TRACE}${this.deviceId()}/`, this, function(request, view) { view.loadFile(view.toTrace(), 0); }); this.newEventOccurred("Ended Trace"); }, loadFile(files, idx) { - this.callProxy('GET', PROXY_ENDPOINTS.FETCH + this.deviceId() + '/' + files[idx] + '/', this, function(request, view) { + this.callProxy('GET', `${PROXY_ENDPOINTS.FETCH}${this.deviceId()}/${files[idx]}/`, this, function(request, view) { try { const enc = new TextDecoder('utf-8'); const resp = enc.decode(request.response); @@ -380,6 +437,24 @@ export default { .flatMap((file) => TRACE_CONFIG[file]) .filter((config) => this.adbStore[config]); }, + toSelectedSfTraceConfig() { + const requestedSelectedConfig = {}; + for (const config in this.SF_SELECTED_CONFIG_VALUES) { + if (this.SF_SELECTED_CONFIG_VALUES[config] !== "") { + requestedSelectedConfig[config] = this.SF_SELECTED_CONFIG_VALUES[config]; + } + } + return requestedSelectedConfig; + }, + toSelectedWmTraceConfig() { + const requestedSelectedConfig = {}; + for (const config in this.WM_SELECTED_CONFIG_VALUES) { + if (this.WM_SELECTED_CONFIG_VALUES[config] !== "") { + requestedSelectedConfig[config] = this.WM_SELECTED_CONFIG_VALUES[config]; + } + } + return requestedSelectedConfig; + }, toDump() { return Object.keys(DUMPS) .filter((dumpKey) => this.adbStore[dumpKey]); @@ -459,6 +534,12 @@ export default {