1/*
2 * Copyright (C) 2022 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 {assertDefined} from 'common/assert_utils';
18import {Timestamp} from 'common/time';
19import {AbstractParser} from 'parsers/legacy/abstract_parser';
20import {com} from 'protos/windowmanager/latest/static';
21import {
22  CustomQueryParserResultTypeMap,
23  CustomQueryType,
24  VisitableParserCustomQuery,
25} from 'trace/custom_query';
26import {EntriesRange} from 'trace/trace';
27import {TraceType} from 'trace/trace_type';
28import {HierarchyTreeNode} from 'trace/tree_node/hierarchy_tree_node';
29import {PropertiesProvider} from 'trace/tree_node/properties_provider';
30import {RectsComputation} from './computations/rects_computation';
31import {WmCustomQueryUtils} from './custom_query_utils';
32import {HierarchyTreeBuilderWm} from './hierarchy_tree_builder_wm';
33import {ParserWmUtils} from './parser_window_manager_utils';
34import {WindowManagerTraceFileProto} from './wm_tampered_protos';
35
36export class ParserWindowManager extends AbstractParser<HierarchyTreeNode> {
37  private static readonly MAGIC_NUMBER = [
38    0x09, 0x57, 0x49, 0x4e, 0x54, 0x52, 0x41, 0x43, 0x45,
39  ]; // .WINTRACE
40
41  private realToBootTimeOffsetNs: bigint | undefined;
42
43  override getTraceType(): TraceType {
44    return TraceType.WINDOW_MANAGER;
45  }
46
47  override getMagicNumber(): number[] {
48    return ParserWindowManager.MAGIC_NUMBER;
49  }
50
51  override getRealToBootTimeOffsetNs(): bigint | undefined {
52    return this.realToBootTimeOffsetNs;
53  }
54
55  override getRealToMonotonicTimeOffsetNs(): bigint | undefined {
56    return undefined;
57  }
58
59  override decodeTrace(
60    buffer: Uint8Array,
61  ): com.android.server.wm.IWindowManagerTraceProto[] {
62    const decoded = WindowManagerTraceFileProto.decode(
63      buffer,
64    ) as com.android.server.wm.IWindowManagerTraceFileProto;
65    const timeOffset = BigInt(
66      decoded.realToElapsedTimeOffsetNanos?.toString() ?? '0',
67    );
68    this.realToBootTimeOffsetNs = timeOffset !== 0n ? timeOffset : undefined;
69    return decoded.entry ?? [];
70  }
71
72  protected override getTimestamp(
73    entry: com.android.server.wm.IWindowManagerTraceProto,
74  ): Timestamp {
75    return this.timestampConverter.makeTimestampFromBootTimeNs(
76      BigInt(assertDefined(entry.elapsedRealtimeNanos).toString()),
77    );
78  }
79
80  override processDecodedEntry(
81    index: number,
82    entry: com.android.server.wm.IWindowManagerTraceProto,
83  ): HierarchyTreeNode {
84    return this.makeHierarchyTree(entry);
85  }
86
87  override customQuery<Q extends CustomQueryType>(
88    type: Q,
89    entriesRange: EntriesRange,
90  ): Promise<CustomQueryParserResultTypeMap[Q]> {
91    return new VisitableParserCustomQuery(type)
92      .visit(CustomQueryType.WM_WINDOWS_TOKEN_AND_TITLE, () => {
93        const result: CustomQueryParserResultTypeMap[CustomQueryType.WM_WINDOWS_TOKEN_AND_TITLE] =
94          [];
95        this.decodedEntries
96          .slice(entriesRange.start, entriesRange.end)
97          .forEach((windowManagerTraceProto) => {
98            WmCustomQueryUtils.parseWindowsTokenAndTitle(
99              windowManagerTraceProto?.windowManagerService
100                ?.rootWindowContainer,
101              result,
102            );
103          });
104        return Promise.resolve(result);
105      })
106      .getResult();
107  }
108
109  private makeHierarchyTree(
110    entryProto: com.android.server.wm.IWindowManagerTraceProto,
111  ): HierarchyTreeNode {
112    const containers: PropertiesProvider[] = ParserWmUtils.extractContainers(
113      assertDefined(entryProto.windowManagerService),
114    );
115
116    const entry = ParserWmUtils.makeEntryProperties(
117      assertDefined(entryProto.windowManagerService),
118    );
119
120    return new HierarchyTreeBuilderWm()
121      .setRoot(entry)
122      .setChildren(containers)
123      .setComputations([new RectsComputation()])
124      .build();
125  }
126}
127