1/* 2 * Copyright (C) 2024 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17import {assertTrue} from 'common/assert_utils'; 18import {ParserTimestampConverter} from 'common/timestamp_converter'; 19import {TraceFile} from 'trace/trace_file'; 20import {WasmEngineProxy} from 'trace_processor/wasm_engine_proxy'; 21import {ParserViewCaptureWindow} from './parser_view_capture_window'; 22 23interface WindowAndPackage { 24 window: string; 25 package: string; 26} 27 28export class ParserViewCapture { 29 private readonly traceFile: TraceFile; 30 private readonly traceProcessor: WasmEngineProxy; 31 private readonly timestampConverter: ParserTimestampConverter; 32 33 private windowParsers: ParserViewCaptureWindow[] = []; 34 35 private static readonly STDLIB_MODULE_NAME = 'android.winscope.viewcapture'; 36 37 constructor( 38 traceFile: TraceFile, 39 traceProcessor: WasmEngineProxy, 40 timestampConverter: ParserTimestampConverter, 41 ) { 42 this.traceFile = traceFile; 43 this.traceProcessor = traceProcessor; 44 this.timestampConverter = timestampConverter; 45 } 46 47 async parse() { 48 await this.traceProcessor.query( 49 `INCLUDE PERFETTO MODULE ${ParserViewCapture.STDLIB_MODULE_NAME};`, 50 ); 51 52 const windowAndPackageNames = await this.queryWindowAndPackageNames(); 53 assertTrue( 54 windowAndPackageNames.length > 0, 55 () => 'Perfetto trace has no ViewCapture windows', 56 ); 57 58 this.windowParsers = windowAndPackageNames.map( 59 (windowAndPackage) => 60 new ParserViewCaptureWindow( 61 this.traceFile, 62 this.traceProcessor, 63 this.timestampConverter, 64 windowAndPackage.package, 65 windowAndPackage.window, 66 ), 67 ); 68 69 const parsePromises = this.windowParsers.map((parser) => parser.parse()); 70 await Promise.all(parsePromises); 71 } 72 73 getWindowParsers(): ParserViewCaptureWindow[] { 74 return this.windowParsers; 75 } 76 77 private async queryWindowAndPackageNames(): Promise<WindowAndPackage[]> { 78 const sql = ` 79 SELECT DISTINCT GROUP_CONCAT(string_value ORDER BY args.key) AS package_and_window 80 FROM android_viewcapture AS vc 81 JOIN args ON vc.arg_set_id = args.arg_set_id 82 WHERE 83 args.key = 'package_name' OR 84 args.key = 'window_name' 85 GROUP BY vc.id 86 ORDER BY package_and_window; 87 `; 88 89 const result = await this.traceProcessor.query(sql).waitAllRows(); 90 91 const names: WindowAndPackage[] = []; 92 for (const it = result.iter({}); it.valid(); it.next()) { 93 const packageAndWindow = it.get('package_and_window') as string; 94 const tokens = packageAndWindow.split(','); 95 assertTrue(tokens.length === 2); 96 names.push({package: tokens[0], window: tokens[1]}); 97 } 98 99 return names; 100 } 101} 102